/* * Copyright (c) 1997, 1998, 1999, 2000, 2002, 2005, 2006 * Tama Communications Corporation * * This file is part of GNU GLOBAL. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifdef HAVE_CONFIG_H #include #endif #include #ifdef STDC_HEADERS #include #endif #ifdef HAVE_STRING_H #include #else #include #endif #include "checkalloc.h" #include "die.h" #include "strbuf.h" #ifndef isblank #define isblank(c) ((c) == ' ' || (c) == '\t') #endif /* String buffer: usage and memory status [xxx]: string buffer 'v': current pointer Function call Memory status ---------------------------------------------------------- (not exist) v sb = strbuf_open(0); [] v strbuf_putc(sb, 'a'); [a] v char *s = strbuf_value(sb); [a\0] s == "a" v strbuf_puts(sb, "bc"); [abc] v char *s = strbuf_value(sb); [abc\0] s == "abc" v int len = strbuf_getlen(sb); [abc\0] len == 3 v strbuf_reset(sb); [abc\0] v int len = strbuf_getlen(sb); [abc\0] len == 0 v strbuf_puts(sb, "XY"); [XYc\0] v char *s = strbuf_value(sb); [XY\0] s == "XY" fp = fopen("/etc/passwd", "r"); v char *s = strbuf_fgets(sb, fp, 0) [root:*:0:0:Charlie &:/root:/bin/csh\0] fclose(fp) s == "root:*:0:0:Charlie &:/root:/bin/csh" strbuf_close(sb); (not exist) */ static void print_and_abort (void); void (*strbuf_alloc_failed_handler) (void) = print_and_abort; static void print_and_abort(void) { die("short of memory."); } /* * __strbuf_expandbuf: expand buffer so that afford to the length data at least. * * i) sb STRBUF structure * i) length required room */ void __strbuf_expandbuf(STRBUF *sb, int length) { int count = sb->curp - sb->sbuf; int newsize = sb->sbufsize + (length > EXPANDSIZE ? length : EXPANDSIZE); char *newbuf; if (sb->alloc_failed) return; newbuf = (char *)check_realloc(sb->sbuf, newsize + 1); sb->sbufsize = newsize; sb->sbuf = newbuf; sb->curp = sb->sbuf + count; sb->endp = sb->sbuf + sb->sbufsize; } /* * strbuf_open: open string buffer. * * i) init initial buffer size * if 0 is specified then use default value. * r) sb STRBUF structure */ STRBUF * strbuf_open(int init) { STRBUF *sb = (STRBUF *)check_calloc(sizeof(STRBUF), 1); sb->sbufsize = (init > 0) ? init : INITIALSIZE; sb->sbuf = (char *)check_malloc(sb->sbufsize + 1); sb->curp = sb->sbuf; sb->endp = sb->sbuf + sb->sbufsize; return sb; } /* * strbuf_reset: reset string buffer. * * i) sb string buffer */ void strbuf_reset(STRBUF *sb) { sb->curp = sb->sbuf; sb->alloc_failed = 0; } /* * strbuf_clear: clear static string buffer. * * i) sb statically defined string buffer * * This function is used for the initializing of static string buffer. * For the detail, see 'STATIC_STRBUF(sb)' macro in strbuf.h. */ void strbuf_clear(STRBUF *sb) { if (sb == NULL) die("NULL string buffer. (strbuf_clear)"); if (strbuf_empty(sb)) { sb->sbufsize = INITIALSIZE; sb->sbuf = (char *)check_malloc(sb->sbufsize + 1); sb->curp = sb->sbuf; sb->endp = sb->sbuf + sb->sbufsize; } else { strbuf_reset(sb); } } /* * strbuf_nputs: Put string with length * * i) sb string buffer * i) s string * i) len length of string */ void strbuf_nputs(STRBUF *sb, const char *s, int len) { if (!sb->alloc_failed && len > 0) { if (sb->curp + len > sb->endp) __strbuf_expandbuf(sb, len); while (len-- > 0) *sb->curp++ = *s++; } } /* * strbuf_nputc: Put characters with length * * i) sb string buffer * i) c character * i) len length of string */ void strbuf_nputc(STRBUF *sb, int c, int len) { if (!sb->alloc_failed && len > 0) { if (sb->curp + len > sb->endp) __strbuf_expandbuf(sb, len); while (len-- > 0) *sb->curp++ = c; } } /* * strbuf_puts: Put string * * i) sb string buffer * i) s string */ void strbuf_puts(STRBUF *sb, const char *s) { if (!sb->alloc_failed) { while (*s) { if (sb->curp >= sb->endp) __strbuf_expandbuf(sb, 0); *sb->curp++ = *s++; } } } /* * strbuf_puts_nl: Put string with a new line * * i) sb string buffer * i) s string */ void strbuf_puts_nl(STRBUF *sb, const char *s) { if (!sb->alloc_failed) { while (*s) { if (sb->curp >= sb->endp) __strbuf_expandbuf(sb, 0); *sb->curp++ = *s++; } if (sb->curp >= sb->endp) __strbuf_expandbuf(sb, 0); *sb->curp++ = '\n'; } } /* * strbuf_putn: put digit string at the last of buffer. * * i) sb STRBUF structure * i) n number */ void strbuf_putn(STRBUF *sb, int n) { if (n == 0) { strbuf_putc(sb, '0'); } else { char num[128]; int i = 0; while (n) { if (i >= sizeof(num)) die("Too big integer value."); num[i++] = n % 10 + '0'; n = n / 10; } while (--i >= 0) strbuf_putc(sb, num[i]); } } /* * strbuf_unputc: remove specified char from the last of buffer * * i) sb STRBUF structure * i) c character * r) 0: do nothing, 1: removed */ int strbuf_unputc(STRBUF *sb, int c) { if (sb->curp > sb->sbuf && *(sb->curp - 1) == c) { sb->curp--; return 1; } return 0; } /* * strbuf_value: return the content of string buffer. * * i) sb STRBUF structure * r) string */ char * strbuf_value(STRBUF *sb) { *sb->curp = 0; return sb->sbuf; } /* * strbuf_trim: trim following blanks. * * i) sb STRBUF structure */ void strbuf_trim(STRBUF *sb) { char *p = sb->curp; while (p > sb->sbuf && isblank(*(p - 1))) *--p = 0; sb->curp = p; } /* * strbuf_fgets: read whole record into string buffer * * o) sb string buffer * i) ip input stream * i) flags flags * STRBUF_NOCRLF remove last '\n' if exist. * STRBUF_APPEND append next record to existing data * r) record buffer (NULL at end of file) * * Returned buffer has whole record. * The buffer end with '\0'.If STRBUF_NOCRLF is set then buffer doesn't * include '\r' and '\n'. */ char * strbuf_fgets(STRBUF *sb, FILE *ip, int flags) { if (!(flags & STRBUF_APPEND)) strbuf_reset(sb); if (sb->curp >= sb->endp) __strbuf_expandbuf(sb, EXPANDSIZE); /* expand buffer */ if (sb->alloc_failed) return sb->sbuf; for (;;) { if (!fgets(sb->curp, sb->endp - sb->curp, ip)) { if (sb->curp == sb->sbuf) return NULL; break; } sb->curp += strlen(sb->curp); if (sb->curp > sb->sbuf && *(sb->curp - 1) == '\n') break; else if (feof(ip)) { return sb->sbuf; } __strbuf_expandbuf(sb, EXPANDSIZE); /* expand buffer */ if (sb->alloc_failed) return sb->sbuf; } if (flags & STRBUF_NOCRLF) { if (*(sb->curp - 1) == '\n') *(--sb->curp) = 0; if (sb->curp > sb->sbuf && *(sb->curp - 1) == '\r') *(--sb->curp) = 0; } return sb->sbuf; } /* * strbuf_sprintf: do sprintf into string buffer. * * i) sb STRBUF structure * i) s similar to sprintf() * Currently the following format is supported. * %s, %d, %d, %s, %-d, %-s */ void strbuf_sprintf(STRBUF *sb, const char *s, ...) { va_list ap; va_start(ap, s); if (sb->alloc_failed) return; for (; *s; s++) { /* * Put the before part of '%'. */ { const char *p; for (p = s; *p && *p != '%'; p++) ; if (p > s) { strbuf_nputs(sb, s, p - s); s = p; } } if (*s == '\0') break; if (*s == '%') { int c = (unsigned char)*++s; /* * '%%' means '%'. */ if (c == '%') { strbuf_putc(sb, c); } /* * If the optional number is specified then * we forward the job to snprintf(3). * o %d * o %s * o %-d * o %-s */ else if (isdigit(c) || (c == '-' && isdigit((unsigned char)*(s + 1)))) { char format[32], buf[1024]; int i = 0; format[i++] = '%'; if (c == '-') format[i++] = *s++; while (isdigit((unsigned char)*s)) format[i++] = *s++; format[i++] = c = *s; format[i] = '\0'; if (c == 'd' || c == 'x') snprintf(buf, sizeof(buf), format, va_arg(ap, int)); else if (c == 's') snprintf(buf, sizeof(buf), format, va_arg(ap, char *)); else die("Unsupported control character '%c'.", c); strbuf_puts(sb, buf); } else if (c == 's') { strbuf_puts(sb, va_arg(ap, char *)); } else if (c == 'd') { strbuf_putn(sb, va_arg(ap, int)); } else { die("Unsupported control character '%c'.", c); } } } va_end(ap); } /* * strbuf_close: close string buffer. * * i) sb STRBUF structure */ void strbuf_close(STRBUF *sb) { if (sb->name) (void)free(sb->name); (void)free(sb->sbuf); (void)free(sb); } /* * Temporary string buffer for general purpose. * * Usage: * * STRBUF *sbt = strbuf_open_tempbuf(); * .... * strbuf_puts(sbtemp, "xxx"); * ... * strbuf_release_tempbuf(sbt); * */ int used = 0; STRBUF * strbuf_open_tempbuf(void) { STATIC_STRBUF(sb); if (used) die("Internal error: temporary string buffer is already used."); used = 1; strbuf_clear(sb); return sb; } void strbuf_release_tempbuf(STRBUF *sb) { used = 0; }