| 1 | /* depend: */ |
| 2 | /* cflags: */ |
| 3 | /* linker: debug.o */ |
| 4 | |
| 5 | #include <assert.h> |
| 6 | #include <limits.h> |
| 7 | #include <malloc.h> |
| 8 | #include <stdio.h> |
| 9 | #include <stdlib.h> |
| 10 | #include <string.h> |
| 11 | |
| 12 | #include "debug.h" |
| 13 | |
| 14 | /* macros */ |
| 15 | |
| 16 | #define CEIL(x, y) (((x) + (y) - 1) / (y)) |
| 17 | #define MIN(x, y) (((x) < (y)) ? (x) : (y)) |
| 18 | #define MAX(x, y) (((x) > (y)) ? (x) : (y)) |
| 19 | |
| 20 | //#define BUFFERSIZE 4096 |
| 21 | #define BUFFERSIZE 256 |
| 22 | #define NBCOLS 8 |
| 23 | #define NBDIGITS 6 |
| 24 | #define SEQLEN 32 |
| 25 | |
| 26 | /* gobal variables */ |
| 27 | |
| 28 | int nbcols = NBCOLS; |
| 29 | int nbdigits = NBDIGITS; |
| 30 | int offset = 0; |
| 31 | |
| 32 | char buffer[BUFFERSIZE] = {0}; |
| 33 | FILE *fin = NULL; |
| 34 | long int addrfile = 0; |
| 35 | FILE *fout = NULL; |
| 36 | char *progname = NULL; |
| 37 | |
| 38 | /* type definitions */ |
| 39 | |
| 40 | typedef struct { |
| 41 | char *sequence; |
| 42 | char bytes[SEQLEN]; |
| 43 | int length; |
| 44 | } sequence_t; |
| 45 | |
| 46 | /* help function */ |
| 47 | |
| 48 | int usage (int ret) |
| 49 | { |
| 50 | FILE *fd = ret ? stderr : stdout; |
| 51 | fprintf (fd, "usage: %s [-i file] [-h] [-n nbcols] [-o file] [-v]\n", progname); |
| 52 | fprintf (fd, " -i: input file\n"); |
| 53 | fprintf (fd, " -h: help message\n"); |
| 54 | fprintf (fd, " -n: number of columns\n"); |
| 55 | fprintf (fd, " -e: commands\n"); |
| 56 | fprintf (fd, " -o: output file\n"); |
| 57 | fprintf (fd, " -v: verbose level (%d)\n", verbose); |
| 58 | fprintf (fd, "\n"); |
| 59 | fprintf (fd, "commands: [/hstr/|addr|+nb] [a hstr] [d nb|-] [i hstr] [p nb|-] [s/h1/h2/[g]]\n"); |
| 60 | fprintf (fd, " addr: move to address (0... octal, [1-9]... deci, 0x... hexa)\n"); |
| 61 | fprintf (fd, " +nb: move to offset (0... octal, [1-9]... deci, 0x... hexa)\n"); |
| 62 | fprintf (fd, " //: move to hexa string hstr\n"); |
| 63 | fprintf (fd, " a : append hexa string hstr to current address\n"); |
| 64 | fprintf (fd, " d : delete nb bytes (- until end file)\n"); |
| 65 | fprintf (fd, " i : insert hexa string hstr to current address\n"); |
| 66 | fprintf (fd, " p : print nb bytes (- until end file)\n"); |
| 67 | fprintf (fd, " s : substitute h1 by h2 (g for globally)\n"); |
| 68 | |
| 69 | return ret; |
| 70 | } |
| 71 | |
| 72 | /* get number of digits */ |
| 73 | |
| 74 | unsigned int getnbdigits (unsigned long int l) { |
| 75 | int n = 0; |
| 76 | while (l) { |
| 77 | n += 2; |
| 78 | l /= 256; |
| 79 | } |
| 80 | return n; |
| 81 | } |
| 82 | |
| 83 | /* print a line */ |
| 84 | |
| 85 | void printline (char *buffer, int nb, unsigned long int addr) { |
| 86 | int i; |
| 87 | |
| 88 | printf ("0x%0*lx:", nbdigits, addr); |
| 89 | for (i = 0; i < nb; i++) { |
| 90 | printf (" %02x", (unsigned char)buffer[i]); |
| 91 | } |
| 92 | for (i = nb; i < nbcols; i++) { |
| 93 | printf (" "); |
| 94 | } |
| 95 | printf (" "); |
| 96 | for (i = 0; i < nb; i++) { |
| 97 | char c = buffer[i]; |
| 98 | printf ("%c", (c > 31) && (c < 127) ? c : '.'); |
| 99 | } |
| 100 | printf ("\n"); |
| 101 | } |
| 102 | |
| 103 | /* write file function */ |
| 104 | |
| 105 | int writefile (char *pt, int nb) { |
| 106 | if (fout) { |
| 107 | fwrite (pt, 1, nb, fout); |
| 108 | } |
| 109 | return 1; |
| 110 | } |
| 111 | |
| 112 | /* search sequence function */ |
| 113 | |
| 114 | int searchseq (sequence_t *seq) { |
| 115 | char *pt = buffer; |
| 116 | int nb = 0; |
| 117 | int i, j; |
| 118 | int valid = 0; |
| 119 | |
| 120 | VERBOSE (DEBUG, printf ("search sequence: %s\n", seq->sequence)); |
| 121 | |
| 122 | while (!feof (fin)) { |
| 123 | int nbread = fread (pt, 1, BUFFERSIZE - (pt - buffer), fin); |
| 124 | nb += nbread; |
| 125 | pt = buffer; |
| 126 | for (i = 0; i < nb - seq->length; i++) { |
| 127 | valid = 1; |
| 128 | for (j = 0; (j < seq->length) && (valid); j++) { |
| 129 | if (pt[i + j] != seq->bytes[j]) { |
| 130 | valid = 0; |
| 131 | } |
| 132 | } |
| 133 | if (valid) { |
| 134 | break; |
| 135 | } |
| 136 | } |
| 137 | |
| 138 | if (!valid) { |
| 139 | writefile (buffer, nb - seq->length); |
| 140 | offset = 0; |
| 141 | addrfile += nb - seq->length; |
| 142 | for (i = 0; i < seq->length; i++) { |
| 143 | buffer[i] = buffer[nb - seq->length + i]; |
| 144 | } |
| 145 | pt = buffer + seq->length; |
| 146 | nb = seq->length; |
| 147 | } else { |
| 148 | writefile (buffer, i); |
| 149 | offset = seq->length; |
| 150 | addrfile += i; |
| 151 | fseek (fin, i - nb, SEEK_CUR); |
| 152 | VERBOSE (DEBUG, printf ("found sequence at 0x%0*lx\n", getnbdigits (addrfile), addrfile)); |
| 153 | return 0; |
| 154 | } |
| 155 | } |
| 156 | |
| 157 | if (!valid) { |
| 158 | writefile (buffer, nb); |
| 159 | addrfile += seq->length; |
| 160 | } |
| 161 | |
| 162 | return 1; |
| 163 | } |
| 164 | |
| 165 | /* go to address function */ |
| 166 | |
| 167 | int gotoaddr (long int addr) { |
| 168 | char buffer[BUFFERSIZE] = {0}; |
| 169 | |
| 170 | if (addr == -1) { |
| 171 | addr = LONG_MAX; |
| 172 | } else if (addrfile > addr) { |
| 173 | return 1; |
| 174 | } |
| 175 | |
| 176 | VERBOSE (DEBUG, printf ("look for address: 0x%04lx\n", addr)); |
| 177 | while (!feof (fin)) { |
| 178 | int nbtoread = (addrfile + BUFFERSIZE > addr) ? addr - addrfile : BUFFERSIZE; |
| 179 | int nbread = fread (buffer, 1, nbtoread, fin); |
| 180 | writefile (buffer, nbread); |
| 181 | addrfile += nbread; |
| 182 | if (addrfile == addr) { |
| 183 | return 0; |
| 184 | } |
| 185 | } |
| 186 | |
| 187 | return 1; |
| 188 | } |
| 189 | |
| 190 | /* insert sequence function */ |
| 191 | |
| 192 | int insertseq (sequence_t *seq) { |
| 193 | char buffer[BUFFERSIZE] = {0}; |
| 194 | |
| 195 | VERBOSE (DEBUG, printf ("insert (%d): '%s'\n", offset, seq->sequence); |
| 196 | int i; |
| 197 | for (i = 0; i < seq->length; i++) { |
| 198 | char c = seq->bytes[i]; |
| 199 | printf (" 0x%02x (%c)", c, ((c >= 32) && (c < 127)) ? c : '.'); |
| 200 | }; |
| 201 | printf ("\n")); |
| 202 | if (offset > 0) { |
| 203 | int nbread = fread (buffer, 1, offset, fin); |
| 204 | if (nbread != offset) { |
| 205 | return 1; |
| 206 | } |
| 207 | writefile (buffer, offset); |
| 208 | offset = 0; |
| 209 | } |
| 210 | writefile (seq->bytes, seq->length); |
| 211 | |
| 212 | return 0; |
| 213 | } |
| 214 | |
| 215 | /* hexadecimal dump function */ |
| 216 | |
| 217 | int hexdump (int len) { |
| 218 | char buffer[BUFFERSIZE] = {0}; |
| 219 | int i; |
| 220 | |
| 221 | char *pt = buffer; |
| 222 | |
| 223 | int nb = 0; |
| 224 | while (!feof (fin)) { |
| 225 | int nbtoread = BUFFERSIZE - (pt - buffer); |
| 226 | if ((len > 0) && (nbtoread > len)) { |
| 227 | nbtoread = len; |
| 228 | } |
| 229 | int nbread = fread (pt, 1, nbtoread, fin); |
| 230 | if (len > 0) { |
| 231 | len -= nbread; |
| 232 | } |
| 233 | nb += nbread; |
| 234 | pt = buffer; |
| 235 | |
| 236 | /* print line */ |
| 237 | while ((nb - (int)(pt - buffer)) / nbcols > 0) { |
| 238 | printline (pt, nbcols, addrfile); |
| 239 | writefile (pt, nbcols); |
| 240 | addrfile += nbcols; |
| 241 | pt += nbcols; |
| 242 | } |
| 243 | |
| 244 | /* copy end buffer */ |
| 245 | nb -= pt - buffer; |
| 246 | for (i = 0; i < nb; i++) { |
| 247 | buffer[i] = pt[i]; |
| 248 | } |
| 249 | pt = buffer + nb; |
| 250 | |
| 251 | /* end partial reading */ |
| 252 | if (len == 0) { |
| 253 | break; |
| 254 | } |
| 255 | } |
| 256 | |
| 257 | /* last line */ |
| 258 | if (nb > 0) { |
| 259 | printline (buffer, nb, addrfile); |
| 260 | writefile (buffer, nb); |
| 261 | addrfile += nb; |
| 262 | } |
| 263 | |
| 264 | return 0; |
| 265 | } |
| 266 | |
| 267 | /* parse octal string */ |
| 268 | |
| 269 | long int octal (char *s, int n) { |
| 270 | int i; |
| 271 | unsigned long int l = 0; |
| 272 | for (i = 0; i < n; i++) { |
| 273 | if ((s[i] >= '0') && (s[i] < '8')) { |
| 274 | l = l * 8 + s[i] - '0'; |
| 275 | } else { |
| 276 | return -1; |
| 277 | } |
| 278 | } |
| 279 | return l; |
| 280 | } |
| 281 | |
| 282 | /* parse hexa string */ |
| 283 | |
| 284 | long int hexa (char *s, int n) { |
| 285 | int i; |
| 286 | unsigned long int l = 0; |
| 287 | for (i = 0; i < n; i++) { |
| 288 | l *= 16; |
| 289 | if ((s[i] >= '0') && (s[i] <= '9')) { |
| 290 | l += s[i] - '0'; |
| 291 | } else if ((s[i] >= 'A') && (s[i] <= 'F')) { |
| 292 | l += s[i] + 10 - 'A'; |
| 293 | } else if ((s[i] >= 'a') && (s[i] <= 'f')) { |
| 294 | l += s[i] + 10 - 'a'; |
| 295 | } else { |
| 296 | return -1; |
| 297 | } |
| 298 | } |
| 299 | return l; |
| 300 | } |
| 301 | |
| 302 | /* special character function */ |
| 303 | |
| 304 | int specialchar (char *s, char *b) { |
| 305 | int i = 0, j = 0; |
| 306 | while (s[i] != 0) { |
| 307 | if (j == SEQLEN) { |
| 308 | return 0; |
| 309 | } |
| 310 | if (s[i] != '\\') { |
| 311 | b[j++] = s[i++]; |
| 312 | continue; |
| 313 | } |
| 314 | |
| 315 | int l = -1; |
| 316 | switch (s[i + 1]) { |
| 317 | case 'a': l = 0x07; i += 2; break; |
| 318 | case 'b': l = 0x08; i += 2; break; |
| 319 | case 'e': l = 0x1b; i += 2; break; |
| 320 | case 'f': l = 0x0c; i += 2; break; |
| 321 | case 'n': l = 0x0a; i += 2; break; |
| 322 | case 'r': l = 0x0d; i += 2; break; |
| 323 | case 't': l = 0x09; i += 2; break; |
| 324 | case 'v': l = 0x0b; i += 2; break; |
| 325 | case '/': l = '/'; i += 2; break; |
| 326 | case '\\': l = '\\'; i += 2; break; |
| 327 | case '\'': l = '\''; i += 2; break; |
| 328 | case '"': l = '"'; i += 2; break; |
| 329 | case '0': |
| 330 | case '1': |
| 331 | case '2': |
| 332 | case '3': |
| 333 | l = octal (s + i + 1, 3); |
| 334 | if (l == -1) { |
| 335 | VERBOSE (WARNING, fprintf (stderr, "incorrect special char (\\%c%c%c)\n", s[i + 1], s[i + 2], s[i + 3])); |
| 336 | } |
| 337 | i += 4; |
| 338 | break; |
| 339 | case 'x': |
| 340 | l = hexa (s + i + 2, 2); |
| 341 | if (l == -1) { |
| 342 | VERBOSE (WARNING, fprintf (stderr, "incorrect special char (\\x%c%c)\n", s[i + 2], s[i + 3])); |
| 343 | } |
| 344 | i += 4; |
| 345 | break; |
| 346 | default: |
| 347 | VERBOSE (WARNING, fprintf (stderr, "incorrect special char (\\%c)\n", s[i + 1])); |
| 348 | i += 2; |
| 349 | break; |
| 350 | } |
| 351 | if (l != -1) { |
| 352 | VERBOSE (DEBUG, printf("l: 0x%02x '%c'\n", l, l)); |
| 353 | b[j++] = l; |
| 354 | } |
| 355 | } |
| 356 | |
| 357 | return j; |
| 358 | } |
| 359 | |
| 360 | /* remove space function */ |
| 361 | |
| 362 | void removespace (char *s, char **p) { |
| 363 | while (*s) { |
| 364 | if ((*s == ' ') || (*s == '\t')) { |
| 365 | s++; |
| 366 | } else { |
| 367 | break; |
| 368 | } |
| 369 | } |
| 370 | if (p != NULL) { |
| 371 | *p = s; |
| 372 | } |
| 373 | } |
| 374 | |
| 375 | /* get pattern function */ |
| 376 | |
| 377 | int getpattern (sequence_t *seq, char *s, char **p) { |
| 378 | |
| 379 | seq->sequence = s; |
| 380 | seq->length = 0; |
| 381 | |
| 382 | while (*s) { |
| 383 | if ((*s == '\\') && ((s[1] == '/') || (s[1] == '\\'))) { |
| 384 | s++; |
| 385 | } else if (*s == '/') { |
| 386 | *s++ = 0; |
| 387 | break; |
| 388 | } |
| 389 | s++; |
| 390 | } |
| 391 | seq->length = specialchar (seq->sequence, seq->bytes); |
| 392 | |
| 393 | if (p != NULL) { |
| 394 | *p = s; |
| 395 | } |
| 396 | |
| 397 | return (seq->length == 0); |
| 398 | } |
| 399 | |
| 400 | /* get hexa sequence function */ |
| 401 | |
| 402 | int gethexaseq (sequence_t *seq, char *s, char **p) { |
| 403 | int i = 0; |
| 404 | |
| 405 | seq->sequence = s; |
| 406 | seq->length = 0; |
| 407 | |
| 408 | while (*s) { |
| 409 | if (((*s >= '0') && (*s <= '9')) || |
| 410 | ((*s >= 'A') && (*s <= 'F')) || |
| 411 | ((*s >= 'a') && (*s <= 'f'))) { |
| 412 | s++; |
| 413 | i++; |
| 414 | if (i % 2 == 0) { |
| 415 | seq->bytes[seq->length] = hexa (seq->sequence + 2 * seq->length, 2); |
| 416 | if (seq->bytes[seq->length] == -1) { |
| 417 | return 1; |
| 418 | } |
| 419 | seq->length++; |
| 420 | } |
| 421 | } else { |
| 422 | break; |
| 423 | } |
| 424 | } |
| 425 | |
| 426 | if (p != NULL) { |
| 427 | *p = s; |
| 428 | } |
| 429 | |
| 430 | return (seq->length == 0) || (i % 2 == 1); |
| 431 | } |
| 432 | |
| 433 | /* get length function */ |
| 434 | |
| 435 | long int getlength (char *s, char **p) { |
| 436 | |
| 437 | while (*s != '\0') { |
| 438 | if ((*s == ' ') || (*s == '\t')) { |
| 439 | s++; |
| 440 | } else if ((*s >= '0') && (*s <= '9')) { |
| 441 | return strtol (s, p, 10); |
| 442 | } else if (*s == '-') { |
| 443 | if (p != NULL) { |
| 444 | *p = s + 1; |
| 445 | } |
| 446 | return -1; |
| 447 | } else { |
| 448 | VERBOSE (ERROR, fprintf (stderr, "unknown length (%s)\n", s)); |
| 449 | return 0; |
| 450 | } |
| 451 | } |
| 452 | |
| 453 | return 0; |
| 454 | } |
| 455 | |
| 456 | /* main function */ |
| 457 | |
| 458 | int main (int argc, char *argv[]) |
| 459 | { |
| 460 | int rc = 0; |
| 461 | char *input = NULL; |
| 462 | char *output = NULL; |
| 463 | char *commands = NULL; |
| 464 | long int length = -1; |
| 465 | sequence_t seq = {0}; |
| 466 | unsigned long int addr = 0; |
| 467 | char c; |
| 468 | |
| 469 | /* get basename */ |
| 470 | char *pt = progname = argv[0]; |
| 471 | while (*pt) { |
| 472 | if ((*pt == '/') || (*pt == '\\')) { |
| 473 | progname = pt + 1; |
| 474 | } |
| 475 | pt++; |
| 476 | } |
| 477 | |
| 478 | while (argc-- > 1) { |
| 479 | char *arg = *(++argv); |
| 480 | if (arg[0] != '-') { |
| 481 | VERBOSE (ERROR, fprintf (stderr, "%s: invalid option -- %s\n", progname, arg)); |
| 482 | return usage (1); |
| 483 | } |
| 484 | char c = arg[1]; |
| 485 | switch (c) { |
| 486 | case 'e': |
| 487 | arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL; |
| 488 | if (arg) { |
| 489 | //commands = (commands == NULL) ? arg : |
| 490 | // strcat (strcat (commands, " "), arg); |
| 491 | if (commands == NULL) { |
| 492 | commands = arg; |
| 493 | } else { |
| 494 | char *tmp = (char *) malloc (strlen (arg) + 1); |
| 495 | strcat (strcat (commands, " "), strcpy (tmp, arg)); |
| 496 | free (tmp); |
| 497 | } |
| 498 | } |
| 499 | break; |
| 500 | case 'i': |
| 501 | input = (arg[2]) ? arg + 2 : (--argc > 0 ) ? *(++argv) : NULL; |
| 502 | break; |
| 503 | case 'n': |
| 504 | arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL; |
| 505 | if (arg == NULL) { |
| 506 | VERBOSE (ERROR, fprintf (stderr, "%s: missing number of columns\n", progname)); |
| 507 | return usage (1); |
| 508 | } |
| 509 | nbcols = atoi (arg); |
| 510 | break; |
| 511 | case 'o': |
| 512 | output = (arg[2]) ? arg + 2 : (--argc > 0 ) ? *(++argv) : NULL; |
| 513 | break; |
| 514 | case 'v': |
| 515 | arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL; |
| 516 | if (arg == NULL) { |
| 517 | VERBOSE (ERROR, fprintf (stderr, "%s: missing verbose level\n", progname)); |
| 518 | return usage (1); |
| 519 | } |
| 520 | verbose = atoi (arg); |
| 521 | break; |
| 522 | case 'h': |
| 523 | default: |
| 524 | return usage (c != 'h'); |
| 525 | } |
| 526 | } |
| 527 | |
| 528 | /* check input */ |
| 529 | fin = stdin; |
| 530 | if (input) { |
| 531 | fin = fopen (input, "rb"); |
| 532 | if (!fin) { |
| 533 | VERBOSE (ERROR, fprintf (stderr, "error: can't open file '%s'\n", input)); |
| 534 | return 1; |
| 535 | } |
| 536 | } |
| 537 | |
| 538 | /* check output */ |
| 539 | if (output) { |
| 540 | fout = fopen (output, "wb"); |
| 541 | if (!fout) { |
| 542 | VERBOSE (ERROR, fprintf (stderr, "error: can't open file '%s'\n", output)); |
| 543 | fclose (fin); |
| 544 | return 1; |
| 545 | } |
| 546 | } else { |
| 547 | //fout = stdout; |
| 548 | } |
| 549 | |
| 550 | /* get file size */ |
| 551 | if (fin != stdin) { |
| 552 | fseek (fin, 0 , SEEK_END); |
| 553 | unsigned long int filesize = ftell (fin); |
| 554 | fseek (fin, 0 , SEEK_SET); |
| 555 | nbdigits = getnbdigits (filesize); |
| 556 | } |
| 557 | |
| 558 | if (commands == NULL) { |
| 559 | VERBOSE (DEBUG, printf ("no command\n")); |
| 560 | hexdump (-1); |
| 561 | } else { |
| 562 | VERBOSE (DEBUG, printf ("commands: %s\n", commands)); |
| 563 | while ((*commands != '\0') && (rc == 0)) { |
| 564 | switch (c = *commands++) { |
| 565 | case ' ': |
| 566 | case '\t': |
| 567 | break; |
| 568 | |
| 569 | case '/': /* search pattern */ |
| 570 | rc = getpattern (&seq, commands, &commands); |
| 571 | if (rc == 0) { |
| 572 | rc = searchseq (&seq); |
| 573 | if (rc == 1) { |
| 574 | VERBOSE (ERROR, fprintf (stderr, "can't find pattern '%s'\n", seq.sequence)); |
| 575 | } |
| 576 | } else { |
| 577 | VERBOSE (ERROR, fprintf (stderr, "erroneous pattern \"%s'\n", seq.sequence)); |
| 578 | } |
| 579 | break; |
| 580 | |
| 581 | case '0': /* read address */ |
| 582 | if (*commands == 'x') { |
| 583 | commands++; |
| 584 | addr = strtol (commands, &commands, 16); |
| 585 | } else { |
| 586 | addr = strtol (commands, &commands, 8); |
| 587 | } |
| 588 | if (addr) { |
| 589 | rc = gotoaddr (addr); |
| 590 | if (rc == 1) { |
| 591 | VERBOSE (ERROR, fprintf (stderr, "can't find address (0x%0*lx)\n", getnbdigits (addr), addr)); |
| 592 | } |
| 593 | } else { |
| 594 | VERBOSE (ERROR, fprintf (stderr, "erroneous address\n")); |
| 595 | rc = 1; |
| 596 | } |
| 597 | offset = 0; |
| 598 | break; |
| 599 | |
| 600 | case '1': |
| 601 | case '2': |
| 602 | case '3': |
| 603 | case '4': |
| 604 | case '5': |
| 605 | case '6': |
| 606 | case '7': |
| 607 | case '8': |
| 608 | case '9': /* read address */ |
| 609 | commands--; |
| 610 | addr = strtol (commands, &commands, 10); |
| 611 | if ((*commands != 0) && (*commands != ' ')) { |
| 612 | VERBOSE (ERROR, fprintf (stderr, "erroneous address ()\n")); |
| 613 | rc = 1; |
| 614 | } else { |
| 615 | rc = gotoaddr (addr); |
| 616 | if (rc == 1) { |
| 617 | VERBOSE (ERROR, fprintf (stderr, "can't find address (0x%0*lx)\n", getnbdigits (addr), addr)); |
| 618 | } |
| 619 | offset = 0; |
| 620 | } |
| 621 | break; |
| 622 | |
| 623 | case 'a': /* append mode */ |
| 624 | offset = 0; |
| 625 | /* fall through */ |
| 626 | |
| 627 | case 'i': /* insert mode */ |
| 628 | removespace (commands, &commands); |
| 629 | rc = gethexaseq (&seq, commands, &commands); |
| 630 | if (rc == 0) { |
| 631 | rc = insertseq (&seq); |
| 632 | if (rc == 1) { |
| 633 | VERBOSE (ERROR, fprintf (stderr, "can't jump (%d)\n", offset)); |
| 634 | } |
| 635 | } else { |
| 636 | VERBOSE (ERROR, fprintf (stderr, "erroneous sequence '%s'\n", seq.sequence)); |
| 637 | } |
| 638 | offset = 0; |
| 639 | break; |
| 640 | |
| 641 | case '+': /* relative move */ |
| 642 | /* fall through */ |
| 643 | |
| 644 | case 'd': /* delete mode */ |
| 645 | /* fall through */ |
| 646 | |
| 647 | case 'p': /* print mode */ |
| 648 | length = getlength (commands, &commands); |
| 649 | if (length == 0){ |
| 650 | VERBOSE (ERROR, fprintf (stderr, "erroneous length\n")); |
| 651 | rc = 1; |
| 652 | } else { |
| 653 | switch (c) { |
| 654 | case '+': |
| 655 | rc = gotoaddr ((length > 0) ? addrfile + length : -1); |
| 656 | if (rc == 1) { |
| 657 | VERBOSE (ERROR, fprintf (stderr, "can't find address (0x%0*lx)\n", getnbdigits (addr), addr)); |
| 658 | } |
| 659 | break; |
| 660 | |
| 661 | case 'd': |
| 662 | fseek (fin, length, SEEK_CUR); |
| 663 | break; |
| 664 | |
| 665 | case 'p': |
| 666 | hexdump (length); |
| 667 | break; |
| 668 | } |
| 669 | } |
| 670 | offset = 0; |
| 671 | break; |
| 672 | |
| 673 | case 's': /* substitute mode */ |
| 674 | if (*commands == '/') { |
| 675 | rc = getpattern (&seq, ++commands, &commands); |
| 676 | if (rc == 0) { |
| 677 | rc = searchseq (&seq); |
| 678 | if (rc == 0) { |
| 679 | fseek (fin, offset, SEEK_CUR); |
| 680 | rc = gethexaseq (&seq, commands, &commands); |
| 681 | commands++; |
| 682 | if (rc == 0) { |
| 683 | offset = 0; |
| 684 | rc = insertseq (&seq); |
| 685 | if (rc == 1) { |
| 686 | VERBOSE (ERROR, fprintf (stderr, "can't jump (%d)\n", offset)); |
| 687 | } |
| 688 | } else { |
| 689 | VERBOSE (ERROR, fprintf (stderr, "erroneous sequence '%s'\n", seq.sequence)); |
| 690 | } |
| 691 | } else { |
| 692 | VERBOSE (ERROR, fprintf (stderr, "can't find pattern '%s'\n", seq.sequence)); |
| 693 | } |
| 694 | } else { |
| 695 | VERBOSE (ERROR, fprintf (stderr, "erroneous pattern '%s'\n", seq.sequence)); |
| 696 | } |
| 697 | } else { |
| 698 | VERBOSE (ERROR, fprintf (stderr, "erroneous sequence '%s'\n", seq.sequence)); |
| 699 | rc = 1; |
| 700 | } |
| 701 | offset = 0; |
| 702 | break; |
| 703 | |
| 704 | default: |
| 705 | VERBOSE (ERROR, fprintf (stderr, "unknown command '%c'\n", commands[-1])); |
| 706 | rc = 1; |
| 707 | } |
| 708 | } |
| 709 | } |
| 710 | |
| 711 | /* end of file */ |
| 712 | if ((rc == 0) && (fout != NULL)) { |
| 713 | while (!feof (fin)) { |
| 714 | int nbread = fread (buffer, 1, BUFFERSIZE, fin); |
| 715 | if (nbread) { |
| 716 | fwrite (buffer, 1, nbread, fout); |
| 717 | } |
| 718 | } |
| 719 | } |
| 720 | |
| 721 | /* close all */ |
| 722 | if (fin) fclose (fin); |
| 723 | if (fout) fclose (fout); |
| 724 | |
| 725 | return rc; |
| 726 | } |
| 727 | |
| 728 | // test: hexdump.exe -h | awk '/usage:/ { rc=1 } END { exit (1-rc) }' |
| 729 | // test: hexdump.exe foo 2>&1 | grep -q 'invalid option' |
| 730 | // test: hexdump.exe -n 2>&1 | grep -q 'missing number of columns' |
| 731 | // test: hexdump.exe -v 2>&1 | grep -q 'missing verbose level' |
| 732 | // test: hexdump.exe -_ 2> /dev/null | awk 'END { if (NR == 0) { exit(0) } else exit (1) }' |
| 733 | // test: hexdump.exe -_ 2>&1 | awk '/usage:/ { rc=1 } END { exit (1-rc) }' |
| 734 | // test: hexdump.exe -i hexdump.c | grep -q '0x[0-9a-f]*: ' |
| 735 | // test: hexdump.exe -i hexdump.ko 2>&1 | grep -q "can't open file" |
| 736 | // test: hexdump.exe -i hexdump.c -o ko/test.c 2>&1 | grep -q "can't open file" |
| 737 | // test: cat hexdump.c | hexdump.exe -n 3 | head -2 | tail -1 | grep -q '0x000003: 64 65 70 dep' |
| 738 | // test: hexdump.exe -i hexdump.c -n 3 | head -2 | tail -1 | grep -q '0x0003: 64 65 70 dep' |
| 739 | // test: hexdump.exe -i hexdump.c -v 3 -n 8 | grep -q 'no command' |
| 740 | // test: hexdump.exe -i hexdump.c -o test.c -e 'p 200' | tail -1 | grep -q '0x00c0:' |
| 741 | // test: cmp hexdump.c test.c; x=$?; rm test.c; test x$x = x0 |
| 742 | // test: hexdump.exe -i hexdump.c -n 8 -e ' /cflags/ p 17 /debug/ p 8' | grep -q '0x0019: 2a 2f 0a 2f 2a 20 6c 69 \*\/\./\* li' |
| 743 | // test: hexdump.exe -i hexdump.c -e ' /\099\411\xgg\y/' 2>&1 | grep -c 'incorrect special char' | xargs test 4 -eq |
| 744 | // test: hexdump.exe -i hexdump.c -o test.c -e ' /cfl\x61gs/ p 16 /d\145bug/ p 8' | grep -q '0x0027: 64 65 62 75 67 2e 6f 20 debug.o' |
| 745 | // test: cmp hexdump.c test.c; x=$?; rm test.c; test x$x = x0 |
| 746 | // test: hexdump.exe -i hexdump.c -e ' /\n/ p 8' | grep -q '0x000d: 0a 2f 2a 20 63 66 6c 61 \./\* cfla' |
| 747 | // test: hexdump.exe -i hexdump.c -o test.c -e ' /\a\b\e\f\r\t\v/ p 8'; x=$?; test x$x = x1 |
| 748 | // test: cmp hexdump.c test.c; x=$?; rm test.c; test x$x = x0 |
| 749 | // test: hexdump.exe -i hexdump.c -v 3 -e " /\'/" -e ' /\"/' -e ' /\\/' -e ' /\x2a/' -e ' /\x3A/' | grep l: | wc -l | xargs test 5 = |
| 750 | // test: hexdump.exe -i hexdump.c -e ' /\n\/* vim:/ p -' | grep -q ': 74 3a 20 2a 2f 0a *t: \*\/\.' |
| 751 | // test: hexdump.exe -i hexdump.c -e 'p go_to_end' 2>&1 | grep -q 'unknown length' |
| 752 | // test: hexdump.exe -i hexdump.c -e ' /\x41BCD/' 2>&1 | grep -q "can't find pattern" |
| 753 | // test: hexdump.exe -i hexdump.c -e ' //' 2>&1 | grep -q 'erroneous pattern' |
| 754 | // test: hexdump.exe -i hexdump.c -e 'foo' 2>&1 | grep -q 'unknown command' |
| 755 | // test: hexdump.exe -i hexdump.c -e '0x20 p 8 64 p 8 0200 p 16' | grep -q '0x0080:' |
| 756 | // test: hexdump.exe -i hexdump.c -e '07777777' 2>&1 | grep -q "can't find address" |
| 757 | // test: hexdump.exe -i hexdump.c -e '0xFFFFFF' 2>&1 | grep -q "can't find address" |
| 758 | // test: hexdump.exe -i hexdump.c -e '99999999' 2>&1 | grep -q "can't find address" |
| 759 | // test: hexdump.exe -i hexdump.c -e '+9999999' 2>&1 | grep -q "can't find address" |
| 760 | // test: hexdump.exe -i hexdump.c -e '09' 2>&1 | grep -q 'erroneous address' |
| 761 | // test: hexdump.exe -i hexdump.c -e '0xg' 2>&1 | grep -q 'erroneous address' |
| 762 | // test: hexdump.exe -i hexdump.c -e '1a' 2>&1 | grep -q 'erroneous address' |
| 763 | // test: hexdump.exe -i hexdump.c -o test.c -e ' /cflags/ a 414e5a /link/ i 2F333B' |
| 764 | // test: grep -q '[A]NZcflags' test.c && grep -q '[l]ink/3;er' test.c; x=$?; rm test.c; test x$x = x0 |
| 765 | // test: hexdump.exe -i hexdump.c -e ' /cflags/ a 414e5' 2>&1 | grep -q 'erroneous sequence' |
| 766 | // test: hexdump.exe -i hexdump.c -o test.c -e ' /lags/ d 2' |
| 767 | // test: grep -q '[c]fgs' test.c; x=$?; rm test.c; test x$x = x0 |
| 768 | // test: hexdump.exe -i hexdump.c -o test.c -e ' /lags/ +2 i 2041' |
| 769 | // test: grep -q '[c]fla Ags:' test.c; x=$?; rm test.c; test x$x = x0 |
| 770 | // test: hexdump.exe -i hexdump.c -o test.c -e ' s/lags/2041/' |
| 771 | // test: grep -q '[c]f A:' test.c; x=$?; rm test.c; test x$x = x0 |
| 772 | // test: hexdump.exe -i hexdump.c -e ' s' 2>&1 | grep -q 'erroneous sequence' |
| 773 | // test: hexdump.exe -i hexdump.c -e ' s//' 2>&1 | grep -q 'erroneous pattern' |
| 774 | // test: hexdump.exe -i hexdump.c -e ' s/\x41BCD/2041/' 2>&1 | grep -q "can't find pattern" |
| 775 | // test: hexdump.exe -i hexdump.c -e ' s/cflags/414e5/' 2>&1 | grep -q 'erroneous sequence' |
| 776 | // test: hexdump.exe -i hexdump.exe | grep -q 'ffff'; test x$? = x1 |
| 777 | |
| 778 | /* vim: set ts=4 sw=4 et: */ |