root/libutil/strbuf.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. print_and_abort
  2. __strbuf_expandbuf
  3. strbuf_open
  4. strbuf_reset
  5. strbuf_clear
  6. strbuf_nputs
  7. strbuf_nputc
  8. strbuf_puts
  9. strbuf_puts_withterm
  10. strbuf_puts_nl
  11. strbuf_putn
  12. strbuf_unputc
  13. strbuf_value
  14. strbuf_trim
  15. strbuf_fgets
  16. strbuf_sprintf
  17. strbuf_vsprintf
  18. strbuf_close
  19. strbuf_open_tempbuf
  20. strbuf_release_tempbuf

   1 /*
   2  * Copyright (c) 1997, 1998, 1999, 2000, 2002, 2005, 2006, 2010
   3  *      Tama Communications Corporation
   4  *
   5  * This file is part of GNU GLOBAL.
   6  *
   7  * This program is free software: you can redistribute it and/or modify
   8  * it under the terms of the GNU General Public License as published by
   9  * the Free Software Foundation, either version 3 of the License, or
  10  * (at your option) any later version.
  11  * 
  12  * This program is distributed in the hope that it will be useful,
  13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15  * GNU General Public License for more details.
  16  * 
  17  * You should have received a copy of the GNU General Public License
  18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  19  */
  20 
  21 #ifdef HAVE_CONFIG_H
  22 #include <config.h>
  23 #endif
  24 #include <ctype.h>
  25 #ifdef STDC_HEADERS
  26 #include <stdlib.h>
  27 #endif
  28 #ifdef HAVE_STRING_H
  29 #include <string.h>
  30 #else
  31 #include <strings.h>
  32 #endif
  33 
  34 #include "checkalloc.h"
  35 #include "die.h"
  36 #include "strbuf.h"
  37 
  38 #ifndef isblank
  39 #define isblank(c)      ((c) == ' ' || (c) == '\t')
  40 #endif
  41 /**
  42  @file
  43 
  44 String buffer: usage and memory status
  45 
  46                                         [xxx]: string buffer <br>
  47                                         'v': current pointer
  48 
  49 @code
  50 Function call                           Memory status
  51 ----------------------------------------------------------
  52                                         (not exist)
  53                                          v
  54 sb = strbuf_open(0);                    []
  55                                           v
  56 strbuf_putc(sb, 'a');                   [a]
  57                                           v
  58 char *s = strbuf_value(sb);             [a\0]           s == "a"
  59                                             v
  60 strbuf_puts(sb, "bc");                  [abc]
  61                                             v
  62 char *s = strbuf_value(sb);             [abc\0]         s == "abc"
  63                                             v
  64 int len = strbuf_getlen(sb);            [abc\0]         len == 3
  65                                          v
  66 strbuf_reset(sb);                       [abc\0]
  67                                          v
  68 int len = strbuf_getlen(sb);            [abc\0]         len == 0
  69                                            v
  70 strbuf_puts(sb, "XY");                  [XYc\0]
  71                                            v
  72 char *s = strbuf_value(sb);             [XY\0]          s == "XY"
  73 
  74 fp = fopen("/etc/passwd", "r");                                             v
  75 char *s = strbuf_fgets(sb, fp, 0)       [root:*:0:0:Charlie &:/root:/bin/csh\0]
  76 fclose(fp)                              s == "root:*:0:0:Charlie &:/root:/bin/csh"
  77 
  78 strbuf_close(sb);                       (not exist)
  79 @endcode
  80 */
  81 
  82 static void print_and_abort (void);
  83 void (*strbuf_alloc_failed_handler) (void) = print_and_abort;
  84 
  85 static void
  86 print_and_abort(void)
  87 {
  88         die("short of memory.");
  89 }
  90 
  91 /**
  92  * __strbuf_expandbuf: expand buffer so that afford to the length data at least.
  93  *
  94  *      @param[in]      sb      #STRBUF structure
  95  *      @param[in]      length  required room
  96  */
  97 void
  98 __strbuf_expandbuf(STRBUF *sb, int length)
  99 {
 100         int count = sb->curp - sb->sbuf;
 101         int newsize = sb->sbufsize + (length > EXPANDSIZE ? length : EXPANDSIZE);
 102         char *newbuf;
 103 
 104         if (sb->alloc_failed)
 105                 return;
 106         newbuf = (char *)check_realloc(sb->sbuf, newsize + 1);
 107         sb->sbufsize = newsize;
 108         sb->sbuf = newbuf;
 109 
 110         sb->curp = sb->sbuf + count;
 111         sb->endp = sb->sbuf + sb->sbufsize;
 112 }
 113 /**
 114  * strbuf_open: open string buffer.
 115  *
 116  *      @param[in]      init    initial buffer size <br>
 117  *                      if 0 (zero) is specified then use default value (#INITIALSIZE).
 118  *      @return sb      #STRBUF structure
 119  */
 120 STRBUF *
 121 strbuf_open(int init)
 122 {
 123         STRBUF *sb = (STRBUF *)check_calloc(sizeof(STRBUF), 1);
 124 
 125         sb->sbufsize = (init > 0) ? init : INITIALSIZE;
 126         sb->sbuf = (char *)check_malloc(sb->sbufsize + 1);
 127         sb->curp = sb->sbuf;
 128         sb->endp = sb->sbuf + sb->sbufsize;
 129 
 130         return sb;
 131 }
 132 /**
 133  * strbuf_reset: reset string buffer.
 134  *
 135  *      @param[in]      sb      string buffer
 136  */
 137 void
 138 strbuf_reset(STRBUF *sb)
 139 {
 140         sb->curp = sb->sbuf;
 141         sb->alloc_failed = 0;
 142 }
 143 /**
 144  * strbuf_clear: clear static string buffer.
 145  *
 146  *      @param[in]      sb      statically defined string buffer
 147  *
 148  * This function is used for the initializing of static string buffer.
 149  * For the detail, see STATIC_STRBUF(sb) macro in @FILE{strbuf.h}.
 150  */
 151 void
 152 strbuf_clear(STRBUF *sb)
 153 {
 154         if (sb == NULL)
 155                 die("NULL string buffer. (strbuf_clear)");
 156         if (strbuf_empty(sb)) {
 157                 sb->sbufsize = INITIALSIZE;
 158                 sb->sbuf = (char *)check_malloc(sb->sbufsize + 1);
 159                 sb->curp = sb->sbuf;
 160                 sb->endp = sb->sbuf + sb->sbufsize;
 161         } else {
 162                 strbuf_reset(sb);
 163         }
 164 }
 165 /**
 166  * strbuf_nputs: Put string with length
 167  *
 168  *      @param[in]      sb      string buffer
 169  *      @param[in]      s       string
 170  *      @param[in]      len     length of string
 171  */
 172 void
 173 strbuf_nputs(STRBUF *sb, const char *s, int len)
 174 {
 175         if (!sb->alloc_failed && len > 0) {
 176                 if (sb->curp + len > sb->endp)
 177                         __strbuf_expandbuf(sb, len);
 178                 while (len-- > 0)
 179                         *sb->curp++ = *s++;
 180         }
 181 }
 182 /**
 183  * strbuf_nputc: Put a character, @a len (number) times
 184  *
 185  *      @param[in]      sb      string buffer
 186  *      @param[in]      c       character
 187  *      @param[in]      len     number of times to put @a c
 188  *
 189  *      @see strbuf_putc()
 190  */
 191 void
 192 strbuf_nputc(STRBUF *sb, int c, int len)
 193 {
 194         if (!sb->alloc_failed && len > 0) {
 195                 if (sb->curp + len > sb->endp)
 196                         __strbuf_expandbuf(sb, len);
 197                 while (len-- > 0)
 198                         *sb->curp++ = c;
 199         }
 200 }
 201 /**
 202  * strbuf_puts: Put string
 203  *
 204  *      @param[in]      sb      string buffer
 205  *      @param[in]      s       string
 206  */
 207 void
 208 strbuf_puts(STRBUF *sb, const char *s)
 209 {
 210         if (!sb->alloc_failed) {
 211                 while (*s) {
 212                         if (sb->curp >= sb->endp)
 213                                 __strbuf_expandbuf(sb, 0);
 214                         *sb->curp++ = *s++;
 215                 }
 216         }
 217 }
 218 /**
 219  * strbuf_puts_withterm: Put string until the terminator
 220  *
 221  *      @param[in]      sb      string buffer
 222  *      @param[in]      s       string
 223  *      @param[in]      c       terminator
 224  *      @return         pointer to the terminator
 225  */
 226 void
 227 strbuf_puts_withterm(STRBUF *sb, const char *s, int c)
 228 {
 229         if (!sb->alloc_failed) {
 230                 while (*s && *s != c) {
 231                         if (sb->curp >= sb->endp)
 232                                 __strbuf_expandbuf(sb, 0);
 233                         *sb->curp++ = *s++;
 234                 }
 235         }
 236 }
 237 /**
 238  * strbuf_puts_nl: Put string with a new line
 239  *
 240  *      @param[in]      sb      string buffer
 241  *      @param[in]      s       string
 242  */
 243 void
 244 strbuf_puts_nl(STRBUF *sb, const char *s)
 245 {
 246         if (!sb->alloc_failed) {
 247                 while (*s) {
 248                         if (sb->curp >= sb->endp)
 249                                 __strbuf_expandbuf(sb, 0);
 250                         *sb->curp++ = *s++;
 251                 }
 252                 if (sb->curp >= sb->endp)
 253                         __strbuf_expandbuf(sb, 0);
 254                 *sb->curp++ = '\n';
 255         }
 256 }
 257 /**
 258  * strbuf_putn: put digit string at the last of buffer.
 259  *
 260  *      @param[in]      sb      #STRBUF structure
 261  *      @param[in]      n       number
 262  */
 263 void
 264 strbuf_putn(STRBUF *sb, int n)
 265 {
 266         if (n == 0) {
 267                 strbuf_putc(sb, '0');
 268         } else {
 269                 char num[128];
 270                 int i = 0;
 271 
 272                 while (n) {
 273                         if (i >= sizeof(num))
 274                                 die("Too big integer value.");
 275                         num[i++] = n % 10 + '0';
 276                         n = n / 10;
 277                 }
 278                 while (--i >= 0)
 279                         strbuf_putc(sb, num[i]);
 280         }
 281 }
 282 /**
 283  * strbuf_unputc: remove specified char from the last of buffer
 284  *
 285  *      @param[in]      sb      #STRBUF structure
 286  *      @param[in]      c       character
 287  *      @return         0: do nothing, 1: removed
 288  */
 289 int
 290 strbuf_unputc(STRBUF *sb, int c)
 291 {
 292         if (sb->curp > sb->sbuf && *(sb->curp - 1) == c) {
 293                 sb->curp--;
 294                 return 1;
 295         }
 296         return 0;
 297 }
 298 /**
 299  * strbuf_value: return the content of string buffer.
 300  *
 301  *      @param[in]      sb      #STRBUF structure
 302  *      @return         string
 303  */
 304 char *
 305 strbuf_value(STRBUF *sb)
 306 {
 307         *sb->curp = 0;
 308         return sb->sbuf;
 309 }
 310 /**
 311  * strbuf_trim: trim following blanks.
 312  *
 313  *      @param[in]      sb      #STRBUF structure
 314  */
 315 void
 316 strbuf_trim(STRBUF *sb)
 317 {
 318         char *p = sb->curp;
 319 
 320         while (p > sb->sbuf && isblank(*(p - 1)))
 321                 *--p = 0;
 322         sb->curp = p;
 323 }
 324 /**
 325  * strbuf_fgets: read whole record into string buffer
 326  *
 327  *      @param[out]     sb      string buffer
 328  *      @param[in]      ip      input stream
 329  *      @param[in]      flags   flags <br>
 330  *                      #STRBUF_NOCRLF: remove last @CODE{'\\n'} and/or @CODE{'\\r'} if exist. <br>
 331  *                      #STRBUF_APPEND: append next record to existing data <br>
 332  *                      #STRBUF_SHARPSKIP: skip lines which start with @CODE{'\#'}
 333  *      @return         record buffer (@VAR{NULL} at end of file)
 334  *
 335  * Returned buffer has whole record. <br>
 336  * The buffer end with @CODE{'\\0'}. If #STRBUF_NOCRLF is set then buffer doesn't
 337  * include @CODE{'\\r'} and @CODE{'\\n'}.
 338  */
 339 char *
 340 strbuf_fgets(STRBUF *sb, FILE *ip, int flags)
 341 {
 342         if (!(flags & STRBUF_APPEND))
 343                 strbuf_reset(sb);
 344 
 345         if (sb->curp >= sb->endp)
 346                 __strbuf_expandbuf(sb, EXPANDSIZE);     /* expand buffer */
 347         if (sb->alloc_failed)
 348                 return sb->sbuf;
 349 
 350         for (;;) {
 351                 if (!fgets(sb->curp, sb->endp - sb->curp, ip)) {
 352                         if (sb->curp == sb->sbuf)
 353                                 return NULL;
 354                         break;
 355                 }
 356                 if (flags & STRBUF_SHARPSKIP && *(sb->curp) == '#')
 357                         continue;
 358                 sb->curp += strlen(sb->curp);
 359                 if (sb->curp > sb->sbuf && *(sb->curp - 1) == '\n')
 360                         break;
 361                 else if (feof(ip)) {
 362                         return sb->sbuf;
 363                 }
 364                 __strbuf_expandbuf(sb, EXPANDSIZE);     /* expand buffer */
 365                 if (sb->alloc_failed)
 366                         return sb->sbuf;
 367         }
 368         if (flags & STRBUF_NOCRLF) {
 369                 if (*(sb->curp - 1) == '\n')
 370                         *(--sb->curp) = 0;
 371                 if (sb->curp > sb->sbuf && *(sb->curp - 1) == '\r')
 372                         *(--sb->curp) = 0;
 373         }
 374         return sb->sbuf;
 375 }
 376 /**
 377  * strbuf_sprintf: do @NAME{sprintf} into string buffer.
 378  *
 379  *      @param[in]      sb      #STRBUF structure
 380  *      @param[in]      s       similar to @NAME{sprintf()} <br>
 381  *                      Currently the following format is supported. <br>
 382  *                      @CODE{\%s, \%d, \%\<number\>d, \%\<number\>s, \%-\<number\>d, \%-\<number\>s}
 383  */
 384 void
 385 strbuf_sprintf(STRBUF *sb, const char *s, ...)
 386 {
 387         va_list ap;
 388 
 389         va_start(ap, s);
 390         strbuf_vsprintf(sb, s, ap);
 391         va_end(ap);
 392 }
 393 /**
 394  * strbuf_vsprintf: do @NAME{vsprintf} into string buffer.
 395  *
 396  *      @param[in]      sb      #STRBUF structure
 397  *      @param[in]      s       similar to @NAME{vsprintf()} <br>
 398  *                      Currently the following format is supported. <br>
 399  *                      @CODE{\%s, \%d, \%\<number\>d, \%\<number\>s, \%-\<number\>d, \%-\<number\>s}
 400  *      @param[in]      ap       <br>
 401  */
 402 void
 403 strbuf_vsprintf(STRBUF *sb, const char *s, va_list ap)
 404 {
 405         if (sb->alloc_failed)
 406                 return;
 407         for (; *s; s++) {
 408                 /*
 409                  * Put the before part of '%'.
 410                  */
 411                 {
 412                         const char *p;
 413                         for (p = s; *p && *p != '%'; p++)
 414                                 ;
 415                         if (p > s) {
 416                                 strbuf_nputs(sb, s, p - s);
 417                                 s = p;
 418                         }
 419                 }
 420                 if (*s == '\0')
 421                         break;
 422                 if (*s == '%') {
 423                         int c = (unsigned char)*++s;
 424                         /*
 425                          * '%%' means '%'.
 426                          */
 427                         if (c == '%') {
 428                                 strbuf_putc(sb, c);
 429                         }
 430                         /*
 431                          * If the optional number is specified then
 432                          * we forward the job to snprintf(3).
 433                          * o %<number>d
 434                          * o %<number>s
 435                          * o %-<number>d
 436                          * o %-<number>s
 437                          */
 438                         else if (isdigit(c) || (c == '-' && isdigit((unsigned char)*(s + 1)))) {
 439                                 char format[32], buf[1024];
 440                                 int i = 0;
 441 
 442                                 format[i++] = '%';
 443                                 if (c == '-')
 444                                         format[i++] = *s++;
 445                                 while (isdigit((unsigned char)*s))
 446                                         format[i++] = *s++;
 447                                 format[i++] = c = *s;
 448                                 format[i] = '\0';
 449                                 if (c == 'd' || c == 'x')
 450                                         snprintf(buf, sizeof(buf), format, va_arg(ap, int));
 451                                 else if (c == 's')
 452                                         snprintf(buf, sizeof(buf), format, va_arg(ap, char *));
 453                                 else
 454                                         die("Unsupported control character '%c'.", c);
 455                                 strbuf_puts(sb, buf);
 456                         } else if (c == 's') {
 457                                 strbuf_puts(sb, va_arg(ap, char *));
 458                         } else if (c == 'd') {
 459                                 strbuf_putn(sb, va_arg(ap, int));
 460                         } else {
 461                                 die("Unsupported control character '%c'.", c);
 462                         }
 463                 }
 464         }
 465 }
 466 /**
 467  * strbuf_close: close string buffer.
 468  *
 469  *      @param[in]      sb      #STRBUF structure
 470  */
 471 void
 472 strbuf_close(STRBUF *sb)
 473 {
 474         if (sb->name)
 475                 (void)free(sb->name);
 476         (void)free(sb->sbuf);
 477         (void)free(sb);
 478 }
 479 /**
 480  * @fn STRBUF *strbuf_open_tempbuf(void)
 481  *
 482  * Temporary string buffer for general purpose.
 483  *
 484  * @par Usage:
 485  *
 486  * @code
 487  *      STRBUF *sbt = strbuf_open_tempbuf();
 488  *      ....
 489  *      strbuf_puts(sbtemp, "xxx");
 490  *      ...
 491  *      strbuf_release_tempbuf(sbt);
 492  * @endcode
 493  *
 494  */
 495 static int used = 0;
 496 
 497 STRBUF *
 498 strbuf_open_tempbuf(void)
 499 {
 500         STATIC_STRBUF(sb);
 501         if (used)
 502                 die("Internal error: temporary string buffer is already used.");
 503         used = 1;
 504         strbuf_clear(sb);
 505         return sb;
 506 }
 507 void
 508 strbuf_release_tempbuf(STRBUF *sb)
 509 {
 510         used = 0;
 511 }

/* [previous][next][first][last][top][bottom][index][help] */