/* * pg_check.c * * A simple check syntax program for PostgreSQL * Originally written by Ranier Vilela and enhanced by many contributors. * * src/bin/pg_check/pg_check.c * Copyright (c) 2022, PostgreSQL Global Development Group * ALL RIGHTS RESERVED; * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose, without fee, and without a written agreement * is hereby granted, provided that the above copyright notice and this * paragraph and the following two paragraphs appear in all copies. * * IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING * LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS * DOCUMENTATION, EVEN IF THE AUTHOR OR DISTRIBUTORS HAVE BEEN ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * THE AUTHOR AND DISTRIBUTORS SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE AUTHOR AND DISTRIBUTORS HAS NO OBLIGATIONS TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * */ #include #include #include #include static const char * progname = "pg_check"; struct S_CTX { int nline; int nargs; int nchars; int nbrackets; int nkeys; int nperc; int nsfmt; bool quote; bool finish; }; typedef struct S_CTX s_ctx; struct S_FUNC { char * function; char * should_string; char * should_char; }; typedef struct S_FUNC s_func; static const s_func pg_functions[] = { { "appendPQExpBuffer(", "should be appendPQExpBufferStr?", "should be appendPQExpBufferChar?" }, { "appendStringInfo(", "should be appendStringInfoString?", "should be appendStringInfoChar?" }, NULL }; void parser_function(s_ctx * ctx, const s_func * pg_function, const char * line) { const char * ptr; size_t len; size_t i; char ch; ctx->finish = false; ptr = line; len = strlen(line); for(i = 0; i < len; i++) { ch = ptr[i]; if (!ctx->quote) { if (ch == '(') ctx->nbrackets++; else if (ch == ')') ctx->nbrackets--; else if (ch == '{') ctx->nkeys++; else if (ch == '}') ctx->nkeys--; else if (ch == ';') { ctx->finish = true; break; } else if (ch == ',') ctx->nargs++; } if (ctx->nargs > 0) if (ch == '"') ctx->quote = !ctx->quote; if (ctx->quote) { if (ch != '"') ctx->nchars++; if (ch == '%') ctx->nperc++; if (ch == 's' && ctx->nperc) { ctx->nsfmt++; ctx->nperc--; } } } /* Analyze */ if (ctx->finish) { if (ctx->nargs < 2) if (ctx->nchars == 1) fprintf(stderr, "line (%d): %s\n", ctx->nline, pg_function->should_char); else fprintf(stderr, "line (%d): %s\n", ctx->nline, pg_function->should_string); else if (ctx->nargs == 2) if (ctx->nsfmt == 1) if (ctx->nchars == 1) fprintf(stderr, "line (%d): %s\n", ctx->nline, pg_function->should_char); else fprintf(stderr, "line (%d): %s\n", ctx->nline, pg_function->should_string); } } void parser_src(FILE * f) { char line[512] = {'\0'}; s_ctx ctx = {0}; int size = (sizeof(pg_functions) / sizeof(s_func)) - 1; int nline; int i; ctx.finish = true; i = 0; nline = 0; while(fgets(line, sizeof(line) - 1, f) != NULL) { nline++; if (ctx.finish) { memset(&ctx, 0, sizeof(ctx)); ctx.finish = true; ctx.nline = nline; for(i = 0; i < size; i++) { const char *function; function = pg_functions[i].function; if (strstr(line, function) != NULL) { parser_function(&ctx, &pg_functions[i], line); if (!ctx.finish) break; } } } else parser_function(&ctx, &pg_functions[i], line); } } int main(int argc, char ** argv) { FILE * f; if (argv[0] != NULL && *argv[0] != 0) { progname = argv[0]; } if (argc != 2) { fprintf(stderr, "usage: %s source.c\n", progname); exit(1); } f = fopen(argv[1], "r"); if (f == NULL) { exit(2); } parser_src(f); fclose(f); exit(0); }