1 /* $Header: util.c,v 3.0.1.5 90/03/27 16:35:13 lwall Locked $
3 * Copyright (c) 1989, Larry Wall
5 * You may distribute under the terms of the GNU General Public License
6 * as specified in the README file that comes with the perl 3.0 kit.
9 * Revision 3.0.1.5 90/03/27 16:35:13 lwall
10 * patch16: MSDOS support
11 * patch16: support for machines that can't cast negative floats to unsigned ints
12 * patch16: tail anchored pattern could dump if string to search was shorter
14 * Revision 3.0.1.4 90/03/01 10:26:48 lwall
15 * patch9: fbminstr() called instr() rather than ninstr()
16 * patch9: nested evals clobbered their longjmp environment
17 * patch9: piped opens returned undefined rather than 0 in child
18 * patch9: the x operator is now up to 10 times faster
20 * Revision 3.0.1.3 89/12/21 20:27:41 lwall
21 * patch7: errno may now be a macro with an lvalue
23 * Revision 3.0.1.2 89/11/17 15:46:35 lwall
24 * patch5: BZERO separate from BCOPY now
25 * patch5: byteorder now is a hex value
27 * Revision 3.0.1.1 89/11/11 05:06:13 lwall
28 * patch2: made dup2 a little better
30 * Revision 3.0 89/10/18 15:32:43 lwall
49 static char nomem[] = "Out of memory!\n";
51 /* paranoid version of malloc */
57 /* NOTE: Do not call the next three routines directly. Use the macros
58 * in handy.h, so that we can easily redefine everything to do tracking of
59 * allocated hunks back to the original New to track down any memory leaks.
69 ptr = malloc(size?size:1); /* malloc(0) is NASTY on our system */
73 fprintf(stderr,"0x%x: (%05d) malloc %d bytes\n",ptr,an++,size);
76 fprintf(stderr,"0x%lx: (%05d) malloc %d bytes\n",ptr,an++,size);
82 fputs(nomem,stdout) FLUSH;
91 /* paranoid version of realloc */
94 saferealloc(where,size)
102 fatal("Null realloc");
103 ptr = realloc(where,size?size:1); /* realloc(0) is NASTY on our system */
107 fprintf(stderr,"0x%x: (%05d) rfree\n",where,an++);
108 fprintf(stderr,"0x%x: (%05d) realloc %d bytes\n",ptr,an++,size);
112 fprintf(stderr,"0x%lx: (%05d) rfree\n",where,an++);
113 fprintf(stderr,"0x%lx: (%05d) realloc %d bytes\n",ptr,an++,size);
120 fputs(nomem,stdout) FLUSH;
129 /* safe version of free */
138 fprintf(stderr,"0x%x: (%05d) free\n",where,an++);
141 fprintf(stderr,"0x%lx: (%05d) free\n",where,an++);
151 #define ALIGN sizeof(long)
158 register char *where;
160 where = safemalloc(size + ALIGN);
164 return where + ALIGN;
168 safexrealloc(where,size)
172 return saferealloc(where - ALIGN, size + ALIGN) + ALIGN;
184 x = where[0] + 100 * where[1];
193 for (i = 0; i < MAXXCOUNT; i++) {
194 if (xcount[i] != lastxcount[i]) {
195 fprintf(stderr,"%2d %2d\t%ld\n", i / 100, i % 100, xcount[i]);
196 lastxcount[i] = xcount[i];
201 #endif /* LEAKTEST */
203 /* copy a string up to some (non-backslashed) delimiter, if any */
206 cpytill(to,from,fromend,delim,retlen)
207 register char *to, *from;
208 register char *fromend;
214 for (; from < fromend; from++,to++) {
216 if (from[1] == delim)
218 else if (from[1] == '\\')
221 else if (*from == delim)
226 *retlen = to - origto;
230 /* return ptr to little string in big string, NULL if not found */
231 /* This routine was donated by Corey Satten. */
236 register char *little;
238 register char *s, *x;
249 for (x=big,s=little; *s; /**/ ) {
263 /* same as instr but allow embedded nulls */
266 ninstr(big, bigend, little, lend)
268 register char *bigend;
272 register char *s, *x;
273 register int first = *little;
274 register char *littleend = lend;
276 if (!first && little > littleend)
278 bigend -= littleend - little++;
279 while (big <= bigend) {
282 for (x=big,s=little; s < littleend; /**/ ) {
294 /* reverse of the above--find last substring */
297 rninstr(big, bigend, little, lend)
303 register char *bigbeg;
304 register char *s, *x;
305 register int first = *little;
306 register char *littleend = lend;
308 if (!first && little > littleend)
311 big = bigend - (littleend - little++);
312 while (big >= bigbeg) {
315 for (x=big+2,s=little; s < littleend; /**/ ) {
327 unsigned char fold[] = {
328 0, 1, 2, 3, 4, 5, 6, 7,
329 8, 9, 10, 11, 12, 13, 14, 15,
330 16, 17, 18, 19, 20, 21, 22, 23,
331 24, 25, 26, 27, 28, 29, 30, 31,
332 32, 33, 34, 35, 36, 37, 38, 39,
333 40, 41, 42, 43, 44, 45, 46, 47,
334 48, 49, 50, 51, 52, 53, 54, 55,
335 56, 57, 58, 59, 60, 61, 62, 63,
336 64, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
337 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
338 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
339 'x', 'y', 'z', 91, 92, 93, 94, 95,
340 96, 'A', 'B', 'C', 'D', 'E', 'F', 'G',
341 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
342 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
343 'X', 'Y', 'Z', 123, 124, 125, 126, 127,
344 128, 129, 130, 131, 132, 133, 134, 135,
345 136, 137, 138, 139, 140, 141, 142, 143,
346 144, 145, 146, 147, 148, 149, 150, 151,
347 152, 153, 154, 155, 156, 157, 158, 159,
348 160, 161, 162, 163, 164, 165, 166, 167,
349 168, 169, 170, 171, 172, 173, 174, 175,
350 176, 177, 178, 179, 180, 181, 182, 183,
351 184, 185, 186, 187, 188, 189, 190, 191,
352 192, 193, 194, 195, 196, 197, 198, 199,
353 200, 201, 202, 203, 204, 205, 206, 207,
354 208, 209, 210, 211, 212, 213, 214, 215,
355 216, 217, 218, 219, 220, 221, 222, 223,
356 224, 225, 226, 227, 228, 229, 230, 231,
357 232, 233, 234, 235, 236, 237, 238, 239,
358 240, 241, 242, 243, 244, 245, 246, 247,
359 248, 249, 250, 251, 252, 253, 254, 255
362 static unsigned char freq[] = {
363 1, 2, 84, 151, 154, 155, 156, 157,
364 165, 246, 250, 3, 158, 7, 18, 29,
365 40, 51, 62, 73, 85, 96, 107, 118,
366 129, 140, 147, 148, 149, 150, 152, 153,
367 255, 182, 224, 205, 174, 176, 180, 217,
368 233, 232, 236, 187, 235, 228, 234, 226,
369 222, 219, 211, 195, 188, 193, 185, 184,
370 191, 183, 201, 229, 181, 220, 194, 162,
371 163, 208, 186, 202, 200, 218, 198, 179,
372 178, 214, 166, 170, 207, 199, 209, 206,
373 204, 160, 212, 216, 215, 192, 175, 173,
374 243, 172, 161, 190, 203, 189, 164, 230,
375 167, 248, 227, 244, 242, 255, 241, 231,
376 240, 253, 169, 210, 245, 237, 249, 247,
377 239, 168, 252, 251, 254, 238, 223, 221,
378 213, 225, 177, 197, 171, 196, 159, 4,
379 5, 6, 8, 9, 10, 11, 12, 13,
380 14, 15, 16, 17, 19, 20, 21, 22,
381 23, 24, 25, 26, 27, 28, 30, 31,
382 32, 33, 34, 35, 36, 37, 38, 39,
383 41, 42, 43, 44, 45, 46, 47, 48,
384 49, 50, 52, 53, 54, 55, 56, 57,
385 58, 59, 60, 61, 63, 64, 65, 66,
386 67, 68, 69, 70, 71, 72, 74, 75,
387 76, 77, 78, 79, 80, 81, 82, 83,
388 86, 87, 88, 89, 90, 91, 92, 93,
389 94, 95, 97, 98, 99, 100, 101, 102,
390 103, 104, 105, 106, 108, 109, 110, 111,
391 112, 113, 114, 115, 116, 117, 119, 120,
392 121, 122, 123, 124, 125, 126, 127, 128,
393 130, 131, 132, 133, 134, 135, 136, 137,
394 138, 139, 141, 142, 143, 144, 145, 146
398 fbmcompile(str, iflag)
402 register unsigned char *s;
403 register unsigned char *table;
405 register int len = str->str_cur;
409 str_grow(str,len+258);
411 table = (unsigned char*)(str->str_ptr + len + 1);
413 table = Null(unsigned char*);
416 for (i = 0; i < 256; i++) {
421 while (s >= (unsigned char*)(str->str_ptr))
424 if (table[*s] == len) {
427 table[*s] = table[fold[*s]] = i;
441 str->str_pok |= SP_FBM; /* deep magic */
444 s = (unsigned char*)(str->str_ptr); /* deeper magic */
446 s = Null(unsigned char*);
449 register int tmp, foldtmp;
450 str->str_pok |= SP_CASEFOLD;
451 for (i = 0; i < len; i++) {
453 foldtmp=freq[fold[s[i]]];
454 if (tmp < frequency && foldtmp < frequency) {
456 /* choose most frequent among the two */
457 frequency = (tmp > foldtmp) ? tmp : foldtmp;
462 for (i = 0; i < len; i++) {
463 if (freq[s[i]] < frequency) {
465 frequency = freq[s[i]];
469 str->str_rare = s[rarest];
470 str->str_state = rarest;
473 fprintf(stderr,"rarest char %c at %d\n",str->str_rare, str->str_state);
478 fbminstr(big, bigend, littlestr)
480 register unsigned char *bigend;
483 register unsigned char *s;
485 register int littlelen;
486 register unsigned char *little;
487 register unsigned char *table;
488 register unsigned char *olds;
489 register unsigned char *oldlittle;
492 if (!(littlestr->str_pok & SP_FBM))
493 return ninstr((char*)big,(char*)bigend,
494 littlestr->str_ptr, littlestr->str_ptr + littlestr->str_cur);
497 littlelen = littlestr->str_cur;
499 if (littlestr->str_pok & SP_TAIL && !multiline) { /* tail anchored? */
500 if (littlelen > bigend - big)
502 little = (unsigned char*)littlestr->str_ptr;
503 if (littlestr->str_pok & SP_CASEFOLD) { /* oops, fake it */
504 big = bigend - littlelen; /* just start near end */
505 if (bigend[-1] == '\n' && little[littlelen-1] != '\n')
509 s = bigend - littlelen;
510 if (*s == *little && bcmp(s,little,littlelen)==0)
511 return (char*)s; /* how sweet it is */
512 else if (bigend[-1] == '\n' && little[littlelen-1] != '\n') {
514 if (*s == *little && bcmp(s,little,littlelen)==0)
520 table = (unsigned char*)(littlestr->str_ptr + littlelen + 1);
522 table = Null(unsigned char*);
524 s = big + --littlelen;
525 oldlittle = little = table - 2;
526 if (littlestr->str_pok & SP_CASEFOLD) { /* case insensitive? */
529 if (tmp = table[*s]) {
533 tmp = littlelen; /* less expensive than calling strncmp() */
536 if (*--s == *--little || fold[*s] == *little)
538 s = olds + 1; /* here we pay the price for failure */
540 if (s < bigend) /* fake up continue to outer loop */
553 if (tmp = table[*s]) {
557 tmp = littlelen; /* less expensive than calling strncmp() */
560 if (*--s == *--little)
562 s = olds + 1; /* here we pay the price for failure */
564 if (s < bigend) /* fake up continue to outer loop */
578 screaminstr(bigstr, littlestr)
582 register unsigned char *s, *x;
583 register unsigned char *big;
585 register int previous;
587 register unsigned char *little;
588 register unsigned char *bigend;
589 register unsigned char *littleend;
591 if ((pos = screamfirst[littlestr->str_rare]) < 0)
594 little = (unsigned char *)(littlestr->str_ptr);
596 little = Null(unsigned char *);
598 littleend = little + littlestr->str_cur;
600 previous = littlestr->str_state;
602 big = (unsigned char *)(bigstr->str_ptr);
604 big = Null(unsigned char*);
606 bigend = big + bigstr->str_cur;
608 while (pos < previous) {
610 if (!(pos += screamnext[pos]))
614 if (littlestr->str_pok & SP_CASEFOLD) { /* case insignificant? */
616 if (big[pos] != first && big[pos] != fold[first])
618 for (x=big+pos+1,s=little; s < littleend; /**/ ) {
621 if (*s++ != *x++ && fold[*(s-1)] != *(x-1)) {
628 return (char *)(big+pos);
634 pos += screamnext[pos] /* does this goof up anywhere? */
642 if (big[pos] != first)
644 for (x=big+pos+1,s=little; s < littleend; /**/ ) {
654 return (char *)(big+pos);
660 pos += screamnext[pos]
669 /* copy a string to a safe spot */
675 register char *newaddr;
677 New(902,newaddr,strlen(str)+1,char);
678 (void)strcpy(newaddr,str);
682 /* same thing but with a known length */
689 register char *newaddr;
691 New(903,newaddr,len+1,char);
692 (void)bcopy(str,newaddr,len); /* might not be null terminated */
693 newaddr[len] = '\0'; /* is now */
697 /* grow a static string to at least a certain length */
700 growstr(strptr,curlen,newlen)
705 if (newlen > *curlen) { /* need more room? */
707 Renew(*strptr,newlen,char);
709 New(905,*strptr,newlen,char);
716 mess(pat,a1,a2,a3,a4)
723 (void)sprintf(s,pat,a1,a2,a3,a4);
727 (void)sprintf(s," at %s line %ld",
728 in_eval?filename:origfilename, (long)line);
732 stab_io(last_in_stab) &&
733 stab_io(last_in_stab)->lines ) {
734 (void)sprintf(s,", <%s> line %ld",
735 last_in_stab == argvstab ? "" : stab_name(last_in_stab),
736 (long)stab_io(last_in_stab)->lines);
739 (void)strcpy(s,".\n");
744 fatal(pat,a1,a2,a3,a4)
749 extern char *e_tmpname;
752 mess(pat,a1,a2,a3,a4);
754 str_set(stab_val(stabent("@",TRUE)),buf);
756 while (loop_ptr >= 0 && (!loop_stack[loop_ptr].loop_label ||
757 strNE(tmps,loop_stack[loop_ptr].loop_label) )) {
760 deb("(Skipping label #%d %s)\n",loop_ptr,
761 loop_stack[loop_ptr].loop_label);
768 deb("(Found label #%d %s)\n",loop_ptr,
769 loop_stack[loop_ptr].loop_label);
774 fatal("Bad label: %s", tmps);
776 longjmp(loop_stack[loop_ptr].loop_env, 1);
779 (void)fflush(stderr);
781 (void)UNLINK(e_tmpname);
783 exit(errno?errno:(statusvalue?statusvalue:255));
787 warn(pat,a1,a2,a3,a4)
791 mess(pat,a1,a2,a3,a4);
799 (void)fflush(stderr);
818 pat = va_arg(args, char *);
820 (void) vsprintf(s,pat,args);
825 (void)sprintf(s," at %s line %ld",
826 in_eval?filename:origfilename, (long)line);
830 stab_io(last_in_stab) &&
831 stab_io(last_in_stab)->lines ) {
832 (void)sprintf(s,", <%s> line %ld",
833 last_in_stab == argvstab ? "" : last_in_stab->str_magic->str_ptr,
834 (long)stab_io(last_in_stab)->lines);
837 (void)strcpy(s,".\n");
847 extern char *e_tmpname;
858 str_set(stab_val(stabent("@",TRUE)),buf);
860 while (loop_ptr >= 0 && (!loop_stack[loop_ptr].loop_label ||
861 strNE(tmps,loop_stack[loop_ptr].loop_label) )) {
864 deb("(Skipping label #%d %s)\n",loop_ptr,
865 loop_stack[loop_ptr].loop_label);
872 deb("(Found label #%d %s)\n",loop_ptr,
873 loop_stack[loop_ptr].loop_label);
878 fatal("Bad label: %s", tmps);
880 longjmp(loop_stack[loop_ptr].loop_env, 1);
883 (void)fflush(stderr);
885 (void)UNLINK(e_tmpname);
887 exit((int)(errno?errno:(statusvalue?statusvalue:255)));
911 (void)fflush(stderr);
915 static bool firstsetenv = TRUE;
916 extern char **environ;
922 register int i=envix(nam); /* where does it go? */
926 environ[i] = environ[i+1];
931 if (!environ[i]) { /* does not exist yet */
932 if (firstsetenv) { /* need we copy environment? */
936 New(901,tmpenv, i+2, char*);
938 for (j=0; j<i; j++) /* copy environment */
939 tmpenv[j] = environ[j];
940 environ = tmpenv; /* tell exec where it is now */
943 Renew(environ, i+2, char*); /* just expand it a bit */
944 environ[i+1] = Nullch; /* make sure it's null terminated */
946 New(904, environ[i], strlen(nam) + strlen(val) + 2, char);
947 /* this may or may not be in */
948 /* the old environ structure */
949 (void)sprintf(environ[i],"%s=%s",nam,val);/* all that work just for this */
956 register int i, len = strlen(nam);
958 for (i = 0; environ[i]; i++) {
959 if (strnEQ(environ[i],nam,len) && environ[i][len] == '=')
960 break; /* strnEQ must come first to avoid */
961 } /* potential SEGV's */
966 unlnk(f) /* unlink all versions of a file */
971 for (i = 0; unlink(f) >= 0; i++) ;
1015 vsprintf(dest, pat, args)
1016 char *dest, *pat, *args;
1020 fakebuf._ptr = dest;
1021 fakebuf._cnt = 32767;
1022 fakebuf._flag = _IOWRT|_IOSTRG;
1023 _doprnt(pat, args, &fakebuf); /* what a kludge */
1024 (void)putc('\0', &fakebuf);
1028 return 0; /* perl doesn't use return value */
1034 vfprintf(fd, pat, args)
1038 _doprnt(pat, args, fd);
1039 return 0; /* wrong, but perl doesn't use the return value */
1042 #endif /* VPRINTF */
1043 #endif /* VARARGS */
1046 #if BYTEORDER != 0x4321
1051 #if (BYTEORDER & 1) == 0
1054 result = ((s & 255) << 8) + ((s >> 8) & 255);
1067 char c[sizeof(long)];
1070 #if BYTEORDER == 0x1234
1071 u.c[0] = (l >> 24) & 255;
1072 u.c[1] = (l >> 16) & 255;
1073 u.c[2] = (l >> 8) & 255;
1077 #if ((BYTEORDER - 0x1111) & 0x444) || !(BYTEORDER & 0xf)
1078 fatal("Unknown BYTEORDER\n");
1083 for (o = BYTEORDER - 0x1111, s = 0; s < (sizeof(long)*8); o >>= 4, s += 8) {
1084 u.c[o & 0xf] = (l >> s) & 255;
1097 char c[sizeof(long)];
1100 #if BYTEORDER == 0x1234
1101 u.c[0] = (l >> 24) & 255;
1102 u.c[1] = (l >> 16) & 255;
1103 u.c[2] = (l >> 8) & 255;
1107 #if ((BYTEORDER - 0x1111) & 0x444) || !(BYTEORDER & 0xf)
1108 fatal("Unknown BYTEORDER\n");
1115 for (o = BYTEORDER - 0x1111, s = 0; s < (sizeof(long)*8); o >>= 4, s += 8) {
1116 l |= (u.c[o & 0xf] & 255) << s;
1123 #endif /* BYTEORDER != 0x4321 */
1133 register int this, that;
1136 int doexec = strNE(cmd,"-");
1140 this = (*mode == 'w');
1142 while ((pid = (doexec?vfork():fork())) < 0) {
1143 if (errno != EAGAIN) {
1146 fatal("Can't fork");
1155 if (p[THIS] != (*mode == 'r')) {
1156 dup2(p[THIS], *mode == 'r');
1160 #if !defined(FCNTL) || !defined(F_SETFD)
1166 for (fd = 3; fd < NOFILE; fd++)
1169 do_exec(cmd); /* may or may not use the shell */
1172 if (tmpstab = stabent("$",allstabs))
1173 str_numset(STAB_STR(tmpstab),(double)getpid());
1180 str = afetch(pidstatary,p[this],TRUE);
1181 str_numset(str,(double)pid);
1184 return fdopen(p[this], mode);
1193 struct stat tmpstatbuf;
1195 fprintf(stderr,"%s", s);
1196 for (fd = 0; fd < 32; fd++) {
1197 if (fstat(fd,&tmpstatbuf) >= 0)
1198 fprintf(stderr," %d",fd);
1200 fprintf(stderr,"\n");
1214 while ((fd = dup(oldfd)) != newfd) /* good enough for low fd's */
1217 close(fdtmp[--fdx]);
1226 register int result;
1228 void (*hstat)(), (*istat)(), (*qstat)();
1230 int (*hstat)(), (*istat)(), (*qstat)();
1236 str = afetch(pidstatary,fileno(ptr),TRUE);
1238 pid = (int)str_gnum(str);
1241 hstat = signal(SIGHUP, SIG_IGN);
1242 istat = signal(SIGINT, SIG_IGN);
1243 qstat = signal(SIGQUIT, SIG_IGN);
1245 if (wait4(pid,&status,0,Null(struct rusage *)) < 0)
1248 if (pid < 0) /* already exited? */
1249 status = str->str_cur;
1251 while ((result = wait(&status)) != pid && result >= 0)
1252 pidgone(result,status);
1257 signal(SIGHUP, hstat);
1258 signal(SIGINT, istat);
1259 signal(SIGQUIT, qstat);
1260 str_numset(str,0.0);
1275 for (count = pidstatary->ary_fill; count >= 0; --count) {
1276 if ((str = afetch(pidstatary,count,FALSE)) &&
1277 ((int)str->str_u.str_nval) == pid) {
1278 str_numset(str, -str->str_u.str_nval);
1279 str->str_cur = status;
1288 register unsigned char *s1;
1289 register unsigned char *s2;
1295 if (tmp = *s1++ - *s2++)
1303 repeatcpy(to,from,len,count)
1305 register char *from;
1310 register char *frombase = from;
1318 while (count-- > 0) {
1319 for (todo = len; todo > 0; todo--) {
1326 #ifndef CASTNEGFLOAT
1334 return (unsigned long)f;
1336 return (unsigned long)along;