293 lines · 6.0 KB · C
RawDownload
/* * 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 BoolexpandStringBuilder(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. */BoolprependString(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. */BoolappendString(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. */BoolappendStringFormat(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. */voidfreeStringBuilder(StringBuilder* b){    if (!b) return;    if (b->buf) free(b->buf);    b->buf = NULL;    free(b);}