perl 3.0 patch #6 patch 5 continued
[p5sagit/p5-mst-13.2.git] / str.c
CommitLineData
ffed7fef 1/* $Header: str.c,v 3.0.1.3 89/11/17 15:38:23 lwall Locked $
a687059c 2 *
3 * Copyright (c) 1989, Larry Wall
4 *
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.
8d063cd8 7 *
8 * $Log: str.c,v $
ffed7fef 9 * Revision 3.0.1.3 89/11/17 15:38:23 lwall
10 * patch5: some machines typedef unchar too
11 * patch5: substitution on leading components occasionally caused <> corruption
12 *
ae986130 13 * Revision 3.0.1.2 89/11/11 04:56:22 lwall
14 * patch2: uchar gives Crays fits
15 *
03a14243 16 * Revision 3.0.1.1 89/10/26 23:23:41 lwall
17 * patch1: string ordering tests were wrong
18 * patch1: $/ now works even when STDSTDIO undefined
19 *
a687059c 20 * Revision 3.0 89/10/18 15:23:38 lwall
21 * 3.0 baseline
8d063cd8 22 *
23 */
24
8d063cd8 25#include "EXTERN.h"
8d063cd8 26#include "perl.h"
a687059c 27#include "perly.h"
8d063cd8 28
a687059c 29extern char **environ;
30
31#ifndef str_get
32char *
33str_get(str)
34STR *str;
8d063cd8 35{
a687059c 36#ifdef TAINT
37 tainted |= str->str_tainted;
38#endif
39 return str->str_pok ? str->str_ptr : str_2ptr(str);
40}
41#endif
8d063cd8 42
a687059c 43/* dlb ... guess we have a "crippled cc".
44 * dlb the following functions are usually macros.
45 */
46#ifndef str_true
47str_true(Str)
48STR *Str;
49{
50 if (Str->str_pok) {
51 if (*Str->str_ptr > '0' ||
52 Str->str_cur > 1 ||
53 (Str->str_cur && *Str->str_ptr != '0'))
54 return 1;
55 return 0;
8d063cd8 56 }
a687059c 57 if (Str->str_nok)
58 return (Str->str_u.str_nval != 0.0);
59 return 0;
60}
61#endif /* str_true */
8d063cd8 62
a687059c 63#ifndef str_gnum
64double str_gnum(Str)
65STR *Str;
66{
67#ifdef TAINT
68 tainted |= Str->str_tainted;
69#endif /* TAINT*/
70 if (Str->str_nok)
71 return Str->str_u.str_nval;
72 return str_2num(Str);
73}
74#endif /* str_gnum */
75/* dlb ... end of crutch */
8d063cd8 76
a687059c 77char *
78str_grow(str,newlen)
79register STR *str;
80register int newlen;
81{
82 register char *s = str->str_ptr;
83
84 if (str->str_state == SS_INCR) { /* data before str_ptr? */
85 str->str_len += str->str_u.str_useful;
86 str->str_ptr -= str->str_u.str_useful;
87 str->str_u.str_useful = 0L;
88 bcopy(s, str->str_ptr, str->str_cur+1);
89 s = str->str_ptr;
90 str->str_state = SS_NORM; /* normal again */
91 if (newlen > str->str_len)
92 newlen += 10 * (newlen - str->str_cur); /* avoid copy each time */
93 }
94 if (newlen > str->str_len) { /* need more room? */
95 if (str->str_len)
96 Renew(s,newlen,char);
97 else
98 New(703,s,newlen,char);
99 str->str_ptr = s;
100 str->str_len = newlen;
8d063cd8 101 }
a687059c 102 return s;
8d063cd8 103}
104
105str_numset(str,num)
106register STR *str;
107double num;
108{
a687059c 109 str->str_u.str_nval = num;
110 str->str_state = SS_NORM;
111 str->str_pok = 0; /* invalidate pointer */
112 str->str_nok = 1; /* validate number */
113#ifdef TAINT
114 str->str_tainted = tainted;
115#endif
8d063cd8 116}
117
378cc40b 118extern int errno;
119
8d063cd8 120char *
121str_2ptr(str)
122register STR *str;
123{
124 register char *s;
378cc40b 125 int olderrno;
8d063cd8 126
127 if (!str)
128 return "";
8d063cd8 129 if (str->str_nok) {
a687059c 130 STR_GROW(str, 24);
131 s = str->str_ptr;
378cc40b 132 olderrno = errno; /* some Xenix systems wipe out errno here */
133#if defined(scs) && defined(ns32000)
a687059c 134 gcvt(str->str_u.str_nval,20,s);
378cc40b 135#else
136#ifdef apollo
a687059c 137 if (str->str_u.str_nval == 0.0)
138 (void)strcpy(s,"0");
378cc40b 139 else
140#endif /*apollo*/
a687059c 141 (void)sprintf(s,"%.20g",str->str_u.str_nval);
378cc40b 142#endif /*scs*/
143 errno = olderrno;
8d063cd8 144 while (*s) s++;
145 }
a687059c 146 else {
147 if (str == &str_undef)
148 return No;
149 if (dowarn)
150 warn("Use of uninitialized variable");
151 STR_GROW(str, 24);
152 s = str->str_ptr;
153 }
8d063cd8 154 *s = '\0';
155 str->str_cur = s - str->str_ptr;
156 str->str_pok = 1;
157#ifdef DEBUGGING
158 if (debug & 32)
159 fprintf(stderr,"0x%lx ptr(%s)\n",str,str->str_ptr);
160#endif
161 return str->str_ptr;
162}
163
164double
165str_2num(str)
166register STR *str;
167{
168 if (!str)
169 return 0.0;
a687059c 170 str->str_state = SS_NORM;
8d063cd8 171 if (str->str_len && str->str_pok)
a687059c 172 str->str_u.str_nval = atof(str->str_ptr);
173 else {
174 if (str == &str_undef)
175 return 0.0;
378cc40b 176 if (dowarn)
a687059c 177 warn("Use of uninitialized variable");
178 str->str_u.str_nval = 0.0;
378cc40b 179 }
8d063cd8 180 str->str_nok = 1;
181#ifdef DEBUGGING
182 if (debug & 32)
a687059c 183 fprintf(stderr,"0x%lx num(%g)\n",str,str->str_u.str_nval);
8d063cd8 184#endif
a687059c 185 return str->str_u.str_nval;
8d063cd8 186}
187
188str_sset(dstr,sstr)
189STR *dstr;
190register STR *sstr;
191{
a687059c 192#ifdef TAINT
193 tainted |= sstr->str_tainted;
194#endif
8d063cd8 195 if (!sstr)
a687059c 196 dstr->str_pok = dstr->str_nok = 0;
197 else if (sstr->str_pok) {
8d063cd8 198 str_nset(dstr,sstr->str_ptr,sstr->str_cur);
a687059c 199 if (sstr->str_nok) {
200 dstr->str_u.str_nval = sstr->str_u.str_nval;
201 dstr->str_nok = 1;
202 dstr->str_state = SS_NORM;
203 }
204 else if (sstr->str_cur == sizeof(STBP)) {
205 char *tmps = sstr->str_ptr;
206
207 if (*tmps == 'S' && bcmp(tmps,"Stab",4) == 0) {
208 dstr->str_magic = str_smake(sstr->str_magic);
209 dstr->str_magic->str_rare = 'X';
210 }
211 }
212 }
213 else if (sstr->str_nok)
214 str_numset(dstr,sstr->str_u.str_nval);
8d063cd8 215 else
a687059c 216 dstr->str_pok = dstr->str_nok = 0;
8d063cd8 217}
218
219str_nset(str,ptr,len)
220register STR *str;
221register char *ptr;
222register int len;
223{
a687059c 224 STR_GROW(str, len + 1);
225 (void)bcopy(ptr,str->str_ptr,len);
8d063cd8 226 str->str_cur = len;
227 *(str->str_ptr+str->str_cur) = '\0';
228 str->str_nok = 0; /* invalidate number */
229 str->str_pok = 1; /* validate pointer */
a687059c 230#ifdef TAINT
231 str->str_tainted = tainted;
232#endif
8d063cd8 233}
234
235str_set(str,ptr)
236register STR *str;
237register char *ptr;
238{
239 register int len;
240
241 if (!ptr)
242 ptr = "";
243 len = strlen(ptr);
a687059c 244 STR_GROW(str, len + 1);
245 (void)bcopy(ptr,str->str_ptr,len+1);
8d063cd8 246 str->str_cur = len;
247 str->str_nok = 0; /* invalidate number */
248 str->str_pok = 1; /* validate pointer */
a687059c 249#ifdef TAINT
250 str->str_tainted = tainted;
251#endif
8d063cd8 252}
253
254str_chop(str,ptr) /* like set but assuming ptr is in str */
255register STR *str;
256register char *ptr;
257{
a687059c 258 register int delta;
259
8d063cd8 260 if (!(str->str_pok))
a687059c 261 fatal("str_chop: internal inconsistency");
262 delta = ptr - str->str_ptr;
263 str->str_len -= delta;
264 str->str_cur -= delta;
265 str->str_ptr += delta;
266 if (str->str_state == SS_INCR)
267 str->str_u.str_useful += delta;
268 else {
269 str->str_u.str_useful = delta;
270 str->str_state = SS_INCR;
271 }
8d063cd8 272 str->str_nok = 0; /* invalidate number */
a687059c 273 str->str_pok = 1; /* validate pointer (and unstudy str) */
8d063cd8 274}
275
276str_ncat(str,ptr,len)
277register STR *str;
278register char *ptr;
279register int len;
280{
281 if (!(str->str_pok))
a687059c 282 (void)str_2ptr(str);
283 STR_GROW(str, str->str_cur + len + 1);
284 (void)bcopy(ptr,str->str_ptr+str->str_cur,len);
8d063cd8 285 str->str_cur += len;
286 *(str->str_ptr+str->str_cur) = '\0';
287 str->str_nok = 0; /* invalidate number */
288 str->str_pok = 1; /* validate pointer */
a687059c 289#ifdef TAINT
290 str->str_tainted |= tainted;
291#endif
8d063cd8 292}
293
294str_scat(dstr,sstr)
295STR *dstr;
296register STR *sstr;
297{
a687059c 298#ifdef TAINT
299 tainted |= sstr->str_tainted;
300#endif
378cc40b 301 if (!sstr)
302 return;
8d063cd8 303 if (!(sstr->str_pok))
a687059c 304 (void)str_2ptr(sstr);
8d063cd8 305 if (sstr)
306 str_ncat(dstr,sstr->str_ptr,sstr->str_cur);
307}
308
309str_cat(str,ptr)
310register STR *str;
311register char *ptr;
312{
313 register int len;
314
315 if (!ptr)
316 return;
317 if (!(str->str_pok))
a687059c 318 (void)str_2ptr(str);
8d063cd8 319 len = strlen(ptr);
a687059c 320 STR_GROW(str, str->str_cur + len + 1);
321 (void)bcopy(ptr,str->str_ptr+str->str_cur,len+1);
8d063cd8 322 str->str_cur += len;
323 str->str_nok = 0; /* invalidate number */
324 str->str_pok = 1; /* validate pointer */
a687059c 325#ifdef TAINT
326 str->str_tainted |= tainted;
327#endif
8d063cd8 328}
329
330char *
a687059c 331str_append_till(str,from,fromend,delim,keeplist)
8d063cd8 332register STR *str;
333register char *from;
a687059c 334register char *fromend;
8d063cd8 335register int delim;
336char *keeplist;
337{
338 register char *to;
339 register int len;
340
341 if (!from)
342 return Nullch;
a687059c 343 len = fromend - from;
344 STR_GROW(str, str->str_cur + len + 1);
8d063cd8 345 str->str_nok = 0; /* invalidate number */
346 str->str_pok = 1; /* validate pointer */
347 to = str->str_ptr+str->str_cur;
a687059c 348 for (; from < fromend; from++,to++) {
349 if (*from == '\\' && from+1 < fromend && delim != '\\') {
8d063cd8 350 if (!keeplist) {
351 if (from[1] == delim || from[1] == '\\')
352 from++;
353 else
354 *to++ = *from++;
355 }
a687059c 356 else if (from[1] && index(keeplist,from[1]))
8d063cd8 357 *to++ = *from++;
358 else
359 from++;
360 }
361 else if (*from == delim)
362 break;
363 *to = *from;
364 }
365 *to = '\0';
366 str->str_cur = to - str->str_ptr;
367 return from;
368}
369
370STR *
a687059c 371#ifdef LEAKTEST
372str_new(x,len)
373int x;
374#else
8d063cd8 375str_new(len)
a687059c 376#endif
8d063cd8 377int len;
378{
379 register STR *str;
380
381 if (freestrroot) {
382 str = freestrroot;
a687059c 383 freestrroot = str->str_magic;
384 str->str_magic = Nullstr;
385 str->str_state = SS_NORM;
8d063cd8 386 }
387 else {
a687059c 388 Newz(700+x,str,1,STR);
8d063cd8 389 }
390 if (len)
a687059c 391 STR_GROW(str, len + 1);
8d063cd8 392 return str;
393}
394
395void
a687059c 396str_magic(str, stab, how, name, namlen)
8d063cd8 397register STR *str;
a687059c 398STAB *stab;
399int how;
400char *name;
401int namlen;
402{
403 if (str->str_magic)
404 return;
405 str->str_magic = Str_new(75,namlen);
406 str = str->str_magic;
407 str->str_u.str_stab = stab;
408 str->str_rare = how;
409 if (name)
410 str_nset(str,name,namlen);
411}
412
413void
414str_insert(bigstr,offset,len,little,littlelen)
415STR *bigstr;
416int offset;
8d063cd8 417int len;
a687059c 418char *little;
419int littlelen;
8d063cd8 420{
a687059c 421 register char *big;
422 register char *mid;
423 register char *midend;
424 register char *bigend;
425 register int i;
426
427 i = littlelen - len;
428 if (i > 0) { /* string might grow */
429 STR_GROW(bigstr, bigstr->str_cur + i + 1);
430 big = bigstr->str_ptr;
431 mid = big + offset + len;
432 midend = bigend = big + bigstr->str_cur;
433 bigend += i;
434 *bigend = '\0';
435 while (midend > mid) /* shove everything down */
436 *--bigend = *--midend;
437 (void)bcopy(little,big+offset,littlelen);
438 bigstr->str_cur += i;
439 return;
440 }
441 else if (i == 0) {
442 (void)bcopy(little,bigstr->str_ptr+offset,len);
443 return;
444 }
445
446 big = bigstr->str_ptr;
447 mid = big + offset;
448 midend = mid + len;
449 bigend = big + bigstr->str_cur;
450
451 if (midend > bigend)
452 fatal("panic: str_insert");
453
454 bigstr->str_pok = SP_VALID; /* disable possible screamer */
455
456 if (mid - big > bigend - midend) { /* faster to shorten from end */
457 if (littlelen) {
458 (void)bcopy(little, mid, littlelen);
459 mid += littlelen;
460 }
461 i = bigend - midend;
462 if (i > 0) {
463 (void)bcopy(midend, mid, i);
464 mid += i;
465 }
466 *mid = '\0';
467 bigstr->str_cur = mid - big;
468 }
469 else if (i = mid - big) { /* faster from front */
470 midend -= littlelen;
471 mid = midend;
472 str_chop(bigstr,midend-i);
473 big += i;
474 while (i--)
475 *--midend = *--big;
476 if (littlelen)
477 (void)bcopy(little, mid, littlelen);
478 }
479 else if (littlelen) {
480 midend -= littlelen;
481 str_chop(bigstr,midend);
482 (void)bcopy(little,midend,littlelen);
483 }
484 else {
485 str_chop(bigstr,midend);
486 }
487 STABSET(bigstr);
8d063cd8 488}
489
490/* make str point to what nstr did */
491
492void
493str_replace(str,nstr)
494register STR *str;
495register STR *nstr;
496{
a687059c 497 if (str->str_state == SS_INCR)
498 str_grow(str,0); /* just force copy down */
499 if (nstr->str_state == SS_INCR)
500 str_grow(nstr,0);
501 if (str->str_ptr)
502 Safefree(str->str_ptr);
8d063cd8 503 str->str_ptr = nstr->str_ptr;
504 str->str_len = nstr->str_len;
505 str->str_cur = nstr->str_cur;
506 str->str_pok = nstr->str_pok;
a687059c 507 str->str_nok = nstr->str_nok;
508#ifdef STRUCTCOPY
509 str->str_u = nstr->str_u;
510#else
511 str->str_u.str_nval = nstr->str_u.str_nval;
512#endif
513#ifdef TAINT
514 str->str_tainted = nstr->str_tainted;
515#endif
516 Safefree(nstr);
8d063cd8 517}
518
519void
520str_free(str)
521register STR *str;
522{
523 if (!str)
524 return;
a687059c 525 if (str->str_state) {
526 if (str->str_state == SS_FREE) /* already freed */
527 return;
528 if (str->str_state == SS_INCR && !(str->str_pok & 2)) {
529 str->str_ptr -= str->str_u.str_useful;
530 str->str_len += str->str_u.str_useful;
531 }
532 }
533 if (str->str_magic)
534 str_free(str->str_magic);
535#ifdef LEAKTEST
8d063cd8 536 if (str->str_len)
a687059c 537 Safefree(str->str_ptr);
538 if ((str->str_pok & SP_INTRP) && str->str_u.str_args)
539 arg_free(str->str_u.str_args);
540 Safefree(str);
541#else /* LEAKTEST */
542 if (str->str_len) {
543 if (str->str_len > 127) { /* next user not likely to want more */
544 Safefree(str->str_ptr); /* so give it back to malloc */
545 str->str_ptr = Nullch;
546 str->str_len = 0;
547 }
548 else
549 str->str_ptr[0] = '\0';
550 }
551 if ((str->str_pok & SP_INTRP) && str->str_u.str_args)
552 arg_free(str->str_u.str_args);
8d063cd8 553 str->str_cur = 0;
554 str->str_nok = 0;
555 str->str_pok = 0;
a687059c 556 str->str_state = SS_FREE;
557#ifdef TAINT
558 str->str_tainted = 0;
559#endif
560 str->str_magic = freestrroot;
8d063cd8 561 freestrroot = str;
a687059c 562#endif /* LEAKTEST */
8d063cd8 563}
564
565str_len(str)
566register STR *str;
567{
568 if (!str)
569 return 0;
570 if (!(str->str_pok))
a687059c 571 (void)str_2ptr(str);
572 if (str->str_ptr)
8d063cd8 573 return str->str_cur;
574 else
575 return 0;
576}
577
a687059c 578str_eq(str1,str2)
579register STR *str1;
580register STR *str2;
581{
582 if (!str1)
583 return str2 == Nullstr;
584 if (!str2)
585 return 0;
586
587 if (!str1->str_pok)
588 (void)str_2ptr(str1);
589 if (!str2->str_pok)
590 (void)str_2ptr(str2);
591
592 if (str1->str_cur != str2->str_cur)
593 return 0;
594
595 return !bcmp(str1->str_ptr, str2->str_ptr, str1->str_cur);
596}
597
598str_cmp(str1,str2)
599register STR *str1;
600register STR *str2;
601{
602 int retval;
603
604 if (!str1)
605 return str2 == Nullstr;
606 if (!str2)
607 return 0;
608
609 if (!str1->str_pok)
610 (void)str_2ptr(str1);
611 if (!str2->str_pok)
612 (void)str_2ptr(str2);
613
614 if (str1->str_cur < str2->str_cur) {
615 if (retval = memcmp(str1->str_ptr, str2->str_ptr, str1->str_cur))
616 return retval;
617 else
03a14243 618 return -1;
a687059c 619 }
620 else if (retval = memcmp(str1->str_ptr, str2->str_ptr, str2->str_cur))
621 return retval;
622 else if (str1->str_cur == str2->str_cur)
623 return 0;
624 else
03a14243 625 return 1;
a687059c 626}
627
8d063cd8 628char *
a687059c 629str_gets(str,fp,append)
8d063cd8 630register STR *str;
631register FILE *fp;
a687059c 632int append;
8d063cd8 633{
8d063cd8 634 register char *bp; /* we're going to steal some values */
635 register int cnt; /* from the stdio struct and put EVERYTHING */
36ce8bec 636 register STDCHAR *ptr; /* in the innermost loop into registers */
637 register char newline = record_separator;/* (assuming >= 6 registers) */
8d063cd8 638 int i;
639 int bpx;
640 int obpx;
641 register int get_paragraph;
642 register char *oldbp;
643
a687059c 644 if (get_paragraph = !rslen) { /* yes, that's an assignment */
8d063cd8 645 newline = '\n';
646 oldbp = Nullch; /* remember last \n position (none) */
647 }
03a14243 648#ifdef STDSTDIO /* Here is some breathtakingly efficient cheating */
649
8d063cd8 650 cnt = fp->_cnt; /* get count into register */
651 str->str_nok = 0; /* invalidate number */
652 str->str_pok = 1; /* validate pointer */
a687059c 653 if (str->str_len <= cnt + 1) /* make sure we have the room */
654 STR_GROW(str, append+cnt+2); /* (remembering cnt can be -1) */
655 bp = str->str_ptr + append; /* move these two too to registers */
8d063cd8 656 ptr = fp->_ptr;
657 for (;;) {
658 screamer:
659 while (--cnt >= 0) { /* this */ /* eat */
660 if ((*bp++ = *ptr++) == newline) /* really */ /* dust */
661 goto thats_all_folks; /* screams */ /* sed :-) */
662 }
663
664 fp->_cnt = cnt; /* deregisterize cnt and ptr */
665 fp->_ptr = ptr;
666 i = _filbuf(fp); /* get more characters */
667 cnt = fp->_cnt;
668 ptr = fp->_ptr; /* reregisterize cnt and ptr */
669
670 bpx = bp - str->str_ptr; /* prepare for possible relocation */
671 if (get_paragraph && oldbp)
672 obpx = oldbp - str->str_ptr;
ffed7fef 673 str->str_cur = bpx;
a687059c 674 STR_GROW(str, bpx + cnt + 2);
8d063cd8 675 bp = str->str_ptr + bpx; /* reconstitute our pointer */
676 if (get_paragraph && oldbp)
677 oldbp = str->str_ptr + obpx;
678
679 if (i == newline) { /* all done for now? */
680 *bp++ = i;
681 goto thats_all_folks;
682 }
683 else if (i == EOF) /* all done for ever? */
684 goto thats_really_all_folks;
685 *bp++ = i; /* now go back to screaming loop */
686 }
687
688thats_all_folks:
689 if (get_paragraph && bp - 1 != oldbp) {
690 oldbp = bp; /* remember where this newline was */
691 goto screamer; /* and go back to the fray */
692 }
693thats_really_all_folks:
694 fp->_cnt = cnt; /* put these back or we're in trouble */
695 fp->_ptr = ptr;
696 *bp = '\0';
697 str->str_cur = bp - str->str_ptr; /* set length */
698
699#else /* !STDSTDIO */ /* The big, slow, and stupid way */
700
03a14243 701 {
702 static char buf[8192];
703 char * bpe = buf + sizeof(buf) - 3;
704
705screamer:
706 bp = buf;
707filler:
708 while ((i = getc(fp)) != EOF && (*bp++ = i) != newline && bp < bpe);
709 if (i == newline && get_paragraph &&
710 (i = getc(fp)) != EOF && (*bp++ = i) != newline && bp < bpe)
711 goto filler;
8d063cd8 712
03a14243 713 *bp = '\0';
a687059c 714 if (append)
715 str_cat(str, buf);
716 else
717 str_set(str, buf);
03a14243 718 if (i != newline && i != EOF) {
719 append = -1;
720 goto screamer;
721 }
a687059c 722 }
8d063cd8 723
724#endif /* STDSTDIO */
725
a687059c 726 return str->str_cur - append ? str->str_ptr : Nullch;
8d063cd8 727}
728
a687059c 729ARG *
730parselist(str)
731STR *str;
732{
733 register CMD *cmd;
734 register ARG *arg;
735 line_t oldline = line;
736 int retval;
8d063cd8 737
a687059c 738 str_sset(linestr,str);
739 in_eval++;
740 oldoldbufptr = oldbufptr = bufptr = str_get(linestr);
741 bufend = bufptr + linestr->str_cur;
742 if (setjmp(eval_env)) {
743 in_eval = 0;
744 fatal("%s\n",stab_val(stabent("@",TRUE))->str_ptr);
745 }
746 error_count = 0;
747 retval = yyparse();
748 in_eval--;
749 if (retval || error_count)
750 fatal("Invalid component in string or format");
751 cmd = eval_root;
752 arg = cmd->c_expr;
753 if (cmd->c_type != C_EXPR || cmd->c_next || arg->arg_type != O_LIST)
754 fatal("panic: error in parselist %d %x %d", cmd->c_type,
755 cmd->c_next, arg ? arg->arg_type : -1);
756 line = oldline;
757 Safefree(cmd);
758 return arg;
759}
760
761void
762intrpcompile(src)
763STR *src;
8d063cd8 764{
a687059c 765 register char *s = str_get(src);
766 register char *send = s + src->str_cur;
767 register STR *str;
768 register char *t;
769 STR *toparse;
770 int len;
771 register int brackets;
772 register char *d;
773 STAB *stab;
774 char *checkpoint;
8d063cd8 775
a687059c 776 toparse = Str_new(76,0);
777 str = Str_new(77,0);
778
779 str_nset(str,"",0);
780 str_nset(toparse,"",0);
781 t = s;
782 while (s < send) {
783 if (*s == '\\' && s[1] && index("$@[{\\]}",s[1])) {
784 str_ncat(str, t, s - t);
785 ++s;
786 if (*nointrp && s+1 < send)
787 if (*s != '@' && (*s != '$' || index(nointrp,s[1])))
788 str_ncat(str,s-1,1);
789 str_ncat(str, "$b", 2);
790 str_ncat(str, s, 1);
791 ++s;
792 t = s;
8d063cd8 793 }
a687059c 794 else if ((*s == '@' || (*s == '$' && !index(nointrp,s[1]))) &&
795 s+1 < send) {
8d063cd8 796 str_ncat(str,t,s-t);
8d063cd8 797 t = s;
a687059c 798 if (*s == '$' && s[1] == '#' && isalpha(s[2]) || s[2] == '_')
799 s++;
800 s = scanreg(s,send,tokenbuf);
801 if (*t == '@' &&
802 (!(stab = stabent(tokenbuf,FALSE)) || !stab_xarray(stab)) ) {
803 str_ncat(str,"@",1);
804 s = ++t;
805 continue; /* grandfather @ from old scripts */
806 }
807 str_ncat(str,"$a",2);
808 str_ncat(toparse,",",1);
809 if (t[1] != '{' && (*s == '[' || *s == '{' /* }} */ ) &&
810 (stab = stabent(tokenbuf,FALSE)) &&
811 ((*s == '[') ? (stab_xarray(stab) != 0) : (stab_xhash(stab) != 0)) ) {
812 brackets = 0;
813 checkpoint = s;
814 do {
815 switch (*s) {
816 case '[': case '{':
817 brackets++;
818 break;
819 case ']': case '}':
820 brackets--;
821 break;
822 case '\'':
823 case '"':
824 if (s[-1] != '$') {
825 s = cpytill(tokenbuf,s+1,send,*s,&len);
826 if (s >= send)
827 fatal("Unterminated string");
828 }
829 break;
830 }
831 s++;
832 } while (brackets > 0 && s < send);
833 if (s > send)
834 fatal("Unmatched brackets in string");
835 if (*nointrp) { /* we're in a regular expression */
836 d = checkpoint;
837 if (*d == '{' && s[-1] == '}') { /* maybe {n,m} */
838 ++d;
839 if (isdigit(*d)) { /* matches /^{\d,?\d*}$/ */
840 if (*++d == ',')
841 ++d;
842 while (isdigit(*d))
843 d++;
844 if (d == s - 1)
845 s = checkpoint; /* Is {n,m}! Backoff! */
846 }
847 }
848 else if (*d == '[' && s[-1] == ']') { /* char class? */
849 int weight = 2; /* let's weigh the evidence */
850 char seen[256];
ffed7fef 851 unsigned char un_char = 0, last_un_char;
a687059c 852
853 Zero(seen,256,char);
854 *--s = '\0';
855 if (d[1] == '^')
856 weight += 150;
857 else if (d[1] == '$')
858 weight -= 3;
859 if (isdigit(d[1])) {
860 if (d[2]) {
861 if (isdigit(d[2]) && !d[3])
862 weight -= 10;
863 }
864 else
865 weight -= 100;
866 }
867 for (d++; d < s; d++) {
ffed7fef 868 last_un_char = un_char;
869 un_char = (unsigned char)*d;
a687059c 870 switch (*d) {
871 case '&':
872 case '$':
ffed7fef 873 weight -= seen[un_char] * 10;
a687059c 874 if (isalpha(d[1]) || isdigit(d[1]) ||
875 d[1] == '_') {
876 d = scanreg(d,s,tokenbuf);
877 if (stabent(tokenbuf,FALSE))
878 weight -= 100;
879 else
880 weight -= 10;
881 }
882 else if (*d == '$' && d[1] &&
883 index("[#!%*<>()-=",d[1])) {
884 if (!d[2] || /*{*/ index("])} =",d[2]))
885 weight -= 10;
886 else
887 weight -= 1;
888 }
889 break;
890 case '\\':
ffed7fef 891 un_char = 254;
a687059c 892 if (d[1]) {
893 if (index("wds",d[1]))
894 weight += 100;
895 else if (seen['\''] || seen['"'])
896 weight += 1;
897 else if (index("rnftb",d[1]))
898 weight += 40;
899 else if (isdigit(d[1])) {
900 weight += 40;
901 while (d[1] && isdigit(d[1]))
902 d++;
903 }
904 }
905 else
906 weight += 100;
907 break;
908 case '-':
ffed7fef 909 if (last_un_char < d[1] || d[1] == '\\') {
910 if (index("aA01! ",last_un_char))
a687059c 911 weight += 30;
912 if (index("zZ79~",d[1]))
913 weight += 30;
914 }
915 else
916 weight -= 1;
917 default:
918 if (isalpha(*d) && d[1] && isalpha(d[1])) {
919 bufptr = d;
920 if (yylex() != WORD)
921 weight -= 150;
922 d = bufptr;
923 }
ffed7fef 924 if (un_char == last_un_char + 1)
a687059c 925 weight += 5;
ffed7fef 926 weight -= seen[un_char];
a687059c 927 break;
928 }
ffed7fef 929 seen[un_char]++;
a687059c 930 }
931#ifdef DEBUGGING
932 if (debug & 512)
933 fprintf(stderr,"[%s] weight %d\n",
934 checkpoint+1,weight);
935#endif
936 *s++ = ']';
937 if (weight >= 0) /* probably a character class */
938 s = checkpoint;
939 }
940 }
941 }
942 if (*t == '@')
943 str_ncat(toparse, "join($\",", 8);
944 if (t[1] == '{' && s[-1] == '}') {
945 str_ncat(toparse, t, 1);
946 str_ncat(toparse, t+2, s - t - 3);
947 }
948 else
949 str_ncat(toparse, t, s - t);
950 if (*t == '@')
951 str_ncat(toparse, ")", 1);
952 t = s;
953 }
954 else
955 s++;
956 }
957 str_ncat(str,t,s-t);
958 if (toparse->str_ptr && *toparse->str_ptr == ',') {
959 *toparse->str_ptr = '(';
960 str_ncat(toparse,",$$);",5);
961 str->str_u.str_args = parselist(toparse);
962 str->str_u.str_args->arg_len--; /* ignore $$ reference */
963 }
964 else
965 str->str_u.str_args = Nullarg;
966 str_free(toparse);
967 str->str_pok |= SP_INTRP;
968 str->str_nok = 0;
969 str_replace(src,str);
970}
971
972STR *
973interp(str,src,sp)
974register STR *str;
975STR *src;
976int sp;
977{
978 register char *s;
979 register char *t;
980 register char *send;
981 register STR **elem;
982
983 if (!(src->str_pok & SP_INTRP)) {
984 int oldsave = savestack->ary_fill;
985
986 (void)savehptr(&curstash);
987 curstash = src->str_u.str_hash; /* so stabent knows right package */
988 intrpcompile(src);
989 restorelist(oldsave);
990 }
991 s = src->str_ptr; /* assumed valid since str_pok set */
992 t = s;
993 send = s + src->str_cur;
994
995 if (src->str_u.str_args) {
996 (void)eval(src->str_u.str_args,G_ARRAY,sp);
997 /* Assuming we have correct # of args */
998 elem = stack->ary_array + sp;
999 }
1000
1001 str_nset(str,"",0);
1002 while (s < send) {
1003 if (*s == '$' && s+1 < send) {
1004 str_ncat(str,t,s-t);
1005 switch(*++s) {
1006 case 'a':
1007 str_scat(str,*++elem);
1008 break;
1009 case 'b':
1010 str_ncat(str,++s,1);
1011 break;
1012 }
1013 t = ++s;
8d063cd8 1014 }
1015 else
1016 s++;
1017 }
8d063cd8 1018 str_ncat(str,t,s-t);
1019 return str;
1020}
1021
1022void
1023str_inc(str)
1024register STR *str;
1025{
1026 register char *d;
1027
1028 if (!str)
1029 return;
1030 if (str->str_nok) {
a687059c 1031 str->str_u.str_nval += 1.0;
8d063cd8 1032 str->str_pok = 0;
1033 return;
1034 }
378cc40b 1035 if (!str->str_pok || !*str->str_ptr) {
a687059c 1036 str->str_u.str_nval = 1.0;
8d063cd8 1037 str->str_nok = 1;
13281fa4 1038 str->str_pok = 0;
8d063cd8 1039 return;
1040 }
378cc40b 1041 d = str->str_ptr;
1042 while (isalpha(*d)) d++;
1043 while (isdigit(*d)) d++;
1044 if (*d) {
8d063cd8 1045 str_numset(str,atof(str->str_ptr) + 1.0); /* punt */
1046 return;
1047 }
378cc40b 1048 d--;
8d063cd8 1049 while (d >= str->str_ptr) {
378cc40b 1050 if (isdigit(*d)) {
1051 if (++*d <= '9')
1052 return;
1053 *(d--) = '0';
1054 }
1055 else {
1056 ++*d;
1057 if (isalpha(*d))
1058 return;
1059 *(d--) -= 'z' - 'a' + 1;
1060 }
8d063cd8 1061 }
1062 /* oh,oh, the number grew */
a687059c 1063 STR_GROW(str, str->str_cur + 2);
8d063cd8 1064 str->str_cur++;
1065 for (d = str->str_ptr + str->str_cur; d > str->str_ptr; d--)
1066 *d = d[-1];
378cc40b 1067 if (isdigit(d[1]))
1068 *d = '1';
1069 else
1070 *d = d[1];
8d063cd8 1071}
1072
1073void
1074str_dec(str)
1075register STR *str;
1076{
8d063cd8 1077 if (!str)
1078 return;
1079 if (str->str_nok) {
a687059c 1080 str->str_u.str_nval -= 1.0;
8d063cd8 1081 str->str_pok = 0;
1082 return;
1083 }
1084 if (!str->str_pok) {
a687059c 1085 str->str_u.str_nval = -1.0;
8d063cd8 1086 str->str_nok = 1;
1087 return;
1088 }
378cc40b 1089 str_numset(str,atof(str->str_ptr) - 1.0);
8d063cd8 1090}
1091
a687059c 1092/* Make a string that will exist for the duration of the expression
1093 * evaluation. Actually, it may have to last longer than that, but
1094 * hopefully cmd_exec won't free it until it has been assigned to a
1095 * permanent location. */
1096
1097static long tmps_size = -1;
8d063cd8 1098
1099STR *
1100str_static(oldstr)
1101STR *oldstr;
1102{
a687059c 1103 register STR *str = Str_new(78,0);
8d063cd8 1104
1105 str_sset(str,oldstr);
1106 if (++tmps_max > tmps_size) {
1107 tmps_size = tmps_max;
1108 if (!(tmps_size & 127)) {
1109 if (tmps_size)
a687059c 1110 Renew(tmps_list, tmps_size + 128, STR*);
8d063cd8 1111 else
a687059c 1112 New(702,tmps_list, 128, STR*);
8d063cd8 1113 }
1114 }
1115 tmps_list[tmps_max] = str;
1116 return str;
1117}
1118
a687059c 1119/* same thing without the copying */
1120
8d063cd8 1121STR *
a687059c 1122str_2static(str)
1123register STR *str;
1124{
1125 if (++tmps_max > tmps_size) {
1126 tmps_size = tmps_max;
1127 if (!(tmps_size & 127)) {
1128 if (tmps_size)
1129 Renew(tmps_list, tmps_size + 128, STR*);
1130 else
1131 New(704,tmps_list, 128, STR*);
1132 }
1133 }
1134 tmps_list[tmps_max] = str;
1135 return str;
1136}
1137
1138STR *
1139str_make(s,len)
8d063cd8 1140char *s;
a687059c 1141int len;
8d063cd8 1142{
a687059c 1143 register STR *str = Str_new(79,0);
8d063cd8 1144
a687059c 1145 if (!len)
1146 len = strlen(s);
1147 str_nset(str,s,len);
8d063cd8 1148 return str;
1149}
1150
1151STR *
1152str_nmake(n)
1153double n;
1154{
a687059c 1155 register STR *str = Str_new(80,0);
8d063cd8 1156
1157 str_numset(str,n);
1158 return str;
1159}
a687059c 1160
1161/* make an exact duplicate of old */
1162
1163STR *
1164str_smake(old)
1165register STR *old;
1166{
1167 register STR *new = Str_new(81,0);
1168
1169 if (!old)
1170 return Nullstr;
1171 if (old->str_state == SS_FREE) {
1172 warn("semi-panic: attempt to dup freed string");
1173 return Nullstr;
1174 }
1175 if (old->str_state == SS_INCR && !(old->str_pok & 2))
1176 str_grow(old,0);
1177 if (new->str_ptr)
1178 Safefree(new->str_ptr);
1179 Copy(old,new,1,STR);
1180 if (old->str_ptr)
1181 new->str_ptr = nsavestr(old->str_ptr,old->str_len);
1182 return new;
1183}
1184
1185str_reset(s,stash)
1186register char *s;
1187HASH *stash;
1188{
1189 register HENT *entry;
1190 register STAB *stab;
1191 register STR *str;
1192 register int i;
1193 register SPAT *spat;
1194 register int max;
1195
1196 if (!*s) { /* reset ?? searches */
1197 for (spat = stash->tbl_spatroot;
1198 spat != Nullspat;
1199 spat = spat->spat_next) {
1200 spat->spat_flags &= ~SPAT_USED;
1201 }
1202 return;
1203 }
1204
1205 /* reset variables */
1206
1207 while (*s) {
1208 i = *s;
1209 if (s[1] == '-') {
1210 s += 2;
1211 }
1212 max = *s++;
1213 for ( ; i <= max; i++) {
1214 for (entry = stash->tbl_array[i];
1215 entry;
1216 entry = entry->hent_next) {
1217 stab = (STAB*)entry->hent_val;
1218 str = stab_val(stab);
1219 str->str_cur = 0;
1220 str->str_nok = 0;
1221#ifdef TAINT
1222 str->str_tainted = tainted;
1223#endif
1224 if (str->str_ptr != Nullch)
1225 str->str_ptr[0] = '\0';
1226 if (stab_xarray(stab)) {
1227 aclear(stab_xarray(stab));
1228 }
1229 if (stab_xhash(stab)) {
1230 hclear(stab_xhash(stab));
1231 if (stab == envstab)
1232 environ[0] = Nullch;
1233 }
1234 }
1235 }
1236 }
1237}
1238
1239#ifdef TAINT
1240taintproper(s)
1241char *s;
1242{
1243#ifdef DEBUGGING
1244 if (debug & 2048)
1245 fprintf(stderr,"%s %d %d %d\n",s,tainted,uid, euid);
1246#endif
1247 if (tainted && (!euid || euid != uid)) {
1248 if (!unsafe)
1249 fatal("%s", s);
1250 else if (dowarn)
1251 warn("%s", s);
1252 }
1253}
1254
1255taintenv()
1256{
1257 register STR *envstr;
1258
1259 envstr = hfetch(stab_hash(envstab),"PATH",4,FALSE);
1260 if (!envstr || envstr->str_tainted) {
1261 tainted = 1;
1262 taintproper("Insecure PATH");
1263 }
1264 envstr = hfetch(stab_hash(envstab),"IFS",3,FALSE);
1265 if (envstr && envstr->str_tainted) {
1266 tainted = 1;
1267 taintproper("Insecure IFS");
1268 }
1269}
1270#endif /* TAINT */