/*------------------------------------------------------------------------- * * main.c * Standalone driver for the synchronous replication config parser. * * Usage: * syncrep_parser "standby1, standby2" * syncrep_parser "3 (s1, s2, s3, s4)" * syncrep_parser "ANY 2 (s1, s2, s3)" * syncrep_parser "FIRST 3 (s1, s2, s3, s4)" * echo "config" | syncrep_parser * *------------------------------------------------------------------------- */ #include "syncrep_defs.h" #include "syncrep_gram.h" /* * Lime parser interface functions (generated by Lime). */ void *syncrepAlloc(void *(*mallocProc)(size_t)); void syncrepFree(void *p, void (*freeProc)(void *)); void syncrep(void *yyp, int yymajor, SyncRepToken yyminor, SyncRepParseState *pstate); /* * Read entire contents of a FILE into a malloc'd buffer. */ static char * read_file(FILE *fp, int *out_len) { size_t capacity = 1024; size_t length = 0; char *buf = malloc(capacity); if (!buf) { fprintf(stderr, "out of memory\n"); exit(1); } while (!feof(fp)) { if (length + 256 > capacity) { capacity *= 2; buf = realloc(buf, capacity); if (!buf) { fprintf(stderr, "out of memory\n"); exit(1); } } size_t n = fread(buf + length, 1, 256, fp); length += n; if (n == 0) break; } /* Trim trailing whitespace/newlines */ while (length > 0 && (buf[length - 1] == '\n' || buf[length - 1] == '\r' || buf[length - 1] == ' ' || buf[length - 1] == '\t')) length--; buf[length] = '\0'; *out_len = (int)length; return buf; } /* * Parse a synchronous_standby_names config string. * Returns 0 on success, non-zero on error. */ static int parse_syncrep(const char *input, int length, int quiet) { SyncRepParseState *pstate; void *parser; SyncRepToken token; int token_type; int result; pstate = syncrep_parse_state_create(); syncrep_parse_state_set_input(pstate, input, length); parser = syncrepAlloc(malloc); if (!parser) { fprintf(stderr, "failed to allocate parser\n"); syncrep_parse_state_destroy(pstate); return 1; } /* Feed tokens to parser */ while ((token_type = syncrep_scan_next(pstate, &token)) != 0) { if (token_type == JUNK) { syncrep_yyerror(pstate, "unexpected character"); break; } syncrep(parser, token_type, token, pstate); if (pstate->error_count > 0) break; } /* Send EOF */ if (pstate->error_count == 0) { SyncRepToken eof_token = {0}; syncrep(parser, 0, eof_token, pstate); } result = pstate->error_count; if (result == 0 && !quiet) { syncrep_config_print(pstate->result, stdout); } if (result == 0 && !quiet) fprintf(stderr, "Parse successful.\n"); else if (result != 0) fprintf(stderr, "Parse failed.\n"); syncrepFree(parser, free); syncrep_parse_state_destroy(pstate); return result; } int main(int argc, char *argv[]) { int quiet = 0; int argidx = 1; /* Parse options */ while (argidx < argc && argv[argidx][0] == '-') { if (strcmp(argv[argidx], "-q") == 0) { quiet = 1; argidx++; } else if (strcmp(argv[argidx], "-h") == 0 || strcmp(argv[argidx], "--help") == 0) { fprintf(stderr, "Usage: %s [-q] [config_string]\n", argv[0]); fprintf(stderr, " -q Quiet mode (validate only)\n"); fprintf(stderr, "\nExamples:\n"); fprintf(stderr, " %s \"s1, s2\"\n", argv[0]); fprintf(stderr, " %s \"3 (s1, s2, s3, s4)\"\n", argv[0]); fprintf(stderr, " %s \"ANY 2 (s1, s2, s3)\"\n", argv[0]); fprintf(stderr, " %s \"FIRST 3 (s1, s2, s3, s4)\"\n", argv[0]); return 0; } else { fprintf(stderr, "Unknown option: %s\n", argv[argidx]); return 1; } } if (argidx < argc) { /* Parse command-line argument */ const char *input = argv[argidx]; return parse_syncrep(input, (int)strlen(input), quiet) ? 1 : 0; } else { /* Read from stdin */ int length; char *input = read_file(stdin, &length); int result = parse_syncrep(input, length, quiet); free(input); return result ? 1 : 0; } }