/*
	WARNING: This file was generated by dkct.
	Changes you make here will be lost if dkct is run again!
	You should modify the original source and run dkct on it.
	Original source: dkwxwiz.ctr
*/

/*
Copyright (C) 2013, Dirk Krause

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 author 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 dkwxwiz.c The dkwxwiz module.
*/


#line 9 "dkwxwiz.ctr"

#include "dk3all.h"
#include "dkt-version.h"





#line 16 "dkwxwiz.ctr"



/**	@defgroup	dkwxwizcmd	Commands for dkwxwiz.
*/
/**@{*/

/**	Show help text.
*/
#define	DKWXWIZ_CMD_HELP	1

/**	Show version information.
*/
#define	DKWXWIZ_CMD_VERSION	2

/**	Show license terms.
*/
#define	DKWXWIZ_CMD_LICENSE	4

/**@}*/


/**	Job structure for dkwxwiz.
*/
typedef struct {
  dk3_app_t		*app;	/**< Application structure. */
  dkChar const * const	*msg;	/**< Localized messages texts. */
  dk3_option_set_t	*opt;	/**< Command line options. */
  dkChar const		*con;	/**< Copyright holder name. */
  dkChar const		*lin;	/**< License name. */
  dkChar const		*pName;	/**< Program name. */
  dkChar const		*aName;	/**< Application class name. */
  dkChar const		*fName;	/**< Frame class name. */
  dkChar const		*xfn;	/**< XPM file name (allocated). */
  dkChar const		*pfn;	/**< Program header file name. */
  dkChar const		*afn;	/**< Application class file name. */
  dkChar const		*ffn;	/**< Frame class file name. */
  dkChar const		*ifn;	/**< Icon file name. */
  dkChar const		*rfn;	/**< RC file name. */
  int			 exv;	/**< Exit value. */
  int			 cmd;	/**< Command to execute. */
  int			 frc;	/**< Force overwriting existing files. */
  int			 obj;	/**< Flag: Use object modules, not libs. */
} DKWXWIZ_JOB;



/**	Macros like $program$ are allowed in the templates.
*/
static char const * const	dkwxwiz_macros[] = {
/* 0 */
"program",

/* 1 */
"application",

/* 2 */
"frame",

/* 3 */
"year",

/* 4 */
"copyrightowner",

/* 5 */
"licensetype",

NULL


#line 92 "dkwxwiz.ctr"
};



/**	Constant dkChar strings, not localized.
*/
static dkChar const * const	dkwxwiz_nl[] = {
/* 0 */
dkT(".h"),

/* 1 */
dkT(".cpt"),

/* 2 */
dkT(".wxc"),

/* 3 */
dkT("dkwxwizh.txt"),

/* 4 */
dkT("dkwxwiza.txt"),

/* 5 */
dkT("dkwxwizf.txt"),

/* 6 */
dkT("r"),

/* 7 */
dkT("w"),

/* 8 */
dkT("Makefile.in"),

/* 9 */
dkT("configure.ac"),

/* 10 */
dkT("dkwxwizm.txt"),

/* 11 */
dkT("dkwxwizc.txt"),

/* 12 */
dkT("wb"),

/* 13 */
dkT("\r\n"),

/* 14 */
dkT("\n"),

/* 15 */
dkT(".xpm"),

/* 16 */
dkT("dkwxwizx.txt"),

/* 17 */
dkT(".ico"),

/* 18 */
dkT("dkwxwiz.ico"),

/* 19 */
dkT("rb"),

/* 20 */
dkT(".rc"),

/* 21 */
dkT("dkwxwizr.txt"),

/* 22 */
dkT("makefile.vc"),

/* 23 */
dkT("dkwxwizv.txt"),

NULL


#line 197 "dkwxwiz.ctr"
};



/**	Constant dkChar strings, localized versions are used if found.
*/
static dkChar const * const	dkwxwiz_msg[]   = {
/* 0 */
dkT("dkwxwiz"),

/* 1 */
dkT("dkt-3"),

/* 2 */
dkT("dkwxwiz.str"),

/* 3 */
dkT("dkwxwiz.txt"),

/* 4 */
dkT("__CHANGE__ 001:\tCopyright owner"),

/* 5 */
dkT("bsd"),

/* 6 */
dkT("File base name \""),

/* 7 */
dkT("\" too long!"),

/* 8 */
dkT("File \""),

/* 9 */
dkT("\" already exists!"),

/* 10 */
dkT("Unknown macro in line!"),

/* 11 */
dkT("Too few command line arguments!"),

/* 12 */
dkT("You should create/modify the following files:"),

/* 13 */
dkT("Windows help file:     \""),

/* 14 */
dkT("non-Windows help file: \""),

/* 15 */
dkT("Windows icon file:     \""),

/* 16 */
dkT("non-Windows icon file: \""),

/* 17 */
dkT("\"."),

/* 18 */
dkT(".chm"),

/* 19 */
dkT(".htb"),

/* 20 */
dkT(".ico"),

/* 21 */
dkT(".xpm"),

/* 22 */
dkT("Text too long or not ASCII: \""),

/* 23 */
dkT("\"!"),

/* 24 */
dkT("Not a C/C++ identifier: \""),

/* 25 */
dkT("\"!"),

NULL


#line 277 "dkwxwiz.ctr"
};



