joe-3.1jupp31.tgz (die zweite Klappeā€¦)
[alioth/jupp.git] / cmd.c
1 /* $MirOS: contrib/code/jupp/cmd.c,v 1.17 2017/08/08 21:39:28 tg Exp $ */
2 /*
3  *      Command execution
4  *      Copyright
5  *              (C) 1992 Joseph H. Allen
6  *
7  *      This file is part of JOE (Joe's Own Editor)
8  */
9 #include "config.h"
10 #include "types.h"
11
12 #ifdef HAVE_STDLIB_H
13 #include <stdlib.h>
14 #endif
15 #include <string.h>
16
17 #include "b.h"
18 #include "bw.h"
19 #include "cmd.h"
20 #include "hash.h"
21 #include "help.h"
22 #include "kbd.h"
23 #include "macro.h"
24 #include "main.h"
25 #include "menu.h"
26 #include "path.h"
27 #include "poshist.h"
28 #include "pw.h"
29 #include "rc.h"
30 #include "tty.h"
31 #include "tw.h"
32 #include "ublock.h"
33 #include "uedit.h"
34 #include "uerror.h"
35 #include "ufile.h"
36 #include "uformat.h"
37 #include "uisrch.h"
38 #include "umath.h"
39 #include "undo.h"
40 #include "usearch.h"
41 #include "ushell.h"
42 #include "utag.h"
43 #include "utils.h"
44 #include "va.h"
45 #include "vs.h"
46 #include "utf8.h"
47 #include "w.h"
48
49 extern int marking;
50 extern int smode;
51 int dobeep = 0;
52 int uexecmd(BW *bw);
53
54 /* Command table */
55
56 int ubeep(BW *bw, int k)
57 {
58         ttputc(7);
59         return 0;
60 }
61
62 extern char main_context[];
63 static int do_keymap(BW *bw, unsigned char *s, void *object, int *notify)
64 {
65         KMAP *new_kmap;
66
67         if (notify)
68                 *notify = 1;
69         if (!s || !*s || !(new_kmap = kmap_getcontext(s, 0)))
70                 return (-1);
71         if (bw->o.context != (unsigned char *)main_context)
72                 free(bw->o.context);
73         bw->o.context = strcmp((char *)s, main_context) ?
74             (unsigned char *)strdup((char *)s) : (unsigned char *)main_context;
75         rmkbd(bw->parent->kbd);
76         bw->parent->kbd = mkkbd(new_kmap);
77         joe_snprintf_1((char *)msgbuf, JOE_MSGBUFSIZE, "New keymap: %s", s);
78         msgnw(bw->parent, msgbuf);
79         return (0);
80 }
81 static int ukeymap(BW *bw)
82 {
83         if (wmkpw(bw->parent, US "Name of keymap to switch to: ", NULL,
84             do_keymap, NULL, NULL, utypebw, NULL, NULL, locale_map)) {
85                 return (0);
86         }
87         return (-1);
88 }
89
90 static int unop(void)
91 {
92         return (0);
93 }
94
95 CMD cmds[] = {
96         {US "abendjoe", TYPETW + TYPEPW + TYPEMENU + TYPEQW, uabendjoe, NULL, 0, NULL},
97         {US "abort", TYPETW + TYPEPW + TYPEMENU + TYPEQW, uabort, NULL, 0, NULL},
98         {US "abortbuf", TYPETW, uabortbuf, NULL, 0, NULL},
99         {US "arg", TYPETW + TYPEPW + TYPEMENU + TYPEQW, uarg, NULL, 0, NULL},
100         {US "ask", TYPETW + TYPEPW, uask, NULL, 0, NULL},
101         {US "backs", TYPETW + TYPEPW + ECHKXCOL + EFIXXCOL + EMINOR + EKILL + EMOD, ubacks, NULL, 1, US "delch"},
102         {US "backsmenu", TYPEMENU, umbacks, NULL, 1, NULL},
103         {US "backw", TYPETW + TYPEPW + ECHKXCOL + EFIXXCOL + EKILL + EMOD, ubackw, NULL, 1, US "delw"},
104         {US "beep", TYPETW + TYPEPW + TYPEMENU + TYPEQW, ubeep, NULL, 0, NULL},
105         {US "begin_marking", TYPETW + TYPEPW, ubegin_marking, NULL, 0, NULL},
106         {US "bknd", TYPETW + TYPEPW, ubknd, NULL, 0, NULL},
107         {US "bkwdc", TYPETW + TYPEPW, ubkwdc, NULL, 1, US "fwrdc"},
108         {US "blkcpy", TYPETW + TYPEPW + EFIXXCOL + EMOD + EBLOCK, ublkcpy, NULL, 1, NULL},
109         {US "blkdel", TYPETW + TYPEPW + EFIXXCOL + EKILL + EMOD + EBLOCK, ublkdel, NULL, 0, NULL},
110         {US "blkmove", TYPETW + TYPEPW + EFIXXCOL + EMOD + EBLOCK, ublkmove, NULL, 0, NULL},
111         {US "blksave", TYPETW + TYPEPW + EBLOCK, ublksave, NULL, 0, NULL},
112         {US "bof", TYPETW + TYPEPW + EMOVE + EFIXXCOL, u_goto_bof, NULL, 0, NULL},
113         {US "bofmenu", TYPEMENU, umbof, NULL, 0, NULL},
114         {US "bol", TYPETW + TYPEPW + EFIXXCOL, u_goto_bol, NULL, 0, NULL},
115         {US "bolmenu", TYPEMENU, umbol, NULL, 0, NULL},
116         {US "bop", TYPETW + TYPEPW + EFIXXCOL, ubop, NULL, 1, US "eop"},
117         {US "bos", TYPETW + TYPEPW + EMOVE, ubos, NULL, 0, NULL},
118         {US "bufed", TYPETW, ubufed, NULL, 0, NULL},
119         {US "build", TYPETW + TYPEPW, ubuild, NULL, 0, NULL},
120         {US "byte", TYPETW + TYPEPW, ubyte, NULL, 0, NULL},
121         {US "cancel", TYPETW + TYPEPW + TYPEMENU + TYPEQW, ucancel, NULL, 0, NULL},
122         {US "center", TYPETW + TYPEPW + EFIXXCOL + EMOD, ucenter, NULL, 1, NULL},
123         {US "col", TYPETW + TYPEPW, ucol, NULL, 0, NULL},
124         {US "complete", TYPEPW + EMINOR + EMOD, ucmplt, NULL, 0, NULL},
125         {US "copy", TYPETW + TYPEPW, ucopy, NULL, 0, NULL},
126         {US "crawll", TYPETW + TYPEPW, ucrawll, NULL, 1, US "crawlr"},
127         {US "crawlr", TYPETW + TYPEPW, ucrawlr, NULL, 1, US "crawll"},
128         {US "ctrl", TYPETW + TYPEPW + EMOD, uctrl, NULL, 0, NULL},
129         {US "delbol", TYPETW + TYPEPW + EFIXXCOL + EKILL + EMOD, udelbl, NULL, 1, US "deleol"},
130         {US "delch", TYPETW + TYPEPW + ECHKXCOL + EFIXXCOL + EMINOR + EKILL + EMOD, udelch, NULL, 1, US "backs"},
131         {US "deleol", TYPETW + TYPEPW + EKILL + EMOD, udelel, NULL, 1, US "delbol"},
132         {US "dellin", TYPETW + TYPEPW + EFIXXCOL + EKILL + EMOD, udelln, NULL, 1, NULL},
133         {US "delw", TYPETW + TYPEPW + EFIXXCOL + ECHKXCOL + EKILL + EMOD, u_word_delete, NULL, 1, US "backw"},
134         {US "dnarw", TYPETW + TYPEPW + EMOVE, udnarw, NULL, 1, US "uparw"},
135         {US "dnarwmenu", TYPEMENU, umdnarw, NULL, 1, US "uparwmenu"},
136         {US "dnslide", TYPETW + TYPEPW + TYPEMENU + TYPEQW + EMOVE, udnslide, NULL, 1, US "upslide"},
137         {US "drop", TYPETW + TYPEPW, udrop, NULL, 0, NULL},
138         {US "dupw", TYPETW, uduptw, NULL, 0, NULL},
139         {US "edit", TYPETW, uedit, NULL, 0, NULL},
140         {US "eof", TYPETW + TYPEPW + EFIXXCOL + EMOVE, u_goto_eof, NULL, 0, NULL},
141         {US "eofmenu", TYPEMENU, umeof, NULL, 0, NULL},
142         {US "eol", TYPETW + TYPEPW + EFIXXCOL, u_goto_eol, NULL, 0, NULL},
143         {US "eolmenu", TYPEMENU, umeol, NULL, 0, NULL},
144         {US "eop", TYPETW + TYPEPW + EFIXXCOL, ueop, NULL, 1, US "bop"},
145         {US "execmd", TYPETW + TYPEPW, uexecmd, NULL, 0, NULL},
146         {US "explode", TYPETW + TYPEPW + TYPEMENU + TYPEQW, uexpld, NULL, 0, NULL},
147         {US "exsave", TYPETW + TYPEPW, uexsve, NULL, 0, NULL},
148         {US "ffirst", TYPETW + TYPEPW, pffirst, NULL, 0, NULL},
149         {US "filt", TYPETW + TYPEPW + EMOD + EBLOCK, ufilt, NULL, 0, NULL},
150         {US "finish", TYPETW + TYPEPW + EMOD, ufinish, NULL, 1, NULL},
151         {US "fmtblk", TYPETW + EMOD + EFIXXCOL + EBLOCK, ufmtblk, NULL, 1, NULL},
152         {US "fnext", TYPETW + TYPEPW, pfnext, NULL, 1, NULL},
153         {US "format", TYPETW + TYPEPW + EFIXXCOL + EMOD, uformat, NULL, 1, NULL},
154         {US "fwrdc", TYPETW + TYPEPW, ufwrdc, NULL, 1, US "bkwdc"},
155         {US "gomark", TYPETW + TYPEPW + EMOVE, ugomark, NULL, 0, NULL},
156         {US "groww", TYPETW, ugroww, NULL, 1, US "shrinkw"},
157         {US "help", TYPETW + TYPEPW + TYPEQW, u_help, NULL, 0, NULL},
158         {US "helpcard", TYPETW + TYPEPW + TYPEQW, u_helpcard, NULL, 0, NULL},
159         {US "hnext", TYPETW + TYPEPW + TYPEQW, u_help_next, NULL, 0, NULL},
160         {US "home", TYPETW + TYPEPW + EFIXXCOL, uhome, NULL, 0, NULL},
161         {US "hprev", TYPETW + TYPEPW + TYPEQW, u_help_prev, NULL, 0, NULL},
162         {US "insc", TYPETW + TYPEPW + EFIXXCOL + EMOD, uinsc, NULL, 1, US "delch"},
163         {US "insf", TYPETW + TYPEPW + EMOD, uinsf, NULL, 0, NULL},
164         {US "isrch", TYPETW + TYPEPW, uisrch, NULL, 0, NULL},
165         {US "keymap", TYPETW + TYPEPW, ukeymap, NULL, 0, NULL},
166         {US "killjoe", TYPETW + TYPEPW + TYPEMENU + TYPEQW, ukilljoe, NULL, 0, NULL},
167         {US "killproc", TYPETW + TYPEPW, ukillpid, NULL, 0, NULL},
168         {US "lindent", TYPETW + TYPEPW + EFIXXCOL + EMOD + EBLOCK, ulindent, NULL, 1, US "rindent"},
169         {US "line", TYPETW + TYPEPW, uline, NULL, 0, NULL},
170         {US "lose", TYPETW + TYPEPW, ulose, NULL, 0, NULL},
171         {US "lower", TYPETW + TYPEPW + EMOD + EBLOCK, ulower, NULL, 0, NULL},
172         {US "ltarw", TYPETW + TYPEPW /* + EFIXXCOL + ECHKXCOL */, u_goto_left, NULL, 1, US "rtarw"},
173         {US "ltarwmenu", TYPEMENU, umltarw, NULL, 1, US "rtarwmenu"},
174         {US "macros", TYPETW + EFIXXCOL, umacros, NULL, 0, NULL},
175         {US "markb", TYPETW + TYPEPW, umarkb, NULL, 0, NULL},
176         {US "markk", TYPETW + TYPEPW, umarkk, NULL, 0, NULL},
177         {US "markl", TYPETW + TYPEPW, umarkl, NULL, 0, NULL},
178         {US "math", TYPETW + TYPEPW, umath, NULL, 0, NULL},
179         {US "mathins", TYPETW + TYPEPW, umathins, NULL, 0, NULL},
180         {US "mathres", TYPETW + TYPEPW, umathres, NULL, 0, NULL},
181         {US "mode", TYPETW + TYPEPW + TYPEQW, umode, NULL, 0, NULL},
182         {US "msg", TYPETW + TYPEPW + TYPEQW + TYPEMENU, umsg, NULL, 0, NULL},
183         {US "nbuf", TYPETW, unbuf, NULL, 1, US "pbuf"},
184         {US "nedge", TYPETW + TYPEPW + EFIXXCOL, unedge, NULL, 1, US "pedge"},
185         {US "nextpos", TYPETW + TYPEPW + EFIXXCOL + EMID + EPOS, unextpos, NULL, 1, US "prevpos"},
186         {US "nextw", TYPETW + TYPEPW + TYPEMENU + TYPEQW, unextw, NULL, 1, US "prevw"},
187         {US "nextword", TYPETW + TYPEPW + EFIXXCOL, u_goto_next, NULL, 1, US "prevword"},
188         {US "nmark", TYPETW + TYPEPW, unmark, NULL, 0, NULL},
189         {US "nop", TYPETW + TYPEPW + TYPEMENU + TYPEQW, unop, NULL, 0, NULL},
190         {US "notmod", TYPETW, unotmod, NULL, 0, NULL},
191         {US "nxterr", TYPETW, unxterr, NULL, 1, US "prverr"},
192         {US "open", TYPETW + TYPEPW + EFIXXCOL + EMOD, uopen, NULL, 1, US "deleol"},
193         {US "parserr", TYPETW, uparserr, NULL, 0, NULL},
194         {US "pbuf", TYPETW, upbuf, NULL, 1, US "nbuf"},
195         {US "pedge", TYPETW + TYPEPW + EFIXXCOL, upedge, NULL, 1, US "nedge"},
196         {US "pgdn", TYPETW + TYPEPW + TYPEMENU + TYPEQW + EMOVE, upgdn, NULL, 1, US "pgup"},
197         {US "pgdnmenu", TYPEMENU, umpgdn, NULL, 1, US "pgupmenu"},
198         {US "pgup", TYPETW + TYPEPW + TYPEMENU + TYPEQW + EMOVE, upgup, NULL, 1, US "pgdn"},
199         {US "pgupmenu", TYPEMENU, umpgup, NULL, 1, US "pgdnmenu"},
200         {US "picokill", TYPETW + TYPEPW + EFIXXCOL + EKILL + EMOD, upicokill, NULL, 1, NULL},
201         {US "play", TYPETW + TYPEPW + TYPEMENU + TYPEQW, uplay, NULL, 1, NULL}, /* EFIXX? */
202         {US "pop", TYPETW + TYPEPW + TYPEMENU + TYPEQW, upop, NULL, 0, NULL},
203         {US "prevpos", TYPETW + TYPEPW + EPOS + EMID + EFIXXCOL, uprevpos, NULL, 1, US "nextpos"},
204         {US "prevw", TYPETW + TYPEPW + TYPEMENU + TYPEQW, uprevw, NULL, 1, US "nextw"},
205         {US "prevword", TYPETW + TYPEPW + EFIXXCOL + ECHKXCOL, u_goto_prev, NULL, 1, US "nextword"},
206         {US "prverr", TYPETW, uprverr, NULL, 1, US "nxterr"},
207         {US "psh", TYPETW + TYPEPW + TYPEMENU + TYPEQW, upsh, NULL, 0, NULL},
208         {US "qrepl", TYPETW + TYPEPW + EMOD, pqrepl, NULL, 0, NULL},
209         {US "query", TYPETW + TYPEPW + TYPEMENU + TYPEQW, uquery, NULL, 0, NULL},
210         {US "querysave", TYPETW, uquerysave, NULL, 0, NULL},
211         {US "quote", TYPETW + TYPEPW + EMOD, uquote, NULL, 0, NULL},
212         {US "quote8", TYPETW + TYPEPW + EMOD, uquote8, NULL, 0, NULL},
213         {US "record", TYPETW + TYPEPW + TYPEMENU + TYPEQW, urecord, NULL, 0, NULL},
214         {US "redo", TYPETW + TYPEPW + EFIXXCOL, uredo, NULL, 1, US "undo"},
215         {US "retype", TYPETW + TYPEPW + TYPEMENU + TYPEQW, uretyp, NULL, 0, NULL},
216         {US "rfirst", TYPETW + TYPEPW, prfirst, NULL, 0, NULL},
217         {US "rindent", TYPETW + TYPEPW + EFIXXCOL + EMOD + EBLOCK, urindent, NULL, 1, US "lindent"},
218         {US "rsrch", TYPETW + TYPEPW, ursrch, NULL, 0, NULL},
219         {US "rtarw", TYPETW + TYPEPW /* + EFIXXCOL */, u_goto_right, NULL, 1, US "ltarw"}, /* EFIX removed for picture mode */
220         {US "rtarwmenu", TYPEMENU, umrtarw, NULL, 1, US "ltarwmenu"},
221         {US "rtn", TYPETW + TYPEPW + TYPEMENU + TYPEQW + EMOD, urtn, NULL, 1, NULL},
222         {US "run", TYPETW + TYPEPW, urun, NULL, 0, NULL},
223         {US "rvmatch", TYPETW + TYPEPW + EFIXXCOL, urvmatch, NULL, 0, NULL},
224         {US "save", TYPETW, usave, NULL, 0, NULL},
225         {US "scratch", TYPETW + TYPEPW, uscratch, NULL, 0, NULL},
226         {US "select", TYPETW + TYPEPW, uselect, NULL, 0, NULL},
227         {US "setmark", TYPETW + TYPEPW, usetmark, NULL, 0, NULL},
228         {US "shell", TYPETW + TYPEPW + TYPEMENU + TYPEQW, ushell, NULL, 0, NULL},
229         {US "shrinkw", TYPETW, ushrnk, NULL, 1, US "groww"},
230         {US "splitw", TYPETW, usplitw, NULL, 0, NULL},
231         {US "stat", TYPETW + TYPEPW, ustat, NULL, 0, NULL},
232         {US "stop", TYPETW + TYPEPW + TYPEMENU + TYPEQW, ustop, NULL, 0, NULL},
233         {US "swap", TYPETW + TYPEPW + EFIXXCOL, uswap, NULL, 0, NULL},
234         {US "switch", TYPETW + TYPEPW, uswitch, NULL, 0, NULL},
235         {US "tabmenu", TYPEMENU, umtab, NULL, 1, US "ltarwmenu"},
236         {US "tag", TYPETW + TYPEPW, utag, NULL, 0, NULL},
237         {US "toggle_marking", TYPETW + TYPEPW, utoggle_marking, NULL, 0, NULL},
238         {US "tomarkb", TYPETW + TYPEPW + EFIXXCOL + EBLOCK, utomarkb, NULL, 0, NULL},
239         {US "tomarkbk", TYPETW + TYPEPW + EFIXXCOL + EBLOCK, utomarkbk, NULL, 0, NULL},
240         {US "tomarkk", TYPETW + TYPEPW + EFIXXCOL + EBLOCK, utomarkk, NULL, 0, NULL},
241         {US "tomatch", TYPETW + TYPEPW + EFIXXCOL, utomatch, NULL, 0, NULL},
242         {US "tos", TYPETW + TYPEPW + EMOVE, utos, NULL, 0, NULL},
243         {US "tw0", TYPETW + TYPEPW + TYPEQW + TYPEMENU, utw0, NULL, 0, NULL},
244         {US "tw1", TYPETW + TYPEPW + TYPEQW + TYPEMENU, utw1, NULL, 0, NULL},
245         {US "txt", TYPETW + TYPEPW, utxt, NULL, 0, NULL},
246         {US "type", TYPETW + TYPEPW + TYPEQW + TYPEMENU + EMINOR + EMOD, utype, NULL, 1, US "backs"},
247         {US "uarg", TYPETW + TYPEPW + TYPEMENU + TYPEQW, uuarg, NULL, 0, NULL},
248         {US "undo", TYPETW + TYPEPW + EFIXXCOL, uundo, NULL, 1, US "redo"},
249         {US "uparw", TYPETW + TYPEPW + EMOVE, uuparw, NULL, 1, US "dnarw"},
250         {US "uparwmenu", TYPEMENU, umuparw, NULL, 1, US "dnarwmenu"},
251         {US "upper", TYPETW + TYPEPW + EMOD + EBLOCK, uupper, NULL, 0, NULL},
252         {US "upslide", TYPETW + TYPEPW + TYPEMENU + TYPEQW + EMOVE, uupslide, NULL, 1, US "dnslide"},
253         {US "yank", TYPETW + TYPEPW + EFIXXCOL + EMOD, uyank, NULL, 1, NULL},
254         {US "yankpop", TYPETW + TYPEPW + EFIXXCOL + EMOD, uyankpop, NULL, 1, NULL},
255         {US "yapp", TYPETW + TYPEPW + EKILL, uyapp, NULL, 0, NULL}
256 };
257
258 /* Execute a command n with key k */
259
260 int execmd(CMD *cmd, int k)
261 {
262         BW *bw = (BW *) maint->curwin->object;
263         int ret = -1;
264
265         /* Send data to shell window: this is broken ^K ^H (help) sends its ^H to shell */
266         if ((maint->curwin->watom->what & TYPETW) && bw->b->pid && piseof(bw->cursor) &&
267         (k==3 || k==13 || k==8 || k==127 || k==4 || ((cmd->func==utype) && (k>=32) && (k<256)))) {
268                 unsigned char c = k;
269                 joe_write(bw->b->out, &c, 1);
270                 return 0;
271         }
272
273         if (cmd->m)
274                 return exmacro(cmd->m, 0);
275
276         /* We don't execute if we have to fix the column position first
277          * (i.e., left arrow when cursor is in middle of nowhere) */
278         if (cmd->flag & ECHKXCOL) {
279                 if (bw->o.hex)
280                         bw->cursor->xcol = piscol(bw->cursor);
281                 else if (bw->cursor->xcol != piscol(bw->cursor))
282                         goto skip;
283         }
284
285         /* Don't execute command if we're in wrong type of window */
286         if (!(cmd->flag & maint->curwin->watom->what))
287                 goto skip;
288
289         /* Complete selection for block commands */
290         if ((cmd->flag & EBLOCK) && marking)
291                 utoggle_marking(maint->curwin->object);
292
293         if ((maint->curwin->watom->what & TYPETW) && bw->b->rdonly && (cmd->flag & EMOD)) {
294                 msgnw(bw->parent, US "Read only");
295                 if (dobeep)
296                         ttputc(7);
297                 goto skip;
298         }
299
300         /* Execute command */
301         ret = cmd->func(maint->curwin->object, k);
302
303         if (smode)
304                 --smode;
305
306         /* Don't update anything if we're going to leave */
307         if (leave)
308                 return 0;
309
310         /* cmd->func could have changed bw on us */
311         bw = (BW *) maint->curwin->object;
312
313         /* Maintain position history */
314         /* If command was not a positioning command */
315         if (!(cmd->flag & EPOS)
316             && (maint->curwin->watom->what & (TYPETW | TYPEPW)))
317                 afterpos();
318
319         /* If command was not a movement */
320         if (!(cmd->flag & (EMOVE | EPOS)) && (maint->curwin->watom->what & (TYPETW | TYPEPW)))
321                 aftermove(maint->curwin, bw->cursor);
322
323         if (cmd->flag & EKILL)
324                 justkilled = 1;
325         else
326                 justkilled = 0;
327
328  skip:
329
330         /* Make dislayed cursor column equal the actual cursor column
331          * for commands which arn't simple vertical movements */
332         if (cmd->flag & EFIXXCOL)
333                 bw->cursor->xcol = piscol(bw->cursor);
334
335         /* Recenter cursor to middle of screen */
336         if (cmd->flag & EMID) {
337                 int omid = mid;
338
339                 mid = 1;
340                 dofollows();
341                 mid = omid;
342         }
343
344         if (dobeep && ret)
345                 ttputc(7);
346         return ret;
347 }
348
349 /* Return command table index for given command name */
350
351 HASH *cmdhash = NULL;
352
353 static void izcmds(void)
354 {
355         int x;
356
357         cmdhash = htmk(256);
358         for (x = 0; x != sizeof(cmds) / sizeof(CMD); ++x)
359                 htadd(cmdhash, cmds[x].name, cmds + x);
360 }
361
362 CMD *findcmd(unsigned char *s)
363 {
364         if (!cmdhash)
365                 izcmds();
366         return (CMD *) htfind(cmdhash, s);
367 }
368
369 void addcmd(unsigned char *s, MACRO *m)
370 {
371         CMD *cmd = (CMD *) joe_malloc(sizeof(CMD));
372
373         if (!cmdhash)
374                 izcmds();
375         cmd->name = (unsigned char *)strdup((char *)s);
376         cmd->flag = 0;
377         cmd->func = NULL;
378         cmd->m = m;
379         cmd->arg = 1;
380         cmd->negarg = NULL;
381         htadd(cmdhash, cmd->name, cmd);
382 }
383
384 static unsigned char **getcmds(void)
385 {
386         unsigned char **s = vaensure(NULL, sizeof(cmds) / sizeof(CMD));
387         int x;
388         HENTRY *e;
389
390         for (x = 0; x != cmdhash->len; ++x)
391                 for (e = cmdhash->tab[x]; e; e = e->next)
392                         s = vaadd(s, vsncpy(NULL, 0, sz(e->name)));
393         vasort(s, aLen(s));
394         return s;
395 }
396
397 /* Command line */
398
399 unsigned char **scmds = NULL;   /* Array of command names */
400
401 static int cmdcmplt(BW *bw)
402 {
403         if (!scmds)
404                 scmds = getcmds();
405         /*XXX simple_cmplt does p_goto_bol, better only to last comma */
406         return simple_cmplt(bw, scmds);
407 }
408
409 static int docmd(BW *bw, unsigned char *s, void *object, int *notify)
410 {
411         MACRO *mac;
412         int ret = -1;
413
414         if (s) {
415                 mac = mparse(NULL, s, &ret);
416                 if (ret < 0 || !mac)
417                         msgnw(bw->parent, US "No such command");
418                 else {
419                         ret = exmacro(mac, 1);
420                         rmmacro(mac);
421                 }
422         }
423         vsrm(s);        /* allocated in pw.c::rtnpw() */
424         if (notify)
425                 *notify = 1;
426         return ret;
427 }
428
429 B *cmdhist = NULL;
430
431 int uexecmd(BW *bw)
432 {
433         if (wmkpw(bw->parent, US "cmd: ", &cmdhist, docmd, US "cmd", NULL, cmdcmplt, NULL, NULL, locale_map)) {
434                 return 0;
435         } else {
436                 return -1;
437         }
438 }
439
440 /*
441  * Show help screen at a specific card
442  */
443 static int do_helpcard(BASE *base, unsigned char *s, void *object, int *notify)
444 {
445         struct help *new_help;
446
447         if (notify)
448                 *notify = 1;
449         if (!s || !*s) {
450                 while (help_actual->prev != NULL)
451                         /* find the first help entry */
452                         help_actual = help_actual->prev;
453                 help_off(base->parent->t);
454                 return (0);
455         }
456         if ((new_help = find_context_help(s)) != NULL) {
457                 help_actual = new_help;
458                 return (help_on(base->parent->t));
459         }
460         return (-1);
461 }
462 int u_helpcard(BASE *base)
463 {
464         if (wmkpw(base->parent, US "Name of help card to show: ", NULL,
465             do_helpcard, NULL, NULL, utypebw, NULL, NULL, locale_map)) {
466                 return (0);
467         }
468         return (-1);
469 }