X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Flibpspp%2Fstr.c;h=44d325e072df297eb80977d1f03abd45af6bd543;hb=5c3291dc396b795696e94f47780308fd7ace6fc4;hp=13c081dda71e0122d4fac98f2f62053fee4d44e2;hpb=9f087e7aa4cdff1d5d46d5e188c0017a9d2d0029;p=pspp-builds.git diff --git a/src/libpspp/str.c b/src/libpspp/str.c index 13c081dd..44d325e0 100644 --- a/src/libpspp/str.c +++ b/src/libpspp/str.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 2006, 2009 Free Software Foundation, Inc. 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 @@ -19,14 +19,15 @@ #include "str.h" #include -#include +#include +#include #include #include #include +#include #include "minmax.h" -#include "size_max.h" #include "xalloc.h" #include "xsize.h" @@ -124,9 +125,9 @@ str_compare_rpad (const char *a, const char *b) /* Copies string SRC to buffer DST, of size DST_SIZE bytes. DST is truncated to DST_SIZE bytes or padded on the right with - spaces as needed. */ + copies of PAD as needed. */ void -buf_copy_str_rpad (char *dst, size_t dst_size, const char *src) +buf_copy_str_rpad (char *dst, size_t dst_size, const char *src, char pad) { size_t src_len = strlen (src); if (src_len >= dst_size) @@ -134,15 +135,15 @@ buf_copy_str_rpad (char *dst, size_t dst_size, const char *src) else { memcpy (dst, src, src_len); - memset (&dst[src_len], ' ', dst_size - src_len); + memset (&dst[src_len], pad, dst_size - src_len); } } /* Copies string SRC to buffer DST, of size DST_SIZE bytes. DST is truncated to DST_SIZE bytes or padded on the left with - spaces as needed. */ + copies of PAD as needed. */ void -buf_copy_str_lpad (char *dst, size_t dst_size, const char *src) +buf_copy_str_lpad (char *dst, size_t dst_size, const char *src, char pad) { size_t src_len = strlen (src); if (src_len >= dst_size) @@ -150,40 +151,42 @@ buf_copy_str_lpad (char *dst, size_t dst_size, const char *src) else { size_t pad_cnt = dst_size - src_len; - memset (&dst[0], ' ', pad_cnt); + memset (&dst[0], pad, pad_cnt); memcpy (dst + pad_cnt, src, src_len); } } /* Copies buffer SRC, of SRC_SIZE bytes, to DST, of DST_SIZE bytes. DST is truncated to DST_SIZE bytes or padded on the left with - spaces as needed. */ + copies of PAD as needed. */ void buf_copy_lpad (char *dst, size_t dst_size, - const char *src, size_t src_size) + const char *src, size_t src_size, + char pad) { if (src_size >= dst_size) memmove (dst, src, dst_size); else { - memset (dst, ' ', dst_size - src_size); + memset (dst, pad, dst_size - src_size); memmove (&dst[dst_size - src_size], src, src_size); } } /* Copies buffer SRC, of SRC_SIZE bytes, to DST, of DST_SIZE bytes. DST is truncated to DST_SIZE bytes or padded on the right with - spaces as needed. */ + copies of PAD as needed. */ void buf_copy_rpad (char *dst, size_t dst_size, - const char *src, size_t src_size) + const char *src, size_t src_size, + char pad) { if (src_size >= dst_size) memmove (dst, src, dst_size); else { memmove (dst, src, src_size); - memset (&dst[src_size], ' ', dst_size - src_size); + memset (&dst[src_size], pad, dst_size - src_size); } } @@ -194,15 +197,18 @@ buf_copy_rpad (char *dst, size_t dst_size, void str_copy_rpad (char *dst, size_t dst_size, const char *src) { - size_t src_len = strlen (src); - if (src_len < dst_size - 1) + if (dst_size > 0) { - memcpy (dst, src, src_len); - memset (&dst[src_len], ' ', dst_size - 1 - src_len); + size_t src_len = strlen (src); + if (src_len < dst_size - 1) + { + memcpy (dst, src, src_len); + memset (&dst[src_len], ' ', dst_size - 1 - src_len); + } + else + memcpy (dst, src, dst_size - 1); + dst[dst_size - 1] = 0; } - else - memcpy (dst, src, dst_size - 1); - dst[dst_size - 1] = 0; } /* Copies SRC to DST, which is in a buffer DST_SIZE bytes long. @@ -252,6 +258,41 @@ str_lowercase (char *s) *s = tolower ((unsigned char) *s); } +/* Converts NUMBER into a string in 26-adic notation in BUFFER, + which has room for SIZE bytes. Returns true if successful, + false if NUMBER, plus a trailing null, is too large to fit in + the available space. + + 26-adic notation is "spreadsheet column numbering": 1 = A, 2 = + B, 3 = C, ... 26 = Z, 27 = AA, 28 = AB, 29 = AC, ... + + 26-adic notation is the special case of a k-adic numeration + system (aka bijective base-k numeration) with k=26. In k-adic + numeration, the digits are {1, 2, 3, ..., k} (there is no + digit 0), and integer 0 is represented by the empty string. + For more information, see + http://en.wikipedia.org/wiki/Bijective_numeration. */ +bool +str_format_26adic (unsigned long int number, char buffer[], size_t size) +{ + size_t length = 0; + + while (number-- > 0) + { + if (length >= size) + return false; + buffer[length++] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"[number % 26]; + number /= 26; + } + + if (length >= size) + return false; + buffer[length] = '\0'; + + buf_reverse (buffer, length); + return true; +} + /* Formats FORMAT into DST, as with sprintf(), and returns the address of the terminating null written to DST. */ char * @@ -511,6 +552,23 @@ ss_match_char (struct substring *ss, char c) return false; } +/* If the first character in SS is in MATCH, removes it and + returns the character that was removed. + Otherwise, returns EOF without changing the string. */ +int +ss_match_char_in (struct substring *ss, struct substring match) +{ + int c = EOF; + if (ss->length > 0 + && memchr (match.string, ss->string[0], match.length) != NULL) + { + c = ss->string[0]; + ss->string++; + ss->length--; + } + return c; +} + /* If SS begins with TARGET, removes it and returns true. Otherwise, returns false without changing SS. */ bool @@ -1135,31 +1193,42 @@ ds_cstr (const struct string *st_) return st->ss.string; } -/* 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. */ +/* Reads characters from STREAM and appends them to ST, stopping + after MAX_LENGTH characters, after appending a newline, or + after an I/O error or end of file was encountered, whichever + comes first. Returns true if at least one character was added + to ST, false if no characters were read before an I/O error or + end of file (or if MAX_LENGTH was 0). + + This function accepts LF, CR LF, and CR sequences as new-line, + and translates each of them to a single '\n' new-line + character in ST. */ bool -ds_read_line (struct string *st, FILE *stream) +ds_read_line (struct string *st, FILE *stream, size_t max_length) { - int c; - - c = getc (stream); - if (c == EOF) - return false; + size_t length; - for (;;) + for (length = 0; length < max_length; length++) { + int c = getc (stream); + if (c == EOF) + break; + + if (c == '\r') + { + c = getc (stream); + if (c != '\n') + { + ungetc (c, stream); + c = '\n'; + } + } ds_put_char (st, c); if (c == '\n') - return true; - - c = getc (stream); - if (c == EOF) - return true; + return true; } + + return length > 0; } /* Removes a comment introduced by `#' from ST, @@ -1205,7 +1274,7 @@ ds_read_config_line (struct string *st, int *line_number, FILE *stream) ds_clear (st); do { - if (!ds_read_line (st, stream)) + if (!ds_read_line (st, stream, SIZE_MAX)) return false; (*line_number)++; ds_rtrim (st, ss_cstr (CC_SPACES)); @@ -1218,8 +1287,8 @@ ds_read_config_line (struct string *st, int *line_number, FILE *stream) /* Attempts to read SIZE * CNT bytes from STREAM and append them to ST. - Returns number of bytes actually read. */ -size_t + Returns true if all the requested data was read, false otherwise. */ +bool ds_read_stream (struct string *st, size_t size, size_t cnt, FILE *stream) { if (size != 0) @@ -1228,12 +1297,18 @@ ds_read_stream (struct string *st, size_t size, size_t cnt, FILE *stream) if (size_in_bounds_p (xsum (ds_length (st), try_bytes))) { char *buffer = ds_put_uninit (st, try_bytes); - size_t got_bytes = fread (buffer, size, cnt, stream); + size_t got_bytes = fread (buffer, 1, try_bytes, stream); ds_truncate (st, ds_length (st) - (try_bytes - got_bytes)); - return got_bytes; + return got_bytes == try_bytes; + } + else + { + errno = ENOMEM; + return false; } } - return 0; + else + return true; } /* Concatenates S onto ST. */ @@ -1321,3 +1396,20 @@ ds_put_char_multiple (struct string *st, int ch, size_t cnt) { memset (ds_put_uninit (st, cnt), ch, cnt); } + + +/* If relocation has been enabled, replace ST, + with its relocated version */ +void +ds_relocate (struct string *st) +{ + const char *orig = ds_cstr (st); + const char *rel = relocate (orig); + + if ( orig != rel) + { + ds_clear (st); + ds_put_cstr (st, rel); + free ((char *) rel); + } +}