/**	License conditions shown for dkwxwiz --license-terms.
*/
static dkChar const * const dkwxwiz_license[] = {
dkT(""),
dkT("Copyright (c) 2013, Dirk Krause"),
dkT("All rights reserved."),
dkT(""),
dkT("Redistribution and use in source and binary forms, with or without"),
dkT("modification, are permitted provided that the following conditions are met:"),
dkT(""),
dkT("* Redistributions of source code must retain the above copyright notice,"),
dkT("  this list of conditions and the following disclaimer."),
dkT("* Redistributions in binary form must reproduce the above copyright"),
dkT("  notice, this list of conditions and the following disclaimer in the"),
dkT("  documentation and/or other materials provided with the distribution."),
dkT("* Neither the name of the copyright holder(s) nor the names of"),
dkT("  contributors may be used to endorse or promote products derived from"),
dkT("  this software without specific prior written permission."),
dkT(""),
dkT("THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS"),
dkT("\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT"),
dkT("LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A"),
dkT("PARTICULAR PURPOSE ARE DISCLAIMED."),
dkT("IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY"),
dkT("DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL"),
dkT("DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS"),
dkT("OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)"),
dkT("HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,"),
dkT("STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN"),
dkT("ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE"),
dkT("POSSIBILITY OF SUCH DAMAGE."),
dkT(""),
NULL


#line 315 "dkwxwiz.ctr"
};


/**	Options allowed for dkwxwiz.
*/
static dk3_option_t const dkwxwiz_options[] = {
  { dkT('h'),  dkT("help"), 0 },
  { dkT('v'),  dkT("version"), 0 },
  { dkT('L'),  dkT("license-terms"), 0 },
  { dkT('f'),  dkT("force"), 0},
  { dkT('l'),  dkT("license"), 1 },
  { dkT('c'),  dkT("copyright-owner"), 1 },
  { dkT('o'),  dkT("object-modules"), 0 }, 
};


/**	Number of options in the dkwxwiz_options array.
*/
static size_t dkwxwiz_sz_options =
sizeof(dkwxwiz_options)/sizeof(dk3_option_t);



/**	Default help text, shown if no help file is found.
*/
static dkChar const * dkwxwiz_help_text[] = {
dkT(""),
dkT("NAME"),
dkT(""),
dkT("  dkwxwiz - Wizard to create a wxWidgets + dkct based project."),
dkT(""),
dkT("SYNOPSIS"),
dkT(""),
dkT("  dkwxwiz [<options>] <program> <application> <window>"),
dkT(""),
dkT("DESCRIPTION"),
dkT(""),
dkT("The program creates source code skeletons for a new GUI application based"),
dkT("on wxWidgets assuming you use the dktools libraries and the dkct program"),
dkT("during development."),
dkT("As arguments you have to specify:"),
dkT(""),
dkT("* The name of the final program (i.e. \"myprog\")."),
dkT(""),
dkT("* The name of the application class derived from wxApp (i.e, \"MyProgApp\")."),
dkT(""),
dkT("* The name of the main window class (i.e. \"MyProgFrame\")."),
dkT(""),
dkT("Use valid C/C++ identifiers for all three names."),
dkT(""),
dkT("OPTIONS"),
dkT(""),
dkT("-h\t--help"),
dkT("  shows a help text."),
dkT(""),
dkT("-v\t--version"),
dkT("  shows the program version."),
dkT(""),
dkT("-L\t--license-terms"),
dkT("  shows the license conditions."),
dkT(""),
dkT("-f\t--force"),
dkT("  forces the program to overwrite existing files."),
dkT(""),
dkT("-c <copyright owner name>"),
dkT("  specifies the name of the copyright owner."),
dkT(""),
dkT("-l <license type>"),
dkT("  specifies the license type (i.e. \"bsd\")."),
dkT(""),
dkT("RETURN VALUE"),
dkT(""),
dkT("The program returns exit status 0 on success, any other value indicates"),
dkT("an error."),
dkT(""),
dkT("EXAMPLES"),
dkT(""),
dkT("Run"),
dkT("  dkwxwiz testprog TestApp TestFrame"),
dkT("in an empty directory to create a new project."),
dkT(""),
dkT("FILES"),
dkT(""),
dkT("The following files from the dkt-3 resource directory are used:"),
dkT(""),
dkT("dkwxwizh.txt\tTemplate for project header file *.h."),
dkT(""),
dkT("dkwxwiza.txt\tTemplate for application class source *.cpt"),
dkT(""),
dkT("dkwxwizf.txt\tTemplate for top-level window class source *.wxc."),
dkT(""),
dkT("dkwxwizc.txt\tTemplate for configure.ac file for autoconf."),
dkT(""),
dkT("dkwxwizm.txt\tTemplate for the Makefile.in file."),
dkT(""),
dkT("dkwxwizx.txt\tTemplate for the *.xpm icon file."),
dkT(""),
dkT("You can create copies of these files in dkt-3-site and modify them"),
dkT("i.e. to set a default copyright owner and a default license type."),
dkT(""),
dkT("SEE ALSO"),
dkT(""),
dkT("http://dktools.sourceforge.net"),
dkT(""),
dkT("AUTHOR"),
dkT(""),
dkT("Dirk Krause"),
dkT(""),
dkT("LICENSE"),
dkT(""),
dkT("Use"),
dkT("  dkwxwiz --license-terms"),
dkT("to view the license conditions."),
NULL


#line 430 "dkwxwiz.ctr"
};


