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