[newbie code] correct possessive plural names in socials

From: Justin (justinl@mac.com)
Date: 07/22/01


===Me===:

I'm nothing if I'm not wordy, so I beg forgiveness to the length of this. If
you great ones don't see where my ineptitudes lie, however, you can't
lend your kind help as well as you might otherwise - and I want to be as
clear as possible.

===The problem==:

In socials, we use $n and $N to insert the name of the char, right?
Well, lets say you have a social line such as "You whack $N's head."

If the name is "David" you get: You whack David's head. -- which is
grammatically correct.

However, if the name is "Davis" (or any name ending in 's'), you get:
You whack Davis's head --which is not correct... (it should be: You
whack Davis' head -- note the correct usage of the possessive plural)

Maybe I'm harboring the dead spirit of an English teacher, I don't
know, but it bothers me for it to be wrong (and NO - changing the social
itself around so that it's something like "You whack the head of $N" is NOT
a good solution). Mostly I thought I would be able to tackle this problem by
slightly modifying $n and $N, using skills I knew already, and I thought
it wouldn't be hard. I was mostly right!

===The Goal===:

To add $x and $X that would figure out the correct possessive plural
form of a name so that I could have the social line such as "You
whack $X head" and have it be correct for names ending or not ending
with 's'.

After this works, I could do a mass find/replace in my socials file for
"$n's" and "$N's" and replace respectivly with "$x" and "$X".

===My solution theory===:

in comm.c, find where it says $n and $N, duplicate that and add cases
for $x and $X (I'll show you exactly what I did later). Instead of calling
PERS(), I call PPERS() (not so clever, P standing for 'plural', PERS
standing for 'person' presumably).

In utils.h, I added a #define PPERS line after the existing #define
PERS line, which differed for my different solutions.

==
===My (non functional) solution #1===:

I thought that I would make a routine that figures out where the NULL
is, and backs up and checks for an 's' and appends the result
accordingly (either just " '  " or " 's " )

here's version 1.1 of solution 1 (i want you to see that I did do _some_
learning before I moved on and eventually came asking for help):

in utils.h, I added something like:
#define PPERS(ch)   char get_plural_name(ch)

in utils.c, I added:

/*char get_plural_name(struct char_data * ch)
{
    int index;
    static struct char_data player_plural_name;

    player_plural_name = GET_NAME(ch);

    for (index = 0; index < 20; index++) {
        if (player_plural_name.name[index] == '\0') {
            if (player_plural_name.name[index - 1] == 's') {
                player_plural_name.name[index] = '\'';
                player_plural_name.name[index + 1] = '\0';
                //how do I return the result?
            }
            else {
                player_plural_name.name[index] = '\'';
                player_plural_name.name[index + 1] = 's';
                player_plural_name.name[index + 2] = '\0';
                //how do I return the result?
        }
    }
    return 0; //should this be here? Or be something else?
}*/

Here's version 1.2 (and last) of my first solution (note that strcat would
probably make it microfractionally slower, but the code got a little
tighter (in truth, I'd like to use it without the strcat, because I know I'm
one for efficiency - but the strcat helped me to see the upcoming
solution #2):

in utils.h, I added something like:
#define PPERS(ch, vict)   char get_plural_name(ch, vict)

in utils.c, I added:

/*char get_plural_name(struct char_data * ch, struct char_data * vict)
{
    int index;
    char player_plural_name[22];

    send_to_all("Test\r\n");

    player_plural_name[0] = PERS(ch, vict);

    index = strlen(player_plural_name);

            if (player_plural_name[index - 1] == 's')
                strcat(player_plural_name, "'");
            else
                strcat(player_plural_name, "'s");
    return 0;
}*/

==
===My (functional, yet player file corrupting) solution #2===:

I thought, "well, if they're using macros all over the place, I'll just use
strcat and do it all in a macro myself"

as in the other two solutions, I left comm.c with this in perform_act
right under case 'N':

  case 'x':
   i = PPERS(ch, to);
   break;
  case 'X':
   CHECK_NULL(vict_obj, PPERS((const struct char_data *) vict_obj, to));
   break;

I commented out all references to get_plural_name() and in utils.h I
made my #define PPERS the following

#define PPERS(ch, vict)  ((PERS(ch, vict)[strlen(PERS(ch, vict)) - 1] ==
's') ? (strcat(PERS(ch, vict), "'")) : (strcat(PERS(ch, vict), "'s")))

in English, this is

obtain the length of PERS and go to the last char in PERS.. is it s? if
so, append with ', if not append with 's

This line took me a literally hours to get to, even after the few days that
it took me to come up with the idea to do it.

I felt so good for 3 minutes after compiling this and doing it without it
crashing and seeing the correct possessive plural on a few different
chars (you know... that happy you-want-to-call-someone-but-you-don't-
know-who feeling - the code works!). Well, that started crumbling
down around me when I noticed that if you do it twice to the same
person, it continues to append ''s on their name. "Oh no, it's saving the
name info back onto the player," I realized.

"Davis" would be in the room as "Davis'" after 1 usage, and after
four usages would be "Davis''s''s" and you would see "Davis''s''s
is standing here" and Davis would see Davis''s''s in his score.

Not only that, when the player logs out with that char it puts this
corrupted name into the player file, and it's possible to not be able to
log in with that char (heh, oops!).

I'm missing something fundamental to how this works as to why it's
saving the name with the player...

===My humble request===:

Since the quest here is to learn, I'd like to know how to fix both of these
solutions. Solution #1 needs to know how to return the result on top of
the fix to #2. #2 needs a "doesn't change player's name permanently"
fix. This has become a little over my head.

It's my thought that a combo of solutions #1.1 and #1.2 will be the
best, when it works (pass both arguments, call PERS (like 1.2, so that
it can append to "someone" if necessary) and then find the NULL (like
1.1)). I'd also appreciate a comment on that as well. Or maybe something I
completely didn't think of is best?


I thank thee for reading this, allowing it to use a few brain cycles in
processing it, and especially for providing what guidance you may.

Justin C. Lauzet

--
   +---------------------------------------------------------------+
   | FAQ: http://qsilver.queensu.ca/~fletchra/Circle/list-faq.html |
   | Archives: http://post.queensu.ca/listserv/wwwarch/circle.html |
   +---------------------------------------------------------------+



This archive was generated by hypermail 2b30 : 12/06/01 PST