/*
Copyright (c) 2000-2007, 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
  its 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	tracecc.c	The tracecc programs main module.
*/



/**	Inside the tracecc module.
*/
#define TRACECC_C 1

#include "tracecc.h"



#include "dktools-version.h"
#include "dkdircfg.h"


/**	Tracecc job structure.
 */
typedef struct {
  dk_app_t	*app;			/**< Application. */
  tracecc_t	*tc;			/**< Tracecc controller. */
  int		mode;			/**< Mode. */
  int		boxwidth;		/**< Box width for comment boxes. */
  int		idestyle;		/**< IDE style. */
  char  	**filenames;		/**< File names to process. */
  int   	filenames_in_use;	/**< Number of file names in use. */
} tracecc_cmd_t;



/**	Application package name.
*/
static char packagename[] = { "dktools" };


/**	System configuration directory.
*/
static char sysconfdir[] = { DK_SYSCONFDIR };



/**	Version number.
*/
static char the_version_number[] = { VERSNUMB } ;



/**	The messages printed by this program.
*/
static char *traceccmsg[100];



/**	String finder data for messages issued by the program.
*/
static dk_string_finder_t tracecc_mesgs[] = {
  { 
  (char *)"/m/00", &(traceccmsg[0]), 
  (char *)"Current configuration:"
  },
  { 
  (char *)"/m/01", &(traceccmsg[1]), 
  (char *)"Create debug information"
  },
  { 
  (char *)"/m/02", &(traceccmsg[2]), 
  (char *)"Debug information to stdout, not to file"
  },
  { 
  (char *)"/m/03", &(traceccmsg[3]), 
  (char *)"Debug information includes timestamp"
  },
  { 
  (char *)"/m/04", &(traceccmsg[4]), 
  (char *)"Debug information in IDE style"
  },
  { 
  (char *)"/m/05", &(traceccmsg[5]), 
  (char *)"Add line numbers to source"
  },
  { 
  (char *)"/m/06", &(traceccmsg[6]), 
  (char *)"Allow C++ comments"
  },
  { 
  (char *)"/m/07", &(traceccmsg[7]), 
  (char *)"Box width"
  },
  { 
  (char *)"/m/08", &(traceccmsg[8]), 
  (char *)"Make style"
  },
  { 
  (char *)"/m/09", &(traceccmsg[9]),  
  (char *)"on"
  },
  { 
  (char *)"/m/10", &(traceccmsg[10]), 
  (char *)"off"
  },
  { 
  (char *)"/m/11", &(traceccmsg[11]), 
  (char *)"Print \"trace\" keyword in debug inf"
  },
  { NULL, NULL, NULL }
};



/**	Option -d.
*/
static char str_d[] = { "-d" };

/**	Option -s.
*/
static char str_s[] = { "-s" };

/**	Option -i.
*/
static char str_i[] = { "-i" };

/**	Option -k.
*/
static char str_k[] = { "-k" };

/**	Option -t.
*/
static char str_t[] = { "-t" };

/**	Option -l.
*/
static char str_l[] = { "-l" };

/**	Option -p.
*/
static char str_p[] = { "-p" };

/**	Option -b.
*/
static char str_b[] = { "-b" };

/**	Option -m.
*/
static char str_m[] = { "-m" };



/**	Help text file.
*/
static char help_file_name[] = { "tracecc2.txt" };



/**	String table name.
*/
static char message_table_name[] = { "tracecca" };



/**	Keyword for long options.
*/
static char  *  kw_long_options[] = {
  "h$elp",
  "v$ersion",
  "c$onfigure",
  "u$nconfigure",
  "s$how-configuration",
  "d$ebug-enable",
  "debug-s$tdout",
  "debug-t$imestamp",
  "debug-i$de",
  "l$inenumbers",
  "m$ake",
  "cp$p-comments",
  "b$ox-width",
  "q$uiet",
  "k$eyword",
  "r$eset",
NULL
};



