Str.c (9713B)
1 /* $Id$ */ 2 /* 3 * String manipulation library for Boehm GC 4 * 5 * (C) Copyright 1998-1999 by Akinori Ito 6 * 7 * This software may be redistributed freely for this purpose, in full 8 * or in part, provided that this entire copyright notice is included 9 * on any copies of this software and applications and derivations thereof. 10 * 11 * This software is provided on an "as is" basis, without warranty of any 12 * kind, either expressed or implied, as to any matter including, but not 13 * limited to warranty of fitness of purpose, or merchantability, or 14 * results obtained from use of this software. 15 */ 16 #include <stdio.h> 17 #include <stdlib.h> 18 #include <gc.h> 19 #include <stdarg.h> 20 #include <string.h> 21 #ifdef __EMX__ /* or include "fm.h" for HAVE_BCOPY? */ 22 #include <strings.h> 23 #endif 24 #include "Str.h" 25 #include "myctype.h" 26 27 #define INITIAL_STR_SIZE 32 28 29 #ifdef STR_DEBUG 30 /* This is obsolete, because "Str" can handle a '\0' character now. */ 31 #define STR_LENGTH_CHECK(x) if (((x)->ptr==0&&(x)->length!=0)||(strlen((x)->ptr)!=(x)->length))abort(); 32 #else /* not STR_DEBUG */ 33 #define STR_LENGTH_CHECK(x) 34 #endif /* not STR_DEBUG */ 35 36 Str 37 Strnew() 38 { 39 Str x = GC_MALLOC(sizeof(struct _Str)); 40 x->ptr = GC_MALLOC_ATOMIC(INITIAL_STR_SIZE); 41 x->ptr[0] = '\0'; 42 x->area_size = INITIAL_STR_SIZE; 43 x->length = 0; 44 return x; 45 } 46 47 Str 48 Strnew_size(int n) 49 { 50 Str x = GC_MALLOC(sizeof(struct _Str)); 51 x->ptr = GC_MALLOC_ATOMIC(n + 1); 52 x->ptr[0] = '\0'; 53 x->area_size = n + 1; 54 x->length = 0; 55 return x; 56 } 57 58 Str 59 Strnew_charp(char *p) 60 { 61 Str x; 62 int n; 63 64 if (p == NULL) 65 return Strnew(); 66 x = GC_MALLOC(sizeof(struct _Str)); 67 n = strlen(p) + 1; 68 x->ptr = GC_MALLOC_ATOMIC(n); 69 x->area_size = n; 70 x->length = n - 1; 71 bcopy((void *)p, (void *)x->ptr, n); 72 return x; 73 } 74 75 Str 76 Strnew_m_charp(char *p, ...) 77 { 78 va_list ap; 79 Str r = Strnew(); 80 81 va_start(ap, p); 82 while (p != NULL) { 83 Strcat_charp(r, p); 84 p = va_arg(ap, char *); 85 } 86 return r; 87 } 88 89 Str 90 Strnew_charp_n(char *p, int n) 91 { 92 Str x; 93 94 if (p == NULL) 95 return Strnew_size(n); 96 x = GC_MALLOC(sizeof(struct _Str)); 97 x->ptr = GC_MALLOC_ATOMIC(n + 1); 98 x->area_size = n + 1; 99 x->length = n; 100 bcopy((void *)p, (void *)x->ptr, n); 101 x->ptr[n] = '\0'; 102 return x; 103 } 104 105 Str 106 Strdup(Str s) 107 { 108 Str n = Strnew_size(s->length); 109 STR_LENGTH_CHECK(s); 110 Strcopy(n, s); 111 return n; 112 } 113 114 void 115 Strclear(Str s) 116 { 117 s->length = 0; 118 s->ptr[0] = '\0'; 119 } 120 121 void 122 Strfree(Str x) 123 { 124 GC_free(x->ptr); 125 GC_free(x); 126 } 127 128 void 129 Strcopy(Str x, Str y) 130 { 131 STR_LENGTH_CHECK(x); 132 STR_LENGTH_CHECK(y); 133 if (x->area_size < y->length + 1) { 134 GC_free(x->ptr); 135 x->ptr = GC_MALLOC_ATOMIC(y->length + 1); 136 x->area_size = y->length + 1; 137 } 138 bcopy((void *)y->ptr, (void *)x->ptr, y->length + 1); 139 x->length = y->length; 140 } 141 142 void 143 Strcopy_charp(Str x, char *y) 144 { 145 int len; 146 147 STR_LENGTH_CHECK(x); 148 if (y == NULL) { 149 x->length = 0; 150 return; 151 } 152 len = strlen(y); 153 if (x->area_size < len + 1) { 154 GC_free(x->ptr); 155 x->ptr = GC_MALLOC_ATOMIC(len + 1); 156 x->area_size = len + 1; 157 } 158 bcopy((void *)y, (void *)x->ptr, len + 1); 159 x->length = len; 160 } 161 162 void 163 Strcopy_charp_n(Str x, char *y, int n) 164 { 165 int len = n; 166 167 STR_LENGTH_CHECK(x); 168 if (y == NULL) { 169 x->length = 0; 170 return; 171 } 172 if (x->area_size < len + 1) { 173 GC_free(x->ptr); 174 x->ptr = GC_MALLOC_ATOMIC(len + 1); 175 x->area_size = len + 1; 176 } 177 bcopy((void *)y, (void *)x->ptr, n); 178 x->ptr[n] = '\0'; 179 x->length = n; 180 } 181 182 void 183 Strcat_charp_n(Str x, char *y, int n) 184 { 185 int newlen; 186 187 STR_LENGTH_CHECK(x); 188 if (y == NULL) 189 return; 190 newlen = x->length + n + 1; 191 if (x->area_size < newlen) { 192 char *old = x->ptr; 193 newlen = newlen * 3 / 2; 194 x->ptr = GC_MALLOC_ATOMIC(newlen); 195 x->area_size = newlen; 196 bcopy((void *)old, (void *)x->ptr, x->length); 197 GC_free(old); 198 } 199 bcopy((void *)y, (void *)&x->ptr[x->length], n); 200 x->length += n; 201 x->ptr[x->length] = '\0'; 202 } 203 204 void 205 Strcat(Str x, Str y) 206 { 207 STR_LENGTH_CHECK(y); 208 Strcat_charp_n(x, y->ptr, y->length); 209 } 210 211 void 212 Strcat_charp(Str x, char *y) 213 { 214 if (y == NULL) 215 return; 216 Strcat_charp_n(x, y, strlen(y)); 217 } 218 219 void 220 Strcat_m_charp(Str x, ...) 221 { 222 va_list ap; 223 char *p; 224 225 va_start(ap, x); 226 while ((p = va_arg(ap, char *)) != NULL) 227 Strcat_charp_n(x, p, strlen(p)); 228 } 229 230 void 231 Strgrow(Str x) 232 { 233 char *old = x->ptr; 234 int newlen; 235 newlen = x->length * 6 / 5; 236 if (newlen == x->length) 237 newlen += 2; 238 x->ptr = GC_MALLOC_ATOMIC(newlen); 239 x->area_size = newlen; 240 bcopy((void *)old, (void *)x->ptr, x->length); 241 GC_free(old); 242 } 243 244 Str 245 Strsubstr(Str s, int beg, int len) 246 { 247 Str new_s; 248 int i; 249 250 STR_LENGTH_CHECK(s); 251 new_s = Strnew(); 252 if (beg >= s->length) 253 return new_s; 254 for (i = 0; i < len && beg + i < s->length; i++) 255 Strcat_char(new_s, s->ptr[beg + i]); 256 return new_s; 257 } 258 259 void 260 Strlower(Str s) 261 { 262 int i; 263 STR_LENGTH_CHECK(s); 264 for (i = 0; i < s->length; i++) 265 s->ptr[i] = TOLOWER(s->ptr[i]); 266 } 267 268 void 269 Strupper(Str s) 270 { 271 int i; 272 STR_LENGTH_CHECK(s); 273 for (i = 0; i < s->length; i++) 274 s->ptr[i] = TOUPPER(s->ptr[i]); 275 } 276 277 void 278 Strchop(Str s) 279 { 280 STR_LENGTH_CHECK(s); 281 while ((s->ptr[s->length - 1] == '\n' || s->ptr[s->length - 1] == '\r') && 282 s->length > 0) { 283 s->length--; 284 } 285 s->ptr[s->length] = '\0'; 286 } 287 288 void 289 Strinsert_char(Str s, int pos, char c) 290 { 291 int i; 292 STR_LENGTH_CHECK(s); 293 if (pos < 0 || s->length < pos) 294 return; 295 if (s->length + 2 > s->area_size) 296 Strgrow(s); 297 for (i = s->length; i > pos; i--) 298 s->ptr[i] = s->ptr[i - 1]; 299 s->ptr[++s->length] = '\0'; 300 s->ptr[pos] = c; 301 } 302 303 void 304 Strinsert_charp(Str s, int pos, char *p) 305 { 306 STR_LENGTH_CHECK(s); 307 while (*p) 308 Strinsert_char(s, pos++, *(p++)); 309 } 310 311 void 312 Strdelete(Str s, int pos, int n) 313 { 314 int i; 315 STR_LENGTH_CHECK(s); 316 if (s->length <= pos + n) { 317 s->ptr[pos] = '\0'; 318 s->length = pos; 319 return; 320 } 321 for (i = pos; i < s->length - n; i++) 322 s->ptr[i] = s->ptr[i + n]; 323 s->ptr[i] = '\0'; 324 s->length = i; 325 } 326 327 void 328 Strtruncate(Str s, int pos) 329 { 330 STR_LENGTH_CHECK(s); 331 s->ptr[pos] = '\0'; 332 s->length = pos; 333 } 334 335 void 336 Strshrink(Str s, int n) 337 { 338 STR_LENGTH_CHECK(s); 339 if (n >= s->length) { 340 s->length = 0; 341 s->ptr[0] = '\0'; 342 } 343 else { 344 s->length -= n; 345 s->ptr[s->length] = '\0'; 346 } 347 } 348 349 void 350 Strremovefirstspaces(Str s) 351 { 352 int i; 353 354 STR_LENGTH_CHECK(s); 355 for (i = 0; i < s->length && IS_SPACE(s->ptr[i]); i++) ; 356 if (i == 0) 357 return; 358 Strdelete(s, 0, i); 359 } 360 361 void 362 Strremovetrailingspaces(Str s) 363 { 364 int i; 365 366 STR_LENGTH_CHECK(s); 367 for (i = s->length - 1; i >= 0 && IS_SPACE(s->ptr[i]); i--) ; 368 s->length = i + 1; 369 s->ptr[i + 1] = '\0'; 370 } 371 372 Str 373 Stralign_left(Str s, int width) 374 { 375 Str n; 376 int i; 377 378 STR_LENGTH_CHECK(s); 379 if (s->length >= width) 380 return Strdup(s); 381 n = Strnew_size(width); 382 Strcopy(n, s); 383 for (i = s->length; i < width; i++) 384 Strcat_char(n, ' '); 385 return n; 386 } 387 388 Str 389 Stralign_right(Str s, int width) 390 { 391 Str n; 392 int i; 393 394 STR_LENGTH_CHECK(s); 395 if (s->length >= width) 396 return Strdup(s); 397 n = Strnew_size(width); 398 for (i = s->length; i < width; i++) 399 Strcat_char(n, ' '); 400 Strcat(n, s); 401 return n; 402 } 403 404 Str 405 Stralign_center(Str s, int width) 406 { 407 Str n; 408 int i, w; 409 410 STR_LENGTH_CHECK(s); 411 if (s->length >= width) 412 return Strdup(s); 413 n = Strnew_size(width); 414 w = (width - s->length) / 2; 415 for (i = 0; i < w; i++) 416 Strcat_char(n, ' '); 417 Strcat(n, s); 418 for (i = w + s->length; i < width; i++) 419 Strcat_char(n, ' '); 420 return n; 421 } 422 423 #define SP_NORMAL 0 424 #define SP_PREC 1 425 #define SP_PREC2 2 426 427 Str 428 Sprintf(char *fmt, ...) 429 { 430 int len = 0; 431 int status = SP_NORMAL; 432 int p = 0; 433 char *f; 434 Str s; 435 va_list ap; 436 437 va_start(ap, fmt); 438 for (f = fmt; *f; f++) { 439 redo: 440 switch (status) { 441 case SP_NORMAL: 442 if (*f == '%') { 443 status = SP_PREC; 444 p = 0; 445 } 446 else 447 len++; 448 break; 449 case SP_PREC: 450 if (IS_ALPHA(*f)) { 451 /* conversion char. */ 452 double vd; 453 int vi; 454 char *vs; 455 void *vp; 456 457 switch (*f) { 458 case 'l': 459 case 'h': 460 case 'L': 461 case 'w': 462 continue; 463 case 'd': 464 case 'i': 465 case 'o': 466 case 'x': 467 case 'X': 468 case 'u': 469 vi = va_arg(ap, int); 470 len += (p > 0) ? p : 10; 471 break; 472 case 'f': 473 case 'g': 474 case 'e': 475 case 'G': 476 case 'E': 477 vd = va_arg(ap, double); 478 len += (p > 0) ? p : 15; 479 break; 480 case 'c': 481 len += 1; 482 vi = va_arg(ap, int); 483 break; 484 case 's': 485 vs = va_arg(ap, char *); 486 vi = strlen(vs); 487 len += (p > vi) ? p : vi; 488 break; 489 case 'p': 490 vp = va_arg(ap, void *); 491 len += 10; 492 break; 493 case 'n': 494 vp = va_arg(ap, void *); 495 break; 496 } 497 status = SP_NORMAL; 498 } 499 else if (IS_DIGIT(*f)) 500 p = p * 10 + *f - '0'; 501 else if (*f == '.') 502 status = SP_PREC2; 503 else if (*f == '%') { 504 status = SP_NORMAL; 505 len++; 506 } 507 break; 508 case SP_PREC2: 509 if (IS_ALPHA(*f)) { 510 status = SP_PREC; 511 goto redo; 512 } 513 break; 514 } 515 } 516 va_end(ap); 517 s = Strnew_size(len * 2); 518 va_start(ap, fmt); 519 vsprintf(s->ptr, fmt, ap); 520 va_end(ap); 521 s->length = strlen(s->ptr); 522 if (s->length > len * 2) { 523 fprintf(stderr, "Sprintf: string too long\n"); 524 exit(1); 525 } 526 return s; 527 } 528 529 Str 530 Strfgets(FILE * f) 531 { 532 Str s = Strnew(); 533 char c; 534 while (1) { 535 c = fgetc(f); 536 if (feof(f) || ferror(f)) 537 break; 538 Strcat_char(s, c); 539 if (c == '\n') 540 break; 541 } 542 return s; 543 } 544 545 Str 546 Strfgetall(FILE * f) 547 { 548 Str s = Strnew(); 549 char c; 550 while (1) { 551 c = fgetc(f); 552 if (feof(f) || ferror(f)) 553 break; 554 Strcat_char(s, c); 555 } 556 return s; 557 }