/**	Initialize job structure.
	@param	job	Job structure to initialize.
	@param	app	Application structure.
	@param	msg	Localized message texts.
*/
static
void
dkwxwiz_job_init(DKWXWIZ_JOB *job, dk3_app_t *app, dkChar const * const *msg)
{
  job->app = app;
  job->msg = msg;
  job->opt = NULL;
  job->pName = NULL;
  job->aName = NULL;
  job->fName = NULL;
  job->xfn = NULL;
  job->pfn = NULL;
  job->afn = NULL;
  job->ffn = NULL;
  job->ifn = NULL;
  job->rfn = NULL;
  job->exv = 1;
  job->cmd = 0;
  job->frc = 0;
  job->obj = 0;
  job->con = NULL;
  job->lin = NULL;
}



/**	Concatenate base name and file suffix.
	@param	job	Job structure.
	@param	bn	Base file name.
	@param	sf	File name suffix.
	@return	Pointer to new allocated file name on success, NULL on error.
*/
static
dkChar const *
dkwxwiz_concatenate(DKWXWIZ_JOB *job, dkChar const *bn, dkChar const *sf)
{
  dkChar		 buf[DK3_MAX_PATH];	/* Temporary name buffer. */
  dkChar const		*back = NULL;
  

#line 477 "dkwxwiz.ctr"
  if(DK3_SIZEOF(buf,dkChar) > (dk3str_len(bn) + dk3str_len(sf))) {
    dk3str_cpy(buf, bn);
    dk3str_cat(buf, sf);
    back = (dkChar const *)dk3str_dup_app(buf, job->app);
  } else {
    /* ERROR: Base name too long! */
    dk3app_log_3(job->app, DK3_LL_ERROR, job->msg, 6, 7, bn);
  } 

#line 485 "dkwxwiz.ctr"
  return back;
}



/**	Build file names for output files.
	@param	job	Job structure.
	@return	1 on success, 0 on error.
*/
static
int
dkwxwiz_build_file_names(DKWXWIZ_JOB *job)
{
  int		 back = 0;
  

#line 500 "dkwxwiz.ctr"
  job->pfn = dkwxwiz_concatenate(job, job->pName, dkwxwiz_nl[0]);
  job->afn = dkwxwiz_concatenate(job, job->aName, dkwxwiz_nl[1]);
  job->ffn = dkwxwiz_concatenate(job, job->fName, dkwxwiz_nl[2]);
  job->xfn = dkwxwiz_concatenate(job, job->pName, dkwxwiz_nl[15]);
  job->ifn = dkwxwiz_concatenate(job, job->pName, dkwxwiz_nl[17]);
  job->rfn = dkwxwiz_concatenate(job, job->pName, dkwxwiz_nl[20]);
  if((job->pfn) && (job->afn) && (job->ffn) && (job->xfn) && (job->ifn)) {
    if(job->rfn) {
      back = 1;
    }
  } 

#line 511 "dkwxwiz.ctr"
  return back;
}



/**	Check one file name whether we can write the file.
	@param	job	Job structure.
	@param	fn	Output file name.
	@return	1 if allowed to write the file, 0 otherwise.
*/
static
int
dkwxwiz_check_one_filename(DKWXWIZ_JOB *job, dkChar const *fn)
{
  dk3_stat_t	 stb;		/* File information. */
  int		 back = 0;
  

#line 528 "dkwxwiz.ctr"
  if(0 == dk3sf_stat_app(&stb, fn, NULL)) {
    back = 1;
  } else {
    /* ERROR: File already exists! */
    dk3app_log_3(job->app, DK3_LL_ERROR, job->msg, 8, 9, fn);
  } 

#line 534 "dkwxwiz.ctr"
  return back;
}



