diff --git a/src/cmdline.h b/src/cmdline.h new file mode 100644 index 0000000..92c61db --- /dev/null +++ b/src/cmdline.h @@ -0,0 +1,99 @@ +/* CMDLINE.H - header file for command line processing functions +*/ +/* Copyright © 1992, 1993, 2001 Kenneth L. Harrenstien +/* Copyright © 2017 Olaf Seibert +** All Rights Reserved +** +** This file is part of the KLH10 Distribution. Use, modification, and +** re-distribution is permitted subject to the terms in the file +** named "LICENSE", which contains the full text of the legal notices +** and should always accompany this Distribution. +** +** This software is provided "AS IS" with NO WARRANTY OF ANY KIND. +** +** This notice (including the copyright and warranty disclaimer) +** must be included in all copies or derivations of this software. +*/ +#ifndef CMDBUFLEN +# define CMDBUFLEN 512 +#endif +#ifndef CMDMAXARG +# define CMDMAXARG 10 +#endif + +struct cmd_s { + struct cmkey_s *cmd_keys;/* Command table */ + int cmd_flags; /* State flags */ + char *cmd_prm; /* Pointer to command prompt */ + char *cmd_buf; /* Pointer to start of buffer */ + size_t cmd_blen; /* Size of buffer */ + int cmd_left; /* # chars left for current cmd being input */ + char *cmd_inp; /* Input deposit pointer */ + char *cmd_rdp; /* Readout pointer */ + size_t cmd_rleft; /* # chars left to read */ + + /* Provide all command routines with their desired arguments */ + char *cmd_arglin; /* Original pointer to start of args on line */ + int cmd_argc; /* # of tokens */ + char *cmd_argv[CMDMAXARG+1]; /* Array of token pointers */ + char *cmd_tdp; /* Next free loc in token buffer */ + size_t cmd_tleft; /* # chars free in token buffer */ + char cmd_tokbuf[CMDBUFLEN+CMDMAXARG]; + +#if 0 + char *cmd_wbf; /* Pointer to work buffer */ + size_t cmd_wblen; /* Size in chars */ + char *cmd_wbp; /* Current deposit ptr */ + size_t cmd_wbleft; /* # chars left */ +#endif +}; + +#define CMDF_ACTIVE 01 /* Activation char seen, execute accumulated cmd */ +#define CMDF_INACCUM 02 /* In accumulation phase */ +#define CMDF_NOPRM 040 /* Disable prompt */ + +struct cmkey_s { + char *cmk_key; + union cmnode *cmk_p; +}; +struct cmrtn_s { + void (*cmr_vect)(struct cmd_s *); /* Function to call */ + int cmr_flgs; /* Misc flags */ + char *cmr_synt; /* Arg syntax */ + char *cmr_help; /* Short one-line help */ + char *cmr_desc; /* Long description */ +}; + +#define CMRF_NOARG 01 /* Command takes no args */ +#define CMRF_TOKS 010 /* Command wants whole line tokenized, via cm */ +#define CMRF_TLIN 020 /* Command wants overall line arg, via cm */ +#define CMRF_CMPTR 040 /* Command wants just cmd state ptr */ + +union cmnode { /* All possible nodes for a keyword */ + struct cmrtn_s cmn_rtn; +}; + + +/* Predeclarations */ +void cmdinit(struct cmd_s *, struct cmkey_s *, char *, char *, size_t); +int cmdexec(struct cmd_s *); +int cmdaccum(struct cmd_s *); + +struct cmkey_s *cmdkeylookup(char *, struct cmkey_s *, struct cmkey_s **); +char *cmdlsetup(struct cmd_s *); +char *cmdlcopy(struct cmd_s *cm, char *line); +void fc_gques(struct cmd_s *cm); +void fc_ghelp(struct cmd_s *cm); + +/* CMDDEF is used to define top-level commands. It does not accumulate +** them into a table (C is far too puny for that) but gathers together +** various information that a higher-level table can then point to. +*/ +#define CMDDEF(deflab, func, flgs, argsyn, minihelp, longdesc) \ + static void func(struct cmd_s *); \ + static struct cmrtn_s deflab = { func, flgs, argsyn, minihelp, longdesc }; + +#define KEYSBEGIN(name) struct cmkey_s name[] = { +#define KEYDEF(key,nod) { key, (union cmnode *)(&nod) }, +#define KEYSEND { 0, 0 } }; + diff --git a/src/dvni20.c b/src/dvni20.c index e7c77a2..c9f8903 100644 --- a/src/dvni20.c +++ b/src/dvni20.c @@ -55,6 +55,7 @@ static int decosfcclossage; #include "kn10dev.h" #include "kn10ops.h" #include "dvni20.h" +#include "cmdline.h" #include "prmstr.h" /* For parameter parsing */ #if KLH10_DEV_DPNI20 /* Event handling and dev sub-proc stuff! */ @@ -238,6 +239,7 @@ static w10_t ni20_datai(struct device *d); static int ni20_init(struct device *d, FILE *of); static void ni20_reset(struct device *d); static void ni20_powoff(struct device *d); +static int ni20_cmd(struct device *d, FILE *of, char *cmdline); #if KLH10_DEV_DPNI20 static void ni20_evhsdon(struct device *d, struct dvevent_s *evp); static void ni20_evhrwak(struct device *d, struct dvevent_s *evp); @@ -327,22 +329,16 @@ static char *niprmtab[] = { static int pareth(char *cp, unsigned char *adr); static int parip(char *cp, unsigned char *adr); -/* NI20_CONF - Parse configuration string and set defaults. -** At this point, device has just been created, but not yet bound -** or initialized. -** NOTE that some strings are dynamically allocated! Someday may want -** to clean them up nicely if config fails or device is uncreated. +/* Set defaults for all configurable parameters */ - static int -ni20_conf(FILE *f, char *s, struct ni20 *ni) +ni20_conf_clear(struct ni20 *ni) { int i, ret = TRUE; struct prmstate_s prm; char buff[200]; long lval; - /* First set defaults for all configurable parameters */ DVDEBUG(ni) = FALSE; ni->ni_ifnam = NULL; ni->ni_ifmeth = NULL; @@ -363,6 +359,22 @@ ni20_conf(FILE *f, char *s, struct ni20 *ni) ni->ni_dpidly = 5; /* Conservative 5-second timeout for T10/T20 */ ni->ni_dpdbg = FALSE; #endif +} + +/* NI20_CONF - Parse configuration string and set defaults. +** At this point, device has just been created, but not yet bound +** or initialized. +** NOTE that some strings are dynamically allocated! Someday may want +** to clean them up nicely if config fails or device is uncreated. +*/ + +static int +ni20_conf(FILE *f, char *s, struct ni20 *ni) +{ + int i, ret = TRUE; + struct prmstate_s prm; + char buff[200]; + long lval; prm_init(&prm, buff, sizeof(buff), s, strlen(s), @@ -620,12 +632,14 @@ dvni20_create(FILE *f, char *s) ni->ni_dv.dv_coni = ni20_coni; ni->ni_dv.dv_datao = ni20_datao; ni->ni_dv.dv_datai = ni20_datai; + ni->ni_dv.dv_cmd = ni20_cmd; ni->ni_dv.dv_bind = NULL; /* Not a controller!! */ ni->ni_dv.dv_init = ni20_init; /* Set up own post-bind init */ ni->ni_dv.dv_reset = ni20_reset; /* System reset (clear stuff) */ ni->ni_dv.dv_powoff = ni20_powoff; /* Power-off cleanup */ + ni20_conf_clear(ni); /* Set all defaults */ if (!ni20_conf(f, s, ni)) /* Do configuration stuff */ return NULL; @@ -769,7 +783,7 @@ ni20_reset(struct device *d) ni20_clear((struct ni20 *)d); } -/* NI20_QUIT - Tells the IMP process to quit +/* NI20_QUIT - Tells the DPNI20 process to quit ** and clean up resources such as networking tunnels. */ static void @@ -3442,6 +3456,172 @@ ni20_ioend(register struct device *drv, /* Now if no errors, check for secondary TCR and initiate it? */ } #endif /* 0 */ + +/* +** "dev ni0 xxx" subcommands +*/ + +struct cmd_ni20_s { + struct cmd_s ni20_cmd; + struct ni20 *ni20_dev; + FILE *ni20_of; +}; + +CMDDEF(cd_ques, fc_ques, CMRF_NOARG, NULL, + "How to get help for the DEV NIx subcommand", "") +CMDDEF(cd_help, fc_help, CMRF_TOKS, NULL, + "Basic help for the DEV NIx subcommands", "") +CMDDEF(cd_init, fc_init, CMRF_NOARG, NULL, + "Initialize the NI20 unit", "") +CMDDEF(cd_start, fc_start, CMRF_NOARG, NULL, + "Start the NI20 unit", "") +CMDDEF(cd_stop, fc_stop, CMRF_NOARG, NULL, + "Stop the NI20 unit", "") +CMDDEF(cd_powoff,fc_powoff, CMRF_NOARG, NULL, + "Power the NI20 unit off", "") +CMDDEF(cd_set, fc_set, CMRF_TLIN, NULL, + "Dynamically change config settings (not all will work!)", "") +#if KLH10_DEV_DPNI20 +CMDDEF(cd_dpquit,fc_dpquit, CMRF_NOARG, NULL, + "Tell the Device Proc to quit", "") +CMDDEF(cd_dpstart,fc_dpstart,CMRF_NOARG, NULL, + "Start the Device Process for the NI20 unit", "") +#endif /* KLH10_DEV_DPNI20 */ + +KEYSBEGIN(ni20keys) + KEYDEF("?", cd_ques) + KEYDEF("help", cd_help) + KEYDEF("init", cd_init) + KEYDEF("start", cd_start) + KEYDEF("stop", cd_stop) + KEYDEF("powoff", cd_powoff) + KEYDEF("set", cd_set) +#if KLH10_DEV_DPNI20 + KEYDEF("dpstart", cd_dpstart) + KEYDEF("dpquit", cd_dpquit) +#endif /* KLH10_DEV_DPNI20 */ +KEYSEND + +static int +ni20_cmd(struct device *d, FILE *of, char *cmdline) +{ + static struct cmd_ni20_s ni20_command; + static char cmdbuf[CMDBUFLEN]; /* Original command string buffer */ + + ni20_command.ni20_dev = (struct ni20 *)d; + ni20_command.ni20_of = of; + + cmdinit(&ni20_command.ni20_cmd, ni20keys, "NI20> ", + cmdbuf, sizeof(cmdbuf)); + cmdlcopy(&ni20_command.ni20_cmd, cmdline); + cmdexec(&ni20_command.ni20_cmd); +} + + +static void +fc_ques(struct cmd_s *cm) +{ + fc_gques(cm); +} + +static void +fc_help(struct cmd_s *cm) +{ + fc_ghelp(cm); +} + +static void +fc_init(struct cmd_s *cm0) +{ + struct cmd_ni20_s *cm = (struct cmd_ni20_s *)cm0; + + ni20_init(&cm->ni20_dev->ni_dv, cm->ni20_of); +} + +static void +fc_start(struct cmd_s *cm0) +{ + struct cmd_ni20_s *cm = (struct cmd_ni20_s *)cm0; + + ni20_start(cm->ni20_dev); +} + +static void +fc_stop(struct cmd_s *cm0) +{ + struct cmd_ni20_s *cm = (struct cmd_ni20_s *)cm0; + + ni20_stop(cm->ni20_dev); +} + +static void +fc_powoff(struct cmd_s *cm0) +{ + struct cmd_ni20_s *cm = (struct cmd_ni20_s *)cm0; + + ni20_powoff(&cm->ni20_dev->ni_dv); +} + +static void +fc_set(struct cmd_s *cm0) +{ + struct cmd_ni20_s *cm = (struct cmd_ni20_s *)cm0; + + ni20_conf(cm->ni20_of, cm0->cmd_arglin, cm->ni20_dev); +} + +#if KLH10_DEV_DPNI20 + +static void +fc_dpstart(struct cmd_s *cm0) +{ + struct cmd_ni20_s *cm = (struct cmd_ni20_s *)cm0; + struct ni20 *ni = cm->ni20_dev; + FILE *of = cm->ni20_of; + + fprintf(of, "[starting DP \"%s\"...", ni->ni_dpname); + + /* HORRIBLE UGLY HACK: for AXP OSF/1 and perhaps other systems, + ** the virtual-runtime timer of setitimer() remains in effect even + ** for the child process of a fork()! To avoid this, we must + ** temporarily turn the timer off, then resume it after the fork + ** is safely out of the way. + ** + ** Otherise, the timer would go off and the unexpected signal would + ** chop down the DP subproc without any warning! + ** + ** Later this should be done in DPSUP.C itself, when I can figure a + ** good way to tell whether the code is part of the KLH10 or a DP + ** subproc. + */ + clk_suspend(); /* Clear internal clock if one */ + int res = dp_start(&ni->ni_dp, ni->ni_dpname); + clk_resume(); /* Resume internal clock if one */ + + if (!res) { + fprintf(of, " Start of DP \"%s\" failed!]\r\n", + ni->ni_dpname); + } else { + fprintf(of, " started!]\r\n"); + } + + /* Set state to "running", assume disabled. + */ + ni->ni_state = NI20_ST_RUN; /* Running disabled */ + ni->ni_dpstate = TRUE; /* Not quite matching other uses, + * but required for dpquit() */ +} + +static void +fc_dpquit(struct cmd_s *cm0) +{ + struct cmd_ni20_s *cm = (struct cmd_ni20_s *)cm0; + + ni20_quit(cm->ni20_dev); +} + +#endif /* KLH10_DEV_DPNI20 */ + /* Massbus Data Channel routines. ** diff --git a/src/klh10.c b/src/klh10.c index ec8e912..7b35c6f 100644 --- a/src/klh10.c +++ b/src/klh10.c @@ -56,6 +56,7 @@ #include "wfio.h" #include "fecmd.h" #include "feload.h" +#include "cmdline.h" #include "prmstr.h" #include "dvcty.h" /* For cty_ functions */ @@ -151,87 +152,15 @@ static int cminchar(void); /* Funct to read from file or TTY */ #define CMDQCHAR '\\' /* Quote char for token parsing */ -#ifndef CMDBUFLEN -# define CMDBUFLEN 512 -#endif -#ifndef CMDMAXARG -# define CMDMAXARG 10 -#endif - -struct cmd_s { - int cmd_flags; /* State flags */ - char *cmd_prm; /* Pointer to command prompt */ - char *cmd_buf; /* Pointer to start of buffer */ - size_t cmd_blen; /* Size of buffer */ - int cmd_left; /* # chars left for current cmd being input */ - char *cmd_inp; /* Input deposit pointer */ - char *cmd_rdp; /* Readout pointer */ - size_t cmd_rleft; /* # chars left to read */ - - /* Provide all command routines with their desired arguments */ - char *cmd_arglin; /* Original pointer to start of args on line */ - int cmd_argc; /* # of tokens */ - char *cmd_argv[CMDMAXARG+1]; /* Array of token pointers */ - char *cmd_tdp; /* Next free loc in token buffer */ - size_t cmd_tleft; /* # chars free in token buffer */ - char cmd_tokbuf[CMDBUFLEN+CMDMAXARG]; - -#if 0 - char *cmd_wbf; /* Pointer to work buffer */ - size_t cmd_wblen; /* Size in chars */ - char *cmd_wbp; /* Current deposit ptr */ - size_t cmd_wbleft; /* # chars left */ -#endif -} command; - -#define CMDF_ACTIVE 01 /* Activation char seen, execute accumulated cmd */ -#define CMDF_INACCUM 02 /* In accumulation phase */ -#define CMDF_NOPRM 040 /* Disable prompt */ static char cmdbuf[CMDBUFLEN]; /* Original command string buffer */ #if 0 static char cmdwbf[CMDBUFLEN]; /* Working buffer */ #endif -struct cmkey_s { - char *cmk_key; - union cmnode *cmk_p; -}; -struct cmrtn_s { - void (*cmr_vect)(struct cmd_s *); /* Function to call */ - int cmr_flgs; /* Misc flags */ - char *cmr_synt; /* Arg syntax */ - char *cmr_help; /* Short one-line help */ - char *cmr_desc; /* Long description */ -}; - -#define CMRF_NOARG 01 /* Command takes no args */ -#define CMRF_TOKS 010 /* Command wants whole line tokenized, via cm */ -#define CMRF_TLIN 020 /* Command wants overall line arg, via cm */ -#define CMRF_CMPTR 040 /* Command wants just cmd state ptr */ - -union cmnode { /* All possible nodes for a keyword */ - struct cmrtn_s cmn_rtn; -}; - - -/* Predeclarations */ -void cmdinit(struct cmd_s *, char *, char *, size_t); -int cmdexec(struct cmd_s *); -int cmdaccum(struct cmd_s *); - -struct cmkey_s *cmdkeylookup(char *, struct cmkey_s *, struct cmkey_s **); -char *cmdlsetup(struct cmd_s *); static void slinlim(char *); - -/* CMDDEF is used to define top-level commands. It does not accumulate -** them into a table (C is far too puny for that) but gathers together -** various information that a higher-level table can then point to. -*/ -#define CMDDEF(deflab, func, flgs, argsyn, minihelp, longdesc) \ - static void func(struct cmd_s *); \ - static struct cmrtn_s deflab = { func, flgs, argsyn, minihelp, longdesc }; +static struct cmd_s command; CMDDEF(cd_ques, fc_ques, CMRF_NOARG, NULL, "How to get help", "") @@ -323,10 +252,6 @@ CMDDEF(cd_lights, fc_lights, CMRF_TLIN, "", #endif -#define KEYSBEGIN(name) struct cmkey_s name[] = { -#define KEYDEF(key,nod) { key, (union cmnode *)(&nod) }, -#define KEYSEND { 0, 0 } }; - KEYSBEGIN(fectbkeys) KEYDEF("?", cd_ques) KEYDEF("help", cd_help) @@ -525,7 +450,7 @@ fe_cmdloop(void) /* Determine new prompt if necessary */ if (cmdpromptnew || (omode != cpu.fe.fe_mode)) { - cmdinit(&command, fe_cmprompt(cpu.fe.fe_mode), + cmdinit(&command, fectbkeys, fe_cmprompt(cpu.fe.fe_mode), cmdbuf, sizeof(cmdbuf)); omode = cpu.fe.fe_mode; prompted = FALSE; @@ -836,10 +761,12 @@ static int cmdargs_all(struct cmd_s *cm); static int cmdargs_n(struct cmd_s *cm, int n); void cmdinit(struct cmd_s *cm, + struct cmkey_s *keys, char *prompt, char *ibuf, size_t ilen) { + cm->cmd_keys = keys; cm->cmd_flags = 0; cm->cmd_prm = prompt; cm->cmd_buf = ibuf; @@ -959,7 +886,7 @@ cmdexec(struct cmd_s *cm) /* Have token, see if it's a command */ stolower(cp); /* Force lowercase for lookup */ - argc = s_keylookup(cp, fectbkeys, sizeof(struct cmkey_s), + argc = s_keylookup(cp, cm->cmd_keys, sizeof(struct cmkey_s), (void *)&key, (void *)&key2); if (argc <= 0) { printf("Unknown command: \"%s\"\n", cp); @@ -1005,7 +932,10 @@ cmdexec(struct cmd_s *cm) return 1; } - +/* +** Fetch a command line from the front end console, or from a command +** file. +*/ char * cmdlsetup(struct cmd_s *cm) { @@ -1050,6 +980,30 @@ cmdlsetup(struct cmd_s *cm) return cp; } +/* CMDLCOPY - Copy a command line into the previously indicated buffer. +*/ +char * +cmdlcopy(struct cmd_s *cm, char *line) +{ + int len = strlen(line); + if (len > cm->cmd_blen) { + len = cm->cmd_blen - 1; + } + + if (cpu.fe.fe_debug) + fprintf(stderr, "[cmdlcopy]"); + + strncpy(cm->cmd_buf, line, len); + cm->cmd_buf[len] = '\0'; + + cm->cmd_rdp = cm->cmd_buf; + cm->cmd_inp = cm->cmd_buf + len; + cm->cmd_rleft = len; + cm->cmd_left = cm->cmd_blen - len; + + return cm->cmd_buf; +} + /* CMDFLS - Flush whitespace from current command pos */ @@ -1158,6 +1112,12 @@ fc_ques(struct cmd_s *cm) printf("Type \"help\" or \"help \" for help.\n"); } +void +fc_gques(struct cmd_s *cm) +{ + fc_ques(cm); +} + static void helpline(register struct cmkey_s *kp) { @@ -1187,13 +1147,13 @@ fc_help(struct cmd_s *cm) cp = cm->cmd_argv[0]; if (!cp || !*cp) { /* If no specific arg, show everything */ - for (kp = fectbkeys; kp->cmk_key; ++kp) { + for (kp = cm->cmd_keys; kp->cmk_key; ++kp) { helpline(kp); } return; } - (void) s_keylookup(cp, (voidp_t)fectbkeys, sizeof(struct cmkey_s), + (void) s_keylookup(cp, (voidp_t)cm->cmd_keys, sizeof(struct cmkey_s), (voidp_t *)&kp, (voidp_t *)&key2); if (!kp) { printf("Unknown command: \"%s\"\n", cp); @@ -1207,12 +1167,18 @@ fc_help(struct cmd_s *cm) } /* More than one match, show each one */ - for (kp = fectbkeys; kp->cmk_key; ++kp) { + for (kp = cm->cmd_keys; kp->cmk_key; ++kp) { if (smatch(cp, kp->cmk_key) > 0) helpline(kp); } } +void +fc_ghelp(struct cmd_s *cm) +{ + fc_help(cm); +} + /* SLINLIM - Limit string to 1 line by chopping it at first EOL seen. */ static void