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