/**	Check whether we can write all files.
	@param	job	Job structure.
	@return	1 if we are allowed to write/overwrite the files, 0 otherwise.
*/
static
int
dkwxwiz_check_filenames(DKWXWIZ_JOB *job)
{
  int			 back = 0;
  

#line 549 "dkwxwiz.ctr"
  if(job->frc) {
    back = 1;
  } else {
    back = 1;
    if(!dkwxwiz_check_one_filename(job, job->pfn)) {
      back = 0;
    }
    if(!dkwxwiz_check_one_filename(job, job->afn)) {
      back = 0;
    }
    if(!dkwxwiz_check_one_filename(job, job->ffn)) {
      back = 0;
    }
    if(!dkwxwiz_check_one_filename(job, job->xfn)) {
      back = 0;
    }
    if(!dkwxwiz_check_one_filename(job, dkwxwiz_nl[8])) {
      back = 0;
    }
    if(!dkwxwiz_check_one_filename(job, dkwxwiz_nl[9])) {
      back = 0;
    }
    if(!dkwxwiz_check_one_filename(job, job->ifn)) {
      back = 0;
    }
    if(!dkwxwiz_check_one_filename(job, job->rfn)) {
      back = 0;
    }
    if(!dkwxwiz_check_one_filename(job, dkwxwiz_nl[22])) {
      back = 0;
    }
  } 

#line 581 "dkwxwiz.ctr"
  return back;
}



/**	Write one string as 8-bit character text to output.
	@param	job	Job structure.
	@param	dfile	Destination file.
	@param	txt	Text to write.
	@return	1 on success, 0 on error.
*/
static
int
dkwxwiz_write_c8_string(DKWXWIZ_JOB *job, FILE *dfile, dkChar const *txt)
{
#if DK3_CHAR_SIZE > 1
  char			 buf[1024];	/* Temporary buffer for output. */
#endif
  int			 back = 0;
#if DK3_CHAR_SIZE > 1
  int			 res = 0;
  

#line 603 "dkwxwiz.ctr"
  res = dk3str_to_c8p_app(
    buf, sizeof(buf), txt, dk3app_get_encoding(job->app), job->app
  );
  if(res) {
    fputs(buf, dfile);
    back = 1;
  } 

#line 610 "dkwxwiz.ctr"
#else
  

#line 612 "dkwxwiz.ctr"
  fputs(txt, dfile);
  back = 1; 

#line 614 "dkwxwiz.ctr"
#endif
  return back;
}



/**	Process one macro.
	@param	job	Job structure.
	@param	dfile	Output (destination) file.
	@param	sfile	Input (source) file.
	@param	cptr	Start of text.
	@param	p1	First '$' character.
	@param	p2	Second '$' character.
	@return	1 on success, 0 on error.
*/
static
int
dkwxwiz_one_macro(
  DKWXWIZ_JOB	*job,
  FILE		*dfile,
  FILE		*sfile,
  char		*cptr,
  char		*p1,
  char		*p2
)
{
  dk3_tm_t		 tm;		/* Local time. */
  dkChar const		*vptr;		/* Pointer to value text. */
  dk3_time_t		 timer;		/* Current time. */
  int			 action;	/* Macro action to perform. */
  int			 back = 1;
  *p1 = '\0';
  fputs(cptr, dfile);
  *p2 = '\0';
  cptr = &(p2[1]);
  p1++;
  action = dk3str_c8_array_index(dkwxwiz_macros, p1, 0);
  switch(action) {
    case 0: {        /* program */
      if(!dkwxwiz_write_c8_string(job, dfile, job->pName)) {
        back = 0;
      }
    } break;
    case 1: {        /* application */
      if(!dkwxwiz_write_c8_string(job, dfile, job->aName)) {
        back = 0;
      }
    } break;
    case 2: {        /* frame */
      if(!dkwxwiz_write_c8_string(job, dfile, job->fName)) {
        back = 0;
      }
    } break;
    case 3: {        /* year */
      if(dk3sf_time(&timer)) {
        if(dk3sf_localtime_app(&tm, &timer, job->app)) {
          fprintf(dfile, "%04d", tm.Y);
        } else {
          back = 0;
        }
      } else {
        /* ERROR: Failed to obtain current time. */
        dk3app_log_i1(job->app, DK3_LL_ERROR, 80);
        back = 0;
      }
    } break;
    case 4: {        /* copyrightowner */
      vptr = job->con;
      if(!(vptr)) { vptr = (job->msg)[4]; }
      if(!dkwxwiz_write_c8_string(job, dfile, vptr)) {
        back = 0;
      }
    } break;
    case 5: {        /* licensetype */
      vptr = job->lin;
      if(!(vptr)) { vptr = (job->msg)[5]; }
      if(!dkwxwiz_write_c8_string(job, dfile, vptr)) {
        back = 0;
      }
    } break;
    default: {
      /* ERROR: Unknown macro */
      dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 10);
      fputc('$', dfile);
      fputs(p1, dfile);
      fputc('$', dfile);
      back = 0;
    } break;
  }
  return back;
}



