f8586b5f9601a87c656d1665e9f3780edda2fcfa
[perl.git] / util.c
1 /* $RCSfile: util.c,v $$Revision: 4.0.1.4 $$Date: 91/11/11 16:48:54 $
2  *
3  *    Copyright (c) 1991, Larry Wall
4  *
5  *    You may distribute under the terms of either the GNU General Public
6  *    License or the Artistic License, as specified in the README file.
7  *
8  * $Log:        util.c,v $
9  * Revision 4.0.1.4  91/11/11  16:48:54  lwall
10  * patch19: study was busted by 4.018
11  * patch19: added little-endian pack/unpack options
12  * 
13  * Revision 4.0.1.3  91/11/05  19:18:26  lwall
14  * patch11: safe malloc code now integrated into Perl's malloc when possible
15  * patch11: index("little", "longer string") could visit faraway places
16  * patch11: warn '-' x 10000 dumped core
17  * patch11: forked exec on non-existent program now issues a warning
18  * 
19  * Revision 4.0.1.2  91/06/07  12:10:42  lwall
20  * patch4: new copyright notice
21  * patch4: made some allowances for "semi-standard" C
22  * patch4: index() could blow up searching for null string
23  * patch4: taintchecks could improperly modify parent in vfork()
24  * patch4: exec would close files even if you cleared close-on-exec flag
25  * 
26  * Revision 4.0.1.1  91/04/12  09:19:25  lwall
27  * patch1: random cleanup in cpp namespace
28  * 
29  * Revision 4.0  91/03/20  01:56:39  lwall
30  * 4.0 baseline.
31  * 
32  */
33 /*SUPPRESS 112*/
34
35 #include "EXTERN.h"
36 #include "perl.h"
37
38 #if !defined(NSIG) || defined(M_UNIX) || defined(M_XENIX)
39 #include <signal.h>
40 #endif
41
42 #ifdef I_VFORK
43 #  include <vfork.h>
44 #endif
45
46 #ifdef I_VARARGS
47 #  include <varargs.h>
48 #endif
49
50 #ifdef I_FCNTL
51 #  include <fcntl.h>
52 #endif
53 #ifdef I_SYS_FILE
54 #  include <sys/file.h>
55 #endif
56
57 #define FLUSH
58
59 #ifndef safemalloc
60
61 static char nomem[] = "Out of memory!\n";
62
63 /* paranoid version of malloc */
64
65 #ifdef DEBUGGING
66 static int an = 0;
67 #endif
68
69 /* NOTE:  Do not call the next three routines directly.  Use the macros
70  * in handy.h, so that we can easily redefine everything to do tracking of
71  * allocated hunks back to the original New to track down any memory leaks.
72  */
73
74 char *
75 safemalloc(size)
76 #ifdef MSDOS
77 unsigned long size;
78 #else
79 MEM_SIZE size;
80 #endif /* MSDOS */
81 {
82     char *ptr;
83 #ifndef STANDARD_C
84     char *malloc();
85 #endif /* ! STANDARD_C */
86
87 #ifdef MSDOS
88         if (size > 0xffff) {
89                 fprintf(stderr, "Allocation too large: %lx\n", size) FLUSH;
90                 exit(1);
91         }
92 #endif /* MSDOS */
93 #ifdef DEBUGGING
94     if ((long)size < 0)
95         fatal("panic: malloc");
96 #endif
97     ptr = malloc(size?size:1);  /* malloc(0) is NASTY on our system */
98 #ifdef DEBUGGING
99 #  ifndef I286
100     if (debug & 128)
101         fprintf(stderr,"0x%x: (%05d) malloc %d bytes\n",ptr,an++,size);
102 #  else
103     if (debug & 128)
104         fprintf(stderr,"0x%lx: (%05d) malloc %d bytes\n",ptr,an++,size);
105 #  endif
106 #endif
107     if (ptr != Nullch)
108         return ptr;
109     else {
110         fputs(nomem,stderr) FLUSH;
111         exit(1);
112     }
113     /*NOTREACHED*/
114 #ifdef lint
115     return ptr;
116 #endif
117 }
118
119 /* paranoid version of realloc */
120
121 char *
122 saferealloc(where,size)
123 char *where;
124 #ifndef MSDOS
125 MEM_SIZE size;
126 #else
127 unsigned long size;
128 #endif /* MSDOS */
129 {
130     char *ptr;
131 #ifndef STANDARD_C
132     char *realloc();
133 #endif /* ! STANDARD_C */
134
135 #ifdef MSDOS
136         if (size > 0xffff) {
137                 fprintf(stderr, "Reallocation too large: %lx\n", size) FLUSH;
138                 exit(1);
139         }
140 #endif /* MSDOS */
141     if (!where)
142         fatal("Null realloc");
143 #ifdef DEBUGGING
144     if ((long)size < 0)
145         fatal("panic: realloc");
146 #endif
147     ptr = realloc(where,size?size:1);   /* realloc(0) is NASTY on our system */
148 #ifdef DEBUGGING
149 #  ifndef I286
150     if (debug & 128) {
151         fprintf(stderr,"0x%x: (%05d) rfree\n",where,an++);
152         fprintf(stderr,"0x%x: (%05d) realloc %d bytes\n",ptr,an++,size);
153     }
154 #  else
155     if (debug & 128) {
156         fprintf(stderr,"0x%lx: (%05d) rfree\n",where,an++);
157         fprintf(stderr,"0x%lx: (%05d) realloc %d bytes\n",ptr,an++,size);
158     }
159 #  endif
160 #endif
161     if (ptr != Nullch)
162         return ptr;
163     else {
164         fputs(nomem,stderr) FLUSH;
165         exit(1);
166     }
167     /*NOTREACHED*/
168 #ifdef lint
169     return ptr;
170 #endif
171 }
172
173 /* safe version of free */
174
175 void
176 safefree(where)
177 char *where;
178 {
179 #ifdef DEBUGGING
180 #  ifndef I286
181     if (debug & 128)
182         fprintf(stderr,"0x%x: (%05d) free\n",where,an++);
183 #  else
184     if (debug & 128)
185         fprintf(stderr,"0x%lx: (%05d) free\n",where,an++);
186 #  endif
187 #endif
188     if (where) {
189         /*SUPPRESS 701*/
190         free(where);
191     }
192 }
193
194 #endif /* !safemalloc */
195
196 #ifdef LEAKTEST
197
198 #define ALIGN sizeof(long)
199
200 char *
201 safexmalloc(x,size)
202 int x;
203 MEM_SIZE size;
204 {
205     register char *where;
206
207     where = safemalloc(size + ALIGN);
208     xcount[x]++;
209     where[0] = x % 100;
210     where[1] = x / 100;
211     return where + ALIGN;
212 }
213
214 char *
215 safexrealloc(where,size)
216 char *where;
217 MEM_SIZE size;
218 {
219     return saferealloc(where - ALIGN, size + ALIGN) + ALIGN;
220 }
221
222 void
223 safexfree(where)
224 char *where;
225 {
226     int x;
227
228     if (!where)
229         return;
230     where -= ALIGN;
231     x = where[0] + 100 * where[1];
232     xcount[x]--;
233     safefree(where);
234 }
235
236 xstat()
237 {
238     register int i;
239
240     for (i = 0; i < MAXXCOUNT; i++) {
241         if (xcount[i] > lastxcount[i]) {
242             fprintf(stderr,"%2d %2d\t%ld\n", i / 100, i % 100, xcount[i]);
243             lastxcount[i] = xcount[i];
244         }
245     }
246 }
247
248 #endif /* LEAKTEST */
249
250 /* copy a string up to some (non-backslashed) delimiter, if any */
251
252 char *
253 cpytill(to,from,fromend,delim,retlen)
254 register char *to;
255 register char *from;
256 register char *fromend;
257 register int delim;
258 int *retlen;
259 {
260     char *origto = to;
261
262     for (; from < fromend; from++,to++) {
263         if (*from == '\\') {
264             if (from[1] == delim)
265                 from++;
266             else if (from[1] == '\\')
267                 *to++ = *from++;
268         }
269         else if (*from == delim)
270             break;
271         *to = *from;
272     }
273     *to = '\0';
274     *retlen = to - origto;
275     return from;
276 }
277
278 /* return ptr to little string in big string, NULL if not found */
279 /* This routine was donated by Corey Satten. */
280
281 char *
282 instr(big, little)
283 register char *big;
284 register char *little;
285 {
286     register char *s, *x;
287     register int first;
288
289     if (!little)
290         return big;
291     first = *little++;
292     if (!first)
293         return big;
294     while (*big) {
295         if (*big++ != first)
296             continue;
297         for (x=big,s=little; *s; /**/ ) {
298             if (!*x)
299                 return Nullch;
300             if (*s++ != *x++) {
301                 s--;
302                 break;
303             }
304         }
305         if (!*s)
306             return big-1;
307     }
308     return Nullch;
309 }
310
311 /* same as instr but allow embedded nulls */
312
313 char *
314 ninstr(big, bigend, little, lend)
315 register char *big;
316 register char *bigend;
317 char *little;
318 char *lend;
319 {
320     register char *s, *x;
321     register int first = *little;
322     register char *littleend = lend;
323
324     if (!first && little > littleend)
325         return big;
326     if (bigend - big < littleend - little)
327         return Nullch;
328     bigend -= littleend - little++;
329     while (big <= bigend) {
330         if (*big++ != first)
331             continue;
332         for (x=big,s=little; s < littleend; /**/ ) {
333             if (*s++ != *x++) {
334                 s--;
335                 break;
336             }
337         }
338         if (s >= littleend)
339             return big-1;
340     }
341     return Nullch;
342 }
343
344 /* reverse of the above--find last substring */
345
346 char *
347 rninstr(big, bigend, little, lend)
348 register char *big;
349 char *bigend;
350 char *little;
351 char *lend;
352 {
353     register char *bigbeg;
354     register char *s, *x;
355     register int first = *little;
356     register char *littleend = lend;
357
358     if (!first && little > littleend)
359         return bigend;
360     bigbeg = big;
361     big = bigend - (littleend - little++);
362     while (big >= bigbeg) {
363         if (*big-- != first)
364             continue;
365         for (x=big+2,s=little; s < littleend; /**/ ) {
366             if (*s++ != *x++) {
367                 s--;
368                 break;
369             }
370         }
371         if (s >= littleend)
372             return big+1;
373     }
374     return Nullch;
375 }
376
377 unsigned char fold[] = {
378         0,      1,      2,      3,      4,      5,      6,      7,
379         8,      9,      10,     11,     12,     13,     14,     15,
380         16,     17,     18,     19,     20,     21,     22,     23,
381         24,     25,     26,     27,     28,     29,     30,     31,
382         32,     33,     34,     35,     36,     37,     38,     39,
383         40,     41,     42,     43,     44,     45,     46,     47,
384         48,     49,     50,     51,     52,     53,     54,     55,
385         56,     57,     58,     59,     60,     61,     62,     63,
386         64,     'a',    'b',    'c',    'd',    'e',    'f',    'g',
387         'h',    'i',    'j',    'k',    'l',    'm',    'n',    'o',
388         'p',    'q',    'r',    's',    't',    'u',    'v',    'w',
389         'x',    'y',    'z',    91,     92,     93,     94,     95,
390         96,     'A',    'B',    'C',    'D',    'E',    'F',    'G',
391         'H',    'I',    'J',    'K',    'L',    'M',    'N',    'O',
392         'P',    'Q',    'R',    'S',    'T',    'U',    'V',    'W',
393         'X',    'Y',    'Z',    123,    124,    125,    126,    127,
394         128,    129,    130,    131,    132,    133,    134,    135,
395         136,    137,    138,    139,    140,    141,    142,    143,
396         144,    145,    146,    147,    148,    149,    150,    151,
397         152,    153,    154,    155,    156,    157,    158,    159,
398         160,    161,    162,    163,    164,    165,    166,    167,
399         168,    169,    170,    171,    172,    173,    174,    175,
400         176,    177,    178,    179,    180,    181,    182,    183,
401         184,    185,    186,    187,    188,    189,    190,    191,
402         192,    193,    194,    195,    196,    197,    198,    199,
403         200,    201,    202,    203,    204,    205,    206,    207,
404         208,    209,    210,    211,    212,    213,    214,    215,
405         216,    217,    218,    219,    220,    221,    222,    223,    
406         224,    225,    226,    227,    228,    229,    230,    231,
407         232,    233,    234,    235,    236,    237,    238,    239,
408         240,    241,    242,    243,    244,    245,    246,    247,
409         248,    249,    250,    251,    252,    253,    254,    255
410 };
411
412 static unsigned char freq[] = {
413         1,      2,      84,     151,    154,    155,    156,    157,
414         165,    246,    250,    3,      158,    7,      18,     29,
415         40,     51,     62,     73,     85,     96,     107,    118,
416         129,    140,    147,    148,    149,    150,    152,    153,
417         255,    182,    224,    205,    174,    176,    180,    217,
418         233,    232,    236,    187,    235,    228,    234,    226,
419         222,    219,    211,    195,    188,    193,    185,    184,
420         191,    183,    201,    229,    181,    220,    194,    162,
421         163,    208,    186,    202,    200,    218,    198,    179,
422         178,    214,    166,    170,    207,    199,    209,    206,
423         204,    160,    212,    216,    215,    192,    175,    173,
424         243,    172,    161,    190,    203,    189,    164,    230,
425         167,    248,    227,    244,    242,    255,    241,    231,
426         240,    253,    169,    210,    245,    237,    249,    247,
427         239,    168,    252,    251,    254,    238,    223,    221,
428         213,    225,    177,    197,    171,    196,    159,    4,
429         5,      6,      8,      9,      10,     11,     12,     13,
430         14,     15,     16,     17,     19,     20,     21,     22,
431         23,     24,     25,     26,     27,     28,     30,     31,
432         32,     33,     34,     35,     36,     37,     38,     39,
433         41,     42,     43,     44,     45,     46,     47,     48,
434         49,     50,     52,     53,     54,     55,     56,     57,
435         58,     59,     60,     61,     63,     64,     65,     66,
436         67,     68,     69,     70,     71,     72,     74,     75,
437         76,     77,     78,     79,     80,     81,     82,     83,
438         86,     87,     88,     89,     90,     91,     92,     93,
439         94,     95,     97,     98,     99,     100,    101,    102,
440         103,    104,    105,    106,    108,    109,    110,    111,
441         112,    113,    114,    115,    116,    117,    119,    120,
442         121,    122,    123,    124,    125,    126,    127,    128,
443         130,    131,    132,    133,    134,    135,    136,    137,
444         138,    139,    141,    142,    143,    144,    145,    146
445 };
446
447 void
448 fbmcompile(str, iflag)
449 STR *str;
450 int iflag;
451 {
452     register unsigned char *s;
453     register unsigned char *table;
454     register unsigned int i;
455     register unsigned int len = str->str_cur;
456     int rarest = 0;
457     unsigned int frequency = 256;
458
459     Str_Grow(str,len+258);
460 #ifndef lint
461     table = (unsigned char*)(str->str_ptr + len + 1);
462 #else
463     table = Null(unsigned char*);
464 #endif
465     s = table - 2;
466     for (i = 0; i < 256; i++) {
467         table[i] = len;
468     }
469     i = 0;
470 #ifndef lint
471     while (s >= (unsigned char*)(str->str_ptr))
472 #endif
473     {
474         if (table[*s] == len) {
475 #ifndef pdp11
476             if (iflag)
477                 table[*s] = table[fold[*s]] = i;
478 #else
479             if (iflag) {
480                 int j;
481                 j = fold[*s];
482                 table[j] = i;
483                 table[*s] = i;
484             }
485 #endif /* pdp11 */
486             else
487                 table[*s] = i;
488         }
489         s--,i++;
490     }
491     str->str_pok |= SP_FBM;             /* deep magic */
492
493 #ifndef lint
494     s = (unsigned char*)(str->str_ptr);         /* deeper magic */
495 #else
496     s = Null(unsigned char*);
497 #endif
498     if (iflag) {
499         register unsigned int tmp, foldtmp;
500         str->str_pok |= SP_CASEFOLD;
501         for (i = 0; i < len; i++) {
502             tmp=freq[s[i]];
503             foldtmp=freq[fold[s[i]]];
504             if (tmp < frequency && foldtmp < frequency) {
505                 rarest = i;
506                 /* choose most frequent among the two */
507                 frequency = (tmp > foldtmp) ? tmp : foldtmp;
508             }
509         }
510     }
511     else {
512         for (i = 0; i < len; i++) {
513             if (freq[s[i]] < frequency) {
514                 rarest = i;
515                 frequency = freq[s[i]];
516             }
517         }
518     }
519     str->str_rare = s[rarest];
520     str->str_state = rarest;
521 #ifdef DEBUGGING
522     if (debug & 512)
523         fprintf(stderr,"rarest char %c at %d\n",str->str_rare, str->str_state);
524 #endif
525 }
526
527 char *
528 fbminstr(big, bigend, littlestr)
529 unsigned char *big;
530 register unsigned char *bigend;
531 STR *littlestr;
532 {
533     register unsigned char *s;
534     register int tmp;
535     register int littlelen;
536     register unsigned char *little;
537     register unsigned char *table;
538     register unsigned char *olds;
539     register unsigned char *oldlittle;
540
541 #ifndef lint
542     if (!(littlestr->str_pok & SP_FBM)) {
543         if (!littlestr->str_ptr)
544             return (char*)big;
545         return ninstr((char*)big,(char*)bigend,
546                 littlestr->str_ptr, littlestr->str_ptr + littlestr->str_cur);
547     }
548 #endif
549
550     littlelen = littlestr->str_cur;
551 #ifndef lint
552     if (littlestr->str_pok & SP_TAIL && !multiline) {   /* tail anchored? */
553         if (littlelen > bigend - big)
554             return Nullch;
555         little = (unsigned char*)littlestr->str_ptr;
556         if (littlestr->str_pok & SP_CASEFOLD) { /* oops, fake it */
557             big = bigend - littlelen;           /* just start near end */
558             if (bigend[-1] == '\n' && little[littlelen-1] != '\n')
559                 big--;
560         }
561         else {
562             s = bigend - littlelen;
563             if (*s == *little && bcmp(s,little,littlelen)==0)
564                 return (char*)s;                /* how sweet it is */
565             else if (bigend[-1] == '\n' && little[littlelen-1] != '\n'
566               && s > big) {
567                     s--;
568                 if (*s == *little && bcmp(s,little,littlelen)==0)
569                     return (char*)s;
570             }
571             return Nullch;
572         }
573     }
574     table = (unsigned char*)(littlestr->str_ptr + littlelen + 1);
575 #else
576     table = Null(unsigned char*);
577 #endif
578     if (--littlelen >= bigend - big)
579         return Nullch;
580     s = big + littlelen;
581     oldlittle = little = table - 2;
582     if (littlestr->str_pok & SP_CASEFOLD) {     /* case insensitive? */
583         if (s < bigend) {
584           top1:
585             /*SUPPRESS 560*/
586             if (tmp = table[*s]) {
587 #ifdef POINTERRIGOR
588                 if (bigend - s > tmp) {
589                     s += tmp;
590                     goto top1;
591                 }
592 #else
593                 if ((s += tmp) < bigend)
594                     goto top1;
595 #endif
596                 return Nullch;
597             }
598             else {
599                 tmp = littlelen;        /* less expensive than calling strncmp() */
600                 olds = s;
601                 while (tmp--) {
602                     if (*--s == *--little || fold[*s] == *little)
603                         continue;
604                     s = olds + 1;       /* here we pay the price for failure */
605                     little = oldlittle;
606                     if (s < bigend)     /* fake up continue to outer loop */
607                         goto top1;
608                     return Nullch;
609                 }
610 #ifndef lint
611                 return (char *)s;
612 #endif
613             }
614         }
615     }
616     else {
617         if (s < bigend) {
618           top2:
619             /*SUPPRESS 560*/
620             if (tmp = table[*s]) {
621 #ifdef POINTERRIGOR
622                 if (bigend - s > tmp) {
623                     s += tmp;
624                     goto top2;
625                 }
626 #else
627                 if ((s += tmp) < bigend)
628                     goto top2;
629 #endif
630                 return Nullch;
631             }
632             else {
633                 tmp = littlelen;        /* less expensive than calling strncmp() */
634                 olds = s;
635                 while (tmp--) {
636                     if (*--s == *--little)
637                         continue;
638                     s = olds + 1;       /* here we pay the price for failure */
639                     little = oldlittle;
640                     if (s < bigend)     /* fake up continue to outer loop */
641                         goto top2;
642                     return Nullch;
643                 }
644 #ifndef lint
645                 return (char *)s;
646 #endif
647             }
648         }
649     }
650     return Nullch;
651 }
652
653 char *
654 screaminstr(bigstr, littlestr)
655 STR *bigstr;
656 STR *littlestr;
657 {
658     register unsigned char *s, *x;
659     register unsigned char *big;
660     register int pos;
661     register int previous;
662     register int first;
663     register unsigned char *little;
664     register unsigned char *bigend;
665     register unsigned char *littleend;
666
667     if ((pos = screamfirst[littlestr->str_rare]) < 0) 
668         return Nullch;
669 #ifndef lint
670     little = (unsigned char *)(littlestr->str_ptr);
671 #else
672     little = Null(unsigned char *);
673 #endif
674     littleend = little + littlestr->str_cur;
675     first = *little++;
676     previous = littlestr->str_state;
677 #ifndef lint
678     big = (unsigned char *)(bigstr->str_ptr);
679 #else
680     big = Null(unsigned char*);
681 #endif
682     bigend = big + bigstr->str_cur;
683     while (pos < previous) {
684 #ifndef lint
685         if (!(pos += screamnext[pos]))
686 #endif
687             return Nullch;
688     }
689 #ifdef POINTERRIGOR
690     if (littlestr->str_pok & SP_CASEFOLD) {     /* case insignificant? */
691         do {
692             if (big[pos-previous] != first && big[pos-previous] != fold[first])
693                 continue;
694             for (x=big+pos+1-previous,s=little; s < littleend; /**/ ) {
695                 if (x >= bigend)
696                     return Nullch;
697                 if (*s++ != *x++ && fold[*(s-1)] != *(x-1)) {
698                     s--;
699                     break;
700                 }
701             }
702             if (s == littleend)
703 #ifndef lint
704                 return (char *)(big+pos-previous);
705 #else
706                 return Nullch;
707 #endif
708         } while (
709 #ifndef lint
710                 pos += screamnext[pos]  /* does this goof up anywhere? */
711 #else
712                 pos += screamnext[0]
713 #endif
714             );
715     }
716     else {
717         do {
718             if (big[pos-previous] != first)
719                 continue;
720             for (x=big+pos+1-previous,s=little; s < littleend; /**/ ) {
721                 if (x >= bigend)
722                     return Nullch;
723                 if (*s++ != *x++) {
724                     s--;
725                     break;
726                 }
727             }
728             if (s == littleend)
729 #ifndef lint
730                 return (char *)(big+pos-previous);
731 #else
732                 return Nullch;
733 #endif
734         } while (
735 #ifndef lint
736                 pos += screamnext[pos]
737 #else
738                 pos += screamnext[0]
739 #endif
740             );
741     }
742 #else /* !POINTERRIGOR */
743     big -= previous;
744     if (littlestr->str_pok & SP_CASEFOLD) {     /* case insignificant? */
745         do {
746             if (big[pos] != first && big[pos] != fold[first])
747                 continue;
748             for (x=big+pos+1,s=little; s < littleend; /**/ ) {
749                 if (x >= bigend)
750                     return Nullch;
751                 if (*s++ != *x++ && fold[*(s-1)] != *(x-1)) {
752                     s--;
753                     break;
754                 }
755             }
756             if (s == littleend)
757 #ifndef lint
758                 return (char *)(big+pos);
759 #else
760                 return Nullch;
761 #endif
762         } while (
763 #ifndef lint
764                 pos += screamnext[pos]  /* does this goof up anywhere? */
765 #else
766                 pos += screamnext[0]
767 #endif
768             );
769     }
770     else {
771         do {
772             if (big[pos] != first)
773                 continue;
774             for (x=big+pos+1,s=little; s < littleend; /**/ ) {
775                 if (x >= bigend)
776                     return Nullch;
777                 if (*s++ != *x++) {
778                     s--;
779                     break;
780                 }
781             }
782             if (s == littleend)
783 #ifndef lint
784                 return (char *)(big+pos);
785 #else
786                 return Nullch;
787 #endif
788         } while (
789 #ifndef lint
790                 pos += screamnext[pos]
791 #else
792                 pos += screamnext[0]
793 #endif
794             );
795     }
796 #endif /* POINTERRIGOR */
797     return Nullch;
798 }
799
800 /* copy a string to a safe spot */
801
802 char *
803 savestr(str)
804 char *str;
805 {
806     register char *newaddr;
807
808     New(902,newaddr,strlen(str)+1,char);
809     (void)strcpy(newaddr,str);
810     return newaddr;
811 }
812
813 /* same thing but with a known length */
814
815 char *
816 nsavestr(str, len)
817 char *str;
818 register int len;
819 {
820     register char *newaddr;
821
822     New(903,newaddr,len+1,char);
823     (void)bcopy(str,newaddr,len);       /* might not be null terminated */
824     newaddr[len] = '\0';                /* is now */
825     return newaddr;
826 }
827
828 /* grow a static string to at least a certain length */
829
830 void
831 growstr(strptr,curlen,newlen)
832 char **strptr;
833 int *curlen;
834 int newlen;
835 {
836     if (newlen > *curlen) {             /* need more room? */
837         if (*curlen)
838             Renew(*strptr,newlen,char);
839         else
840             New(905,*strptr,newlen,char);
841         *curlen = newlen;
842     }
843 }
844
845 #ifndef I_VARARGS
846 /*VARARGS1*/
847 mess(pat,a1,a2,a3,a4)
848 char *pat;
849 long a1, a2, a3, a4;
850 {
851     char *s;
852     int usermess = strEQ(pat,"%s");
853     STR *tmpstr;
854
855     s = buf;
856     if (usermess) {
857         tmpstr = str_mortal(&str_undef);
858         str_set(tmpstr, (char*)a1);
859         *s++ = tmpstr->str_ptr[tmpstr->str_cur-1];
860     }
861     else {
862         (void)sprintf(s,pat,a1,a2,a3,a4);
863         s += strlen(s);
864     }
865
866     if (s[-1] != '\n') {
867         if (curcmd->c_line) {
868             (void)sprintf(s," at %s line %ld",
869               stab_val(curcmd->c_filestab)->str_ptr, (long)curcmd->c_line);
870             s += strlen(s);
871         }
872         if (last_in_stab &&
873             stab_io(last_in_stab) &&
874             stab_io(last_in_stab)->lines ) {
875             (void)sprintf(s,", <%s> line %ld",
876               last_in_stab == argvstab ? "" : stab_name(last_in_stab),
877               (long)stab_io(last_in_stab)->lines);
878             s += strlen(s);
879         }
880         (void)strcpy(s,".\n");
881         if (usermess)
882             str_cat(tmpstr,buf+1);
883     }
884     if (usermess)
885         return tmpstr->str_ptr;
886     else
887         return buf;
888 }
889
890 /*VARARGS1*/
891 fatal(pat,a1,a2,a3,a4)
892 char *pat;
893 long a1, a2, a3, a4;
894 {
895     extern FILE *e_fp;
896     extern char *e_tmpname;
897     char *tmps;
898     char *message;
899
900     message = mess(pat,a1,a2,a3,a4);
901     if (in_eval) {
902         str_set(stab_val(stabent("@",TRUE)),message);
903         tmps = "_EVAL_";
904         while (loop_ptr >= 0 && (!loop_stack[loop_ptr].loop_label ||
905           strNE(tmps,loop_stack[loop_ptr].loop_label) )) {
906 #ifdef DEBUGGING
907             if (debug & 4) {
908                 deb("(Skipping label #%d %s)\n",loop_ptr,
909                     loop_stack[loop_ptr].loop_label);
910             }
911 #endif
912             loop_ptr--;
913         }
914 #ifdef DEBUGGING
915         if (debug & 4) {
916             deb("(Found label #%d %s)\n",loop_ptr,
917                 loop_stack[loop_ptr].loop_label);
918         }
919 #endif
920         if (loop_ptr < 0) {
921             in_eval = 0;
922             fatal("Bad label: %s", tmps);
923         }
924         longjmp(loop_stack[loop_ptr].loop_env, 1);
925     }
926     fputs(message,stderr);
927     (void)fflush(stderr);
928     if (e_fp)
929         (void)UNLINK(e_tmpname);
930     statusvalue >>= 8;
931     exit((int)((errno&255)?errno:((statusvalue&255)?statusvalue:255)));
932 }
933
934 /*VARARGS1*/
935 warn(pat,a1,a2,a3,a4)
936 char *pat;
937 long a1, a2, a3, a4;
938 {
939     char *message;
940
941     message = mess(pat,a1,a2,a3,a4);
942     fputs(message,stderr);
943 #ifdef LEAKTEST
944 #ifdef DEBUGGING
945     if (debug & 4096)
946         xstat();
947 #endif
948 #endif
949     (void)fflush(stderr);
950 }
951 #else
952 /*VARARGS0*/
953 char *
954 mess(args)
955 va_list args;
956 {
957     char *pat;
958     char *s;
959     STR *tmpstr;
960     int usermess;
961 #ifndef HAS_VPRINTF
962 #ifdef CHARVSPRINTF
963     char *vsprintf();
964 #else
965     int vsprintf();
966 #endif
967 #endif
968
969 #ifdef lint
970     pat = Nullch;
971 #else
972     pat = va_arg(args, char *);
973 #endif
974     s = buf;
975     usermess = strEQ(pat, "%s");
976     if (usermess) {
977         tmpstr = str_mortal(&str_undef);
978         str_set(tmpstr, va_arg(args, char *));
979         *s++ = tmpstr->str_ptr[tmpstr->str_cur-1];
980     }
981     else {
982         (void) vsprintf(s,pat,args);
983         s += strlen(s);
984     }
985
986     if (s[-1] != '\n') {
987         if (curcmd->c_line) {
988             (void)sprintf(s," at %s line %ld",
989               stab_val(curcmd->c_filestab)->str_ptr, (long)curcmd->c_line);
990             s += strlen(s);
991         }
992         if (last_in_stab &&
993             stab_io(last_in_stab) &&
994             stab_io(last_in_stab)->lines ) {
995             (void)sprintf(s,", <%s> line %ld",
996               last_in_stab == argvstab ? "" : last_in_stab->str_magic->str_ptr,
997               (long)stab_io(last_in_stab)->lines);
998             s += strlen(s);
999         }
1000         (void)strcpy(s,".\n");
1001         if (usermess)
1002             str_cat(tmpstr,buf+1);
1003     }
1004
1005     if (usermess)
1006         return tmpstr->str_ptr;
1007     else
1008         return buf;
1009 }
1010
1011 /*VARARGS0*/
1012 fatal(va_alist)
1013 va_dcl
1014 {
1015     va_list args;
1016     extern FILE *e_fp;
1017     extern char *e_tmpname;
1018     char *tmps;
1019     char *message;
1020
1021 #ifndef lint
1022     va_start(args);
1023 #else
1024     args = 0;
1025 #endif
1026     message = mess(args);
1027     va_end(args);
1028     if (in_eval) {
1029         str_set(stab_val(stabent("@",TRUE)),message);
1030         tmps = "_EVAL_";
1031         while (loop_ptr >= 0 && (!loop_stack[loop_ptr].loop_label ||
1032           strNE(tmps,loop_stack[loop_ptr].loop_label) )) {
1033 #ifdef DEBUGGING
1034             if (debug & 4) {
1035                 deb("(Skipping label #%d %s)\n",loop_ptr,
1036                     loop_stack[loop_ptr].loop_label);
1037             }
1038 #endif
1039             loop_ptr--;
1040         }
1041 #ifdef DEBUGGING
1042         if (debug & 4) {
1043             deb("(Found label #%d %s)\n",loop_ptr,
1044                 loop_stack[loop_ptr].loop_label);
1045         }
1046 #endif
1047         if (loop_ptr < 0) {
1048             in_eval = 0;
1049             fatal("Bad label: %s", tmps);
1050         }
1051         longjmp(loop_stack[loop_ptr].loop_env, 1);
1052     }
1053     fputs(message,stderr);
1054     (void)fflush(stderr);
1055     if (e_fp)
1056         (void)UNLINK(e_tmpname);
1057     statusvalue >>= 8;
1058     exit((int)((errno&255)?errno:((statusvalue&255)?statusvalue:255)));
1059 }
1060
1061 /*VARARGS0*/
1062 warn(va_alist)
1063 va_dcl
1064 {
1065     va_list args;
1066     char *message;
1067
1068 #ifndef lint
1069     va_start(args);
1070 #else
1071     args = 0;
1072 #endif
1073     message = mess(args);
1074     va_end(args);
1075
1076     fputs(message,stderr);
1077 #ifdef LEAKTEST
1078 #ifdef DEBUGGING
1079     if (debug & 4096)
1080         xstat();
1081 #endif
1082 #endif
1083     (void)fflush(stderr);
1084 }
1085 #endif
1086
1087 void
1088 setenv(nam,val)
1089 char *nam, *val;
1090 {
1091     register int i=envix(nam);          /* where does it go? */
1092
1093     if (environ == origenviron) {       /* need we copy environment? */
1094         int j;
1095         int max;
1096         char **tmpenv;
1097
1098         /*SUPPRESS 530*/
1099         for (max = i; environ[max]; max++) ;
1100         New(901,tmpenv, max+2, char*);
1101         for (j=0; j<max; j++)           /* copy environment */
1102             tmpenv[j] = savestr(environ[j]);
1103         tmpenv[max] = Nullch;
1104         environ = tmpenv;               /* tell exec where it is now */
1105     }
1106     if (!val) {
1107         while (environ[i]) {
1108             environ[i] = environ[i+1];
1109             i++;
1110         }
1111         return;
1112     }
1113     if (!environ[i]) {                  /* does not exist yet */
1114         Renew(environ, i+2, char*);     /* just expand it a bit */
1115         environ[i+1] = Nullch;  /* make sure it's null terminated */
1116     }
1117     else
1118         Safefree(environ[i]);
1119     New(904, environ[i], strlen(nam) + strlen(val) + 2, char);
1120 #ifndef MSDOS
1121     (void)sprintf(environ[i],"%s=%s",nam,val);/* all that work just for this */
1122 #else
1123     /* MS-DOS requires environment variable names to be in uppercase */
1124     /* [Tom Dinger, 27 August 1990: Well, it doesn't _require_ it, but
1125      * some utilities and applications may break because they only look
1126      * for upper case strings. (Fixed strupr() bug here.)]
1127      */
1128     strcpy(environ[i],nam); strupr(environ[i]);
1129     (void)sprintf(environ[i] + strlen(nam),"=%s",val);
1130 #endif /* MSDOS */
1131 }
1132
1133 int
1134 envix(nam)
1135 char *nam;
1136 {
1137     register int i, len = strlen(nam);
1138
1139     for (i = 0; environ[i]; i++) {
1140         if (strnEQ(environ[i],nam,len) && environ[i][len] == '=')
1141             break;                      /* strnEQ must come first to avoid */
1142     }                                   /* potential SEGV's */
1143     return i;
1144 }
1145
1146 #ifdef EUNICE
1147 unlnk(f)        /* unlink all versions of a file */
1148 char *f;
1149 {
1150     int i;
1151
1152     for (i = 0; unlink(f) >= 0; i++) ;
1153     return i ? 0 : -1;
1154 }
1155 #endif
1156
1157 #ifndef HAS_MEMCPY
1158 #ifndef HAS_BCOPY
1159 char *
1160 bcopy(from,to,len)
1161 register char *from;
1162 register char *to;
1163 register int len;
1164 {
1165     char *retval = to;
1166
1167     while (len--)
1168         *to++ = *from++;
1169     return retval;
1170 }
1171 #endif
1172
1173 #ifndef HAS_BZERO
1174 char *
1175 bzero(loc,len)
1176 register char *loc;
1177 register int len;
1178 {
1179     char *retval = loc;
1180
1181     while (len--)
1182         *loc++ = 0;
1183     return retval;
1184 }
1185 #endif
1186 #endif
1187
1188 #ifdef I_VARARGS
1189 #ifndef HAS_VPRINTF
1190
1191 #ifdef CHARVSPRINTF
1192 char *
1193 #else
1194 int
1195 #endif
1196 vsprintf(dest, pat, args)
1197 char *dest, *pat, *args;
1198 {
1199     FILE fakebuf;
1200
1201     fakebuf._ptr = dest;
1202     fakebuf._cnt = 32767;
1203 #ifndef _IOSTRG
1204 #define _IOSTRG 0
1205 #endif
1206     fakebuf._flag = _IOWRT|_IOSTRG;
1207     _doprnt(pat, args, &fakebuf);       /* what a kludge */
1208     (void)putc('\0', &fakebuf);
1209 #ifdef CHARVSPRINTF
1210     return(dest);
1211 #else
1212     return 0;           /* perl doesn't use return value */
1213 #endif
1214 }
1215
1216 #ifdef DEBUGGING
1217 int
1218 vfprintf(fd, pat, args)
1219 FILE *fd;
1220 char *pat, *args;
1221 {
1222     _doprnt(pat, args, fd);
1223     return 0;           /* wrong, but perl doesn't use the return value */
1224 }
1225 #endif
1226 #endif /* HAS_VPRINTF */
1227 #endif /* I_VARARGS */
1228
1229 /*
1230  * I think my_swap(), htonl() and ntohl() have never been used.
1231  * perl.h contains last-chance references to my_swap(), my_htonl()
1232  * and my_ntohl().  I presume these are the intended functions;
1233  * but htonl() and ntohl() have the wrong names.  There are no
1234  * functions my_htonl() and my_ntohl() defined anywhere.
1235  * -DWS
1236  */
1237 #ifdef MYSWAP
1238 #if BYTEORDER != 0x4321
1239 short
1240 my_swap(s)
1241 short s;
1242 {
1243 #if (BYTEORDER & 1) == 0
1244     short result;
1245
1246     result = ((s & 255) << 8) + ((s >> 8) & 255);
1247     return result;
1248 #else
1249     return s;
1250 #endif
1251 }
1252
1253 long
1254 htonl(l)
1255 register long l;
1256 {
1257     union {
1258         long result;
1259         char c[sizeof(long)];
1260     } u;
1261
1262 #if BYTEORDER == 0x1234
1263     u.c[0] = (l >> 24) & 255;
1264     u.c[1] = (l >> 16) & 255;
1265     u.c[2] = (l >> 8) & 255;
1266     u.c[3] = l & 255;
1267     return u.result;
1268 #else
1269 #if ((BYTEORDER - 0x1111) & 0x444) || !(BYTEORDER & 0xf)
1270     fatal("Unknown BYTEORDER\n");
1271 #else
1272     register int o;
1273     register int s;
1274
1275     for (o = BYTEORDER - 0x1111, s = 0; s < (sizeof(long)*8); o >>= 4, s += 8) {
1276         u.c[o & 0xf] = (l >> s) & 255;
1277     }
1278     return u.result;
1279 #endif
1280 #endif
1281 }
1282
1283 long
1284 ntohl(l)
1285 register long l;
1286 {
1287     union {
1288         long l;
1289         char c[sizeof(long)];
1290     } u;
1291
1292 #if BYTEORDER == 0x1234
1293     u.c[0] = (l >> 24) & 255;
1294     u.c[1] = (l >> 16) & 255;
1295     u.c[2] = (l >> 8) & 255;
1296     u.c[3] = l & 255;
1297     return u.l;
1298 #else
1299 #if ((BYTEORDER - 0x1111) & 0x444) || !(BYTEORDER & 0xf)
1300     fatal("Unknown BYTEORDER\n");
1301 #else
1302     register int o;
1303     register int s;
1304
1305     u.l = l;
1306     l = 0;
1307     for (o = BYTEORDER - 0x1111, s = 0; s < (sizeof(long)*8); o >>= 4, s += 8) {
1308         l |= (u.c[o & 0xf] & 255) << s;
1309     }
1310     return l;
1311 #endif
1312 #endif
1313 }
1314
1315 #endif /* BYTEORDER != 0x4321 */
1316 #endif /* MYSWAP */
1317
1318 /*
1319  * Little-endian byte order functions - 'v' for 'VAX', or 'reVerse'.
1320  * If these functions are defined,
1321  * the BYTEORDER is neither 0x1234 nor 0x4321.
1322  * However, this is not assumed.
1323  * -DWS
1324  */
1325
1326 #define HTOV(name,type)                                         \
1327         type                                                    \
1328         name (n)                                                \
1329         register type n;                                        \
1330         {                                                       \
1331             union {                                             \
1332                 type value;                                     \
1333                 char c[sizeof(type)];                           \
1334             } u;                                                \
1335             register int i;                                     \
1336             register int s;                                     \
1337             for (i = 0, s = 0; i < sizeof(u.c); i++, s += 8) {  \
1338                 u.c[i] = (n >> s) & 0xFF;                       \
1339             }                                                   \
1340             return u.value;                                     \
1341         }
1342
1343 #define VTOH(name,type)                                         \
1344         type                                                    \
1345         name (n)                                                \
1346         register type n;                                        \
1347         {                                                       \
1348             union {                                             \
1349                 type value;                                     \
1350                 char c[sizeof(type)];                           \
1351             } u;                                                \
1352             register int i;                                     \
1353             register int s;                                     \
1354             u.value = n;                                        \
1355             n = 0;                                              \
1356             for (i = 0, s = 0; i < sizeof(u.c); i++, s += 8) {  \
1357                 n += (u.c[i] & 0xFF) << s;                      \
1358             }                                                   \
1359             return n;                                           \
1360         }
1361
1362 #if defined(HAS_HTOVS) && !defined(htovs)
1363 HTOV(htovs,short)
1364 #endif
1365 #if defined(HAS_HTOVL) && !defined(htovl)
1366 HTOV(htovl,long)
1367 #endif
1368 #if defined(HAS_VTOHS) && !defined(vtohs)
1369 VTOH(vtohs,short)
1370 #endif
1371 #if defined(HAS_VTOHL) && !defined(vtohl)
1372 VTOH(vtohl,long)
1373 #endif
1374
1375 #ifndef MSDOS
1376 FILE *
1377 mypopen(cmd,mode)
1378 char    *cmd;
1379 char    *mode;
1380 {
1381     int p[2];
1382     register int this, that;
1383     register int pid;
1384     STR *str;
1385     int doexec = strNE(cmd,"-");
1386
1387     if (pipe(p) < 0)
1388         return Nullfp;
1389     this = (*mode == 'w');
1390     that = !this;
1391 #ifdef TAINT
1392     if (doexec) {
1393         taintenv();
1394         taintproper("Insecure dependency in exec");
1395     }
1396 #endif
1397     while ((pid = (doexec?vfork():fork())) < 0) {
1398         if (errno != EAGAIN) {
1399             close(p[this]);
1400             if (!doexec)
1401                 fatal("Can't fork");
1402             return Nullfp;
1403         }
1404         sleep(5);
1405     }
1406     if (pid == 0) {
1407 #define THIS that
1408 #define THAT this
1409         close(p[THAT]);
1410         if (p[THIS] != (*mode == 'r')) {
1411             dup2(p[THIS], *mode == 'r');
1412             close(p[THIS]);
1413         }
1414         if (doexec) {
1415 #if !defined(HAS_FCNTL) || !defined(F_SETFD)
1416             int fd;
1417
1418 #ifndef NOFILE
1419 #define NOFILE 20
1420 #endif
1421             for (fd = maxsysfd + 1; fd < NOFILE; fd++)
1422                 close(fd);
1423 #endif
1424             do_exec(cmd);       /* may or may not use the shell */
1425             warn("Can't exec \"%s\": %s", cmd, strerror(errno));
1426             _exit(1);
1427         }
1428         /*SUPPRESS 560*/
1429         if (tmpstab = stabent("$",allstabs))
1430             str_numset(STAB_STR(tmpstab),(double)getpid());
1431         forkprocess = 0;
1432         hclear(pidstatus, FALSE);       /* we have no children */
1433         return Nullfp;
1434 #undef THIS
1435 #undef THAT
1436     }
1437     do_execfree();      /* free any memory malloced by child on vfork */
1438     close(p[that]);
1439     if (p[that] < p[this]) {
1440         dup2(p[this], p[that]);
1441         close(p[this]);
1442         p[this] = p[that];
1443     }
1444     str = afetch(fdpid,p[this],TRUE);
1445     str->str_u.str_useful = pid;
1446     forkprocess = pid;
1447     return fdopen(p[this], mode);
1448 }
1449 #endif /* !MSDOS */
1450
1451 #ifdef NOTDEF
1452 dumpfds(s)
1453 char *s;
1454 {
1455     int fd;
1456     struct stat tmpstatbuf;
1457
1458     fprintf(stderr,"%s", s);
1459     for (fd = 0; fd < 32; fd++) {
1460         if (fstat(fd,&tmpstatbuf) >= 0)
1461             fprintf(stderr," %d",fd);
1462     }
1463     fprintf(stderr,"\n");
1464 }
1465 #endif
1466
1467 #ifndef HAS_DUP2
1468 dup2(oldfd,newfd)
1469 int oldfd;
1470 int newfd;
1471 {
1472 #if defined(HAS_FCNTL) && defined(F_DUPFD)
1473     close(newfd);
1474     fcntl(oldfd, F_DUPFD, newfd);
1475 #else
1476     int fdtmp[256];
1477     int fdx = 0;
1478     int fd;
1479
1480     if (oldfd == newfd)
1481         return 0;
1482     close(newfd);
1483     while ((fd = dup(oldfd)) != newfd)  /* good enough for low fd's */
1484         fdtmp[fdx++] = fd;
1485     while (fdx > 0)
1486         close(fdtmp[--fdx]);
1487 #endif
1488 }
1489 #endif
1490
1491 #ifndef MSDOS
1492 int
1493 mypclose(ptr)
1494 FILE *ptr;
1495 {
1496 #ifdef VOIDSIG
1497     void (*hstat)(), (*istat)(), (*qstat)();
1498 #else
1499     int (*hstat)(), (*istat)(), (*qstat)();
1500 #endif
1501     int status;
1502     STR *str;
1503     int pid;
1504
1505     str = afetch(fdpid,fileno(ptr),TRUE);
1506     pid = (int)str->str_u.str_useful;
1507     astore(fdpid,fileno(ptr),Nullstr);
1508     fclose(ptr);
1509     hstat = signal(SIGHUP, SIG_IGN);
1510     istat = signal(SIGINT, SIG_IGN);
1511     qstat = signal(SIGQUIT, SIG_IGN);
1512     pid = wait4pid(pid, &status, 0);
1513     signal(SIGHUP, hstat);
1514     signal(SIGINT, istat);
1515     signal(SIGQUIT, qstat);
1516     return(pid < 0 ? pid : status);
1517 }
1518
1519 int
1520 wait4pid(pid,statusp,flags)
1521 int pid;
1522 int *statusp;
1523 int flags;
1524 {
1525 #if !defined(HAS_WAIT4) && !defined(HAS_WAITPID)
1526     int result;
1527     STR *str;
1528     char spid[16];
1529 #endif
1530
1531     if (!pid)
1532         return -1;
1533 #ifdef HAS_WAIT4
1534     return wait4((pid==-1)?0:pid,statusp,flags,Null(struct rusage *));
1535 #else
1536 #ifdef HAS_WAITPID
1537     return waitpid(pid,statusp,flags);
1538 #else
1539     if (pid > 0) {
1540         sprintf(spid, "%d", pid);
1541         str = hfetch(pidstatus,spid,strlen(spid),FALSE);
1542         if (str != &str_undef) {
1543             *statusp = (int)str->str_u.str_useful;
1544             hdelete(pidstatus,spid,strlen(spid));
1545             return pid;
1546         }
1547     }
1548     else {
1549         HENT *entry;
1550
1551         hiterinit(pidstatus);
1552         if (entry = hiternext(pidstatus)) {
1553             pid = atoi(hiterkey(entry,statusp));
1554             str = hiterval(entry);
1555             *statusp = (int)str->str_u.str_useful;
1556             sprintf(spid, "%d", pid);
1557             hdelete(pidstatus,spid,strlen(spid));
1558             return pid;
1559         }
1560     }
1561     if (flags)
1562         fatal("Can't do waitpid with flags");
1563     else {
1564         while ((result = wait(statusp)) != pid && pid > 0 && result >= 0)
1565             pidgone(result,*statusp);
1566         if (result < 0)
1567             *statusp = -1;
1568     }
1569     return result;
1570 #endif
1571 #endif
1572 }
1573
1574 /*SUPPRESS 590*/
1575 pidgone(pid,status)
1576 int pid;
1577 int status;
1578 {
1579 #if defined(HAS_WAIT4) || defined(HAS_WAITPID)
1580 #else
1581     register STR *str;
1582     char spid[16];
1583
1584     sprintf(spid, "%d", pid);
1585     str = hfetch(pidstatus,spid,strlen(spid),TRUE);
1586     str->str_u.str_useful = status;
1587 #endif
1588     return;
1589 }
1590 #endif /* !MSDOS */
1591
1592 #ifndef HAS_MEMCMP
1593 memcmp(s1,s2,len)
1594 register unsigned char *s1;
1595 register unsigned char *s2;
1596 register int len;
1597 {
1598     register int tmp;
1599
1600     while (len--) {
1601         if (tmp = *s1++ - *s2++)
1602             return tmp;
1603     }
1604     return 0;
1605 }
1606 #endif /* HAS_MEMCMP */
1607
1608 void
1609 repeatcpy(to,from,len,count)
1610 register char *to;
1611 register char *from;
1612 int len;
1613 register int count;
1614 {
1615     register int todo;
1616     register char *frombase = from;
1617
1618     if (len == 1) {
1619         todo = *from;
1620         while (count-- > 0)
1621             *to++ = todo;
1622         return;
1623     }
1624     while (count-- > 0) {
1625         for (todo = len; todo > 0; todo--) {
1626             *to++ = *from++;
1627         }
1628         from = frombase;
1629     }
1630 }
1631
1632 #ifndef CASTNEGFLOAT
1633 unsigned long
1634 castulong(f)
1635 double f;
1636 {
1637     long along;
1638
1639 #if CASTFLAGS & 2
1640 #   define BIGDOUBLE 2147483648.0
1641     if (f >= BIGDOUBLE)
1642         return (unsigned long)(f-(long)(f/BIGDOUBLE)*BIGDOUBLE)|0x80000000;
1643 #endif
1644     if (f >= 0.0)
1645         return (unsigned long)f;
1646     along = (long)f;
1647     return (unsigned long)along;
1648 }
1649 #endif
1650
1651 #ifndef HAS_RENAME
1652 int
1653 same_dirent(a,b)
1654 char *a;
1655 char *b;
1656 {
1657     char *fa = rindex(a,'/');
1658     char *fb = rindex(b,'/');
1659     struct stat tmpstatbuf1;
1660     struct stat tmpstatbuf2;
1661 #ifndef MAXPATHLEN
1662 #define MAXPATHLEN 1024
1663 #endif
1664     char tmpbuf[MAXPATHLEN+1];
1665
1666     if (fa)
1667         fa++;
1668     else
1669         fa = a;
1670     if (fb)
1671         fb++;
1672     else
1673         fb = b;
1674     if (strNE(a,b))
1675         return FALSE;
1676     if (fa == a)
1677         strcpy(tmpbuf,".");
1678     else
1679         strncpy(tmpbuf, a, fa - a);
1680     if (stat(tmpbuf, &tmpstatbuf1) < 0)
1681         return FALSE;
1682     if (fb == b)
1683         strcpy(tmpbuf,".");
1684     else
1685         strncpy(tmpbuf, b, fb - b);
1686     if (stat(tmpbuf, &tmpstatbuf2) < 0)
1687         return FALSE;
1688     return tmpstatbuf1.st_dev == tmpstatbuf2.st_dev &&
1689            tmpstatbuf1.st_ino == tmpstatbuf2.st_ino;
1690 }
1691 #endif /* !HAS_RENAME */
1692
1693 unsigned long
1694 scanoct(start, len, retlen)
1695 char *start;
1696 int len;
1697 int *retlen;
1698 {
1699     register char *s = start;
1700     register unsigned long retval = 0;
1701
1702     while (len-- && *s >= '0' && *s <= '7') {
1703         retval <<= 3;
1704         retval |= *s++ - '0';
1705     }
1706     *retlen = s - start;
1707     return retval;
1708 }
1709
1710 unsigned long
1711 scanhex(start, len, retlen)
1712 char *start;
1713 int len;
1714 int *retlen;
1715 {
1716     register char *s = start;
1717     register unsigned long retval = 0;
1718     char *tmp;
1719
1720     while (len-- && *s && (tmp = index(hexdigit, *s))) {
1721         retval <<= 4;
1722         retval |= (tmp - hexdigit) & 15;
1723         s++;
1724     }
1725     *retlen = s - start;
1726     return retval;
1727 }