| /* $RCSfile$$Revision$$Date$ |
| * |
| * Copyright (c) 1989, Larry Wall |
| * |
| * You may distribute under the terms of the GNU General Public License |
| * as specified in the README file that comes with the perl 3.0 kit. |
| * |
| */ |
| |
| #include "EXTERN.h" |
| #include "perl.h" |
| |
| #if !defined(NSIG) || defined(M_UNIX) || defined(M_XENIX) |
| #include <signal.h> |
| #endif |
| |
| #ifdef I_VFORK |
| # include <vfork.h> |
| #endif |
| |
| #ifdef I_VARARGS |
| # include <varargs.h> |
| #endif |
| |
| #ifdef I_FCNTL |
| # include <fcntl.h> |
| #endif |
| #ifdef I_SYS_FILE |
| # include <sys/file.h> |
| #endif |
| |
| #define FLUSH |
| |
| static char nomem[] = "Out of memory!\n"; |
| |
| /* paranoid version of malloc */ |
| |
| #ifdef DEBUGGING |
| static int an = 0; |
| #endif |
| |
| /* NOTE: Do not call the next three routines directly. Use the macros |
| * in handy.h, so that we can easily redefine everything to do tracking of |
| * allocated hunks back to the original New to track down any memory leaks. |
| */ |
| |
| char * |
| safemalloc(size) |
| #ifdef MSDOS |
| unsigned long size; |
| #else |
| MEM_SIZE size; |
| #endif /* MSDOS */ |
| { |
| char *ptr; |
| #ifndef __STDC__ |
| #ifdef BWGC |
| char *gc_malloc(); |
| #else |
| char *malloc(); |
| #endif |
| #endif /* ! __STDC__ */ |
| |
| #ifdef MSDOS |
| if (size > 0xffff) { |
| fprintf(stderr, "Allocation too large: %lx\n", size) FLUSH; |
| exit(1); |
| } |
| #endif /* MSDOS */ |
| #ifdef DEBUGGING |
| if ((long)size < 0) |
| fatal("panic: malloc"); |
| #endif |
| #ifdef BWGC |
| ptr = gc_malloc(size?size:1); /* malloc(0) is NASTY on our system */ |
| #else |
| ptr = malloc(size?size:1); /* malloc(0) is NASTY on our system */ |
| #endif |
| #ifdef DEBUGGING |
| # ifndef I286 |
| if (debug & 128) |
| fprintf(stderr,"0x%x: (%05d) malloc %d bytes\n",ptr,an++,size); |
| # else |
| if (debug & 128) |
| fprintf(stderr,"0x%lx: (%05d) malloc %d bytes\n",ptr,an++,size); |
| # endif |
| #endif |
| if (ptr != Nullch) |
| return ptr; |
| else { |
| fputs(nomem,stderr) FLUSH; |
| exit(1); |
| } |
| /*NOTREACHED*/ |
| #ifdef lint |
| return ptr; |
| #endif |
| } |
| |
| /* paranoid version of realloc */ |
| |
| char * |
| saferealloc(where,size) |
| char *where; |
| #ifndef MSDOS |
| MEM_SIZE size; |
| #else |
| unsigned long size; |
| #endif /* MSDOS */ |
| { |
| char *ptr; |
| #ifndef __STDC__ |
| #ifdef BWGC |
| char *gc_realloc(); |
| #else |
| char *realloc(); |
| #endif |
| #endif /* ! __STDC__ */ |
| |
| #ifdef MSDOS |
| if (size > 0xffff) { |
| fprintf(stderr, "Reallocation too large: %lx\n", size) FLUSH; |
| exit(1); |
| } |
| #endif /* MSDOS */ |
| if (!where) |
| fatal("Null realloc"); |
| #ifdef DEBUGGING |
| if ((long)size < 0) |
| fatal("panic: realloc"); |
| #endif |
| #ifdef BWGC |
| ptr = gc_realloc(where,size?size:1); /* realloc(0) is NASTY on our system */ |
| #else |
| ptr = realloc(where,size?size:1); /* realloc(0) is NASTY on our system */ |
| #endif |
| #ifdef DEBUGGING |
| # ifndef I286 |
| if (debug & 128) { |
| fprintf(stderr,"0x%x: (%05d) rfree\n",where,an++); |
| fprintf(stderr,"0x%x: (%05d) realloc %d bytes\n",ptr,an++,size); |
| } |
| # else |
| if (debug & 128) { |
| fprintf(stderr,"0x%lx: (%05d) rfree\n",where,an++); |
| fprintf(stderr,"0x%lx: (%05d) realloc %d bytes\n",ptr,an++,size); |
| } |
| # endif |
| #endif |
| if (ptr != Nullch) |
| return ptr; |
| else { |
| fputs(nomem,stderr) FLUSH; |
| exit(1); |
| } |
| /*NOTREACHED*/ |
| #ifdef lint |
| return ptr; |
| #endif |
| } |
| |
| /* safe version of free */ |
| |
| void |
| safefree(where) |
| char *where; |
| { |
| #ifdef DEBUGGING |
| # ifndef I286 |
| if (debug & 128) |
| fprintf(stderr,"0x%x: (%05d) free\n",where,an++); |
| # else |
| if (debug & 128) |
| fprintf(stderr,"0x%lx: (%05d) free\n",where,an++); |
| # endif |
| #endif |
| #ifndef IGNOREFREE |
| if (where) { |
| free(where); |
| } |
| #endif |
| } |
| |
| #ifdef LEAKTEST |
| |
| #define ALIGN sizeof(long) |
| |
| char * |
| safexmalloc(x,size) |
| int x; |
| MEM_SIZE size; |
| { |
| register char *where; |
| |
| where = safemalloc(size + ALIGN); |
| xcount[x]++; |
| where[0] = x % 100; |
| where[1] = x / 100; |
| return where + ALIGN; |
| } |
| |
| char * |
| safexrealloc(where,size) |
| char *where; |
| MEM_SIZE size; |
| { |
| return saferealloc(where - ALIGN, size + ALIGN) + ALIGN; |
| } |
| |
| void |
| safexfree(where) |
| char *where; |
| { |
| int x; |
| |
| if (!where) |
| return; |
| where -= ALIGN; |
| x = where[0] + 100 * where[1]; |
| xcount[x]--; |
| safefree(where); |
| } |
| |
| xstat() |
| { |
| register int i; |
| |
| for (i = 0; i < MAXXCOUNT; i++) { |
| if (xcount[i] != lastxcount[i]) { |
| fprintf(stderr,"%2d %2d\t%ld\n", i / 100, i % 100, xcount[i]); |
| lastxcount[i] = xcount[i]; |
| } |
| } |
| } |
| |
| #endif /* LEAKTEST */ |
| |
| /* copy a string up to some (non-backslashed) delimiter, if any */ |
| |
| char * |
| cpytill(to,from,fromend,delim,retlen) |
| register char *to; |
| register char *from; |
| register char *fromend; |
| register int delim; |
| int *retlen; |
| { |
| char *origto = to; |
| |
| for (; from < fromend; from++,to++) { |
| if (*from == '\\') { |
| if (from[1] == delim) |
| from++; |
| else if (from[1] == '\\') |
| *to++ = *from++; |
| } |
| else if (*from == delim) |
| break; |
| *to = *from; |
| } |
| *to = '\0'; |
| *retlen = to - origto; |
| return from; |
| } |
| |
| /* return ptr to little string in big string, NULL if not found */ |
| /* This routine was donated by Corey Satten. */ |
| |
| char * |
| instr(big, little) |
| register char *big; |
| register char *little; |
| { |
| register char *s, *x; |
| register int first; |
| |
| if (!little) |
| return big; |
| first = *little++; |
| if (!first) |
| return big; |
| while (*big) { |
| if (*big++ != first) |
| continue; |
| for (x=big,s=little; *s; /**/ ) { |
| if (!*x) |
| return Nullch; |
| if (*s++ != *x++) { |
| s--; |
| break; |
| } |
| } |
| if (!*s) |
| return big-1; |
| } |
| return Nullch; |
| } |
| |
| /* same as instr but allow embedded nulls */ |
| |
| char * |
| ninstr(big, bigend, little, lend) |
| register char *big; |
| register char *bigend; |
| char *little; |
| char *lend; |
| { |
| register char *s, *x; |
| register int first = *little; |
| register char *littleend = lend; |
| |
| if (!first && little > littleend) |
| return big; |
| bigend -= littleend - little++; |
| while (big <= bigend) { |
| if (*big++ != first) |
| continue; |
| for (x=big,s=little; s < littleend; /**/ ) { |
| if (*s++ != *x++) { |
| s--; |
| break; |
| } |
| } |
| if (s >= littleend) |
| return big-1; |
| } |
| return Nullch; |
| } |
| |
| /* reverse of the above--find last substring */ |
| |
| char * |
| rninstr(big, bigend, little, lend) |
| register char *big; |
| char *bigend; |
| char *little; |
| char *lend; |
| { |
| register char *bigbeg; |
| register char *s, *x; |
| register int first = *little; |
| register char *littleend = lend; |
| |
| if (!first && little > littleend) |
| return bigend; |
| bigbeg = big; |
| big = bigend - (littleend - little++); |
| while (big >= bigbeg) { |
| if (*big-- != first) |
| continue; |
| for (x=big+2,s=little; s < littleend; /**/ ) { |
| if (*s++ != *x++) { |
| s--; |
| break; |
| } |
| } |
| if (s >= littleend) |
| return big+1; |
| } |
| return Nullch; |
| } |
| |
| unsigned char fold[] = { |
| 0, 1, 2, 3, 4, 5, 6, 7, |
| 8, 9, 10, 11, 12, 13, 14, 15, |
| 16, 17, 18, 19, 20, 21, 22, 23, |
| 24, 25, 26, 27, 28, 29, 30, 31, |
| 32, 33, 34, 35, 36, 37, 38, 39, |
| 40, 41, 42, 43, 44, 45, 46, 47, |
| 48, 49, 50, 51, 52, 53, 54, 55, |
| 56, 57, 58, 59, 60, 61, 62, 63, |
| 64, 'a', 'b', 'c', 'd', 'e', 'f', 'g', |
| 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', |
| 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', |
| 'x', 'y', 'z', 91, 92, 93, 94, 95, |
| 96, 'A', 'B', 'C', 'D', 'E', 'F', 'G', |
| 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', |
| 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', |
| 'X', 'Y', 'Z', 123, 124, 125, 126, 127, |
| 128, 129, 130, 131, 132, 133, 134, 135, |
| 136, 137, 138, 139, 140, 141, 142, 143, |
| 144, 145, 146, 147, 148, 149, 150, 151, |
| 152, 153, 154, 155, 156, 157, 158, 159, |
| 160, 161, 162, 163, 164, 165, 166, 167, |
| 168, 169, 170, 171, 172, 173, 174, 175, |
| 176, 177, 178, 179, 180, 181, 182, 183, |
| 184, 185, 186, 187, 188, 189, 190, 191, |
| 192, 193, 194, 195, 196, 197, 198, 199, |
| 200, 201, 202, 203, 204, 205, 206, 207, |
| 208, 209, 210, 211, 212, 213, 214, 215, |
| 216, 217, 218, 219, 220, 221, 222, 223, |
| 224, 225, 226, 227, 228, 229, 230, 231, |
| 232, 233, 234, 235, 236, 237, 238, 239, |
| 240, 241, 242, 243, 244, 245, 246, 247, |
| 248, 249, 250, 251, 252, 253, 254, 255 |
| }; |
| |
| static unsigned char freq[] = { |
| 1, 2, 84, 151, 154, 155, 156, 157, |
| 165, 246, 250, 3, 158, 7, 18, 29, |
| 40, 51, 62, 73, 85, 96, 107, 118, |
| 129, 140, 147, 148, 149, 150, 152, 153, |
| 255, 182, 224, 205, 174, 176, 180, 217, |
| 233, 232, 236, 187, 235, 228, 234, 226, |
| 222, 219, 211, 195, 188, 193, 185, 184, |
| 191, 183, 201, 229, 181, 220, 194, 162, |
| 163, 208, 186, 202, 200, 218, 198, 179, |
| 178, 214, 166, 170, 207, 199, 209, 206, |
| 204, 160, 212, 216, 215, 192, 175, 173, |
| 243, 172, 161, 190, 203, 189, 164, 230, |
| 167, 248, 227, 244, 242, 255, 241, 231, |
| 240, 253, 169, 210, 245, 237, 249, 247, |
| 239, 168, 252, 251, 254, 238, 223, 221, |
| 213, 225, 177, 197, 171, 196, 159, 4, |
| 5, 6, 8, 9, 10, 11, 12, 13, |
| 14, 15, 16, 17, 19, 20, 21, 22, |
| 23, 24, 25, 26, 27, 28, 30, 31, |
| 32, 33, 34, 35, 36, 37, 38, 39, |
| 41, 42, 43, 44, 45, 46, 47, 48, |
| 49, 50, 52, 53, 54, 55, 56, 57, |
| 58, 59, 60, 61, 63, 64, 65, 66, |
| 67, 68, 69, 70, 71, 72, 74, 75, |
| 76, 77, 78, 79, 80, 81, 82, 83, |
| 86, 87, 88, 89, 90, 91, 92, 93, |
| 94, 95, 97, 98, 99, 100, 101, 102, |
| 103, 104, 105, 106, 108, 109, 110, 111, |
| 112, 113, 114, 115, 116, 117, 119, 120, |
| 121, 122, 123, 124, 125, 126, 127, 128, |
| 130, 131, 132, 133, 134, 135, 136, 137, |
| 138, 139, 141, 142, 143, 144, 145, 146 |
| }; |
| |
| void |
| fbmcompile(str, iflag) |
| STR *str; |
| int iflag; |
| { |
| register unsigned char *s; |
| register unsigned char *table; |
| register int i; |
| register int len = str->str_cur; |
| int rarest = 0; |
| unsigned int frequency = 256; |
| |
| Str_Grow(str,len+258); |
| #ifndef lint |
| table = (unsigned char*)(str->str_ptr + len + 1); |
| #else |
| table = Null(unsigned char*); |
| #endif |
| s = table - 2; |
| for (i = 0; i < 256; i++) { |
| table[i] = len; |
| } |
| i = 0; |
| #ifndef lint |
| while (s >= (unsigned char*)(str->str_ptr)) |
| #endif |
| { |
| if (table[*s] == len) { |
| #ifndef pdp11 |
| if (iflag) |
| table[*s] = table[fold[*s]] = i; |
| #else |
| if (iflag) { |
| int j; |
| j = fold[*s]; |
| table[j] = i; |
| table[*s] = i; |
| } |
| #endif /* pdp11 */ |
| else |
| table[*s] = i; |
| } |
| s--,i++; |
| } |
| str->str_pok |= SP_FBM; /* deep magic */ |
| |
| #ifndef lint |
| s = (unsigned char*)(str->str_ptr); /* deeper magic */ |
| #else |
| s = Null(unsigned char*); |
| #endif |
| if (iflag) { |
| register unsigned int tmp, foldtmp; |
| str->str_pok |= SP_CASEFOLD; |
| for (i = 0; i < len; i++) { |
| tmp=freq[s[i]]; |
| foldtmp=freq[fold[s[i]]]; |
| if (tmp < frequency && foldtmp < frequency) { |
| rarest = i; |
| /* choose most frequent among the two */ |
| frequency = (tmp > foldtmp) ? tmp : foldtmp; |
| } |
| } |
| } |
| else { |
| for (i = 0; i < len; i++) { |
| if (freq[s[i]] < frequency) { |
| rarest = i; |
| frequency = freq[s[i]]; |
| } |
| } |
| } |
| str->str_rare = s[rarest]; |
| str->str_state = rarest; |
| #ifdef DEBUGGING |
| if (debug & 512) |
| fprintf(stderr,"rarest char %c at %d\n",str->str_rare, str->str_state); |
| #endif |
| } |
| |
| char * |
| fbminstr(big, bigend, littlestr) |
| unsigned char *big; |
| register unsigned char *bigend; |
| STR *littlestr; |
| { |
| register unsigned char *s; |
| register int tmp; |
| register int littlelen; |
| register unsigned char *little; |
| register unsigned char *table; |
| register unsigned char *olds; |
| register unsigned char *oldlittle; |
| |
| #ifndef lint |
| if (!(littlestr->str_pok & SP_FBM)) |
| return ninstr((char*)big,(char*)bigend, |
| littlestr->str_ptr, littlestr->str_ptr + littlestr->str_cur); |
| #endif |
| |
| littlelen = littlestr->str_cur; |
| #ifndef lint |
| if (littlestr->str_pok & SP_TAIL && !multiline) { /* tail anchored? */ |
| if (littlelen > bigend - big) |
| return Nullch; |
| little = (unsigned char*)littlestr->str_ptr; |
| if (littlestr->str_pok & SP_CASEFOLD) { /* oops, fake it */ |
| big = bigend - littlelen; /* just start near end */ |
| if (bigend[-1] == '\n' && little[littlelen-1] != '\n') |
| big--; |
| } |
| else { |
| s = bigend - littlelen; |
| if (*s == *little && bcmp(s,little,littlelen)==0) |
| return (char*)s; /* how sweet it is */ |
| else if (bigend[-1] == '\n' && little[littlelen-1] != '\n' |
| && s > big) { |
| s--; |
| if (*s == *little && bcmp(s,little,littlelen)==0) |
| return (char*)s; |
| } |
| return Nullch; |
| } |
| } |
| table = (unsigned char*)(littlestr->str_ptr + littlelen + 1); |
| #else |
| table = Null(unsigned char*); |
| #endif |
| if (--littlelen >= bigend - big) |
| return Nullch; |
| s = big + littlelen; |
| oldlittle = little = table - 2; |
| if (littlestr->str_pok & SP_CASEFOLD) { /* case insensitive? */ |
| if (s < bigend) { |
| top1: |
| if (tmp = table[*s]) { |
| #ifdef POINTERRIGOR |
| if (bigend - s > tmp) { |
| s += tmp; |
| goto top1; |
| } |
| #else |
| if ((s += tmp) < bigend) |
| goto top1; |
| #endif |
| return Nullch; |
| } |
| else { |
| tmp = littlelen; /* less expensive than calling strncmp() */ |
| olds = s; |
| while (tmp--) { |
| if (*--s == *--little || fold[*s] == *little) |
| continue; |
| s = olds + 1; /* here we pay the price for failure */ |
| little = oldlittle; |
| if (s < bigend) /* fake up continue to outer loop */ |
| goto top1; |
| return Nullch; |
| } |
| #ifndef lint |
| return (char *)s; |
| #endif |
| } |
| } |
| } |
| else { |
| if (s < bigend) { |
| top2: |
| if (tmp = table[*s]) { |
| #ifdef POINTERRIGOR |
| if (bigend - s > tmp) { |
| s += tmp; |
| goto top2; |
| } |
| #else |
| if ((s += tmp) < bigend) |
| goto top2; |
| #endif |
| return Nullch; |
| } |
| else { |
| tmp = littlelen; /* less expensive than calling strncmp() */ |
| olds = s; |
| while (tmp--) { |
| if (*--s == *--little) |
| continue; |
| s = olds + 1; /* here we pay the price for failure */ |
| little = oldlittle; |
| if (s < bigend) /* fake up continue to outer loop */ |
| goto top2; |
| return Nullch; |
| } |
| #ifndef lint |
| return (char *)s; |
| #endif |
| } |
| } |
| } |
| return Nullch; |
| } |
| |
| char * |
| screaminstr(bigstr, littlestr) |
| STR *bigstr; |
| STR *littlestr; |
| { |
| register unsigned char *s, *x; |
| register unsigned char *big; |
| register int pos; |
| register int previous; |
| register int first; |
| register unsigned char *little; |
| register unsigned char *bigend; |
| register unsigned char *littleend; |
| |
| if ((pos = screamfirst[littlestr->str_rare]) < 0) |
| return Nullch; |
| #ifndef lint |
| little = (unsigned char *)(littlestr->str_ptr); |
| #else |
| little = Null(unsigned char *); |
| #endif |
| littleend = little + littlestr->str_cur; |
| first = *little++; |
| previous = littlestr->str_state; |
| #ifndef lint |
| big = (unsigned char *)(bigstr->str_ptr); |
| #else |
| big = Null(unsigned char*); |
| #endif |
| bigend = big + bigstr->str_cur; |
| big -= previous; |
| while (pos < previous) { |
| #ifndef lint |
| if (!(pos += screamnext[pos])) |
| #endif |
| return Nullch; |
| } |
| if (littlestr->str_pok & SP_CASEFOLD) { /* case insignificant? */ |
| do { |
| if (big[pos] != first && big[pos] != fold[first]) |
| continue; |
| for (x=big+pos+1,s=little; s < littleend; /**/ ) { |
| if (x >= bigend) |
| return Nullch; |
| if (*s++ != *x++ && fold[*(s-1)] != *(x-1)) { |
| s--; |
| break; |
| } |
| } |
| if (s == littleend) |
| #ifndef lint |
| return (char *)(big+pos); |
| #else |
| return Nullch; |
| #endif |
| } while ( |
| #ifndef lint |
| pos += screamnext[pos] /* does this goof up anywhere? */ |
| #else |
| pos += screamnext[0] |
| #endif |
| ); |
| } |
| else { |
| do { |
| if (big[pos] != first) |
| continue; |
| for (x=big+pos+1,s=little; s < littleend; /**/ ) { |
| if (x >= bigend) |
| return Nullch; |
| if (*s++ != *x++) { |
| s--; |
| break; |
| } |
| } |
| if (s == littleend) |
| #ifndef lint |
| return (char *)(big+pos); |
| #else |
| return Nullch; |
| #endif |
| } while ( |
| #ifndef lint |
| pos += screamnext[pos] |
| #else |
| pos += screamnext[0] |
| #endif |
| ); |
| } |
| return Nullch; |
| } |
| |
| /* copy a string to a safe spot */ |
| |
| char * |
| savestr(str) |
| char *str; |
| { |
| register char *newaddr; |
| |
| New(902,newaddr,strlen(str)+1,char); |
| (void)strcpy(newaddr,str); |
| return newaddr; |
| } |
| |
| /* same thing but with a known length */ |
| |
| char * |
| nsavestr(str, len) |
| char *str; |
| register int len; |
| { |
| register char *newaddr; |
| |
| New(903,newaddr,len+1,char); |
| (void)bcopy(str,newaddr,len); /* might not be null terminated */ |
| newaddr[len] = '\0'; /* is now */ |
| return newaddr; |
| } |
| |
| /* grow a static string to at least a certain length */ |
| |
| void |
| growstr(strptr,curlen,newlen) |
| char **strptr; |
| int *curlen; |
| int newlen; |
| { |
| if (newlen > *curlen) { /* need more room? */ |
| if (*curlen) |
| Renew(*strptr,newlen,char); |
| else |
| New(905,*strptr,newlen,char); |
| *curlen = newlen; |
| } |
| } |
| |
| #ifndef I_VARARGS |
| /*VARARGS1*/ |
| mess(pat,a1,a2,a3,a4) |
| char *pat; |
| long a1, a2, a3, a4; |
| { |
| char *s; |
| |
| s = buf; |
| (void)sprintf(s,pat,a1,a2,a3,a4); |
| s += strlen(s); |
| if (s[-1] != '\n') { |
| if (curcmd->c_line) { |
| (void)sprintf(s," at %s line %ld", |
| stab_val(curcmd->c_filestab)->str_ptr, (long)curcmd->c_line); |
| s += strlen(s); |
| } |
| if (last_in_stab && |
| stab_io(last_in_stab) && |
| stab_io(last_in_stab)->lines ) { |
| (void)sprintf(s,", <%s> line %ld", |
| last_in_stab == argvstab ? "" : stab_name(last_in_stab), |
| (long)stab_io(last_in_stab)->lines); |
| s += strlen(s); |
| } |
| (void)strcpy(s,".\n"); |
| } |
| } |
| |
| /*VARARGS1*/ |
| #if 0 |
| fatal(pat,a1,a2,a3,a4) |
| char *pat; |
| long a1, a2, a3, a4; |
| { |
| extern FILE *e_fp; |
| extern char *e_tmpname; |
| char *tmps; |
| |
| mess(pat,a1,a2,a3,a4); |
| if (in_eval) { |
| str_set(stab_val(stabent("@",TRUE)),buf); |
| tmps = "_EVAL_"; |
| while (loop_ptr >= 0 && (!loop_stack[loop_ptr].loop_label || |
| strNE(tmps,loop_stack[loop_ptr].loop_label) )) { |
| #ifdef DEBUGGING |
| if (debug & 4) { |
| deb("(Skipping label #%d %s)\n",loop_ptr, |
| loop_stack[loop_ptr].loop_label); |
| } |
| #endif |
| loop_ptr--; |
| } |
| #ifdef DEBUGGING |
| if (debug & 4) { |
| deb("(Found label #%d %s)\n",loop_ptr, |
| loop_stack[loop_ptr].loop_label); |
| } |
| #endif |
| if (loop_ptr < 0) { |
| in_eval = 0; |
| fatal("Bad label: %s", tmps); |
| } |
| longjmp(loop_stack[loop_ptr].loop_env, 1); |
| } |
| fputs(buf,stderr); |
| (void)fflush(stderr); |
| if (e_fp) |
| (void)UNLINK(e_tmpname); |
| statusvalue >>= 8; |
| exit((int)((errno&255)?errno:((statusvalue&255)?statusvalue:255))); |
| } |
| #endif |
| |
| /*VARARGS1*/ |
| warn(pat,a1,a2,a3,a4) |
| char *pat; |
| long a1, a2, a3, a4; |
| { |
| mess(pat,a1,a2,a3,a4); |
| fputs(buf,stderr); |
| #ifdef LEAKTEST |
| #ifdef DEBUGGING |
| if (debug & 4096) |
| xstat(); |
| #endif |
| #endif |
| (void)fflush(stderr); |
| } |
| #else |
| /*VARARGS0*/ |
| mess(args) |
| va_list args; |
| { |
| char *pat; |
| char *s; |
| #ifdef CHARVSPRINTF |
| char *vsprintf(); |
| #else |
| int vsprintf(); |
| #endif |
| |
| s = buf; |
| #ifdef lint |
| pat = Nullch; |
| #else |
| pat = va_arg(args, char *); |
| #endif |
| (void) vsprintf(s,pat,args); |
| |
| s += strlen(s); |
| if (s[-1] != '\n') { |
| if (curcmd->c_line) { |
| (void)sprintf(s," at %s line %ld", |
| stab_val(curcmd->c_filestab)->str_ptr, (long)curcmd->c_line); |
| s += strlen(s); |
| } |
| if (last_in_stab && |
| stab_io(last_in_stab) && |
| stab_io(last_in_stab)->lines ) { |
| (void)sprintf(s,", <%s> line %ld", |
| last_in_stab == argvstab ? "" : last_in_stab->str_magic->str_ptr, |
| (long)stab_io(last_in_stab)->lines); |
| s += strlen(s); |
| } |
| (void)strcpy(s,".\n"); |
| } |
| } |
| |
| /*VARARGS0*/ |
| fatal(va_alist) |
| va_dcl |
| { |
| va_list args; |
| extern FILE *e_fp; |
| extern char *e_tmpname; |
| char *tmps; |
| |
| #ifndef lint |
| va_start(args); |
| #else |
| args = 0; |
| #endif |
| mess(args); |
| va_end(args); |
| if (in_eval) { |
| str_set(stab_val(stabent("@",TRUE)),buf); |
| tmps = "_EVAL_"; |
| while (loop_ptr >= 0 && (!loop_stack[loop_ptr].loop_label || |
| strNE(tmps,loop_stack[loop_ptr].loop_label) )) { |
| #ifdef DEBUGGING |
| if (debug & 4) { |
| deb("(Skipping label #%d %s)\n",loop_ptr, |
| loop_stack[loop_ptr].loop_label); |
| } |
| #endif |
| loop_ptr--; |
| } |
| #ifdef DEBUGGING |
| if (debug & 4) { |
| deb("(Found label #%d %s)\n",loop_ptr, |
| loop_stack[loop_ptr].loop_label); |
| } |
| #endif |
| if (loop_ptr < 0) { |
| in_eval = 0; |
| fatal("Bad label: %s", tmps); |
| } |
| longjmp(loop_stack[loop_ptr].loop_env, 1); |
| } |
| fputs(buf,stderr); |
| (void)fflush(stderr); |
| if (e_fp) |
| (void)UNLINK(e_tmpname); |
| statusvalue >>= 8; |
| exit((int)((errno&255)?errno:((statusvalue&255)?statusvalue:255))); |
| } |
| |
| /*VARARGS0*/ |
| warn(va_alist) |
| va_dcl |
| { |
| va_list args; |
| |
| #ifndef lint |
| va_start(args); |
| #else |
| args = 0; |
| #endif |
| mess(args); |
| va_end(args); |
| |
| fputs(buf,stderr); |
| #ifdef LEAKTEST |
| #ifdef DEBUGGING |
| if (debug & 4096) |
| xstat(); |
| #endif |
| #endif |
| (void)fflush(stderr); |
| } |
| #endif |
| |
| void |
| my_setenv(nam,val) |
| char *nam, *val; |
| { |
| register int i=envix(nam); /* where does it go? */ |
| |
| if (environ == origenviron) { /* need we copy environment? */ |
| int j; |
| int max; |
| char **tmpenv; |
| |
| for (max = i; environ[max]; max++) ; |
| New(901,tmpenv, max+2, char*); |
| for (j=0; j<max; j++) /* copy environment */ |
| tmpenv[j] = savestr(environ[j]); |
| tmpenv[max] = Nullch; |
| environ = tmpenv; /* tell exec where it is now */ |
| } |
| if (!val) { |
| while (environ[i]) { |
| environ[i] = environ[i+1]; |
| i++; |
| } |
| return; |
| } |
| if (!environ[i]) { /* does not exist yet */ |
| Renew(environ, i+2, char*); /* just expand it a bit */ |
| environ[i+1] = Nullch; /* make sure it's null terminated */ |
| } |
| else |
| Safefree(environ[i]); |
| New(904, environ[i], strlen(nam) + strlen(val) + 2, char); |
| #ifndef MSDOS |
| (void)sprintf(environ[i],"%s=%s",nam,val);/* all that work just for this */ |
| #else |
| /* MS-DOS requires environment variable names to be in uppercase */ |
| /* [Tom Dinger, 27 August 1990: Well, it doesn't _require_ it, but |
| * some utilities and applications may break because they only look |
| * for upper case strings. (Fixed strupr() bug here.)] |
| */ |
| strcpy(environ[i],nam); strupr(environ[i]); |
| (void)sprintf(environ[i] + strlen(nam),"=%s",val); |
| #endif /* MSDOS */ |
| } |
| |
| int |
| envix(nam) |
| char *nam; |
| { |
| register int i, len = strlen(nam); |
| |
| for (i = 0; environ[i]; i++) { |
| if (strnEQ(environ[i],nam,len) && environ[i][len] == '=') |
| break; /* strnEQ must come first to avoid */ |
| } /* potential SEGV's */ |
| return i; |
| } |
| |
| #ifdef EUNICE |
| unlnk(f) /* unlink all versions of a file */ |
| char *f; |
| { |
| int i; |
| |
| for (i = 0; unlink(f) >= 0; i++) ; |
| return i ? 0 : -1; |
| } |
| #endif |
| |
| #ifndef HAS_MEMCPY |
| #ifndef HAS_BCOPY |
| char * |
| bcopy(from,to,len) |
| register char *from; |
| register char *to; |
| register int len; |
| { |
| char *retval = to; |
| |
| while (len--) |
| *to++ = *from++; |
| return retval; |
| } |
| #endif |
| |
| #ifndef HAS_BZERO |
| char * |
| bzero(loc,len) |
| register char *loc; |
| register int len; |
| { |
| char *retval = loc; |
| |
| while (len--) |
| *loc++ = 0; |
| return retval; |
| } |
| #endif |
| #endif |
| |
| #ifdef I_VARARGS |
| #ifndef HAS_VPRINTF |
| |
| #ifdef CHARVSPRINTF |
| char * |
| #else |
| int |
| #endif |
| vsprintf(dest, pat, args) |
| char *dest, *pat, *args; |
| { |
| FILE fakebuf; |
| |
| fakebuf._ptr = dest; |
| fakebuf._cnt = 32767; |
| #ifndef _IOSTRG |
| #define _IOSTRG 0 |
| #endif |
| fakebuf._flag = _IOWRT|_IOSTRG; |
| _doprnt(pat, args, &fakebuf); /* what a kludge */ |
| (void)putc('\0', &fakebuf); |
| #ifdef CHARVSPRINTF |
| return(dest); |
| #else |
| return 0; /* perl doesn't use return value */ |
| #endif |
| } |
| |
| #ifdef DEBUGGING |
| int |
| vfprintf(fd, pat, args) |
| FILE *fd; |
| char *pat, *args; |
| { |
| _doprnt(pat, args, fd); |
| return 0; /* wrong, but perl doesn't use the return value */ |
| } |
| #endif |
| #endif /* HAS_VPRINTF */ |
| #endif /* I_VARARGS */ |
| |
| #ifdef MYSWAP |
| #if BYTEORDER != 0x4321 |
| short |
| my_swap(s) |
| short s; |
| { |
| #if (BYTEORDER & 1) == 0 |
| short result; |
| |
| result = ((s & 255) << 8) + ((s >> 8) & 255); |
| return result; |
| #else |
| return s; |
| #endif |
| } |
| |
| long |
| htonl(l) |
| register long l; |
| { |
| union { |
| long result; |
| char c[sizeof(long)]; |
| } u; |
| |
| #if BYTEORDER == 0x1234 |
| u.c[0] = (l >> 24) & 255; |
| u.c[1] = (l >> 16) & 255; |
| u.c[2] = (l >> 8) & 255; |
| u.c[3] = l & 255; |
| return u.result; |
| #else |
| #if ((BYTEORDER - 0x1111) & 0x444) || !(BYTEORDER & 0xf) |
| fatal("Unknown BYTEORDER\n"); |
| #else |
| register int o; |
| register int s; |
| |
| for (o = BYTEORDER - 0x1111, s = 0; s < (sizeof(long)*8); o >>= 4, s += 8) { |
| u.c[o & 0xf] = (l >> s) & 255; |
| } |
| return u.result; |
| #endif |
| #endif |
| } |
| |
| long |
| ntohl(l) |
| register long l; |
| { |
| union { |
| long l; |
| char c[sizeof(long)]; |
| } u; |
| |
| #if BYTEORDER == 0x1234 |
| u.c[0] = (l >> 24) & 255; |
| u.c[1] = (l >> 16) & 255; |
| u.c[2] = (l >> 8) & 255; |
| u.c[3] = l & 255; |
| return u.l; |
| #else |
| #if ((BYTEORDER - 0x1111) & 0x444) || !(BYTEORDER & 0xf) |
| fatal("Unknown BYTEORDER\n"); |
| #else |
| register int o; |
| register int s; |
| |
| u.l = l; |
| l = 0; |
| for (o = BYTEORDER - 0x1111, s = 0; s < (sizeof(long)*8); o >>= 4, s += 8) { |
| l |= (u.c[o & 0xf] & 255) << s; |
| } |
| return l; |
| #endif |
| #endif |
| } |
| |
| #endif /* BYTEORDER != 0x4321 */ |
| #endif /* HAS_HTONS */ |
| |
| #ifndef MSDOS |
| FILE * |
| mypopen(cmd,mode) |
| char *cmd; |
| char *mode; |
| { |
| int p[2]; |
| register int this, that; |
| register int pid; |
| STR *str; |
| int doexec = strNE(cmd,"-"); |
| |
| if (pipe(p) < 0) |
| return Nullfp; |
| this = (*mode == 'w'); |
| that = !this; |
| while ((pid = (doexec?vfork():fork())) < 0) { |
| if (errno != EAGAIN) { |
| close(p[this]); |
| if (!doexec) |
| fatal("Can't fork"); |
| return Nullfp; |
| } |
| sleep(5); |
| } |
| if (pid == 0) { |
| #define THIS that |
| #define THAT this |
| close(p[THAT]); |
| if (p[THIS] != (*mode == 'r')) { |
| dup2(p[THIS], *mode == 'r'); |
| close(p[THIS]); |
| } |
| if (doexec) { |
| #if !defined(I_FCNTL) || !defined(F_SETFD) |
| int fd; |
| |
| #ifndef NOFILE |
| #define NOFILE 20 |
| #endif |
| for (fd = 3; fd < NOFILE; fd++) |
| close(fd); |
| #endif |
| do_exec(cmd); /* may or may not use the shell */ |
| _exit(1); |
| } |
| if (tmpstab = stabent("$",allstabs)) |
| str_numset(STAB_STR(tmpstab),(double)getpid()); |
| forkprocess = 0; |
| hclear(pidstatus, FALSE); /* we have no children */ |
| return Nullfp; |
| #undef THIS |
| #undef THAT |
| } |
| do_execfree(); /* free any memory malloced by child on vfork */ |
| close(p[that]); |
| if (p[that] < p[this]) { |
| dup2(p[this], p[that]); |
| close(p[this]); |
| p[this] = p[that]; |
| } |
| str = afetch(fdpid,p[this],TRUE); |
| str->str_u.str_useful = pid; |
| forkprocess = pid; |
| return fdopen(p[this], mode); |
| } |
| #endif /* !MSDOS */ |
| |
| #ifdef NOTDEF |
| dumpfds(s) |
| char *s; |
| { |
| int fd; |
| struct stat tmpstatbuf; |
| |
| fprintf(stderr,"%s", s); |
| for (fd = 0; fd < 32; fd++) { |
| if (fstat(fd,&tmpstatbuf) >= 0) |
| fprintf(stderr," %d",fd); |
| } |
| fprintf(stderr,"\n"); |
| } |
| #endif |
| |
| #ifndef HAS_DUP2 |
| dup2(oldfd,newfd) |
| int oldfd; |
| int newfd; |
| { |
| #if defined(HAS_FCNTL) && defined(F_DUPFD) |
| close(newfd); |
| fcntl(oldfd, F_DUPFD, newfd); |
| #else |
| int fdtmp[20]; |
| int fdx = 0; |
| int fd; |
| |
| if (oldfd == newfd) |
| return 0; |
| close(newfd); |
| while ((fd = dup(oldfd)) != newfd) /* good enough for low fd's */ |
| fdtmp[fdx++] = fd; |
| while (fdx > 0) |
| close(fdtmp[--fdx]); |
| #endif |
| } |
| #endif |
| |
| #ifndef MSDOS |
| int |
| mypclose(ptr) |
| FILE *ptr; |
| { |
| #ifdef VOIDSIG |
| void (*hstat)(), (*istat)(), (*qstat)(); |
| #else |
| int (*hstat)(), (*istat)(), (*qstat)(); |
| #endif |
| int status; |
| STR *str; |
| int pid; |
| |
| str = afetch(fdpid,fileno(ptr),TRUE); |
| astore(fdpid,fileno(ptr),Nullstr); |
| fclose(ptr); |
| pid = (int)str->str_u.str_useful; |
| hstat = signal(SIGHUP, SIG_IGN); |
| istat = signal(SIGINT, SIG_IGN); |
| qstat = signal(SIGQUIT, SIG_IGN); |
| pid = wait4pid(pid, &status, 0); |
| signal(SIGHUP, hstat); |
| signal(SIGINT, istat); |
| signal(SIGQUIT, qstat); |
| return(pid < 0 ? pid : status); |
| } |
| |
| int |
| wait4pid(pid,statusp,flags) |
| int pid; |
| int *statusp; |
| int flags; |
| { |
| int result; |
| STR *str; |
| char spid[16]; |
| |
| if (!pid) |
| return -1; |
| #ifdef HAS_WAIT4 |
| return wait4((pid==-1)?0:pid,statusp,flags,Null(struct rusage *)); |
| #else |
| #ifdef HAS_WAITPID |
| return waitpid(pid,statusp,flags); |
| #else |
| if (pid > 0) { |
| sprintf(spid, "%d", pid); |
| str = hfetch(pidstatus,spid,strlen(spid),FALSE); |
| if (str != &str_undef) { |
| *statusp = (int)str->str_u.str_useful; |
| hdelete(pidstatus,spid,strlen(spid)); |
| return pid; |
| } |
| } |
| else { |
| HENT *entry; |
| |
| hiterinit(pidstatus); |
| if (entry = hiternext(pidstatus)) { |
| pid = atoi(hiterkey(entry,statusp)); |
| str = hiterval(entry); |
| *statusp = (int)str->str_u.str_useful; |
| sprintf(spid, "%d", pid); |
| hdelete(pidstatus,spid,strlen(spid)); |
| return pid; |
| } |
| } |
| if (flags) |
| fatal("Can't do waitpid with flags"); |
| else { |
| while ((result = wait(statusp)) != pid && pid > 0 && result >= 0) |
| pidgone(result,*statusp); |
| if (result < 0) |
| *statusp = -1; |
| } |
| return result; |
| #endif |
| #endif |
| } |
| |
| pidgone(pid,status) |
| int pid; |
| int status; |
| { |
| #if defined(HAS_WAIT4) || defined(HAS_WAITPID) |
| #else |
| register STR *str; |
| char spid[16]; |
| |
| sprintf(spid, "%d", pid); |
| str = hfetch(pidstatus,spid,strlen(spid),TRUE); |
| str->str_u.str_useful = status; |
| #endif |
| return; |
| } |
| #endif /* !MSDOS */ |
| |
| #ifndef HAS_MEMCMP |
| memcmp(s1,s2,len) |
| register unsigned char *s1; |
| register unsigned char *s2; |
| register int len; |
| { |
| register int tmp; |
| |
| while (len--) { |
| if (tmp = *s1++ - *s2++) |
| return tmp; |
| } |
| return 0; |
| } |
| #endif /* HAS_MEMCMP */ |
| |
| void |
| repeatcpy(to,from,len,count) |
| register char *to; |
| register char *from; |
| int len; |
| register int count; |
| { |
| register int todo; |
| register char *frombase = from; |
| |
| if (len == 1) { |
| todo = *from; |
| while (count-- > 0) |
| *to++ = todo; |
| return; |
| } |
| while (count-- > 0) { |
| for (todo = len; todo > 0; todo--) { |
| *to++ = *from++; |
| } |
| from = frombase; |
| } |
| } |
| |
| #ifndef CASTNEGFLOAT |
| unsigned long |
| castulong(f) |
| double f; |
| { |
| long along; |
| |
| #if CASTFLAGS & 2 |
| # define BIGDOUBLE 2147483648.0 |
| if (f >= BIGDOUBLE) |
| return (unsigned long)(f-(long)(f/BIGDOUBLE)*BIGDOUBLE)|0x80000000; |
| #endif |
| if (f >= 0.0) |
| return (unsigned long)f; |
| along = (long)f; |
| return (unsigned long)along; |
| } |
| #endif |
| |
| #ifndef HAS_RENAME |
| int |
| same_dirent(a,b) |
| char *a; |
| char *b; |
| { |
| char *fa = rindex(a,'/'); |
| char *fb = rindex(b,'/'); |
| struct stat tmpstatbuf1; |
| struct stat tmpstatbuf2; |
| #ifndef MAXPATHLEN |
| #define MAXPATHLEN 1024 |
| #endif |
| char tmpbuf[MAXPATHLEN+1]; |
| |
| if (fa) |
| fa++; |
| else |
| fa = a; |
| if (fb) |
| fb++; |
| else |
| fb = b; |
| if (strNE(a,b)) |
| return FALSE; |
| if (fa == a) |
| strcpy(tmpbuf,"."); |
| else |
| strncpy(tmpbuf, a, fa - a); |
| if (stat(tmpbuf, &tmpstatbuf1) < 0) |
| return FALSE; |
| if (fb == b) |
| strcpy(tmpbuf,"."); |
| else |
| strncpy(tmpbuf, b, fb - b); |
| if (stat(tmpbuf, &tmpstatbuf2) < 0) |
| return FALSE; |
| return tmpstatbuf1.st_dev == tmpstatbuf2.st_dev && |
| tmpstatbuf1.st_ino == tmpstatbuf2.st_ino; |
| } |
| #endif /* !HAS_RENAME */ |
| |
| unsigned long |
| scanoct(start, len, retlen) |
| char *start; |
| int len; |
| int *retlen; |
| { |
| register char *s = start; |
| register unsigned long retval = 0; |
| |
| while (len-- && *s >= '0' && *s <= '7') { |
| retval <<= 3; |
| retval |= *s++ - '0'; |
| } |
| *retlen = s - start; |
| return retval; |
| } |
| |
| unsigned long |
| scanhex(start, len, retlen) |
| char *start; |
| int len; |
| int *retlen; |
| { |
| register char *s = start; |
| register unsigned long retval = 0; |
| char *tmp; |
| |
| while (len-- && *s && (tmp = index(hexdigit, *s))) { |
| retval <<= 4; |
| retval |= (tmp - hexdigit) & 15; |
| s++; |
| } |
| *retlen = s - start; |
| return retval; |
| } |