1 // Copyright 2020 Michael Reilly (mreilly@resiliware.com).
2 //
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions
5 // are met:
6 // 1. Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // 2. Redistributions in binary form must reproduce the above copyright
9 // notice, this list of conditions and the following disclaimer in the
10 // documentation and/or other materials provided with the distribution.
11 // 3. Neither the names of the copyright holders nor the names of the
12 // contributors may be used to endorse or promote products derived from
13 // this software without specific prior written permission.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 // ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
18 // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
19 // OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27 #define SRCNAME "hexpeek_settings.c"
28
29 #include <hexpeek.h>
30
31 #include <stdlib.h>
32 #include <libgen.h>
33 #include <limits.h>
34 #include <string.h>
35 #include <fcntl.h>
36 #include <errno.h>
37
outputWidth(int part,int formode,hoff_t linewh)38 hoff_t outputWidth(int part, int formode, hoff_t linewh)
39 {
40 hoff_t result = 0;
41
42 switch(part)
43 {
44 case 0:
45 if(Params.margin)
46 result += (Params.margin + strlen(MarginPost));
47 break;
48 case 1:
49 if(Params.mode_groups[formode])
50 {
51 hoff_t seps = linewh / Params.mode_groups[formode] +
52 (linewh % Params.mode_groups[formode] ? 1 : 0);
53 if(seps > 0)
54 result += (strlen(GroupPre(0)) + strlen(GroupTerm));
55 seps--;
56 if(seps > 0)
57 result += (strlen(GroupPre(1)) + strlen(GroupTerm)) * seps;
58 }
59 else
60 {
61 result += strlen(GroupPre(0));
62 }
63 result += linewh * MODE_CHCNT(formode);
64 break;
65 case 2:
66 if(Params.print_text)
67 result += 2 + linewh;
68 break;
69 default:
70 die();
71 }
72
73 assert(result >= 0);
74 return result;
75 }
76
totalWidth(int formode,hoff_t linewh)77 static hoff_t totalWidth(int formode, hoff_t linewh)
78 {
79 hoff_t result = 0;
80 for(int part = 0; part < 3; part++)
81 result += outputWidth(part, formode, linewh);
82 return result;
83 }
84
ascertainShared(char const * str,int * subtype,char const ** post)85 int ascertainShared(char const *str, int *subtype, char const **post)
86 {
87 assert(str);
88
89 int cmd = CMD_NONE;
90 int subtp = 0;
91
92 if(strnconsume(&str, "endianb", 7) == 0)
93 {
94 cmd = CMD_ENDIAN;
95 subtp = 1;
96 }
97 else if(strnconsume(&str, "endianl", 7) == 0)
98 {
99 cmd = CMD_ENDIAN;
100 subtp = -1;
101 }
102 else if(strnconsume(&str, "hexl", 4) == 0)
103 {
104 cmd = CMD_HEX;
105 subtp = 1;
106 }
107 else if(strnconsume(&str, "hexu", 4) == 0)
108 {
109 cmd = CMD_HEX;
110 subtp = -1;
111 }
112 else if(strnconsume(&str, "hex", 3) == 0)
113 cmd = CMD_HEX;
114 else if(strnconsume(&str, "bits", 4) == 0)
115 cmd = CMD_BITS;
116 else if(strnconsume(&str, "rlen", 4) == 0)
117 cmd = CMD_RLEN;
118 else if(strnconsume(&str, "slen", 4) == 0)
119 cmd = CMD_SLEN;
120 else if(strnconsume(&str, "line", 4) == 0)
121 cmd = CMD_LINE;
122 else if(strnconsume(&str, "cols", 4) == 0)
123 cmd = CMD_COLS;
124 else if(strnconsume(&str, "group", 5) == 0)
125 cmd = CMD_GROUP;
126 else if(strnconsume(&str, "margin", 6) == 0)
127 cmd = CMD_MARGIN;
128 else if(strnconsume(&str, "scalar", 6) == 0)
129 cmd = CMD_SCALAR;
130 else if(strnconsume(&str, "prefix", 6) == 0)
131 {
132 cmd = CMD_PREFIX;
133 subtp = 1;
134 }
135 else if(strnconsume(&str, "+prefix", 7) == 0)
136 {
137 cmd = CMD_PREFIX;
138 subtp = -1;
139 }
140 else if(strnconsume(&str, "autoskip", 8) == 0)
141 {
142 cmd = CMD_AUTOSKIP;
143 subtp = 1;
144 }
145 else if(strnconsume(&str, "+autoskip", 9) == 0)
146 {
147 cmd = CMD_AUTOSKIP;
148 subtp = -1;
149 }
150 else if(strnconsume(&str, "diffskip", 8) == 0)
151 {
152 cmd = CMD_DIFFSKIP;
153 subtp = 1;
154 }
155 else if(strnconsume(&str, "+diffskip", 9) == 0)
156 {
157 cmd = CMD_DIFFSKIP;
158 subtp = -1;
159 }
160 else if(strnconsume(&str, "text", 4) == 0)
161 {
162 cmd = CMD_TEXT;
163 if(strnconsume(&str, "=ascii", 6) == 0)
164 subtp = CODEPAGE_ASCII;
165 else if(strnconsume(&str, "=ebcdic", 7) == 0)
166 subtp = CODEPAGE_EBCDIC;
167 else
168 subtp = CODEPAGE_NIL;
169 }
170 else if(strnconsume(&str, "+text", 5) == 0)
171 {
172 cmd = CMD_TEXT;
173 if(strnconsume(&str, "=ascii", 6) == 0)
174 subtp = -CODEPAGE_ASCII;
175 else if(strnconsume(&str, "=ebcdic", 7) == 0)
176 subtp = -CODEPAGE_EBCDIC;
177 else
178 subtp = -CODEPAGE_NIL;
179 }
180 else if(strnconsume(&str, "ruler", 5) == 0)
181 {
182 cmd = CMD_RULER;
183 subtp = 1;
184 }
185 else if(strnconsume(&str, "+ruler", 6) == 0)
186 {
187 cmd = CMD_RULER;
188 subtp = -1;
189 }
190
191 if(cmd != CMD_NONE)
192 {
193 if(subtype)
194 *subtype = subtp;
195 if(post)
196 *post = str;
197 }
198 return cmd;
199 }
200
setModeVar(hoff_t * arr,int formode,hoff_t value)201 static rc_t setModeVar(hoff_t *arr, int formode, hoff_t value)
202 {
203 rc_t rc = RC_UNSPEC;
204
205 if(arr == Params.mode_lines)
206 {
207 if(value > MAXW_LINE)
208 {
209 rc = RC_USER;
210 prerr("line width may not exceed " MS(MAXW_LINE) " octets\n");
211 goto end;
212 }
213 }
214 if(arr == Params.mode_groups)
215 {
216 if(value > MAXW_GROUP)
217 {
218 rc = RC_USER;
219 prerr("group width may not exceed " MS(MAXW_GROUP) " octets\n");
220 goto end;
221 }
222 }
223
224 if(formode < 0)
225 {
226 for(formode = 0; formode < MODE_COUNT; formode++)
227 arr[formode] = value;
228 }
229 else
230 {
231 assert(formode < MODE_COUNT);
232 arr[formode] = value;
233 }
234
235 rc = RC_OK;
236
237 end:
238 return rc;
239 }
240
processShared(int cmd,int subtype,char const * arg,int formode)241 rc_t processShared(int cmd, int subtype, char const *arg, int formode)
242 {
243 rc_t rc = RC_UNSPEC;
244 hoff_t tmph = 0;
245
246 if(cmd == CMD_ENDIAN)
247 {
248 Params.endian_big = (subtype > 0);
249 }
250 else if(cmd == CMD_HEX)
251 {
252 Params.disp_mode = MODE_HEX;
253 if(subtype)
254 Params.hexlower = (subtype > 0);
255 }
256 else if(cmd == CMD_BITS)
257 {
258 Params.disp_mode = MODE_BITS;
259 }
260 else if(cmd == CMD_RLEN)
261 {
262 if((rc = strtosz(arg, &tmph)))
263 goto end;
264 if((rc = setModeVar(Params.mode_print_defs, formode, tmph)))
265 goto end;
266 }
267 else if(cmd == CMD_SLEN)
268 {
269 if((rc = strtosz(arg, &tmph)))
270 goto end;
271 if((rc = setModeVar(Params.mode_search_defs, formode, tmph)))
272 goto end;
273 }
274 else if(cmd == CMD_LINE)
275 {
276 if((rc = strtosz(arg, &tmph)))
277 goto end;
278 if((rc = setModeVar(Params.mode_lines, formode, tmph)))
279 goto end;
280 }
281 else if(cmd == CMD_COLS)
282 {
283 if((rc = strtosz(arg, &tmph)))
284 goto end;
285 if((rc = setModeVar(Params.mode_lines, formode, tmph)))
286 goto end;
287 if((rc = setModeVar(Params.mode_print_defs, formode, tmph)))
288 goto end;
289 if((rc = setModeVar(Params.mode_search_defs, formode, tmph)))
290 goto end;
291 }
292 else if(cmd == CMD_GROUP)
293 {
294 if((rc = strtosz(arg, &tmph)))
295 goto end;
296 if((rc = setModeVar(Params.mode_groups, formode, tmph)))
297 goto end;
298 }
299 else if(cmd == CMD_MARGIN)
300 {
301 assert(arg);
302 if(streq(arg, "full"))
303 {
304 Params.margin = HOFF_HEX_FULL_WIDTH;
305 }
306 else
307 {
308 rc = strtosz(arg, &tmph);
309 checkrc(rc);
310 // Argument is taken in octet length, but saved in char length
311 if(tmph >= INT_MAX / MODE_CHCNT(MODE_HEX))
312 {
313 rc = RC_USER;
314 prerr("excessive margin width\n");
315 goto end;
316 }
317 Params.margin = MODE_CHCNT(MODE_HEX) * (int)tmph;
318 }
319 }
320 else if(cmd == CMD_SCALAR)
321 {
322 assert(arg);
323 if(streq(arg, MS(DEF_SCALAR_BASE)))
324 Params.scalar_base = DEF_SCALAR_BASE;
325 else if(streq(arg, "0"))
326 Params.scalar_base = 0;
327 else
328 {
329 rc = RC_USER;
330 prerr("invalid argument to scalar\n");
331 goto end;
332 }
333 }
334 else if(cmd == CMD_PREFIX)
335 {
336 Params.print_prefix = (subtype > 0);
337 }
338 else if(cmd == CMD_AUTOSKIP)
339 {
340 Params.autoskip = (subtype > 0);
341 }
342 else if(cmd == CMD_DIFFSKIP)
343 {
344 Params.diffskip = (subtype > 0);
345 }
346 else if(cmd == CMD_TEXT)
347 {
348 Params.print_text = (subtype > 0);
349 subtype = abs(subtype);
350 if(subtype != CODEPAGE_NIL)
351 Params.text_encoding = subtype;
352 }
353 else if(cmd == CMD_RULER)
354 {
355 Params.ruler = (subtype > 0);
356 }
357 else
358 {
359 rc = RC_NIL;
360 goto end;
361 }
362
363 rc = RC_OK;
364
365 end:
366 return rc;
367 }
368
generateCommand(int op,char * at,char * len)369 void generateCommand(int op, char *at, char *len)
370 {
371 traceEntry("%d, '%s', '%s'", op, at, len);
372
373 assert(op > 0);
374 assert( ! GeneratedCommand_mal);
375 assert( ! Params.command);
376
377 if( ! at)
378 at = "0";
379
380 size_t s_len = 0;
381 s_len += 3; // "$0@"
382 s_len += strlen(at); // <AT>
383 s_len += 1; // "," or ":"
384 if(len)
385 s_len += strlen(len); // <LEN>
386 else
387 s_len += 3; // "max"
388 s_len += 1; // "~" or "\0"
389
390 s_len *= op;
391
392 GeneratedCommand_mal = Malloc(s_len);
393
394 for(int ix = 0; ix < op; ix++)
395 {
396 if(ix == 0)
397 strcat(GeneratedCommand_mal, "$0@");
398 else
399 strcat(GeneratedCommand_mal, "~$1@");
400 strcat(GeneratedCommand_mal, at);
401 if(len)
402 {
403 strcat(GeneratedCommand_mal, ",");
404 strcat(GeneratedCommand_mal, len);
405 }
406 else
407 strcat(GeneratedCommand_mal, ":max");
408 }
409
410 GeneratedCommand_mal[s_len - 1] = '\0';
411 Params.command = GeneratedCommand_mal;
412
413 traceExit("'%s'", Params.command);
414 }
415
parseDescriptor(char const * string)416 int parseDescriptor(char const *string)
417 {
418 char *endptr = NULL;
419 long tmpl = strtol(string, &endptr, 10); // always decimal
420 if(endptr == string || *endptr != '\0' || tmpl < 0 || tmpl > INT_MAX)
421 return -1;
422 return (int)tmpl;
423 }
424
425 // Macros for simple, but unavoidable, repetition
426 #define advanceArgs() \
427 if(ix + 1 >= argc) \
428 { \
429 rc = RC_USER; \
430 prerr("missing argument to '%s'\n", argv[ix]); \
431 goto end; \
432 } \
433 ix++;
434 #define setupDump() \
435 subsequent_open_flags = O_RDONLY; \
436 do_dump = true;
437 #define setupPack() \
438 subsequent_open_flags = O_RDONLY; \
439 Params.do_pack = true;
440 #define setupDiff() \
441 subsequent_open_flags = O_RDONLY; \
442 do_diff = true;
443
444 // Only sets members of Params indicated by arguments, leaves other members at
445 // their initial values. Do not pass read-only strings in argv.
parseArgv(int argc,char ** argv)446 rc_t parseArgv(int argc, char **argv)
447 {
448 rc_t rc = RC_UNSPEC;
449 int ix = 0, counter = 0;
450 int subsequent_open_flags = -1, file_count = 0, pending = -1;
451 bool flags_done = false, do_dump = false, do_diff = false;
452 bool line_z = false, group_z = false;
453 char *cmd_at = NULL, *cmd_len = NULL, *found = NULL;
454
455 assert(argv);
456
457 // Alternate invocations
458 char const *invok = basename(argv[0]);
459 if(streq(invok, viwNM))
460 {
461 subsequent_open_flags = O_RDONLY;
462 }
463 else if(streq(invok, DmpNM))
464 {
465 setupDump();
466 }
467 else if(streq(invok, pckNM))
468 {
469 setupPack();
470 }
471 else if(streq(invok, dffNM))
472 {
473 setupDiff();
474 }
475
476 // Flag parser
477 for(ix = 1; ix < argc; )
478 {
479 bool isfd = false;
480 if(flags_done)
481 goto process_infile;
482
483 rc = plugin_argv(argc, argv, &ix);
484 if(rc == RC_OK)
485 continue;
486 else if(rc != RC_NIL)
487 goto end;
488
489 if(streq(argv[ix], "-dump"))
490 {
491 setupDump();
492 }
493 else if(streq(argv[ix], "-pack"))
494 {
495 setupPack();
496 }
497 else if(streq(argv[ix], "-diff"))
498 {
499 setupDiff();
500 }
501 else if(streq(argv[ix], "-s"))
502 {
503 advanceArgs();
504 cmd_at = argv[ix];
505 }
506 else if(streq(argv[ix], "-l"))
507 {
508 advanceArgs();
509 cmd_len = argv[ix];
510 }
511 else if(streq(argv[ix], "-r"))
512 {
513 subsequent_open_flags = O_RDONLY;
514 pending = file_count;
515 }
516 else if(streq(argv[ix], "-w"))
517 {
518 subsequent_open_flags = O_RDWR | O_CREAT;
519 pending = file_count;
520 }
521 else if(streq(argv[ix], "-W"))
522 {
523 subsequent_open_flags = O_RDWR;
524 pending = file_count;
525 }
526 else if(streq(argv[ix], "-ik"))
527 {
528 Params.allow_ik = true;
529 }
530 else if(streq(argv[ix], "+ik"))
531 {
532 Params.allow_ik = false;
533 }
534 else if(streq(argv[ix], "-x"))
535 {
536 advanceArgs();
537 Params.command = argv[ix];
538 }
539 else if(streq(argv[ix], "-o"))
540 {
541 int tmpfd = -1;
542 advanceArgs();
543 if(streq(argv[ix], "-d"))
544 {
545 advanceArgs();
546 tmpfd = parseDescriptor(argv[ix]);
547 if(tmpfd < 0)
548 {
549 rc = RC_USER;
550 prerr("bad input to '-o -d'\n");
551 goto end;
552 }
553 }
554 else
555 {
556 int o_flags = O_WRONLY | O_CREAT;
557 if( ! Params.do_pack)
558 o_flags |= O_TRUNC;
559 rc = hexpeek_open(argv[ix], o_flags, PERM, &tmpfd);
560 if(rc)
561 goto end;
562 }
563 if(tmpfd != STDOUT_FILENO)
564 assert(dup2(tmpfd, STDOUT_FILENO) == STDOUT_FILENO);
565 }
566 else if(streq(argv[ix], "+lineterm"))
567 {
568 Params.line_term = "";
569 }
570 else if(streq(argv[ix], "-format"))
571 {
572 advanceArgs();
573 if(strnconsume((char const **)&argv[ix],
574 GroupFmtLiTern, strlen(GroupFmtLiTern)) == 0)
575 Params.group_pre[0] = argv[ix] + 1;
576 else
577 Params.group_pre[0] = argv[ix];
578 Params.group_pre[1] = argv[ix];
579 char *first = NULL;
580 for(found = argv[ix]; ; )
581 {
582 found = strchr(found, GroupFmtGroup[0]);
583 if( ! found)
584 break;
585 if(strncmp(found, GroupFmtGroup, strlen(GroupFmtGroup)) == 0)
586 {
587 if(first)
588 {
589 rc = RC_USER;
590 prerr("duplicate '%s'\n", GroupFmtGroup);
591 goto end;
592 }
593 first = found;
594 found += strlen(GroupFmtGroup);
595 }
596 else if(found[1] == '%')
597 {
598 memmove(found, found + 1, strlen(found));
599 found++;
600 }
601 else
602 {
603 rc = RC_USER;
604 prerr("unrecognized format specifier\n");
605 goto end;
606 }
607 }
608 if( ! first)
609 {
610 rc = RC_USER;
611 prerr("format string must contain '%s'\n", GroupFmtGroup);
612 goto end;
613 }
614 *first = '\0';
615 Params.group_term = first + strlen(GroupFmtGroup);
616 }
617 else if(streq(argv[ix], "-pedantic"))
618 {
619 Params.infer = false;
620 Params.tolerate_eof = false;
621 }
622 else if(streq(argv[ix], "+pedantic"))
623 {
624 Params.infer = true;
625 Params.tolerate_eof = true;
626 }
627 else if(streq(argv[ix], "-strict"))
628 {
629 Params.fail_strict = true;
630 }
631 else if(streq(argv[ix], "+strict"))
632 {
633 Params.fail_strict = false;
634 }
635 else if(streq(argv[ix], "-unique"))
636 {
637 Params.assume_unique_infiles = true;
638 }
639 else if(streq(argv[ix], "+tty"))
640 {
641 Params.assume_ttys = 0;
642 }
643 else if(streq(argv[ix], "-backup"))
644 {
645 advanceArgs();
646 if(streq(argv[ix], "sync"))
647 Params.backup_sync = true;
648 else if(streq(argv[ix], "max"))
649 Params.backup_depth = MAX_BACKUP_DEPTH;
650 else
651 {
652 char *endptr = NULL;
653 long tmpl = strtol(argv[ix], &endptr, Params.scalar_base);
654 if(endptr != argv[ix] && *endptr == '\0' &&
655 tmpl >= 0 && tmpl <= MAX_BACKUP_DEPTH)
656 {
657 Params.backup_depth = tmpl;
658 }
659 else
660 {
661 rc = RC_USER;
662 prerr("invalid argument to -backup\n");
663 goto end;
664 }
665 }
666 }
667 else if(streq(argv[ix], "-recover"))
668 {
669 if(Params.recover_interactive)
670 {
671 rc = RC_USER;
672 prerr("duplicate -recover flag\n");
673 goto end;
674 }
675 Params.recover_interactive = true;
676 }
677 else if(streq(argv[ix], "-AutoRecover"))
678 {
679 if(Params.recover_auto)
680 {
681 rc = RC_USER;
682 prerr("duplicate -AutoRecover flag\n");
683 goto end;
684 }
685 Params.recover_auto = true;
686 }
687 #ifdef HEXPEEK_TRACE
688 else if(streq(argv[ix], "-trace"))
689 {
690 advanceArgs();
691 Params.trace_fp = fopen(argv[ix], "w");
692 if( ! Params.trace_fp)
693 {
694 rc = RC_CRIT;
695 prerr("error opening file \"%s\": %s\n", cleanstring(argv[ix]),
696 strerror(errno));
697 goto end;
698 }
699 trace("TRACE START\n");
700 trace("Invocation:");
701 for(int trace_idx = 0; trace_idx < argc; trace_idx++)
702 fprintf(Params.trace_fp, " '%s'", argv[trace_idx]);
703 fprintf(Params.trace_fp, "\n");
704 trace("HOFF_MAX = " TRC_hoff "\n", trchoff(HOFF_MAX));
705 }
706 #endif
707 else if(streq(argv[ix], "-p"))
708 {
709 rc = processShared(CMD_COLS, 0, "0", -1);
710 checkrc(rc);
711 rc = processShared(CMD_GROUP, 0, "0", -1);
712 checkrc(rc);
713 Params.margin = 0;
714 Params.autoskip = false;
715 Params.diffskip = false;
716 Params.print_text = false;
717 Params.ruler = false;
718 }
719 else if(streq(argv[ix], "-d"))
720 {
721 advanceArgs();
722 isfd = true;
723 goto process_infile;
724 }
725 else if(streq(argv[ix], "--"))
726 {
727 flags_done = true;
728 }
729 else if((*argv[ix] == '-' || *argv[ix] == '+') && argv[ix][1] != '\0')
730 {
731 int tmpcmd = CMD_NONE, tmpst = 0;
732 char const *postflag = NULL;
733 if(*argv[ix] == '+')
734 tmpcmd = ascertainShared(argv[ix], &tmpst, &postflag);
735 else
736 tmpcmd = ascertainShared(argv[ix] + 1, &tmpst, &postflag);
737 if(tmpcmd == CMD_NONE)
738 {
739 // No match, try short flags
740 if(streq(argv[ix], "-b"))
741 tmpcmd = CMD_BITS;
742 else if(streq(argv[ix], "-c"))
743 tmpcmd = CMD_COLS;
744 else if(streq(argv[ix], "-g"))
745 tmpcmd = CMD_GROUP;
746 }
747 if(tmpcmd == CMD_NONE)
748 {
749 rc = RC_USER;
750 prerr("unrecognized flag '%s'\n", argv[ix]);
751 goto end;
752 }
753 else if(postflag && *postflag != '\0')
754 {
755 rc = RC_USER;
756 prerr("trailing text to setting flag\n");
757 goto end;
758 }
759 else
760 {
761 char const *tmparg = NULL;
762 switch(tmpcmd)
763 {
764 case CMD_RLEN:
765 case CMD_SLEN:
766 case CMD_LINE:
767 case CMD_COLS:
768 case CMD_GROUP:
769 case CMD_MARGIN:
770 case CMD_SCALAR:
771 advanceArgs();
772 tmparg = argv[ix];
773 break;
774 }
775 rc = processShared(tmpcmd, tmpst, tmparg, -1);
776 checkrc(rc);
777 }
778 }
779 else
780 {
781 process_infile:
782 if(file_count >= MAX_INFILES)
783 {
784 rc = RC_USER;
785 prerr("too many infiles\n");
786 goto end;
787 }
788 if(isfd)
789 {
790 // non-path infile from -d
791 Params.infiles[file_count].fd = parseDescriptor(argv[ix]);
792 if(Params.infiles[file_count].fd < 0)
793 {
794 rc = RC_USER;
795 prerr("bad input to '-d'\n");
796 goto end;
797 }
798 }
799 else
800 {
801 Params.infiles[file_count].path = argv[ix];
802 }
803 Params.infiles[file_count].open_flags = subsequent_open_flags;
804 file_count++;
805 }
806
807 ix++;
808 }
809
810 // Check hanging flags
811 if(pending >= file_count)
812 {
813 rc = RC_USER;
814 prerr("-r, -w, or -W after infiles has no effect!\n");
815 goto end;
816 }
817
818 // Special operations
819 if((cmd_at || cmd_len) && ! do_diff)
820 do_dump = true;
821 if(Params.command)
822 counter++;
823 if(do_dump)
824 counter++;
825 if(do_diff)
826 counter++;
827 if(Params.do_pack)
828 counter++;
829 if(Params.recover_interactive || Params.recover_auto)
830 counter++;
831 if(counter > 1)
832 {
833 rc = RC_USER;
834 prerr("more than one of -x, -dump, -diff, -pack, and -recover"
835 " specified\n");
836 goto end;
837 }
838 if(do_dump)
839 {
840 if(file_count > 1)
841 {
842 rc = RC_USER;
843 prerr("cannot dump more than one file\n");
844 goto end;
845 }
846 generateCommand(1, cmd_at, cmd_len);
847 }
848 else if(Params.do_pack)
849 {
850 if(file_count > 1)
851 {
852 rc = RC_USER;
853 prerr("cannot pack more than one input file\n");
854 goto end;
855 }
856 }
857 else if(do_diff)
858 {
859 if(file_count != 2)
860 {
861 rc = RC_USER;
862 prerr("need two files to diff\n");
863 goto end;
864 }
865 generateCommand(2, cmd_at, cmd_len);
866 }
867
868 // Recovery mode
869 if(Params.recover_interactive && Params.recover_auto)
870 {
871 rc = RC_USER;
872 prerr("-recover and -AutoRecover conflict\n");
873 goto end;
874 }
875 if(Params.recover_interactive || Params.recover_auto)
876 {
877 if(file_count > 1)
878 {
879 rc = RC_USER;
880 prerr("only one file can be recovered at a time\n");
881 goto end;
882 }
883 if(Params.backup_depth > 0)
884 {
885 rc = RC_USER;
886 prerr("Recovery mode and backup depth > 0 conflict\n");
887 goto end;
888 }
889 Params.backup_depth = 0;
890 if(Params.infiles[0].open_flags < 0)
891 {
892 Params.infiles[0].open_flags = O_RDWR;
893 }
894 else if(Params.infiles[0].open_flags != O_RDWR)
895 {
896 rc = RC_USER;
897 prerr("Recovery mode requires write permission to data file\n");
898 goto end;
899 }
900 }
901 // Set default open flags if not given
902 else
903 {
904 if(Params.backup_depth < 0)
905 Params.backup_depth = DEFAULT_BACKUP_DEPTH;
906 for(int fi = 0; fi < MAX_INFILES; fi++)
907 {
908 if(Params.infiles[fi].path)
909 {
910 if(Params.infiles[fi].open_flags < 0)
911 {
912 if(access(Params.infiles[fi].path, F_OK) == 0 &&
913 access(Params.infiles[fi].path, W_OK))
914 Params.infiles[fi].open_flags = O_RDONLY;
915 else
916 Params.infiles[fi].open_flags = O_RDWR | O_CREAT;
917 }
918 }
919 else if(Params.infiles[fi].open_flags < 0)
920 {
921 Params.infiles[fi].open_flags =
922 fcntl(Params.infiles[fi].fd, F_GETFL);
923 }
924 }
925 }
926
927 // Set default print format variables if not given
928 if(Params.margin < 0)
929 Params.margin = HOFF_HEX_DEFAULT_WIDTH;
930 for(int md = 0; md < MODE_COUNT; md++)
931 {
932 hoff_t divisor = (do_diff ? 2 : 1);
933 for(hoff_t guess = 0x20; guess > 1; guess /= 2)
934 {
935 if(totalWidth(md, guess) <= TERMINAL_WIDTH)
936 {
937 if(Params.mode_print_defs[md] < 0)
938 Params.mode_print_defs[md] = guess / divisor;
939 if(Params.mode_search_defs[md] < 0)
940 Params.mode_search_defs[md] = guess / divisor;
941 if(Params.mode_lines[md] < 0)
942 Params.mode_lines[md] = guess / divisor;
943 break;
944 }
945 }
946 }
947
948 // Check if line or group width is zero
949 for(int md = 0; md < MODE_COUNT; md++)
950 {
951 if(Params.mode_lines[md] == 0)
952 line_z = true;
953 if(Params.mode_groups[md] == 0)
954 group_z = true;
955 }
956
957 // Set other defaults
958 if(Params.autoskip < 0)
959 Params.autoskip = interactive();
960 if(Params.print_text < 0 && ! line_z)
961 Params.print_text = interactive();
962 if(Params.fail_strict < 0)
963 Params.fail_strict = ! interactive();
964 #ifdef HEXPEEK_EDITABLE_CONSOLE
965 if(Params.editable_console < 0)
966 Params.editable_console = interactive();
967 #endif
968
969 // Non-critical warnings
970 if(line_z && Params.print_text)
971 prwarn("zero line width disables text output\n");
972 if(group_z && ! Params.endian_big)
973 prwarn("zero group width disables little endian mode\n");
974
975 rc = RC_OK;
976
977 end:
978 if(rc && ix < argc)
979 {
980 prerr("error while processing argument '%s' at position %d\n",
981 argv[ix], ix);
982 }
983 if(Params.mode_print_defs[MODE_HEX] < 0)
984 Params.mode_print_defs[MODE_HEX] = 0x20;
985 if(Params.mode_search_defs[MODE_HEX] < 0)
986 Params.mode_search_defs[MODE_HEX] = 0x20;
987 if(Params.mode_lines[MODE_HEX] < 0)
988 Params.mode_lines[MODE_HEX] = 0x20;
989 if(Params.mode_print_defs[MODE_BITS] < 0)
990 Params.mode_print_defs[MODE_BITS] = 0x8;
991 if(Params.mode_search_defs[MODE_BITS] < 0)
992 Params.mode_search_defs[MODE_BITS] = 0x8;
993 if(Params.mode_lines[MODE_BITS] < 0)
994 Params.mode_lines[MODE_BITS] = 0x8;
995 return rc;
996 }
997