From b990f5c31bc831e588a86f9f4826387c6843c989 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Fri, 31 Mar 2006 00:30:21 +0000 Subject: [PATCH] Improve string library. --- src/language/control/repeat.c | 2 +- src/language/data-io/data-reader.c | 2 +- src/language/lexer/lexer.c | 10 +- src/libpspp/ChangeLog | 35 ++ src/libpspp/str.c | 592 +++++++++++++++-------------- src/libpspp/str.h | 49 +-- src/output/ChangeLog | 5 + src/output/output.c | 95 +---- src/output/postscript.c | 4 +- src/ui/terminal/read-line.c | 2 +- 10 files changed, 405 insertions(+), 391 deletions(-) diff --git a/src/language/control/repeat.c b/src/language/control/repeat.c index a71501b7..6cfbb6bb 100644 --- a/src/language/control/repeat.c +++ b/src/language/control/repeat.c @@ -562,7 +562,7 @@ do_repeat_read (struct string *output, char **file_name, int *line_number, } line = block->cur_line; - ds_replace (output, line->line); + ds_assign_c_str (output, line->line); *file_name = line->file_name; *line_number = -line->line_number; block->cur_line = line->next; diff --git a/src/language/data-io/data-reader.c b/src/language/data-io/data-reader.c index c4bdd538..6f717fd2 100644 --- a/src/language/data-io/data-reader.c +++ b/src/language/data-io/data-reader.c @@ -187,7 +187,7 @@ read_inline_record (struct dfm_reader *r) return false; } - ds_replace (&r->line, ds_c_str (&getl_buf)); + ds_assign_string (&r->line, &getl_buf); return true; } diff --git a/src/language/lexer/lexer.c b/src/language/lexer/lexer.c index ec8c4510..3d2e29ac 100644 --- a/src/language/lexer/lexer.c +++ b/src/language/lexer/lexer.c @@ -34,6 +34,8 @@ #include #include +#include "size_max.h" + #include "gettext.h" #define _(msgid) gettext (msgid) #define N_(msgid) msgid @@ -125,7 +127,7 @@ restore_token (void) { assert (put_token != 0); token = put_token; - ds_replace (&tokstr, ds_c_str (&put_tokstr)); + ds_assign_string (&tokstr, &put_tokstr); str_copy_trunc (tokid, sizeof tokid, ds_c_str (&tokstr)); tokval = put_tokval; put_token = 0; @@ -137,7 +139,7 @@ static void save_token (void) { put_token = token; - ds_replace (&put_tokstr, ds_c_str (&tokstr)); + ds_assign_string (&put_tokstr, &tokstr); put_tokval = tokval; } @@ -693,7 +695,7 @@ lex_put_back_id (const char *id) assert (lex_id_to_token (id, strlen (id)) == T_ID); save_token (); token = T_ID; - ds_replace (&tokstr, id); + ds_assign_c_str (&tokstr, id); str_copy_trunc (tokid, sizeof tokid, ds_c_str (&tokstr)); } @@ -930,7 +932,7 @@ lex_negative_to_dash (void) { token = T_POS_NUM; tokval = -tokval; - ds_replace (&tokstr, ds_c_str (&tokstr) + 1); + ds_assign_substring (&tokstr, &tokstr, 1, SIZE_MAX); save_token (); token = '-'; } diff --git a/src/libpspp/ChangeLog b/src/libpspp/ChangeLog index 1902d196..98bd3dd0 100644 --- a/src/libpspp/ChangeLog +++ b/src/libpspp/ChangeLog @@ -1,3 +1,38 @@ +Thu Mar 30 16:15:37 2006 Ben Pfaff + + * str.c: (ds_create) Adjust capacity selection. + (ds_init) Use MAX macro for clarity. + (ds_create_substr) Rewrote. + (ds_replace) Renamed ds_assign_c_str(), reimplemented. Changed + all callers to use a ds_assign_*() function. + (ds_init_substring) New function. + (ds_assign_string) New function. + (ds_assign_substring) New function. + (ds_assign_buffer) New function. + (ds_assign_c_str) New function. + (ds_truncate) Rewrote for clarity. + (ds_rpad) Reimplement in terms of ds_putc_multiple(). + (ds_ltrim_spaces) Reimplement. + (ds_trim_spaces) New function. + (ds_separate) New function. + (ds_c_str) Make tolerant of null pointer, allowing static + initialization of strings. + (ds_find) Rename ds_span(), change interface. + (ds_n_find) Rename ds_cspan(), change interface. + (ds_at) New function. + (ds_first) Reimplement in terms of ds_at(). + (remove_comment) New function. + (ds_get_config_line) Reimplement in terms of other functions. + Change type of LINE_NUMBER parameter. Updated all callers. + (ds_vprintf) Modify for clarity. + (ds_putc) Better to be safe than sorry. + (ds_putc_multiple) New function. + + * str.h: (struct string) Reorder members. + (macro DS_INITIALIZER) New macro that can be used to initialize a + string (as empty). + (ds_c_str) Remove inline version. + Tue Mar 28 13:49:11 WST 2006 John Darrington * str.[ch]: New functions ds_create_substr, ds_find, ds_n_find, diff --git a/src/libpspp/str.c b/src/libpspp/str.c index b8e55344..e84021be 100644 --- a/src/libpspp/str.c +++ b/src/libpspp/str.c @@ -25,6 +25,8 @@ #include #include "alloc.h" #include "message.h" +#include "minmax.h" +#include "size_max.h" /* Reverses the order of NBYTES bytes at address P, thus converting between little- and big-endian byte orders. */ @@ -237,66 +239,31 @@ void ds_create (struct string *st, const char *s) { st->length = strlen (s); - st->capacity = 8 + st->length * 2; + st->capacity = MAX (8, st->length * 2); st->string = xmalloc (st->capacity + 1); strcpy (st->string, s); } -/* Initializes DST with the contents of SRC between characters FIRST and LAST - inclusive */ -void -ds_create_substr(struct string *dst, const struct string *src, - int first, int last) -{ - assert(last >= first); - dst->length = last - first + 1; - dst->capacity = 8 + dst->length * 2; - dst->string = xmalloc (dst->capacity + 1); - - memcpy (dst->string, &src->string[first], dst->length); -} - - /* Initializes ST, making room for at least CAPACITY characters. */ void ds_init (struct string *st, size_t capacity) { st->length = 0; - if (capacity > 8) - st->capacity = capacity; - else - st->capacity = 8; + st->capacity = MAX (8, capacity); st->string = xmalloc (st->capacity + 1); } -/* Replaces the contents of ST with STRING. STRING may overlap with - ST. */ +/* Frees ST. */ void -ds_replace (struct string *st, const char *string) +ds_destroy (struct string *st) { - size_t new_length = strlen (string); - if (new_length > st->capacity) + if (st != NULL) { - /* The new length is longer than the allocated length, so - there can be no overlap. */ + free (st->string); + st->string = NULL; st->length = 0; - ds_concat (st, string, new_length); + st->capacity = 0; } - else - { - /* Overlap is possible, but the new string will fit in the - allocated space, so we can just copy data. */ - st->length = new_length; - memmove (st->string, string, st->length); - } -} - -/* Frees ST. */ -void -ds_destroy (struct string *st) -{ - free (st->string); - st->string = NULL; } /* Swaps the contents of strings A and B. */ @@ -308,6 +275,56 @@ ds_swap (struct string *a, struct string *b) *b = tmp; } +/* Initializes DST with the CNT characters from SRC starting at + position IDX. */ +void +ds_init_substring (struct string *dst, + const struct string *src, size_t idx, size_t cnt) +{ + assert (dst != src); + ds_init (dst, cnt); + ds_assign_substring (dst, src, idx, cnt); +} + +/* Copies SRC into DST. + DST and SRC may be the same string. */ +void +ds_assign_string (struct string *dst, const struct string *src) +{ + ds_assign_buffer (dst, ds_data (src), ds_length (src)); +} + +/* Replaces DST by CNT characters from SRC starting at position + IDX. + DST and SRC may be the same string. */ +void +ds_assign_substring (struct string *dst, + const struct string *src, size_t idx, size_t cnt) +{ + if (idx < src->length) + ds_assign_buffer (dst, src->string + idx, MIN (cnt, src->length - idx)); + else + ds_clear (dst); +} + +/* Replaces DST by the LENGTH characters in SRC. + SRC may be a substring within DST. */ +void +ds_assign_buffer (struct string *dst, const char *src, size_t length) +{ + dst->length = length; + ds_extend (dst, length); + memmove (dst->string, src, length); +} + +/* Replaces DST by null-terminated string SRC. SRC may overlap + with DST. */ +void +ds_assign_c_str (struct string *dst, const char *src) +{ + ds_assign_buffer (dst, src, strlen (src)); +} + /* Truncates ST to zero length. */ void ds_clear (struct string *st) @@ -315,20 +332,48 @@ ds_clear (struct string *st) st->length = 0; } +/* Ensures that ST can hold at least MIN_CAPACITY characters plus a null + terminator. */ +void +ds_extend (struct string *st, size_t min_capacity) +{ + if (min_capacity > st->capacity) + { + st->capacity *= 2; + if (st->capacity < min_capacity) + st->capacity = 2 * min_capacity; + + st->string = xrealloc (st->string, st->capacity + 1); + } +} + +/* Shrink ST to the minimum capacity need to contain its content. */ +void +ds_shrink (struct string *st) +{ + if (st->capacity != st->length) + { + st->capacity = st->length; + st->string = xrealloc (st->string, st->capacity + 1); + } +} + +/* Truncates ST to at most LENGTH characters long. */ +void +ds_truncate (struct string *st, size_t length) +{ + if (st->length > length) + st->length = length; +} + /* Pad ST on the right with copies of PAD until ST is at least LENGTH characters in size. If ST is initially LENGTH characters or longer, this is a no-op. */ void ds_rpad (struct string *st, size_t length, char pad) { - assert (st != NULL); - if (st->length < length) - { - if (st->capacity < length) - ds_extend (st, length); - memset (&st->string[st->length], pad, length - st->length); - st->length = length; - } + if (length > st->length) + ds_putc_multiple (st, pad, length - st->length); } /* Removes trailing spaces from ST. @@ -350,22 +395,21 @@ ds_rtrim_spaces (struct string *st) int ds_ltrim_spaces (struct string *st) { - int idx = ds_n_find(st, "\t "); - if (0 == idx) - return 0; - - if (idx < 0 ) - { - int len = ds_length(st); - ds_clear(st); - return len; - } - - ds_replace(st, &ds_c_str(st)[idx]); - - return idx; + size_t cnt = 0; + while (isspace (ds_at (st, cnt))) + cnt++; + if (cnt > 0) + ds_assign_substring (st, st, cnt, SIZE_MAX); + return cnt; } +/* Trims leading and trailing spaces from ST. */ +void +ds_trim_spaces (struct string *st) +{ + ds_rtrim_spaces (st); + ds_ltrim_spaces (st); +} /* If the last character in ST is C, removes it and returns true. Otherwise, returns false without modifying ST. */ @@ -382,39 +426,42 @@ ds_chomp (struct string *st, char c_) return false; } -/* Ensures that ST can hold at least MIN_CAPACITY characters plus a null - terminator. */ -void -ds_extend (struct string *st, size_t min_capacity) -{ - if (min_capacity > st->capacity) - { - st->capacity *= 2; - if (st->capacity < min_capacity) - st->capacity = min_capacity * 2; - - st->string = xrealloc (st->string, st->capacity + 1); - } -} +/* Divides ST into tokens separated by any of the DELIMITERS. + Each call replaces TOKEN by the next token in ST, or by an + empty string if no tokens remain. Returns true if a token was + obtained, false otherwise. -/* Shrink ST to the minimum capacity need to contain its content. */ -void -ds_shrink (struct string *st) + Before the first call, initialize *SAVE_IDX to -1. Do not + modify *SAVE_IDX between calls. + + ST divides into exactly one more tokens than it contains + delimiters. That is, a delimiter at the start or end of ST or + a pair of adjacent delimiters yields an empty token, and the + empty string contains a single token. */ +bool +ds_separate (const struct string *st, struct string *token, + const char *delimiters, int *save_idx) { - if (st->capacity != st->length) + int start_idx; + + ds_clear (token); + if (*save_idx < 0) { - st->capacity = st->length; - st->string = xrealloc (st->string, st->capacity + 1); + *save_idx = 0; + if (ds_is_empty (st)) + return true; } -} + else if (*save_idx < ds_length (st)) + ++*save_idx; + else + return false; -/* Truncates ST to at most LENGTH characters long. */ -void -ds_truncate (struct string *st, size_t length) -{ - if (length >= st->length) - return; - st->length = length; + start_idx = *save_idx; + while (*save_idx < ds_length (st) + && strchr (delimiters, ds_data (st)[*save_idx]) == NULL) + ++*save_idx; + ds_assign_substring (token, st, start_idx, *save_idx - start_idx); + return true; } /* Returns true if ST is empty, false otherwise. */ @@ -431,72 +478,55 @@ ds_length (const struct string *st) return st->length; } -/* Returns the allocation size of ST. */ -size_t -ds_capacity (const struct string *st) +/* Returns the value of ST as a null-terminated string. */ +char * +ds_c_str (const struct string *st_) { - return st->capacity; + struct string *st = (struct string *) st_; + if (st->string == NULL) + ds_extend (st, 1); + st->string[st->length] = '\0'; + return st->string; } - -/* Returns the index of the first character in ST which - is an element of the set CS. - Returns -1 if no characters are found. -*/ -int -ds_find(const struct string *st, const char cs[]) +/* Returns the string data inside ST. */ +char * +ds_data (const struct string *st) { - int i; - int j; - for(i = 0; i < st->length ; ++i) - { - if ('\0' == st->string[i]) - break; - for (j = 0 ; j < strlen(cs) ; ++j) - { - if ( st->string[i] == cs[j]) - return i; - } - } - return -1; + return st->string; } -/* Returns the index of the first character in ST which - is NOT an element of the set CS. - Returns -1 if no such character is found. -*/ -int -ds_n_find(const struct string *st, const char cs[]) +/* Returns a pointer to the null terminator ST. + This might not be an actual null character unless ds_c_str() has + been called since the last modification to ST. */ +char * +ds_end (const struct string *st) { - int i; - int j; - for(i = 0; i < st->length ; ++i) - { - bool found = false; - if ('\0' == st->string[i]) - break; - for (j = 0 ; j < strlen(cs) ; ++j) - { - if ( st->string[i] == cs[j]) - { - found = true; - break; - } - } - if ( !found ) - return i; - } - return -1; + return st->string + st->length; } +/* Returns the allocation size of ST. */ +size_t +ds_capacity (const struct string *st) +{ + return st->capacity; +} +/* Returns the character in position IDX in ST, as a value in the + range of unsigned char. Returns EOF if IDX is out of the + range of indexes for ST. */ +int +ds_at (const struct string *st, size_t idx) +{ + return idx < st->length ? (unsigned char) st->string[idx] : EOF; +} /* Returns the first character in ST as a value in the range of unsigned char. Returns EOF if ST is the empty string. */ int ds_first (const struct string *st) { - return st->length > 0 ? (unsigned char) st->string[0] : EOF; + return ds_at (st, 0); } /* Returns the last character in ST as a value in the range of @@ -507,28 +537,117 @@ ds_last (const struct string *st) return st->length > 0 ? (unsigned char) st->string[st->length - 1] : EOF; } -/* Returns the value of ST as a null-terminated string. */ -char * -ds_c_str (const struct string *st) +/* Returns the number of consecutive characters starting at OFS + in ST that are in SKIP_SET. (The null terminator is not + considered to be part of SKIP_SET.) */ +size_t +ds_span (const struct string *st, size_t ofs, const char skip_set[]) { - ((char *) st->string)[st->length] = '\0'; - return st->string; + size_t i; + for (i = ofs; i < st->length; i++) + { + int c = st->string[i]; + if (strchr (skip_set, c) == NULL || c == '\0') + break; + } + return i - ofs; } -/* Returns the string data inside ST. */ -char * -ds_data (const struct string *st) +/* Returns the number of consecutive characters starting at OFS + in ST that are not in STOP_SET. (The null terminator is not + considered to be part of STOP_SET.) */ +size_t +ds_cspan (const struct string *st, size_t ofs, const char stop_set[]) { - return st->string; + size_t i; + for (i = ofs; i < st->length; i++) + { + int c = st->string[i]; + if (strchr (stop_set, c) != NULL) + break; + } + return i - ofs; } -/* Returns a pointer to the null terminator ST. - This might not be an actual null character unless ds_c_str() has - been called since the last modification to ST. */ -char * -ds_end (const struct string *st) +/* Appends to ST a newline-terminated line read from STREAM. + Newline is the last character of ST on return, unless an I/O error + or end of file is encountered after reading some characters. + Returns true if a line is successfully read, false if no characters at + all were read before an I/O error or end of file was + encountered. */ +bool +ds_gets (struct string *st, FILE *stream) { - return st->string + st->length; + int c; + + c = getc (stream); + if (c == EOF) + return false; + + for (;;) + { + ds_putc (st, c); + if (c == '\n') + return true; + + c = getc (stream); + if (c == EOF) + return true; + } +} + +/* Removes a comment introduced by `#' from ST, + ignoring occurrences inside quoted strings. */ +static void +remove_comment (struct string *st) +{ + char *cp; + int quote = 0; + + for (cp = ds_c_str (st); cp < ds_end (st); cp++) + if (quote) + { + if (*cp == quote) + quote = 0; + else if (*cp == '\\') + cp++; + } + else if (*cp == '\'' || *cp == '"') + quote = *cp; + else if (*cp == '#') + { + ds_truncate (st, cp - ds_c_str (st)); + break; + } +} + +/* Reads a line from STREAM into ST, then preprocesses as follows: + + - Splices lines terminated with `\'. + + - Deletes comments introduced by `#' outside of single or double + quotes. + + - Deletes trailing white space. + + Returns true if a line was successfully read, false on + failure. If LINE_NUMBER is non-null, then *LINE_NUMBER is + incremented by the number of lines read. */ +bool +ds_get_config_line (FILE *stream, struct string *st, int *line_number) +{ + ds_clear (st); + do + { + if (!ds_gets (st, stream)) + return false; + (*line_number)++; + ds_rtrim_spaces (st); + } + while (ds_chomp (st, '\\')); + + remove_comment (st); + return true; } /* Concatenates S onto ST. */ @@ -554,9 +673,6 @@ ds_concat (struct string *st, const char *buf, size_t len) st->length += len; } -void ds_vprintf (struct string *st, const char *format, va_list args); - - /* Formats FORMAT as a printf string and appends the result to ST. */ void ds_printf (struct string *st, const char *format, ...) @@ -564,48 +680,48 @@ ds_printf (struct string *st, const char *format, ...) va_list args; va_start (args, format); - ds_vprintf(st,format,args); + ds_vprintf(st, format, args); va_end (args); - } /* Formats FORMAT as a printf string and appends the result to ST. */ void -ds_vprintf (struct string *st, const char *format, va_list args) +ds_vprintf (struct string *st, const char *format, va_list args_) { - /* Fscking glibc silently changed behavior between 2.0 and 2.1. - Fsck fsck fsck. Before, it returned -1 on buffer overflow. Now, - it returns the number of characters (not bytes) that would have - been written. */ - int avail, needed; - va_list a1; + va_list args; + +#ifndef va_copy +#define va_copy(DST, SRC) (DST) = (SRC) +#endif - va_copy(a1, args); + va_copy (args, args_); avail = st->capacity - st->length + 1; needed = vsnprintf (st->string + st->length, avail, format, args); - + va_end (args); if (needed >= avail) { ds_extend (st, st->length + needed); - vsprintf (st->string + st->length, format, a1); + va_copy (args, args_); + vsprintf (st->string + st->length, format, args); + va_end (args); } - else - while (needed == -1) - { - va_list a2; - va_copy(a2, a1); - - ds_extend (st, (st->capacity + 1) * 2); - avail = st->capacity - st->length + 1; - - needed = vsnprintf (st->string + st->length, avail, format, a2); - va_end(a2); + else + { + /* Some old libc's returned -1 when the destination string + was too short. */ + while (needed == -1) + { + ds_extend (st, (st->capacity + 1) * 2); + avail = st->capacity - st->length + 1; - } - va_end(a1); + va_copy (args, args_); + needed = vsnprintf (st->string + st->length, avail, format, args); + va_end (args); + } + } st->length += needed; } @@ -614,110 +730,20 @@ ds_vprintf (struct string *st, const char *format, va_list args) void ds_putc (struct string *st, int ch) { - if (st->length == st->capacity) + if (st->length >= st->capacity) ds_extend (st, st->length + 1); st->string[st->length++] = ch; } -/* Appends to ST a newline-terminated line read from STREAM. - Newline is the last character of ST on return, unless an I/O error - or end of file is encountered after reading some characters. - Returns 1 if a line is successfully read, or 0 if no characters at - all were read before an I/O error or end of file was - encountered. */ -int -ds_gets (struct string *st, FILE *stream) +/* Appends CNT copies of character CH to ST. */ +void +ds_putc_multiple (struct string *st, int ch, size_t cnt) { - int c; - - c = getc (stream); - if (c == EOF) - return 0; - - for (;;) - { - ds_putc (st, c); - if (c == '\n') - return 1; - - c = getc (stream); - if (c == EOF) - return 1; - } + ds_extend (st, st->length + cnt); + memset (&st->string[st->length], ch, cnt); + st->length += cnt; } -/* Reads a line from STREAM into ST, then preprocesses as follows: - - - Splices lines terminated with `\'. - - - Deletes comments introduced by `#' outside of single or double - quotes. - - - Trailing whitespace will be deleted. - - Increments cust_ln as appropriate. - - Returns nonzero only if a line was successfully read. */ -int -ds_get_config_line (FILE *stream, struct string *st, struct file_locator *where) -{ - /* Read the first line. */ - ds_clear (st); - where->line_number++; - if (!ds_gets (st, stream)) - return 0; - - /* Read additional lines, if any. */ - for (;;) - { - /* Remove trailing whitespace. */ - { - char *s = ds_c_str (st); - size_t len = ds_length (st); - - while (len > 0 && isspace ((unsigned char) s[len - 1])) - len--; - ds_truncate (st, len); - } - - /* Check for trailing \. Remove if found, bail otherwise. */ - if (ds_length (st) == 0 || ds_c_str (st)[ds_length (st) - 1] != '\\') - break; - ds_truncate (st, ds_length (st) - 1); - - /* Append another line and go around again. */ - { - int success = ds_gets (st, stream); - where->line_number++; - if (!success) - return 1; - } - } - - /* Find a comment and remove. */ - { - char *cp; - int quote = 0; - - for (cp = ds_c_str (st); *cp; cp++) - if (quote) - { - if (*cp == quote) - quote = 0; - else if (*cp == '\\') - cp++; - } - else if (*cp == '\'' || *cp == '"') - quote = *cp; - else if (*cp == '#') - { - ds_truncate (st, cp - ds_c_str (st)); - break; - } - } - - return 1; -} /* Lengthed strings. */ diff --git a/src/libpspp/str.h b/src/libpspp/str.h index c0643263..6f34c200 100644 --- a/src/libpspp/str.h +++ b/src/libpspp/str.h @@ -108,30 +108,43 @@ ls_end (const struct fixed_string *st) struct string { + char *string; /* String data, not necessarily null terminated. */ size_t length; /* Length, not including a null terminator. */ size_t capacity; /* Allocated capacity, not including one extra byte allocated for null terminator. */ - char *string; /* String data, not necessarily null - terminated. */ }; +#define DS_INITIALIZER {NULL, 0, 0} + /* Constructors, destructors. */ -void ds_create (struct string *, const char *); void ds_init (struct string *, size_t); +void ds_init_substring (struct string *, + const struct string *src, size_t start, size_t cnt); +void ds_create (struct string *, const char *); void ds_destroy (struct string *); void ds_swap (struct string *, struct string *); -/* Copy, shrink, extend. */ -void ds_replace (struct string *, const char *); +/* Replacement. */ +void ds_assign_string (struct string *, const struct string *); +void ds_assign_substring (struct string *, + const struct string *, size_t start, size_t cnt); +void ds_assign_buffer (struct string *, const char *, size_t); +void ds_assign_c_str (struct string *, const char *); + +/* Shrink, extend. */ void ds_clear (struct string *); void ds_extend (struct string *, size_t); void ds_shrink (struct string *); void ds_truncate (struct string *, size_t); + +/* Padding, trimming. */ void ds_rpad (struct string *, size_t length, char pad); int ds_rtrim_spaces (struct string *); -int ds_ltrim_spaces (struct string *st); - +int ds_ltrim_spaces (struct string *); +void ds_trim_spaces (struct string *); bool ds_chomp (struct string *, char); +bool ds_separate (const struct string *src, struct string *token, + const char *delimiters, int *save_idx); /* Inspectors. */ bool ds_is_empty (const struct string *); @@ -140,16 +153,19 @@ char *ds_c_str (const struct string *); char *ds_data (const struct string *); char *ds_end (const struct string *); size_t ds_capacity (const struct string *); +int ds_at (const struct string *, size_t idx); int ds_first (const struct string *); int ds_last (const struct string *); +size_t ds_span (const struct string *st, size_t ofs, const char skip_set[]); +size_t ds_cspan (const struct string *st, size_t ofs, const char stop_set[]); /* File input. */ -struct file_locator; -int ds_gets (struct string *, FILE *); -int ds_get_config_line (FILE *, struct string *, struct file_locator *); +bool ds_gets (struct string *, FILE *); +bool ds_get_config_line (FILE *, struct string *, int *line_number); /* Append. */ void ds_putc (struct string *, int ch); +void ds_putc_multiple (struct string *, int ch, size_t); void ds_puts (struct string *, const char *); void ds_concat (struct string *, const char *, size_t); void ds_vprintf (struct string *st, const char *, va_list); @@ -171,14 +187,6 @@ ds_length (const struct string *st) return st->length; } -extern inline char * -ds_c_str (const struct string *st) -{ - assert(st); - ((char *) st->string)[st->length] = '\0'; - return st->string; -} - extern inline char * ds_data (const struct string *st) { @@ -210,12 +218,7 @@ spprintf (char *dst, const char *format, ...) return dst + count; } -int ds_find(const struct string *st, const char cs[]); - -int ds_n_find(const struct string *st, const char cs[]); -void ds_create_substr(struct string *dst, const struct string *src, - int first, int last); #endif /* str_h */ diff --git a/src/output/ChangeLog b/src/output/ChangeLog index 0560dd88..7af231d1 100644 --- a/src/output/ChangeLog +++ b/src/output/ChangeLog @@ -1,3 +1,8 @@ +Thu Mar 30 16:26:56 2006 Ben Pfaff + + * output.c: (colon_tokenize) Removed. + (configure_driver_line) Rewrote to use ds_separate(). Fixed leak. + Tue Mar 28 13:50:53 WST 2006 John Darrington * html.c, postscript.c, output.c: Changed to fit the new signature diff --git a/src/output/output.c b/src/output/output.c index 716f7c10..0390e1af 100644 --- a/src/output/output.c +++ b/src/output/output.c @@ -302,7 +302,7 @@ outp_read_devices (void) { char *cp; - if (!ds_get_config_line (f, &line, &where)) + if (!ds_get_config_line (f, &line, &where.line_number)) { if (ferror (f)) msg (ME, _("Reading %s: %s."), init_fn, strerror (errno)); @@ -664,58 +664,6 @@ find_driver (char *name) return NULL; } -/* Tokenize string SRC into colon-separated fields, removing leading and - trailing whitespace on tokens. Tokens are placed into DEST. - - CP should remain unchanged throughout. - It is the callers responsibility to destroy CP and DEST. - - - Returns true if there are more fields, false otherwise. - - FIXME: Should ignore colons inside double quotes. */ -static bool -colon_tokenize(const struct string *src, struct string *dest, - struct string *cp) -{ - int last; - - if ( src ) - ds_create(cp, ds_c_str(src)); - - int first = ds_n_find(cp, "\t "); - int delim = ds_find(cp, ":") ; - - if ( delim < 0 ) - last = ds_length(cp); - else - last = delim - 1; - - if ( delim == first) - { - ds_create(dest,""); - } - else - { - ds_create_substr(dest, cp, first, last); - } - - if ( last < ds_length(cp) ) - { - struct string temp; - ds_create_substr(&temp, cp, last + 2, ds_length(cp)); - ds_swap(cp, &temp); - ds_destroy(&temp); - return true; - } - else - { - ds_clear(cp); - return false; - } -} - - /* String S is in format: DRIVERNAME:CLASSNAME:DEVICETYPE:OPTIONS Adds a driver to outp_driver_list pursuant to the specification @@ -821,34 +769,29 @@ error: static void configure_driver_line (struct string *line) { - fn_interp_vars(line, find_defn_value); + struct string tokens[4]; + int save_idx; + size_t i; - struct string driver_name; - struct string class_name; - struct string device_type; - struct string options; + fn_interp_vars (line, find_defn_value); - struct string sss; - colon_tokenize (line, &driver_name, &sss); - colon_tokenize (NULL, &class_name, &sss); - colon_tokenize (NULL, &device_type, &sss); - colon_tokenize (NULL, &options, &sss); - - if (ds_is_empty(&driver_name) || ds_is_empty(&class_name)) + save_idx = -1; + for (i = 0; i < 4; i++) { - msg (IS, _("Driver definition line contains fewer fields " - "than expected")); - return; + struct string *token = &tokens[i]; + ds_init (token, 0); + ds_separate (line, token, i < 3 ? ":" : "", &save_idx); + ds_trim_spaces (token); } - configure_driver (ds_c_str(&driver_name), ds_c_str(&class_name), - ds_c_str(&device_type), ds_c_str(&options)); + if (!ds_is_empty (&tokens[0]) && !ds_is_empty (&tokens[1])) + configure_driver (ds_c_str (&tokens[0]), ds_c_str (&tokens[1]), + ds_c_str (&tokens[2]), ds_c_str (&tokens[3])); + else + msg (IS, _("Driver definition line missing driver name or class name")); - ds_destroy(&driver_name); - ds_destroy(&class_name); - ds_destroy(&device_type); - ds_destroy(&options); - ds_destroy(&sss); + for (i = 0; i < 4; i++) + ds_destroy (&tokens[i]); } /* Destroys output driver D. */ @@ -1210,7 +1153,7 @@ outp_get_paper_size (char *size, int *h, int *v) { char *cp, *bp, *ep; - if (!ds_get_config_line (f, &line, &where)) + if (!ds_get_config_line (f, &line, &where.line_number)) { if (ferror (f)) msg (ME, _("Reading %s: %s."), pprsz_fn, strerror (errno)); diff --git a/src/output/postscript.c b/src/output/postscript.c index 5d0d5776..b26676a9 100644 --- a/src/output/postscript.c +++ b/src/output/postscript.c @@ -935,7 +935,7 @@ output_encodings (struct outp_driver *this) where.line_number = 0; err_push_file_locator (&where); - while (ds_get_config_line (f, &buf, &where)) + while (ds_get_config_line (f, &buf, &where.line_number)) { char *sp; @@ -1104,7 +1104,7 @@ read_ps_encodings (struct outp_driver *this) for (;;) { - if (!ds_get_config_line (f, &line, &where)) + if (!ds_get_config_line (f, &line, &where.line_number)) { if (ferror (f)) msg (ME, _("Reading %s: %s."), encoding_fn, strerror (errno)); diff --git a/src/ui/terminal/read-line.c b/src/ui/terminal/read-line.c index e9211351..7122b78d 100644 --- a/src/ui/terminal/read-line.c +++ b/src/ui/terminal/read-line.c @@ -130,7 +130,7 @@ readln_read (struct string *line, const char *prompt) { if (string[0]) add_history (string); - ds_replace (line, string); + ds_assign_c_str (line, string); free (string); return true; } -- 2.30.2