/* begincopyright Copyright (c) 1988 Xerox Corporation. All rights reserved. Use and copying of this software and preparation of derivative works based upon this software are permitted. Any distribution of this software or derivative works must comply with all applicable United States export control laws. This software is made available AS IS, and Xerox Corporation makes no warranty about the software, its performance or its conformity to any specification. Any person obtaining a copy of this software is requested to send their name and post office or electronic mail address to PCRCoordinator.pa@xerox.com, or to: PCR Coordinator Xerox PARC 3333 Coyote Hill Rd. Palo Alto, CA 94304 endcopyright */ /* * CommandLine.h * * PCR command line interface. * * All procs in this interface are usable from initialization code, * (before allocator and threads have been set up) * EXCEPT the ones that use the XR←Fildes type. * * Demers, April 15, 1990 11:43:36 am PDT */ #ifndef ←XR←COMMAND←LINE← #define ←XR←COMMAND←LINE← 1 #ifndef ←XR←BASIC←TYPES← # include "xr/BasicTypes.h" #endif #ifndef ←XR←THREADS← # include "xr/Threads.h" #endif /* * Command Lines */ typedef XR←Pointer /* opaque */ XR←CLHandle; /* Handle to a command line. To construct one see XR←CLCreateHandleFromXXX below. */ extern XR←CLHandle XR←CLCreateHandleFromArgs(/* int argc, char **argv */); /* Create handle from given args. The argv vector and the arg strings it points to are NOT copied, and so should be immutable. */ extern XR←CLHandle XR←CLCreateHandleFromCharProc(/* XR←MesaProc charProc -- closure for int (*charProc)(XR←MesaProc self) XR←MesaProc promptProc -- closure for void (*promptProc)(char *prompt, int nBytes, XR←MesaProc self) */); /* The charProc should behave like a Unix getchar -- it should return the char as an int, or (-1) at the end. If non-NIL, the promptProc is called to print interactive prompts. Implementation is lazy -- the charProc is actually called as a result of calling CLProcess on the resulting CLHandle. */ extern XR←CLHandle XR←CLCreateHandleFromFile(/* XR←Fildes file; XR←Fildes promptFile; */); /* Create handle for reading from given file, which must be open. The prompt may be (usually is) XR←nullFildes; */ extern XR←CLHandle XR←CLCreateHandleFromString(/* char *string; */); /* Create handle for reading args from given string. The string is not copied, and so should be immutable. */ extern int XR←CLPrependArgsToHandle(/* XR←CLHandle h, int argc, char **argv */); /* Prepend args to handle. The argv vector is copied. The underlying strings are not copied, and so should be immutable. Return 0 on success, (-1) on failure. */ extern void XR←CLDestroyHandle(/* XR←CLHandle h */); /* Destroy the Handle. It's okay just to drop it on the floor. If the handle was created from a file, this does NOT close the file. */ /* * Command Line Processing Procs -- * * registration, invocation, ... */ typedef XR←Pointer /* opaque */ XR←CLProcsHandle; /* Handle to collection of registered command line processing procs (see below). */ typedef struct XR←CLCallEnvRep { XR←CLHandle clce←h; XR←CLProcsHandle clce←pH; XR←MesaProc clce←msgSink; /* closure for void (*sink)(char *buf, int nBytes, XR←MesaProc self) */ int *clce←msgVerbosityP; struct XR←JmpBufRep clce←jmpBuf; XR←MesaProc clce←handlerProc; /* closure for int (*handlerProc)(int prevResult, XR←MesaProc self) */ XR←Pointer clce←clientData; } *XR←CLCallEnv; /* Call environment passed to CLProc (below). The CLProc can either return or call XR←longjmp(clce←jmpBuf, x). If it promises not to do the XR←longjmp, the CLProc is free to store into clce←jmpbuf. The CLProc may store into clce←handlerProc; the stored handler proc will be invoked if this or a subsequent CLProc returns an error value. */ typedef int (*XR←CLProc)(/* XR←CLCallEnv clce, int argc, char **argv, int prevResult, XR←MesaProc self */); /* "Command Line Proc" -- proc to process a command line argument group. The clce value provides command line and procs handles, as well as a place to put message output. If the result is nonzero, it will be stored with associated argument group in command line. The intent is that 0 means "ignored" or "not processed;" positive values are success codes and negative values are error codes. The prevResult value comes from a previous call to a CLProc; see the description of XR←CLApply below. Usual result: 0 means "ignored" or "not processed" >0 means success of some sort <0 means error of some sort but see the description of postProc in XR←CLApply below. */ /* Proc header for a CLProc ... */ #define XR←CLPROC(name) \ int name (clce, argc, argv, prevResult, self) \ XR←CLCallEnv clce; \ int argc; \ char **argv; \ int prevResult; \ XR←MesaProc self; /* Message printing macros for CLProcs ... */ /* To use, omit left paren, e.g. */ /* XR←CLXXXMsg "Hello %d %s\n", 17, "world" ); */ #define XR←CLCEVerbose(clce,which) \ ( *((clce)->clce←msgVerbosityP) >= (which) ) #define XR←CLVerbose(which) \ XR←CLCEVerbose(clce,(which)) #define XR←CLCEMsg(clce) \ XR←PPrintF( (clce)->clce←msgSink, #define XR←CLMsg XR←CLCEMsg(clce) #define XR←CLMsgIf(which) \ if( XR←CLVerbose(which) ) XR←CLMsg #define XR←CLPanicMsg XR←CLMsg #define XR←CLErrorMsg XR←CLMsgIf(XR←VERBOSITY←ERROR) #define XR←CLQuietMsg XR←CLMsgIf(XR←VERBOSITY←QUIET) #define XR←CLWarningMsg XR←CLMsgIf(XR←VERBOSITY←WARNING) #define XR←CLNormalMsg XR←CLMsgIf(XR←VERBOSITY←NORMAL) #define XR←CLLogMsg XR←CLMsgIf(XR←VERBOSITY←LOG) #define XR←CLStatsMsg XR←CLMsgIf(XR←VERBOSITY←STATS) #define XR←CLVerboseMsg XR←CLMsgIf(XR←VERBOSITY←VERBOSE) /* Indirect call from one CLProc to another */ extern int XR←CLCallIndirect(/* XR←CLCallEnv clce, char *key, int argc, char **argv */); /* Invoke CLProc for key on remaining arguments. The prevResult argument will be 0. This can be simulated with other procs in this interface, and is provided as a convenience. */ /* simple utilities for creating CLProcs */ typedef bool /* oldVal = */ (*XR←CLSetBoolProc)(/* bool newVal */); typedef unsigned /* oldVal = */ (*XR←CLSetUnsignedProc)(/* unsigned newVal */); extern int XR←CLProc←setBool(/* ... */); /* An XR←CLProc that expects self->mp←x to be an XR←CLSetBoolProc. Prints "<commandname> set to <on|off> (was <on|off>)" at normal verbosity. */ extern int XR←CLProc←setUnsigned(/* ... */); /* An XR←CLProc that expects self->mp←x to be an XR←CLSetUnsignedProc. Prints "<commandname> set to <newnum> (was <oldnum>)" at normal verbosity. */ /* ProcsHandles -- collections of registered procs */ extern XR←CLProcsHandle XR←CLCreateProcsHandle(/* */); /* Create a CLProcsHandle. */ typedef XR←Pointer /* opaque */ XR←CLRegistration; /* Handle to a registered CLProc. */ extern XR←CLRegistration XR←CLRegisterProc(/* XR←CLProcsHandle pH, char *key, bool caseSensitive, char *helpMsg, XR←MesaProc proc, -- closure of an XR←CLProc bool replace */); /* Add a new Registration to the CLProcsHandle. Return it, or NIL on failure. Multiple procs may not be registered for given key; if a registration already exists the call will fail unless `replace' is TRUE. */ extern int XR←CLUnsafeRegisterProcs(/* XR←CLProcsHandle pH, char **description */); /* The description points to a NIL-terminated sequence, where each sequence element consists of (char *) theMesaProc.mp←proc, (char *) theMesaProc.mp←x, (char *) helpMessage (may be NIL), (char *) firstKey, ... (char *) lastKey, NIL (thus, the whole thing ends with two consecutive NILs). All the procs are registered, with replace == TRUE. Return 0 on success, <0 on failure. Like the name says, this is <<<unsafe>>>, but a useful creature comfort. */ extern int XR←CLUnregister(/* XR←CLProcsHandle pH, XR←CLRegistration r */); /* Undo a registration. Return 0 on success, (-1) on failure. */ extern XR←CLRegistration XR←CLGetRegistrationWithKey(/* XR←CLProcsHandle pH, char *key */); /* Return specified registration, or NIL if none exists. */ extern void XR←CLEnumerateRegistrations(/* XR←CLProcsHandle pH, XR←MesaProc eachRegistration -- closure of bool (*proc)(XR←CLRegistration r, XR←MesaProc self) */); /* Enumerate specified registrations. The proc should return FALSE to abort enumeration. The CLEnumerateRegistrations call holds a monitor; the callback proc may not call into this package except for CLGetRegistrationDetails. */ extern void XR←CLGetRegistrationDetails(/* XR←CLRegistration r, char **key, (* result *) bool *caseSensitive, (* result *) char **helpMsg, (* result *) XR←MesaProc *proc (* result *) */); /* Fill in non-NIL result buffers. */ extern XR←MesaProc XR←CLGetProcForKey(/* XR←CLProcsHandle pH, char *key */); /* Return registered MesaProc, or NIL if none exists. This can be simulated with above procs, is provided as a convenience. */ extern void XR←CLDestroyProcsHandle(/* XR←CLProcsHandle pH */); /* Destroy the ProcsHandle. It's okay just to drop it on the floor. */ /* * * Command Line Processing ... * */ extern int XR←CLApply(/* XR←CLCallEnv clce, XR←MesaProc preProc, -- closure for XR←CLProc, may be NIL XR←MesaProc postProc, -- closure for XR←CLProc, may be NIL */); /* Process the argument groups in command line clce->clce←h using CLProc values registered with clce->clce←pH. For each arg group: - If preProc is specified, invoke it on each arg group. Interpret the result as follows: < 0 => abort processing 0 => call registered CLProc >0 => don't call registered CLProc but continue processing A missing preProc is equivalent to one that always returns 0. - Lookup the registered CLProc and invoke it. Save the result it returns to be passed to the postProc, as described below. A missing registered CLProc is equivalent to a CLProc that does nothing and returns 0. The CLProc can simulate a nonzero return by doing an XR←longjmp to clce->clce←jb. - If postProc is specified, invoke it on each selected arg group after calling the registered CLProc. The result returned by the CLProc is passed as the prevResult argument in this call. Interpret the result as follows: <= 0 => abort processing > 0 => continue processing A missing postProc is equivalent to one that always returns its prevResult argument; thus, it aborts after the first arg group whose CLProc fails or is missing. Return the result of the last postProc invoked. */ #endif