// ================================================================ static char* read_line_fgetc_psb(FILE* fp, string_builder_t* psb, char* irs) { while (TRUE) { int c = fgetc(fp); if (c == EOF) { if (sb_is_empty(psb)) return NULL; else return sb_finish(psb); } else if (c == irs[0]) { return sb_finish(psb); } else { sb_append_char(psb, c); } } }
// ================================================================ static char* read_line_mmap_psb(file_reader_mmap_state_t* ph, string_builder_t* psb, char* irs) { char *p = ph->sol; while (TRUE) { if (p == ph->eof) { ph->sol = p; if (sb_is_empty(psb)) return NULL; else return sb_finish(psb); } else if (*p == irs[0]) { ph->sol = p+1; return sb_finish(psb); } else { sb_append_char(psb, *p); p++; } } }
// ================================================================ static char* read_line_pfr_psb(peek_file_reader_t* pfr, string_builder_t* psb, char* irs, int irs_len) { while (TRUE) { if (pfr_at_eof(pfr)) { if (sb_is_empty(psb)) return NULL; else return sb_finish(psb); } else if (pfr_next_is(pfr, irs, irs_len)) { if (!pfr_advance_past(pfr, irs)) { fprintf(stderr, "%s: Internal coding error: IRS found and lost.\n", MLR_GLOBALS.argv0); exit(1); } return sb_finish(psb); } else { sb_append_char(psb, pfr_read_char(pfr)); } } }
static char* read_line_pfr_psb(peek_file_reader_t* pfr, string_builder_t* psb, parse_trie_t* ptrie) { int rc, stridx, matchlen; while (TRUE) { pfr_buffer_by(pfr, ptrie->maxlen); rc = parse_trie_ring_match(ptrie, pfr->peekbuf, pfr->sob, pfr->npeeked, pfr->peekbuflenmask, &stridx, &matchlen); if (rc) { pfr_advance_by(pfr, matchlen); switch(stridx) { case IRS_STRIDX: return sb_finish(psb); break; case IRSEOF_STRIDX: return sb_finish(psb); break; case EOF_STRIDX: return NULL; break; } } else { sb_append_char(psb, pfr_read_char(pfr)); } } }
char* lrec_sprint(lrec_t* prec, char* ors, char* ofs, char* ops) { string_builder_t* psb = sb_alloc(SB_ALLOC_LENGTH); if (prec == NULL) { sb_append_string(psb, "NULL"); } else { int nf = 0; for (lrece_t* pe = prec->phead; pe != NULL; pe = pe->pnext) { if (nf > 0) sb_append_string(psb, ofs); sb_append_string(psb, pe->key); sb_append_string(psb, ops); sb_append_string(psb, pe->value); nf++; } sb_append_string(psb, ors); } char* rv = sb_finish(psb); sb_free(psb); return rv; }
int main(int argc, char **argv) { int i; UpClient *upclient; IxpClient *client; signals_setup(&quit_handler); client = ixp_nsmount("wmii"); if(client == NULL) { printf("ixp_nsmount: %s\n", ixp_errbuf()); abort(); } mainloop = g_main_loop_new(NULL, FALSE); upclient = up_client_new(); sb_init(&sb, client); sb_add(&sb, &sbe_ac); for(i = 0; i < MAX_BATTERIES; i++) { sb_add(&sb, &sbe_batteries[i]); } up_client_enumerate_devices_sync(upclient, NULL, NULL); g_signal_connect(upclient, "device-added", G_CALLBACK(device_added_cb), NULL); g_signal_connect(upclient, "device-removed", G_CALLBACK(device_removed_cb), NULL); g_signal_connect(upclient, "device-changed", G_CALLBACK(device_changed_cb), NULL); g_signal_connect(upclient, "changed", G_CALLBACK(changed_cb), NULL); update_sb(upclient); g_main_loop_run(mainloop); sb_finish(&sb); ixp_unmount(client); }
/* * JSON serializes a collection of dSets. * * sets -- A collection of dSet objects. * count -- The number of dSets in sets. * */ char* json_serialize(dSet** sets, int count) { SB sb; sb_init(&sb); sb_putc(&sb, '['); int i; for (i = 0; i < count; i++) { sb_put_dset(&sb, sets[i]); if (i != count - 1) { sb_putc(&sb, ','); } } sb_putc(&sb, ']'); sb_finish(&sb); return sb.start; }
int main(int argc, char **argv) { int n, nfds, res; struct itimerspec timerits; struct epoll_event events[MAX_EVENTS]; struct epoll_event timerevent; IxpClient* client; struct sb sb; signals_setup(&quit_handler); struct sb_entry sbe_sda = { .sbe_path = "/rbar/60_sda", .sbe_private = "sda", .sbe_init = &init_block, .sbe_update = &update_block, .sbe_foreground = 0xbbbbbb, .sbe_background = 0x444444, .sbe_border = 0x555555, }; struct sb_entry sbe_sdb = { .sbe_path = "/rbar/61_sdb", .sbe_private = "sdb", .sbe_init = &init_block, .sbe_update = &update_block, .sbe_foreground = 0xbbbbbb, .sbe_background = 0x444444, .sbe_border = 0x555555, }; struct sb_entry sbe_sdc = { .sbe_path = "/rbar/62_sdc", .sbe_private = "sdc", .sbe_init = &init_block, .sbe_update = &update_block, .sbe_foreground = 0xbbbbbb, .sbe_background = 0x444444, .sbe_border = 0x555555, }; int epollfd = epoll_create1(EPOLL_CLOEXEC); if(epollfd == -1) { perror("epoll_create"); abort(); } int timerfd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC); if(timerfd == -1) { perror("timerfd_create"); abort(); } timerevent.events = EPOLLIN; timerevent.data.fd = timerfd; timerits.it_interval.tv_sec = 0; timerits.it_interval.tv_nsec = 250 * 1000 * 1000; timerits.it_value.tv_sec = timerits.it_interval.tv_sec; timerits.it_value.tv_nsec = timerits.it_interval.tv_nsec; client = ixp_nsmount("wmii"); if(client == NULL) { printf("ixp_nsmount: %s\n", ixp_errbuf()); abort(); } res = epoll_ctl(epollfd, EPOLL_CTL_ADD, timerfd, &timerevent); if(res == -1) { perror("epoll_ctl"); abort(); } res = timerfd_settime(timerfd, 0, &timerits, NULL); if(res == -1) { perror("timerfd_settime"); abort(); } sb_init(&sb, client); sb_add(&sb, &sbe_sda); sb_add(&sb, &sbe_sdb); sb_add(&sb, &sbe_sdc); while(1) { nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1); if(nfds == -1) { if(errno != EINTR) { perror("epoll_wait"); abort(); } } if(should_quit) { break; } for (n = 0; n < nfds; n++) { if(events[n].data.fd == timerfd) { uint64_t x; read(timerfd, &x, sizeof(x)); sb_update(&sb); } } } sb_finish(&sb); ixp_unmount(client); return 0; }
static int lrec_reader_stdio_csv_get_fields(lrec_reader_stdio_csv_state_t* pstate, rslls_t* pfields, context_t* pctx, int is_header) { int rc, stridx, matchlen, record_done, field_done; peek_file_reader_t* pfr = pstate->pfr; string_builder_t* psb = pstate->psb; char* field = NULL; int field_length = 0; if (pfr_peek_char(pfr) == (char)EOF) // char defaults to unsigned on some platforms return FALSE; // Strip the UTF-8 BOM, if any. This is MUCH simpler for mmap, and for stdio on files. For mmap // we can test the first 3 bytes, then skip past them or not. For stdio on files we can fread // the first 3 bytes, then rewind the fp if they're not the UTF-8 BOM. But for stdio on stdin // (which is the primary reason we support stdio in Miller), we cannot rewind: stdin is not // rewindable. if (is_header) { pfr_buffer_by(pfr, UTF8_BOM_LENGTH); int rc = parse_trie_ring_match(pstate->putf8_bom_parse_trie, pfr->peekbuf, pfr->sob, pfr->npeeked, pfr->peekbuflenmask, &stridx, &matchlen); #ifdef DEBUG_PARSER printf("RC=%d stridx=0x%04x matchlen=%d\n", rc, stridx, matchlen); #endif if (rc == TRUE && stridx == UTF8_BOM_STRIDX) { pfr_advance_by(pfr, matchlen); } } // Loop over fields in record record_done = FALSE; while (!record_done) { // Assumption is dquote is "\"" if (pfr_peek_char(pfr) != pstate->dquote[0]) { // NOT DOUBLE-QUOTED // Loop over characters in field field_done = FALSE; while (!field_done) { pfr_buffer_by(pfr, pstate->pno_dquote_parse_trie->maxlen); rc = parse_trie_ring_match(pstate->pno_dquote_parse_trie, pfr->peekbuf, pfr->sob, pfr->npeeked, pfr->peekbuflenmask, &stridx, &matchlen); #ifdef DEBUG_PARSER pfr_print(pfr); #endif if (rc) { #ifdef DEBUG_PARSER printf("RC=%d stridx=0x%04x matchlen=%d\n", rc, stridx, matchlen); #endif switch(stridx) { case EOF_STRIDX: // end of record rslls_append(pfields, sb_finish(psb), FREE_ENTRY_VALUE, 0); field_done = TRUE; record_done = TRUE; break; case IFS_EOF_STRIDX: fprintf(stderr, "%s: syntax error: record-ending field separator at line %lld.\n", MLR_GLOBALS.bargv0, pstate->ilno); exit(1); break; case IFS_STRIDX: // end of field rslls_append(pfields, sb_finish(psb), FREE_ENTRY_VALUE, 0); field_done = TRUE; break; case IRS_STRIDX: // end of record field = sb_finish_with_length(psb, &field_length); // The line-ending '\n' won't be included in the field buffer. if (pstate->do_auto_line_term) { if (field_length > 0 && field[field_length-1] == '\r') { field[field_length-1] = 0; context_set_autodetected_crlf(pctx); } else { context_set_autodetected_lf(pctx); } } rslls_append(pfields, field, FREE_ENTRY_VALUE, 0); field_done = TRUE; record_done = TRUE; break; case DQUOTE_STRIDX: // CSV syntax error: fields containing quotes must be fully wrapped in quotes fprintf(stderr, "%s: syntax error: unwrapped double quote at line %lld.\n", MLR_GLOBALS.bargv0, pstate->ilno); exit(1); break; default: fprintf(stderr, "%s: internal coding error: unexpected token %d at line %lld.\n", MLR_GLOBALS.bargv0, stridx, pstate->ilno); exit(1); break; } pfr_advance_by(pfr, matchlen); } else { #ifdef DEBUG_PARSER char c = pfr_read_char(pfr); printf("CHAR=%c [%02x]\n", isprint((unsigned char)c) ? c : ' ', (unsigned)c); sb_append_char(psb, c); #else sb_append_char(psb, pfr_read_char(pfr)); #endif } } } else { // DOUBLE-QUOTED pfr_advance_by(pfr, pstate->dquotelen); // loop over characters in field field_done = FALSE; char* field = NULL; int field_length = 0; while (!field_done) { pfr_buffer_by(pfr, pstate->pdquote_parse_trie->maxlen); rc = parse_trie_ring_match(pstate->pdquote_parse_trie, pfr->peekbuf, pfr->sob, pfr->npeeked, pfr->peekbuflenmask, &stridx, &matchlen); if (rc) { switch(stridx) { case EOF_STRIDX: // end of record fprintf(stderr, "%s: unmatched double quote at line %lld.\n", MLR_GLOBALS.bargv0, pstate->ilno); exit(1); break; case DQUOTE_EOF_STRIDX: // end of record rslls_append(pfields, sb_finish(psb), FREE_ENTRY_VALUE, FIELD_QUOTED_ON_INPUT); field_done = TRUE; record_done = TRUE; break; case DQUOTE_IFS_STRIDX: // end of field rslls_append(pfields, sb_finish(psb), FREE_ENTRY_VALUE, FIELD_QUOTED_ON_INPUT); field_done = TRUE; break; case DQUOTE_IRS_STRIDX: // end of record case DQUOTE_IRS2_STRIDX: // end of record field = sb_finish_with_length(psb, &field_length); // The line-ending '\n' won't be included in the field buffer. if (pstate->do_auto_line_term) { if (field_length > 0 && field[field_length-1] == '\r') { field[field_length-1] = 0; context_set_autodetected_crlf(pctx); } else { context_set_autodetected_lf(pctx); } } rslls_append(pfields, field, FREE_ENTRY_VALUE, FIELD_QUOTED_ON_INPUT); field_done = TRUE; record_done = TRUE; break; case DQUOTE_DQUOTE_STRIDX: // RFC-4180 CSV: "" inside a dquoted field is an escape for " sb_append_char(psb, pstate->dquote[0]); break; default: fprintf(stderr, "%s: internal coding error: unexpected token %d at line %lld.\n", MLR_GLOBALS.bargv0, stridx, pstate->ilno); exit(1); break; } pfr_advance_by(pfr, matchlen); } else { sb_append_char(psb, pfr_read_char(pfr)); } } } } return TRUE; }
static int lrec_reader_mmap_csv_get_fields(lrec_reader_mmap_csv_state_t* pstate, rslls_t* pfields, file_reader_mmap_state_t* phandle, context_t* pctx) { int rc, stridx, matchlen, record_done, field_done; string_builder_t* psb = pstate->psb; if (phandle->sol >= phandle->eof) return FALSE; char* p = phandle->sol; char* e = p; // loop over fields in record record_done = FALSE; while (!record_done) { // Assumption is dquote is "\"" if (*e != pstate->dquote[0]) { // start of non-quoted field // Loop over characters in field field_done = FALSE; while (!field_done) { MLR_INTERNAL_CODING_ERROR_IF(e > phandle->eof); rc = parse_trie_match(pstate->pno_dquote_parse_trie, e, phandle->eof, &stridx, &matchlen); if (rc) { switch(stridx) { case IFS_STRIDX: // end of field *e = 0; rslls_append(pfields, p, NO_FREE, 0); p = e + matchlen; field_done = TRUE; break; case IRS_STRIDX: // end of record *e = 0; if (pstate->do_auto_line_term) { if (e > p && e[-1] == '\r') { e[-1] = 0; context_set_autodetected_crlf(pctx); } else { context_set_autodetected_lf(pctx); } } rslls_append(pfields, p, NO_FREE, 0); p = e + matchlen; field_done = TRUE; record_done = TRUE; break; case DQUOTE_STRIDX: // CSV syntax error: fields containing quotes must be fully wrapped in quotes fprintf(stderr, "%s: syntax error: unwrapped double quote at line %lld.\n", MLR_GLOBALS.bargv0, pstate->ilno); exit(1); break; default: fprintf(stderr, "%s: internal coding error: unexpected token %d at line %lld.\n", MLR_GLOBALS.bargv0, stridx, pstate->ilno); exit(1); break; } e += matchlen; } else if (e >= phandle->eof) { // We read to end of file without seeing end of line. We can't always zero-poke a null character to // terminate the C string: if the file size is not a multiple of the OS page size it'll work (it's // our copy-on-write memory). But if the file size is a multiple of the page size, then zero-poking // at EOF is one byte past the page and that will segv us. char* copy = mlr_alloc_string_from_char_range(p, phandle->eof - p); rslls_append(pfields, copy, FREE_ENTRY_VALUE, 0); p = e + matchlen; field_done = TRUE; record_done = TRUE; break; } else { e++; } } } else { // start of quoted field e += pstate->dquotelen; p = e; // loop over characters in field field_done = FALSE; int contiguous = TRUE; // If there are no embedded double-double quotes, then the field value is a contiguous // array of bytes between the start and end double-quotes (non-inclusive). E.g. "ab,c" // has contents ab,c. In that case we can point the rslls at that range of bytes // with no data-copying. However, if there are embedded double-double quotes, then // we use the string-build logic to build up a dynamically allocated string. E.g. // "ab""c" becomes ab"c. while (!field_done) { if (e >= phandle->eof) { fprintf(stderr, "%s: unmatched double quote at line %lld.\n", MLR_GLOBALS.bargv0, pstate->ilno); exit(1); } rc = parse_trie_match(pstate->pdquote_parse_trie, e, phandle->eof, &stridx, &matchlen); if (rc) { switch(stridx) { case DQUOTE_IFS_STRIDX: // end of field *e = 0; if (contiguous) rslls_append(pfields, p, NO_FREE, FIELD_QUOTED_ON_INPUT); else rslls_append(pfields, sb_finish(psb), FREE_ENTRY_VALUE, FIELD_QUOTED_ON_INPUT); p = e + matchlen; field_done = TRUE; break; case DQUOTE_IRS_STRIDX: // end of record case DQUOTE_IRS2_STRIDX: // end of record *e = 0; if (pstate->do_auto_line_term) { if (e > p && e[-1] == '\r') { e[-1] = 0; context_set_autodetected_crlf(pctx); } else { context_set_autodetected_lf(pctx); } } if (contiguous) rslls_append(pfields, p, NO_FREE, FIELD_QUOTED_ON_INPUT); else rslls_append(pfields, sb_finish(psb), FREE_ENTRY_VALUE, FIELD_QUOTED_ON_INPUT); p = e + matchlen; field_done = TRUE; record_done = TRUE; break; case DQUOTE_DQUOTE_STRIDX: // RFC-4180 CSV: "" inside a dquoted field is an escape for " if (contiguous) { // not anymore it isn't sb_append_char_range(psb, p, e); contiguous = FALSE; } else { sb_append_char(psb, pstate->dquote[0]); } break; default: fprintf(stderr, "%s: internal coding error: unexpected token %d at line %lld.\n", MLR_GLOBALS.bargv0, stridx, pstate->ilno); exit(1); break; } e += matchlen; } else { if (!contiguous) sb_append_char(psb, *e); e++; } } } } phandle->sol = e; return TRUE; }