/* $Header: /belch_a/users/rearl/tinymuck/src/RCS/stringutil.c,v 1.10 90/09/28 12:25:08 rearl Exp $ */ /* * $Log: stringutil.c,v $ * Revision 1.10 90/09/28 12:25:08 rearl * Moved alloc_string() and alloc_prog_string() to here. * * Revision 1.9 90/09/18 08:02:25 rearl * Speedups mainly, improved upper/lowercase lookup. * * Revision 1.8 90/09/16 04:43:06 rearl * Preparation code added for disk-based MUCK. * * Revision 1.7 90/09/10 02:19:51 rearl * Introduced string compression of properties, for the * COMPRESS compiler option. * * Revision 1.6 90/08/15 03:08:38 rearl * Messed around with pronoun_substitute. Hopefully made it easier to use. * * Revision 1.5 90/08/02 18:50:43 rearl * Fixed bug in capitalized self-substitutions. * * Revision 1.4 90/08/02 02:17:16 rearl * Capital % substitutions now automatically capitalize the * corresponding self-sub property. Example: %O -> Her. * * Revision 1.3 90/07/29 17:45:08 rearl * Pronoun substitution for programs fixed. * * Revision 1.2 90/07/22 04:28:33 casie * Added %r/%R substitutions for reflexive pronouns. * * Revision 1.1 90/07/19 23:04:13 casie * Initial revision * * */ #include "copyright.h" #include "config.h" #include "interface.h" /* String utilities */ #include <ctype.h> #include "externs.h" #define DOWNCASE(x) (lowercase[x]) int string_compare(register const char *s1, register const char *s2) { while(*s1 && *s2 && DOWNCASE(*s1) == DOWNCASE(*s2)) s1++, s2++; return(DOWNCASE(*s1) - DOWNCASE(*s2)); } int string_prefix(register const char *string, register const char *prefix) { while(*string && *prefix && DOWNCASE(*string) == DOWNCASE(*prefix)) string++, prefix++; return *prefix == '\0'; } /* accepts only nonempty matches starting at the beginning of a word */ const char *string_match(register const char *src, register const char *sub) { if(*sub != '\0') { while(*src) { if(string_prefix(src, sub)) return src; /* else scan to beginning of next word */ while(*src && isalnum(*src)) src++; while(*src && !isalnum(*src)) src++; } } return 0; } /* * pronoun_substitute() * * %-type substitutions for pronouns * * %s/%S for subjective pronouns (he/she/it, He/She/It) * %o/%O for objective pronouns (him/her/it, Him/Her/It) * %p/%P for possessive pronouns (his/her/its, His/Her/Its) * %n for the player's name. */ const char *pronoun_substitute(dbref player, char *str, dbref privs) { static char result[BUFFER_LEN]; char temp[BUFFER_LEN]; char c; int gend; const int none = GENDER_UNASSIGNED; const static char *subjective[4] = { "", "it", "she", "he" }; const static char *possessive[4] = { "", "its", "her", "his" }; const static char *objective[4] = { "", "it", "her", "him" }; const static char *reflexive[4] = { "", "itself", "herself", "himself" }; const static char *absolute[4] = { "", "its", "hers", "his" }; *result = '\0'; if ((privs < 0) || (privs >= db_top)) privs = 1; /* figure out player gender */ gend = genderof(player); while (*str) { *temp = '\0'; switch(*str) { case '[': str++; exec(&str, temp, privs, player, 0); if (*str == ']') str++; break; case '%': c = *(++str); switch(c) { case '%': strcpy(temp, "%"); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (awptr[c - '0']) strcpy(temp, awptr[c - '0']); break; case 'v': case 'V': { int a; char x[5]; a = toupper(str[1]); if ((a < 'A') || (a > 'Z')) break; if (*str) str++; *x = 'v'; *(x+2) = '\0'; *(x+1) = a; if(get_attr(privs, x)) strcpy(temp, get_attr(privs, x)); } break; case 'a': case 'A': if(gend == none) sprintf(temp, "%s's", NAME(player)); else strcpy(temp, absolute[gend]); break; case 'r': case 'R': strcpy(temp, (gend == none) ? NAME(player) : reflexive[gend]); break; case 's': case 'S': strcpy(temp, (gend == none) ? NAME(player) : subjective[gend]); break; case 'p': case 'P': if (gend == none) sprintf(temp, "%s's", NAME(player)); else strcpy(temp, possessive[gend]); break; case 'o': case 'O': strcpy(temp, (gend == none) ? NAME(player) : objective[gend]); break; case 'n': case 'N': strcpy(temp, NAME(player)); break; case '#': sprintf(temp, "#%d", (int) player); break; default: break; } if(isupper(c) && islower(*temp)) *temp = toupper(*temp); if (*str) str++; break; case '\\': /* check for escape */ if(str[1]) str++; sprintf(temp, "%c", *str++); break; default: sprintf(temp, "%c", *str++); break; } if(strlen(temp) + strlen(result) < BUFFER_LEN) strcat(result, temp); } return result; } char *alloc_string(const char *string) { char *s; /* NULL, "" -> NULL */ if(string == 0 || *string == '\0') return 0; if((s = (char *) malloc(strlen(string)+5)) == 0) { abort(); } strcpy(s, string); return s; } char *alloc_ec_string(const char *what) { char *x; x = alloc_string(what); if(x) return x; x = alloc_string("X"); /* easiest thing */ *x = '\0'; /*yep, easiest thing */ return x; } struct shared_string * alloc_prog_string(const char *s) { struct shared_string *ss; int length; if(s == NULL || *s == '\0') return(NULL); length = strlen(s); if((ss = (struct shared_string *) malloc(sizeof(struct shared_string) + length)) == NULL) abort(); ss->links = 1; ss->length = length; bcopy(s, ss->data, ss->length + 1); return(ss); } /* function to split up a list given a seperator */ /* note str will get hacked up */ char * parse_up(char **str, char *delimit) { int deep = 0; char *s = *str, *os = *str; if (!*s) return (NULL); while (*s && (*s != *delimit)) { if (*s++ == '{') { deep = 1; while (deep && *s) switch (*s++) { case '{': deep++; break; case '}': deep--; break; } } } if (*s) *s++ = 0; *str = s; return (os); }