This is cutil.c in view mode; [Download] [Up]
/* Wide AREA INFORMATION SERVER SOFTWARE No guarantees or restrictions. See the readme file for the full standard disclaimer. 3.26.90 Harry Morris, morris@think.com 4.11.90 HWM - generalized conditional includes (see c-dialect.h) 7/19/91 speed up substrcmp by ses@ccgr.technion.ac.il (Simon E Spero) * * $Log: cutil.c,v $ * Revision 1.24 92/03/28 19:53:39 jonathan * Removed useless ifdef BSD in cprintf * * Revision 1.23 92/03/07 19:44:39 jonathan * ANSIfied arguments. * * Revision 1.22 92/03/04 16:14:23 jonathan * Added include <ctype.h> for isalnum. * * Revision 1.21 92/02/21 11:03:15 jonathan * Fixed $Log. * * Revision 1.20 92/02/21 11:02:02 jonathan * Added wais_log_level, RCSIdent * * Revision 1.19 92/02/16 21:24:54 jonathan * Added code for vprintf, if needed (like for old BSD). * * Revision 1.18 92/02/12 14:33:26 morris * made string_downcase not die when passed NULL * * Revision 1.17 92/02/12 13:16:21 jonathan * Added $Log so RCS will put the log message in the header * * */ #ifndef lint static char *RCSid = "$Header: /proj/wais/wais-8-b5/ir/RCS/cutil.c,v 1.24 92/03/28 19:53:39 jonathan Exp $"; #endif #define _C_C_util_ #include "cutil.h" #include "panic.h" #include <ctype.h> #include <string.h> #ifdef M_XENIX /* perhaps this should be in ustubs.h */ #include <malloc.h> char* calloc(); #endif /* def M_XENIX */ /*----------------------------------------------------------------------*/ /*#define MEMORY_ACCOUNTING*/ #ifdef MEMORY_ACCOUNTING #undef s_checkPtr #define s_checkPtr(ptr) fs_checkPtr(ptr) static FILE* memRecord = NULL; static void prepMemAcct _AP((void)); static void prepMemAcct() { if (memRecord == NULL) memRecord = s_fopen("MemoryAccounting","w"); } static void flushMemAcct _AP((void)); static void flushMemAcct() { fflush(memRecord); } #define tickles 0 static char* badPtr = (char*)-1; static size_t badSize = -1; #endif /* def MEMORY_ACCOUNTING */ /*----------------------------------------------------------------------*/ void fs_checkPtr(ptr) void* ptr; /* If the ptr is NULL, give an error */ { #ifdef MEMORY_ACCOUNTING static char** ptrs = NULL; long i; static Boolean doneSetup = false; if (doneSetup == false) { #ifdef THINK_C Debugger(); #endif /* def THINK_C */ doneSetup = true; } #endif /* def MEMORY_ACCOUNTING */ if (ptr == NULL) panic("checkPtr found a NULL pointer"); #ifdef MEMORY_ACCOUNTING /* look for specific ptr (useful when tracking un-freed memory) */ if (ptr == badPtr) warn("checking found bad ptr"); /* tickle a memory bug */ if (ptrs == NULL && tickles > 0) ptrs = (char**)malloc((size_t)tickles * sizeof(char*)); for (i = 0; i < tickles; i++) { ptrs[i] = malloc((size_t)5); } for (i = 0; i < tickles; i++) { free(ptrs[i]); } #endif /* def MEMORY_ACCOUNTING */ } /*----------------------------------------------------------------------*/ void* fs_malloc(size) size_t size; /* does safety checks and optional accounting */ { register void* ptr = NULL; if(!size) return(NULL); #ifdef THINK_C ptr = (void*)NewPtr((long)size); s_checkPtr(ptr); memset(ptr,0,(size_t)size); /* zero it */ #else ptr = (void*)calloc((size_t)size,(size_t)1); s_checkPtr(ptr); #endif #ifdef MEMORY_ACCOUNTING /* look for specific size (useful when tracking un-freed memory) */ if (size == badSize) warn("bad size in malloc"); prepMemAcct(); fprintf(memRecord,"malloced %lu bytes at %lu\n",size,ptr); flushMemAcct(); #endif return(ptr); } /*----------------------------------------------------------------------*/ void* fs_realloc(ptr,size) void* ptr; size_t size; /* does safety checks and optional accounting note - we don't know how big ptr's memory is, so we can't ensure that any new memory allocated is NULLed! */ { register void* nptr = NULL; if (ptr == NULL) /* this is really a malloc */ return(s_malloc(size)); #ifdef THINK_C nptr = NewPtr(size); /* need to make a copy */ s_checkPtr(nptr); BlockMove(ptr,nptr,size); /* move the old contents into it */ DisposPtr(ptr); /* get rid of the old ones */ #else nptr = (void*)realloc(ptr,size); s_checkPtr(ptr); #endif #ifdef MEMORY_ACCOUNTING /* look for specific size (useful when tracking un-freed memory) */ if (size == badSize) warn("bad size in realloc"); prepMemAcct(); fprintf(memRecord,"realloced %lu bytes at %lu from %lu\n",size,nptr,ptr); flushMemAcct(); #endif return(nptr); } /*----------------------------------------------------------------------*/ void fs_free(ptr) void* ptr; /* does safety checks and optional accounting */ { #ifdef MEMORY_ACCOUNTING prepMemAcct(); /* note that the sizeof a pointer is always 4. If only we could find out how much space that pointer was pointing to. Oh well, this is a place holder for now */ fprintf(memRecord,"freed %lu bytes at %lu\n",(size_t)sizeof(ptr),ptr); flushMemAcct(); /* look for specific ptr (useful when tracking un-freed memory) */ if (ptr == badPtr) warn("bad ptr in free"); #endif if (ptr != NULL) /* some non-ansi compilers/os's cant handle freeing null */ { /* if we knew the size of this block of memory, we could clear it - oh well */ #ifdef THINK_C DisposPtr(ptr); #else free(ptr); #endif } } /*----------------------------------------------------------------------*/ char* s_strdup(s) char* s; /* return a copy of s. This is identical to the standard library routine strdup(), except that it is safe. If s == NULL or malloc fails, appropriate action is taken. */ { unsigned long len; char* copy = NULL; if (s == NULL) /* saftey check to postpone stupid errors */ return(NULL); len = strlen(s); /* length of string - terminator */ copy = (char*)s_malloc((size_t)(sizeof(char)*(len + 1))); strncpy(copy,s,len + 1); return(copy); } /*----------------------------------------------------------------------*/ char* fs_strncat(dst,src,maxToAdd,maxTotal) char* dst; char* src; size_t maxToAdd; size_t maxTotal; /* like strncat, except the fourth argument limits the maximum total length of the resulting string */ { size_t dstSize = strlen(dst); size_t srcSize = strlen(src); if (dstSize + srcSize < maxTotal) /* use regular old strncat */ return(strncat(dst,src,maxToAdd)); else { size_t truncateTo = maxTotal - dstSize - 1; char saveChar; char* result = NULL; saveChar = src[truncateTo]; src[truncateTo] = '\0'; result = strncat(dst,src,maxToAdd); src[truncateTo] = saveChar; return(result); } } /*----------------------------------------------------------------------*/ char* fs_strncpy(s1, s2, n) char* s1; char* s2; long n; /* like strncpy except that it guarentees that the destination string ends with a NULL at position n. */ { s1[n-1] = '\0'; return(strncpy(s1, s2, n - 1)); } /*----------------------------------------------------------------------*/ typedef long (longfunc) _AP((long c)); char* strtokf(s1,isDelimiter) char* s1; longfunc *isDelimiter; /* really *isDelimiter() */ /* This function is exactly like strtok, except that instead of passing a delimiter string, you pass a function that decides if a character is a delimiter or not, returning IS_DELIMITER or NOT_DELIMITER respecively. Note that passing a NULL delimiter function will cause the last delimiter to be used. */ { static char* searchStr = NULL; static longfunc *delimiterFunc; long i; char* startTok = NULL; if (s1 != NULL) /* passing s1 = NULL says use the last pos */ searchStr = s1; if (isDelimiter != NULL) delimiterFunc = isDelimiter; if (searchStr == NULL || searchStr[0] == '\0') return(NULL); /* nothing left to search */ if (delimiterFunc == NULL) return(NULL); /* no delimiter to search with */ /* find the start of the next token */ for (i = 0; searchStr[i] != '\0'; i++) { if ((*delimiterFunc)((long)searchStr[i]) == NOT_DELIMITER) break; } if (searchStr[i] == '\0') return(NULL); /* read to end of search string */ else startTok = searchStr + i; /* remember the starting point for this token*/ /* find the end of the next token */ for (; searchStr[i] != '\0'; i++) { if ((*delimiterFunc)((long)searchStr[i]) == IS_DELIMITER) break; } /* if the end is a delimiter (and not just the end of the search string) replace it with '\0', and put searchStr just beyond it, otherwise put searchStr at the terminator. */ if (searchStr[i] != '\0') { searchStr[i] = '\0'; searchStr = searchStr + i + 1; } else searchStr = searchStr + i; return(startTok); } /*----------------------------------------------------------------------*/ char* strtokf_isalnum(s1) char* s1; /* This is a partially evaluated version of strtok_f */ { static char* searchStr = NULL; long i; char* startTok = NULL; if (s1 != NULL) /* passing s1 = NULL says use the last pos */ searchStr = s1; if (searchStr == NULL || searchStr[0] == '\0') return(NULL); /* nothing left to search */ /* find the start of the next token */ for (i = 0; searchStr[i] != '\0'; i++) { if (isalnum(searchStr[i])) break; } if (searchStr[i] == '\0') return(NULL); /* read to end of search string */ else startTok = searchStr + i; /* remember the starting point for this token*/ /* find the end of the next token */ for (; searchStr[i] != '\0'; i++) { if (!isalnum(searchStr[i])) break; } /* if the end is a delimiter (and not just the end of the search string) replace it with '\0', and put searchStr just beyond it, otherwise put searchStr at the terminator. */ if (searchStr[i] != '\0') { searchStr[i] = '\0'; searchStr = searchStr + i + 1; } else searchStr = searchStr + i; return(startTok); } /*----------------------------------------------------------------------*/ #ifdef ANSI_LIKE /* use ansi varargs */ long cprintf(boolean print, char* format, ...) /* just like printf, but only prints if the first argument = 1 */ { va_list ap; /* the variable arguments */ if (print == 1) { long res; va_start(ap,format); /* init ap */ res = vprintf(format,ap); /* print the contents */ va_end(ap); /* free ap */ return(res); } else return(0); } #else /* use k&r varargs */ long cprintf(va_alist) va_dcl /* just like printf, but only prints if the first argument = 1 */ { va_list ap; /* the variable arguments */ boolean print; long res; va_start(ap); /* init ap */ print = va_arg(ap,boolean); /* get the condition */ if (print == 1) { char* format = va_arg(ap,char*); /* get the format */ res = vprintf(format,ap); /* print the contents */ } else res = 0; va_end(ap); /* free ap */ return(res); } #endif extern char* log_file_name; extern FILE* logfile; /* waislog - a new and improved logging facility. first two arguments are important, the rest is text. arg1: priority. If priority > log_level (some global), output this message arg2: message code. This is the kind of message (search, retrieval, etc). */ #ifdef ANSI_LIKE /* use ansi varargs */ void waislog(long priority, long message, char* format, ...) /* just like printf, but prints to the logfile, with PID and time. */ { va_list ap; /* the variable arguments */ if(priority <= wais_log_level) { if(logfile == NULL && log_file_name != NULL) logfile = fopen(log_file_name, "a"); if(logfile) { va_start(ap, format); fprintf(logfile, "%d: %d: %s: %d: ", wais_pid, log_line++, printable_time(), message); vfprintf(logfile, format,ap); /* print the contents */ fprintf(logfile, "\n"); fflush(logfile); va_end(ap); /* free ap */ } if(logfile != NULL && logfile != stderr) { fclose(logfile); logfile = NULL; } } } #else /* use k&r varargs */ void waislog(va_alist) va_dcl /* just like printf, but prints to the logfile, with PID and time. */ { va_list ap; /* the variable arguments */ char* format; static long line = 0; int priority, message; va_start(ap); /* init ap */ priority = va_arg(ap, int); if(priority <= wais_log_level) { if(logfile == NULL && log_file_name != NULL) logfile = fopen(log_file_name, "a"); if(logfile) { message = va_arg(ap, int); fprintf(logfile, "%d: %d: %s: %d: ", wais_pid, line++, printable_time(), message); format = va_arg(ap,char*); /* get the format */ vfprintf(logfile, format,ap); /* print the contents */ fprintf(logfile, "\n"); fflush(logfile); } if(logfile != NULL && logfile != stderr) { fclose(logfile); logfile = NULL; } } va_end(ap); /* free ap */ } #endif /* ANSI_LIKE */ /*----------------------------------------------------------------------*/ void warn(message) char* message; { #ifdef THINK_C Debugger(); #else printf("%s\n<press return to continue>\n",message); getchar(); #endif } /*----------------------------------------------------------------------*/ boolean substrcmp(string1,string2) char *string1, *string2; { /* compares the strings up until one of then ends. * returns true if they are the same, false if not. */ register char *a, *b; a = string1; b = string2; while (*a && *b) if(*a++ != *b++) return false; return true; } /*----------------------------------------------------------------------*/ char *printable_time() { static char *string; time_t tptr; time(&tptr); string = ctime(&tptr); if(string){ if(string[strlen(string)-1] == '\n') string[strlen(string)-1] = '\0'; return(string+4); } else return("Time Unknown"); } /*----------------------------------------------------------------------*/ char char_downcase(long_ch) unsigned long long_ch; { unsigned char ch = long_ch & 0xFF; /* just want one byte */ /* when ansi is the way of the world, this can be tolower */ return (((ch >= 'A') && (ch <= 'Z')) ? (ch + 'a' -'A') : ch); } char *string_downcase(word) char *word; { long i = 0; if (word == NULL) return(NULL); while(word[i] != '\0') { word[i] = char_downcase((unsigned long)word[i]); i++; } return(word); } /*----------------------------------------------------------------------*/ /* parsing arguments functions */ char *next_arg(argc,argv) int *argc; char ***argv; /* Returns NULL when it is out of arguments, This side effects both argc and argv. argc always contains the number of arguments left. The first returned is the command name. */ { if((*argc)-- > 0) return(*((*argv)++)); else return(NULL); } /*----------------------------------------------------------------------*/ char *peek_arg(argc,argv) int *argc; char ***argv; /* Returns the next argument without popping it. Returns NULL when it is out of arguments. */ { if((*argc) > 0) return(**argv); else return(NULL); } /*----------------------------------------------------------------------*/ #ifdef THINK_C #include <EventMgr.h> #undef MAX_FILE_NAME_LEN #ifdef WAIStation #include "CRetrievalApp.h" #endif /* def WAIStation */ #endif /* def THINK_C */ void beFriendly() /* this routine is called during time intensive operations on single processing machines (macs and DOS). It gives time to other processes */ { #ifdef never #ifdef THINK_C EventRecord macEvent; /* an event */ static RgnHandle mouseRgn = NULL; /* region for mouse moved events */ long sleepTime; /* max time between events */ #ifdef WAIStation gApplication->FrobWaitCursor(); #endif /* def WAIStation */ if (mouseRgn == NULL) mouseRgn = NewRgn(); /* do we need to set its value? */ sleepTime = 5; /* arbitrary - a tech note recommends < 50 */ WaitNextEvent(everyEvent,&macEvent,sleepTime,mouseRgn); #endif /* def THINK_C */ #endif } #ifdef BSD #define NEED_VPRINTF #endif #ifdef NEED_VPRINTF /* Portable vsprintf by Robert A. Larson <blarson@skat.usc.edu> */ /* Copyright 1989 Robert A. Larson. * Distribution in any form is allowed as long as the author * retains credit, changes are noted by their author and the * copyright message remains intact. This program comes as-is * with no warentee of fitness for any purpouse. * * Thanks to Doug Gwen, Chris Torek, and others who helped clarify * the ansi printf specs. * * Please send any bug fixes and improvments to blarson@skat.usc.edu . * The use of goto is NOT a bug. */ /* Feb 7, 1989 blarson First usenet release */ /* This code implements the vsprintf function, without relying on * the existance of _doprint or other system specific code. * * Define NOVOID if void * is not a supported type. * * Two compile options are available for efficency: * INTSPRINTF should be defined if sprintf is int and returns * the number of chacters formated. * LONGINT should be defined if sizeof(long) == sizeof(int) * * They only make the code smaller and faster, they need not be * defined. * * UNSIGNEDSPECIAL should be defined if unsigned is treated differently * than int in argument passing. If this is definded, and LONGINT is not, * the compiler must support the type unsingned long. * * Most quirks and bugs of the available sprintf fuction are duplicated, * however * in the width and precision fields will work correctly * even if sprintf does not support this, as will the n format. * * Bad format strings, or those with very long width and precision * fields (including expanded * fields) will cause undesired results. */ #ifdef OSK /* os9/68k can take advantage of both */ #define LONGINT #define INTSPRINTF #endif /* This must be a typedef not a #define! */ #ifdef NOVOID typedef char *pointer; #else typedef void *pointer; #endif #ifdef INTSPRINTF #define Sprintf(string,format,arg) (sprintf((string),(format),(arg))) #else #define Sprintf(string,format,arg) (\ sprintf((string),(format),(arg)),\ strlen(string)\ ) #endif typedef int *intp; int vsprintf(dest, format, args) char *dest; register char *format; va_list args; { register char *dp = dest; register char c; register char *tp; char tempfmt[64]; #ifndef LONGINT int longflag; #endif tempfmt[0] = '%'; while( (c = *format++) != 0) { if(c=='%') { tp = &tempfmt[1]; #ifndef LONGINT longflag = 0; #endif continue_format: switch(c = *format++) { case 's': *tp++ = c; *tp = '\0'; dp += Sprintf(dp, tempfmt, va_arg(args, char *)); break; case 'u': case 'x': case 'o': case 'X': #ifdef UNSIGNEDSPECIAL *tp++ = c; *tp = '\0'; #ifndef LONGINT if(longflag) dp += Sprintf(dp, tempfmt, va_arg(args, unsigned long)); else #endif dp += Sprintf(dp, tempfmt, va_arg(args, unsigned)); break; #endif case 'd': case 'c': case 'i': *tp++ = c; *tp = '\0'; #ifndef LONGINT if(longflag) dp += Sprintf(dp, tempfmt, va_arg(args, long)); else #endif dp += Sprintf(dp, tempfmt, va_arg(args, int)); break; case 'f': case 'e': case 'E': case 'g': case 'G': *tp++ = c; *tp = '\0'; dp += Sprintf(dp, tempfmt, va_arg(args, double)); break; case 'p': *tp++ = c; *tp = '\0'; dp += Sprintf(dp, tempfmt, va_arg(args, pointer)); break; case '-': case '+': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '.': case ' ': case '#': case 'h': *tp++ = c; goto continue_format; case 'l': #ifndef LONGINT longflag = 1; *tp++ = c; #endif goto continue_format; case '*': tp += Sprintf(tp, "%d", va_arg(args, int)); goto continue_format; case 'n': *va_arg(args, intp) = dp - dest; break; case '%': default: *dp++ = c; break; } } else *dp++ = c; } *dp = '\0'; return dp - dest; } int vfprintf(dest, format, args) FILE *dest; register char *format; va_list args; { register char c; register char *tp; register int count = 0; char tempfmt[64]; #ifndef LONGINT int longflag; #endif tempfmt[0] = '%'; while(c = *format++) { if(c=='%') { tp = &tempfmt[1]; #ifndef LONGINT longflag = 0; #endif continue_format: switch(c = *format++) { case 's': *tp++ = c; *tp = '\0'; count += fprintf(dest, tempfmt, va_arg(args, char *)); break; case 'u': case 'x': case 'o': case 'X': #ifdef UNSIGNEDSPECIAL *tp++ = c; *tp = '\0'; #ifndef LONGINT if(longflag) count += fprintf(dest, tempfmt, va_arg(args, unsigned long)); else #endif count += fprintf(dest, tempfmt, va_arg(args, unsigned)); break; #endif case 'd': case 'c': case 'i': *tp++ = c; *tp = '\0'; #ifndef LONGINT if(longflag) count += fprintf(dest, tempfmt, va_arg(args, long)); else #endif count += fprintf(dest, tempfmt, va_arg(args, int)); break; case 'f': case 'e': case 'E': case 'g': case 'G': *tp++ = c; *tp = '\0'; count += fprintf(dest, tempfmt, va_arg(args, double)); break; case 'p': *tp++ = c; *tp = '\0'; count += fprintf(dest, tempfmt, va_arg(args, pointer)); break; case '-': case '+': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '.': case ' ': case '#': case 'h': *tp++ = c; goto continue_format; case 'l': #ifndef LONGINT longflag = 1; *tp++ = c; #endif goto continue_format; case '*': tp += Sprintf(tp, "%d", va_arg(args, int)); goto continue_format; case 'n': *va_arg(args, intp) = count; break; case '%': default: putc(c, dest); count++; break; } } else { putc(c, dest); count++; } } return count; } vprintf(format, args) char *format; va_list args; { return vfprintf(stdout, format, args); } #endif /*----------------------------------------------------------------------*/
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.