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