/**	Find '$' character starting a dkwxwiz macro.
	@param	txt	Text to search for macro.
	@return	Pointer to first macro found on success, NULL if no macro found.
*/
static
char *
dkwxwiz_find_macro_start(char *txt)
{
  char		*p1;		/* Probably start of new macro. */
  char		*back = NULL;
  p1 = dk3str_c8_chr(txt, '$');
  while((p1) && (!(back))) {
    switch(p1[1]) {
      case '!': case '?':
      case '(': case '{':
      case '@': case '*':
      case '<': case '>':{
        p1 = dk3str_c8_chr(&(p1[1]), '$');
      } break;
      default: {
        back = p1;
      } break;
    }
  }
  return back;
}



/**	Transfer one source file contents to destination file.
	@param	job	Job structure.
	@param	dfile	Destination file.
	@param	sfile	Template file.
	@param	iswin	Flag: Insist on Windows line ends.
	@return	1 on success, 0 on error.
*/
static
int
dkwxwiz_transfer_file(DKWXWIZ_JOB *job, FILE *dfile, FILE *sfile, int iswin)
{
  char			 buf[4096];		/* Line buffer. */
  char			*cptr;			/* Remaining line to process. */
  char			*p1;			/* Start of macro. */
  char			*p2;			/* End of macro. */
  unsigned long		 oldsourceline;		/* Old source line number. */
  unsigned long		 lineno = 0UL;		/* Current source line. */
  int			 back = 1;
  

#line 756 "dkwxwiz.ctr"
  oldsourceline = dk3app_get_source_line(job->app);
  while(fgets(buf, sizeof(buf), sfile)) {
    lineno++;
    dk3app_set_source_line(job->app, lineno);
    dk3str_c8_delnl(buf);
    cptr = buf;
#if 0
    while(cptr) {
      p1 = dk3str_c8_chr(cptr, '$');
      if(p1) {
        switch(p1[1]) {
	  case '!': case '?': case '(': case '{': {
	    p1 = dk3str_c8_chr(&(p1[1]), '$');
	    if(p1) {
	      p2 = dk3str_c8_chr(&(p1[1]), '$');
	      if(p2) {
	        if(!dkwxwiz_one_macro(job, dfile, sfile, cptr, p1, p2)) {
		  back = 0;
		}
		cptr = ++p2;
	      } else {
	        fputs(cptr, dfile);
	        cptr = NULL;
	      }
	    } else {
	      fputs(cptr, dfile);
	      cptr = NULL;
	    }
	  } break;
	  default: {
	    p2 = dk3str_c8_chr(&(p1[1]), '$');
	    if(p2) {
	      if(!dkwxwiz_one_macro(job, dfile, sfile, cptr, p1, p2)) {
	        back = 0;
	      }
	      cptr = ++p2;
	    } else {
	      fputs(cptr, dfile);
	      cptr = NULL;
	    }
	  } break;
	}
      } else {
        fputs(cptr, dfile);
	cptr = NULL;
      }
    }
#else
    while(cptr) {
      p1 = dkwxwiz_find_macro_start(cptr);
      if(p1) {
        p2 = dk3str_c8_chr(&(p1[1]), '$');
	if(p2) {
	  if(!dkwxwiz_one_macro(job, dfile, sfile, cptr, p1, p2)) {
	    back = 0;
	  }
	  cptr = p2;
	  cptr++;
	} else {
	  fputs(cptr, dfile);
	  cptr = NULL;
	}
      } else {
        fputs(cptr, dfile),
	cptr = NULL;
      }
    }
#endif
    /* fputs(dkwxwiz_nl[(iswin) ? 13 : 14], dfile); */
    if(iswin) {
      fputc(0x0d, dfile);
    }
    fputc(0x0a, dfile);
  }
  dk3app_set_source_line(job->app, oldsourceline);
  

#line 832 "dkwxwiz.ctr"
  return back;
}



/**	Produce one output file.
	@param	job	Job structure.
	@param	dn	Destination file name.
	@param	sn	Source file name (template).
	@param	isbin	Flag: Open output for binary writing.
	@param	iswin	Flag: Use Windows line ends.
	@return	1 on success, 0 on error.
*/
static
int
dkwxwiz_one_output_file(
  DKWXWIZ_JOB	*job,
  dkChar const	*dn,
  dkChar const	*sn,
  int		 isbin,
  int		 iswin
)
{
  dk3_search_t		*sres;		/* Search result set. */
  FILE			*sfile;		/* Source file. */
  FILE			*dfile;		/* Destination file. */
  dkChar const		*srcname;	/* Source file name. */
  dkChar const		*oldsourcename;	/* Old source file name. */
  int			 back = 0;
  

#line 862 "dkwxwiz.ctr"
  oldsourcename = dk3app_get_source_file(job->app);
  sres = dk3app_find_config_file_revers(job->app, sn, 0);
  if(sres) {				

#line 865 "dkwxwiz.ctr"
    dk3search_reset(sres);
    srcname = dk3search_next(sres);
    if(srcname) {			

#line 868 "dkwxwiz.ctr"
      sfile = dk3sf_fopen_app(srcname, dkwxwiz_nl[6], job->app);
      if(sfile) {			

#line 870 "dkwxwiz.ctr"
        dfile = dk3sf_fopen_app(dn, dkwxwiz_nl[(isbin) ? 12 : 7], job->app);
	if(dfile) {			

#line 872 "dkwxwiz.ctr"
	  dk3app_set_source_file(job->app, sn);
	  back = dkwxwiz_transfer_file(job, dfile, sfile, iswin);
	  if(!dk3sf_fclose_fn_app(dfile, dn, job->app)) {
	    back = 0;
	  }
	} else {			

#line 878 "dkwxwiz.ctr"
	}
        fclose(sfile);
      } else {				

#line 881 "dkwxwiz.ctr"
      }
    } else {				

#line 883 "dkwxwiz.ctr"
      /* ERROR: File sn not found! */
      dk3app_log_i3(job->app, DK3_LL_ERROR, 150, 151, sn);
    }
    dk3search_close(sres);
  } else {				

#line 888 "dkwxwiz.ctr"
  }
  dk3app_set_source_file(job->app, oldsourcename);
  

#line 891 "dkwxwiz.ctr"
  return back;
}



