windows-nt/Source/XPSP1/NT/sdktools/mep/src/mep.c
2020-09-26 16:20:57 +08:00

423 lines
9.9 KiB
C

/*** mep.c - top level for editor
*
* Copyright <C> 1988, Microsoft Corporation
*
* Revision History:
* 26-Nov-1991 mz Strip off near/far
*************************************************************************/
#define INCL_DOS
#include "mep.h"
#include "version.h"
#define DEBFLAG Z
/*
* use double macro level to force rup to be turned into string representation
*/
#define VER(x,y,z) VER2(x,y,z)
#define VER2(x,y,z) "Version "###x##"."###y"."###z" "szVerName
char Name[] = "Microsoft (R) Editor";
char Version[] = VER(rmj,rmm,rup);
char CopyRight[] = "Copyright (C) Microsoft Corp 1987-1990. All rights reserved";
/*** main - program entry
*
* Input:
* C standard command line parameters. Recognizes:
*
* /e string - Execute string of commands on startup
* /t - Following file is "temporary", not kept in file history
* /D - Don't read tools.ini
* /r - Global no-edit mode (can't edit files)
* /m markname - Start up at given mark
* /pwb - Start as PWB
*
* When the editor is built with DEBUG defined, the following are also
* recognized:
*
* /d debflags - Specifies which debugging to turn on
* /f filename - Specifies file for debug output
*
* The following are present in the CW version of the editor only. They are
* for testing only and should NOT be documented:
*
* /vt tapename- Set tape name
* /vr - Record messages to file "default.key"
* /vp - Play back messages from file "default.key"
* /vd digit - Set playback delay from 0 to 9
*
*
* Output:
* Returns nothing. Exits via CleanExit()
*
* Exceptions:
* Various and sundry, based on program operation
*
*************************************************************************/
void __cdecl
main (
int c,
char **v
) {
char *pExecute = NULL; /* string to execute on start */
char *szMark = NULL; /* mark to go to on start */
char *szName = v[0]; /* ptr to invokation name */
flagType InLoop = TRUE;
ConvertAppToOem( c, v );
SHIFT(c,v);
#if DEBUG
debug = 0;
//debfh = stdout;
#endif
while (c && fSwitChr (**v) && InLoop) {
switch ((*v)[1]) {
#if DEBUG
case 'f':
case 'F':
SHIFT(c,v);
if ((debfh = MepFOpen(*v, ACCESSMODE_WRITE, SHAREMODE_RW, TRUE)) == NULL) {
printf("Can't open %s for debug output - using stdout\n", *v);
//debfh = stdout;
}
// setbuf(debfh, NULL);
break;
#endif
case 'e':
case 'E':
//
// /e command to execute
//
if ( c > 1 ) {
SHIFT (c, v);
pExecute = *v;
}
break;
case 't':
case 'T':
//
// /t next file is temporary .. don't keep in file history
//
InLoop = FALSE;
break;
#if DEBUG
case 'd':
//
// /d### debug level
//
SHIFT(c,v);
debug = ntoi (*v, 16);
break;
#else
case 'd':
#endif
case 'D':
//
// /D don't read tools.ini
//
fDefaults = TRUE;
break;
case 'r':
case 'R':
//
// /r Enter with noedit
//
fGlobalRO = TRUE;
break;
case 'm':
case 'M':
//
// /m markname - start at markname
//
SHIFT(c,v);
szMark = *v;
default:
printf ("%s %s\n", Name, Version);
printf ("%s\n", CopyRight);
printf("Usage: %s [/D] [/e cmd-string] [/m mark] [/r] [[/t] filename]*\n", szName);
fSaveScreen = FALSE;
exit(1);
break;
}
if (InLoop) {
SHIFT(c,v);
}
}
InitNames (szName);
cArgs = c;
pArgs = v;
// assert (_heapchk() == _HEAPOK);
/*
* At this point, command line arguments have been processed. Continue with
* initialization.
*/
if (!init ()) {
CleanExit (1, CE_VM);
}
/*
* based on the re-entry state, take appropriate initial action:
* - PWB_ENTRY: process rest of command line
* - PWB_COMPILE: read compile log, and go to first error in log
* - PWB_SHELL: do nothing
*/
#if 0
//
// BUGBUG what is this supposed to do?
//
if (szMark) {
GoToMark;
}
#endif
domessage (CopyRight);
Display ();
/*
* execute autostart macro if present
*/
if (NameToFunc ("autostart")) {
fExecute ("autostart");
Display ();
}
/*
* execute command line /e parameter if present
*/
if (pExecute) {
fExecute (pExecute);
}
TopLoop ();
CleanExit (0, CE_VM | CE_SIGNALS | CE_STATE);
}
/*** TopLoop - read a command and execute it until termination
*
* We read commands from the editor input and send them to the proper
* recipients. We continue to do this until a termination flag is seen.
*
* Input:
* None
*
* Output:
* Returns nothing
*
*************************************************************************/
void
TopLoop (
void
) {
PCMD pFuncPrev = &cmdUnassigned;
while (!fBreak) {
PCMD pFunc = zloop (ZL_CMD | ZL_BRK);
if (pFunc != NULL) {
/* if prev wasn't graphic or this wasn't graphic then
* log a boundary
*/
if (pFuncPrev->func != graphic || pFunc->func != graphic) {
LogBoundary ();
}
fRetVal = SendCmd (pFunc);
if (pFunc->func != cancel) {
if (fCtrlc) {
DoCancel ();
}
}
pFuncPrev = pFunc;
}
}
fBreak = FALSE;
}
/*** zloop - read next command, potentially updating screen
*
* zloop updates screen until a command is read that is not a macro
* invocation. If a macro invocation is seen then just execute it and
* continue. The reason for this is that the macro invocation will set up a
* new input context that we'll retrieve in the next loop.
*
* We call RecordCmd for each command, in case we have recording on. If
* the user has done <meta><record>, we record macro names, not their
* values. This is because a macro with flow control, especially a loop,
* will behave badly (possibly hang) because none of the editing commands
* return values.
*
* Input:
* flags - ZL_CMD command key, should be an event
* - ZL_BRK take fBreak into account
*
* Output:
* Returns a pointer to command structure that is next to be executed
*
*************************************************************************/
PCMD
zloop (
flagType flags
) {
REGISTER PCMD pFunc;
EVTargs e;
while (!fBreak || !TESTFLAG(flags, ZL_BRK)) {
/*
* Between every command, check heap and pfile list consistancy
*/
// assert (_heapchk() == _HEAPOK);
// assert (_pfilechk());
/* if macro in progress then
*/
if (mtest ()) {
pFunc = mGetCmd ();
} else {
DoDisplay ();
do {
pFunc = ReadCmd ();
e.arg.key = keyCmd.KeyInfo;
if (!TESTFLAG(flags, ZL_CMD)) {
break;
}
} while (DeclareEvent (EVT_KEY, (EVTargs *)&e));
}
if (pFunc != NULL) {
RecordCmd (pFunc);
if (pFunc->func == macro) {
fRetVal = SendCmd (pFunc);
} else {
break;
}
}
}
return pFunc;
}
/*** Idle & IdleThread - Code executed at idle time
*
* Idle loop. Structured so that only ONE idle-item does something each time
* though the loop. Ensures minimum exit delay. When nothing has
* happened we sleep a bit each time, to make sure we're not hogging the CPU.
*
* Also causes the screen to be updated, if need be.
*
* Idle is structure so that routines which it calls return either:
* TRUE - idle processing done, perhaps more to be done
* FALSE - no idle processing done, and no more anticipated.
*
* Input:
* none
*
* Output:
* Returns nothing
*
*************************************************************************/
void
IdleThread (
void
) {
while (TRUE) {
WaitForSingleObject( semIdle, INFINITE);
Idle();
SetEvent( semIdle );
Sleep(100L);
}
}
flagType
Idle (
void
) {
if (TESTFLAG (fDisplay, (RTEXT | RCURSOR | RSTATUS))) {
DoDisplay ();
}
if (!DeclareEvent (EVT_IDLE, NULL)) {
if (!fIdleUndo (FALSE)) {
return FALSE;
}
}
/*
* got here, means someone processed idle, and may have more to do
*/
return TRUE;
}
/*** IntError - Internal error Processor.
*
* Allow user to abort, or attempt to continue.
*
* Input:
* p = pointer to error string
*
* Output:
* Returns only if user says to.
*
*************************************************************************/
void
IntError (
char *p
) {
static char pszMsg [] = "MEP internal error - %s, continue? ";
if ( OriginalScreen ) {
consoleSetCurrentScreen( OriginalScreen );
}
printf ("\n");
if (TESTFLAG (fInit, INIT_VIDEO)) {
if (!confirm (pszMsg, p)) {
#if DEBUG
fflush (debfh);
#endif
CleanExit (1, CE_STATE);
} else {
;
}
} else {
printf (pszMsg, p);
CleanExit (1, FALSE);
}
}