/*------------------------------------------------------------------------- * * main.c * Standalone driver for the replication protocol parser (Lime version). * * Reads replication commands from stdin or a file and parses them * using the Lime-generated parser, printing the parsed command structure. * * Usage: * repl_parser # read from stdin * repl_parser file.repl # read from file * repl_parser -q file.repl # quiet mode (validate only) * * Converted from: src/backend/replication/repl_gram.y * src/backend/replication/repl_scanner.l * *------------------------------------------------------------------------- */ #include "repl_defs.h" #include "repl_gram.h" #include /* * Lime parser interface functions (generated by Lime). * These are declared with the prefix from %name repl. */ void *replAlloc(void *(*mallocProc)(size_t)); void replFree(void *p, void (*freeProc)(void *)); void repl(void *yyp, int yymajor, ReplToken yyminor, ReplParseState *pstate); /* * Read entire contents of a FILE into a malloc'd buffer. */ static char * read_file(FILE *fp, int *out_len) { size_t capacity = 4096; size_t length = 0; char *buf = malloc(capacity); if (!buf) { fprintf(stderr, "out of memory\n"); exit(1); } while (!feof(fp)) { if (length + 1024 > capacity) { capacity *= 2; buf = realloc(buf, capacity); if (!buf) { fprintf(stderr, "out of memory\n"); exit(1); } } size_t n = fread(buf + length, 1, 1024, fp); length += n; if (n == 0) break; } buf[length] = '\0'; *out_len = (int)length; return buf; } /* * Parse a single replication command string. * Returns 0 on success, non-zero on error. */ static int parse_repl_command(const char *input, int length, int quiet) { ReplParseState *pstate; void *parser; ReplToken token; int token_type; int result; pstate = repl_parse_state_create(); repl_parse_state_set_input(pstate, input, length); parser = replAlloc(malloc); if (!parser) { fprintf(stderr, "failed to allocate parser\n"); repl_parse_state_destroy(pstate); return 1; } /* Feed tokens to the parser */ while ((token_type = repl_scan_next(pstate, &token)) != 0) { repl(parser, token_type, token, pstate); if (pstate->error_count > 0) break; } /* Send EOF to the parser */ if (pstate->error_count == 0) { ReplToken eof_token = {0}; repl(parser, 0, eof_token, pstate); } result = pstate->error_count; /* Print result */ if (result == 0 && !quiet && pstate->result) { repl_print_command(pstate->result); } /* Clean up */ if (pstate->result) { /* Use extern free function from repl_actions.c */ extern void repl_free_command(ReplCommand *cmd); repl_free_command(pstate->result); } replFree(parser, free); repl_parse_state_destroy(pstate); return result; } int main(int argc, char *argv[]) { FILE *input_file = stdin; int quiet = 0; int argidx = 1; char *input; int length; int result; /* Parse command-line 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] [file.repl]\n", argv[0]); fprintf(stderr, " -q Quiet mode (validate only)\n"); return 0; } else { fprintf(stderr, "Unknown option: %s\n", argv[argidx]); return 1; } } /* Open input file if specified */ if (argidx < argc) { input_file = fopen(argv[argidx], "r"); if (!input_file) { fprintf(stderr, "Cannot open '%s': %s\n", argv[argidx], strerror(errno)); return 1; } } /* Read input */ input = read_file(input_file, &length); if (input_file != stdin) fclose(input_file); /* Parse */ result = parse_repl_command(input, length, quiet); free(input); if (result == 0 && !quiet) fprintf(stderr, "Parse successful.\n"); else if (result != 0) fprintf(stderr, "Parse failed with %d error(s).\n", result); return result ? 1 : 0; }