/* PSPP - a program for statistical analysis.
- Copyright (C) 1997-9, 2000, 2006, 2009 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2006, 2009, 2010 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
#include <stdint.h>
#include <stdlib.h>
+#include <libpspp/cast.h>
#include <libpspp/message.h>
#include <libpspp/pool.h>
#include <relocatable.h>
#include "minmax.h"
#include "xalloc.h"
+#include "xmemdup0.h"
#include "xsize.h"
\f
/* Reverses the order of NBYTES bytes at address P, thus converting
}
}
-/* Finds the last NEEDLE of length NEEDLE_LEN in a HAYSTACK of length
- HAYSTACK_LEN. Returns a pointer to the needle found. */
-char *
-buf_find_reverse (const char *haystack, size_t haystack_len,
- const char *needle, size_t needle_len)
-{
- int i;
- for (i = haystack_len - needle_len; i >= 0; i--)
- if (!memcmp (needle, &haystack[i], needle_len))
- return (char *) &haystack[i];
- return 0;
-}
-
/* Compares the SIZE bytes in A to those in B, disregarding case,
and returns a strcmp()-type result. */
int
return true;
}
-/* Formats FORMAT into DST, as with sprintf(), and returns the
- address of the terminating null written to DST. */
-char *
-spprintf (char *dst, const char *format, ...)
-{
- va_list args;
- int count;
-
- va_start (args, format);
- count = vsprintf (dst, format, args);
- va_end (args);
-
- return dst + count;
-}
-
/* Sets the SIZE bytes starting at BLOCK to C,
and returns the byte following BLOCK. */
void *
\f
/* Substrings. */
-/* Returns an empty substring. */
-struct substring
-ss_empty (void)
-{
- struct substring ss;
- ss.string = NULL;
- ss.length = 0;
- return ss;
-}
-
-/* Returns a substring whose contents are the given C-style
- string CSTR. */
-struct substring
-ss_cstr (const char *cstr)
-{
- return ss_buffer (cstr, strlen (cstr));
-}
-
-/* Returns a substring whose contents are the CNT characters in
- BUFFER. */
-struct substring
-ss_buffer (const char *buffer, size_t cnt)
-{
- struct substring ss;
- ss.string = (char *) buffer;
- ss.length = cnt;
- return ss;
-}
-
/* Returns a substring whose contents are the CNT characters
starting at the (0-based) position START in SS. */
struct substring
return ss;
}
-/* Makes a malloc()'d copy of the contents of OLD
+/* Makes a malloc()'d, null-terminated copy of the contents of OLD
and stores it in NEW. */
void
ss_alloc_substring (struct substring *new, struct substring old)
{
- new->string = xmalloc (old.length);
+ new->string = xmemdup0 (old.string, old.length);
new->length = old.length;
- memcpy (new->string, old.string, old.length);
}
/* Allocates room for a CNT-character string in NEW. */
char *
ds_cstr (const struct string *st_)
{
- struct string *st = (struct string *) st_;
+ struct string *st = CONST_CAST (struct string *, st_);
if (st->ss.string == NULL)
ds_extend (st, 1);
st->ss.string[st->ss.length] = '\0';
return st->ss.string;
}
+/* Returns the value of ST as a null-terminated string and then
+ reinitialized ST as an empty string. The caller must free the
+ returned string with free(). */
+char *
+ds_steal_cstr (struct string *st)
+{
+ char *s = ds_cstr (st);
+ ds_init_empty (st);
+ return s;
+}
+
/* 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
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. */
+ This function treats LF and CR LF sequences as new-line,
+ translating each of them to a single '\n' new-line character
+ in ST. */
bool
ds_read_line (struct string *st, FILE *stream, size_t max_length)
{
for (length = 0; length < max_length; length++)
{
int c = getc (stream);
- if (c == EOF)
- break;
-
- if (c == '\r')
+ switch (c)
{
+ case EOF:
+ return length > 0;
+
+ case '\n':
+ ds_put_char (st, c);
+ return true;
+
+ case '\r':
c = getc (stream);
- if (c != '\n')
+ if (c == '\n')
+ {
+ /* CR followed by LF is special: translate to \n. */
+ ds_put_char (st, '\n');
+ return true;
+ }
+ else
{
+ /* CR followed by anything else is just CR. */
+ ds_put_char (st, '\r');
+ if (c == EOF)
+ return true;
ungetc (c, stream);
- c = '\n';
}
+ break;
+
+ default:
+ ds_put_char (st, c);
}
- ds_put_char (st, c);
- if (c == '\n')
- return true;
}
return length > 0;
{
ds_clear (st);
ds_put_cstr (st, rel);
- free ((char *) rel);
+ /* The documentation for relocate says that casting away const
+ and then freeing is appropriate ... */
+ free (CONST_CAST (char *, rel));
}
}