a "replacement" for awk and sed
[perl.git] / str.c
1 /* $Header: str.c,v 1.0 87/12/18 13:06:22 root Exp $
2  *
3  * $Log:        str.c,v $
4  * Revision 1.0  87/12/18  13:06:22  root
5  * Initial revision
6  * 
7  */
8
9 #include "handy.h"
10 #include "EXTERN.h"
11 #include "search.h"
12 #include "util.h"
13 #include "perl.h"
14
15 str_reset(s)
16 register char *s;
17 {
18     register STAB *stab;
19     register STR *str;
20     register int i;
21     register int max;
22     register SPAT *spat;
23
24     if (!*s) {          /* reset ?? searches */
25         for (spat = spat_root; spat != Nullspat; spat = spat->spat_next) {
26             spat->spat_flags &= ~SPAT_USED;
27         }
28         return;
29     }
30
31     /* reset variables */
32
33     while (*s) {
34         i = *s;
35         if (s[1] == '-') {
36             s += 2;
37         }
38         max = *s++;
39         for ( ; i <= max; i++) {
40             for (stab = stab_index[i]; stab; stab = stab->stab_next) {
41                 str = stab->stab_val;
42                 str->str_cur = 0;
43                 if (str->str_ptr != Nullch)
44                     str->str_ptr[0] = '\0';
45             }
46         }
47     }
48 }
49
50 str_numset(str,num)
51 register STR *str;
52 double num;
53 {
54     str->str_nval = num;
55     str->str_pok = 0;           /* invalidate pointer */
56     str->str_nok = 1;           /* validate number */
57 }
58
59 char *
60 str_2ptr(str)
61 register STR *str;
62 {
63     register char *s;
64
65     if (!str)
66         return "";
67     GROWSTR(&(str->str_ptr), &(str->str_len), 24);
68     s = str->str_ptr;
69     if (str->str_nok) {
70         sprintf(s,"%.20g",str->str_nval);
71         while (*s) s++;
72     }
73     *s = '\0';
74     str->str_cur = s - str->str_ptr;
75     str->str_pok = 1;
76 #ifdef DEBUGGING
77     if (debug & 32)
78         fprintf(stderr,"0x%lx ptr(%s)\n",str,str->str_ptr);
79 #endif
80     return str->str_ptr;
81 }
82
83 double
84 str_2num(str)
85 register STR *str;
86 {
87     if (!str)
88         return 0.0;
89     if (str->str_len && str->str_pok)
90         str->str_nval = atof(str->str_ptr);
91     else
92         str->str_nval = 0.0;
93     str->str_nok = 1;
94 #ifdef DEBUGGING
95     if (debug & 32)
96         fprintf(stderr,"0x%lx num(%g)\n",str,str->str_nval);
97 #endif
98     return str->str_nval;
99 }
100
101 str_sset(dstr,sstr)
102 STR *dstr;
103 register STR *sstr;
104 {
105     if (!sstr)
106         str_nset(dstr,No,0);
107     else if (sstr->str_nok)
108         str_numset(dstr,sstr->str_nval);
109     else if (sstr->str_pok)
110         str_nset(dstr,sstr->str_ptr,sstr->str_cur);
111     else
112         str_nset(dstr,"",0);
113 }
114
115 str_nset(str,ptr,len)
116 register STR *str;
117 register char *ptr;
118 register int len;
119 {
120     GROWSTR(&(str->str_ptr), &(str->str_len), len + 1);
121     bcopy(ptr,str->str_ptr,len);
122     str->str_cur = len;
123     *(str->str_ptr+str->str_cur) = '\0';
124     str->str_nok = 0;           /* invalidate number */
125     str->str_pok = 1;           /* validate pointer */
126 }
127
128 str_set(str,ptr)
129 register STR *str;
130 register char *ptr;
131 {
132     register int len;
133
134     if (!ptr)
135         ptr = "";
136     len = strlen(ptr);
137     GROWSTR(&(str->str_ptr), &(str->str_len), len + 1);
138     bcopy(ptr,str->str_ptr,len+1);
139     str->str_cur = len;
140     str->str_nok = 0;           /* invalidate number */
141     str->str_pok = 1;           /* validate pointer */
142 }
143
144 str_chop(str,ptr)       /* like set but assuming ptr is in str */
145 register STR *str;
146 register char *ptr;
147 {
148     if (!(str->str_pok))
149         str_2ptr(str);
150     str->str_cur -= (ptr - str->str_ptr);
151     bcopy(ptr,str->str_ptr, str->str_cur + 1);
152     str->str_nok = 0;           /* invalidate number */
153     str->str_pok = 1;           /* validate pointer */
154 }
155
156 str_ncat(str,ptr,len)
157 register STR *str;
158 register char *ptr;
159 register int len;
160 {
161     if (!(str->str_pok))
162         str_2ptr(str);
163     GROWSTR(&(str->str_ptr), &(str->str_len), str->str_cur + len + 1);
164     bcopy(ptr,str->str_ptr+str->str_cur,len);
165     str->str_cur += len;
166     *(str->str_ptr+str->str_cur) = '\0';
167     str->str_nok = 0;           /* invalidate number */
168     str->str_pok = 1;           /* validate pointer */
169 }
170
171 str_scat(dstr,sstr)
172 STR *dstr;
173 register STR *sstr;
174 {
175     if (!(sstr->str_pok))
176         str_2ptr(sstr);
177     if (sstr)
178         str_ncat(dstr,sstr->str_ptr,sstr->str_cur);
179 }
180
181 str_cat(str,ptr)
182 register STR *str;
183 register char *ptr;
184 {
185     register int len;
186
187     if (!ptr)
188         return;
189     if (!(str->str_pok))
190         str_2ptr(str);
191     len = strlen(ptr);
192     GROWSTR(&(str->str_ptr), &(str->str_len), str->str_cur + len + 1);
193     bcopy(ptr,str->str_ptr+str->str_cur,len+1);
194     str->str_cur += len;
195     str->str_nok = 0;           /* invalidate number */
196     str->str_pok = 1;           /* validate pointer */
197 }
198
199 char *
200 str_append_till(str,from,delim,keeplist)
201 register STR *str;
202 register char *from;
203 register int delim;
204 char *keeplist;
205 {
206     register char *to;
207     register int len;
208
209     if (!from)
210         return Nullch;
211     len = strlen(from);
212     GROWSTR(&(str->str_ptr), &(str->str_len), str->str_cur + len + 1);
213     str->str_nok = 0;           /* invalidate number */
214     str->str_pok = 1;           /* validate pointer */
215     to = str->str_ptr+str->str_cur;
216     for (; *from; from++,to++) {
217         if (*from == '\\' && from[1] && delim != '\\') {
218             if (!keeplist) {
219                 if (from[1] == delim || from[1] == '\\')
220                     from++;
221                 else
222                     *to++ = *from++;
223             }
224             else if (index(keeplist,from[1]))
225                 *to++ = *from++;
226             else
227                 from++;
228         }
229         else if (*from == delim)
230             break;
231         *to = *from;
232     }
233     *to = '\0';
234     str->str_cur = to - str->str_ptr;
235     return from;
236 }
237
238 STR *
239 str_new(len)
240 int len;
241 {
242     register STR *str;
243     
244     if (freestrroot) {
245         str = freestrroot;
246         freestrroot = str->str_link.str_next;
247         str->str_link.str_magic = Nullstab;
248     }
249     else {
250         str = (STR *) safemalloc(sizeof(STR));
251         bzero((char*)str,sizeof(STR));
252     }
253     if (len)
254         GROWSTR(&(str->str_ptr), &(str->str_len), len + 1);
255     return str;
256 }
257
258 void
259 str_grow(str,len)
260 register STR *str;
261 int len;
262 {
263     if (len && str)
264         GROWSTR(&(str->str_ptr), &(str->str_len), len + 1);
265 }
266
267 /* make str point to what nstr did */
268
269 void
270 str_replace(str,nstr)
271 register STR *str;
272 register STR *nstr;
273 {
274     safefree(str->str_ptr);
275     str->str_ptr = nstr->str_ptr;
276     str->str_len = nstr->str_len;
277     str->str_cur = nstr->str_cur;
278     str->str_pok = nstr->str_pok;
279     if (str->str_nok = nstr->str_nok)
280         str->str_nval = nstr->str_nval;
281     safefree((char*)nstr);
282 }
283
284 void
285 str_free(str)
286 register STR *str;
287 {
288     if (!str)
289         return;
290     if (str->str_len)
291         str->str_ptr[0] = '\0';
292     str->str_cur = 0;
293     str->str_nok = 0;
294     str->str_pok = 0;
295     str->str_link.str_next = freestrroot;
296     freestrroot = str;
297 }
298
299 str_len(str)
300 register STR *str;
301 {
302     if (!str)
303         return 0;
304     if (!(str->str_pok))
305         str_2ptr(str);
306     if (str->str_len)
307         return str->str_cur;
308     else
309         return 0;
310 }
311
312 char *
313 str_gets(str,fp)
314 register STR *str;
315 register FILE *fp;
316 {
317 #ifdef STDSTDIO         /* Here is some breathtakingly efficient cheating */
318
319     register char *bp;          /* we're going to steal some values */
320     register int cnt;           /*  from the stdio struct and put EVERYTHING */
321     register char *ptr;         /*   in the innermost loop into registers */
322     register char newline = record_separator;   /* (assuming >= 6 registers) */
323     int i;
324     int bpx;
325     int obpx;
326     register int get_paragraph;
327     register char *oldbp;
328
329     if (get_paragraph = !newline) {     /* yes, that's an assignment */
330         newline = '\n';
331         oldbp = Nullch;                 /* remember last \n position (none) */
332     }
333     cnt = fp->_cnt;                     /* get count into register */
334     str->str_nok = 0;                   /* invalidate number */
335     str->str_pok = 1;                   /* validate pointer */
336     if (str->str_len <= cnt)            /* make sure we have the room */
337         GROWSTR(&(str->str_ptr), &(str->str_len), cnt+1);
338     bp = str->str_ptr;                  /* move these two too to registers */
339     ptr = fp->_ptr;
340     for (;;) {
341       screamer:
342         while (--cnt >= 0) {                    /* this */      /* eat */
343             if ((*bp++ = *ptr++) == newline)    /* really */    /* dust */
344                 goto thats_all_folks;           /* screams */   /* sed :-) */ 
345         }
346         
347         fp->_cnt = cnt;                 /* deregisterize cnt and ptr */
348         fp->_ptr = ptr;
349         i = _filbuf(fp);                /* get more characters */
350         cnt = fp->_cnt;
351         ptr = fp->_ptr;                 /* reregisterize cnt and ptr */
352
353         bpx = bp - str->str_ptr;        /* prepare for possible relocation */
354         if (get_paragraph && oldbp)
355             obpx = oldbp - str->str_ptr;
356         GROWSTR(&(str->str_ptr), &(str->str_len), str->str_cur + cnt + 1);
357         bp = str->str_ptr + bpx;        /* reconstitute our pointer */
358         if (get_paragraph && oldbp)
359             oldbp = str->str_ptr + obpx;
360
361         if (i == newline) {             /* all done for now? */
362             *bp++ = i;
363             goto thats_all_folks;
364         }
365         else if (i == EOF)              /* all done for ever? */
366             goto thats_really_all_folks;
367         *bp++ = i;                      /* now go back to screaming loop */
368     }
369
370 thats_all_folks:
371     if (get_paragraph && bp - 1 != oldbp) {
372         oldbp = bp;     /* remember where this newline was */
373         goto screamer;  /* and go back to the fray */
374     }
375 thats_really_all_folks:
376     fp->_cnt = cnt;                     /* put these back or we're in trouble */
377     fp->_ptr = ptr;
378     *bp = '\0';
379     str->str_cur = bp - str->str_ptr;   /* set length */
380
381 #else /* !STDSTDIO */   /* The big, slow, and stupid way */
382
383     static char buf[4192];
384
385     if (fgets(buf, sizeof buf, fp) != Nullch)
386         str_set(str, buf);
387     else
388         str_set(str, No);
389
390 #endif /* STDSTDIO */
391
392     return str->str_cur ? str->str_ptr : Nullch;
393 }
394
395
396 STR *
397 interp(str,s)
398 register STR *str;
399 register char *s;
400 {
401     register char *t = s;
402     char *envsave = envname;
403     envname = Nullch;
404
405     str_set(str,"");
406     while (*s) {
407         if (*s == '\\' && s[1] == '$') {
408             str_ncat(str, t, s++ - t);
409             t = s++;
410         }
411         else if (*s == '$' && s[1] && s[1] != '|') {
412             str_ncat(str,t,s-t);
413             s = scanreg(s,tokenbuf);
414             str_cat(str,reg_get(tokenbuf));
415             t = s;
416         }
417         else
418             s++;
419     }
420     envname = envsave;
421     str_ncat(str,t,s-t);
422     return str;
423 }
424
425 void
426 str_inc(str)
427 register STR *str;
428 {
429     register char *d;
430
431     if (!str)
432         return;
433     if (str->str_nok) {
434         str->str_nval += 1.0;
435         str->str_pok = 0;
436         return;
437     }
438     if (!str->str_pok) {
439         str->str_nval = 1.0;
440         str->str_nok = 1;
441         return;
442     }
443     for (d = str->str_ptr; *d && *d != '.'; d++) ;
444     d--;
445     if (!isdigit(*str->str_ptr) || !isdigit(*d) ) {
446         str_numset(str,atof(str->str_ptr) + 1.0);  /* punt */
447         return;
448     }
449     while (d >= str->str_ptr) {
450         if (++*d <= '9')
451             return;
452         *(d--) = '0';
453     }
454     /* oh,oh, the number grew */
455     GROWSTR(&(str->str_ptr), &(str->str_len), str->str_cur + 2);
456     str->str_cur++;
457     for (d = str->str_ptr + str->str_cur; d > str->str_ptr; d--)
458         *d = d[-1];
459     *d = '1';
460 }
461
462 void
463 str_dec(str)
464 register STR *str;
465 {
466     register char *d;
467
468     if (!str)
469         return;
470     if (str->str_nok) {
471         str->str_nval -= 1.0;
472         str->str_pok = 0;
473         return;
474     }
475     if (!str->str_pok) {
476         str->str_nval = -1.0;
477         str->str_nok = 1;
478         return;
479     }
480     for (d = str->str_ptr; *d && *d != '.'; d++) ;
481     d--;
482     if (!isdigit(*str->str_ptr) || !isdigit(*d) || (*d == '0' && d == str->str_ptr)) {
483         str_numset(str,atof(str->str_ptr) - 1.0);  /* punt */
484         return;
485     }
486     while (d >= str->str_ptr) {
487         if (--*d >= '0')
488             return;
489         *(d--) = '9';
490     }
491 }
492
493 /* make a string that will exist for the duration of the expression eval */
494
495 STR *
496 str_static(oldstr)
497 STR *oldstr;
498 {
499     register STR *str = str_new(0);
500     static long tmps_size = -1;
501
502     str_sset(str,oldstr);
503     if (++tmps_max > tmps_size) {
504         tmps_size = tmps_max;
505         if (!(tmps_size & 127)) {
506             if (tmps_size)
507                 tmps_list = (STR**)saferealloc((char*)tmps_list,
508                     (tmps_size + 128) * sizeof(STR*) );
509             else
510                 tmps_list = (STR**)safemalloc(128 * sizeof(char*));
511         }
512     }
513     tmps_list[tmps_max] = str;
514     return str;
515 }
516
517 STR *
518 str_make(s)
519 char *s;
520 {
521     register STR *str = str_new(0);
522
523     str_set(str,s);
524     return str;
525 }
526
527 STR *
528 str_nmake(n)
529 double n;
530 {
531     register STR *str = str_new(0);
532
533     str_numset(str,n);
534     return str;
535 }