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