/**	Copy a binary file directly.
	@param	job	Job structure.
	@param	dn	Destination file name.
	@param	sn	Source file name.
	@return	1 on success, 0 on error.
*/
static
int
dkwxwiz_copy_binary(DKWXWIZ_JOB *job, dkChar const *dn, dkChar const *sn)
{
  char			 buf[4096];	/* Data buffer for copying. */
  dk3_search_t		*sres;		/* Search result set. */
  dkChar const		*srcname;	/* Source file name. */
  FILE			*sfile;		/* Source file. */
  FILE			*dfile;		/* Destination file. */
  size_t		 rdbytes;	/* Number of bytes read. */
  size_t		 wrbytes;	/* Number of bytes written. */
  int			 back	= 0;

  sres = dk3app_find_config_file_revers(job->app, sn, 0);
  if(sres) {
    dk3search_reset(sres);
    srcname = dk3search_next(sres);
    if(srcname) {
      sfile = dk3sf_fopen_app(srcname, dkwxwiz_nl[19], job->app);
      if(sfile) {
        dfile = dk3sf_fopen_app(dn, dkwxwiz_nl[12], job->app);
	if(dfile) {
	  back = 1;
	  do {
	    rdbytes = fread(buf, 1, sizeof(buf), sfile);
	    if(rdbytes > 0) {
	      wrbytes = fwrite(buf, 1, rdbytes, dfile);
	      if(wrbytes != rdbytes) {
	        back = 0;
		/* ERROR: Write operation failed! */
		dk3app_log_i1(job->app, DK3_LL_ERROR, 120);
	      }
	    }
	  } while((rdbytes > 0) && (1 == back));
	  if(!dk3sf_fclose_fn_app(dfile, dn, job->app)) {
	    back = 0;
	  }
	}
        fclose(sfile);
      }
    } else {
      dk3app_log_i3(job->app, DK3_LL_ERROR, 150, 151, sn);
    }
    dk3search_close(sres);
  }
  return back;
}



/**	Produce output files.
	@param	job	Job structure.
*/
static
void
dkwxwiz_produce_output(DKWXWIZ_JOB *job)
{
  

#line 960 "dkwxwiz.ctr"
  if(dkwxwiz_one_output_file(job, job->pfn, dkwxwiz_nl[3], 0, 0))
  {
    if(dkwxwiz_one_output_file(job, job->afn, dkwxwiz_nl[4], 0, 0))
    {
      if(dkwxwiz_one_output_file(job, job->ffn, dkwxwiz_nl[5], 0, 0))
      {
        if(dkwxwiz_one_output_file(job, dkwxwiz_nl[8], dkwxwiz_nl[10], 0, 0))
	{
	  if(dkwxwiz_one_output_file(job, dkwxwiz_nl[9], dkwxwiz_nl[11],0,0))
	  {
	    if(dkwxwiz_one_output_file(job, job->xfn, dkwxwiz_nl[16], 1, 0))
	    {
	      if(dkwxwiz_copy_binary(job, job->ifn, dkwxwiz_nl[18])) {
	      if(dkwxwiz_one_output_file(job,dkwxwiz_nl[22],dkwxwiz_nl[23],1,1))
	      {
	        if(dkwxwiz_one_output_file(job,job->rfn,dkwxwiz_nl[21],1,1)) {
                  job->exv = 0;
	          /* You should provide the following files: */
	          dk3sf_initialize_stdout();
	          dk3sf_fputs((job->msg)[12], stdout);
	          dk3sf_fputc(dkT('\n'), stdout);
	          /* Windows help file: */
	          dk3sf_fputs((job->msg)[13], stdout);
	          dk3sf_fputs(job->aName, stdout);
	          dk3sf_fputs((job->msg)[18], stdout);
	          dk3sf_fputs((job->msg)[17], stdout);
	          dk3sf_fputc(dkT('\n'), stdout);
	          /* non-Windows help file: */
	          dk3sf_fputs((job->msg)[14], stdout);
	          dk3sf_fputs(job->aName, stdout);
	          dk3sf_fputs((job->msg)[19], stdout);
	          dk3sf_fputs((job->msg)[17], stdout);
	          dk3sf_fputc(dkT('\n'), stdout);
	          /* Windows icon file (ico) */
	          dk3sf_fputs((job->msg)[15], stdout);
	          dk3sf_fputs(job->aName, stdout);
	          dk3sf_fputs((job->msg)[20], stdout);
	          dk3sf_fputs((job->msg)[17], stdout);
	          dk3sf_fputc(dkT('\n'), stdout);
	          /* non-Windows icon file (xpm) */
	          dk3sf_fputs((job->msg)[16], stdout);
	          dk3sf_fputs(job->aName, stdout);
	          dk3sf_fputs((job->msg)[21], stdout);
	          dk3sf_fputs((job->msg)[17], stdout);
	          dk3sf_fputc(dkT('\n'), stdout);
		}
	      }
	      }
	    }
	  }
	}
      }
    }
  } 

#line 1014 "dkwxwiz.ctr"
}




