int cbuf_print_quoted(cbuf* ost, const char* s, size_t len) { int n = 1; int ret; cbuf_reserve(ost, len+2); cbuf_putc(ost,'"'); while(len--) { switch (*s) { case '"': case '\\': ret = cbuf_printf(ost, "\\%c", *s); break; default: if (isprint(*s) && ((*s == ' ') || !isspace(*s))) { ret = cbuf_putc(ost, *s); } else { ret = cbuf_printf(ost, "\\%02x", *s); } } s++; if (ret == -1) { return -1; } n += ret; } ret = cbuf_putc(ost,'"'); return (ret == -1) ? -1 : (n + ret); }
static bool srprs_key(const char** ptr, cbuf* key, bool* del) { const char* pos = *ptr; const char* closing_bracket_pos = NULL; size_t closing_bracket_idx = 0; if (!srprs_skipws(&pos) || !srprs_char(&pos, '[')) { return false; } *del = srprs_char(&pos, '-'); cbuf_clear(key); while (true) { while (srprs_charsetinv(&pos, "]\\", key)) ; switch (*pos) { case ']': closing_bracket_idx = cbuf_getpos(key); closing_bracket_pos = pos; cbuf_putc(key, ']'); pos++; break; case '\\': cbuf_putc(key, '\\'); /* n++; */ /* cbuf_puts(subkeyidx, cbuf_getpos(key), sizeof(size_t)) */ while (srprs_char(&pos,'\\')) ; break; case '\0': if (closing_bracket_pos == NULL) { return false; } /* remove trailing backslash (if any) */ if (*(closing_bracket_pos-1)=='\\') { closing_bracket_idx--; } cbuf_setpos(key, closing_bracket_idx); *ptr = closing_bracket_pos+1; return true; default: assert(false); } } }
int cbuf_print_quoted_string(cbuf* ost, const char* s) { int n = 1; cbuf_putc(ost,'"'); while(true) { switch (*s) { case '\0': cbuf_putc(ost, '"'); return n+1; case '"': case '\\': cbuf_putc(ost, '\\'); n++; /* no break */ default: cbuf_putc(ost, *s); n++; } s++; } }
/* matches the empty string, for zero length lists */ static bool srprs_val_hex_values(const char** ptr, cbuf* val, bool* cont) { const char* pos = *ptr; unsigned u; do { if (!srprs_skipws(&pos) || !srprs_hex(&pos, 2, &u) || !srprs_skipws(&pos)) { break; } cbuf_putc(val, (char)u); } while(srprs_char(&pos, ',')); *ptr = pos; if (srprs_skipws(&pos) && srprs_eol_cont(&pos, cont)) { *ptr = pos; } return true; }
/** * Column callback */ static inline void cb_col(void *s, size_t len, void *data) { struct csv_context *ctx = (struct csv_context *)data; size_t cnt; // Put a comma if we should if(ctx->put_comma) { ctx->csv_buf = cbuf_putc(ctx->csv_buf, ','); } ctx->put_comma = 1; // If we are keeping same columns together see if we're on one if(ctx->gcol > -1 && ctx->col == ctx->gcol) { // Don't treat header columns as a group column if(!ctx->use_header || ctx->header_len) { // If we have a last column value and we're in overflow, check // the new row's value against the last one if(ctx->gcol_buf && ctx->opos && memcmp(ctx->gcol_buf, s, len) != 0) { // Flush the data we have! flush_file(ctx, 1); } else if(!ctx->gcol_buf) { // Initialize a new group column buffer ctx->gcol_buf = cbuf_init(len); } // Update our last group column value ctx->gcol_buf = cbuf_setlen(ctx->gcol_buf, (const char*)s, len); } } // Make sure we can write all the data while((cnt = csv_write(CBUF_PTR(ctx->csv_buf), CBUF_REM(ctx->csv_buf), s, len)) > CBUF_REM(ctx->csv_buf)) { // We didn't have room, reallocate ctx->csv_buf = cbuf_double(ctx->csv_buf); } // Increment where we are in our buffer CBUF_POS(ctx->csv_buf)+=cnt; // Increment our column ctx->col++; }
/** * Row parsing callback */ void cb_row(int c, void *data) { // Type cast to our context structure struct csv_context *ctx = (struct csv_context*)data; // Put a newline ctx->csv_buf = cbuf_putc(ctx->csv_buf, '\n'); // If we're injecting headers, and we don't have a header length, then // this row is a header. Otherwise, just increment our row count. if(ctx->use_header && !ctx->header_len) { // Set the length of our header ctx->header_len = CBUF_POS(ctx->csv_buf); // Only increment our row count if we're counting header rows if(ctx->count_header) { ctx->row++; } } else { // Increment row count ctx->row++; } // If we're at or above our row limit, either keep track/ of the position // of this row (if we're grouping columns), or write these rows to disk. if(ctx->row >= ctx->max_rows) { // Mark the position of this row if we're grouping columns, or flush if(ctx->gcol >= 0) { ctx->opos = CBUF_POS(ctx->csv_buf); } else { flush_file(ctx, 0); } } // Back on column zero ctx->col=0; // We don't need a comma for the next column ctx->put_comma = 0; }