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 16void 17str_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 24char * 25str_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 47double 48str_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 64void 65str_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 77void 78str_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 88void 89str_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 103void 104str_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 116void 117str_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 129void 130str_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 138void 139str_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 155char * 156str_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 190STR * 191str_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 208void 209str_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 217void 218str_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 230void 231str_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 244int 245str_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 257char * 258str_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 318thats_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 339void 340str_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 375void 376str_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 407STR * 408str_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 428STR * 429str_make(char *s) 430{ 431 register STR *str = str_new(0); 432 433 str_set(str,s); 434 return str; 435} 436 437STR * 438str_nmake(double n) 439{ 440 register STR *str = str_new(0); 441 442 str_numset(str,n); 443 return str; 444} 445