ftp.nice.ch/pub/next/connectivity/infosystems/WAIStation.1.9.6.N.b.tar.gz#/WAIS/ir/cutil.c

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.