/**	Default help text, printed if no help text file is found.
*/
static char *help_text[] = {
  (char *)"Usage:",
  (char *)"======",
  (char *)"tracecc [-r] [<options>] <directory>",
  (char *)"tracecc [-r] [<options>] <inputfile> <outputfile>",
  (char *)"tracecc -h",
  (char *)"tracecc -v",
  (char *)"tracecc [-r] -c <options>",
  (char *)"tracecc -u",
  (char *)"tracecc -C",
  (char *)"",
  (char *)"Options:",
  (char *)"========",
  (char *)"-h         --help",
  (char *)"             Show help text.",
  (char *)"-v         --version",
  (char *)"             Print version information.",
  (char *)"-c         --configure",
  (char *)"             Configure permanent options.",
  (char *)"             Note: configuration is always relative to the current",
  (char *)"             permanent option set. It is recommended to run",
  (char *)"             tracecc -u",
  (char *)"             before configuring new permanent options.",
  (char *)"-u         --unconfigure",
  (char *)"             Remove all permanent options.",
  (char *)"-C         --show-confguration",
  (char *)"             Show current permanent options.",
  (char *)"",
  (char *)"-r         --reset",
  (char *)"             Reset all options (use as first option).",
  (char *)"             This can be used to skip preferences.",
  (char *)"-d         --debug-enable[=<bool>]",
  (char *)"             Enable debug messages.",
  (char *)"-s         --debug-stdout[=<bool>]",
  (char *)"             If debugging is enabled, debug messages go to",
  (char *)"             standard output instead of a file.",
  (char *)"-t         --debug-timestamp[=<bool>]",
  (char *)"             If debugging is enabled, a timestamp information",
  (char *)"             is printed with each debug information.",
  (char *)"-i         --debug-ide[=<str>]",
  (char *)"             If debugging is enabled, debug messages are",
  (char *)"             printed in IDE style.",
  (char *)"-l         --linenumbers[=<bool>]",
  (char *)"             Place '#line xx \"file\"' directives in destination",
  (char *)"             files pointing to appropriate places in the",
  (char *)"             original source.",
  (char *)"-m         --make[=<bool>]",
  (char *)"             Run in make style, only create new destination",
  (char *)"             files if necessary.",
  (char *)"-p         --cpp-comments[=<bool>]",
  (char *)"             C++ style comments are allowed by the compiler.",
  (char *)"-b <int>   --boxwidth[=<int>]",
  (char *)"             Set box width for comment boxes.",
  NULL
};



/**	IDE style names.
*/
static char *ide_styles[] = {
  (char *)"none",
  (char *)"gcc",
  (char *)"msvc",
  (char *)"workshop",
  (char *)"tasm",
  NULL
};



/**	Bit mask to enable all options.
*/
#define TRACECC_OPT_ALL	255



/**	Reset tracecc job.
	@param	cmd	Tracecc job.
*/
static void reset_cmd DK_P1(tracecc_cmd_t *,cmd)
{
  cmd->mode &= (~(TRACECC_OPT_ALL));
  cmd->boxwidth = 75;
  cmd->idestyle = 0;
}





/**	Abbreviation.
*/
typedef unsigned char *UCP;



/**	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
};



/**	Print version number.
*/
static void print_version DK_P0()
{
  char  *  *ptr;
  printf("\n");
  printf(
    "tracecc 2 (part of the dklibs collection, version %s)\n",
    the_version_number
  );
  printf("Tracing and debugging preprocessor for C, C++, Objective-C and");
  printf(" Java\n");
  printf("Copyright (C) 2002-2010 Dipl.-Ing. D. Krause\n");
  printf("http://dktools.sourceforge.net/\n\n");
  ptr = license_terms;
  while(*ptr) {
    printf("%s\n", *(ptr++));
  }
  printf("\nLibraries used:\n\n");
  ptr = dklic_get();
  while(*ptr) {
    printf("%s\n", *(ptr++));
  }
  printf("\n");
}



/**	Show IDE option.
	@param	opt	Option.
	@param	v	Option value.
	@param	comment	Option description.
	@param	iptr	Largest string.
	@param	cp	Codepage for text.
*/
static void
show_ide_opt DK_P5(char *,opt,int,v,char *,comment,char *,iptr,UCP,cp)
{
  size_t max, cur, i;
  char *s;
  max = 0;
  cur = strlen(traceccmsg[9]);
  if(cur > max) max = cur;
  cur = strlen(traceccmsg[10]);
  if(cur > max) max = cur;
  cur = strlen(iptr);
  if(cur > max) max = cur;
  if(cp) {
    dkcp_fputs(stdout, cp, opt);
  } else {
    fputs(opt, stdout);
  }
  fputs("   ", stdout);
  s = iptr;
  cur = strlen(s);
  cur = max - cur;
  for(i = 0; i < cur; i++) printf(" ");
  if(cp) {
    dkcp_fputs(stdout, cp, s);
  } else {
    fputs(s, stdout);
  }
  fputs("   ", stdout);
  if(cp) {
    dkcp_fputs(stdout, cp, comment);
  } else {
    fputs(comment, stdout);
  }
  fputc('\n', stdout);
}



