1 /*
2 Copyright (C) 2011-2021, Dirk Krause
3 SPDX-License-Identifier: BSD-3-Clause
4 */
5 
6 /*
7 	WARNING: This file was generated by the dkct program (see
8 	http://dktools.sourceforge.net/ for details).
9 	Changes you make here will be lost if dkct is run again!
10 	You should modify the original source and run dkct on it.
11 	Original source: dkct.ctr
12 */
13 
14 
15 /**	@file	dkct.c	Dirk Krause's C/C++ tool.
16 */
17 
18 #include "dk4conf.h"
19 
20 #include <dkct/dkct.h>
21 
22 #include <libdk3c/dk3enc.h>
23 
24 
25 
26 
27 
28 
29 
30 /**	Application group name.
31 */
32 static dkChar const dkct_group_name[] = { dkT("dktools") };
33 
34 
35 
36 /**	Version number string.
37 */
38 static dkChar const dkct_version[] = {
39 dkT("dkct ") DKT_VERSION_DK
40 };
41 
42 
43 
44 /**	License conditions shown for dkct --license.
45 */
46 static dkChar const * const dkct_license[] = {
47 dkT(""),
48 dkT("Copyright (c) 2011-2016, Dirk Krause"),
49 dkT("All rights reserved."),
50 dkT(""),
51 dkT("Redistribution and use in source and binary forms,"),
52 dkT("with or without modification, are permitted provided"),
53 dkT("that the following conditions are met:"),
54 dkT(""),
55 dkT("* Redistributions of source code must retain the above"),
56 dkT("  copyright notice, this list of conditions and the"),
57 dkT("  following disclaimer."),
58 dkT("* Redistributions in binary form must reproduce the above"),
59 dkT("  copyright notice, this list of conditions and the following"),
60 dkT("  disclaimer in the documentation and/or other materials"),
61 dkT("  provided with the distribution."),
62 dkT("* Neither the name of the copyright holder(s) nor the names of"),
63 dkT("  contributors may be used to endorse or promote"),
64 dkT("  products derived from this software without specific"),
65 dkT("  prior written permission."),
66 dkT(""),
67 dkT("THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND"),
68 dkT("CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,"),
69 dkT("INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF"),
70 dkT("MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE"),
71 dkT("DISCLAIMED."),
72 dkT("IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE"),
73 dkT("LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,"),
74 dkT("EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT"),
75 dkT("LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;"),
76 dkT("LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)"),
77 dkT("HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN"),
78 dkT("CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE"),
79 dkT("OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS"),
80 dkT("SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH"),
81 dkT("DAMAGE."),
82 dkT(""),
83 NULL
84 
85 };
86 
87 
88 
89 /**	Options for the dkct program.
90 */
91 static dk3_option_t const dkct_options[] = {
92   { dkT('R'), dkT("reset"), 0 },
93   { dkT('d'), dkT("debug"), 0 },
94   { dkT('s'), dkT("debug-stdout"), 0 },
95   { dkT('l'), dkT("line-numbers"), 0 },
96   { dkT('m'), dkT("make"), 0 },
97   { dkT('b'), dkT("box-width"), 1 },
98   { dkT('h'), dkT("help"), 0 },
99   { dkT('v'), dkT("version"), 0 },
100   { dkT('L'), dkT("license-terms"), 0 },
101   { dkT('\0'),dkT("license"), 0 },
102   { dkT('t'), dkT("timestamp"), 0 },
103   { dkT('k'), dkT("trace-keyword"), 0 },
104   { dkT('w'), dkT("windows-wide-char"), 0 },
105   { dkT('p'), dkT("portable-output"), 0 },
106   { dkT('S'), dkT("splint"), 0 },
107   { dkT('\0'),dkT("splint-comment-char"), 1 },
108   { dkT('\0'),dkT("no-modification-warning"), 0 }
109 };
110 /**	Number of options in the \a dkct_options array.
111 */
112 static size_t dkct_sz_options = sizeof(dkct_options)/sizeof(dk3_option_t);
113 
114 /**	Keywords without need for localization.
115 */
116 static dkChar const * dkct_not_localized[] = {
117 /*   0 */ dkT("."),	/* Current directory. */
118 NULL
119 };
120 
121 
122 
123 /**	File name for help file.
124 */
125 static dkChar const dkct_help_file_name[] = {
126 dkT("dkct.txt")
127 };
128 
129 
130 
131 /**	Default help text, shown if help text file is not found.
132 */
133 static dkChar const * dkct_help_text[] = {
134 dkT(""),
135 dkT("NAME"),
136 dkT(""),
137 dkT("  dkct - Dirk Krause's C tool"),
138 dkT(""),
139 dkT("SYNOPSIS"),
140 dkT(""),
141 dkT("  dkt [<options>] [<files>]"),
142 dkT(""),
143 dkT("DESCRIPTION"),
144 dkT(""),
145 dkT("The program provides:"),
146 dkT("- A preprocessor for debug/trace instructions,"),
147 dkT("- a code generator for state machines,"),
148 dkT("- a code generator for GUIs using the wxWidgets library."),
149 dkT(""),
150 dkT("The program converts *.ctr, *.cpt, *.mtr and *.jtr files to *.c, *.cpp,"),
151 dkT("*.m and *.java. The source files can contain debug instructions in a special"),
152 dkT("notation. When producing release versions the debug instructions are ignored."),
153 dkT("When producing debug versions the debug instructions are converted to output"),
154 dkT("instructtions."),
155 dkT(""),
156 dkT("OPTIONS"),
157 dkT(""),
158 dkT("-R"),
159 dkT("--reset"),
160 dkT("\tIgnore all settings from configuration files."),
161 dkT(""),
162 dkT("-d"),
163 dkT("--debug"),
164 dkT("\tCreate debug output."),
165 dkT(""),
166 dkT("-s"),
167 dkT("--debug-stdout"),
168 dkT("\tDebug output goes to standard output."),
169 dkT(""),
170 dkT("-t"),
171 dkT("--timestamp"),
172 dkT("\tDebug output contains a timestamp."),
173 dkT(""),
174 dkT("-k"),
175 dkT("--trace-keyword"),
176 dkT("\tDebug output contains \"trace\" string."),
177 dkT(""),
178 dkT("-w"),
179 dkT("--windows-wide-char"),
180 dkT("\tPrepare debug output for wchar_t."),
181 dkT(""),
182 dkT("-p"),
183 dkT("--portable-output"),
184 dkT("\tCreate portable debug output code (implies -w)."),
185 dkT(""),
186 dkT("-l"),
187 dkT("--line-numbers"),
188 dkT("\tWrite preprozessor directives \"#line ...\" to output."),
189 dkT(""),
190 dkT("-m"),
191 dkT("--make"),
192 dkT("\tMake mode: rebuild destination files only if necessary."),
193 dkT(""),
194 dkT("-b <width>"),
195 dkT("--box-width=<width>"),
196 dkT("\tBox with for comment boxes."),
197 dkT(""),
198 dkT("-S"),
199 dkT("--splint"),
200 dkT("\tWrite annotation comments for the splint program."),
201 dkT(""),
202 dkT("--splint-comment-char=<character>"),
203 dkT("\tUse the specified character to mark splint comments."),
204 dkT(""),
205 dkT("--no-modification-warning"),
206 dkT("\tSuppress the warning at the beginning of output files."),
207 dkT("\tThese warnings tell the user to not modify the output files produced"),
208 dkT("\tby dkct, users should modify the input files processed by dkct"),
209 dkT("\tinstead."),
210 dkT(""),
211 dkT("-h"),
212 dkT("--help"),
213 dkT("\tShow help text."),
214 dkT(""),
215 dkT("-v"),
216 dkT("--version"),
217 dkT("\tShow version number."),
218 dkT(""),
219 dkT("-L"),
220 dkT("--license-terms"),
221 dkT("\tShow license conditions."),
222 dkT(""),
223 dkT("EXIT STATUS"),
224 dkT(""),
225 dkT("The program returns 0 on success, any other value indicates an error."),
226 dkT(""),
227 dkT("FILES"),
228 dkT(""),
229 dkT("The dk4trace.h and dk4trace.c files containing the functions for debugging"),
230 dkT("and tracing are available in the dktools/dkct subdirectory of the"),
231 dkT("/usr/share or /usr/local/share directory."),
232 dkT(""),
233 dkT("SEE ALSO"),
234 dkT(""),
235 dkT("http://sourceforge.net/p/dktools/dkct%20manual/"),
236 dkT(""),
237 dkT("AUTHOR"),
238 dkT(""),
239 dkT("Dirk Krause"),
240 dkT(""),
241 dkT("LICENSE"),
242 dkT(""),
243 dkT("Use"),
244 dkT("  dkct --license-terms"),
245 dkT("to view the license conditions."),
246 dkT(""),
247 NULL
248 
249 };
250 
251 
252 
253 /**	Initialize option set.
254 	@param	o	Option set.
255 */
256 static
257 void
dkct_option_set_init(DKCT_OPTION_SET * o)258 dkct_option_set_init(DKCT_OPTION_SET *o)
259 {
260   o->deb = 0; o->lnn = 0; o->mak = 0; o->sty = 0;
261   o->bw = 78; o->tkw = 0; o->ts = 0;  o->win = 0;
262   o->tip = 0; o->deben = 1; o->port = 0;
263   o->spls = '\0';
264   o->nowarn = 0;
265 }
266 
267 
268 
269 /**	Initialize job structure.
270 	@param	j	Structure to initialize.
271 */
272 static
273 void
dkct_job_init(DKCT_J * j)274 dkct_job_init(DKCT_J *j)
275 {
276   j->exval = DKT_RESULT_ERR_UNSPECIFIC;
277   j->app = NULL;
278   j->msg = NULL;
279   j->nlc = NULL;
280   j->opt = NULL;
281   j->sCwd = NULL;
282   j->cmd = 0;
283   j->curdi = 0;
284   dkct_option_set_init(&(j->dkcto));
285 }
286 
287 
288 
289 /**	Clean up job structure.
290 	@param	j	Job structure to clean up.
291 */
292 static
293 void
dkct_job_cleanup(DKCT_J * j)294 dkct_job_cleanup(DKCT_J *j)
295 {
296   if(j->opt) {
297     dk3opt_close(j->opt);
298   } j->opt = NULL;
299   if(j->app) {
300     dk3app_close(j->app);
301   } j->app = NULL;
302   j->msg = NULL; j->nlc = NULL;
303 }
304 
305 
306 
307 /**	Process command line arguments, search for options.
308 	@param	j	Job structure.
309 	@return	1 on success, 0 on error.
310 */
311 static
312 int
dkct_process_arguments(DKCT_J * j)313 dkct_process_arguments(DKCT_J *j)
314 {
315   int back = 0;
316   int		 i;	/* Temporary value to read box width. */
317   dkChar const	*arg;	/* Argument value. */
318 
319   j->opt = dk3opt_open_from_app(
320     dkct_options,
321     dkct_sz_options,
322     0x00,
323     NULL,
324     j->app
325   );
326   if(j->opt) {
327     if(dk3opt_get_error_code(j->opt) == 0) {
328       back = 1;
329       if(dk3opt_is_set(j->opt, dkT('R'))) {
330         dkct_option_set_init(&(j->dkcto));
331       }
332       if (dk3opt_is_set_long(j->opt, dkct_options[16].lo)) {
333         (j->dkcto).nowarn = 1;
334       }
335       if(dk3opt_is_set(j->opt, dkT('d'))) {
336         (j->dkcto).deb = 1;
337       }
338       if(dk3opt_is_set(j->opt, dkT('s'))) {
339         (j->dkcto).deb = 2;
340       }
341       if((j->dkcto).deb) {
342         if(dk3opt_is_set(j->opt, dkT('t'))) {
343 	  (j->dkcto).ts = 1;
344 	}
345 	if(dk3opt_is_set(j->opt, dkT('k'))) {
346 	  (j->dkcto).tkw = 1;
347 	}
348 	if(dk3opt_is_set(j->opt, dkT('w'))) {
349 	  (j->dkcto).win = 1;
350 	}
351 	if(dk3opt_is_set(j->opt, dkT('p'))) {
352 	  (j->dkcto).port = 1;
353 	}
354       }
355       if(dk3opt_is_set(j->opt, dkT('l'))) {
356         (j->dkcto).lnn = 1;
357       }
358       if(dk3opt_is_set(j->opt, dkT('m'))) {
359         (j->dkcto).mak = 1;
360       }
361       if(dk3opt_is_set(j->opt, dkT('h'))) {
362         j->cmd |= DK3_APP_CMD_HELP;
363       }
364       if(dk3opt_is_set(j->opt, dkT('v'))) {
365         j->cmd |= DK3_APP_CMD_VERSION;
366       }
367       if(dk3opt_is_set(j->opt, dkT('L'))) {
368         j->cmd |= DK3_APP_CMD_LICENSE;
369       }
370       if(dk3opt_is_set_long(j->opt, dkT("license"))) {
371         j->cmd |= DK3_APP_CMD_LICENSE;
372       }
373       if(dk3opt_is_set(j->opt, dkT('b'))) {
374         arg = dk3opt_get_short_arg(j->opt, dkT('b'));
375 	if(arg) {
376 #if VERSION_BEFORE_20140716
377 	  if(dk3sf_sscanf3(arg, dkT("%d"), &i))
378 #else
379 	  if(0 != dk3ma_i_from_string(&i, arg, NULL))
380 #endif
381 	  {
382 	    if(i > 20) {
383 	      (j->dkcto).bw = i;
384 	    } else {
385 	      j->exval = DKT_RESULT_ERR_OPTION; back = 0;
386 	    }
387 	  } else {
388 	    j->exval = DKT_RESULT_ERR_OPTION; back = 0;
389 	  }
390 	} else {
391 	  j->exval = DKT_RESULT_ERR_OPTION; back = 0;
392 	}
393       }
394 
395 #if VERSION_BEFORE_20140611
396       if (dk3opt_is_set(j->opt, dkT('S'))) {
397         arg = dk3opt_get_short_arg(j->opt, dkT('S'));
398 	if (arg) {
399 	  if (dk3str_len(arg) == 1) {
400 	    if (128 > (int)(*arg)) {
401 	      (j->dkcto).spls = (char)(*arg);
402 	    } else {
403 	      j->exval = DKT_RESULT_ERR_OPTION; back = 0;
404 	      /* ##### ERROR: Not an ASCII character */
405 	    }
406 	  } else {
407 	    j->exval = DKT_RESULT_ERR_OPTION; back = 0;
408 	    /* ##### ERROR: Just one character allowed */
409 	  }
410 	} else {
411 	  j->exval = DKT_RESULT_ERR_OPTION; back = 0;
412 	}
413       }
414 #else
415       if (dk3opt_is_set_long(j->opt, dkct_options[14].lo)) {
416         arg = dk3opt_get_long_arg(j->opt, dkct_options[14].lo);
417 	if (arg) {
418 	  if (1 == dk3str_len(arg)) {
419 #if DK3_CHAR_SIZE > 1
420 	    if (128UL > dk3enc_dk_to_ul(*arg)) {
421 	      (j->dkcto).spls = (char)(*arg);
422 	    } else {
423 	      /* ##### ERROR: Not an ASCII character! */
424 	      j->exval = DKT_RESULT_ERR_OPTION; back = 0;
425 	    }
426 #else
427 	    if (128 > (int)((unsigned char)(*arg))) {
428 	      (j->dkcto).spls = (char)(*arg);
429 	    } else {
430 	      /* ##### ERROR: Not an ASCII character! */
431 	      j->exval = DKT_RESULT_ERR_OPTION; back = 0;
432 	    }
433 #endif
434 	  } else {
435 	    /* ##### ERROR: Exactly one character required! */
436 	    j->exval = DKT_RESULT_ERR_OPTION; back = 0;
437 	  }
438 	} else {
439 	  /* ##### ERROR: Argument required for option! */
440 	  j->exval = DKT_RESULT_ERR_OPTION; back = 0;
441 	}
442       } else {
443       }
444       if (dk3opt_is_set(j->opt, dkT('S'))) {
445         if ('\0' == (j->dkcto).spls) {
446 	  (j->dkcto).spls = '@';
447 	}
448       } else {
449       }
450 #endif
451     } else {
452       j->exval = DKT_RESULT_ERR_OPTION;
453     }
454   } else {
455     j->exval = DKT_RESULT_ERR_OPTION;
456   }
457   return back;
458 }
459 
460 
461 
462 /**	Run for file after expanding wildcards.
463 	@param	j	Job structure.
464 	@param	fn	Source file name.
465 	@param	sufi	Source file suffix index.
466 */
467 static
468 void
dkct_really_run_for_file(DKCT_J * j,dkChar const * fn,int sufi)469 dkct_really_run_for_file(DKCT_J *j, dkChar const *fn, int sufi)
470 {
471   char		 shn[DK3_MAX_PATH];	/* Short file name. */
472   dkChar const	*pstart;		/* Short file name. */
473   int		 ie;			/* System input encoding. */
474   DKCT_SRC	*psrc;			/* Source structure. */
475   int		 success;		/* Flag: Success so far. */
476 
477   pstart = dk3str_rchr(fn, DK3_CHAR_SEP);
478   if(pstart) {
479     pstart++;
480   } else {
481     pstart = fn;
482   }
483   if(pstart) {
484     ie = dk3app_get_encoding(j->app);
485     if(dk3str_to_c8p_app(shn, sizeof(shn), pstart, ie, j->app)) {
486       psrc = dkct_tr_new(&(j->dkcto), shn, sufi, j->app, fn);
487       if(psrc) {
488         success = 0;
489 	if(j->curdi) { psrc->curdi = 1; }
490         psrc->msg = j->msg;
491 	dk3app_log_1(j->app, DK3_LL_PROGRESS, j->msg, 106);
492         if(dkct_tr_read(psrc, fn, sufi)) {
493 	  if(dkct_tr_check(psrc, fn, sufi)) {
494 	    if(dkct_tr_write(psrc, fn, sufi)) {
495 	      success = 1;
496 	    }
497 	  }
498 	}
499 	dk3app_set_source_line(j->app, 0UL);
500 	dk3app_log_1(j->app, DK3_LL_PROGRESS, j->msg, 107);
501 	if(!success) {
502 	  j->exval = DKT_RESULT_ERR_UNSPECIFIC;
503 	  switch(psrc->ec) {
504 	    case DK3_ERROR_MEMORY: {
505 	      j->exval = DKT_RESULT_ERR_MEMORY;
506 	    } break;
507 	    case DK3_ERROR_SYNTAX: {
508 	      j->exval = DKT_RESULT_ERR_INPUT;
509 	    } break;
510 	  }
511 	} else {
512 	  if (DK3_ERROR_NONE != psrc->ec) {
513 	    switch (psrc->ec) {
514 	      case DK3_ERROR_SYNTAX: {
515 	        j->exval = DKT_RESULT_ERR_INPUT;
516 	      } break;
517 	    }
518 	  }
519 	}
520         dkct_tr_delete(psrc); psrc = NULL;
521       } else {
522         j->exval = DKT_RESULT_ERR_MEMORY;
523       }
524     }
525   }
526 
527 }
528 
529 
530 
531 /**	Run for a file name.
532 	@param	j	Job structure.
533 	@param	fn	Source file name.
534 */
535 static
536 void
dkct_run_for_file(DKCT_J * j,dkChar const * fn)537 dkct_run_for_file(DKCT_J *j, dkChar const *fn)
538 {
539   int		 	 must_run = 1;		/* Flag: Must run. */
540   int		 	 ai;			/* Source suffix type. */
541   dkChar const		*su;			/* Source suffx. */
542   dkChar const		*oldsourcename;		/* Old source file name. */
543   dkChar const		*shortSourceName;	/* Short source file name. */
544   dkChar		*xsu;			/* Suffix position. */
545   dkChar const * const	*lfdsu;			/* Destination suffix. */
546   dkChar	 	 b1[DK3_MAX_PATH];	/* Destination file name. */
547   unsigned long		 oldsourceline;		/* Old source line number. */
548 
549   oldsourcename = dk3app_get_source_file(j->app);
550   oldsourceline = dk3app_get_source_line(j->app);
551   if(j->curdi) {
552     shortSourceName = dk3str_rchr(fn, (dk3app_not_localized(20))[0]);
553     if(shortSourceName) { shortSourceName++; }
554     else { shortSourceName = fn; }
555   } else {
556     shortSourceName = fn;
557   }
558   dk3app_set_source_file(j->app, shortSourceName);
559   dk3app_set_source_line(j->app, 0UL);
560   su = dk3str_get_suffix(fn);
561   if(su) {
562 #if DK3_ON_WINDOWS || DK3_HAVE_FNCASEINS
563     ai = dk3str_array_index(dkct_str_get_source_suffixes(), su, 0);
564 #else
565     ai = dk3str_array_index(dkct_str_get_source_suffixes(), su, 1);
566 #endif
567     if(ai >= 0) {
568       if((j->dkcto).mak) {
569         if(dk3str_len(fn) < DK3_SIZEOF(b1,dkChar)) {
570 	  dk3str_cpy_not_overlapped(b1, fn);
571 	  lfdsu = (dkct_str_get_dest_suffixes())[ai];
572 	  xsu = dk3str_get_suffix(b1);
573 	  if(xsu) {
574 	    must_run = 0;
575 	    while(*lfdsu) {
576 	      *xsu = dkT('\0');
577 	      if((dk3str_len(b1)+dk3str_len(*lfdsu)) < DK3_SIZEOF(b1,dkChar)) {
578 	        dk3str_cat(b1, *lfdsu);
579 		if(dk3sf_must_rebuild(b1, fn)) {
580 		  must_run = 1;
581 		}
582 	      } else {
583 	        must_run = 1;
584 	      }
585 	      lfdsu++;
586 	    }
587 	  }
588 	}
589       }
590       if(must_run) {
591         dkct_really_run_for_file(j, fn, ai);
592       } else {
593         /* Progress: All output files up to date. 105 */
594 	dk3app_log_1(j->app, DK3_LL_PROGRESS, j->msg, 105);
595       }
596     } else {
597       /* Wrong suffix, not an input file! */
598       dk3app_log_3(j->app, DK3_LL_ERROR, j->msg, 0, 1, fn);
599       j->exval = DKT_RESULT_ERR_FILENAME;
600     }
601   } else {
602     /* No suffix, Not an input file! */
603     dk3app_log_3(j->app, DK3_LL_ERROR, j->msg, 0, 1, fn);
604     j->exval = DKT_RESULT_ERR_FILENAME;
605   }
606   dk3app_set_source_file(j->app, oldsourcename);
607   dk3app_set_source_line(j->app, oldsourceline);
608 
609 }
610 
611 
612 
613 /**	Run for a directory.
614 	@param	j	Job structure.
615 	@param	dn	Directory name.
616 	@param	fcd	Flag: Use chdir() to enter directory (ignored).
617 */
618 static
619 void
dkct_run_for_directory(DKCT_J * j,dkChar const * dn,int fcd)620 dkct_run_for_directory(DKCT_J *j, dkChar const *dn, int fcd)
621 {
622   int			 ok = 1;	/* Flag: Ok so far. */
623   dk3_dir_t		*dir;	/* Directory. */
624   dkChar const		*en;	/* Current file name. */
625   dkChar const		*su;	/* File name suffix. */
626   dk3_stat_t const	*es;	/* Stat information for current file. */
627   int			 ai;	/* Source suffix type. */
628 
629   if(fcd) {
630 #if 0
631     /* Change into directory dn. */
632     if(!dk3sf_chdir_app(dn, j->app)) {
633       ok = 0;
634     }
635 #endif
636   }
637   if(ok) {
638     dir = dk3dir_open_app(dn, j->app);
639     if(dir) {
640       while(dk3dir_get_next_file(dir)) {
641         en = dk3dir_get_fullname(dir);
642 	es = dk3dir_get_stat(dir);
643 	if((en) && (es)) {
644 	  switch((es->ft) & (~(DK3_FT_SYMLINK))) {
645 	    case DK3_FT_REGULAR: {
646 	      su = dk3str_get_suffix(en);
647 	      if(su) {
648 #if DK3_ON_WINDOWS || DK3_HAVE_FNCASEINS
649 	        ai = dk3str_array_index(dkct_str_get_source_suffixes(), su, 0);
650 #else
651 		ai = dk3str_array_index(dkct_str_get_source_suffixes(), su, 1);
652 #endif
653 		if(ai >= 0) {
654 		  dkct_run_for_file(j, en);
655 		}
656 	      }
657 	    } break;
658 	  }
659 	}
660       }
661       dk3dir_close(dir);
662     } else {
663       /* ERROR: Failed to open directory! */
664       j->exval = DKT_RESULT_ERR_OPENDIR;
665     }
666   }
667   if(fcd) {
668 #if 0
669     /* Change back into previous current directory. */
670     if(ok) {
671       dk3sf_chdir_app(j->sCwd, j->app);
672     }
673 #endif
674   }
675 }
676 
677 
678 
679 /**	Run for a directory, test for current directory before running.
680 	@param	j	Job structure.
681 	@param	fn	Directory name.
682 */
683 static
684 void
dkct_run_for_directory_test_current(DKCT_J * j,dkChar const * fn)685 dkct_run_for_directory_test_current(DKCT_J *j, dkChar const *fn)
686 {
687   if(dk3str_cmp(fn, dkct_not_localized[0]) == 0) {
688     j->curdi = 1;
689     dkct_run_for_directory(j, fn, 0);
690   } else {
691     dkct_run_for_directory(j, fn, 1);
692   }
693 }
694 
695 
696 
697 /**	Run for the given file names.
698 	@param	j	Job structure.
699 */
700 static
701 void
dkct_run(DKCT_J * j)702 dkct_run(DKCT_J *j)
703 {
704   int 			 nfn;			/* Number of file names. */
705   dkChar const		*arg;			/* Current argument. */
706   dkChar const		*en;			/* File name. */
707   dkChar		 bu[DK3_MAX_PATH];	/* Buffer input file name. */
708   dk3_stat_t		 stb;			/* Stat inf for input file. */
709   dk3_stat_t const	*es;			/* Stat inf for output file. */
710   dk3_dir_t		*fne;			/* File name expander. */
711   int			 i;			/* Current argument index. */
712   int			 found = 0;		/* Flag: Matching file found. */
713 
714   nfn = dk3opt_get_num_args(j->opt);
715   if(nfn > 0) {
716     for(i = 0; i < nfn; i++) {
717       arg = dk3opt_get_arg(j->opt, i);
718       if(arg) {
719         if(dk3str_len(arg) < DK3_SIZEOF(bu,dkChar)) {
720 	  dk3str_cpy_not_overlapped(bu, arg);
721 	  dk3str_correct_filename(bu);
722 	  if(dk3sf_must_expand(bu)) {
723 	    fne = dk3dir_fne_open_app(bu, j->app);
724 	    if(fne) {
725 	      found = 0;
726 	      while(dk3dir_get_next_file(fne)) {
727 	        en = dk3dir_get_fullname(fne);
728 		es = dk3dir_get_stat(fne);
729 		if((en) && (es)) {
730 		  switch((es->ft) & (~(DK3_FT_SYMLINK))) {
731 		    case DK3_FT_REGULAR: {
732 		      found = 1;
733 		      dkct_run_for_file(j, en);
734 		    } break;
735 		    default: {
736 		      /* Illegal file type! */
737 		      dk3app_log_3(j->app, DK3_LL_ERROR, j->msg, 2, 3, en);
738 		      j->exval = DKT_RESULT_ERR_INPUT;
739 		    } break;
740 		  }
741 		}
742 	      }
743 	      while(dk3dir_get_next_directory(fne)) {
744 	        en = dk3dir_get_fullname(fne);
745 		es = dk3dir_get_stat(fne);
746 		if((en) && (es)) {
747 		  switch((es->ft) & (~(DK3_FT_SYMLINK))) {
748 		    case DK3_FT_DIRECTORY: {
749 		      dkct_run_for_directory_test_current(j, en);
750 		    } break;
751 		    default: {
752 		      /* Illegal file type! */
753 		      dk3app_log_3(j->app, DK3_LL_ERROR, j->msg, 2, 3, en);
754 		      j->exval = DKT_RESULT_ERR_INPUT;
755 		    } break;
756 		  }
757 		}
758 	      }
759 	      if(!found) {
760 	        /* ERROR: No such file or directory! */
761 		dk3app_log_i3(j->app, DK3_LL_ERROR, 215, 216, bu);
762 		j->exval = DKT_RESULT_ERR_FILENAME;
763 	      }
764 	      dk3dir_close(fne);
765 	    } else {
766 	      /* ERROR: No fne */
767 	      j->exval = DKT_RESULT_ERR_MEMORY;
768 	    }
769 	  } else {
770 	    if(dk3sf_stat_app(&stb, bu, j->app)) {
771 	      switch((stb.ft) & (~(DK3_FT_SYMLINK))) {
772 	        case DK3_FT_REGULAR: {
773 		  dkct_run_for_file(j, bu);
774 		} break;
775 		case DK3_FT_DIRECTORY: {
776 		  dkct_run_for_directory_test_current(j, bu);
777 		} break;
778 		default: {
779 		  /* ERROR: Illegal file type! */
780 		  dk3app_log_3(j->app, DK3_LL_ERROR, j->msg, 2, 3, bu);
781 		  j->exval = DKT_RESULT_ERR_FILENAME;
782 		} break;
783 	      }
784 	    } else {
785 	      /* ERROR: No such file or directory! */
786 	      j->exval = DKT_RESULT_ERR_FILENAME;
787 	    }
788 	  }
789 	} else {
790 	  /* ERROR: Name too long! */
791 	  dk3app_log_i3(j->app, DK3_LL_ERROR, 65, 66, arg);
792 	  j->exval = DKT_RESULT_ERR_FILENAME;
793 	}
794       } else {
795         /* BUG */
796 	j->exval = DKT_RESULT_ERR_UNSPECIFIC;
797       }
798     }
799   } else {
800     j->curdi = 1;
801     dkct_run_for_directory(j, j->sCwd, 0);
802   }
803 }
804 
805 
806 
807 /**	Show license conditions.
808 	@param	j	Job structure.
809 */
810 static
811 void
dkct_show_license(void)812 dkct_show_license(void)
813 {
814   dkChar const * const *sptr;	/* Pointer to traverse text. */
815 
816   sptr = dkct_license;
817   dk3sf_initialize_stdout();
818   while(*sptr) {
819     dk3sf_fputs(*(sptr++), stdout);
820     dk3sf_fputc(dkT('\n'), stdout);
821   }
822 }
823 
824 
825 
826 /**	The main() function.
827 	@param	argc	Number of command line arguments.
828 	@param	argv	Command line arguments array.
829 	@return	0 on success, any other value indicates an error.
830 */
831 DK3_MAIN
832 {
833   int		exval = 0;		/* Exit status code. */
834   DKCT_J	j;			/* Job structure. */
835   dkChar	cd[DK3_MAX_PATH];	/* Buffer for current directory. */
836 
837 
838   dkct_job_init(&j);
839   j.app = dk3app_open_command(
840     argc, (dkChar const * const *)argv, dkct_group_name
841   );
842   if(j.app) {
843     j.msg = dk3app_messages(
844       j.app,
845       dkct_str_get_string_table_file_name(),
846       (dkChar const **)dkct_str_get_message_texts()
847     );
848     j.nlc = dkct_not_localized;
849     if(dk3sf_getcwd_app(cd, DK3_SIZEOF(cd,dkChar), j.app)) {
850       j.sCwd = cd;
851       if(dkct_process_arguments(&j)) {
852         j.exval = DKT_RESULT_OK;
853 	if(j.cmd) {
854 	  /* Help, version, license */
855 	  if((j.cmd) & DK3_APP_CMD_VERSION) {
856 	    dk3sf_initialize_stdout();
857 	    dk3sf_fputs(dkct_version, stdout);
858 	    dk3sf_fputc(dkT('\n'), stdout);
859 	  }
860 	  if((j.cmd) & DK3_APP_CMD_LICENSE) {
861 	    dkct_show_license();
862 	  }
863 	  if((j.cmd) & DK3_APP_CMD_HELP) {
864 	    dk3app_help(j.app, dkct_help_file_name, dkct_help_text);
865 	  }
866 	} else {
867 	  dkct_run(&j);
868 	}
869       }
870     }
871   }
872   exval = j.exval;
873   dkct_job_cleanup(&j);
874 
875 
876   fflush(stdout);
877   exit(exval); return exval;
878 }
879 
880 
881 
882 /* vim: set ai sw=2 : */
883 
884