/* Copyright (c) 2008-2010, Dirk Krause All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above opyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Dirk Krause nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @file filtmsql.c The filtmsql program. */ /** Inside the filtmsql module. */ #define FILTMSQL_C 1 #include "filtmsql.h" #include "dktools-version.h" #line 54 "filtmsql.ctr" /** Exit status. */ static int exval = 1; #ifndef GROUPNAME /** Application group name. */ #define GROUPNAME "dktools" #endif #ifndef PROGRAMNAME /** Application name. */ #define PROGRAMNAME "filtmsql" #endif /** System configuratin directory. */ static char scdir[] = { DK_SYSCONFDIR }; /** Application group name. */ static char grname[] = { GROUPNAME }; /** Application name. */ static char programname[] = { PROGRAMNAME }; /** Version number. */ static char versnumb[] = { VERSNUMB }; /** Long options. */ static char *long_keywords[] = { "h$elp", "v$ersion", NULL }; /** License terms. */ static char *license_terms[] = { "Redistribution and use in source and binary forms, with or without", "modification, are permitted provided that the following conditions are met:", "* Redistributions of source code must retain the above copyright notice, this", " list of conditions and the following disclaimer.", "* Redistributions in binary form must reproduce the above copyright notice,", " this list of conditions and the following disclaimer in the documentation", " and/or other materials provided with the distribution.", "* Neither the name of the Dirk Krause nor the names of other contributors may", " be used to endorse or promote products derived from this software without", " specific prior written permission.", "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"", "AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE", "IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE", "ARE DISCLAIMED.", "IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY", "DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES", "(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;", "LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND", "ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT", "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS", "SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.", NULL }; /** Help text. */ static char *help_text[] = { "filtmsql - Reformatter for mysqldump output", "===========================================", "", "Usage:", "------", "", "filtmsql", "filtmsql ", "filtmsql ", "\treformats output from mysqldump.", "", "filtmsql -h", "\tshows this help text.", "", "filtmsql -v", "\tshows version information.", "", NULL }; /** Key/value pairs, message title, default message. */ static dk_key_value_t kv[] = { { (char *)"00", (char *)"Option \"" }, { (char *)"01", (char *)"\" is unknown!" }, { (char *)"02", (char *)"Too many file names specified!" }, { (char *)"03", (char *)"Failed to write data to output file!" }, { (char *)"04", (char *)"File pattern \"" }, { (char *)"05", (char *)"\" must match exactly one file name!" }, { (char *)"06", (char *)"Failed to create file name expander!" } }; /** Number of elements in the kv array. */ static size_t szkv = sizeof(kv)/sizeof(dk_key_value_t); /** File open mode "w". */ static char str_w[] = { "w" }; /** File open mode "r". */ static char str_r[] = { "r" }; /** String table name for localized texts. */ static char table_name[] = { "filtmsql" }; /* This file was generated by genau. You should not apply changes to this file because they may be overwritten by the next run of genau. */ #ifndef FILTMSQL_AUTOMATA /** Include only once. */ #define FILTMSQL_AUTOMATA /* states */ /** State: S_BRCLOSE. */ #define S_BRCLOSE 1 /** State: S_BRCLOSE_COMMA. */ #define S_BRCLOSE_COMMA 2 /** State: S_BT. */ #define S_BT 3 /** State: S_BT_BS. */ #define S_BT_BS 4 /** State: S_COMMENT. */ #define S_COMMENT 5 /** State: S_COMMENT_ASTERISK. */ #define S_COMMENT_ASTERISK 6 /** State: S_COMMENT_LINE. */ #define S_COMMENT_LINE 7 /** State: S_DQ. */ #define S_DQ 8 /** State: S_DQ_BS. */ #define S_DQ_BS 9 /** State: S_MINUS. */ #define S_MINUS 10 /** State: S_SLASH. */ #define S_SLASH 11 /** State: S_SQ. */ #define S_SQ 12 /** State: S_SQ_BS. */ #define S_SQ_BS 13 /** State: S_START. */ #define S_START 0 /* inputs */ /** Input: I_ANY. */ #define I_ANY 0 /** Input: I_ASTERISK. */ #define I_ASTERISK 1 /** Input: I_BRCLOSE. */ #define I_BRCLOSE 2 /** Input: I_BROPEN. */ #define I_BROPEN 3 /** Input: I_BS. */ #define I_BS 4 /** Input: I_BT. */ #define I_BT 5 /** Input: I_COMMA. */ #define I_COMMA 6 /** Input: I_DQ. */ #define I_DQ 7 /** Input: I_MINUS. */ #define I_MINUS 8 /** Input: I_NL. */ #define I_NL 9 /** Input: I_SLASH. */ #define I_SLASH 10 /** Input: I_SQ. */ #define I_SQ 11 /* outputs */ /** Output: O_PRINT. */ #define O_PRINT 0 /** Output: O_PRINT_NEWLINE. */ #define O_PRINT_NEWLINE 1 /* functions */ #include #include #ifndef FILTMSQL_C #if !DK_HAVE_PROTOTYPES #define EXTERN extern #else #define EXTERN /* nix */ #endif #else #define EXTERN /* nix */ #endif #ifdef __cplusplus extern "C" { #endif /** State transition. @param s Pointer to state variable (in: current, out: new). @param i Current state machine input. @return State machine output. */ EXTERN int filtmsql_decide DK_PR((int *s, int i)); /** State machine reset. @param s Pointer to state variable. */ EXTERN void filtmsql_reset DK_PR((int *s)); #ifdef __cplusplus } #endif #endif /* This file was generated by genau. You should not apply changes to this file because they may be overwritten by the next run of genau. */ /** State machine reset. @param s Pointer to state variable. */ void filtmsql_reset DK_P1(int *, s) { if(s) { *s = S_START; } } /** State transition. @param s Pointer to state variable (in: current, out: new). @param i Current state machine input. @return State machine output. */ int filtmsql_decide DK_P2(int *, s, int, i) { int n,o; o = O_PRINT; if(s) { n = *s; switch(*s) { case S_BRCLOSE : { switch(i) { case I_BRCLOSE : { n = S_BRCLOSE; o = O_PRINT; } break; case I_COMMA : { n = S_BRCLOSE_COMMA; o = O_PRINT; } break; default : { n = S_START; o = O_PRINT; } break; } } break; case S_BRCLOSE_COMMA : { switch(i) { case I_BRCLOSE : { n = S_BRCLOSE; o = O_PRINT; } break; case I_BROPEN : { n = S_START; o = O_PRINT_NEWLINE; } break; default : { n = S_START; o = O_PRINT; } break; } } break; case S_BT : { switch(i) { case I_BS : { n = S_BT_BS; o = O_PRINT; } break; case I_BT : { n = S_START; o = O_PRINT; } break; default : { n = S_BT; o = O_PRINT; } break; } } break; case S_BT_BS : { n = S_BT; o = O_PRINT; } break; case S_COMMENT : { switch(i) { case I_ASTERISK : { n = S_COMMENT_ASTERISK; o = O_PRINT; } break; default : { n = S_COMMENT; o = O_PRINT; } break; } } break; case S_COMMENT_ASTERISK : { switch(i) { case I_ASTERISK : { n = S_COMMENT_ASTERISK; o = O_PRINT; } break; case I_SLASH : { n = S_START; o = O_PRINT; } break; default : { n = S_COMMENT; o = O_PRINT; } break; } } break; case S_COMMENT_LINE : { switch(i) { case I_NL : { n = S_START; o = O_PRINT; } break; default : { n = S_COMMENT_LINE; o = O_PRINT; } break; } } break; case S_DQ : { switch(i) { case I_BS : { n = S_DQ_BS; o = O_PRINT; } break; case I_DQ : { n = S_START; o = O_PRINT; } break; default : { n = S_DQ; o = O_PRINT; } break; } } break; case S_DQ_BS : { n = S_DQ; o = O_PRINT; } break; case S_MINUS : { switch(i) { case I_MINUS : { n = S_COMMENT_LINE; o = O_PRINT; } break; default : { n = S_START; o = O_PRINT; } break; } } break; case S_SLASH : { switch(i) { case I_ASTERISK : { n = S_COMMENT; o = O_PRINT; } break; case I_SLASH : { n = S_SLASH; o = O_PRINT; } break; default : { n = S_START; o = O_PRINT; } break; } } break; case S_SQ : { switch(i) { case I_BS : { n = S_SQ_BS; o = O_PRINT; } break; case I_SQ : { n = S_START; o = O_PRINT; } break; default : { n = S_SQ; o = O_PRINT; } break; } } break; case S_SQ_BS : { n = S_SQ; o = O_PRINT; } break; case S_START : { switch(i) { case I_BRCLOSE : { n = S_BRCLOSE; o = O_PRINT; } break; case I_BT : { n = S_BT; o = O_PRINT; } break; case I_DQ : { n = S_DQ; o = O_PRINT; } break; case I_MINUS : { n = S_MINUS; o = O_PRINT; } break; case I_SLASH : { n = S_SLASH; o = O_PRINT; } break; case I_SQ : { n = S_SQ; o = O_PRINT; } break; } } break; } *s = n; } return o; } #line 218 "filtmsql.ctr" /** Message. @param fj Filtmsql job. @param ll Log level. @param m Index of message in text array. */ static void tool_msg_1 DK_P3(FJ *,fj, int,ll, size_t,m) { dkapp_log_msg(fj->a, ll, &((fj->msg)[m]), 1); } /** Message containing three parts. @param fj Filtmsql job. @param ll Log level. @param m1 Index of first message part in text array. @param m2 Index of third message part in text array. @param t Second message part. */ static void tool_msg_3 DK_P5(FJ *,fj, int,ll, size_t,m1, size_t,m2, char *,t) { char *msgptr[3]; msgptr[0] = (fj->msg)[m1]; msgptr[1] = t; msgptr[2] = (fj->msg)[m2]; dkapp_log_msg(fj->a, ll, msgptr, 3); } /** Check whether the application must run silently or is run as a filter. @param argc Number of command line arguments. @param argv Command line arguments array. @param rs Pointer to result variable (silently). @param rf Pointer to result variable (filter). */ static void silence_check DK_P4(int,argc,char **,argv,int *,rs, int *,rf) { int i, filenames; char *ptr, **lfdptr; filenames = 0; lfdptr = argv; lfdptr++; i = 1; while(i < argc) { ptr = *lfdptr; if(*ptr == '-') { ptr++; if(*ptr == 's') { if(rs) *rs = 1; } } else { filenames++; } lfdptr++; i++; } if(filenames < 2) { if(rf) *rf = 1; } } /** Initialize FJ structure. @param fj Filtmsql job to initialize. */ static void fj_init DK_P1(FJ *,fj) { fj->a = NULL; fj->cmd = FILTMSQL_CMD_NORMAL; fj->exval = 1; fj->ifn1 = fj->ofn1 = fj->ifn2 = fj->ofn2 = NULL; fj->inf = NULL; fj->outf = NULL; } /** Process arguments. Check for -h, -v, --help, --version, -s and for file names. @param fj Filtmsql job. @return 1 on success, 0 on error. */ static int process_args DK_P1(FJ *,fj) { int back = 1, i = 0, xargc = 0; char *p1, *ptr, **xargv, **lfdptr; xargc = dkapp_get_argc(fj->a); xargv = dkapp_get_argv(fj->a); lfdptr = xargv; lfdptr++; i = 1; while(i < xargc) { ptr = *lfdptr; if(*ptr == '-') { p1 = ptr; p1++; switch(*p1) { case '-' : { p1++; switch(dkstr_array_abbr(long_keywords, p1, '$', 0)) { case 0: { fj->cmd |= FILTMSQL_CMD_HELP; } break; case 1: { fj->cmd |= FILTMSQL_CMD_VERSION; } break; default: { back = 0; /* ERROR: Unknown option */ tool_msg_3(fj, DK_LOG_LEVEL_ERROR, 0, 1, ptr); } break; } } break; case 'h' : { fj->cmd |= FILTMSQL_CMD_HELP; } break; case 'v' : { fj->cmd |= FILTMSQL_CMD_VERSION; } break; case 's' : { } break; default: { back = 0; /* ERROR: Unknown option */ tool_msg_3(fj, DK_LOG_LEVEL_ERROR, 0, 1, ptr); } break; } } else { if(fj->ifn1) { if(fj->ofn1) { back = 0; /* ERROR: Too many file name arguments */ tool_msg_1(fj, DK_LOG_LEVEL_ERROR, 2); } else { fj->ofn1 = ptr; } } else { fj->ifn1 = ptr; } } lfdptr++; i++; } return back; } /** Show help text. @param fj Filtmsql job. */ static void print_help DK_P1(FJ *,fj) { dkapp_help(fj->a, "filtmsql.txt", help_text); } /** Show version information. @param fj Filtmsql job. */ static void print_version DK_P1(FJ *,fj) { char **ptr = NULL; printf( "\n%s (part of the dktools collection, version %s)\n", programname, versnumb ); printf("MySQL dump reformatter\n"); printf("Copyright (C) 2008-2010 - Dipl.-Ing. Dirk Krause\n"); printf("http://dktools.sourceforge.net/\n\n"); ptr = license_terms; while(*ptr) { printf("%s\n", *(ptr++)); } } /** Classify input character to produce input for automata functions. @param c Character to classify. @return Classification. */ static int classify_input DK_P1(char,c) { int back = I_ANY; switch(c) { case '`': { back = I_BT; } break; case '\\': { back = I_BS; } break; case '\'': { back = I_SQ; } break; case '"': { back = I_DQ; } break; case '-': { back = I_MINUS; } break; case '/': { back = I_SLASH; } break; case '*': { back = I_ASTERISK; } break; case '(': { back = I_BROPEN; } break; case ')': { back = I_BRCLOSE; } break; case ',': { back = I_COMMA; } break; case '\n': { back = I_NL; } break; } return back; } /** Flush pending output. @param fj Filtmsql job. */ static void flush_output DK_P1(FJ *,fj) { size_t res; if(fj->us_ob) { res = fwrite(fj->ob, sizeof(char), fj->us_ob, fj->outf); if(res != fj->us_ob) { /* Problem while writing */ tool_msg_1(fj, DK_LOG_LEVEL_ERROR, 3); fj->exval = 1; } } fj->us_ob = 0; } /** Add one character to output buffer, flush if necessary. @param fj Filtmsql job. @param c Current character to process. */ static void add_to_output DK_P2(FJ *,fj, char,c) { (fj->ob)[fj->us_ob] = c; fj->us_ob += 1; if(fj->us_ob >= fj->sz_ob) { flush_output(fj); } } /** Do a conversion. The files are opened, buffers were allocated. @param fj Filtmsql job. */ static void run_for_buffers DK_P1(FJ *,fj) { int can_continue; /* flag, can continue */ int it; /* input type */ int s; /* current state */ long br; /* brackets level */ size_t rdbytes; /* number of input bytes read successfully */ size_t i; /* index of current input byte to process */ fj->us_ob = 0; br = 0L; filtmsql_reset(&s); can_continue = 1; while(can_continue) { can_continue = 0; rdbytes = fread(fj->ib, sizeof(char), fj->sz_ib, fj->inf); if(rdbytes > 0) { can_continue = 1; for(i = 0; i < rdbytes; i++) { it = classify_input((fj->ib)[i]); switch(filtmsql_decide(&s, it)) { case O_PRINT_NEWLINE: { if(br == 0L) { add_to_output(fj, '\n'); } add_to_output(fj, (fj->ib)[i]); } break; default: { add_to_output(fj, (fj->ib)[i]); } break; } switch((fj->ib)[i]) { case '(': { switch(s) { case S_START: case S_BRCLOSE: case S_BRCLOSE_COMMA: { br++; } break; } } break; case ')': { switch(s) { case S_START: case S_BRCLOSE: case S_BRCLOSE_COMMA: { br--; if(br < 0L) br = 0L; } break; } } break; } } } } flush_output(fj); } /** Start processing of files. Allocate buffers and invoke the conversion. @param fj Filtmsql job. */ static void run_for_files DK_P1(FJ *,fj) { char inb1def[256], outb1def[256], *ib, *ob; size_t sz; sz = (size_t)16384U; ib = dk_new(char,sz); ob = dk_new(char,sz); if(ib) { fj->ib = ib; fj->sz_ib = sz; } else { fj->ib = inb1def; fj->sz_ib = sizeof(inb1def); } if(ob) { fj->ob = ob; fj->sz_ob = sz; } else { fj->ob = outb1def; fj->sz_ob = sizeof(outb1def); } run_for_buffers(fj); if(ob) { dk_delete(ob); } if(ib) { dk_delete(ib); } } /** Run with a known input file. Open the output file if necessary and start processing. @param fj Filtmsql job. */ static void run_for_input_file DK_P1(FJ *,fj) { FILE *outf = NULL; dk_fne_t *fneo = NULL; if(fj->ofn1) { if(dksf_must_expand_filename(fj->ofn1)) { fneo = dkfne_open(fj->ofn1, 1, 0); if(fneo) { fj->ofn2 = dkfne_get_one(fneo); if(fj->ofn2) { outf = dkapp_fopen(fj->a, fj->ofn2, str_w); if(outf) { fj->outf = outf; fj->exval = 0; run_for_files(fj); fclose(outf); outf = NULL; fj->outf = NULL; } else { dkapp_err_fopenw(fj->a, fj->ofn2); } } else { /* ERROR: Not exactly one name */ tool_msg_3(fj, DK_LOG_LEVEL_ERROR, 4, 5, fj->ofn1); } dkfne_close(fneo); fneo = NULL; } else { /* ERROR: Memory */ tool_msg_1(fj, DK_LOG_LEVEL_ERROR, 6); } } else { outf = dkapp_fopen(fj->a, fj->ofn1, str_w); if(outf) { fj->ofn2 = fj->ofn1; fj->outf = outf; fj->exval = 0; run_for_files(fj); fclose(outf); outf = NULL; fj->outf = NULL; } else { dkapp_err_fopenw(fj->a, fj->ofn1); } } } else { fj->outf = stdout; fj->ofn1 = fj->ofn2 = NULL; fj->exval = 0; run_for_files(fj); } } /** Run with specified file names. Test file names whether or not an expansion is needed. @param fj Filtmsql job. */ static void run_conversion DK_P1(FJ *,fj) { FILE *inf = NULL; dk_fne_t *fneo = NULL; if(fj->ifn1) { if(dksf_must_expand_filename(fj->ifn1)) { fneo = dkfne_open(fj->ifn1, 1, 0); if(fneo) { fj->ifn2 = dkfne_get_one(fneo); if(fj->ifn2) { inf = dkapp_fopen(fj->a, fj->ifn2, str_r); if(inf) { fj->inf = inf; run_for_input_file(fj); fclose(inf); inf = NULL; fj->inf = NULL; } else { dkapp_err_fopenr(fj->a, fj->ifn2); } } else { /* ERROR: No matching file or to many files */ tool_msg_3(fj, DK_LOG_LEVEL_ERROR, 4, 5, fj->ifn1); } dkfne_close(fneo); fneo = NULL; } else { /* ERROR: Memory */ tool_msg_1(fj, DK_LOG_LEVEL_ERROR, 6); } } else { inf = dkapp_fopen(fj->a, fj->ifn1, str_r); if(inf) { fj->ifn2 = fj->ifn1; fj->inf = inf; run_for_input_file(fj); fclose(inf); inf = NULL; fj->inf = NULL; } else { dkapp_err_fopenr(fj->a, fj->ifn1); } } } else { fj->inf = stdin; fj->outf = stdout; fj->exval = 0; fj->ifn1 = fj->ifn2 = fj->ofn1 = fj->ofn2 = NULL; run_for_files(fj); } } /** Process command line arguments. Either run a conversion or print help/version information. @param fj Filtmsql job. */ static void run DK_P1(FJ *,fj) { if(process_args(fj)) { if(fj->cmd) { if((fj->cmd) & (FILTMSQL_CMD_HELP | FILTMSQL_CMD_VERSION)) { fj->exval = 0; print_version(fj); if((fj->cmd) & FILTMSQL_CMD_HELP) { print_help(fj); } } } else { run_conversion(fj); } } } /** Character pointer. */ typedef char *PCHAR; /** The main() function of the filtmsql program. @param argc Number of command line arguments. @param argv Command line arguments array. @return 0 on success, any other value indicates an error. */ #ifdef DK_HAVE_PROTOTYPES int main(int argc, char *argv[]) #else int main(argc, argv) int argc; char *argv[]; #endif { FJ fj; int rs = 0, rf = 0; char *x; #line 698 "filtmsql.ctr" silence_check(argc, argv, &rs, &rf); fj_init(&fj); fj.a = dkapp_open_ext1(argc,argv, grname, scdir, rs, rf); if(fj.a) { fj.msg = dkapp_find_key_value(fj.a, kv, szkv, table_name); if(fj.msg) { run(&fj); exval = fj.exval; x = (char *)(fj.msg); dk_delete(x); } else { dkapp_err_memory(fj.a, sizeof(PCHAR), szkv); } dkapp_close(fj.a); fj.a = NULL; } else { if(!rs) { /* ERROR: Memory */ fprintf(stderr, "ERROR: Not enough memory (RAM/swap space)!\n"); fflush(stderr); } } #line 721 "filtmsql.ctr" exit(exval); return exval; }