/**	Show boolean option.
	@param	opt	Option.
	@param	v	Option value.
	@param	comment	Option description.
	@param	iptr	Largest string at position.
	@param	cp	Codepage.
*/
static void
show_bool_opt DK_P5(char *,opt,int,v,char *,comment,char *,iptr,UCP,cp)
{
  size_t max, cur, i;
  char *s;
  max = 0;
  cur = strlen(traceccmsg[9]);
  if(cur > max) max = cur;
  cur = strlen(traceccmsg[10]);
  if(cur > max) max = cur;
  cur = strlen(iptr);
  if(cur > max) max = cur;
  if(cp) {
    dkcp_fputs(stdout, cp, opt);
  } else {
    fputs(opt, stdout);
  }
  fputs("   ", stdout);
  s = (v ? traceccmsg[9] : traceccmsg[10]);
  cur = strlen(s);
  cur = max - cur;
  for(i = 0; i < cur; i++) fputc(' ', stdout);
  if(cp) {
    dkcp_fputs(stdout, cp, s);
  } else {
    fputs(s, stdout);
  }
  fputs("   ", stdout);
  if(cp) {
    dkcp_fputs(stdout, cp, comment);
  } else {
    fputs(comment,stdout);
  }
  fputc('\n', stdout);
}



/**	Show integer option.
	@param	opt	Option.
	@param	v	Value.
	@param	comment	Option description.
	@param	iptr	Maximum string length.
	@param	cp	Codepage to use for print.
*/
static void
show_int_opt DK_P5(char *,opt,int,v,char *,comment,char *,iptr,UCP,cp)
{
  size_t max, cur, i;
  char buffer[32];
  max = 0;
  cur = strlen(traceccmsg[9]);
  if(cur > max) max = cur;
  cur = strlen(traceccmsg[10]);
  if(cur > max) max = cur;
  cur = strlen(iptr);
  if(cur > max) max = cur;
  if(cp) {
    dkcp_fputs(stdout, cp, opt);
  } else {
    fputs(opt, stdout);
  }
  fputc(' ', stdout);
  sprintf(buffer, "%d", v);
  cur = strlen(buffer);
  if((max + 2) >= cur) {
    cur = (max + 2) - cur;
    for(i = 0; i < cur; i++) fputc(' ', stdout);
    if(cp) {
      dkcp_fputs(stdout, cp, buffer);
    } else {
      fputs(buffer, stdout);
    }
    fputs("   ", stdout);
    if(cp) {
      dkcp_fputs(stdout, cp, comment);
    } else {
      fputs(comment, stdout);
    }
  } else {
    printf("%s ", buffer);
    if((max + 4) >= cur) {
      cur = (max + 4) - cur;
      for(i = 0; i < cur; i++) printf(" ");
    }
    if(cp) {
      dkcp_fputs(stdout, cp, comment);
    } else {
      fputs(comment, stdout);
    }
  }
  fputc('\n', stdout);
}



/**	Show configuration to stdout.
	@param	cmd	Tracecc job.
*/
static void
show_configuration DK_P1(tracecc_cmd_t *,cmd)
{
  int i; char *iptr;
  UCP cp;

  cp = NULL;
  if(cmd->app) { cp = dkapp_get_stdout_codepage(cmd->app); }
  i = cmd->idestyle;
  if(i < 0) i = 0; if(i > 4) i = 4;
  iptr = ide_styles[i];
  printf("%s\n", traceccmsg[0]);
  show_bool_opt(
    str_d, ((cmd->mode) & TRACECC_OPT_DEBUG), traceccmsg[1], iptr, cp
  );
  show_bool_opt(
    str_s, ((cmd->mode) & TRACECC_OPT_DEBST), traceccmsg[2], iptr, cp
  );
  show_ide_opt(
    str_i, ((cmd->mode) & cmd->idestyle), traceccmsg[4],iptr, cp
  );
  show_bool_opt(
    str_k, ((cmd->mode) & TRACECC_OPT_KEYWORD), traceccmsg[11], iptr, cp
  );
  show_bool_opt(
    str_t, ((cmd->mode) & TRACECC_OPT_DATETIME), traceccmsg[3],iptr, cp
  );
  show_bool_opt(
    str_l, ((cmd->mode) & TRACECC_OPT_LINENO), traceccmsg[5],iptr, cp
  );
  show_bool_opt(
    str_p, ((cmd->mode) & TRACECC_OPT_CPPCOMMENT), traceccmsg[6],iptr, cp
  );
  show_int_opt(
    str_b, cmd->boxwidth, traceccmsg[7],iptr,cp
  );
  show_bool_opt(
    str_m, ((cmd->mode) & TRACECC_OPT_MAKE), traceccmsg[8],iptr,cp
  );
}