/**	Check whether character starts or continues an identifier.
	@param	c	Character to process.
	@param	isfirst	Flag: Is start of string.
	@return	1 on success, 0 on error.
*/
static
int
dkwxwiz_valid_identifier_char(char c, int isfirst)
{
  int		 back = 0;
  if('_' == c) {
    back = 1;
  } else {
    if(('a' <= c) && ('z' >= c)) {
      back = 1;
    } else {
      if(('A' <= c) && ('Z' >= c)) {
        back = 1;
      } else {
        if(!(isfirst)) {
	  if('0' == c) {
	    back = 1;
	  } else {
	    if(('1' <= c) && ('9' >= c)) {
	      back = 1;
	    }
	  }
	}
      }
    }
  }
  return back;
}



/**	Check ASCII string whether it contains a C/C++ identifier
	@param	job	Job structure.
	@param	txt	Text to check.
	@return	1 on success, 0 on error.
*/
static
int
dkwxwiz_check_ascii_c_identifier(DKWXWIZ_JOB *job, char const *txt)
{
  char const	*cptr;		/* Current character to process. */
  int		 isfirst = 1;	/* Flag: Is first character. */
  int		 back = 1;

  cptr = txt;
  while((*cptr) && (back)) {
    if(!dkwxwiz_valid_identifier_char(*cptr, isfirst)) {
      back = 0;
    }
    isfirst = 0;
    cptr++;
  }
  return back;
}



/**	Check one name whether or not it is a C/C++ identifier.
	@param	job	Job structure.
	@param	txt	Text to check.
	@return	1 on success, 0 on error.
*/
static
int
dkwxwiz_check_one_c_identifier(DKWXWIZ_JOB *job, dkChar const *txt)
{
  char			 buf[DK3_MAX_PATH];	/* Conversion buffer. */
  int			 res;			/* Conversion result. */
  int		 	 back = 0;

  res = dk3str_to_c8p_app(
    buf, sizeof(buf), txt, dk3app_get_encoding(job->app), NULL
  );
  if(res) {
    if(dkwxwiz_check_ascii_c_identifier(job, buf)) {
      back = 1;
    } else {
      /* ERROR: Not a C/C++ identifier! */
      dk3app_log_3(job->app, DK3_LL_ERROR, job->msg, 24, 25, txt);
    }
  } else {
    /* ERROR: Text is too long or contains non-ASCII characters! */
    dk3app_log_3(job->app, DK3_LL_ERROR, job->msg, 22, 23, txt);
  }
  return back;
}



/**	Check program name, application class name, window class name.
	@param	job	Job structure.
	@return	1 on success (all names are valid C/C++ identifiers),
	0 on error.
*/
static
int
dkwxwiz_check_c_identifiers(DKWXWIZ_JOB *job)
{
  int		 back = 1;
  if(!dkwxwiz_check_one_c_identifier(job, job->pName)) {
    back = 0;
  }
  if(!dkwxwiz_check_one_c_identifier(job, job->aName)) {
    back = 0;
  }
  if(!dkwxwiz_check_one_c_identifier(job, job->fName)) {
    back = 0;
  }
  return back;
}



/**	Run with known program, application and frame name.
	@param	job	Job structure.
*/
static
void
dkwxwiz_run_with_names(DKWXWIZ_JOB *job)
{
  

#line 1145 "dkwxwiz.ctr"
  if(dkwxwiz_build_file_names(job)) {
    if(dkwxwiz_check_filenames(job)) {
      if(dkwxwiz_check_c_identifiers(job)) {
        dkwxwiz_produce_output(job);
      }
    }
  }
  if(job->ffn) {
    dk3_release(job->ffn)
  }
  if(job->afn)  {
    dk3_release(job->afn)
  }
  if(job->pfn) {
    dk3_release(job->pfn)
  }
  if(job->xfn) {
    dk3_release(job->xfn)
  }
  if(job->ifn) {
    dk3_release(job->ifn)
  }
  if(job->rfn) {
    dk3_release(job->rfn)
  }
  

#line 1171 "dkwxwiz.ctr"
}



