/* * String utilities needed throughout the Hugs codebase. */ #include "prelude.h" #include "storage.h" #include "connect.h" #include "errors.h" #include "strutil.h" #include "char.h" /* -------------------------------------------------------------------------- * String manipulation routines: * ------------------------------------------------------------------------*/ String strCopy(s) /* make malloced copy of a string */ String s; { if (s) { char *t; if ((t=(char *)malloc(strlen(s)+1))==0) { ERRMSG(0) "String storage space exhausted" EEND; } strcpy(t, s); return t; } return NULL; } String strnCopy(s,n) /* make malloced copy of a substring */ String s; Int n; { if (s) { char *t; if ((Int)strlen(s) < n) n = strlen(s); if ((t=(char *)malloc(n+1))==0) { ERRMSG(0) "String storage space exhausted" EEND; } strncpy(t, s, n); t[n] = '\0'; return t; } return NULL; } /* Given a string containing a possibly qualified name, * split it up into a module and a name portion. */ Void splitQualString(nm, pMod, pName) String nm; String* pMod; String* pName; { String dot; /* Find the last occurrence of '.' preceded by an identifier */ dot = nm + strlen(nm) - 1; while (dot != nm && !(*dot == '.' && isIn(dot[-1],IDAFTER))) dot--; if (dot == nm) { *pMod = NULL; *pName = nm; } else { /* The module portion consists of everything upto the last dot. */ *pMod = strnCopy(nm, dot - nm); /* Everything after the last '.' is the name string */ *pName = dot+1; } } /* Cheap&cheerful expandable strings / StringBuilders. * * Note: I'm willfully breaking the convention of using K&R style * function declarations here. Their time has come and gone. */ struct StringBuilder { unsigned int len; unsigned int size; char* buf; }; #define INITIAL_BUILDER_SIZE 200 static Bool expandStringBuilder Args((StringBuilder* b, unsigned int newSz)); /* * Function: newStringBuilder(sz) * * Allocate a new StringBuilder object, giving its * initial buffer size 'sz'. If sz == 0, the initial size * is set to INITIAL_BUILDER_SIZE.. * */ StringBuilder* newStringBuilder ( unsigned int sz ) { StringBuilder* b = (StringBuilder*)malloc(sizeof(StringBuilder)); if (!b) return NULL; b->size = ( sz == 0 ? INITIAL_BUILDER_SIZE : sz); b->len = 0; b->buf = (char*)malloc(sizeof(char)*b->size); if (!b->buf) { free(b); return NULL; } *(b->buf) = '\0'; return b; } /* * Function: expandStringBuilder(builder, newSz) * * Internal function for expanding a StringBuilder's internal * buffer to 'newSz'. Along with expansion the old contents of * the buffer is copied over. * * Returns TRUE if successful. */ static Bool expandStringBuilder(StringBuilder* b, unsigned int newSz) { char* buf; if (!b) return FALSE; if (b->size > newSz) return FALSE; buf = realloc(b->buf, newSz); if (!buf) return FALSE; b->size = newSz; b->buf = buf; return TRUE; } /* * Function: prependString(builder, str) * * The preferred usage mode for StringBuilders is to * concatenate stuff at the back, but prependString() * handles addition at the other end. * * Returns TRUE if successful. */ Bool prependString(StringBuilder* b, char* str) { unsigned int len, newLen; if (!b) return FALSE; if (!str) return TRUE; len = strlen(str); newLen = b->len + len; if (len==0) return TRUE; if ( newLen >= b->size ) { unsigned int newSz = b->size*2; if ( newSz < newLen ) { newSz = newLen; } if ( !expandStringBuilder(b, newSz) ) { return FALSE; } } /* shift the buffer down to make room for 'str' */ memcpy(b->buf+len, b->buf, b->len+1); memcpy(b->buf, str, len-1); b->len = newLen; return TRUE; } /* * Function: appendString(builder, str) * * Append 'str' to the back of 'builder', expanding its * buffer to accommodate the added string, if needs be. * * Returns TRUE if successful. */ Bool appendString(StringBuilder* b, char* str) { unsigned int len, newLen; if (!b) return FALSE; if (!str) return TRUE; len = strlen(str); newLen = b->len + len; if (len==0) return TRUE; if ( newLen >= b->size ) { unsigned int newSz = b->size*2; if ( newSz < newLen ) { newSz = newLen; } if ( !expandStringBuilder(b, newSz) ) { return FALSE; } } memcpy(b->buf+b->len,str,len+1); b->len = newLen; return TRUE; } /* * Function: appendStringFormat(builder, fmt, arg) * * This function provides an extremely limited form of * sprintf()-style format strings, allowing the substitution * of 'arg' zero or more times via the format string 'fmt': * * appendStringFormat(builder, "-P%s -Y%s", "foo"); * * is equivalent to * * appendString(builder, "-Pfoo -Yfoo"); * * Returns TRUE if successful. */ Bool appendStringFormat(StringBuilder* b, char* fmt, char* arg) { char* prev = fmt; char* ptr = fmt; char tmp; if (!b) return FALSE; while ( (ptr = strchr(ptr, '%')) ) { /* Append verbatim text from the format string */ tmp = *ptr; *ptr = '\0'; appendString(b, prev); *ptr = tmp; if ( ptr[1] != '%' ) { /* Not an escaped occurrence of '%' */ switch (ptr[1]) { case 's': appendString(b, arg); ptr += 2; break; default: fprintf(stderr,"Unsupported format specifier, %%%c; ignoring", ptr[1]); ptr += 2; break; } } else { if (ptr[1] != '\0') { ptr += 2; } } prev = ptr; } appendString(b,prev); return TRUE; } /* * Function: toString(builder) * * Returns a pointer to the builder's internal buffer, i.e., * a copy is not made (=> the caller isn't passed the * responsibility of freeing the returned string.) * * */ char* toString(StringBuilder* b) { if (!b) return NULL; return (b->buf); } /* * Function: freeStringBuilder(builder) * * Free up a StringBuilder object. */ void freeStringBuilder(StringBuilder* b) { if (!b) return; if (b->buf) free(b->buf); b->buf = NULL; free(b); }