/* windCmdAM.c - * * This file contains Magic command routines for those commands * that are valid in all windows. * * ********************************************************************* * * Copyright (C) 1985, 1990 Regents of the University of California. * * * Permission to use, copy, modify, and distribute this * * * software and its documentation for any purpose and without * * * fee is hereby granted, provided that the above copyright * * * notice appear in all copies. The University of California * * * makes no representations about the suitability of this * * * software for any purpose. It is provided "as is" without * * * express or implied warranty. Export of this software outside * * * of the United States of America may require an export license. * * ********************************************************************* */ #ifndef lint static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/windows/windCmdAM.c,v 1.2 2008/12/11 04:20:15 tim Exp $"; #endif /* not lint */ #include #include #include #ifdef HAVE_SYS_TIME_H #include #endif #include #include #include #include #include /* for round() function */ #include "tcltk/tclmagic.h" #include "utils/magic.h" #include "textio/textio.h" #include "utils/geometry.h" #include "windows/windows.h" #include "utils/malloc.h" #include "utils/runstats.h" #include "utils/macros.h" #include "utils/signals.h" #include "graphics/graphics.h" #include "utils/styles.h" #include "textio/txcommands.h" #include "graphics/glyphs.h" #include "windows/windInt.h" #include "tiles/tile.h" #include "utils/hash.h" #include "database/database.h" #include "dbwind/dbwind.h" #include "utils/utils.h" #include "cif/cif.h" /* Forward declarations */ void windDoMacro(); /* * ---------------------------------------------------------------------------- * * windBorderCmd -- * * Change the flag which says whether new windows will have a border. * * Usage: * windborder [on|off] * * Results: * None. * * Side effects: * A flag is changed. * In Tcl, if no options are presented, the border status is returned * in the command exit status. * * ---------------------------------------------------------------------------- */ void windBorderCmd(w, cmd) MagWindow *w; TxCommand *cmd; { int place; bool value; static const char * const onoff[] = {"on", "off", 0}; static const bool truth[] = {TRUE, FALSE}; if (cmd->tx_argc > 2) goto usage; else if (cmd->tx_argc == 1) { if (w == (MagWindow *)NULL) { TxError("No window specified for caption command\n"); goto usage; } value = (w->w_flags & WIND_BORDER) ? 0 : 1; #ifdef MAGIC_WRAPPER /* this cast to remove const is ok, TCL_STATIC conveys the storage handling of this string */ Tcl_SetResult(magicinterp, (char *)onoff[value], TCL_STATIC); #else TxPrintf("Window border is %s\n", onoff[value]); #endif return; } place = Lookup(cmd->tx_argv[1], onoff); if (place < 0) goto usage; if (truth[place]) { WindDefaultFlags |= WIND_BORDER; TxPrintf("New windows will have a border.\n"); } else { WindDefaultFlags &= ~WIND_BORDER; TxPrintf("New windows will not have a border.\n"); } return; usage: TxError("Usage: %s [on|off]\n", cmd->tx_argv[0]); return; } /* * ---------------------------------------------------------------------------- * * windCaptionCmd -- * * Change the flag which says whether new windows will have a title caption. * * Usage: * windcaption [on|off] * * Results: * None. * * Side effects: * A flag is changed. * In Tcl, if no options are presented, the window title caption is * returned in the command status. * * ---------------------------------------------------------------------------- */ void windCaptionCmd(w, cmd) MagWindow *w; TxCommand *cmd; { int place; Rect ts; static const char * const onoff[] = {"on", "off", 0}; static const bool truth[] = {TRUE, FALSE}; if (cmd->tx_argc > 2) goto usage; else if (cmd->tx_argc == 1) { if (w == (MagWindow *)NULL) { TxError("No window specified for caption command\n"); goto usage; } #ifdef MAGIC_WRAPPER Tcl_SetResult(magicinterp, w->w_caption, TCL_STATIC); #else TxPrintf("Window caption is \"%s\"\n", w->w_caption); #endif return; } place = Lookup(cmd->tx_argv[1], onoff); if (place < 0) goto usage; if (truth[place]) { WindDefaultFlags |= WIND_CAPTION; TxPrintf("New windows will have a title caption.\n"); } else { WindDefaultFlags &= ~WIND_CAPTION; TxPrintf("New windows will not have a title caption.\n"); } return; usage: TxError("Usage: %s [on|off]\n", cmd->tx_argv[0]); return; } /* * ---------------------------------------------------------------------------- * * windCenterCmd -- * * Implement the "center" command. * Move a window's view to center the point underneath the cursor, or to * the specified coordinate (in surface units). * * Usage: * center [x y] * center horizontal|vertical f * * Results: * None. * * Side effects: * The view in the window underneath the cursor is changed * to center the point underneath the cursor. * * ---------------------------------------------------------------------------- */ void windCenterCmd(w, cmd) MagWindow *w; TxCommand *cmd; { Point rootPoint; Rect newArea, oldArea; if (w == NULL) { TxError("Point to a window first.\n"); return; } if (cmd->tx_argc == 1) { if ((w->w_flags & WIND_SCROLLABLE) == 0) { TxError("Sorry, can't scroll this window.\n"); return; } WindPointToSurface(w, &cmd->tx_p, &rootPoint, (Rect *) NULL); } else if (cmd->tx_argc == 3) { if ((w->w_flags & WIND_SCROLLABLE) == 0) { TxError("Sorry, can't scroll this window.\n"); return; } if (cmd->tx_argv[1][0] == 'h' || cmd->tx_argv[1][0] == 'v') { double frac; if (!StrIsNumeric(cmd->tx_argv[2])) { TxError("Must specify a fractional value.\n"); return; } frac = atof(cmd->tx_argv[2]); if (cmd->tx_argv[1][0] == 'h') { rootPoint.p_y = 0; rootPoint.p_x = w->w_bbox->r_xbot + frac * (w->w_bbox->r_xtop - w->w_bbox->r_xbot) - (w->w_surfaceArea.r_xtop + w->w_surfaceArea.r_xbot)/2; } else { rootPoint.p_x = 0; rootPoint.p_y = w->w_bbox->r_ybot + frac * (w->w_bbox->r_ytop - w->w_bbox->r_ybot) - (w->w_surfaceArea.r_ytop + w->w_surfaceArea.r_ybot)/2; } WindScroll(w, &rootPoint, (Point *)NULL); return; } else { if (!StrIsInt(cmd->tx_argv[1]) || !StrIsInt(cmd->tx_argv[2])) { TxError("Coordinates must be integer values\n"); return; } rootPoint.p_x = atoi(cmd->tx_argv[1]); rootPoint.p_y = atoi(cmd->tx_argv[2]); } } else { TxError("Usage: center [x y]\n"); TxError(" center horizontal|vertical f\n"); return; } oldArea = w->w_surfaceArea; newArea.r_xbot = rootPoint.p_x - (oldArea.r_xtop - oldArea.r_xbot)/2; newArea.r_xtop = newArea.r_xbot - oldArea.r_xbot + oldArea.r_xtop; newArea.r_ybot = rootPoint.p_y - (oldArea.r_ytop - oldArea.r_ybot)/2; newArea.r_ytop = newArea.r_ybot - oldArea.r_ybot + oldArea.r_ytop; WindMove(w, &newArea); } /* * ---------------------------------------------------------------------------- * windCloseCmd -- * * Close the window that is pointed at. * * Results: * None. * * Side effects: * The window is closed, and the client is notified. The client may * refuse to have the window closed, in which case nothing happens. * ---------------------------------------------------------------------------- */ void windCloseCmd(w, cmd) MagWindow *w; TxCommand *cmd; { if ((cmd->tx_argc == 2) && GrWindowNamePtr) { char *mwname; for (w = windTopWindow; w != (MagWindow *)NULL; w = w->w_nextWindow) { mwname = (*GrWindowNamePtr)(w); if (!strcmp(mwname, cmd->tx_argv[1])) break; } if (w == NULL) { TxError("Window named %s cannot be found\n", cmd->tx_argv[1]); return; } } if (w == (MagWindow *) NULL) { TxError("Point to a window first\n"); return; } if (!WindDelete(w)) { TxError("Unable to close that window\n"); return; } } #ifdef MAGIC_WRAPPER /* * ---------------------------------------------------------------------------- * windBypassCmd -- * * Run a magic command independently of the command line. That is, * if a command is being typed on the command line, the input * redirection will not be reset by the execution of this command. * To avoid having such commands interfere with the selection * mechanism, save and restore the command count. * * Results: * None. * * Side effects: * * * ---------------------------------------------------------------------------- */ void windBypassCmd(w, cmd) MagWindow *w; TxCommand *cmd; { int saveCount; if (cmd->tx_argc == 1) { TxError("Usage: *bypass \n"); return; } /* Dispatch the referenced command */ saveCount = TxCommandNumber; TxTclDispatch((ClientData)w, cmd->tx_argc - 1, cmd->tx_argv + 1, FALSE); TxCommandNumber = saveCount; if (TxInputRedirect == TX_INPUT_PENDING_RESET) TxInputRedirect = TX_INPUT_REDIRECTED; } #endif /* MAGIC_WRAPPER */ /* * ---------------------------------------------------------------------------- * windCrashCmd -- * * Generate a core dump. * * Results: * None. * * Side effects: * Dumps core by calling niceabort(). * * ---------------------------------------------------------------------------- */ void windCrashCmd(w, cmd) MagWindow *w; TxCommand *cmd; { if (cmd->tx_argc != 1) { TxError("Usage: *crash\n"); return; } TxPrintf("OK -- crashing...\n"); TxFlush(); niceabort(); } /* * ---------------------------------------------------------------------------- * windCursorCmd -- * * Report the cursor position in Magic (internal) coordinates * If an argument of a number is given, then the cursor icon * is changed to the glyph of that number. * * Results: * None. * * Side effects: * Prints coordinates (non-Tcl version) * Return value set to the cursor position as a list (Tcl version) * ---------------------------------------------------------------------------- */ void windCursorCmd(w, cmd) MagWindow *w; TxCommand *cmd; { Point p_in, p_out; int resulttype = DBW_SNAP_INTERNAL; double cursx, cursy, oscale; DBWclientRec *crec; #ifdef MAGIC_WRAPPER Tcl_Obj *listxy; #endif if (cmd->tx_argc == 2) { if (StrIsInt(cmd->tx_argv[1])) { if (GrSetCursorPtr != NULL) (*GrSetCursorPtr)(atoi(cmd->tx_argv[1])); return; } else if (*cmd->tx_argv[1] == 'l') { resulttype = DBW_SNAP_LAMBDA; } else if (*cmd->tx_argv[1] == 'u') { resulttype = DBW_SNAP_USER; } else if (*cmd->tx_argv[1] == 'm') { resulttype = DBW_SNAP_MICRONS; } else if (*cmd->tx_argv[1] == 'w') { resulttype = -1; // Use this value for "window" } else if (*cmd->tx_argv[1] == 's') { resulttype = -2; // Use this value for "screen" } else if (*cmd->tx_argv[1] != 'i') { TxError("Usage: cursor glyphnum\n"); TxError(" (or): cursor [internal | lambda | microns | user | window]\n"); return; } } if (GrGetCursorPosPtr == NULL) return; if (resulttype == -2) GrGetCursorRootPos(w, &p_in); else GrGetCursorPos(w, &p_in); if (resulttype >= 0) { WindPointToSurface(w, &p_in, &p_out, (Rect *)NULL); /* Snap the cursor position if snap is in effect */ if (DBWSnapToGrid != DBW_SNAP_INTERNAL) ToolSnapToGrid(w, &p_out, (Rect *)NULL); } /* Transform the result to declared units with option "lambda" or "grid" */ switch (resulttype) { case -2: case -1: cursx = (double)p_in.p_x; cursy = (double)p_in.p_y; break; case DBW_SNAP_INTERNAL: cursx = (double)p_out.p_x; cursy = (double)p_out.p_y; break; case DBW_SNAP_LAMBDA: cursx = (double)(p_out.p_x * DBLambda[0]) / (double)DBLambda[1]; cursy = (double)(p_out.p_y * DBLambda[0]) / (double)DBLambda[1]; break; case DBW_SNAP_MICRONS: oscale = (double)CIFGetOutputScale(1000); cursx = (double)(p_out.p_x * oscale); cursy = (double)(p_out.p_y * oscale); break; case DBW_SNAP_USER: crec = (DBWclientRec *)w->w_clientData; cursx = (double)((p_out.p_x - crec->dbw_gridRect.r_xbot) / (crec->dbw_gridRect.r_xtop - crec->dbw_gridRect.r_xbot)); cursy = (double)((p_out.p_y - crec->dbw_gridRect.r_ybot) / (crec->dbw_gridRect.r_ytop - crec->dbw_gridRect.r_ybot)); break; } #ifdef MAGIC_WRAPPER listxy = Tcl_NewListObj(0, NULL); if ((cursx == round(cursx)) && (cursy == round(cursy))) { Tcl_ListObjAppendElement(magicinterp, listxy, Tcl_NewIntObj((int)cursx)); Tcl_ListObjAppendElement(magicinterp, listxy, Tcl_NewIntObj((int)cursy)); } else { Tcl_ListObjAppendElement(magicinterp, listxy, Tcl_NewDoubleObj(cursx)); Tcl_ListObjAppendElement(magicinterp, listxy, Tcl_NewDoubleObj(cursy)); } Tcl_SetObjResult(magicinterp, listxy); #else TxPrintf("%g %g\n", cursx, cursy); #endif } /* * ---------------------------------------------------------------------------- * windDebugCmd -- * * Change to a new debugging mode. * * Results: * None. * * Side effects: * None. * ---------------------------------------------------------------------------- */ void windDebugCmd(w, cmd) MagWindow *w; TxCommand *cmd; { if (cmd->tx_argc != 1) goto usage; windPrintCommands = !windPrintCommands; TxError("Window command debugging set to %s\n", (windPrintCommands ? "TRUE" : "FALSE")); return; usage: TxError("Usage: *winddebug\n"); } /* * ---------------------------------------------------------------------------- * windDumpCmd -- * * Dump out debugging info. * * Results: * None. * * Side effects: * None. * ---------------------------------------------------------------------------- */ void windDumpCmd(w, cmd) MagWindow *w; TxCommand *cmd; { (void) windDump(); } #ifndef MAGIC_WRAPPER /* * ---------------------------------------------------------------------------- * * windEchoCmd -- * * Echo the arguments * * Results: * None. * * Side effects: * Text may appear on the terminal * * ---------------------------------------------------------------------------- */ void windEchoCmd(w, cmd) MagWindow *w; TxCommand *cmd; { int i; bool newline = TRUE; for (i = 1; i < cmd->tx_argc; i++) { if (i != 1) TxPrintf(" "); if ( (i == 1) && (strcmp(cmd->tx_argv[i], "-n") == 0) ) newline = FALSE; else TxPrintf("%s", cmd->tx_argv[i]); } if (newline) TxPrintf("\n"); TxFlush(); } #endif /* * ---------------------------------------------------------------------------- * * windFilesCmd -- * * Find out what files are currently open. * * Usage: * *files * * Side Effects: * None. * * ---------------------------------------------------------------------------- */ /*ARGSUSED*/ void windFilesCmd(w, cmd) MagWindow *w; TxCommand *cmd; { #define NUM_FD 20 /* max number of open files per process */ int fd; struct stat buf; int unopen, open; open = unopen = 0; for (fd = 0; fd < NUM_FD; fd++) { if (fstat(fd, &buf) != 0) { if (errno == EBADF) unopen++; else TxError("file descriptor %d: %s\n", fd, strerror(errno)); } else { char *type; switch (buf.st_mode & S_IFMT) { case S_IFDIR: {type = "directory"; break;} case S_IFCHR: {type = "character special"; break;} case S_IFBLK: {type = "block special"; break;} case S_IFREG: {type = "regular"; break;} case S_IFLNK: {type = "symbolic link"; break;} case S_IFSOCK: {type = "socket"; break;} default: {type = "unknown"; break;} } TxError("file descriptor %d: open (type: '%s', inode number %ld)\n", fd, type, buf.st_ino); open++; } } TxError("%d open files, %d unopened file descriptors left\n", open, unopen); } /* * ---------------------------------------------------------------------------- * * windGrowCmd -- * * Grow a window to full-screen size or back to previous size. * * Results: * None. * * Side effects: * Text may appear on the terminal * * ---------------------------------------------------------------------------- */ void windGrowCmd(w, cmd) MagWindow *w; TxCommand *cmd; { if (w == NULL) { TxError("Point to a window first.\n"); return; }; WindFullScreen(w); } /* * ---------------------------------------------------------------------------- * windGrstatsCmd -- * * Take statistics on the graphics code. * * Results: * None. * * Side effects: * None. * ---------------------------------------------------------------------------- */ void windGrstatsCmd(w, cmd) MagWindow *w; TxCommand *cmd; { char *RunStats(), *rstatp; static struct tms tlast, tdelta; int i, style, count; int us; extern int GrNumClipBoxes; int usPerRect, rectsPerSec; if (cmd->tx_argc < 2 || cmd->tx_argc > 3) { TxError("Usage: grstats num [ style ]\n"); return; } if (!StrIsInt(cmd->tx_argv[1]) || (cmd->tx_argc == 3 && !StrIsInt(cmd->tx_argv[2]))) { TxError("Count & style must be numeric\n"); return; } if (w == (MagWindow *) NULL) { TxError("Point to a window first.\n"); return; } count = atoi(cmd->tx_argv[1]); if (cmd->tx_argc == 3) style = atoi(cmd->tx_argv[2]); else style = -1; WindUpdate(); if (style >= 0) GrLock(w, TRUE); (void) RunStats(RS_TINCR, &tlast, &tdelta); GrNumClipBoxes = 0; for (i = 0; i < count; i++) { if (SigInterruptPending) break; if (style < 0) { WindAreaChanged(w, (Rect *) NULL); WindUpdate(); } else { Rect r; #define GRSIZE 15 #define GRSPACE 20 r.r_xbot = w->w_screenArea.r_xbot - GRSIZE/2; r.r_ybot = w->w_screenArea.r_ybot - GRSIZE/2; r.r_xtop = r.r_xbot + GRSIZE - 1; r.r_ytop = r.r_ybot + GRSIZE - 1; GrClipBox(&w->w_screenArea, STYLE_ERASEALL); GrSetStuff(style); while (r.r_xbot <= w->w_screenArea.r_xtop) { while (r.r_ybot <= w->w_screenArea.r_ytop) { GrFastBox(&r); r.r_ybot += GRSPACE; r.r_ytop += GRSPACE; } r.r_xbot += GRSPACE; r.r_xtop += GRSPACE; r.r_ybot = w->w_screenArea.r_ybot - GRSIZE/2; r.r_ytop = r.r_ybot + GRSIZE - 1; } } } rstatp = RunStats(RS_TINCR, &tlast, &tdelta); us = tdelta.tms_utime * (1000000 / 60); usPerRect = us / MAX(1, GrNumClipBoxes); rectsPerSec = 1000000 / MAX(1, usPerRect); TxPrintf("[%s]\n%d rectangles, %d uS, %d uS/rectangle, %d rects/sec\n", rstatp, GrNumClipBoxes, us, usPerRect, rectsPerSec); if (style >= 0) GrUnlock(w); } /* * ---------------------------------------------------------------------------- * windHelpCmd -- * * Just a dummy proc. (Only for this particular, global, client) * This is just here so that there is an entry in our help table! * * Results: * None. * * Side effects: * None. * ---------------------------------------------------------------------------- */ void windHelpCmd(w, cmd) MagWindow *w; TxCommand *cmd; { ASSERT(FALSE, windHelpCmd); } /* * ---------------------------------------------------------------------------- * windLogCommandsCmd -- * * Log the commands and button pushes in a file. * * Syntax: * logcommands start Open and start a new command log file * logcommands stop End and close a command log file * logcommands update Refresh display after each log command * logcommands suspend Suspend logging of commands * logcommands resume Resume logging of commands * * Legacy syntax: * logcommands [update] Start a new command log file with updating * logcommands End and close a command log file * * Results: * None. * * Side effects: * None. * ---------------------------------------------------------------------------- */ #define LOG_CMD_START 0 // Create a new log file (default behavior) #define LOG_CMD_STOP 1 // End a log file and stop logging. #define LOG_CMD_UPDATE 2 // Update display after every logged command. #define LOG_CMD_SUSPEND 3 // Suspend command logging. #define LOG_CMD_RESUME 4 // Resume command logging. void windLogCommandsCmd(w, cmd) MagWindow *w; TxCommand *cmd; { char *fileName = NULL; unsigned char flags = 0; int idx = LOG_CMD_STOP; static const char * const logKeywords[] = {"start", "stop", "update", "suspend", "resume", 0}; if ((cmd->tx_argc < 1) || (cmd->tx_argc > 3)) goto usage; if (cmd->tx_argc > 1) { idx = Lookup(cmd->tx_argv[1], logKeywords); if (idx < 0) fileName = cmd->tx_argv[1]; } if (cmd->tx_argc == 3) { int i; if (fileName == NULL) fileName = cmd->tx_argv[2]; else { /* Legacy behavior: Allow "logcommands update" * to mean "logcommands start ; logcommands update" */ i = Lookup(cmd->tx_argv[2], logKeywords); if (i != LOG_CMD_UPDATE) goto usage; flags = TX_LOG_UPDATE; idx = LOG_CMD_START; } } switch (idx) { case LOG_CMD_START: if (fileName == NULL) break; TxLogStart(fileName, w); if (flags & TX_LOG_UPDATE) TxLogUpdate(); return; case LOG_CMD_STOP: TxLogStop(); return; case LOG_CMD_UPDATE: TxLogUpdate(); return; case LOG_CMD_SUSPEND: TxLogSuspend(); return; case LOG_CMD_RESUME: TxLogResume(); return; } usage: TxError("Usage: %s [start|stop|update|suspend|resume [filename]]\n", cmd->tx_argv[0]); } /* * ---------------------------------------------------------------------------- * * windIntMacroCmd -- * * Define a new interactive macro. * * Results: * None. * * Side effects: * Calls windDoMacro. * * ---------------------------------------------------------------------------- */ void windIntMacroCmd(w, cmd) MagWindow *w; TxCommand *cmd; { windDoMacro(w, cmd, TRUE); } /* * ---------------------------------------------------------------------------- * * windMacroCmd -- * * Define a new macro. * * Results: * None. * * Side effects: * Calls windDoMacro * * ---------------------------------------------------------------------------- */ void windMacroCmd(w, cmd) MagWindow *w; TxCommand *cmd; { windDoMacro(w, cmd, FALSE); } /* * ---------------------------------------------------------------------------- * * windDoMacro -- * * Working function for CmdIntMacro and CmdMacro * * Results: * None. * * Side effects: * Causes the macro package to define a new macro. * * ---------------------------------------------------------------------------- */ void windDoMacro(w, cmd, interactive) MagWindow *w; TxCommand *cmd; bool interactive; { char *cp, *cn; char nulltext[] = ""; char ch; int ct, argstart, verbose; bool any, iReturn; bool do_list = FALSE; bool do_help = FALSE; bool do_reverse = FALSE; char *searchterm = NULL; macrodef *cMacro; HashTable *clienttable; HashEntry *h; HashSearch hs; WindClient wc; /* If the first argument is a window name, we attempt to */ /* retrieve a client ID from it. This overrides the actual */ /* window the command was called from, so technically we */ /* can define macros for clients from inside other clients. */ /* The main use, though, is to define macros for a client */ /* from a script, rc file, or command-line. */ /* Default to the layout window if the command has no */ /* associated window. */ argstart = 1; if (cmd->tx_argc == 1) wc = DBWclientID; /* Added by NP 11/15/04 */ else if (cmd->tx_argc > 1) wc = WindGetClient(cmd->tx_argv[1], TRUE); while (cmd->tx_argc > argstart) { if (!strcmp(cmd->tx_argv[argstart], "list")) { do_list = TRUE; argstart++; } else if (!strcmp(cmd->tx_argv[argstart], "help")) { do_help = TRUE; argstart++; } else if (!strcmp(cmd->tx_argv[argstart], "search")) { if (cmd->tx_argc > (argstart + 1)) { argstart++; searchterm = cmd->tx_argv[argstart]; } argstart++; } else if (!strcmp(cmd->tx_argv[argstart], "-reverse")) { do_reverse = TRUE; argstart++; } else if (!strcmp(cmd->tx_argv[argstart], "copy")) { if (cmd->tx_argc > (argstart + 1)) { argstart++; if (wc == (WindClient)NULL) { if (w != NULL) wc = w->w_client; else wc = DBWclientID; } MacroCopy(wc, cmd->tx_argv[argstart]); } return; } else break; } /* If client wasn't specified, use window default, else use */ /* DBW client. */ if (wc == (WindClient)NULL) { if (w != NULL) wc = w->w_client; else wc = DBWclientID; if (cmd->tx_argc > (argstart + 1)) { /* The first argument, if there is one after resolving */ /* all of the optional arugments, should be a key. */ /* If it doesn't look like one, then check if the */ /* next argument looks like a key, which would indicate */ /* an unregistered client as the first argument. A */ /* macro retrieved from an unregistered client returns */ /* nothing but does not generate an error. This allows */ /* the default macro set to declare macros for, e.g., the */ /* wind3d client and fail quietly if magic was compiled */ /* without OpenGL support. */ if (MacroKey(cmd->tx_argv[argstart], &verbose) == 0) if (MacroKey(cmd->tx_argv[argstart + 1], &verbose) != 0) { wc = 0; argstart++; return; } } } else argstart++; if (cmd->tx_argc == argstart) { if (wc == (WindClient)0) { TxError("No such client.\n"); return; } h = HashLookOnly(&MacroClients, (char *)wc); if (h == NULL) return; else { clienttable = (HashTable *)HashGetValue(h); if (clienttable == (HashTable *)NULL) { TxError("No such client.\n"); return; } } cn = NULL; any = FALSE; ch = 0; HashStartSearch(&hs); while (TRUE) { if (cn) { /* this loop uses 'continue' after 'cn' was assigned from malloc below, so * this ensures it is freed up at the start of the next iteration. */ freeMagic(cn); cn = NULL; } h = HashNext(clienttable, &hs); if (h == NULL) break; cMacro = (macrodef *) HashGetValue(h); if (cMacro == (macrodef *)NULL) break; cn = MacroName((spointertype)h->h_key.h_ptr); /* "imacro list" returns only interactive macros. */ if (interactive && !cMacro->interactive) continue; if (do_help) cp = (cMacro->helptext == NULL) ? cMacro->macrotext : cMacro->helptext; else cp = cMacro->macrotext; if (cp == (char *)NULL) cp = (char *)(&nulltext[0]); if (searchterm != NULL) { /* Refine results by keyword search */ if (!strstr(cp, searchterm)) continue; } if (do_list) { #ifdef MAGIC_WRAPPER // NOTE: Putting cp before cn makes it easier to // generate a reverse lookup hash table for matching // against menu items, to automatically generate // the "accelerator" text. if (do_reverse) Tcl_AppendElement(magicinterp, cp); Tcl_AppendElement(magicinterp, cn); if (!do_reverse) Tcl_AppendElement(magicinterp, cp); #else TxPrintf("%s = \"%s\"\n", cn, cp); #endif } else { if (cMacro->interactive) TxPrintf("Interactive macro '%s' %s \"%s\"\n", cn, (do_help) ? "" : "contains", cp); else TxPrintf("Macro '%s' %s \"%s\"\n", cn, (do_help) ? "" : "contains", cp); } any = TRUE; } if (!any) { if (!do_list) TxPrintf("No macros are defined for this client.\n"); } return; } else if (cmd->tx_argc == (argstart + 1)) { ct = MacroKey(cmd->tx_argv[argstart], &verbose); if (ct == 0) { if (verbose) TxError("Unrecognized macro name %s\n", cmd->tx_argv[argstart]); return; } if (do_help) cp = MacroRetrieveHelp(wc, ct); else cp = MacroRetrieve(wc, ct, &iReturn); if (cp != NULL) { cn = MacroName(ct); if (do_list) { #ifdef MAGIC_WRAPPER Tcl_SetResult(magicinterp, cp, TCL_VOLATILE); #else TxPrintf("%s\n", cp); #endif } else { if (iReturn) { TxPrintf("Interactive macro '%s' contains \"%s\"\n", cn, cp); } else { TxPrintf("Macro '%s' contains \"%s\"\n", cn, cp); } } freeMagic(cp); freeMagic(cn); } return; } else if (cmd->tx_argc == (argstart + 2)) { int verbose; ct = MacroKey(cmd->tx_argv[argstart], &verbose); if (ct == 0) { if (verbose) TxError("Unrecognized macro name %s\n", cmd->tx_argv[argstart]); return; } argstart++; if (cmd->tx_argv[argstart][0] == '\0') MacroDelete(wc, ct); else if (do_help) MacroDefineHelp(wc, ct, cmd->tx_argv[argstart]); else if (interactive) MacroDefine(wc, ct, cmd->tx_argv[argstart], NULL, TRUE); else MacroDefine(wc, ct, cmd->tx_argv[argstart], NULL, FALSE); return; } else if (cmd->tx_argc == (argstart + 3)) { int verbose; ct = MacroKey(cmd->tx_argv[argstart], &verbose); if (ct == 0) { if (verbose) TxError("Unrecognized macro name %s\n", cmd->tx_argv[argstart]); return; } argstart++; if (cmd->tx_argv[argstart][0] == '\0') MacroDelete(wc, ct); else if (interactive) MacroDefine(wc, ct, cmd->tx_argv[argstart], cmd->tx_argv[argstart + 1], TRUE); else MacroDefine(wc, ct, cmd->tx_argv[argstart], cmd->tx_argv[argstart + 1], FALSE); return; } TxError("Usage: %s [client] [macro_name [string] [help_text]]\n", cmd->tx_argv[0]); }