/**	Check whether we need to run silently.
	@param	argc	Number of command line arguments.
	@param	argv	Command line arguments array.
	@param	s	Pointer to result variable.
*/
static void
silence_check DK_P3(int,argc,char **,argv,int *,s)
{
  int sil = 0;
  int i; char *ptr, *argptr, **lfdptr;
  
  sil = dkapp_silence_check(argc,argv);
  if(!sil) {
    lfdptr = argv; lfdptr++; i = 1;
    while(i < argc) {
      ptr = *lfdptr;
      if(*ptr == '-') {
        ptr++;
	switch(*ptr) {
	  case 'b': {
	    ptr++;
	    if(!(*ptr)) {
	      lfdptr++; i++;
	    }
	  } break;
	  case 'q': {
	    sil = 1;
	  } break;
	  case '-': {
	    ptr++;
	    argptr = dkstr_chr(ptr, '=');
	    if(argptr) { *argptr = '\0'; }
            if(dkstr_array_abbr(kw_long_options,ptr,'$',1) == 13) {
	      sil = 1;
	    }
	    if(argptr) { *argptr = '='; }
	  } break;
	}
      }
      lfdptr++; i++;
    }
  }
  *s = sil;
}



/**	Set or reseet a bit.
	@param	iptr	Destination value.
	@param	bit	Bit number.
	@param	vptr	Boolean value expressed as text.
*/
static
void
set_or_reset DK_P3(int *,iptr,int,bit,char *,vptr)
{
  int val;
  int on;
  
  val = *iptr;
  on = 1;
  if(vptr) {
  if(*vptr) {
    switch(*vptr) {
      case '+': on = 1; break;
      case '-': on = 0; break;
      default: {
        if(dkstr_is_bool(vptr)) {
	  on = dkstr_is_on(vptr);
	}
      } break;
    }
  }
  }
  if(on) {
    val |= bit;
  } else {
    val &= (~bit);
  }
  *iptr = val;
}



