From owner-cvs-all@FreeBSD.ORG Fri May 26 08:18:05 2006 Return-Path: X-Original-To: cvs-all@FreeBSD.org Delivered-To: cvs-all@FreeBSD.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id F3E8416A457; Fri, 26 May 2006 08:18:04 +0000 (UTC) (envelope-from ganbold@micom.mng.net) Received: from publicd.ub.mng.net (publicd.ub.mng.net [202.179.0.88]) by mx1.FreeBSD.org (Postfix) with ESMTP id B2F7043D5D; Fri, 26 May 2006 08:18:03 +0000 (GMT) (envelope-from ganbold@micom.mng.net) Received: from [202.179.0.164] (helo=[192.168.0.18]) by publicd.ub.mng.net with esmtpa (Exim 4.61 (FreeBSD)) (envelope-from ) id 1FjXWC-00055x-GZ; Fri, 26 May 2006 17:18:00 +0900 Message-ID: <4476B9B7.7030602@micom.mng.net> Date: Fri, 26 May 2006 17:17:59 +0900 From: Ganbold User-Agent: Thunderbird 1.5.0.2 (X11/20060425) MIME-Version: 1.0 To: Gleb Smirnoff References: <200605241446.k4OEkvo0011251@repoman.freebsd.org> <44751F01.4030702@micom.mng.net> <20060525072311.GG27819@FreeBSD.org> In-Reply-To: <20060525072311.GG27819@FreeBSD.org> Content-Type: multipart/mixed; boundary="------------010007020708090901020203" Cc: cvs-src@FreeBSD.org, src-committers@FreeBSD.org, cvs-all@FreeBSD.org Subject: Re: cvs commit: src/usr.sbin/ngctl config.c connect.c debug.c dot.c list.c main.c mkpeer.c msg.c name.c ngctl.h rmhook.c show.c shutdown.c status.c types.c write.c X-BeenThere: cvs-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: CVS commit messages for the entire tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 26 May 2006 08:18:05 -0000 This is a multi-part message in MIME format. --------------010007020708090901020203 Content-Type: text/plain; charset=KOI8-R; format=flowed Content-Transfer-Encoding: 7bit Gleb, Gleb Smirnoff wrote: > On Thu, May 25, 2006 at 12:05:37PM +0900, Ganbold wrote: > G> Gleb, > G> > G> I modified my previous patch accordingly. Hopefully it follows style(9) > G> more; removed typedef, changed function names to follow original > G> function naming styles in code, space after return statements according > G> to style(9). > > I am working on your patch now. I'm doing some minor changes to match > style of surrounding code, and also moving to queue(3) instead of > home-made linked list. > > > G> - return(CMDRTN_USAGE); > G> + return (CMDRTN_USAGE); > > Let's commit these style changes later. > > G> diff -u /usr/src/usr.sbin/ngctl/main.c /usr/home/tsgan/ngctl/main.c > G> --- /usr/src/usr.sbin/ngctl/main.c Wed May 24 23:46:55 2006 > G> +++ /usr/home/tsgan/ngctl/main.c Thu May 25 11:47:59 2006 > G> @@ -50,6 +50,7 @@ > G> #include > G> #include > G> #include > G> +#include > G> #include > G> > G> #include > G> @@ -61,6 +62,13 @@ > G> #define WHITESPACE " \t\r\n\v\f" > G> #define DUMP_BYTES_PER_LINE 16 > G> > G> +/* Previously issued commands list */ > G> +struct cmdlist { > G> + char *cmd; /* command */ > G> + struct cmdlist *prev; /* previous command */ > G> + struct cmdlist *next; /* next command */ > G> +}; > G> + > > Yes, yes. This is what I'm tending to do. Do not touch ngctl.h, since > this type is private to main.c > > I lowercased CMDLIST, too. :) > > G> +static int ScanCmd(char *cmd, struct cmdlist **curr); > > I uppercased "s" and "c" in this function too. Damn, haven't you rooted > my notebook? :) > Maybe :) > Please wait for me to send you a patch converted to queue(3) macro, and > then continue discussion. > > OK, Here is the patch for main.c which uses TAILQ. I couldn't get rid of tailcmd and yet I found one small bug in ScanCmd. For loop (for (j=0 ; j < i; j++) {putchar(8); putchar(' '); putchar(8);}) in ScanCmd really should be inside the if statement otherwise it will delete the whole line if user presses up key first time. The other thing is when user press down arrow after entering some commands it shows last command. Should we let this behave in this way? Usually in shell after entering command when user presses down arrow it will not show anything. Please let me know if I did something wrong. Maybe there are some wrong naming with tailq variables. thanks, Ganbold --------------010007020708090901020203 Content-Type: text/plain; name="main.c.patch2" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="main.c.patch2" --- /usr/src/usr.sbin/ngctl/main.c Wed May 24 23:46:55 2006 +++ main.c Fri May 26 16:53:58 2006 @@ -39,6 +39,7 @@ */ #include +#include #include #include @@ -50,6 +51,7 @@ #include #include #include +#include #include #include @@ -61,6 +63,11 @@ #define WHITESPACE " \t\r\n\v\f" #define DUMP_BYTES_PER_LINE 16 +struct cmdlist { + char *cmd; /* command */ + TAILQ_ENTRY(cmdlist) cmd_link; +}; + /* Internal functions */ static int ReadFile(FILE *fp); static int DoParseCommand(char *line); @@ -72,6 +79,10 @@ static int ReadCmd(int ac, char **av); static int HelpCmd(int ac, char **av); static int QuitCmd(int ac, char **av); +static int ScanCmd(char *cmd, struct cmdlist **curr); +static struct cmdlist *AddCmd(char *cmd); +static struct cmdlist *GetNextCmd(struct cmdlist *curr); +static struct cmdlist *GetPrevCmd(struct cmdlist *curr); /* List of commands */ static const struct ngcmd *const cmds[] = { @@ -118,9 +129,18 @@ { "exit" } }; +TAILQ_HEAD(tqhead, cmdlist) tq; +struct tqhead *tqp; + +/* tail command in commands list */ +struct cmdlist *tailcmd = NULL; + /* Our control and data sockets */ int csock, dsock; +/* this variable must be set go to previous command in history list */ +int goprev; + /* * main() */ @@ -188,7 +208,7 @@ rtn = EX_OSERR; break; } - return(rtn); + return (rtn); } /* @@ -205,10 +225,10 @@ continue; if ((rtn = DoParseCommand(line)) != 0) { warnx("line %d: error in file", num); - return(rtn); + return (rtn); } } - return(CMDRTN_OK); + return (CMDRTN_OK); } /* @@ -218,12 +238,29 @@ DoInteractive(void) { const int maxfd = MAX(csock, dsock) + 1; + struct cmdlist *curr; + int scan_status = 0; + struct termios new_settings; + struct termios stored_settings; + + /* init tailq */ + TAILQ_INIT(&tq); + tqp = &tq; (*help_cmd.func)(0, NULL); while (1) { struct timeval tv; fd_set rfds; + /* record the old settings to restore the terminal when finished */ + tcgetattr(0, &stored_settings); + new_settings = stored_settings; + + /* set things up for character-at-a-time */ + new_settings.c_lflag &= ~(ECHO | ECHOK | ICANON); + new_settings.c_cc[VTIME] = 1; + tcsetattr(0, TCSANOW, &new_settings); + /* See if any data or control messages are arriving */ FD_ZERO(&rfds); FD_SET(csock, &rfds); @@ -272,15 +309,28 @@ if (FD_ISSET(0, &rfds)) { char buf[LINE_MAX]; - if (fgets(buf, sizeof(buf), stdin) == NULL) { - printf("\n"); - break; + /* always begin from last command */ + goprev = 0; + memset(buf, 0, LINE_MAX); + + scan_status = ScanCmd(buf, &curr); + if (scan_status == 0) { + rewind(stdin); + continue; } + snprintf(buf, LINE_MAX, "%s", curr->cmd); if (DoParseCommand(buf) == CMDRTN_QUIT) break; } + /* restore the old settings */ + tcsetattr(0, TCSANOW, &stored_settings); + } + /* destroy commands */ + while ((curr = TAILQ_FIRST(tqp)) != NULL) { + TAILQ_REMOVE(tqp, curr, cmd_link); + free(curr); } - return(CMDRTN_QUIT); + return (CMDRTN_QUIT); } /* @@ -298,7 +348,7 @@ av[++ac] = strtok(NULL, WHITESPACE)); /* Do command */ - return(DoCommand(ac, av)); + return (DoCommand(ac, av)); } /* @@ -311,12 +361,12 @@ int rtn; if (ac == 0 || *av[0] == 0) - return(CMDRTN_OK); + return (CMDRTN_OK); if ((cmd = FindCommand(av[0])) == NULL) - return(CMDRTN_ERROR); + return (CMDRTN_ERROR); if ((rtn = (*cmd->func)(ac, av)) == CMDRTN_USAGE) warnx("usage: %s", cmd->cmd); - return(rtn); + return (rtn); } /* @@ -331,16 +381,16 @@ if (MatchCommand(cmds[k], string)) { if (found != -1) { warnx("\"%s\": ambiguous command", string); - return(NULL); + return (NULL); } found = k; } } if (found == -1) { warnx("\"%s\": unknown command", string); - return(NULL); + return (NULL); } - return(cmds[found]); + return (cmds[found]); } /* @@ -383,17 +433,17 @@ case 2: if ((fp = fopen(av[1], "r")) == NULL) { warn("%s", av[1]); - return(CMDRTN_ERROR); + return (CMDRTN_ERROR); } break; default: - return(CMDRTN_USAGE); + return (CMDRTN_USAGE); } /* Process it */ rtn = ReadFile(fp); fclose(fp); - return(rtn); + return (rtn); } /* @@ -419,7 +469,7 @@ *s = '\0'; printf(" %-10s %s\n", buf, cmd->desc); } - return(CMDRTN_OK); + return (CMDRTN_OK); default: /* Show help on a specific command */ if ((cmd = FindCommand(av[1])) != NULL) { @@ -462,7 +512,7 @@ } } } - return(CMDRTN_OK); + return (CMDRTN_OK); } /* @@ -471,7 +521,159 @@ static int QuitCmd(int ac __unused, char **av __unused) { - return(CMDRTN_QUIT); + return (CMDRTN_QUIT); +} + +/* + * Get commands from stdin, up/down arrow keys handling + */ +static int +ScanCmd(char *cmd, struct cmdlist **curr) +{ + struct cmdlist *p; + int c, i, j, finished; + + p = *curr; + c = 1; i = 0; finished = 0; + + while (c && !finished && i < LINE_MAX) { + c = getchar(); + switch (c) { + case '\t': + printf("tab\n"); + break; + case '\n': + finished = 1; + putchar('\n'); + if (i > 0) { + cmd[i] = '\0'; + p = AddCmd(cmd); + } + break; + case 8: + /* backspace */ + case 127: + /* delete */ + if (i > 0) { + cmd[--i] = '\0'; + putchar(8); putchar(' '); putchar(8); + } + break; + case 27: + /* ESC + * Check up/down arrow keys + */ + c = getchar(); + if (c == 91) { + /* it looks like we have an arrow key here */ + c = getchar(); + if (c > 68 || c < 65) { + /* ignore right/left arrow keys, put the characters back in the queue + *(except for the ESC) + */ + ungetc(c, stdin); + ungetc(91, stdin); + } else if (c == 65) { + /* up arrow key */ + p = GetPrevCmd(p); + if (p != NULL) { + for (j=0 ; j < i; j++) { + putchar(8); putchar(' '); putchar(8); + } + printf("%s", p->cmd); + cmd = strdup(p->cmd); + i = strlen(cmd); + } + } else if (c == 66) { + /* down arrow key */ + p = GetNextCmd(p); + if(p != NULL) { + for (j=0 ; j < i; j++) { + putchar(8); putchar(' '); putchar(8); + } + printf("%s", p->cmd); + cmd = strdup(p->cmd); + i = strlen(cmd); + } + } + } else + /* not an arrow key, put the char back */ + ungetc(c, stdin); + break; + + default: + cmd[i++] = c; + putchar(c); + break; + } + } + *curr = p; + + return (strlen(cmd)); +} + +/* + * add new command to the command list + */ +static struct cmdlist +*AddCmd(char *cmd) +{ + struct cmdlist *p; + + p = (struct cmdlist *) malloc(sizeof(struct cmdlist)); + + if (p == NULL || (p->cmd = strdup(cmd)) == NULL) { + warn("malloc"); + exit (CMDRTN_ERROR); + } + if(TAILQ_FIRST(tqp) == NULL) + TAILQ_INSERT_HEAD(tqp, p, cmd_link); + else + TAILQ_INSERT_TAIL(tqp, p, cmd_link); + + /* store tail */ + tailcmd = p; + + return (p); + } + +/* + * Get next command from the command list + */ +static struct cmdlist +*GetNextCmd(struct cmdlist *curr) +{ + struct cmdlist *p; + + p = curr; + + /* if current command is not latest in a command list, get next command */ + if (p != tailcmd && p != NULL) + p = TAILQ_NEXT(p, cmd_link); + + return (p); +} + +/* + * Get previous command from the command list + */ +static struct cmdlist +*GetPrevCmd(struct cmdlist *curr) +{ + struct cmdlist *p; + + p = curr; + + if (p == tailcmd && goprev != 1) { + goprev = 1; + return (p); + } + + /* if current command is not first in a command list, get previous command */ + if (goprev && p != TAILQ_FIRST(tqp) && p != NULL) + p = TAILQ_PREV(p, tqhead, cmd_link); + + return (p); } /* --------------010007020708090901020203--