1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
|
/*
Comma separated value database format scanner
This function implements a somewhat extended flavour
of CSV. In addition to the standard quoted fields,
permitting embedded commas, with embedded quotes
represented as "", backslash escaped characters
expressed as three octal digits are also permitted,
with a double backslash representing an embedded
backslash. This is necessary to permit fields
which include end-of-line delimiters which would
otherwise truncate the record when it is read.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "csv.h"
#define BufferInitial 256 /* Initial buffer size */
#define BufferExpansion 1024 /* Buffer expansion increment */
#define EOS '\0'
#define FALSE 0
#define TRUE 1
static const char *csptr; /* CSV scan pointer */
/* CSVSCANINIT -- Initialise scanning of a CSV record. */
void CSVscanInit(const char *s)
{
csptr = s;
}
/* CSVSCANFIELD -- Scan next field from a CSV record. The actual
length of the field is placed in the
global variable CSVfieldLength. If the
field is not quoted, leading and trailing
spaces are discarded.
The argument b_f is a pointer to a
*/
int CSVfieldLength = 0; /* Length of CSV field scanned */
#define f (*b_f)
#define flen (*b_flen)
static void expand_buf(char **b_f, int *b_flen)
{
if ((f == NULL) || (flen == 0)) {
f = (char *) malloc(BufferInitial);
if (f == NULL) {
fprintf(stderr, "Unable to allocate %d byte CSV field buffer.\n", BufferInitial);
abort();
}
flen = BufferInitial;
} else {
flen += BufferExpansion;
f = (char *) realloc(f, flen);
if (f == NULL) {
fprintf(stderr, "Unable to expand CSV field buffer to %d bytes.\n", flen);
abort();
}
}
}
#define store(c) if (CSVfieldLength >= (flen - 1)) \
{ expand_buf(b_f, b_flen); } \
f[CSVfieldLength] = c; \
CSVfieldLength++;
int CSVscanField(char **b_f, int *b_flen)
{
int foundfield = FALSE, quoted = FALSE;
CSVfieldLength = 0;
if (*csptr != EOS) {
foundfield = TRUE;
while ((*csptr != EOS) && isspace(*csptr)) {
csptr++;
}
if (*csptr == '"') {
quoted = TRUE;
csptr++;
while (*csptr != EOS) {
if (*csptr == '"') {
if (csptr[1] == '"') {
store('"');
csptr += 2;
} else {
csptr++;
break;
}
} else if (*csptr == '\\') {
if (csptr[1] == '\\') {
store('\\');
csptr += 2;
} else {
unsigned int v = 0;
int i;
for (i = 0; i < 3; i++) {
csptr++;
if ((*csptr >= '0') && (*csptr <= '7')) {
v = (v << 3) | (*csptr - '0');
} else {
csptr--;
}
}
csptr++;
store((char) v);
}
} else {
char c = *csptr++;
store(c);
}
}
}
while (*csptr != ',' && *csptr != EOS) {
char c = *csptr++;
store(c);
}
if (*csptr == ',') {
csptr++;
}
}
f[CSVfieldLength] = EOS; /* Append C string terminator */
/* If the field wasn't quoted, elide any trailing spaces. */
if (foundfield && !quoted) {
while (CSVfieldLength > 0 && isspace(f[CSVfieldLength - 1])) {
f[--CSVfieldLength] = EOS;
}
}
return foundfield;
}
#undef f
#undef flen
|