/** Process arguments.
	@param	cmd	Tracecc job.
	@param	argc	Number of command line arguments.
	@param	argv	Command line arguments array.
*/
static
void
process_args DK_P3(tracecc_cmd_t *,cmd,int,argc,char **,argv)
{
  char *ptr, *argptr, **ifnptr, **lfdptr; int i;
  
  if(cmd) {
    cmd->filenames_in_use = 0; ifnptr = cmd->filenames;
    lfdptr = argv; lfdptr++; i = 1;
    while(i < argc) {
      ptr = *lfdptr;
      if(ptr) {
        if(*ptr == '-') {
	  ptr++;
	  switch(*ptr) {
	    case '-': {
	      ptr++;
	      argptr = dkstr_chr(ptr, '=');
	      if(argptr) { *(argptr++) = '\0'; }
	      switch(dkstr_array_abbr(kw_long_options,ptr,'$',1)) {
	        case 0: {
		  cmd->mode |= TRACECC_OPT_HELP;
		} break;
		case 1: {
		  cmd->mode |= TRACECC_OPT_VERSION;
		} break;
		case 2: {
		  cmd->mode |= TRACECC_OPT_CONFIG;
		} break;
		case 3: {
		  cmd->mode |= TRACECC_OPT_UNCONF;
		} break;
		case 4: {
		  cmd->mode |= TRACECC_OPT_SHOWCONF;
		} break;
		case 5: {
		  set_or_reset(&(cmd->mode),TRACECC_OPT_DEBUG,argptr);
		} break;
		case 6: {
		  set_or_reset(&(cmd->mode),TRACECC_OPT_DEBST,argptr);
		} break;
		case 7: {
		  set_or_reset(&(cmd->mode),TRACECC_OPT_DATETIME,argptr);
		} break;
		case 8: {
		  /* set_or_reset(&(cmd->mode),TRACECC_OPT_DEB_IDE,argptr); */
		  cmd->idestyle =
		  (argptr ? dkapp_ide_type(argptr) : 1);
		} break;
		case 9: {
		  set_or_reset(&(cmd->mode),TRACECC_OPT_LINENO,argptr);
		} break;
		case 10: {
		  set_or_reset(&(cmd->mode),TRACECC_OPT_MAKE,argptr);
		} break;
		case 11: {
		  set_or_reset(&(cmd->mode),TRACECC_OPT_CPPCOMMENT,argptr);
		} break;
		case 12: {
		  if(argptr) {
		    int i;
		    if(sscanf(argptr, "%d", &i) == 1) {
		      if(i < 40) i = 40;
		      if(i > 256) i = 256;
		      cmd->boxwidth = i;
		    }
		  }
		} break;
		case 13: {
		} break;
		case 14: {
		  set_or_reset(&(cmd->mode),TRACECC_OPT_KEYWORD,argptr);
		} break;
		case 15: {
		  reset_cmd(cmd);
		} break;
		default: {
		} break;
	      }
	    } break;
	    case 'r': {
	      reset_cmd(cmd);
	    } break;
	    case 'k': {
	      set_or_reset(&(cmd->mode), TRACECC_OPT_KEYWORD, ++ptr);
	    } break;
	    case 'h': {
	      cmd->mode |= TRACECC_OPT_HELP;
	    } break;
	    case 'v': {
	      cmd->mode |= TRACECC_OPT_VERSION;
	    } break;
	    case 'c': {
	      cmd->mode |= TRACECC_OPT_CONFIG;
	    } break;
	    case 'u': {
	      cmd->mode |= TRACECC_OPT_UNCONF;
	    } break;
	    case 'C': {
	      cmd->mode |= TRACECC_OPT_SHOWCONF;
	    } break;
	    case 'b': {
	      ptr++; argptr = NULL;
	      if(*ptr) {
	        argptr = ptr;
	      } else {
	        i++; lfdptr++;
		if(i < argc) {
		  argptr = *lfdptr;
		}
	      }
	      if(argptr) {
	        int i;
		if(sscanf(argptr, "%d", &i) == 1) {
		  if(i < 40) i = 40;
		  if(i > 256) i = 256;
		  cmd->boxwidth = i;
		}
	      }
	    } break;
	    case 'd': {
	      set_or_reset(&(cmd->mode), TRACECC_OPT_DEBUG, ++ptr);
	    } break;
	    case 's': {
	      set_or_reset(&(cmd->mode), TRACECC_OPT_DEBST, ++ptr);
	    } break;
	    case 'i': {
	      /* set_or_reset(&(cmd->mode), TRACECC_OPT_DEB_IDE, ++ptr); */
	      argptr = NULL; ptr++;
	      if(*ptr) {
	        argptr = ptr;
	      } else {
	        lfdptr++; i++;
		if(i < argc) {
		  argptr = *lfdptr;
		}
	      }
	      if(argptr) {
	        cmd->idestyle = dkapp_ide_type(argptr);
	      }
	    } break;
	    case 'l': {
	      set_or_reset(&(cmd->mode), TRACECC_OPT_LINENO, ++ptr);
	    } break;
	    case 'm': {
	      set_or_reset(&(cmd->mode), TRACECC_OPT_MAKE, ++ptr);
	    } break;
	    case 'p': {
              set_or_reset(&(cmd->mode), TRACECC_OPT_CPPCOMMENT, ++ptr);
	    } break;
	    case 't': {
	      set_or_reset(&(cmd->mode), TRACECC_OPT_DATETIME, ++ptr);
	    } break;
	    case 'q': {
	      /* ##### */
	    } break;
	  }
	} else {
	  *(ifnptr++) = ptr;
	  cmd->filenames_in_use += 1;
	}
      } else {
        i = argc;
      }
      lfdptr++; i++;
    }
  }
}


/**	Abbreviation.
*/
typedef char *p_char_t;