/**	Run the program normally (no help/version/license).
	@param	job	Job structure.
*/
static
void
dkwxwiz_run_normally(DKWXWIZ_JOB *job)
{
  int		nargs;		/* Number of command line arguments. */
  

#line 1184 "dkwxwiz.ctr"
  nargs = dk3opt_get_num_args(job->opt);
  if(3 <= nargs) {
    job->pName = dk3opt_get_arg(job->opt, 0);
    job->aName = dk3opt_get_arg(job->opt, 1);
    job->fName = dk3opt_get_arg(job->opt, 2);
    if((job->pName) && (job->aName) && (job->fName)) {
      if(dk3opt_is_set(job->opt, dkT('f'))) {
        job->frc = 1;
      }
      if(dk3opt_is_set(job->opt, dkT('o'))) {
        job->obj = 1;
      }
      job->con = dk3opt_get_short_arg(job->opt, dkT('c'));
      job->lin = dk3opt_get_short_arg(job->opt, dkT('l'));
      dkwxwiz_run_with_names(job);
    } else {
      /* ERROR: Too few arguments. */
      dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 11);
      dk3app_help(job->app, dkwxwiz_msg[3], dkwxwiz_help_text);
    }
  } else {
    /* ERROR: Too few arguments. */
    dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 11);
    dk3app_help(job->app, dkwxwiz_msg[3], dkwxwiz_help_text);
  } 

#line 1209 "dkwxwiz.ctr"
}



/**	Run the program.
	@param	job	Job structure.
*/
static
void
dkwxwiz_run(DKWXWIZ_JOB *job)
{
  dkChar const * const	*sptr;	/* Pointer to traverse text. */
  

#line 1222 "dkwxwiz.ctr"
  job->opt = dk3opt_open_from_app(
    dkwxwiz_options,
    dkwxwiz_sz_options,
    0x00,
    NULL,
    job->app
  );
  if(job->opt) {
    if(dk3opt_get_error_code(job->opt) == 0) {
      if(dk3opt_is_set(job->opt, dkT('h'))) {
        job->cmd |= DKWXWIZ_CMD_HELP;
      }
      if(dk3opt_is_set(job->opt, dkT('v'))) {
        job->cmd |= DKWXWIZ_CMD_VERSION;
      }
      if(dk3opt_is_set(job->opt, dkT('L'))) {
        job->cmd |= DKWXWIZ_CMD_LICENSE;
      }
      if(job->cmd) {
        /*	Version.
	*/
	dk3sf_initialize_stdout();
	dk3sf_fputs(dkwxwiz_msg[0], stdout);
	dk3sf_fputc(dkT(' '), stdout);
	dk3sf_fputs( DKT_VERSION , stdout);
	dk3sf_fputc(dkT('\n'), stdout);
	/*	Help text.
	*/
        if(DKWXWIZ_CMD_HELP & (job->cmd)) {
	  dk3app_help(job->app, dkwxwiz_msg[3], dkwxwiz_help_text);
	}
	/*	License.
	*/
	if(DKWXWIZ_CMD_LICENSE & (job->cmd)) {
	  sptr = dkwxwiz_license;
	  while(*sptr) {
	    dk3sf_fputs(*(sptr++), stdout);
	    dk3sf_fputc(dkT('\n'), stdout);
	  }
	}
      } else {
        dkwxwiz_run_normally(job);
      }
    }
    dk3opt_close(job->opt);
    job->opt = NULL;
  } 

#line 1269 "dkwxwiz.ctr"
}



/**	Program entry point.
	@param	argc	Number of command line arguments.
	@param	argv	Command line arguments array.
	@return	0 on success, any other value indicates an error.
*/
DK3_MAIN
{
  DKWXWIZ_JOB		 job;		/* Job structure. */
  dk3_app_t		*app = NULL;	/* Application structure. */
  dkChar const * const	*msg = NULL;	/* Localized messages. */
  int			 exval;		/* No success yet. */

  

#line 1286 "dkwxwiz.ctr"
  

#line 1287 "dkwxwiz.ctr"
  app = dk3app_open_command(
    argc, (dkChar const * const *)argv, dkwxwiz_msg[1]
  );
  if(app) {
    msg = dk3app_messages(app, dkwxwiz_msg[2], (dkChar const **)dkwxwiz_msg);
    dkwxwiz_job_init(&job, app, msg);
    dkwxwiz_run(&job);
    dk3app_close(app);
  } else {
    fputs("dkwxwiz: ERROR: Not enough memory!\n", stderr);
    fflush(stderr);
  }
  exval = job.exv;
  

#line 1301 "dkwxwiz.ctr"
  

#line 1302 "dkwxwiz.ctr"
  exit(exval); return exval;
}

