4 * (C) 1992 Joseph H. Allen
6 * This file is part of JOE (Joe's Own Editor)
11 __RCSID("$MirOS: contrib/code/jupp/macro.c,v 1.11 2017/12/02 04:32:40 tg Exp $");
33 MACRO *freemacros = NULL;
37 MACRO *mkmacro(int k, int arg, int n, CMD *cmd)
44 macro = (MACRO *) joe_malloc(sizeof(MACRO) * 64);
45 for (x = 0; x != 64; ++x) { /* FIXME: why limit to 64? */
46 macro[x].steps = (MACRO **) freemacros;
47 freemacros = macro + x;
51 freemacros = (MACRO *) macro->steps;
61 /* Eliminate a macro */
63 void rmmacro(MACRO *macro)
69 for (x = 0; x != macro->n; ++x)
70 rmmacro(macro->steps[x]);
71 joe_free(macro->steps);
73 macro->steps = (MACRO **) freemacros;
78 /* Add a step to block macro */
80 void addmacro(MACRO *macro, MACRO *m)
82 if (macro->n == macro->size) {
84 macro->steps = (MACRO **) joe_realloc(macro->steps, (macro->size += 8) * sizeof(MACRO *));
86 macro->steps = (MACRO **) joe_malloc((macro->size = 8) * sizeof(MACRO *));
88 macro->steps[macro->n++] = m;
91 /* Duplicate a macro */
93 MACRO *dupmacro(MACRO *mac)
95 MACRO *m = mkmacro(mac->k, mac->arg, mac->n, mac->cmd);
100 m->steps = (MACRO **) joe_malloc((m->size = mac->n) * sizeof(MACRO *));
101 for (x = 0; x != m->n; ++x)
102 m->steps[x] = dupmacro(mac->steps[x]);
107 /* Set key part of macro */
109 MACRO *macstk(MACRO *m, int k)
115 /* Set arg part of macro */
117 MACRO *macsta(MACRO *m, int a)
123 /* Parse text into a macro
124 * sta is set to: ending position in buffer for no error.
125 * -1 for syntax error
126 * -2 for need more input
129 MACRO *mparse(MACRO *m, unsigned char *buf, int *sta)
135 /* Skip whitespace */
136 while (joe_isblank(locale_map,buf[x]))
139 /* If the buffer is only whitespace then treat as unknown command */
145 /* Do we have a string? */
146 if (buf[x] == '\"') {
148 while (buf[x] && buf[x] != '\"') {
149 if (buf[x] == '\\' && buf[x + 1]) {
172 if (buf[x + 1] >= '0' && buf[x + 1] <= '9')
173 c = c * 16 + buf[++x] - '0';
174 else if ((buf[x + 1] >= 'a' && buf[x + 1] <= 'f') || (buf[x + 1] >= 'A' && buf[x + 1] <= 'F'))
175 c = c * 16 + (buf[++x] & 0xF) + 9;
176 if (buf[x + 1] >= '0' && buf[x + 1] <= '9')
177 c = c * 16 + buf[++x] - '0';
178 else if ((buf[x + 1] >= 'a' && buf[x + 1] <= 'f') || (buf[x + 1] >= 'A' && buf[x + 1] <= 'F'))
179 c = c * 16 + (buf[++x] & 0xF) + 9;
193 if (buf[x + 1] >= '0' && buf[x + 1] <= '7')
194 c = c * 8 + buf[++x] - '0';
195 if (buf[x + 1] >= '0' && buf[x + 1] <= '7')
196 c = c * 8 + buf[++x] - '0';
205 m = mkmacro(-1, 1, 0, NULL);
209 m = mkmacro(-1, 1, 0, NULL);
210 addmacro(m, mkmacro(buf[x], 1, 0, findcmd(US "type")));
217 /* Do we have a command? */
219 for (y = x; buf[y] && buf[y] != ',' && buf[y] != ' ' && buf[y] != '\t' && buf[y] != '\n' && buf[x] != '\r'; ++y) ;
225 cmd = findcmd(buf + x);
233 m = mkmacro(-1, 1, 0, NULL);
236 addmacro(m, mkmacro(-1, 1, 0, cmd));
238 m = mkmacro(-1, 1, 0, cmd);
243 /* Skip whitespace */
244 while (joe_isblank(locale_map,buf[x]))
247 /* Do we have a comma? */
250 while (joe_isblank(locale_map,buf[x]))
252 if (buf[x] && buf[x] != '\r' && buf[x] != '\n')
263 /* Convert macro to text */
265 static unsigned char *ptr;
269 static unsigned char *unescape(unsigned char *uptr, int c)
274 } else if (c == '\\') {
277 } else if (c == '\'') {
280 } else if (c < 32 || c > 126) {
281 /* FIXME: what if c > 256 or c < 0 ? */
284 *uptr++ = "0123456789ABCDEF"[c >> 4];
285 *uptr++ = "0123456789ABCDEF"[c & 15];
291 static void domtext(MACRO *m)
298 for (x = 0; x != m->n; ++x)
299 domtext(m->steps[x]);
301 if (instr && strcmp(m->cmd->name, "type")) {
309 if (!strcmp(m->cmd->name, "type")) {
314 ptr = unescape(ptr, m->k);
316 for (x = 0; m->cmd->name[x]; ++x)
317 *ptr++ = m->cmd->name[x];
318 if (!strcmp(m->cmd->name, "play") || !strcmp(m->cmd->name, "gomark") || !strcmp(m->cmd->name, "setmark") || !strcmp(m->cmd->name, "record") || !strcmp(m->cmd->name, "uarg")) {
321 ptr = unescape(ptr, m->k);
328 unsigned char *mtext(unsigned char *s, MACRO *m)
340 /* Keyboard macro recorder */
342 static MACRO *kbdmacro[10];
343 static int playmode[10];
345 struct recmac *recmac = NULL;
347 static void unmac(void)
350 rmmacro(recmac->m->steps[--recmac->m->n]);
355 if (recmac && recmac->m->n)
356 recmac->m->steps[recmac->m->n - 1]->k = 3;
359 static void record(MACRO *m)
362 addmacro(recmac->m, dupmacro(m));
365 /* Query for user input */
370 struct recmac *tmp = recmac;
378 /* Macro execution */
380 MACRO *curmacro = NULL; /* Set if we're in a macro */
382 static int arg = 0; /* Repeat argument */
383 static int argset = 0; /* Set if 'arg' is set */
385 int exmacro(MACRO *m, int u)
388 /*XXX why is this local here and global below? */
403 ; /* dead store: negarg = 0; */
410 cmd = findcmd(cmd->negarg);
420 if (m->steps || larg != 1 || !(cmd->flag & EMINOR)
421 || maint->curwin->watom->what == TYPEQW /* Undo work right for s & r */
427 while (larg-- && !leave && !ret)
429 MACRO *tmpmac = curmacro;
430 int tmpptr = macroptr;
434 while (m && x != m->n && !leave && !ret) {
449 ret = execmd(cmd, m->k);
461 /* Execute a macro */
466 return exmacro(m, 1);
469 /* Keyboard macro user routines */
471 static int dorecord(BW *bw, int c, void *object, int *notify)
478 if (c > '9' || c < '0') {
482 for (n = 0; n != 10; ++n)
485 r = (struct recmac *) joe_malloc(sizeof(struct recmac));
487 r->m = mkmacro(0, 1, 0, NULL);
494 int urecord(BW *bw, int c)
496 if (c >= '0' && c <= '9')
497 return dorecord(bw, c, NULL, NULL);
498 else if (mkqw(bw->parent, sc("Macro to record (0-9 or ^C to abort): "), dorecord, NULL, NULL, NULL))
504 extern volatile int dostaupd;
510 struct recmac *r = recmac;
516 rmmacro(kbdmacro[r->n]);
517 kbdmacro[r->n] = r->m;
519 record(m = mkmacro(r->n + '0', 1, 0, findcmd(US "play"))), rmmacro(m);
525 static int doplay(BW *bw, int c, void *object, int *notify)
529 if (c >= '0' && c <= '9') {
533 if (playmode[c] || !kbdmacro[c])
536 ret = exmacro(kbdmacro[c], 0);
548 unsigned char buf[1024];
550 p_goto_eol(bw->cursor);
551 for (x = 0; x != 10; ++x)
553 mtext(buf, kbdmacro[x]);
554 binss(bw->cursor, buf);
555 p_goto_eol(bw->cursor);
556 joe_snprintf_2((char *)buf, JOE_MSGBUFSIZE, "\t^K %c\tMacro %d", x + '0', x);
557 binss(bw->cursor, buf);
558 p_goto_eol(bw->cursor);
559 binsc(bw->cursor, '\n');
565 int uplay(BW *bw, int c)
567 if (c >= '0' && c <= '9')
568 return doplay(bw, c, NULL, NULL);
569 else if (mkqwna(bw->parent, sc("Play-"), doplay, NULL, NULL, NULL))
575 /* Repeat-count setting */
577 static int doarg(BW *bw, unsigned char *s, void *object, int *notify)
585 msgnw(bw->parent, merrt);
596 if (wmkpw(bw->parent, US "No. times to repeat next command (^C to abort): ", NULL, doarg, NULL, NULL, utypebw, NULL, NULL, locale_map))
605 static int douarg(BW *bw, int c, void *object, int *notify)
609 else if (c >= '0' && c <= '9')
610 unaarg = unaarg * 10 + c - '0';
611 else if (c == 'U' - '@')
616 else if (c == 7 || c == 3 || c == 32) {
635 joe_snprintf_2((char *)msgbuf, JOE_MSGBUFSIZE, "Repeat %s%d", negarg ? "-" : "", unaarg);
636 if (mkqwna(bw->parent, sz(msgbuf), douarg, NULL, NULL, notify))
642 int uuarg(BW *bw, int c)
646 if ((c >= '0' && c <= '9') || c == '-')
647 return douarg(bw, c, NULL, NULL);
648 else if (mkqwna(bw->parent, sc("Repeat"), douarg, NULL, NULL, NULL))