It was possible to create a bad ref
[jimtcl.git] / jim-bio.c
blobf6e8b01bd63f85fc38dd79ab0cdc8b03a5a45cff
2 /*
3 * jim-bio.c
5 * Implements the bio command for binary I/O
7 * bio read ?-hex? fd var length
9 * Reads 'length' bytes of binary data from 'fd' and stores an encoded string
10 * in 'var' so that the string contains no internal null characters.
12 * Returns the number of (original) chars read, which may be short if EOF is reached.
14 * bio write ?-hex? fd encoded
16 * Writes the binary-encoded string 'encoded' to 'fd'
18 * Returns the number of chars written (if no error)
20 * Note that by default no encoding is actually done since Jim supports strings containing nulls!
22 * Alternatively, if -hex is specified, the data is read and written as ascii hex
25 #include <stdlib.h>
26 #include <string.h>
27 #include <stdio.h>
28 #include <time.h>
29 #include <errno.h>
31 #include <jim.h>
32 #include <jim-subcmd.h>
34 static int hex2char(const char *hex)
36 int value;
38 value = (hex[0] >= 'A' ? ((hex[0] & 0xdf) - 'A') + 10 : (hex[0] - '0'));
39 value *= 16;
40 value += (hex[1] >= 'A' ? ((hex[1] & 0xdf) - 'A') + 10 : (hex[1] - '0'));
41 return value;
44 static void char2hex(int c, char hex[2])
46 hex[1] = (c & 0x0F) >= 0x0A ? (c & 0x0F) + 'A' - 10 : (c & 0x0F) + '0';
47 c /= 16;
48 hex[0] = (c & 0x0F) >= 0x0A ? (c & 0x0F) + 'A' - 10 : (c & 0x0F) + '0';
51 /**
52 * Modelled on Jim_ReadCmd
55 static int bio_cmd_read(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
57 char buf[130];
58 int count = 0;
59 long len;
60 int hex = 0;
61 int total = 0;
62 FILE *fh;
63 Jim_Obj *result;
65 if (Jim_CompareStringImmediate(interp, argv[0], "-hex")) {
66 hex++;
67 argv++;
68 argc--;
70 else if (argc == 4) {
71 return -1;
74 fh = Jim_AioFilehandle(interp, argv[0]);
76 if (!fh) {
77 return JIM_ERR;
80 if (Jim_GetLong(interp, argv[2], &len) != JIM_OK) {
81 return JIM_ERR;
84 result = Jim_NewStringObj(interp, "", 0);
86 /* Read one char at a time */
87 while (len > 0) {
88 int ch = fgetc(fh);
90 if (ch == EOF) {
91 break;
93 total++;
95 if (hex) {
96 char2hex(ch, buf + count);
97 count += 2;
99 else {
100 buf[count++] = ch;
103 if (count >= sizeof(buf)) {
104 /* Buffer is full, so append it */
105 Jim_AppendString(interp, result, buf, count);
106 count = 0;
108 len--;
111 if (ferror(fh)) {
112 Jim_SetResultString(interp, "error during read", -1);
113 clearerr(fh);
114 return JIM_ERR;
117 /* Add anything still pending */
118 Jim_AppendString(interp, result, buf, count);
120 if (Jim_SetVariable(interp, argv[1], result) != JIM_OK) {
121 return JIM_ERR;
124 Jim_SetResultInt(interp, total);
126 return JIM_OK;
129 static int bio_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
131 long count = 0;
132 long maxlen = LONG_MAX;
134 FILE *infh = Jim_AioFilehandle(interp, argv[0]);
135 FILE *outfh = Jim_AioFilehandle(interp, argv[1]);
137 if (infh == NULL || outfh == NULL) {
138 return JIM_ERR;
141 if (argc == 3) {
142 if (Jim_GetLong(interp, argv[2], &maxlen) != JIM_OK) {
143 return JIM_ERR;
147 while (count < maxlen) {
148 int ch = fgetc(infh);
150 if (ch == EOF || fputc(ch, outfh) == EOF) {
151 break;
153 count++;
156 if (ferror(infh)) {
157 Jim_SetResultFormatted(interp, "error reading \"%#s\": %s", argv[0], strerror(errno));
158 clearerr(infh);
159 return JIM_ERR;
162 if (ferror(outfh)) {
163 Jim_SetResultFormatted(interp, "error writing \"%#s\": %s", argv[1], strerror(errno));
164 clearerr(outfh);
165 return JIM_ERR;
168 Jim_SetResultInt(interp, count);
170 return JIM_OK;
173 static int bio_cmd_write(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
175 FILE *fh;
176 const char *pt;
177 int hex = 0;
178 long total = 0;
179 int len;
182 if (Jim_CompareStringImmediate(interp, argv[0], "-hex")) {
183 hex++;
184 argv++;
185 argc--;
187 else if (argc == 3) {
188 return -1;
191 fh = Jim_AioFilehandle(interp, argv[0]);
192 if (fh == NULL) {
193 return JIM_ERR;
196 pt = Jim_GetString(argv[1], &len);
197 while (len-- > 0) {
198 int ch;
200 if (hex) {
201 ch = hex2char(pt);
202 pt += 2;
203 len--;
205 else {
206 ch = *pt++;
208 if (fputc(ch, fh) == EOF) {
209 break;
211 total++;
214 if (ferror(fh)) {
215 Jim_SetResultString(interp, "error during write", -1);
216 clearerr(fh);
217 return JIM_ERR;
220 Jim_SetResultInt(interp, total);
222 return JIM_OK;
225 static const jim_subcmd_type bio_command_table[] = {
226 { .cmd = "read",
227 .function = bio_cmd_read,
228 .args = "?-hex? fd var numbytes",
229 .minargs = 3,
230 .maxargs = 4,
231 .description = "Read binary bytes as an encoded string"
233 { .cmd = "write",
234 .function = bio_cmd_write,
235 .args = "?-hex? fd buf",
236 .minargs = 2,
237 .maxargs = 3,
238 .description = "Write an encoded string as binary bytes"
240 { .cmd = "copy",
241 .function = bio_cmd_copy,
242 .args = "fromfd tofd ?bytes?",
243 .minargs = 2,
244 .maxargs = 3,
245 .description = "Read from one fd and write to another"
247 { 0 }
251 Jim_bioInit(Jim_Interp *interp)
253 Jim_CreateCommand(interp, "bio", Jim_SubCmdProc, (void *)bio_command_table, NULL);
254 return JIM_OK;