/* Copyright (c) 1993 Stephen F. White */ #include "cool.h" #include "proto.h" #include "servers.h" String *string_new (int len) { String *new; int newlen = MAX (len, STRING_INIT_SIZE); new = (String *) cool_malloc (sizeof (String) + newlen + 1); new->mem = newlen; new->len = 0; new->ref = 1; new->str = (char *) new + sizeof (String); new->str[0] = '\0'; return new; } #ifndef INLINE String *string_dup (String * s) { s->ref++; return s; } void string_free (String * s) { s->ref--; if (s->ref == 0) { FREE (s); } } #endif /* * string_cpy() - copy a char * into a String struct */ String *string_cpy (const char *s) { String *new; new = string_new (strlen (s)); new = string_cat (new, s); return new; } String *string_ncpy (const char *s, int len) { String *new; new = string_new (len + 1); strncpy (new->str, s, len); new->len = len; new->str[len] = '\0'; return new; } static String *string_extend_to (String * str, int mem) { String *new; if (!str) return 0; if (!str->str) return 0; if (mem <= str->mem) { return str; } #ifdef STRING_DOUBLING while (mem > str->mem) { str->mem = (str->mem + sizeof (String)) * 2 - sizeof (String); } #else str->mem = (mem / STRING_GROW_BY + 1) * STRING_GROW_BY; #endif new = string_new (str->mem); new->str[str->len] = '\0'; strcpy (new->str, str->str); new->len = strlen (new->str); new->str[new->len] = '\0'; FREE (str); return new; } String *string_catc (String * str, char c) { if (!str) return 0; if (str->len + 2 > str->mem) { str = string_extend_to (str, str->len + 2); } str->str[str->len++] = c; str->str[str->len] = '\0'; return str; } String *string_cat (String * str, const char *s) { int len; if (!str) return 0; if (!str->str) return 0; if (!s) return 0; len = str->len + strlen (s); if (len + 1 > str->mem) { str = string_extend_to (str, len + 1); } strcat(str->str, s); str->len = len; str->str[len] = '\0'; return str; } String *string_catnum (String * str, int num) { int len; if (!str) return 0; if (!str->str) return 0; len = str->len + INT_SIZE; if (len + 1 > str->mem) { str = string_extend_to (str, len + 1); } sprintf (str->str + str->len, "%d", num); str->len = strlen (str->str); return str; } String *string_catobj (String * str, Objid obj, int full) { const char *servername; int len; if (!str) return 0; servername = serv_id2name (obj.server); len = str->len + INT_SIZE + 2 + (full ? strlen (servername) : 0); if (len + 1 > str->mem) { str = string_extend_to (str, len + 1); } if (full) { sprintf (str->str + str->len, "#%d@%s", obj.id, servername); } else { sprintf (str->str + str->len, "#%d", obj.id); } str->len = strlen (str->str); return str; } String *string_indent_cat (String * str, int indent, const char *s) { int len; char *c; if (!str) return 0; len = str->len + indent + strlen (s); if (len + 1 > str->mem) { str = string_extend_to (str, len + 1); } c = str->str + str->len; for (; indent; indent--) { *c++ = ' '; } strcpy (c, s); str->len = len; return str; } String *string_backslash (String * str, const char *s) { int len; const char *t; char *r; if (!str) return 0; /* * calculate required length, including backslashes * NOTE: CR-LF turns into \n, both of which are two chars, so no * length adjustment is needed */ len = str->len; for (t = s; *t; t++, len++) { if ( *t == '"' || *t == '\t') { len++; } } /* * extend string, if we have to */ if (len + 1 > str->mem) { str = string_extend_to (str, len + 1); } r = str->str + str->len; /* skip to end of string */ while( *s ) { switch (*s) { case '\r': s++; /* ignore \r; handle \n instead */ case '\n': *r++ = '\\'; *r++ = 'n'; break; case '\t': *r++ = '\\'; *r++ = 't'; break; case '\\': *r++ = *s; *r++ = *s; break; case '"': *r++ = '\\'; default: *r++ = *s; break; } s++; } *r = '\0'; str->len = strlen(str->str); return str; } /*********** * string_output * By Robin Powell * * Turn literal '\''n''s into \r\n ***********/ String * string_output( String *str ) { char *r,*s; if (!str) return 0; if (!str->str) return 0; s = str->str; r = str->str; while( *s ) { switch(*s) { case '\\': s++; switch(*s) { case 'n': /* Replaces the two chars '\' and 'n' */ *r = '\r'; r++; *r = '\n'; r++; break; case '\\': *r = '\\'; r++; break; default: *r = '\\'; r++; *r = *s; r++; break; } break; default: *r++ = *s; break; } if( *s ) s++; } *r = '\0'; str->len = strlen(str->str); return str; } /*********** * string_fixquote * By Robin Powell * * Removes " pairs if the string starts with ". Truncates at the second ". * If the string starts with ", also turn \" to ". * Turn \n to \r\n. ***********/ String * string_fixquote( String *str ) { char *r,*s; int in_quote = 0; int first_char = 0; /* Set if we've seen a non-blank char */ if (!str) return 0; if (!str->str) return 0; s = str->str; r = str->str; while( *s ) { if( first_char == 0 && isspace((int)*s) ) { s++; continue; } /* Not using a switch here so breaks could be used properly */ if( *s == '"' ) { if( in_quote == 1 ) { /* Found matching quote */ break; } else { if( first_char == 0 ) { in_quote = 1; s++; continue; } } } if( *s == '\\' ) { s++; switch(*s) { case '"': if( !in_quote ) { *r = '\\'; r++; } *r = '"'; r++; s++; break; case 'n': /* Replaces the two chars '\' and 'n' */ *r = '\r'; r++; *r = '\n'; r++; s++; break; default: *r = '\\'; r++; *r = *s; r++; s++; break; } continue; } first_char = 1; *r++ = *s; s++; } *r = '\0'; str->len = strlen(str->str); return str; } String *string_pad (String * str, int padlen, char tok) { int len; char *s; if (!str) return 0; len = str->len + padlen; if (len + 1 > str->mem) { str = string_extend_to (str, len + 1); } s = str->str + str->len; while (padlen--) { *s++ = tok; } *s = '\0'; str->len = len; return str; } String *string_prepad (String * str, int padlen, char tok) { int len; char *s, *d; if (!str) return 0; len = str->len + padlen; if (len + 1 > str->mem) { str = string_extend_to (str, len + 1); } for (s = str->str + str->len, d = s + padlen; s >= str->str;) { *d-- = *s--; } s = str->str; while (padlen--) { *s++ = tok; } str->len = len; return str; } String *string_strip_cr (String * str) { char *s1, *s2; if (!str) return 0; for (s1 = s2 = str->str; *s1; s1++) { if (*s1 != '\r') { *s2++ = *s1; } } *s2 = '\0'; /* terminate it */ str->len = s2 - str->str; return str; } /* string_strip_cr() */ /*********** * string_list * By Robin Powell * * Return a list of all the letters in a string, used in op_for. ***********/ List * string_list(String *str) { List *new = list_new(0); int i; MapPair *pair; for (i = 0; i < str->len; i++) { Var temp; temp.v.str = string_new(2); temp.type = STR; temp.v.str->str[0] = str->str[i]; temp.v.str->str[1] = '\0'; new = list_append(new, var_dup(temp), 0 ); } return new; }