1 /* Copyright (C) 1992, 1995-2004 artofcode LLC. All rights reserved.
2
3 This software is provided AS-IS with no warranty, either express or
4 implied.
5
6 This software is distributed under license and may not be copied,
7 modified or distributed except as expressly authorized under the terms
8 of the license contained in the file LICENSE in this distribution.
9
10 For more information about licensing, please refer to
11 http://www.ghostscript.com/licensing/. For information on
12 commercial licensing, go to http://www.artifex.com/licensing/ or
13 contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14 San Rafael, CA 94903, U.S.A., +1(415)492-9861.
15 */
16
17 /* $Id: echogs.c,v 1.7 2004/01/07 19:50:35 giles Exp $ */
18 /* 'echo'-like utility */
19
20 #include "stdpre.h"
21 #include <stdio.h>
22 #include <stdlib.h>
23
24 #if defined(__sun__) && !defined(const)
25 /* Apparently, there are archaic Sun platforms which don't include
26 * prototypes for fputc/fputs in stdio.h. The following prototype can
27 * cause type mismatches if const has been defined (usually with
28 * -Dconst=), so it's only included if const is undefined.
29 */
30 extern int fputc(int, FILE *), fputs(const char *, FILE *);
31 #endif
32
33 /* Some systems have time_t in sys/types.h rather than time.h. */
34 #include <sys/types.h>
35 #include <ctype.h>
36 #include <string.h>
37 #include <time.h> /* for ctime */
38
39 /*
40 * This program exists solely to get around omissions, problems, and
41 * incompatibilities in various shells and utility environments.
42 * Don't count on it staying the same from one release to another!
43 */
44
45 /*
46 * Usage:
47 echogs [-e .extn] [-(w|a)[b][-] file] [-h] [-n]
48 (-b|-B | -d|-D | -f|-F | -x hexstring | -(l|q|Q) string | -(l|q|Q)string |
49 -s | -u string | -i | -r file | -R file | -X)*
50 [-] string*
51 * Echoes string(s), or the binary equivalent of hexstring(s).
52 * If -w, writes to file; if -a, appends to file; if neither,
53 * writes to stdout. -wb and -ab open the file in binary mode.
54 * -w and -a search forward for the next argument that is not a switch.
55 * An appended - means the same as - alone, taking effect after the file
56 * argument.
57 * -e specifies an extension to be added to the file name.
58 * If -h, write the output in hex instead of literally.
59 * If -n, does not append a newline to the output.
60 * -b or -B means insert the base part (minus directories) of the file name
61 * passed as the argument of -w or -a.
62 * -d or -D means insert the date and time.
63 * -f or -F means insert the file name passed as the argument of -w or -a.
64 * -q means write the next string literally.
65 * -l or -Q means the same as -q followed by -s.
66 * -s means write a space.
67 * -u means convert the next string to upper case.
68 * -i means read from stdin, treating each line as an argument.
69 * -r means read from a named file in the same way.
70 * -R means copy a named file with no interpretation
71 * (but convert to hex if -h is in effect).
72 * -X means treat any following literals as hex rather than string data.
73 * - or -+ alone means treat the rest of the line as literal data,
74 * even if the first string begins with a -.
75 * -+<letter> is equivalent to -<Letter>, i.e., it upper-cases the letter.
76 * Inserts spaces automatically between the trailing strings,
77 * but nowhere else; in particular,
78 echogs -q a b
79 * writes 'ab', in contrast to
80 echogs -q a -s b
81 * which writes 'a b'.
82 */
83
84 static int hputc(int, FILE *), hputs(const char *, FILE *);
85
86 int
main(int argc,char * argv[])87 main(int argc, char *argv[])
88 {
89 FILE *out = stdout;
90 /*
91 * The initialization in = 0 is unnecessary: in is only referenced if
92 * interact = 1, in which case in has always been initialized.
93 * We initialize in = 0 solely to pacify stupid compilers.
94 */
95 FILE *in = 0;
96 const char *extn = "";
97 char fmode[4];
98 #define FNSIZE 100
99 char *fnparam;
100 char fname[FNSIZE];
101 int newline = 1;
102 int interact = 0;
103 int (*eputc)(int, FILE *) = fputc;
104 int (*eputs)(const char *, FILE *) = fputs;
105 #define LINESIZE 1000
106 char line[LINESIZE];
107 char sw = 0, sp = 0, hexx = 0;
108 char **argp = argv + 1;
109 int nargs = argc - 1;
110
111 if (nargs > 0 && !strcmp(*argp, "-e")) {
112 if (nargs < 2)
113 return 1;
114 extn = argp[1];
115 argp += 2, nargs -= 2;
116 }
117 if (nargs > 0 && (*argp)[0] == '-' &&
118 ((*argp)[1] == 'w' || (*argp)[1] == 'a')
119 ) {
120 size_t len = strlen(*argp);
121 int i;
122
123 if (len > 4)
124 return 1;
125 for (i = 1; i < nargs; i++)
126 if (argp[i][0] != '-')
127 break;
128 if (i == nargs)
129 return 1;
130 fnparam = argp[i];
131 strcpy(fmode, *argp + 1);
132 strcpy(fname, fnparam);
133 strcat(fname, extn);
134 if (fmode[len - 2] == '-') {
135 /*
136 * The referents of argp are actually const, but they can't be
137 * declared that way, so we have to make a writable constant.
138 */
139 static char dash[2] = { '-', 0 };
140
141 fmode[len - 2] = 0;
142 argp[i] = dash;
143 argp++, nargs--;
144 } else {
145 for (; i > 1; i--)
146 argp[i] = argp[i - 1];
147 argp += 2, nargs -= 2;
148 }
149 } else
150 strcpy(fname, "");
151 if (nargs > 0 && !strcmp(*argp, "-h")) {
152 eputc = hputc, eputs = hputs;
153 argp++, nargs--;
154 }
155 if (nargs > 0 && !strcmp(*argp, "-n")) {
156 newline = 0;
157 argp++, nargs--;
158 }
159 if (strlen(fname) != 0) {
160 out = fopen(fname, fmode);
161 if (out == 0)
162 return 1;
163 }
164 while (1) {
165 char *arg;
166
167 if (interact) {
168 if (fgets(line, LINESIZE, in) == NULL) {
169 interact = 0;
170 if (in != stdin)
171 fclose(in);
172 continue;
173 }
174 /* Remove the terminating \n. */
175 line[strlen(line) - 1] = 0;
176 arg = line;
177 } else {
178 if (nargs == 0)
179 break;
180 arg = *argp;
181 argp++, nargs--;
182 }
183 if (sw == 0 && arg[0] == '-') {
184 char chr = arg[1];
185
186 sp = 0;
187 swc:switch (chr) {
188 case 'l': /* literal string, then -s */
189 chr = 'Q';
190 /* falls through */
191 case 'q': /* literal string */
192 case 'Q': /* literal string, then -s */
193 if (arg[2] != 0) {
194 (*eputs) (arg + 2, out);
195 if (chr == 'Q')
196 (*eputc) (' ', out);
197 break;
198 }
199 /* falls through */
200 case 'r': /* read from a file */
201 case 'R':
202 case 'u': /* upper-case string */
203 case 'x': /* hex string */
204 sw = chr;
205 break;
206 case 's': /* write a space */
207 (*eputc) (' ', out);
208 break;
209 case 'i': /* read interactively */
210 interact = 1;
211 in = stdin;
212 break;
213 case 'b': /* insert base file name */
214 case 'B':
215 arg = fnparam + strlen(fnparam);
216 while (arg > fnparam &&
217 (isalnum(arg[-1]) || arg[-1] == '_'))
218 --arg;
219 (*eputs) (arg, out);
220 break;
221 case 'd': /* insert date/time */
222 case 'D':
223 {
224 time_t t;
225 char str[26];
226
227 time(&t);
228 strcpy(str, ctime(&t));
229 str[24] = 0; /* remove \n */
230 (*eputs) (str, out);
231 } break;
232 case 'f': /* insert file name */
233 case 'F':
234 (*eputs) (fnparam, out);
235 break;
236 case 'X': /* treat literals as hex */
237 hexx = 1;
238 break;
239 case '+': /* upper-case command */
240 if (arg[1]) {
241 ++arg;
242 chr = toupper(arg[1]);
243 goto swc;
244 }
245 /* falls through */
246 case 0: /* just '-' */
247 sw = '-';
248 break;
249 }
250 } else
251 switch (sw) {
252 case 0:
253 case '-':
254 if (hexx)
255 goto xx;
256 if (sp)
257 (*eputc) (' ', out);
258 (*eputs) (arg, out);
259 sp = 1;
260 break;
261 case 'q':
262 sw = 0;
263 (*eputs) (arg, out);
264 break;
265 case 'Q':
266 sw = 0;
267 (*eputs) (arg, out);
268 (*eputc) (' ', out);
269 break;
270 case 'r':
271 sw = 0;
272 in = fopen(arg, "r");
273 if (in == NULL)
274 exit(exit_FAILED);
275 interact = 1;
276 break;
277 case 'R':
278 sw = 0;
279 in = fopen(arg, "r");
280 if (in == NULL)
281 exit(exit_FAILED);
282 while (fread(line, 1, 1, in) > 0)
283 (*eputc) (line[0], out);
284 fclose(in);
285 break;
286 case 'u':
287 {
288 char *up;
289
290 for (up = arg; *up; up++)
291 (*eputc) (toupper(*up), out);
292 }
293 sw = 0;
294 break;
295 case 'x':
296 xx:{
297 char *xp;
298 unsigned int xchr = 1;
299
300 for (xp = arg; *xp; xp++) {
301 char ch = *xp;
302
303 if (!isxdigit(ch))
304 return 1;
305 xchr <<= 4;
306 xchr += (isdigit(ch) ? ch - '0' :
307 (isupper(ch) ? tolower(ch) : ch)
308 - 'a' + 10);
309 if (xchr >= 0x100) {
310 (*eputc) (xchr & 0xff, out);
311 xchr = 1;
312 }
313 }
314 }
315 sw = 0;
316 break;
317 }
318 }
319 if (newline)
320 (*eputc) ('\n', out);
321 if (out != stdout)
322 fclose(out);
323 return exit_OK;
324 }
325
326 static int
hputc(int ch,FILE * out)327 hputc(int ch, FILE * out)
328 {
329 static const char *hex = "0123456789abcdef";
330
331 /* In environments where char is signed, ch may be negative (!). */
332 putc(hex[(ch >> 4) & 0xf], out);
333 putc(hex[ch & 0xf], out);
334 return 0;
335 }
336
337 static int
hputs(const char * str,FILE * out)338 hputs(const char *str, FILE * out)
339 {
340 while (*str)
341 hputc(*str++ & 0xff, out);
342 return 0;
343 }
344