source: trunk/user/ksh/ksh.c @ 445

Last change on this file since 445 was 445, checked in by alain, 6 years ago

Restructure the mini_libc.

File size: 19.8 KB
RevLine 
[407]1///////////////////////////////////////////////////////////////////////////////
2// File   :  ksh.c
3// Date   :  October 2017
4// Author :  Alain Greiner
5///////////////////////////////////////////////////////////////////////////////
6// This single thread application implement a simple shell for ALMOS-MKH.
7///////////////////////////////////////////////////////////////////////////////
[230]8
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
[444]12#include <sys/wait.h>
13#include <signal.h>
14#include <unistd.h>
[445]15#include <almosmkh.h>
[230]16
[407]17#define CMD_MAX_SIZE   (256)    // max number of characters in one command
[436]18#define LOG_DEPTH      (32)     // max number of registered commands
[407]19#define MAX_ARGS           (32)     // max number of arguments in a command
20#define FIFO_SIZE      (1024)   // FIFO depth for recursive ls
[230]21
[407]22////////////////////////////////////////////////////////////////////////////////
23//         Structures
24////////////////////////////////////////////////////////////////////////////////
[230]25
[407]26// one entry in the registered commands array
27typedef struct log_entry_s
28{
29        char          buf[CMD_MAX_SIZE];
30        unsigned int  count;
31}
32log_entry_t;
[230]33
[407]34// one entry in the supported command types array
35typedef struct ksh_cmd_s
36{
37        char * name;
38        char * desc;
39        void   (*fn)( int , char ** );
40}
41ksh_cmd_t;
42
43
[230]44////////////////////////////////////////////////////////////////////////////////
45//         Global Variables
46////////////////////////////////////////////////////////////////////////////////
47
[407]48ksh_cmd_t       cmd[];                    // array of supported commands
[230]49
[407]50log_entry_t     log_entries[LOG_DEPTH];   // array of registered commands
[230]51
[407]52unsigned int    ptw;                      // write pointer in log_entries[]
53unsigned int    ptr;                      // read pointer in log_entries[]
[230]54
55////////////////////////////////////////////////////////////////////////////////
56//         Shell  Commands
57////////////////////////////////////////////////////////////////////////////////
58
[407]59/////////////////////////////////////////////
60static void cmd_cat( int argc , char **argv )
[230]61{
[407]62        char         * path;
[230]63
[407]64        if (argc != 2) 
65    {
[409]66                printf("  usage: cat pathname\n");
[230]67                return;
68        }
[407]69
[230]70        path = argv[1];
71
[409]72    printf("  error: not implemented yet\n");
[407]73
74/*
75        // open the file
76        fd = open( path , O_RDONLY , 0 );
77        if (fd < 0)
78    {
[409]79                printf("  error: cannot open %s\n", path);
[230]80                goto exit;
81        }
82
[407]83        // get file size
84        if (stat(path, &st) == -1)
85    {
[409]86                printf("  error: cannot stat %s\n", path);
[230]87                goto exit;
88        }
89        if (S_ISDIR(st.st_mode)) {
[409]90                printf("  error: %s is a directory\n", path);
[230]91                goto exit;
92        }
93        size = st.st_size;
94
[407]95        // mmap the file
[230]96        buf = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
97        if (buf == NULL || buf == (char *)-1) {
[409]98                printf("  error: cannot map %s\n", path);
[230]99                goto exit;
100        }
101
[407]102        // set terminating '0' XXX
[230]103        buf[size-1] = 0;
104
[407]105        // display the file content
[230]106        printf("%s", buf);
107
108exit:
[407]109        if (buf != NULL) munmap(buf, size);
110        if (fd >= 0) close(fd);
111*/
[230]112
[407]113}   // end cmd_cat()
114
115////////////////////////////////////////////
116static void cmd_cd( int argc , char **argv )
117{
118        char * path;
119
120        if (argc != 2)
121    {
[409]122                printf("  usage: cd pathname\n");
[407]123                return;
124        }
125
126        path = argv[1];
127
[409]128    printf("  error: not implemented yet\n");
[407]129/*
130        path = argv[1];
131
132        if (chdir(path) == -1)
133    {
[409]134                printf("  error: cannot cd to %s\n", path);
[407]135        }
136*/
137
138}   // end cmd_cd()
139
140/////////////////////////////////////////
[230]141static void cmd_cp(int argc, char **argv)
142{
[407]143//      int src_fd = -1, dst_fd = -1;
144//      char *srcpath, *dstpath;
145//      struct stat st;
146//      size_t size, i;
147//      char buf[1024];
[230]148
[407]149        if (argc != 3) 
150    {
[409]151                printf("  usage: cp src_pathname dst_pathname\n");
[230]152                return;
153        }
154
[409]155    printf("  error: not implemented yet\n");
[407]156
157/*
[230]158        srcpath = argv[1];
159        dstpath = argv[2];
160
[407]161        // open the src file
[230]162        src_fd = open(srcpath, O_RDONLY, 0);
163        if (src_fd < 0) {
[409]164                printf("  error: cannot open %s / err = %d\n", srcpath, errno);
[230]165                goto exit;
166        }
167
[407]168        // get file size
[230]169        if (stat(srcpath, &st) == -1) {
[409]170                printf("  error: cannot stat %s\n", srcpath);
[230]171                goto exit;
172        }
173        if (S_ISDIR(st.st_mode)) {
[409]174                printf("  error: %s is a directory\n", srcpath);
[230]175                goto exit;
176        }
177        size = st.st_size;
178
[407]179        // open the dst file
[230]180        dst_fd = open(dstpath, O_CREAT|O_TRUNC|O_RDWR, 0);
181        if (dst_fd < 0) {
[409]182                printf("  error: cannot open %s / err = %d\n", dstpath, errno);
[230]183                goto exit;
184        }
185        if (stat(dstpath, &st) == -1) {
[409]186                printf("  error: cannot stat %s\n", dstpath);
[230]187                goto exit;
188        }
189        if (S_ISDIR(st.st_mode)) {
[409]190                printf("  error: %s is a directory\n", dstpath);
[230]191                goto exit;
192        }
193
194        i = 0;
195        while (i < size)
196        {
197                size_t rlen = (size - i < 1024 ? size - i : 1024);
198                size_t wlen;
199                ssize_t ret;
200
[407]201                // read the source
[230]202                ret = read(src_fd, buf, rlen);
203                if (ret == -1) {
[409]204                        printf("  error: cannot read from file %s\n", srcpath);
[230]205                        goto exit;
206                }
207                rlen = (size_t)ret;
208
[407]209                // write to the destination
[230]210                ret = write(dst_fd, buf, rlen);
211                if (ret == -1) {
[409]212                        printf("  error: cannot write to file %s\n", dstpath);
[230]213                        goto exit;
214                }
215                wlen = (size_t)ret;
216
[407]217                // check
[230]218                if (wlen != rlen) {
[409]219                        printf("  error: cannot write on device\n");
[230]220                        goto exit;
221                }
222
223                i += rlen;
224        }
225
226exit:
[407]227        if (src_fd >= 0) close(src_fd);
228        if (dst_fd >= 0) close(dst_fd);
229*/
[230]230
[407]231}   // end cmd_cp()
232
[436]233/////////////////////////////////////////////////
234static void cmd_display( int argc , char **argv )
235{
236    unsigned int  cxy;
237    unsigned int  lid;
238    unsigned int  pid;
239    unsigned int  txt_id;
240
241    if( strcmp( argv[1] , "vmm" ) == 0 )
242    {
[442]243        if( argc != 4 )
[436]244        {
[442]245                    printf("  usage: display vmm cxy pid\n");
[436]246                    return;
247            }
248
[442]249            cxy = atoi(argv[2]);
250            pid = atoi(argv[3]);
[436]251
[442]252        if( display_vmm( cxy , pid ) )
[436]253        {
[442]254            printf("  error: no process %x in cluster %x\n", pid , cxy );
[436]255        }
256    }
257    else if( strcmp( argv[1] , "sched" ) == 0 )
258    {
259        if( argc != 4 )
260        {
261                    printf("  usage: display sched cxy lid\n");
262                    return;
263            }
264
265            cxy = atoi(argv[2]);
266            lid = atoi(argv[3]);
267
268        if( display_sched( cxy , lid ) )
269        {
270            printf("  error: illegal arguments cxy = %x / lid = %d\n", cxy, lid );
271        }
272    }
273    else if( strcmp( argv[1] , "process" ) == 0 )
274    {
275        if( argc != 3 )
276        {
277                    printf("  usage: display process cxy\n");
278                    return;
279            }
280
281            cxy = atoi(argv[2]);
282
283        if( display_cluster_processes( cxy ) )
284        {
285            printf("  error: illegal argument cxy = %x\n", cxy );
286        }
287    }
288    else if( strcmp( argv[1] , "txt" ) == 0 )
289    {
290        if( argc != 3 )
291        {
292                    printf("  usage: display txt txt_id\n");
293                    return;
294            }
295
296            txt_id = atoi(argv[2]);
297
298        if( display_txt_processes( txt_id ) )
299        {
300            printf("  error: illegal argument txt_id = %x\n", txt_id );
301        }
302    }
303    else if( strcmp( argv[1] , "vfs" ) == 0 )
304    {
305        if( argc != 2 )
306        {
307                    printf("  usage: display vfs\n");
308                    return;
309            }
310
311        display_vfs();
312    }
313    else if( strcmp( argv[1] , "chdev" ) == 0 )
314    {
315        if( argc != 2 )
316        {
317                    printf("  usage: display chdev\n");
318                    return;
319            }
320
321        display_chdev();
322    }
[445]323    else if( strcmp( argv[1] , "dqdt" ) == 0 )
324    {
325        if( argc != 2 )
326        {
327                    printf("  usage: display dqdt\n");
328                    return;
329            }
330
331        display_dqdt();
332    }
[436]333    else
334    {
335        printf("  usage: display (vmm/sched/process/vfs/chdev/txt) [arg2] [arg3]\n");
336    }
337} // end cmd_display()
338
[427]339/////////////////////////////////////////
340static void cmd_fg(int argc, char **argv)
341{
342        unsigned int pid;
343
344        if (argc != 2) 
345    {
346                printf("  usage: %s pid\n", argv[0]);
347                return;
348        }
349
350    pid = atoi( argv[1] );   
351
352    if( pid == 0 )
353    {
[442]354                printf("  error: PID cannot be 0\n" );
[427]355        }
356
357    if( fg( pid ) )
358    {
359                printf("  error: cannot find process %x\n", pid );
360        }
[436]361}  // end cmd_fg()
[427]362
[407]363//////////////////////////////////////////////
364static void cmd_help( int argc , char **argv )
[230]365{
[407]366        unsigned int i;
[230]367
[407]368        if (argc != 1) 
369    {
[409]370                printf("  usage: %s\n", argv[0]);
[230]371                return;
372        }
373
374        printf("available commands:\n");
[407]375        for (i = 0 ; cmd[i].name ; i++) 
376    {
[230]377                printf("\t%s\t : %s\n", cmd[i].name , cmd[i].desc);
378        }
[407]379}   // end cmd_help()
[230]380
[407]381//////////////////////////////////////////////
382static void cmd_kill( int argc , char **argv )
[230]383{
[407]384        unsigned int pid;
[230]385
[407]386        if (argc != 2) 
387    {
[409]388                printf("  usage: %s pid\n", argv[0]);
[230]389                return;
390        }
391
[427]392        pid = atoi( argv[1] );
[230]393
[427]394    if( pid == 0 )
395    {
[440]396                printf("  error: kernel process 0 cannot be killed\n" );
[427]397        }
398
[416]399        if( kill( pid , SIGKILL ) )
[407]400    {
[440]401                printf("  error: process %x cannot be killed\n", pid );
[230]402        }
[407]403}   // end cmd_kill()
[230]404
[407]405//////////////////////////////////////////////
406static void cmd_load( int argc , char **argv )
[230]407{
[436]408        int                  ret_fork;           // return value from fork
409        int                  ret_exec;           // return value from exec
410    unsigned int         ksh_pid;            // KSH process PID
411        char               * pathname;           // path to .elf file
412    unsigned int         background;         // background execution if non zero
413    int                  status;             // new process exit status
[407]414
[427]415        if( (argc < 2) || (argc > 3) ) 
[407]416    {
[434]417                printf("  usage: %s pathname [&]\n", argv[0] );
[407]418                return;
419        }
420
421        pathname = argv[1];
422
[427]423    if( argc == 3 ) background = (argv[2][0] == '&');
[434]424    else            background = 0;
[427]425
[434]426    // get KSH process PID
427    ksh_pid = getpid();
[407]428
[434]429    // KSH process fork CHILD process
[436]430        ret_fork = fork();
[434]431
[436]432    if ( ret_fork < 0 )          // it is a failure reported to KSH
[407]433    {
[434]434        printf("  error: ksh process unable to fork\n");
[440]435        return;
[434]436    }
[436]437    else if (ret_fork == 0)      // it is the CHILD process
[434]438    {
439        // CHILD process exec NEW process
[444]440        ret_exec = execve( pathname , NULL , NULL );
[434]441
[441]442        // this is only executed in case of exec failure
[436]443        if( ret_exec )
[409]444        {
[441]445            printf("  error: child process unable to exec <%s>\n", pathname );
446            exit( 0 );
[436]447        }   
448        } 
449    else                        // it is the parent KSH : ret_fork is the new process PID
450    {
[441]451        // give back terminal ownership to KSH if new process created in background /
452        // wait new process completion before returning to command interpreter otherwise
453        if( background )   fg( ksh_pid );
454        else               wait( &status );
[436]455
[441]456        // return to command interpreter
457        return;
[436]458    }
[407]459}   // end cmd_load
460
461/////////////////////////////////////////////
462static void cmd_log( int argc , char **argv )
463{
464        unsigned int i;
465
[230]466        printf("--- registered commands ---\n");
[407]467        for (i = 0; i < LOG_DEPTH; i++) 
468    {
[436]469                printf(" - %d\t: %s\n", i, &log_entries[i].buf);
[230]470        }
471}
472
[407]473////////////////////////////////////////////
474static void cmd_ls( int argc , char **argv )
[230]475{
[407]476        char  * path;
[230]477
[407]478//  struct dirent * file;
479//  DIR *dir;
480
481        if (argc == 1)
482    {
[230]483                path = ".";
[407]484        }
485    else if (argc == 2) 
486    {
[230]487                path = argv[1];
[407]488        } 
489    else 
490    {
[409]491                printf("  usage: ls [path]\n");
[230]492                return;
493        }
494
[409]495    printf("  error: not implemented yet\n");
[407]496/*
497        dir = opendir( path );
[230]498        while ((file = readdir(dir)) != NULL)
499        {
500                printf(" %s\n", file->d_name);
501        }
502        closedir(dir);
[407]503*/
[230]504}
505
[407]506///////////////////////////////////////////////
507static void cmd_mkdir( int argc , char **argv )
[230]508{
[407]509        char * pathname;
[230]510
[407]511        if (argc != 2)
512    {
[409]513                printf("  usage: mkdir pathname\n");
[230]514                return;
515        }
516
[407]517    pathname = argv[1];
[230]518
[409]519    printf("  error: not implemented yet\n");
[407]520/*
521        if ( mkdir( path, 0x700) == -1 )
522    {
[409]523                printf("  error: cannot create directory %s\n", path);
[230]524        }
[407]525*/
[230]526}
527
[407]528////////////////////////////////////////////
529static void cmd_mv( int argc , char **argv )
[230]530{
[407]531
[230]532        if (argc < 3)
533        {
534                printf("  usage : %s src_pathname dst_pathname\n", argv[0]);
535                return;
536        }
537
[409]538    printf("  error: not implemented yet\n");
[407]539   
540/*
[230]541        int ret = giet_fat_rename(argv[1], argv[2]);
542        if (ret < 0)
543        {
[409]544                printf("  error : cannot move %s to %s / err = %d\n", argv[1], argv[2], ret );
[230]545        }
[407]546*/
547
[230]548}
549
[407]550/////////////////////////////////////////////
551static void cmd_pwd( int argc , char **argv )
[230]552{
[407]553        char buf[1024];
[230]554
[407]555        if (argc != 1)
556    {
[409]557                printf("  usage: pwd\n");
[407]558                return;
559        }
560
561        if ( getcwd( buf , 1024 ) ) 
562    {
[409]563                printf("  error: unable to get current directory\n");
[407]564        }
565    else 
566    {
567                printf("%s\n", buf);
568        }
569}
570
571////////////////////////////////////////////
572static void cmd_rm( int argc , char **argv )
573{
574        char * pathname;
575
576        if (argc != 2)
577    {
[409]578                printf("  usage: rm pathname\n");
[230]579                return;
580        }
581
[407]582        pathname = argv[1];
[230]583
[409]584    printf("  error: not implemented yet\n");
[407]585/*
586        if (remove(path) == -1)
587    {
[409]588                printf("  error: cannot remove %s\n", path);
[230]589        }
[407]590*/
591
[230]592}
593
[407]594///////////////////////////////////////////////
595static void cmd_rmdir( int argc , char **argv )
[230]596{
597        cmd_rm(argc, argv);
598}
599
[442]600///////////////////////////////////////////////
601static void cmd_trace( int argc , char **argv )
602{
603    unsigned int cxy;
604    unsigned int lid;
605
606        if (argc != 3)
607    {
608                printf("  usage: trace cxy lid \n");
609                return;
610        }
611
612    cxy = atoi(argv[1]);
613    lid = atoi(argv[2]);
614
615    if( trace( 1 , cxy , lid ) )
616    {
617        printf("  error: core[%x,%d] not found\n", cxy, lid );
618    }
619}
620
621///////////////////////////////////////////////
622static void cmd_untrace( int argc , char **argv )
623{
624    unsigned int cxy;
625    unsigned int lid;
626
627        if (argc != 3)
628    {
629                printf("  usage: untrace cxy lid \n");
630                return;
631        }
632
633    cxy = atoi(argv[1]);
634    lid = atoi(argv[2]);
635
636    if( trace( 0 , cxy , lid ) )
637    {
638        printf("  error: core[%x,%d] not found\n", cxy, lid );
639    }
640}
641
[407]642//////////////////////////////////////////////////////////////////
643// Array of commands
644//////////////////////////////////////////////////////////////////
[230]645
[407]646ksh_cmd_t cmd[] =
[230]647{
[435]648        { "cat",     "display file content",                            cmd_cat     },
649        { "cd",      "change current directory",                        cmd_cd      },
650        { "cp",      "replicate a file in file system",                 cmd_cp      },
651    { "fg",      "put a process in foreground",                     cmd_fg      },
652    { "display", "display vmm/sched/process/vfs/chdev/txt",         cmd_display },
653        { "load",    "load an user application",                        cmd_load    },
654        { "help",    "list available commands",                         cmd_help    },
655        { "kill",    "kill an application (all threads)",               cmd_kill    },
656        { "log",     "list registered commands",                        cmd_log     },
657        { "ls",      "list directory entries",                          cmd_ls      },
658        { "mkdir",   "create a new directory",                          cmd_mkdir   },
659        { "mv",      "move a file in file system",                      cmd_mv      },
660        { "pwd",     "print current working directory",                 cmd_pwd     },
661        { "rm",      "remove a file from file system",                  cmd_rm      },
662        { "rmdir",   "remove a directory from file system",             cmd_rmdir   },
[442]663        { "trace",   "activate trace for a given core",                 cmd_trace   },
664        { "untrace", "desactivate trace for a given core",              cmd_untrace },
[435]665        { NULL,      NULL,                                                                              NULL        }
[230]666};
667
[407]668////////////////////////////////////////////////////////////////////////////////////
669// This function analyses one command (with arguments), execute it, and return.
670////////////////////////////////////////////////////////////////////////////////////
[230]671static void parse(char *buf)
672{
673        int argc = 0;
674        char *argv[MAX_ARGS];
675        int i;
676        int len = strlen(buf);
677
678        // build argc/argv
[407]679        for (i = 0; i < len; i++) 
680    {
681                if (buf[i] == ' ') 
682        {
[230]683                        buf[i] = '\0';
[407]684                }
685        else if (i == 0 || buf[i - 1] == '\0') 
686        {
687                        if (argc < MAX_ARGS) 
688            {
[230]689                                argv[argc] = &buf[i];
690                                argc++;
691                        }
692                }
693        }
694
[407]695        if (argc > 0)
696    {
[230]697                int found = 0;
698
699                argv[argc] = NULL;
700
[407]701                // try to match typed command
702                for (i = 0; cmd[i].name; i++)
703        {
704                        if (strcmp(argv[0], cmd[i].name) == 0)
705            {
[230]706                                cmd[i].fn(argc, argv);
707                                found = 1;
708                                break;
709                        }
710                }
711
[407]712                if (!found)
713        {
[434]714                        printf("  undefined command <%s>\n", argv[0]);
[230]715                }
716        }
717}
718
[407]719///////////////////////////////////
720int main( int argc , char *argv[] )
[230]721{
[407]722        char         c;                                           // read character
723        char         buf[CMD_MAX_SIZE];           // buffer for one command
724        unsigned int count = 0;                           // pointer in buf
725        unsigned int i;                                           // index for loops
[230]726
[407]727        enum fsm_states
728    {
[230]729                NORMAL,
730                ESCAPE,
731                BRAKET,
732        };
733
[407]734    // log buffer initialisation
735        memset( &log_entries , 0, sizeof(log_entries));
736        ptw   = 0;
737        ptr   = 0;
[230]738
[440]739        printf( "\n\n~~~ shell ~~~\n\n" );
[230]740
741        // command buffer initialisation
[407]742        memset( buf, 0x20 , sizeof(buf) );
[230]743        count = 0;
744
745        // display first prompt
746        printf("# ");
747
748        // This lexical analyser writes one command line in the buf buffer.
749        // It is implemented as a 3 states FSM to handle the following sequences:
750        // - ESC [ A : up arrow
751        // - ESC [ B : down arrow
752        // - ESC [ C : right arrow
753        // - ESC [ D : left arrow
[407]754        // The three states have the following semantic:
[230]755        // - NORMAL : no (ESC) character has been found
756        // - ESCAPE : the character (ESC) has been found
757        // - BRAKET : the wo characters (ESC,[) have been found
[436]758
[230]759        unsigned int state = NORMAL;
760
[407]761// @@@
[442]762// parse("load /bin/user/hello.elf");
[407]763// @@@
[408]764
[230]765        while (1)
766        {
[407]767                c = (char)getchar();
[230]768
[407]769        if( c == 0 ) continue;
770
[230]771                switch (state)
772                {
773                        case NORMAL:
774                        {
775                                if ((c == '\b') || (c == 0x7F))  // backspace => remove one character
776                                {
777                                        if (count > 0) {
778                                                printf("\b \b");
779                                                count--;
780                                        }
781                                }
782                                else if (c == '\n')      // new line => call parser to execute command
783                                {
784                                        if (count > 0)
785                                        {
786                                                // complete command
787                                                buf[count] = '\0';
788
789                                                // register command in log arrays
790                                                strcpy(log_entries[ptw].buf, buf);
791                                                log_entries[ptw].count = count;
792                                                ptw = (ptw + 1) % LOG_DEPTH;
793                                                ptr = ptw;
794
795                                                // execute command
796                                                printf("\n");
797                                                parse((char *)&buf);
798
799                                                // reinitialise buffer and display prompt
800                                                for ( i = 0 ; i < sizeof(buf) ; i++ ) buf[i] = 0x20;
801                                                count = 0;
802                                                printf("# ");
803                                        }
[441]804                    else
805                    {
806                        printf("\n# ");
807                    }
[230]808                                }
809                                else if (c == '\t')     // tabulation => do nothing
810                                {
811                                }
[436]812                                else if (c == (char)0x1B)       // ESC => start an escape sequence
[230]813                                {
814                                        state = ESCAPE;
815                                }
816                                else if (c == 0x03)     // ^C  => cancel current command
817                                {
818                                        for (i = 0; i < count; i++) printf("\b \b");
819                                        for (i = 0; i < sizeof(buf); i++) buf[i] = 0x20;
820                                        count = 0;
821                                }
822                                else                                     // register character in command buffer
823                                {
824                                        if (count < sizeof(buf) - 1)
825                                        {
[418]826                                                putchar( c );
[230]827                                                buf[count] = c;
828                                                count++;
829                                        }
830                                }
831                                break;
832                        }
833                        case ESCAPE:
834                        {
835                                if (c == '[')           //  valid sequence => continue
836                                {
837                                        state = BRAKET;
838                                }
839                                else                               // invalid sequence => do nothing
840                                {
841                                        state = NORMAL;
842                                }
843                                break;
844                        }
845                        case BRAKET:
846                        {
847                                if (c == 'D')   // valid  LEFT sequence => move buf pointer left
848                                {
849                                        if (count > 0)
850                                        {
851                                                printf("\b");
852                                                count--;
853                                        }
854
855                                        // get next user char
856                                        state = NORMAL;
857                                }
858                                else if (c == 'C')   // valid  RIGHT sequence => move buf pointer right
859                                {
860                                        if (count < sizeof(buf) - 1)
861                                        {
862                                                printf("%c", buf[count]);
863                                                count++;
864                                        }
865
866                                        // get next user char
867                                        state = NORMAL;
868                                }
869                                else if (c == 'A')   // valid  UP sequence => move log pointer backward
870                                {
871                                        // cancel current command
872                                        for (i = 0; i < count; i++) printf("\b \b");
873                                        count = 0;
874
875                                        // copy log command into buf
876                                        ptr = (ptr - 1) % LOG_DEPTH;
877                                        strcpy(buf, log_entries[ptr].buf);
878                                        count = log_entries[ptr].count;
879
880                                        // display log command
881                                        printf("%s", buf);
882
883                                        // get next user char
884                                        state = NORMAL;
885                                }
886                                else if (c == 'B')   // valid  DOWN sequence => move log pointer forward
887                                {
888                                        // cancel current command
889                                        for (i = 0 ; i < count; i++) printf("\b \b");
890                                        count = 0;
891
892                                        // copy log command into buf
893                                        ptr = (ptr + 1) % LOG_DEPTH;
894                                        strcpy(buf, log_entries[ptr].buf);
895                                        count = log_entries[ptr].count;
896
897                                        // display log command
898                                        printf("%s", buf);
899
900                                        // get next user char
901                                        state = NORMAL;
902                                }
903                                else                               // other character => do nothing
904                                {
905                                        // get next user char
906                                        state = NORMAL;
907                                }
908                                break;
909                        }
910                }
911        }
[436]912}  // end main()
[230]913
Note: See TracBrowser for help on using the repository browser.