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