--- freem/src/xecline.c 2025/05/05 14:53:17 1.22 +++ freem/src/xecline.c 2025/05/20 14:36:06 1.28 @@ -1,5 +1,5 @@ /* - * $Id: xecline.c,v 1.22 2025/05/05 14:53:17 snw Exp $ + * $Id: xecline.c,v 1.28 2025/05/20 14:36:06 snw Exp $ * freem interpreter proper * * @@ -24,6 +24,24 @@ * along with FreeM. If not, see . * * $Log: xecline.c,v $ + * Revision 1.28 2025/05/20 14:36:06 snw + * Documentation updates; raise ZCMMND instead of NOSTAND for restricted_mode restrictions + * + * Revision 1.27 2025/05/19 21:29:29 snw + * Add basic tab completion to direct mode + * + * Revision 1.26 2025/05/19 02:03:31 snw + * Reverse-engineer and document argumented ZPRINT (thanks to D. Wicksell) + * + * Revision 1.25 2025/05/18 18:15:38 snw + * Add ZEDIT command for editing routines + * + * Revision 1.24 2025/05/14 12:22:04 snw + * Further work on shared memory + * + * Revision 1.23 2025/05/06 16:10:06 snw + * Add extra blank before readline call on NetBSD + * * Revision 1.22 2025/05/05 14:53:17 snw * Modify rpm spec to include documentation TODO * @@ -171,6 +189,162 @@ void rbuf_dump(void); short rbuf_slot_from_name(char *); short is_standard(void); +#ifdef HAVE_LIBREADLINE +char *m_commands[] = { + "?", + "@", + "!<", + "!>", + "!!", + "ablock", + "astart", + "astop", + "aunblock", + "break", + "close", + "do", + "else", + "events", + "for", + "goto", + "halt", + "hang", + "history", + "if", + "job", + "jobtab", + "kill", + "ksubscripts", + "kvalue", + "lock", + "locktab", + "merge", + "new", + "open", + "quit", + "rbuf", + "rcl", + "read", + "set", + "shmpages", + "shmstat", + "tcommit", + "then", + "trantab", + "trollback", + "tstart", + "use", + "view", + "wh", + "write", + "xecute", + "zassert", + "zbreak", + "zconst", + "zedit", + "zgoto", + "zhalt", + "zinsert", + "zjob", + "zload", + "zmap", + "znew", + "zprint", + "zquit", + "zremove", + "zsave", + "zthrow", + "ztrap", + "zunmap", + "zwatch", + "zwith", + "zwrite", + "ABLOCK", + "ASTART", + "ASTOP", + "AUNBLOCK", + "BREAK", + "CLOSE", + "DO", + "ELSE", + "FOR", + "GOTO", + "HALT", + "HANG", + "IF", + "JOB", + "KILL", + "KSUBSCRIPTS", + "KVALUE", + "LOCK", + "MERGE", + "NEW", + "OPEN", + "QUIT", + "READ", + "SET", + "TCOMMIT", + "THEN", + "TROLLBACK", + "TSTART", + "USE", + "VIEW", + "WRITE", + "XECUTE", + "ZASSERT", + "ZBREAK", + "ZCONST", + "ZEDIT", + "ZGOTO", + "ZHALT", + "ZINSERT", + "ZJOB", + "ZLOAD", + "ZMAP", + "ZNEW", + "ZPRINT", + "ZQUIT", + "ZREMOVE", + "ZSAVE", + "ZTHROW", + "ZTRAP", + "ZUNMAP", + "ZWATCH", + "ZWITH", + "ZWRITE", + NULL +}; + +char **command_completion(const char *, int, int); +char *command_generator(const char *, int); + +char **command_completion(const char *text, int start, int end) +{ + if (start > 0) return NULL; + rl_attempted_completion_over = 1; + return rl_completion_matches(text, command_generator); +} + +char *command_generator(const char *text, int state) +{ + static int list_index, len; + char *name; + + if (!state) { + list_index = 0; + len = strlen(text); + } + + while ((name = m_commands[list_index++])) { + if (strncmp(name, text, len) == 0) { + return strdup(name); + } + } + + return NULL; +} +#endif + /* * xecline(): * typ (where to go on function entry): 1 = restart @@ -258,7 +432,7 @@ next_line: /* entry point for n if (debug_mode) { debug_mode = debugger (DEBENTRY_LINE, entryref); } - + job_set_status (pid, JSTAT_INTERPRETER); if (then_ctr > 0) { @@ -531,7 +705,7 @@ next0: if (ch == '!') { /* UNIXCALL */ if (restricted_mode) { - merr_raise (NOSTAND); + merr_raise (CMMND); goto err; } @@ -4534,7 +4708,7 @@ use_socket: if (k > MAXSEQ) goto open_socket; if (restricted_mode) { - merr_raise (NOSTAND); + merr_raise (CMMND); goto err; } @@ -5286,6 +5460,11 @@ halt: break; /* Z-COMMANDS */ + case ZEDIT: + merr_raise (cmd_zedit (&ra)); + MRESCHECK(ra); + break; + case ZGO: /* ZGO with arguments: same as GOTO but with BREAK on */ @@ -5425,7 +5604,7 @@ zgo: merr_raise (NOPGM); break; - } /*error */ + } /* error */ stcpy (varnam, rou_name); } @@ -5561,11 +5740,11 @@ zgo: if (*codptr == EOL || *codptr == SP) { merr_raise (ARGLIST); break; - } /*error */ + } /* error */ dosave[0] = EOL; - /* parse stringlit */ + /* parse strlit */ expr (STRING); if (merr () > OK) break; @@ -5674,7 +5853,7 @@ zgo: } if ((*(beg + 1)) == EOL) break; - + write_m (beg + 1); if (merr () > OK) break; } @@ -7276,6 +7455,8 @@ direct_mode: int hist_idx; HIST_ENTRY *hist_ent; + rl_attempted_completion_function = command_completion; + if (quiet_mode == FALSE) { if (tp_level == 0) { snprintf (fmrl_prompt, sizeof (fmrl_prompt) - 1, "\r\n%s.%s> ", shm_env, nsname); @@ -7287,7 +7468,11 @@ direct_mode: set_io (UNIX); job_set_status (pid, JSTAT_DIRECTMODE); - + +#if defined(__NetBSD__) + printf ("\r\n"); +#endif + /* readline() does its own malloc() */ fmrl_buf = readline (fmrl_prompt); @@ -7298,6 +7483,7 @@ direct_mode: goto halt; } + if (strlen (fmrl_buf) > 0) { add_history (fmrl_buf);