/* * COMMAND.C * * (C)Copyright 1987 by Matthew Dillon, All Rights Reserved * * )c single character (typing) * 'c single character (typing) * `string' string of characters w/ embedded `' allowed! * (string) same thing w/ embedded () allowed! * \c override * * name arg arg command name. The arguments are interpreted as strings * for the command. * * $scanf macro insert scanf'd variable * $filename macro insert current file name * * Any string arguments not part of a command are considered to be typed * text. */ #include "defs.h" #include #if AREXX extern int foundcmd; /* control for implicit ARexx macro invocation */ extern int cmderr; /* global command error flag for do_rexx()'s use */ #endif #define CF_COK 1 /* Can be executed while in command line mode */ #define CF_PAR 2 /* ESCIMM special flag.. save rest of command line */ /* so it can be executed after user entry */ #define CF_ICO 4 /* OK to execute if iconified, else uniconify first*/ #define BTOCP(val, type) ((type)((long)val << 2)) extern char *breakout(); typedef void (*FPTR) ARGS((long)); typedef struct { char *name; /* command name */ ubyte args; ubyte flags; void (*func) ARGS((long)); /* function */ } COMM; /* extern void do_map(), do_unmap(), do_up(), do_down(), do_left(), do_right(), do_return(), do_bs(), do_del(), do_esc(), do_downadd(), do_lastcolumn(), do_firstcolumn(),do_edit(), do_tab(), do_backtab(), do_save(), do_saveas(), do_deline(), do_insline(), do_top(), do_bottom(), do_source(), do_firstnb(), do_quit(), do_find(), do_page(), do_savetabs(), do_split(), do_goto(), do_screentop(), do_screenbottom(), do_repeat(), do_tabstop(), do_insertmode(), do_block(), do_bdelete(), do_bcopy(), do_bmove(), do_bsave(), do_wleft(), do_wright(), do_remeol(), do_savemap(), do_if(), do_tlate(), do_bsource(), do_findr(), do_findstr(), do_newwindow(), do_windowparm(),do_resize(), do_margin(), do_wordwrap(), do_reformat(), do_execute(), do_chfilename(),do_scrollup(), do_scrolldown(),do_recall(), do_scanf(), do_iconify(), do_tomouse(), do_refs(), do_arpload(), do_arpsave(), do_arpinsfile(),do_setfont(), do_ignorecase(),do_ctags(), do_addpath(), do_rempath(), do_set(), do_setenv(), do_unset(), do_unsetenv(), do_ipc(), do_cd(); extern void do_menu(), do_menuclear(), do_menuadd(), do_menudel(), do_menudelhdr(), do_menuon(), do_menuoff(); extern void do_null(), do_rx(); extern void do_popmark(), do_swapmark(), do_purgemark(), do_ping(), do_pong(), do_undo(); extern int do_pushmark(), do_rexx(), do_join(), do_toggle(), do_command(), do_col(); #if AREXX extern void do_rx(), do_rx1(), do_rx2(); #endif */ /*============================================================================*/ /* * WLEFT/WRIGHT will check command line mode themselves, and thus can * be marked flags=1 even though they can change the line number. * * No more than 255 commands may exist unless you change the type of hindex[] * * Command names MUST be sorted by their first character */ unsigned char hindex[26]; /* alpha hash into table */ /* args flags */ COMM Comm[] = { #ifndef NO_DO2 "addpath", 1, CF_COK, (FPTR)do_addpath, #endif "arpinsfile", 0, 0, (FPTR)do_arpinsfile, "arpload", 0, 0, (FPTR)do_arpload, "arpsave", 0, 0, (FPTR)do_arpsave, "back", 0, CF_COK, (FPTR)do_bs, "backtab", 0, CF_COK, (FPTR)do_backtab, "bcopy", 0, 0, (FPTR)do_bcopy, "bdelete", 0, 0, (FPTR)do_bdelete, "block", 0, 0, (FPTR)do_block, /* checks com name for mode */ "bmove", 0, 0, (FPTR)do_bmove, "bottom", 0, 0, (FPTR)do_bottom, "bs", 0, CF_COK, (FPTR)do_bs, "bsave", 1, CF_COK, (FPTR)do_bsave, "bsource", 0, 0, (FPTR)do_bsource, "cd", 1, CF_COK, (FPTR)do_cd, "chfilename", 1, 0, (FPTR)do_chfilename, "col", 1, CF_COK, (FPTR)do_col, #ifndef NO_DO_CTAGS "ctags", 0, CF_ICO, (FPTR)do_ctags, #endif "del", 0, CF_COK, (FPTR)do_del, "deline", 0, 0, (FPTR)do_deline, "down", 0, 0, (FPTR)do_down, "downadd", 0, 0, (FPTR)do_downadd, "esc", 0, CF_COK, (FPTR)do_esc, "escimm", 1, CF_PAR, (FPTR)do_esc, "execute", 1, CF_ICO, (FPTR)do_execute, "find", 1, 0, (FPTR)do_find, /* checks com name for mode */ "findr", 2, 0, (FPTR)do_findr, /* checks com name for mode */ "findstr", 1, CF_COK, (FPTR)do_findstr, /* checks com name for mode */ "first", 0, CF_COK, (FPTR)do_firstcolumn, "firstnb", 0, CF_COK, (FPTR)do_firstnb, "goto", 1, 0, (FPTR)do_goto, "height", 1, CF_COK, (FPTR)do_windowparm, "iconify", 0, CF_ICO, (FPTR)do_iconify, "if", 2, CF_COK, (FPTR)do_if, "ifelse", 3, CF_COK, (FPTR)do_if, "ignorecase", 1, CF_COK, (FPTR)do_ignorecase, "insertmode", 1, CF_COK, (FPTR)do_insertmode, "insfile", 1, 0, (FPTR)do_edit, "insline", 0, 0, (FPTR)do_insline, #ifndef NODRES "ipc", 3, CF_COK, (FPTR)do_ipc, #endif "join", 0, 0, (FPTR)do_join, "last", 0, CF_COK, (FPTR)do_lastcolumn, "left", 0, CF_COK, (FPTR)do_left, "leftedge", 1, CF_COK, (FPTR)do_windowparm, "map", 2, CF_COK, (FPTR)do_map, "margin", 1, CF_COK, (FPTR)do_margin, "menuon", 0, 0, (FPTR)do_menuon, "menuoff", 0, 0, (FPTR)do_menuoff, "menuadd", 3, 0, (FPTR)do_menuadd, "menudel", 2, 0, (FPTR)do_menudel, "menudelhdr", 1, 0, (FPTR)do_menudelhdr, "menuclear", 0, 0, (FPTR)do_menuclear, "newfile", 1, 0, (FPTR)do_edit, /* checks com name for mode */ "newwindow", 0, CF_ICO, (FPTR)do_newwindow, "next", 0, 0, (FPTR)do_find, "nextr", 0, 0, (FPTR)do_findr, "null", 0, CF_COK, (FPTR)do_null, "pagedown", 0, 0, (FPTR)do_page, "pageset", 1, 0, (FPTR)do_page, "pageup", 0, 0, (FPTR)do_page, "ping", 1, CF_ICO, (FPTR)do_ping, "pong", 1, 0, (FPTR)do_pong, "prev", 0, 0, (FPTR)do_find, "prevr", 0, 0, (FPTR)do_findr, "popmark", 0, 0, (FPTR)do_popmark, "purgemark", 0, 0, (FPTR)do_purgemark, "pushmark", 0, 0, (FPTR)do_pushmark, "quit", 0, CF_ICO, (FPTR)do_quit, "recall", 0, CF_COK, (FPTR)do_recall, #ifndef NO_DO_REF "ref", 0, 0, (FPTR)do_refs, #endif "reformat", 0, 0, (FPTR)do_reformat, "remeol", 0, CF_COK, (FPTR)do_remeol, #ifndef NO_DO2 "rempath", 1, CF_COK, (FPTR)do_rempath, #endif "repeat", 2, CF_ICO|CF_COK, (FPTR)do_repeat, "repstr", 1, CF_COK, (FPTR)do_findstr, "resettoggle", 1, CF_COK, (FPTR)do_toggle, "resize", 2, 0, (FPTR)do_resize, "return", 0, CF_COK, (FPTR)do_return, /* special meaning in command line mode */ "right", 0, CF_COK, (FPTR)do_right, #if AREXX "rx", 1, 0, (FPTR)do_rx, /* explicit ARexx macro invocation */ "rx1", 2, 0, (FPTR)do_rx1, /* explicit, with 1 arg to ARexx macro */ "rx2", 3, 0, (FPTR)do_rx2, /* explicit, with 2 args to ARexx macro */ #endif "saveas", 1, CF_ICO|CF_COK, (FPTR)do_saveas, "savemap", 1, CF_ICO|CF_COK, (FPTR)do_savemap, /* checks com name for mode */ "saveold", 0, CF_ICO|CF_COK, (FPTR)do_save, "savesmap", 1, CF_ICO|CF_COK, (FPTR)do_savemap, "savetabs", 1, CF_ICO|CF_COK, (FPTR)do_savetabs, "scanf", 1, CF_COK, (FPTR)do_scanf, "screenbottom", 0, 0, (FPTR)do_screenbottom, "screentop", 0, 0, (FPTR)do_screentop, "scrollup", 0, 0, (FPTR)do_scrollup, "scrolldown", 0, 0, (FPTR)do_scrolldown, "set", 2, CF_ICO|CF_COK, (FPTR)do_set, "setenv", 2, CF_ICO|CF_COK, (FPTR)do_setenv, "setfont", 2, 0, (FPTR)do_setfont, "settoggle", 1, CF_COK, (FPTR)do_toggle, "source", 1, CF_COK, (FPTR)do_source, "split", 0, 0, (FPTR)do_split, "swapmark", 0, 0, (FPTR)do_swapmark, "tab", 0, CF_COK, (FPTR)do_tab, "tabstop", 1, CF_COK, (FPTR)do_tabstop, "tlate", 1, CF_COK, (FPTR)do_tlate, "tmpheight", 1, CF_COK, (FPTR)do_windowparm, "tmpwidth", 1, CF_COK, (FPTR)do_windowparm, "toggle", 1, CF_COK, (FPTR)do_toggle, "tomouse", 0, 0, (FPTR)do_tomouse, "top", 0, 0, (FPTR)do_top, "topedge", 1, CF_COK, (FPTR)do_windowparm, "unblock", 0, 0, (FPTR)do_block, "undo", 0, 0, (FPTR)do_undo, "unmap", 1, CF_ICO|CF_COK, (FPTR)do_unmap, "unset", 1, CF_ICO|CF_COK, (FPTR)do_unset, "unsetenv", 1, CF_ICO|CF_COK, (FPTR)do_unsetenv, "up", 0, 0, (FPTR)do_up, "while", 2, CF_ICO|CF_COK, (FPTR)do_if, "width", 1, CF_COK, (FPTR)do_windowparm, "wleft", 0, CF_COK, (FPTR)do_wleft, "wordwrap", 1, CF_COK, (FPTR)do_wordwrap, "wright", 0, CF_COK, (FPTR)do_wright, NULL, 0, 0, NULL }; void init_command() { register short hi; register COMM *comm; hi = sizeof(Comm)/sizeof(Comm[0]) - 2; comm = Comm + hi; while (hi >= 0) { hindex[comm->name[0] - 'a'] = hi; --hi; --comm; } } #define MAXIA 5 do_command(str) char *str; { register char *arg; char *aux1, *aux2; char *repstr[MAXIA]; char quoted; short repi = 0; register short i, j; static int level; if (++level > 20) { title("Recursion Too Deep!"); --level; #if AREXX foundcmd = 1; /* to prevent us from trying an ARexx macro */ #endif return(0); } while (arg = breakout(&str, "ed, &aux1)) { if (quoted) { if (Ep->iconmode) uniconify(); text_write(arg); goto loop; } for (i = 0; arg[i]; ++i) { if (arg[i] >= 'A' && arg[i] <= 'Z') arg[i] += 'a' - 'A'; } if (arg[0] >= 'a' && arg[0] <= 'z') { register COMM *comm = &Comm[hindex[arg[0]-'a']]; for (; comm->name && comm->name[0] == arg[0]; ++comm) { if (strcmp(arg, comm->name) == 0) { #if AREXX foundcmd = 1; #endif av[0] = (ubyte *)comm->name; for (j = 1; j <= comm->args; ++j) { av[j] = (ubyte *)breakout(&str, "ed, &aux2); if (aux2) { if (repi == MAXIA) { free(aux2); title("Command too complex"); goto fail; } else { repstr[repi++] = aux2; } } if (!av[j]) { title("Bad argument"); goto fail; } } av[j] = NULL; /* end of arglist */ if ((comm->flags & CF_COK) || !Comlinemode) { if (comm->flags & CF_PAR) { if (Partial) free(Partial); Partial = (char *)malloc(strlen(str)+1); strcpy(Partial, str); str += strlen(str); /* skip string */ } if (Ep->iconmode && !(comm->flags & CF_ICO)) uniconify(); (*comm->func)(-1); } if (Abortcommand) goto fail; goto loop; } } } /* Command not found, check for macro */ { char *str; int ret; if ((str = keyspectomacro(arg)) || (str = menutomacro(arg))) { str = (char *)strcpy(malloc(strlen(str)+1), str); ret = do_command(str); free(str); #if AREXX if (ret) { foundcmd = 1; /* dunno about this yet for ARexx macros */ goto loop; } #else if (ret) goto loop; #endif goto fail; } } /* Command still not found, check for public macro */ /* code to be added */ #if AREXX do_rxImplied(arg, str); #else title("Unknown Command"); #endif fail: --level; while (--repi >= 0) free(repstr[repi]); if (aux1) free(aux1); return(0); loop: if (aux1) free(aux1); } --level; while (--repi >= 0) free(repstr[repi]); return(1); } void do_null() { } void do_source() { char buf[256]; void *xfi; register char *str; long oldlock = CurrentDir(DupLock(Ep->dirlock)); if (xfi = xfopen(av[1], "r", 512)) { while (xfgets(xfi, buf, 256) >= 0) { if (buf[0] == '#') continue; for (str = buf; *str; ++str) { if (*str == 9) *str = ' '; } do_command(buf); } xfclose(xfi); } else { if (av[0]) title("File not found"); } UnLock(CurrentDir(oldlock)); } void do_quit() { extern char Quitflag; Quitflag = 1; } void do_execute() { long oldlock = CurrentDir(Ep->dirlock); long NilFH = Open("null:", 1006); PROC *proc = (PROC *)FindTask(NULL); if (NilFH) { proc->pr_ConsoleTask = (APTR)BTOCP(NilFH, struct FileHandle *)->fh_Port; Execute(av[1], NilFH, NilFH); Close(NilFH); } else { title("NULL: device required for (execute)"); } CurrentDir(oldlock); } /* * repeat X command * * Since repeat takes up 512+ stack, it should not be nested more than * twice. * * (if X is not a number it can be abbr. with 2 chars) * * X = N -number of repeats * line -current line # (lines begin at 1) * lbot -#lines to the bottom, inc. current * cleft -column # (columns begin at 0) * (thus is also chars to the left) * cright-#chars to eol, including current char * tr -#char positions to get to next tab stop * tl -#char positions to get to next backtab stop */ #define SC(a,b) ((a)<<8|(b)) void do_repeat() { register ubyte *ptr = av[1]; register unsigned long n; char buf1[256]; char buf2[256]; breakreset(); strcpy(buf1, av[2]); switch((ptr[0]<<8)+ptr[1]) { case SC('l','i'): n = text_lineno(); break; case SC('l','b'): n = text_lines() - text_lineno() + 1; break; case SC('c','l'): n = text_colno(); break; case SC('c','r'): n = text_cols() - text_colno(); break; case SC('t','r'): n = text_tabsize()-(text_colno() % text_tabsize()); break; case SC('t','l'): n = text_colno() % text_tabsize(); if (n == 0) n = text_tabsize(); break; default: n = atoi(av[1]); break; } while (n > 0) { strcpy(buf2, buf1); if (do_command(buf2) == 0 || breakcheck()) { Abortcommand = 1; break; } --n; } } /* * BREAKOUT() * * Break out the next argument. The argument is space delimited and * might be quoted with `' or (), or single quoted as 'c or )c * * Also: $var -variable insertion * ^c -control character */ char * breakout(ptr, quoted, paux) register char **ptr; char **paux; char *quoted; { register char *str = *ptr; char *base; short count = 0; char opc = 0; char clc = 0; char immode = 0; char isaux = 0; char buf[256]; short di = 0; *quoted = 0; *paux = NULL; while (*str == ' ') ++str; if (!*str) return(NULL); *ptr = str; base = str; while (*str) { if (immode) { if (di != sizeof(buf)-1) buf[di++] = *str; ++str; continue; } if (count == 0) { if (*str == ' ') break; if (*str == '\'' || *str == ')') clc = *str; if (*str == '`') { opc = '`'; clc = '\''; } if (*str == '(') { opc = '('; clc = ')'; } } if (*str == opc) { ++count; if (str == *ptr) { *quoted = 1; base = ++str; continue; } } if (*str == clc) { --count; if (count == 0 && *quoted) /* end of argument */ break; if (str == *ptr && count < 0) { immode = 1; *quoted = 1; base = ++str; continue; } } /* * $varname $(varname) $`varname'. I.E. three forms are allowed, * which allows one to insert the string almost anywhere. The * first form names are limited to alpha-numerics, '-', and '_'. */ if (*str == '$') { register char *ptr; char *tmpptr; char c, ce; short len; ce = 0; /* first form */ ++str; /* skip $ */ if (*str == '(') { /* second form */ ce = ')'; ++str; } else if (*str == '`') { /* third form */ ce = '\''; ++str; } ptr = str; /* start of varname */ if (ce) { /* until end char OR */ while (*ptr && *ptr != ce) ++ptr; } else { /* smart end-varname */ while ((*ptr >= 'a' && *ptr <= 'z') || (*ptr >= 'A' && *ptr <= 'Z') || (*ptr >= '0' && *ptr <= '9') || *ptr == '-' || *ptr == '_' ) { ++ptr; } } len = ptr - str; /* length of variable */ c = *ptr; *ptr = 0; /* temp. terminate \0 */ if (strcmp(str, "scanf") == 0) { *ptr = c; isaux = 1; if (di + strlen(String) < sizeof(buf)-1) { strcpy(buf + di, String); di += strlen(buf + di); } str += len; /* next string pos */ if (ce) ++str; continue; } if (strcmp(str, "fpath") == 0) { register short i; for (i = strlen(Ep->Name); i >= 0; --i) { if (Ep->Name[i] == ':' || Ep->Name[i] == '/') break; } ++i; *ptr = c; isaux = 1; if (di + i < sizeof(buf)-1) { BMov(Ep->Name, buf + di, i); di += i; buf[di] = 0; } str += len; if (ce) ++str; continue; } if (strcmp(str, "fname") == 0) { register short i; short j; for (i = strlen(Ep->Name); i >= 0; --i) { if (Ep->Name[i] == ':' || Ep->Name[i] == '/') break; } ++i; j = strlen(Ep->Name + i); *ptr = c; isaux = 1; if (di + j < sizeof(buf)-1) { BMov(Ep->Name + i, buf + di, j); di += j; buf[di] = 0; } str += len; if (ce) ++str; continue; } if (strcmp(str, "filename") == 0) { *ptr = c; isaux = 1; if (di + strlen(Ep->Name) < sizeof(buf)-1) { strcpy(buf + di, Ep->Name); di += strlen(buf + di); } str += len; if (ce) ++str; continue; } if (strcmp(str, "colno") == 0) { *ptr = c; isaux = 1; if (di < sizeof(buf)-8) { sprintf(buf + di, "%ld", Ep->Column + 1); di += strlen(buf + di); } str += len; if (ce) ++str; continue; } if (strcmp(str, "lineno") == 0) { *ptr = c; isaux = 1; if (di < sizeof(buf)-8) { sprintf(buf + di, "%ld", Ep->Line + 1); di += strlen(buf + di); } str += len; if (ce) ++str; continue; } if (tmpptr = getvar(str)) { ptr = tmpptr; str[len] = c; isaux = 1; if (di + strlen(ptr) < sizeof(buf)-1) { strcpy(buf + di, ptr); di += strlen(buf + di); } str += len; if (ce) ++str; free(ptr); continue; } *ptr = c; --str; if (ce) --str; } if (*str == '^' && (str[1] & 0x1F)) { ++str; *str &= 0x1F; isaux = 1; } if (*str == '\\' && str[1]) { ++str; isaux = 1; } buf[di++] = *str++; } buf[di++] = 0; if (isaux) { *paux = malloc(di); strcpy(*paux, buf); base = *paux; } if (*str) { /* space ended */ *str = '\0'; *ptr = str + 1; /* next arg */ } else { *ptr = str; /* last arg */ } return(base); }