macro.c
来自「nedit 是一款linux下的开发源码的功能强大的编辑器」· C语言 代码 · 共 1,752 行 · 第 1/5 页
C
1,752 行
/* Verify that a replay macro exists and it's not empty and that */ /* we're not already running a macro */ if (ReplayMacro != NULL && ReplayMacro[0] != 0 && window->macroCmdData == NULL) { /* Parse the replay macro (it's stored in text form) and compile it into an executable program "prog" */ prog = ParseMacro(ReplayMacro, &errMsg, &stoppedAt); if (prog == NULL) { fprintf(stderr, "NEdit internal error, learn/replay macro syntax error: %s\n", errMsg); return; } /* run the executable program */ runMacro(window, prog); }}/*** Read the initial NEdit macro file if one exists.*/void ReadMacroInitFile(WindowInfo *window){ const char* autoloadName = GetRCFileName(AUTOLOAD_NM); static int initFileLoaded = False; /* GetRCFileName() might return NULL if an error occurs during creation of the preference file directory. */ if (autoloadName != NULL && !initFileLoaded) { ReadMacroFile(window, autoloadName, False); initFileLoaded = True; }}/*** Read an NEdit macro file. Extends the syntax of the macro parser with** define keyword, and allows intermixing of defines with immediate actions.*/int ReadMacroFile(WindowInfo *window, const char *fileName, int warnNotExist){ int result; char *fileString; fileString = ReadAnyTextFile(fileName); if (fileString == NULL){ if (errno != ENOENT || warnNotExist) { DialogF(DF_ERR, window->shell, 1, "Read Macro", "Error reading macro file %s: %s", "dismiss", fileName,#ifdef VMS strerror(errno, vaxc$errno));#else strerror(errno));#endif } return False; } /* Parse fileString */ result = readCheckMacroString(window->shell, fileString, window, fileName, NULL); XtFree(fileString); return result;}/*** Parse and execute a macro string including macro definitions. Report** parsing errors in a dialog posted over window->shell.*/int ReadMacroString(WindowInfo *window, char *string, const char *errIn){ return readCheckMacroString(window->shell, string, window, errIn, NULL);} /*** Check a macro string containing definitions for errors. Returns True** if macro compiled successfully. Returns False and puts up** a dialog explaining if macro did not compile successfully.*/ int CheckMacroString(Widget dialogParent, char *string, const char *errIn, char **errPos){ return readCheckMacroString(dialogParent, string, NULL, errIn, errPos);} /*** Parse and optionally execute a macro string including macro definitions.** Report parsing errors in a dialog posted over dialogParent, using the** string errIn to identify the entity being parsed (filename, macro string,** etc.). If runWindow is specified, runs the macro against the window. If** runWindow is passed as NULL, does parse only. If errPos is non-null, ** returns a pointer to the error location in the string.*/static int readCheckMacroString(Widget dialogParent, char *string, WindowInfo *runWindow, const char *errIn, char **errPos){ char *stoppedAt, *inPtr, *namePtr, *errMsg; char subrName[MAX_SYM_LEN]; Program *prog; Symbol *sym; DataValue subrPtr; inPtr = string; while (*inPtr != '\0') { /* skip over white space and comments */ while (*inPtr==' ' || *inPtr=='\t' || *inPtr=='\n'|| *inPtr=='#') { if (*inPtr == '#') while (*inPtr != '\n' && *inPtr != '\0') inPtr++; else inPtr++; } if (*inPtr == '\0') break; /* look for define keyword, and compile and store defined routines */ if (!strncmp(inPtr, "define", 6) && (inPtr[6]==' ' || inPtr[6]=='\t')) { inPtr += 6; inPtr += strspn(inPtr, " \t\n"); namePtr = subrName; while (isalnum((unsigned char)*inPtr) || *inPtr == '_') *namePtr++ = *inPtr++; *namePtr = '\0'; inPtr += strspn(inPtr, " \t\n"); if (*inPtr != '{') { if (errPos != NULL) *errPos = stoppedAt; return ParseError(dialogParent, string, inPtr, errIn, "expected '{'"); } prog = ParseMacro(inPtr, &errMsg, &stoppedAt); if (prog == NULL) { if (errPos != NULL) *errPos = stoppedAt; return ParseError(dialogParent, string, stoppedAt, errIn, errMsg); } if (runWindow != NULL) { sym = LookupSymbol(subrName); if (sym == NULL) { subrPtr.val.prog = prog; subrPtr.tag = NO_TAG; sym = InstallSymbol(subrName, MACRO_FUNCTION_SYM, subrPtr); } else { if (sym->type == MACRO_FUNCTION_SYM) FreeProgram(sym->value.val.prog); else sym->type = MACRO_FUNCTION_SYM; sym->value.val.prog = prog; } } inPtr = stoppedAt; /* Parse and execute immediate (outside of any define) macro commands and WAIT for them to finish executing before proceeding. Note that the code below is not perfect. If you interleave code blocks with definitions in a file which is loaded from another macro file, it will probably run the code blocks in reverse order! */ } else { prog = ParseMacro(inPtr, &errMsg, &stoppedAt); if (prog == NULL) { if (errPos != NULL) *errPos = stoppedAt; return ParseError(dialogParent, string, stoppedAt, errIn, errMsg); } if (runWindow != NULL) { XEvent nextEvent; if (runWindow->macroCmdData == NULL) { runMacro(runWindow, prog); while (runWindow->macroCmdData != NULL) { XtAppNextEvent(XtWidgetToApplicationContext( runWindow->shell), &nextEvent); ServerDispatchEvent(&nextEvent); } } else RunMacroAsSubrCall(prog); } inPtr = stoppedAt; } } return True;}/*** Run a pre-compiled macro, changing the interface state to reflect that** a macro is running, and handling preemption, resumption, and cancellation.** frees prog when macro execution is complete;*/static void runMacro(WindowInfo *window, Program *prog){ DataValue result; char *errMsg; int stat; macroCmdInfo *cmdData; XmString s; /* If a macro is already running, just call the program as a subroutine, instead of starting a new one, so we don't have to keep a separate context, and the macros will serialize themselves automatically */ if (window->macroCmdData != NULL) { RunMacroAsSubrCall(prog); return; } /* put up a watch cursor over the waiting window */ BeginWait(window->shell); /* enable the cancel menu item */ XtVaSetValues(window->cancelMacroItem, XmNlabelString, s=XmStringCreateSimple("Cancel Macro"), NULL); XmStringFree(s); XtSetSensitive(window->cancelMacroItem, True); /* Create a data structure for passing macro execution information around amongst the callback routines which will process i/o and completion */ cmdData = (macroCmdInfo *)XtMalloc(sizeof(macroCmdInfo)); window->macroCmdData = cmdData; cmdData->bannerIsUp = False; cmdData->closeOnCompletion = False; cmdData->program = prog; cmdData->context = NULL; cmdData->continueWorkProcID = 0; cmdData->dialog = NULL; /* Set up timer proc for putting up banner when macro takes too long */ cmdData->bannerTimeoutID = XtAppAddTimeOut( XtWidgetToApplicationContext(window->shell), BANNER_WAIT_TIME, bannerTimeoutProc, window); /* Begin macro execution */ stat = ExecuteMacro(window, prog, 0, NULL, &result, &cmdData->context, &errMsg); if (stat == MACRO_ERROR) { finishMacroCmdExecution(window); DialogF(DF_ERR, window->shell, 1, "Macro Error", "Error executing macro: %s", "Dismiss", errMsg); return; } if (stat == MACRO_DONE) { finishMacroCmdExecution(window); return; } if (stat == MACRO_TIME_LIMIT) { ResumeMacroExecution(window); return; } /* (stat == MACRO_PREEMPT) Macro was preempted */}/*** Continue with macro execution after preemption. Called by the routines** whose actions cause preemption when they have completed their lengthy tasks.** Re-establishes macro execution work proc. Window must be the window in** which the macro is executing (the window to which macroCmdData is attached),** and not the window to which operations are focused.*/void ResumeMacroExecution(WindowInfo *window){ macroCmdInfo *cmdData = (macroCmdInfo *)window->macroCmdData; if (cmdData != NULL) cmdData->continueWorkProcID = XtAppAddWorkProc( XtWidgetToApplicationContext(window->shell), continueWorkProc, window);}/*** Cancel the macro command in progress (user cancellation via GUI)*/void AbortMacroCommand(WindowInfo *window){ if (window->macroCmdData == NULL) return; /* If there's both a macro and a shell command executing, the shell command must have been called from the macro. When called from a macro, shell commands don't put up cancellation controls of their own, but rely instead on the macro cancellation mechanism (here) */#ifndef VMS if (window->shellCmdData != NULL) AbortShellCommand(window);#endif /* Free the continuation */ FreeRestartData(((macroCmdInfo *)window->macroCmdData)->context); /* Kill the macro command */ finishMacroCmdExecution(window);}/*** Call this before closing a window, to clean up macro references to the** window, stop any macro which might be running from it, free associated** memory, and check that a macro is not attempting to close the window from** which it is run. If this is being called from a macro, and the window** this routine is examining is the window from which the macro was run, this** routine will return False, and the caller must NOT CLOSE THE WINDOW. ** Instead, empty it and make it Untitled, and let the macro completion** process close the window when the macro is finished executing.*/int MacroWindowCloseActions(WindowInfo *window){ macroCmdInfo *mcd, *cmdData = window->macroCmdData; WindowInfo *w; if (MacroRecordActionHook != 0 && MacroRecordWindow == window) { FinishLearn(); } /* If no macro is executing in the window, allow the close, but check if macros executing in other windows have it as focus. If so, set their focus back to the window from which they were originally run */ if (cmdData == NULL) { for (w=WindowList; w!=NULL; w=w->next) { mcd = (macroCmdInfo *)w->macroCmdData; if (w == MacroRunWindow() && MacroFocusWindow() == window) SetMacroFocusWindow(MacroRunWindow()); else if (mcd != NULL && mcd->context->focusWindow == window) mcd->context->focusWindow = mcd->context->runWindow; } return True; } /* If the macro currently running (and therefore calling us, because execution must otherwise return to the main loop to execute any commands), is running in this window, tell the caller not to close, and schedule window close on completion of macro */ if (window == MacroRunWindow()) { cmdData->closeOnCompletion = True; return False; } /* Free the continuation */ FreeRestartData(cmdData->context); /* Kill the macro command */ finishMacroCmdExecution(window); return True;}/*** Clean up after the execution of a macro command: free memory, and restore** the user interface state.*/static void finishMacroCmdExecution(WindowInfo *window){
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?