1 /* $OpenBSD: binedit.c,v 1.1 2016/07/30 10:56:13 schwarze Exp $ */ 2 /* 3 * Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 #include <ctype.h> 18 #include <endian.h> 19 #include <err.h> 20 #include <stdint.h> 21 #include <stdio.h> 22 23 static int32_t getint(const char **); 24 static int copybyte(const char); 25 26 27 int 28 main(int argc, char *argv[]) 29 { 30 const char *cmd; /* Command string from the command line. */ 31 int32_t pos; /* Characters read so far. */ 32 int32_t dest; /* Number of characters to be read. */ 33 int32_t val; /* Value to be written. */ 34 int32_t i; /* Auxiliary for reading and writing. */ 35 36 if (argc != 2) 37 errx(1, "usage: binedit command_string"); 38 cmd = argv[1]; 39 dest = pos = val = 0; 40 while (*cmd != '\0') { 41 switch (*cmd++) { 42 case 'a': /* Advance to destination. */ 43 while (pos < dest) { 44 pos++; 45 if (copybyte('a') == EOF) 46 errx(1, "a: EOF"); 47 } 48 break; 49 case 'c': /* Copy. */ 50 i = getint(&cmd); 51 pos += i; 52 while (i--) 53 if (copybyte('c') == EOF) 54 errx(1, "c: EOF"); 55 break; 56 case 'd': /* Set destination. */ 57 dest = val; 58 break; 59 case 'f': /* Finish. */ 60 if (*cmd != '\0') 61 errx(1, "%s: not the last command", cmd - 1); 62 while (copybyte('f') != EOF) 63 continue; 64 break; 65 case 'i': /* Increment. */ 66 i = getint(&cmd); 67 if (i == 0) 68 i = 1; 69 val += i; 70 break; 71 case 'r': /* Read. */ 72 pos += sizeof(i); 73 if (fread(&i, sizeof(i), 1, stdin) != 1) { 74 if (ferror(stdin)) 75 err(1, "r: fread"); 76 else 77 errx(1, "r: EOF"); 78 } 79 val = be32toh(i); 80 break; 81 case 's': /* Skip. */ 82 i = getint(&cmd); 83 pos += i; 84 while (i--) { 85 if (getchar() == EOF) { 86 if (ferror(stdin)) 87 err(1, "s: getchar"); 88 else 89 errx(1, "s: EOF"); 90 } 91 } 92 break; 93 case 'w': /* Write one integer. */ 94 if (*cmd == '-' || *cmd == '+' || 95 isdigit((unsigned char)*cmd)) 96 val = getint(&cmd); 97 i = htobe32(val); 98 if (fwrite(&i, sizeof(i), 1, stdout) != 1) 99 err(1, "w: fwrite"); 100 break; 101 default: 102 errx(1, "%c: invalid command", cmd[-1]); 103 } 104 } 105 return 0; 106 } 107 108 static int32_t 109 getint(const char **cmd) 110 { 111 int32_t res; 112 int minus; 113 114 res = 0; 115 minus = 0; 116 if (**cmd == '-') { 117 minus = 1; 118 (*cmd)++; 119 } else if (**cmd == '+') 120 (*cmd)++; 121 while(isdigit((unsigned char)**cmd)) 122 res = res * 10 + *(*cmd)++ - '0'; 123 return minus ? -res : res; 124 } 125 126 static int 127 copybyte(const char cmd) 128 { 129 int ch; 130 131 if ((ch = getchar()) == EOF) { 132 if (ferror(stdin)) 133 err(1, "%c: getchar", cmd); 134 } else if (putchar(ch) == EOF) 135 err(1, "%c: putchar", cmd); 136 return ch; 137 } 138