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

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

1/ Fix a bug in the Multithreaded "sort" applicationr:
The pthread_create() arguments must be declared as global variables.
2/ The exit syscall can be called by any thread of a process..

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