w3m

Unnamed repository; edit this file to name it for gitweb.
git clone https://logand.com/git/w3m.git/
Log | Files | Refs | README

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 }