/**	Run for a command after we are configured.
	@param	cmd	Tracecc job.
	@return	1 on success, 0 on error.
*/
static
int
run_for_cmd DK_P1(tracecc_cmd_t *,cmd)
{
  int back = 0;
  
  if(((cmd->mode) & TRACECC_OPT_HELP) || ((cmd->mode) & TRACECC_OPT_VERSION)) {
    
    print_version();
    if((cmd->mode) & TRACECC_OPT_HELP) {
      
      dkapp_help(cmd->app, help_file_name, help_text);
    }
  } else {
if(((cmd->mode) & TRACECC_OPT_CONFIG) || ((cmd->mode) & TRACECC_OPT_UNCONF)) {
  if((cmd->mode) & TRACECC_OPT_UNCONF) {
    
    dkapp_unconfigure(cmd->app);
    back = 1;
  } else {
    
    tracecc_save_preferences(cmd->app, cmd->mode, cmd->boxwidth, cmd->idestyle);
    back = 1;
  }
} else {
  if((cmd->mode) & TRACECC_OPT_SHOWCONF) {
    
    show_configuration(cmd);
    back = 1;
  } else {
    
    switch(cmd->filenames_in_use) {
      case 0: {
        char *pwd; long mpl;
	mpl = dksf_get_maxpathlen();
	if(mpl) {
	  pwd = dk_new(char,mpl);
	  if(pwd) {
	    if(dksf_getcwd(pwd,mpl)) {
	      back = tracecc_dir(cmd->tc, pwd);
	    } else {
	      dkapp_err_cwd(cmd->app);
	    }
	    dk_delete(pwd);
	  } else {
	    dkapp_err_memory(cmd->app,1,mpl);
	  }
	} else {
	  
	}
      } break;
      case 2: {
        back = tracecc_files(cmd->tc,(cmd->filenames)[0], (cmd->filenames)[1]);
      } break;
      default: {
        int i;
	back = 1;
	for(i = 0; i < cmd->filenames_in_use; i++) {
	  if(!tracecc_dir(cmd->tc, (cmd->filenames)[i])) {
	    back = 0;
	  }
	}
      } break;
    }
  }
}
  }
  
  return back;
}



/**	Run with application structure.
	@param	app	Application.
	@return	1 on success, 0 on error.
*/
static int
run_main DK_P1(dk_app_t *,app)
{
  int back = 0;
  char **lfdptr;
  int argc, i; char **argv;
  tracecc_cmd_t cmd;
  
  cmd.app = app; cmd.tc = NULL; cmd.filenames = NULL;
  cmd.filenames_in_use = 0; cmd.mode = 0;
  cmd.boxwidth = 75; cmd.idestyle = 0;
  argc = dkapp_get_argc(app); argv = dkapp_get_argv(app);
  cmd.filenames = dk_new(p_char_t,argc);
  if(cmd.filenames) {
    
    lfdptr = cmd.filenames;
    for(i = 0; i < argc; i++) { *(lfdptr++) = NULL; }
    cmd.tc = tracecc_open(app);
    if(cmd.tc) {
      cmd.mode = tracecc_get_mode(cmd.tc);
      cmd.boxwidth = tracecc_get_boxwidth(cmd.tc);
      cmd.idestyle = tracecc_get_idestyle(cmd.tc);
      process_args(&cmd,argc,argv);
      tracecc_set_mode(cmd.tc, cmd.mode);
      tracecc_set_boxwidth(cmd.tc, cmd.boxwidth);
      tracecc_set_idestyle(cmd.tc, cmd.idestyle);
      back = run_for_cmd(&cmd);
      tracecc_close(cmd.tc);
    } else {
      dkapp_err_memory(app, sizeof(tracecc_t),1);
    }
    lfdptr = cmd.filenames;
    for(i = 0; i < argc; i++) { *(lfdptr++) = NULL; }
    dk_delete(cmd.filenames);
  } else {
    
    dkapp_err_memory(app, sizeof(p_char_t), (size_t)argc);
  }
  
  return back;
}



/**	The main function of the tracecc program.
  	@param	argc	Number of command line arguments.
	@param	argv	Command line arguments array.
	@return	0 on success, any other value indicates an error.
*/
#if DK_HAVE_PROTOTYPES
int main(int argc, char *argv[])
#else
int main(argc, argv) int argc; char *argv[];
#endif
{
  int exval = 0;
  int silent;
  dk_app_t *app;
  
  
  silence_check(argc,argv,&silent);
  app = dkapp_open_ext1(argc, argv, packagename, sysconfdir, silent, 0);
  if(app) {
    
    dkapp_find_multi(app, tracecc_mesgs, message_table_name);
    exval = run_main(app);
    dkapp_close(app); app = NULL;
  } else {
    
    if(!silent) {
      fprintf(stderr, "ERROR: Not enough memory!\n");
      fflush(stderr);
    }
  }
  exval = (exval ? 0 : 1);
  
  
  exit(exval);
  return exval;
}

