/*
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 <inputfile>",
"filtmsql <inputfile> <outputfile>",
"\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  <dk.h>
#include  <dktypes.h>

#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;
}



