|
|
/* misc.c - miscellanous routines
* * 06/16/88 MattS Created * * 10/15/89 MattS Added AutoDoc comment blocks */
#include <stdio.h>
#include <ctype.h>
#ifdef MSDOS
#include <io.h>
#include <stdlib.h>
#endif
#include <fcntl.h>
#include <malloc.h>
#include <string.h>
#include "misc.h"
#define FALSE 0
#define TRUE 1
/*
** Compare a string with a hi-bit terminates string */
#ifdef NOT_NEEDED
/*
* @doc MISC INTERNAL * * @func int | hb_strcmp | This function compares a string with a * hi-bit terminated string. (instead of zero terminated) * * @parm unsigned char * | str | Zero terminated string. * * @parm unsigned char * | hb_str | High-bit terminated string. * * @rdesc The return is the same as strcmp. * */ hb_strcmp(str, hb_str) register unsigned char *str, *hb_str; { unsigned char hbc;
for (;;) { hbc = *hb_str & (unsigned char)0x7f; if (hbc == *str) { if (*++str == 0) return (*hb_str & 0x80) ? 0 : -1; else if (*hb_str++ & 0x80) return 1; } else return *str - hbc; } }
/*
* @doc MISC * * @func int | hex_nyb | This function converts the hex character into * binary. * * @parm int | chr | The character to convert. * * @rdesc The return is the binary hex value of <p chr>. * */ int hex_nyb(chr) register int chr; { if (chr >= '0' && chr <= '9') return chr - '0'; else if (chr >= 'A' && chr <= 'Z') return chr - 'A' + 0xA; else return chr - 'a' + 0xA; }
/*
* @doc INTERNAL MISC * * @func int | hex_bytes | This function converts a hex string to binary. * * @parm char * | str | Specifies string to convert. * * @parm int | nbytes | Specifies length of string. * * @rdesc Returns binary value of hex string. * * @xref hex_nyb * */ int hex_bytes(str, nbytes) register char *str; register int nbytes; { register int ret = 0;
while (nbytes--) { ret <<= 4; ret += hex_nyb(*str++); } return ret; }
/*
* @doc INTERNAL MISC * * @func long | htoi | This function converts a hex string to a long. * * @parm char * | str | Specifies string to convert. * * @xref hex_bytes * */
/*
* Interpret an ASCII string as a hex number, convert to long int. */ long htoi(str) char *str; { register long ret = 0; register unsigned char ch;
while (ch = *str++) if (ch >= '0' && ch <= '9') ret = (ret << 4) + ch - '0'; else if (ch >= 'A' && ch <= 'Z') ret = (ret << 4) + ch - 'A' + 10; else if (ch >= 'a' && ch <= 'z') ret = (ret << 4) + ch - 'a' + 10; else return ret; return ret; }
/* nindex --
* */
/*
* * @doc INTERNAL MISC * * @func int | nindex | looks for pattern p in string s starting at position start. * * @parm char * | p | Specifies pattern. * * @parm char * | s | Specifies string. * * @parm int | start | Specifies starting offset in string. * * @rdesc It returns an index to the position AFTER p if it succeeds; else -1. */ int nindex(p,s,start) char p[]; char s[]; int start; { register int j = start; register int i; int match = -1; int nLineLen = strlen(s); int nPattLen = strlen(p);
while ( j < nLineLen ) { /*find first letter of pattern
*/ while (j < nLineLen) { if (p[0] == s[j++]) { /* found 1st char of pattern */ match = 1; /* toggle flag */ break; /* go on to next step */ } }
if (match == 1) { /* look for rest of pattern
*/ for (i = 1; (i < nPattLen) && (j < nLineLen) ; i++,j++) { if (p[i] != s[j]) { match = -1; /* pattern doesn't match: toggle flag */ break; /* stop looking */ } }
if (j >= nLineLen) /* if we're at end, it doesn't matter */ { match = -1; break; /* break main loop with flag = fail */ } else { if (match == 1) /* found the pattern */ { match = j; /* match points to char after pattern */ break; /* break main loop with flag = success */ } } } }
return(match); }
/*
* * @doc INTERNAL MISC * * @func int | parse | Split of the line, point <p fl> array to each record, records are seperated by * <p sep> charactor. * * @parm char * | cp | Specifies line. * * @parm char ** | fl | Specifies array of argument pointers. * * @parm char | sep | Specifies argument seperator character. * * @rdesc This function returns the number of fields it found. */ int parse(cp, fl, sep) register char *cp, **fl, sep; { register int nfields = 1;
*fl++ = cp; while (1) { if (*cp == sep) { nfields++; *fl++ = cp + 1; *cp = 0; } else if (*cp == '\n' || *cp == '\0') { *cp = 0; return nfields; } cp++; } }
/*
* * Progress routines * * */
long pinc, ploc, loc;
/*
* * @doc INTERNAL MISC * * @func void | init_progress | This function initializes the progress * indicator. * * @parm long | size | Specifies the total size. * * @xref show_progress * */ void init_progress(size) long size; { ploc = pinc = size / 80; loc = 0; }
/*
* * @doc INTERNAL MISC * * @func void | show_progress | This function displays the progress * according to the initialized value in <f init_progress>. * * @parm int | amount | Specifies the delta processed since last call * */ void show_progress(int amt) { if( (loc + amt) >ploc) { while( (loc + pinc) <= ploc+ amt) { loc+=pinc; fputc('.', stdout); fflush(stdout); } ploc += amt; } }
/*
** mem_to_long and long_to_mem are used to convert back and forth between * the byte-order independant representation of integers and the * the internal C format */
/*
* * @doc INTERNAL MISC * * @func long | mem_to_long | Used to convert back and forth between * the byte-order independant representation of integers and the * the internal C format. * * @parm unsigned char * |cp| Specifies the memory to convert. * * @parm short |nbytes | Specifies the number of bytes to convert. * * @rdesc This function returns the Local version of the value contained * in the memory location. * * @comm This function was meant to provide byte-order independence capability * in C code and was used in Microsoft Bookshelf and the Microsoft Library * products. * * @xref long_to_mem * */ long mem_to_long(cp, nbytes) register unsigned char *cp; register short nbytes; { register int i; register long ret = 0;
for (i = nbytes; i > 0;) { ret <<= 8; ret += cp[--i]; } return ret; }
/*
* * @doc INTERNAL MISC * * @func void | long_to_mem | This function is used to convert back and forth between * the byte-order independant representation of integers and the * the internal C format. * * @parm long | value | Specifies the value to save into the memory. * * @parm unsigned char * |cp| Specifies the memory buffer. * * @parm short |nbytes | Specifies the number of bytes to convert. * * @comm This function was meant to provide byte-order independence capability * in C code and was used in Microsoft Bookshelf and the Microsoft Library * products. * * @xref mem_to_long * */ void long_to_mem(val, cp, nbytes) register long val; register unsigned char *cp; register int nbytes; { register int i;
for (i = 0; i < nbytes; i++) { *cp++ = (unsigned char)val & (unsigned char)0xff; val >>= 8; } }
/*
** This function is available under Sun 3.2 UNIX but not on MS-DOS so I ** had to write it in order to use the index building tools under MS-DOS ** ** getopt(argc, argv, template) ** argc, argv are the arguments to main ** template is a string of legal arguemnt characters. ** if a character in the template is followed by a ':', this means ** that the option takes an additional argument which will either be the ** remainder of the argument string if this argument strings ended, ** the next argument. ** ** RETURNS: ** '?' on error, print usage and exit ** EOF when end of options is hit, use "optind" to get non option args ** chr means that option "chr" was specified and if it takes an ** additional argument, that would be in the string "optarg" ** ** Here is an example program which just echos back how it parsed the command ** line, using getopt. This template says the program has flags 'a' and 'b' ** and options 'c' and 'd'. Legal commmand lines would be: ** D>prog hello there folks ** D>prog -a hello folks ** D>prog -ab -chello -d there folks ** D>prog -abc hello -dthere folks ** ** extern char *optarg; ** extern int optind; ** char *my_template = "abc:d:"; ** ** main(argc, argv) ** char **argv; ** { ** int arg; ** ** while (arg = getopt(argv, argv, my_template)) ** if (optarg) ** printf("-%c %s\n", arg, optarg); ** else if (arg == '?') { ** printf("Argument error\n"); ** break; ** } else ** printf("-%c\n", arg); ** for (arg = optind; arg < argc - 1; arg++) ** printf("### %s\n", argv[arg]); ** } */
static int argNum; static char *optparse; int optind = 1; char *optarg;
getopt(argc, argv, template) int argc; char **argv, *template; { register char *arg, *tp;
optarg = NULL; if (!optparse) if (++argNum < argc) { arg = argv[argNum]; if (*arg != '-') { optind = argNum; return EOF; } optparse = arg + 1; } else return EOF; for (tp = template; *tp; tp++) if (*tp == *optparse) { if (tp[1] == ':') { if (optparse[1]) { optarg = optparse + 1; optparse = 0; } else if (++argNum == argc) return '?'; else optarg = argv[argNum]; } if (optparse && *++optparse == 0) optparse = NULL; return *tp; } return '?'; }
#endif
/*
/*
* * @doc INTERNAL MISC * * @func int | findlshortname | This function returns the offset of the * end of the complete path and file name not counting the file extension. * * @parm char * | fullname | Specifies the name to search. * * @rdesc The return value is the offset of the end of the complete path * and file name not counting the file extension. * */ int findlshortname(fullname) /* find the length of the short name */ /* full path/file name not counting extension */ char *fullname; { char *ch; int cnt;
if(!fullname || !*fullname) return(0);
cnt=strlen(fullname); ch=fullname+cnt;
while(*ch!='.' && *ch!='\\' && *ch!='/' && cnt) { ch--; cnt--; }
if(!cnt) return(strlen(fullname));
return(ch - fullname); }
/* getblong - get the next number from a buffer. Returns a long positive
* value if successful, otherwise returns -1. Scans-off leading BS. * Parameters: takes a pointer to a char and a pointer to an int which * will become a pointer the character following the number. */ /*
* * @doc INTERNAL MISC * * @func long | getblong | ATOL for buffer. * * @parm char * | line | Specifies buffer. * * @parm int * | i | Specifies current offset into buffer. This value is * updated as the buffer is scanned. * * @rdesc This function returns the Long value of the ASCII value contained * in the buffer at the specified offset. * * The offset is updated to the next character after the last ASCII character. * */ long getblong(line, i) char *line; int *i; { int pos = *i; long result = 0; int nLineLen = strlen(line);
/* while (!isdigit(line[pos]) && pos < nLineLen) */ /* ++pos; */
if (pos == nLineLen) return ((long)-1);
while (isdigit(line[pos]) && pos < nLineLen) result = 10 * result + line[pos++] - '0';
*i = pos;
return (result); }
#ifdef NOT_NEEDED
/*
* * @doc INTERNAL MISC * * @func char * | parse_sec_name | This function parses the section * name from a complete name. * * It was written for use in for Compound File indexing tools for * Microsoft Library. * * @parm char ** | ppch | Specifies the name to parse. * * @rdesc Ack. * */ char * parse_sec_name(char **ppch) { char *pch; char *p2ch; int j;
if(!ppch || !*ppch) return(NULL);
pch=*ppch;
while(*pch && *pch!='!') pch++;
if(!*pch) /* default section name is file name */ return(*ppch);
*pch='\0';
pch++;
p2ch=*ppch; *ppch=pch;
return(p2ch); }
#endif
/* *
* * * Memory Management routines * * * * * * */
char _achmemout[]= "Oh my, we seem to be out of %smemory. %ld Allocated\n" ;
/* Generic memory management */
/*
* * @doc INTERNAL MISC * * @func char * | cp_alloc | Allocates memory for the string and copies * it into the buffer and returns it. * * @parm char * | pch| Specifies string to copy. * * @comm The buffer should be freed with <f my_free>. * */ char * cp_alloc(pch) char *pch; { char *pch2;
if(!pch) return(NULL);
pch2=my_malloc(strlen(pch)+1); strcpy(pch2,pch); return pch2; }
/*
* * @doc INTERNAL MISC * * @func void | memfil | Fills the memory with zero. * * @parm int * | mem | Specifies the memory block to fill. * * @parm unsigned int | size | Specifies the size of the memory block. * * @comm The size of the memory block does not have to be a multiple of 2. * */ void memfil(mem,size) register int *mem; register unsigned int size; { char flag=FALSE; char *pch;
if(size&1) /* it's odd so int fill won't work all the way */ { flag=TRUE; size--; }
size=size/2; while(size--) *mem++=0;
if(flag) { pch=(char *)mem; *pch='\0'; }
}
/*
* * @doc INTERNAL MISC * * @func char * | clear_alloc | This function allocates memory and * initialized it to zeros. * * @parm unsigned int | size | Specifies the size of the memory to allocate. * * @comm The allocated memory should be freed with <f my_free>. * */ char * clear_alloc(size) unsigned int size; { char *pmem;
pmem=my_malloc(size); memfil((int *)pmem,size);
return pmem; }
static long ivemalloc=0;
/*
* * @doc INTERNAL MISC * * @func char * | my_malloc | Allocates memory and checks for errors. * * @parm unsigned int | size | Specifies the size of the memory to allocate. * * @comm The allocated memory should be freed with <f my_free>. * */ char * my_malloc(size) unsigned int size; { char *pmem; int hck;
if(size>32767) { fprintf(stderr,"Size >32K\n"); exit(666); } hck=_heapchk(); if(hck == _HEAPBADNODE) { fprintf(stderr,"Bad node in Heap. Ack!\n"); exit(666); } if(hck == _HEAPBADBEGIN) { fprintf(stderr,"Bad begin in Heap. Ack!\n"); exit(666); } pmem=(char *)malloc(size); if(pmem==NULL) { fprintf(stderr,_achmemout,"",ivemalloc); exit(777); } ivemalloc+=size; return(pmem); }
/*
* * @doc INTERNAL MISC * * @func void | my_free | Frees the specified buffer. * * @parm void * | buffer | Specifies the buffe to free. * */ void my_free(void * buffer) { if(!buffer) return;
ivemalloc-=_msize(buffer); free(buffer); return;
}
/* used by old indexing tools */
char *cpalloc(str) char *str; { return(cp_alloc(str)); }
/*
* * @doc INTERNAL MISC * * @func void | setmem | Sets the memory to the specified value. * * @parm char * | mem | Specifies the memory. * * @parm int | size | Specifies the size of the memory block. * * @parm char | val | Specifies the value to set the memory to. * * @comm Filling with zero is much faster with <f mem_fil>. * */ void setmem(src, size, val) register char *src; register int size; register char val; { while (size-- > 0) *src++ = val; }
/*
* * @doc INTERNAL MISC * * @func void | movmem | This function moves the specified memory. * Overlap is not checked. * * @parm char * | src | Source of copy. * * @parm char * | dst | Destination of copy. * * @parm int | len | Specifies number of bytes to copy. * */ void movmem(src,dst,len) register char *src, *dst; register int len; { while (len-- > 0) *dst++ = *src++; }
#ifdef NOT_NEEDED
/* explicit NEAR memory management calls */
char near * ncp_alloc(pch) char near *pch; { char near *pch2;
if(!pch) return(NULL);
pch2=nmy_malloc(strlen(pch)+1); strcpy(pch2,pch); return pch2; }
void nmemfil(mem,size) register int near *mem; register unsigned int size; { char flag=FALSE; char near *pch;
if(size&1) /* it's odd so int fill won't work all the way */ { flag=TRUE; size--; }
size=size/2; while(size--) *mem++=0;
if(flag) { pch=(char near *)mem; *pch='\0'; }
}
char near * nclear_alloc(size) unsigned int size; { char near *pmem;
pmem=nmy_malloc(size); memfil((int near*)pmem,size);
return pmem; }
static long ivenmalloc=0;
char near * nmy_malloc(size) unsigned int size; { char near *pmem;
pmem=(char near *)_nmalloc(size); if(pmem==NULL) { fprintf(stderr,_achmemout,"NEAR ",ivenmalloc); exit(777); } ivenmalloc+=size; return(pmem); }
/* used by old indexing tools */
char near * ncpalloc(str) char near *str; { return(ncp_alloc(str)); }
void nsetmem(src, size, val) register char near *src; register int size; register char val; { while (size-- > 0) *src++ = val; }
void nmovmem(src,dst,len) register char near *src; register char near *dst; register int len; { while (len-- > 0) *dst++ = *src++; }
/* explicit FAR memory management calls */
char far * fcp_alloc(pch) char far *pch; { char far *pch2;
if(!pch) return(NULL);
pch2=fmy_malloc(strlen(pch)+1); strcpy(pch2,pch); return pch2; }
void fmemfil(mem,size) register int far *mem; register unsigned int size; { char flag=FALSE; char far *pch;
if(size&1) /* it's odd so int fill won't work all the way */ { flag=TRUE; size--; }
size=size/2; while(size--) *mem++=0;
if(flag) { pch=(char far *)mem; *pch='\0'; }
}
char far * fclear_alloc(size) unsigned int size; { char far *pmem;
pmem=fmy_malloc(size); fmemfil((int far*)pmem,size);
return pmem; }
static long ivefmalloc=0;
char far * fmy_malloc(size) unsigned int size; { char far *pmem;
pmem=(char far *)_fmalloc(size); if(pmem==NULL) { fprintf(stderr,_achmemout,"FAR ",ivefmalloc); exit(777); } ivefmalloc+=size; return(pmem); }
/* used by old indexing tools */
char far * fcpalloc(str) char far *str; { return(fcp_alloc(str)); }
void fsetmem(src, size, val) register char far *src; register int size; register char val; { while (size-- > 0) *src++ = val; }
void fmovmem(src,dst,len) register char far *src; register char far *dst; register int len; { while (len-- > 0) *dst++ = *src++; }
#endif
/*
* * @doc INTERNAL MISC * * @func void | mymktemp | Make a temporary file. The returned file name is * guranteed to be unique and not already exist. * * @parm char * | lpszpath | Specifies the path to create the file. * * @parm char * | lpszbuffer | Specifies the buffer to receive the * full path/file name. * * */ void mymktemp(char * lpszpath, char * lpszbuffer) { static int i=0; FILE *fp;
sprintf(lpszbuffer,"%sdoc%05X.xxx",lpszpath,i++); fp=fopen(lpszbuffer,"r"); if(!fp) return;
fclose(fp); while(fp) {
if(i>30000) { fprintf(stderr,"ERROR: Cannot create temporary files on %s.\n",lpszpath); exit(1); } sprintf(lpszbuffer,"%sdoc%05X.xxx",lpszpath,i++); fp=fopen(lpszbuffer,"r");
if(fp) fclose(fp); } }
|