%% options copyright owner = Dirk Krause copyright year = 2013-2014 license = bsd %% module #include "dk3all.h" #include "dkt-version.h" $!trace-include /** @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[] = { $!string-table # # 0 # program # # 1 # application # # 2 # frame # # 3 # year # # 4 # copyrightowner # # 5 # licensetype $!end }; /** Constant dkChar strings, not localized. */ static dkChar const * const dkwxwiz_nl[] = { $!string-table macro=dkT # # 0: Suffix .h # .h # # 1: Suffix .cpt # .cpt # # 2: Suffix .wxc # .wxc # # 3: Program header file name. # dkwxwizh.txt # # 4: Application class file name. # dkwxwiza.txt # # 5: Frame class file name. # dkwxwizf.txt # # 6: Open mode read # r # # 7: Open mode write # w # # 8: Makefile name Makefile.in # Makefile.in # # 9: Autoconf file configure.ac # configure.ac # # 10: Souce for Makefile.in # dkwxwizm.txt # # 11: Source for configure.ac # dkwxwizc.txt # # 12: Write mode binary # wb # # 13: Windows line end. # \r\n # # 14: Normal line end. # \n # # 15: XPM file name suffix # .xpm # # 16: XPM file template # dkwxwizx.txt # # 17: Icon file name suffix # .ico # # 18: Icon file # dkwxwiz.ico # # 19: File open mode read binary. # rb # # 20: Suffix for rc file # .rc # # 21: Resource file template file name. # dkwxwizr.txt # # 22: VC makefile name # makefile.vc # # 23: VC makefile template file name. # dkwxwizv.txt $!end }; /** Constant dkChar strings, localized versions are used if found. */ static dkChar const * const dkwxwiz_msg[] = { $!string-table file=dkwxwiz.str,macro=dkT # # 0: Program name. # dkwxwiz # # 1: Program group name. # dkt-3 # # 2: String table file name. # dkwxwiz.str # # 3: Help file name. # dkwxwiz.txt # # 4: Copyright owner. # __CHANGE__ 001: Copyright owner # # 5: License type. # bsd # # 6 7 File base name too long! # File base name " " too long! # # 8 9 File already exists! # File " " already exists! # # 10 # Unknown macro in line! # # 11 # Too few command line arguments! # # 12 # You should create/modify the following files: # # 13 14 15 16 17 # Windows help file: " non-Windows help file: " Windows icon file: " non-Windows icon file: " ". # # 18 19 20 21 # .chm .htb .ico .xpm # # 22 23 # Text too long or not ASCII: " "! # # 24 25 # Not a C/C++ identifier: " "! $!end }; /** License conditions shown for dkwxwiz --license-terms. */ static dkChar const * const dkwxwiz_license[] = { $!text macro=dkT Copyright (c) 2013, 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 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 copyright holder(s) 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. $!end }; /** 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[] = { $!text file=dkwxwiz.txt,macro=dkT NAME dkwxwiz - Wizard to create a wxWidgets + dkct based project. SYNOPSIS dkwxwiz [] DESCRIPTION The program creates source code skeletons for a new GUI application based on wxWidgets assuming you use the dktools libraries and the dkct program during development. As arguments you have to specify: * The name of the final program (i.e. "myprog"). * The name of the application class derived from wxApp (i.e, "MyProgApp"). * The name of the main window class (i.e. "MyProgFrame"). Use valid C/C++ identifiers for all three names. OPTIONS -h --help shows a help text. -v --version shows the program version. -L --license-terms shows the license conditions. -f --force forces the program to overwrite existing files. -c specifies the name of the copyright owner. -l specifies the license type (i.e. "bsd"). RETURN VALUE The program returns exit status 0 on success, any other value indicates an error. EXAMPLES Run dkwxwiz testprog TestApp TestFrame in an empty directory to create a new project. FILES The following files from the dkt-3 resource directory are used: dkwxwizh.txt Template for project header file *.h. dkwxwiza.txt Template for application class source *.cpt dkwxwizf.txt Template for top-level window class source *.wxc. dkwxwizc.txt Template for configure.ac file for autoconf. dkwxwizm.txt Template for the Makefile.in file. dkwxwizx.txt Template for the *.xpm icon file. You can create copies of these files in dkt-3-site and modify them i.e. to set a default copyright owner and a default license type. SEE ALSO http://dktools.sourceforge.net AUTHOR Dirk Krause LICENSE Use dkwxwiz --license-terms to view the license conditions. $!end }; /** 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; $? "+ dkwxwiz_concatenate" if(DK3_SIZEOF(buf,dkChar) > (dk3str_len(bn) + dk3str_len(sf))) { dk3str_cpy_not_overlapped(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); } $? "- dkwxwiz_concatenate %s", TR_PTR(back) 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; $? "+ dkwxwiz_build_file_names" 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; } } $? "- dkwxwiz_build_file_names %d", back 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; $? "+ dkwxwiz_check_one_filename" 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); } $? "- dkwxwiz_check_one_filename %d", back 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; $? "+ dkwxwiz_check_filenames" 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; } } $? "- dkwxwiz_check_filenames %d", back 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; $? "+ dkwxwiz_write_c8_string" res = dk3str_to_c8p_app( buf, sizeof(buf), txt, dk3app_get_encoding(job->app), job->app ); if(res) { fputs(buf, dfile); back = 1; } $? "- dkwxwiz_write_c8_string %d", back #else $? "+ dkwxwiz_write_c8_string %s", TR_PTR(txt) fputs(txt, dfile); back = 1; $? "- dkwxwiz_write_c8_string %d", back #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; $? "+ dkwxwiz_transfer_file" 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); $? "- dkwxwiz_transfer_file %d", back 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; $? "+ dkwxwiz_one_output_file" oldsourcename = dk3app_get_source_file(job->app); sres = dk3app_find_config_file_revers(job->app, sn, 0); if(sres) { $? ". source found" dk3search_reset(sres); srcname = dk3search_next(sres); if(srcname) { $? ". srcname" sfile = dk3sf_fopen_app(srcname, dkwxwiz_nl[6], job->app); if(sfile) { $? ". sfile" dfile = dk3sf_fopen_app(dn, dkwxwiz_nl[(isbin) ? 12 : 7], job->app); if(dfile) { $? ". dfile" 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 { $? "! dfile" } fclose(sfile); } else { $? "! sfile" } } else { $? "! srcname" /* ERROR: File sn not found! */ dk3app_log_i3(job->app, DK3_LL_ERROR, 150, 151, sn); } dk3search_close(sres); } else { $? "! sres" } dk3app_set_source_file(job->app, oldsourcename); $? "- dkwxwiz_one_output_file %d", back 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) { $? "+ dkwxwiz_produce_output" 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); } } } } } } } } } $? "- dkwxwiz_produce_output" } /** 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) { $? "+ dkwxwiz_run_with_names" if(dkwxwiz_build_file_names(job)) { if(dkwxwiz_check_filenames(job)) { if(dkwxwiz_check_c_identifiers(job)) { dkwxwiz_produce_output(job); } } } dk3_release(job->ffn); dk3_release(job->afn); dk3_release(job->pfn); dk3_release(job->xfn); dk3_release(job->ifn); dk3_release(job->rfn); $? "- dkwxwiz_run_with_names" } /** 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. */ $? "+ dkwxwiz_run_normally" 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); } $? "- dkwxwiz_run_normally" } /** Run the program. @param job Job structure. */ static void dkwxwiz_run(DKWXWIZ_JOB *job) { dkChar const * const *sptr; /* Pointer to traverse text. */ $? "+ dkwxwiz_run" 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; } $? "- dkwxwiz_run" } /** 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. */ $!trace-init dkwxwiz.deb $? "+ main" #if DK3_HAVE_TZSET tzset(); #endif job.exv = 1; 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; $? "- main %d", exval $!trace-end fflush(stdout); exit(exval); return exval; }