/* $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);
}