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