1 /* $Header: str.c,v 3.0.1.2 89/11/11 04:56:22 lwall Locked $
3 * Copyright (c) 1989, Larry Wall
5 * You may distribute under the terms of the GNU General Public License
6 * as specified in the README file that comes with the perl 3.0 kit.
9 * Revision 3.0.1.2 89/11/11 04:56:22 lwall
10 * patch2: uchar gives Crays fits
12 * Revision 3.0.1.1 89/10/26 23:23:41 lwall
13 * patch1: string ordering tests were wrong
14 * patch1: $/ now works even when STDSTDIO undefined
16 * Revision 3.0 89/10/18 15:23:38 lwall
25 extern char **environ;
33 tainted |= str->str_tainted;
35 return str->str_pok ? str->str_ptr : str_2ptr(str);
39 /* dlb ... guess we have a "crippled cc".
40 * dlb the following functions are usually macros.
47 if (*Str->str_ptr > '0' ||
49 (Str->str_cur && *Str->str_ptr != '0'))
54 return (Str->str_u.str_nval != 0.0);
64 tainted |= Str->str_tainted;
67 return Str->str_u.str_nval;
71 /* dlb ... end of crutch */
78 register char *s = str->str_ptr;
80 if (str->str_state == SS_INCR) { /* data before str_ptr? */
81 str->str_len += str->str_u.str_useful;
82 str->str_ptr -= str->str_u.str_useful;
83 str->str_u.str_useful = 0L;
84 bcopy(s, str->str_ptr, str->str_cur+1);
86 str->str_state = SS_NORM; /* normal again */
87 if (newlen > str->str_len)
88 newlen += 10 * (newlen - str->str_cur); /* avoid copy each time */
90 if (newlen > str->str_len) { /* need more room? */
94 New(703,s,newlen,char);
96 str->str_len = newlen;
105 str->str_u.str_nval = num;
106 str->str_state = SS_NORM;
107 str->str_pok = 0; /* invalidate pointer */
108 str->str_nok = 1; /* validate number */
110 str->str_tainted = tainted;
128 olderrno = errno; /* some Xenix systems wipe out errno here */
129 #if defined(scs) && defined(ns32000)
130 gcvt(str->str_u.str_nval,20,s);
133 if (str->str_u.str_nval == 0.0)
137 (void)sprintf(s,"%.20g",str->str_u.str_nval);
143 if (str == &str_undef)
146 warn("Use of uninitialized variable");
151 str->str_cur = s - str->str_ptr;
155 fprintf(stderr,"0x%lx ptr(%s)\n",str,str->str_ptr);
166 str->str_state = SS_NORM;
167 if (str->str_len && str->str_pok)
168 str->str_u.str_nval = atof(str->str_ptr);
170 if (str == &str_undef)
173 warn("Use of uninitialized variable");
174 str->str_u.str_nval = 0.0;
179 fprintf(stderr,"0x%lx num(%g)\n",str,str->str_u.str_nval);
181 return str->str_u.str_nval;
189 tainted |= sstr->str_tainted;
192 dstr->str_pok = dstr->str_nok = 0;
193 else if (sstr->str_pok) {
194 str_nset(dstr,sstr->str_ptr,sstr->str_cur);
196 dstr->str_u.str_nval = sstr->str_u.str_nval;
198 dstr->str_state = SS_NORM;
200 else if (sstr->str_cur == sizeof(STBP)) {
201 char *tmps = sstr->str_ptr;
203 if (*tmps == 'S' && bcmp(tmps,"Stab",4) == 0) {
204 dstr->str_magic = str_smake(sstr->str_magic);
205 dstr->str_magic->str_rare = 'X';
209 else if (sstr->str_nok)
210 str_numset(dstr,sstr->str_u.str_nval);
212 dstr->str_pok = dstr->str_nok = 0;
215 str_nset(str,ptr,len)
220 STR_GROW(str, len + 1);
221 (void)bcopy(ptr,str->str_ptr,len);
223 *(str->str_ptr+str->str_cur) = '\0';
224 str->str_nok = 0; /* invalidate number */
225 str->str_pok = 1; /* validate pointer */
227 str->str_tainted = tainted;
240 STR_GROW(str, len + 1);
241 (void)bcopy(ptr,str->str_ptr,len+1);
243 str->str_nok = 0; /* invalidate number */
244 str->str_pok = 1; /* validate pointer */
246 str->str_tainted = tainted;
250 str_chop(str,ptr) /* like set but assuming ptr is in str */
257 fatal("str_chop: internal inconsistency");
258 delta = ptr - str->str_ptr;
259 str->str_len -= delta;
260 str->str_cur -= delta;
261 str->str_ptr += delta;
262 if (str->str_state == SS_INCR)
263 str->str_u.str_useful += delta;
265 str->str_u.str_useful = delta;
266 str->str_state = SS_INCR;
268 str->str_nok = 0; /* invalidate number */
269 str->str_pok = 1; /* validate pointer (and unstudy str) */
272 str_ncat(str,ptr,len)
279 STR_GROW(str, str->str_cur + len + 1);
280 (void)bcopy(ptr,str->str_ptr+str->str_cur,len);
282 *(str->str_ptr+str->str_cur) = '\0';
283 str->str_nok = 0; /* invalidate number */
284 str->str_pok = 1; /* validate pointer */
286 str->str_tainted |= tainted;
295 tainted |= sstr->str_tainted;
299 if (!(sstr->str_pok))
300 (void)str_2ptr(sstr);
302 str_ncat(dstr,sstr->str_ptr,sstr->str_cur);
316 STR_GROW(str, str->str_cur + len + 1);
317 (void)bcopy(ptr,str->str_ptr+str->str_cur,len+1);
319 str->str_nok = 0; /* invalidate number */
320 str->str_pok = 1; /* validate pointer */
322 str->str_tainted |= tainted;
327 str_append_till(str,from,fromend,delim,keeplist)
330 register char *fromend;
339 len = fromend - from;
340 STR_GROW(str, str->str_cur + len + 1);
341 str->str_nok = 0; /* invalidate number */
342 str->str_pok = 1; /* validate pointer */
343 to = str->str_ptr+str->str_cur;
344 for (; from < fromend; from++,to++) {
345 if (*from == '\\' && from+1 < fromend && delim != '\\') {
347 if (from[1] == delim || from[1] == '\\')
352 else if (from[1] && index(keeplist,from[1]))
357 else if (*from == delim)
362 str->str_cur = to - str->str_ptr;
379 freestrroot = str->str_magic;
380 str->str_magic = Nullstr;
381 str->str_state = SS_NORM;
384 Newz(700+x,str,1,STR);
387 STR_GROW(str, len + 1);
392 str_magic(str, stab, how, name, namlen)
401 str->str_magic = Str_new(75,namlen);
402 str = str->str_magic;
403 str->str_u.str_stab = stab;
406 str_nset(str,name,namlen);
410 str_insert(bigstr,offset,len,little,littlelen)
419 register char *midend;
420 register char *bigend;
424 if (i > 0) { /* string might grow */
425 STR_GROW(bigstr, bigstr->str_cur + i + 1);
426 big = bigstr->str_ptr;
427 mid = big + offset + len;
428 midend = bigend = big + bigstr->str_cur;
431 while (midend > mid) /* shove everything down */
432 *--bigend = *--midend;
433 (void)bcopy(little,big+offset,littlelen);
434 bigstr->str_cur += i;
438 (void)bcopy(little,bigstr->str_ptr+offset,len);
442 big = bigstr->str_ptr;
445 bigend = big + bigstr->str_cur;
448 fatal("panic: str_insert");
450 bigstr->str_pok = SP_VALID; /* disable possible screamer */
452 if (mid - big > bigend - midend) { /* faster to shorten from end */
454 (void)bcopy(little, mid, littlelen);
459 (void)bcopy(midend, mid, i);
463 bigstr->str_cur = mid - big;
465 else if (i = mid - big) { /* faster from front */
468 str_chop(bigstr,midend-i);
473 (void)bcopy(little, mid, littlelen);
475 else if (littlelen) {
477 str_chop(bigstr,midend);
478 (void)bcopy(little,midend,littlelen);
481 str_chop(bigstr,midend);
486 /* make str point to what nstr did */
489 str_replace(str,nstr)
493 if (str->str_state == SS_INCR)
494 str_grow(str,0); /* just force copy down */
495 if (nstr->str_state == SS_INCR)
498 Safefree(str->str_ptr);
499 str->str_ptr = nstr->str_ptr;
500 str->str_len = nstr->str_len;
501 str->str_cur = nstr->str_cur;
502 str->str_pok = nstr->str_pok;
503 str->str_nok = nstr->str_nok;
505 str->str_u = nstr->str_u;
507 str->str_u.str_nval = nstr->str_u.str_nval;
510 str->str_tainted = nstr->str_tainted;
521 if (str->str_state) {
522 if (str->str_state == SS_FREE) /* already freed */
524 if (str->str_state == SS_INCR && !(str->str_pok & 2)) {
525 str->str_ptr -= str->str_u.str_useful;
526 str->str_len += str->str_u.str_useful;
530 str_free(str->str_magic);
533 Safefree(str->str_ptr);
534 if ((str->str_pok & SP_INTRP) && str->str_u.str_args)
535 arg_free(str->str_u.str_args);
539 if (str->str_len > 127) { /* next user not likely to want more */
540 Safefree(str->str_ptr); /* so give it back to malloc */
541 str->str_ptr = Nullch;
545 str->str_ptr[0] = '\0';
547 if ((str->str_pok & SP_INTRP) && str->str_u.str_args)
548 arg_free(str->str_u.str_args);
552 str->str_state = SS_FREE;
554 str->str_tainted = 0;
556 str->str_magic = freestrroot;
558 #endif /* LEAKTEST */
579 return str2 == Nullstr;
584 (void)str_2ptr(str1);
586 (void)str_2ptr(str2);
588 if (str1->str_cur != str2->str_cur)
591 return !bcmp(str1->str_ptr, str2->str_ptr, str1->str_cur);
601 return str2 == Nullstr;
606 (void)str_2ptr(str1);
608 (void)str_2ptr(str2);
610 if (str1->str_cur < str2->str_cur) {
611 if (retval = memcmp(str1->str_ptr, str2->str_ptr, str1->str_cur))
616 else if (retval = memcmp(str1->str_ptr, str2->str_ptr, str2->str_cur))
618 else if (str1->str_cur == str2->str_cur)
625 str_gets(str,fp,append)
630 register char *bp; /* we're going to steal some values */
631 register int cnt; /* from the stdio struct and put EVERYTHING */
632 register STDCHAR *ptr; /* in the innermost loop into registers */
633 register char newline = record_separator;/* (assuming >= 6 registers) */
637 register int get_paragraph;
638 register char *oldbp;
640 if (get_paragraph = !rslen) { /* yes, that's an assignment */
642 oldbp = Nullch; /* remember last \n position (none) */
644 #ifdef STDSTDIO /* Here is some breathtakingly efficient cheating */
646 cnt = fp->_cnt; /* get count into register */
647 str->str_nok = 0; /* invalidate number */
648 str->str_pok = 1; /* validate pointer */
649 if (str->str_len <= cnt + 1) /* make sure we have the room */
650 STR_GROW(str, append+cnt+2); /* (remembering cnt can be -1) */
651 bp = str->str_ptr + append; /* move these two too to registers */
655 while (--cnt >= 0) { /* this */ /* eat */
656 if ((*bp++ = *ptr++) == newline) /* really */ /* dust */
657 goto thats_all_folks; /* screams */ /* sed :-) */
660 fp->_cnt = cnt; /* deregisterize cnt and ptr */
662 i = _filbuf(fp); /* get more characters */
664 ptr = fp->_ptr; /* reregisterize cnt and ptr */
666 bpx = bp - str->str_ptr; /* prepare for possible relocation */
667 if (get_paragraph && oldbp)
668 obpx = oldbp - str->str_ptr;
669 STR_GROW(str, bpx + cnt + 2);
670 bp = str->str_ptr + bpx; /* reconstitute our pointer */
671 if (get_paragraph && oldbp)
672 oldbp = str->str_ptr + obpx;
674 if (i == newline) { /* all done for now? */
676 goto thats_all_folks;
678 else if (i == EOF) /* all done for ever? */
679 goto thats_really_all_folks;
680 *bp++ = i; /* now go back to screaming loop */
684 if (get_paragraph && bp - 1 != oldbp) {
685 oldbp = bp; /* remember where this newline was */
686 goto screamer; /* and go back to the fray */
688 thats_really_all_folks:
689 fp->_cnt = cnt; /* put these back or we're in trouble */
692 str->str_cur = bp - str->str_ptr; /* set length */
694 #else /* !STDSTDIO */ /* The big, slow, and stupid way */
697 static char buf[8192];
698 char * bpe = buf + sizeof(buf) - 3;
703 while ((i = getc(fp)) != EOF && (*bp++ = i) != newline && bp < bpe);
704 if (i == newline && get_paragraph &&
705 (i = getc(fp)) != EOF && (*bp++ = i) != newline && bp < bpe)
713 if (i != newline && i != EOF) {
719 #endif /* STDSTDIO */
721 return str->str_cur - append ? str->str_ptr : Nullch;
730 line_t oldline = line;
733 str_sset(linestr,str);
735 oldoldbufptr = oldbufptr = bufptr = str_get(linestr);
736 bufend = bufptr + linestr->str_cur;
737 if (setjmp(eval_env)) {
739 fatal("%s\n",stab_val(stabent("@",TRUE))->str_ptr);
744 if (retval || error_count)
745 fatal("Invalid component in string or format");
748 if (cmd->c_type != C_EXPR || cmd->c_next || arg->arg_type != O_LIST)
749 fatal("panic: error in parselist %d %x %d", cmd->c_type,
750 cmd->c_next, arg ? arg->arg_type : -1);
760 register char *s = str_get(src);
761 register char *send = s + src->str_cur;
766 register int brackets;
771 toparse = Str_new(76,0);
775 str_nset(toparse,"",0);
778 if (*s == '\\' && s[1] && index("$@[{\\]}",s[1])) {
779 str_ncat(str, t, s - t);
781 if (*nointrp && s+1 < send)
782 if (*s != '@' && (*s != '$' || index(nointrp,s[1])))
784 str_ncat(str, "$b", 2);
789 else if ((*s == '@' || (*s == '$' && !index(nointrp,s[1]))) &&
793 if (*s == '$' && s[1] == '#' && isalpha(s[2]) || s[2] == '_')
795 s = scanreg(s,send,tokenbuf);
797 (!(stab = stabent(tokenbuf,FALSE)) || !stab_xarray(stab)) ) {
800 continue; /* grandfather @ from old scripts */
802 str_ncat(str,"$a",2);
803 str_ncat(toparse,",",1);
804 if (t[1] != '{' && (*s == '[' || *s == '{' /* }} */ ) &&
805 (stab = stabent(tokenbuf,FALSE)) &&
806 ((*s == '[') ? (stab_xarray(stab) != 0) : (stab_xhash(stab) != 0)) ) {
820 s = cpytill(tokenbuf,s+1,send,*s,&len);
822 fatal("Unterminated string");
827 } while (brackets > 0 && s < send);
829 fatal("Unmatched brackets in string");
830 if (*nointrp) { /* we're in a regular expression */
832 if (*d == '{' && s[-1] == '}') { /* maybe {n,m} */
834 if (isdigit(*d)) { /* matches /^{\d,?\d*}$/ */
840 s = checkpoint; /* Is {n,m}! Backoff! */
843 else if (*d == '[' && s[-1] == ']') { /* char class? */
844 int weight = 2; /* let's weigh the evidence */
846 unsigned char unchar = 0, lastunchar;
852 else if (d[1] == '$')
856 if (isdigit(d[2]) && !d[3])
862 for (d++; d < s; d++) {
864 unchar = (unsigned char)*d;
868 weight -= seen[unchar] * 10;
869 if (isalpha(d[1]) || isdigit(d[1]) ||
871 d = scanreg(d,s,tokenbuf);
872 if (stabent(tokenbuf,FALSE))
877 else if (*d == '$' && d[1] &&
878 index("[#!%*<>()-=",d[1])) {
879 if (!d[2] || /*{*/ index("])} =",d[2]))
888 if (index("wds",d[1]))
890 else if (seen['\''] || seen['"'])
892 else if (index("rnftb",d[1]))
894 else if (isdigit(d[1])) {
896 while (d[1] && isdigit(d[1]))
904 if (lastunchar < d[1] || d[1] == '\\') {
905 if (index("aA01! ",lastunchar))
907 if (index("zZ79~",d[1]))
913 if (isalpha(*d) && d[1] && isalpha(d[1])) {
919 if (unchar == lastunchar + 1)
921 weight -= seen[unchar];
928 fprintf(stderr,"[%s] weight %d\n",
929 checkpoint+1,weight);
932 if (weight >= 0) /* probably a character class */
938 str_ncat(toparse, "join($\",", 8);
939 if (t[1] == '{' && s[-1] == '}') {
940 str_ncat(toparse, t, 1);
941 str_ncat(toparse, t+2, s - t - 3);
944 str_ncat(toparse, t, s - t);
946 str_ncat(toparse, ")", 1);
953 if (toparse->str_ptr && *toparse->str_ptr == ',') {
954 *toparse->str_ptr = '(';
955 str_ncat(toparse,",$$);",5);
956 str->str_u.str_args = parselist(toparse);
957 str->str_u.str_args->arg_len--; /* ignore $$ reference */
960 str->str_u.str_args = Nullarg;
962 str->str_pok |= SP_INTRP;
964 str_replace(src,str);
978 if (!(src->str_pok & SP_INTRP)) {
979 int oldsave = savestack->ary_fill;
981 (void)savehptr(&curstash);
982 curstash = src->str_u.str_hash; /* so stabent knows right package */
984 restorelist(oldsave);
986 s = src->str_ptr; /* assumed valid since str_pok set */
988 send = s + src->str_cur;
990 if (src->str_u.str_args) {
991 (void)eval(src->str_u.str_args,G_ARRAY,sp);
992 /* Assuming we have correct # of args */
993 elem = stack->ary_array + sp;
998 if (*s == '$' && s+1 < send) {
1002 str_scat(str,*++elem);
1005 str_ncat(str,++s,1);
1013 str_ncat(str,t,s-t);
1026 str->str_u.str_nval += 1.0;
1030 if (!str->str_pok || !*str->str_ptr) {
1031 str->str_u.str_nval = 1.0;
1037 while (isalpha(*d)) d++;
1038 while (isdigit(*d)) d++;
1040 str_numset(str,atof(str->str_ptr) + 1.0); /* punt */
1044 while (d >= str->str_ptr) {
1054 *(d--) -= 'z' - 'a' + 1;
1057 /* oh,oh, the number grew */
1058 STR_GROW(str, str->str_cur + 2);
1060 for (d = str->str_ptr + str->str_cur; d > str->str_ptr; d--)
1075 str->str_u.str_nval -= 1.0;
1079 if (!str->str_pok) {
1080 str->str_u.str_nval = -1.0;
1084 str_numset(str,atof(str->str_ptr) - 1.0);
1087 /* Make a string that will exist for the duration of the expression
1088 * evaluation. Actually, it may have to last longer than that, but
1089 * hopefully cmd_exec won't free it until it has been assigned to a
1090 * permanent location. */
1092 static long tmps_size = -1;
1098 register STR *str = Str_new(78,0);
1100 str_sset(str,oldstr);
1101 if (++tmps_max > tmps_size) {
1102 tmps_size = tmps_max;
1103 if (!(tmps_size & 127)) {
1105 Renew(tmps_list, tmps_size + 128, STR*);
1107 New(702,tmps_list, 128, STR*);
1110 tmps_list[tmps_max] = str;
1114 /* same thing without the copying */
1120 if (++tmps_max > tmps_size) {
1121 tmps_size = tmps_max;
1122 if (!(tmps_size & 127)) {
1124 Renew(tmps_list, tmps_size + 128, STR*);
1126 New(704,tmps_list, 128, STR*);
1129 tmps_list[tmps_max] = str;
1138 register STR *str = Str_new(79,0);
1142 str_nset(str,s,len);
1150 register STR *str = Str_new(80,0);
1156 /* make an exact duplicate of old */
1162 register STR *new = Str_new(81,0);
1166 if (old->str_state == SS_FREE) {
1167 warn("semi-panic: attempt to dup freed string");
1170 if (old->str_state == SS_INCR && !(old->str_pok & 2))
1173 Safefree(new->str_ptr);
1174 Copy(old,new,1,STR);
1176 new->str_ptr = nsavestr(old->str_ptr,old->str_len);
1184 register HENT *entry;
1185 register STAB *stab;
1188 register SPAT *spat;
1191 if (!*s) { /* reset ?? searches */
1192 for (spat = stash->tbl_spatroot;
1194 spat = spat->spat_next) {
1195 spat->spat_flags &= ~SPAT_USED;
1200 /* reset variables */
1208 for ( ; i <= max; i++) {
1209 for (entry = stash->tbl_array[i];
1211 entry = entry->hent_next) {
1212 stab = (STAB*)entry->hent_val;
1213 str = stab_val(stab);
1217 str->str_tainted = tainted;
1219 if (str->str_ptr != Nullch)
1220 str->str_ptr[0] = '\0';
1221 if (stab_xarray(stab)) {
1222 aclear(stab_xarray(stab));
1224 if (stab_xhash(stab)) {
1225 hclear(stab_xhash(stab));
1226 if (stab == envstab)
1227 environ[0] = Nullch;
1240 fprintf(stderr,"%s %d %d %d\n",s,tainted,uid, euid);
1242 if (tainted && (!euid || euid != uid)) {
1252 register STR *envstr;
1254 envstr = hfetch(stab_hash(envstab),"PATH",4,FALSE);
1255 if (!envstr || envstr->str_tainted) {
1257 taintproper("Insecure PATH");
1259 envstr = hfetch(stab_hash(envstab),"IFS",3,FALSE);
1260 if (envstr && envstr->str_tainted) {
1262 taintproper("Insecure IFS");