]> git.sur5r.net Git - cc65/blob - testcode/lib/tinyshell.c
add "tinyshell" test program for file operations
[cc65] / testcode / lib / tinyshell.c
1 /*
2  * Simple ("tiny") shell to test filename and directory functions.
3  * Copyright (c) 2013, Christian Groessler, chris@groessler.org
4  */
5
6 #define VERSION_ASC "0.90"
7
8 #define KEYB_BUFSZ 80
9 #define PROMPT ">>> "
10 #ifdef __ATARI__
11 #define UPPERCASE      /* define (e.g. for Atari) to convert filenames etc. to upper case */
12 #endif
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <errno.h>
18 #include <unistd.h>
19 #ifndef __CC65__
20 #include <sys/stat.h>
21 #include <sys/param.h>
22 #else
23 #define MAXPATHLEN 64
24 #endif
25 #include <sys/types.h>
26 #include <fcntl.h>
27 #include <dirent.h>
28
29 #define CMD_NOTHING 0
30 #define CMD_INVALID 1
31 #define CMD_HELP    2
32 #define CMD_QUIT    3
33 #define CMD_LS      4
34 #define CMD_MKDIR   5
35 #define CMD_RMDIR   6
36 #define CMD_CHDIR   7
37 #define CMD_RM      8
38 #define CMD_RENAME  9
39 #define CMD_COPY    10
40 #define CMD_PWD     11
41
42 static unsigned char terminate;
43 static unsigned char cmd;
44 static unsigned char *cmd_asc, *arg1, *arg2, *arg3;
45 static unsigned char keyb_buf[KEYB_BUFSZ];
46 static size_t cpbuf_sz = 4096;
47
48 struct cmd_table {
49     unsigned char *name;
50     unsigned char code;
51 } cmd_table[] = {
52     { "help",  CMD_HELP },
53     { "quit",  CMD_QUIT },
54     { "q",     CMD_QUIT },
55     { "exit",  CMD_QUIT },
56     { "ls",    CMD_LS },
57     { "dir",   CMD_LS },
58     { "md",    CMD_MKDIR },
59     { "mkdir", CMD_MKDIR },
60     { "rd",    CMD_RMDIR },
61     { "rmdir", CMD_RMDIR },
62     { "cd",    CMD_CHDIR },
63     { "chdir", CMD_CHDIR },
64     { "rm",    CMD_RM },
65     { "del",   CMD_RM },
66     { "cp",    CMD_COPY },
67     { "copy",  CMD_COPY },
68     { "mv",    CMD_RENAME },
69     { "ren",   CMD_RENAME },
70     { "pwd",   CMD_PWD },
71     { NULL, 0 }
72 };
73
74 static void banner(void)
75 {
76     puts("\"tiny\" command line shell, v" VERSION_ASC);
77     puts("written by chris@groessler.org");
78     puts("type 'help' for help\n");
79 }
80
81 static void get_command(void)
82 {
83     unsigned char i = 0;
84
85     arg1 = arg2 = arg3 = NULL;
86
87     /* issue prompt */
88     printf(PROMPT);
89
90     /* get input from the user */
91     if (! fgets(keyb_buf, KEYB_BUFSZ, stdin)) {
92         puts("");
93         cmd = CMD_QUIT;
94         return;
95     }
96
97     /* split input into cmd, arg1, arg2, arg3 */
98
99     /* get and parse command */
100     cmd_asc = strtok(keyb_buf, " \t\n");
101     if (! cmd_asc) {
102         cmd = CMD_NOTHING;
103         return;
104     }
105     cmd = CMD_INVALID;
106     while (cmd_table[i].name) {
107         if (! strcmp(cmd_table[i].name, cmd_asc)) {
108             cmd = cmd_table[i].code;
109             break;
110         }
111         i++;
112     }
113
114     /* get arguments */
115     arg1 = strtok(NULL, " \t\n");
116     if (! arg1)
117         return;
118     arg2 = strtok(NULL, " \t\n");
119     if (! arg2)
120         return;
121     arg3 = strtok(NULL, " \t\n");
122 }
123
124 static void cmd_help(void)
125 {
126     puts("quit, exit -  exit shell");
127     puts("ls, dir    -  display current directory");
128     puts("              and drive contents");
129     puts("rm, del    -  delete file");
130     puts("cp, copy   -  copy file");
131     puts("mv, ren    -  rename file");
132     puts("cd, chdir  -  change directory or drive");
133     puts("md, mkdir  -  make directory or drive");
134     puts("rd, rmdir  -  remove directory or drive");
135     puts("sorry, you cannot start programs here");
136 }
137
138 static void cmd_ls(void)
139 {
140     DIR *dir;
141     unsigned char *arg;
142     struct dirent *dirent;
143 #ifdef __ATARI__
144     char need_free = 0;
145 #endif
146
147     if (arg2) {
148         puts("usage: ls [dir]");
149         return;
150     }
151
152     /* print directory listing */
153     if (arg1) {
154 #ifdef UPPERCASE
155         strupr(arg1);
156 #endif
157 #ifdef __ATARI__
158         /* not sure if this shouldn't be done by the runtime lib */
159         if (*(arg1 + strlen(arg1) - 1) == ':' || *(arg1 + strlen(arg1) - 1) == '>') {
160             arg = malloc(strlen(arg1) + 4);
161             if (! arg) {
162                 printf("malloc failed: %s", strerror(errno));
163                 return;
164             }
165             need_free = 1;
166             memcpy(arg, arg1, strlen(arg1) + 1);
167             strcat(arg, "*.*");
168         }
169         else
170 #endif
171             arg = arg1;
172     }
173     else
174         arg = ".";
175
176     dir = opendir(arg);
177 #ifdef __ATARI__
178     if (need_free) free(arg);
179 #endif
180     if (! dir) {
181         puts("opendir failed");
182         return;
183     }
184
185     while (dirent = readdir(dir))
186         puts(dirent->d_name);
187
188     closedir(dir);
189 }
190
191 static void cmd_rm(void)
192 {
193     if (!arg1 || arg2) {
194         puts("usage: rm <file>");
195         return;
196     }
197
198 #ifdef UPPERCASE
199     strupr(arg1);
200 #endif
201
202     if (unlink(arg1))
203         printf("remove failed: %s\n", strerror(errno));
204 }
205
206 static void cmd_mkdir(void)
207 {
208     if (!arg1 || arg2) {
209         puts("usage: mkdir <dir>");
210         return;
211     }
212
213 #ifdef UPPERCASE
214     strupr(arg1);
215 #endif
216
217     if (mkdir(arg1, 0777))
218         printf("mkdir failed: %s\n", strerror(errno));
219 }
220
221 static void cmd_rmdir(void)
222 {
223     if (!arg1 || arg2) {
224         puts("usage: rmdir <dir>");
225         return;
226     }
227
228 #ifdef UPPERCASE
229     strupr(arg1);
230 #endif
231
232     if (rmdir(arg1))
233         printf("rmdir failed: %s\n", strerror(errno));
234 }
235
236 static void cmd_chdir(void)
237 {
238     if (!arg1 || arg2) {
239         puts("usage: cddir <dir>");
240         return;
241     }
242
243 #ifdef UPPERCASE
244     strupr(arg1);
245 #endif
246
247     if (chdir(arg1))
248         printf("chdir failed: %s\n", strerror(errno));
249 }
250
251 static void cmd_pwd(void)
252 {
253     char *buf;
254
255     if (arg1) {
256         puts("usage: pwd");
257         return;
258     }
259
260     buf = malloc(MAXPATHLEN);
261     if (! buf) {
262         printf("malloc %u bytes failed: %s\n", MAXPATHLEN, strerror(errno));
263         return;
264     }
265     if (!getcwd(buf, MAXPATHLEN)) {
266         printf("getcwd failed: %s\n", strerror(errno));
267         free(buf);
268         return;
269     }
270
271     puts(buf);
272     free(buf);
273 }
274
275 static void cmd_rename(void)
276 {
277     if (!arg2 || arg3) {
278         puts("usage: mv <oldname> <newname>");
279         return;
280     }
281
282 #ifdef UPPERCASE
283     strupr(arg1);
284     strupr(arg2);
285 #endif
286
287     if (rename(arg1, arg2))
288         printf("rename failed: %s\n", strerror(errno));
289 }
290
291 static void cmd_copy(void)
292 {
293     int srcfd = -1, dstfd = -1;
294     unsigned char *buf;
295     int readsz, writesz;
296
297     if (!arg2 || arg3) {
298         puts("usage: cp <src> <dest>");
299         return;
300     }
301
302 #ifdef UPPERCASE
303     strupr(arg1);
304     strupr(arg2);
305 #endif
306
307     buf = malloc(cpbuf_sz);
308     if (! buf) {
309         printf("malloc %u bytes failed: %s\n", cpbuf_sz, strerror(errno));
310         return;
311     }
312
313     while (1) {
314         if (srcfd == -1) {
315             srcfd = open(arg1, O_RDONLY);
316             if (srcfd < 0) {
317                 printf("open(%s) failed: %s\n", arg1, strerror(errno));
318                 break;
319             }
320         }
321
322         readsz = read(srcfd, buf, cpbuf_sz);
323         if (readsz < 0) {
324             printf("read error: %s\n", strerror(errno));
325             break;
326         }
327         if (! readsz)
328             break;
329
330         if (dstfd == -1) {
331             dstfd = open(arg2, O_WRONLY | O_CREAT | O_TRUNC, 0777);
332             if (dstfd < 0) {
333                 printf("open(%s) failed: %s\n", arg2, strerror(errno));
334                 break;
335             }
336         }
337
338         writesz = write(dstfd, buf, readsz);
339         if (writesz < 0 || writesz != readsz) {
340             printf("write error: %s\n", strerror(errno));
341             break;
342         }
343         if (readsz != cpbuf_sz)
344             break;
345     }
346
347     free(buf);
348     if (srcfd >= 0) close(srcfd);
349     if (dstfd >= 0) close(dstfd);
350 }
351
352 static void run_command(void)
353 {
354     switch (cmd) {
355         default: puts("internal error"); return;
356         case CMD_NOTHING: return;
357         case CMD_INVALID: puts("invalid command"); return;
358         case CMD_HELP: cmd_help(); return;
359         case CMD_QUIT: terminate = 1; return;
360         case CMD_LS: cmd_ls(); return;
361         case CMD_RM: cmd_rm(); return;
362         case CMD_CHDIR: cmd_chdir(); return;
363         case CMD_MKDIR: cmd_mkdir(); return;
364         case CMD_RMDIR: cmd_rmdir(); return;
365         case CMD_PWD: cmd_pwd(); return;
366         case CMD_RENAME: cmd_rename(); return;
367         case CMD_COPY: cmd_copy(); return;
368     }
369 }
370
371 int main(void)
372 {
373     banner();
374
375     while (! terminate) {
376         get_command();
377         run_command();
378     }
379     return 0;
380 }
381
382 /* Local Variables: */
383 /* c-file-style: "cpg" */
384 /* c-basic-offset: 4 */
385 /* End: */