RDROYA01@ULKYVX.BITNET (Robert Royar) (11/04/87)
With all the talk about microEmaxen and argument passing, I thought
that I would add the following to the fire. I have a program
called uEmail which is an ME derivative. In keeping with RMS's
request that all the micro knockoffs not be called EMACS, the name
is not uEmacs. It has a number of compatible functions with
GNUEmacs, and is designed to run as a front end to a connected host
running EMACS or as a stand alone editor. uEmail uses low-level
i/o for everything. I even linked out all of the library
subroutines for streams and appropriated the 8K _fds[] for dynamic
memory use. It includes its own shell for running non-GEM programs
and can be execed at startup before the DESKTOP claims 32K of the
available memory. It's a big sucker (~120K) and uses a number of
startup files to define envirs, the screen font, and default macros
(assigned to specific keys ala Bridger Martin's Backgrounder, a
CP/M program). This is not a commercial for the editor because it
is no longer available through the net.
About arg passing, I appropriated trap 0 to pass pointer to a
structure to any interested program loaded in the shell. The
stucture contains a good deal of useful info about the editor's
state and includes the command line and a pointer to the alias
table. I figure an unused trap is safe game. I reste the trap on
exit. Since the ENVIR structure contains uEmail BUFFER info, I can
write programs to filter buffers to new files, count words and the
like. I've written a standard i/o package called stuei.c which
gives character and line equivalents to getc, ungetc, and gets.
These read from buffers inside the editor. I've also included a
function pointer to a command line reader which allows full command
editing. This allows a shell program to use edited command lines
without the problems associated with GEM level inchar/outchar.
Anyway, here is the standard header file for stuei.c just to give
you an idea.
/* header file for uemail CLI programs which need to use the environment
* table.
*/
#define MAXBUF 16 /* # of buffers in __bp[] */
#define NFILEN 128 /* # of bytes, file name */
#define NBUFN 128 /* # of bytes, buffer name */
#define NLINE 256 /* # of bytes, line */
#define NKBDM 256 /* # of strokes, keyboard macro */
#define NPAT 128 /* # of bytes, pattern */
#define HUGE 1000 /* Huge number */
#define CTRL 0x0100 /* Control flag, or'ed in */
#define META 0x0200 /* Meta flag, or'ed in */
#define CTLX 0x0400 /* ^X flag, or'ed in */
#define SPEC 0x0800 /* Special scancode keys */
#define MAYBE -1 /* Conditional based on query */
#define ABORT 2 /* Death, ^G, abort, etc. */
/*
* There is a window structure allocated for
* every active display window. The windows are kept in a
* big list, in top to bottom screen order, with the listhead at
* "wheadp". Each window contains its own values of dot and mark.
* The flag field contains some bits that are set by commands
* to guide redisplay; although this is a bit of a compromise in
* terms of decoupling, the full blown redisplay is just too
* expensive to run for every input character.
*/
typedef struct WINDOW {
struct WINDOW *w_wndp; /* Next window */
struct BUFFER *w_bufp; /* Buffer displayed in window */
struct LINE *w_linep; /* Top line in the window */
struct LINE *w_dotp; /* Line containing "." */
short w_doto; /* Byte offset for "." */
struct LINE *w_markp; /* Line containing "mark" */
short w_marko; /* Byte offset for "mark" */
int w_percent; /* Percent of buffer before dot */
char w_toprow; /* Origin 0 top row of window */
char w_ntrows; /* # of rows of text in window */
char w_force; /* If NZ, forcing row. */
char w_flag; /* Flags. */
} WINDOW;
#define WFFORCE 0x01 /* Window needs forced reframe */
#define WFMOVE 0x02 /* Movement from line to line */
#define WFEDIT 0x04 /* Editing within a line */
#define WFHARD 0x08 /* Better to a full display */
#define WFMODE 0x10 /* Update mode line. */
/*
* Text is kept in buffers. A buffer header, described
* below, exists for every buffer in the system. The buffers are
* kept in a big list, so that commands that search for a buffer by
* name can find the buffer header. There is a safe store for the
* dot and mark in the header, but this is only valid if the buffer
* is not being displayed (that is, if "b_nwnd" is 0). The text for
* the buffer is kept in a circularly linked list of lines, with
* a pointer to the header line in "b_linep".
*/
typedef struct BUFFER {
struct BUFFER *b_bufp; /* Link to next BUFFER */
struct LINE *b_dotp; /* Link to "." LINE structure */
short b_doto; /* Offset of "." in above LINE */
struct LINE *b_markp; /* The same as the above two, */
short b_marko; /* but for the "mark" */
struct LINE *b_linep; /* Link to the header LINE */
char b_nwnd; /* Count of windows on buffer */
char b_flag; /* Flags */
int b_bmode; /* This buffer's current modes */
char b_fname[NFILEN]; /* File name */
char b_bname[NBUFN]; /* Buffer name */
char b_btime[10]; /* Opened or written last */
} BUFFER;
#define BFTEMP 0x01 /* Internal temporary buffer */
#define BFCHG 0x02 /* Changed since last write */
#define BMNWRAP 0x0001 /* Buffer is in No-Wrap mode */
#define BMWRAP 0x0002 /* Buffer is in Wrap mode */
#define BMCMODE 0x0004 /* Buffer is in C-Mode */
#define BMRDONL 0x0008 /* Buffer is readonly */
#define BMOMODE 0x0010 /* Buffer is in Overwrite mode */
#define BMINFO 0x0020 /* Buffer is in info buffer */
/*
* The starting position of a
* region, and the size of the region in
* characters, is kept in a region structure.
* Used by the region commands.
*/
typedef struct {
struct LINE *r_linep; /* Origin LINE address. */
short r_offset; /* Origin LINE offset. */
short r_size; /* Length in characters. */
} REGION;
/*
* All text is kept in circularly linked
* lists of "LINE" structures. These begin at the
* header line (which is the blank line beyond the
* end of the buffer). This line is pointed to by
* the "BUFFER". Each line contains a the number of
* bytes in the line (the "used" size), the size
* of the text array, and the text. The end of line
* is not stored as a byte; it's implied. Future
* additions will include update hints, and a
* list of marks into the line.
*/
typedef struct LINE {
struct LINE *l_fp; /* Link to the next line */
struct LINE *l_bp; /* Link to the previous line */
short l_size; /* Allocated size */
short l_used; /* Used size */
char l_text[]; /* A bunch of characters. */
} LINE;
#define lforw(lp) ((lp)->l_fp)
#define lback(lp) ((lp)->l_bp)
#define lgetc(lp, n) ((lp)->l_text[(n)]&0xFF)
#define llength(lp) ((lp)->l_used)
/* aliases are kept in dynamically allocated tables. Space for each alias
* and its associated value is allocated as needed.
*/
typedef struct ALITAB {
struct ALITAB *a_forw; /* next table */
char *alias; /* alias */
char *value; /* actual value */
} ALITAB;
extern ALITAB *aheadp; /* structure header */
typedef struct HISTORY {
struct HISTORY *h_forw;
struct HISTORY *h_back;
char *command;
int num;
} HISTORY;
/* environment header initialized at startup and maintained throughout
* session. A pointer to the structure is returned in d0 on trap #0.
*/
typedef struct ENVIR {
BUFFER *bheadp; /* buffer head pointer */
BUFFER *curbp; /* current buffer pointer */
WINDOW *wheadp; /* window head pointer */
WINDOW *curwp; /* current window pointer */
ALITAB *aheadp; /* alias header pointer */
HISTORY *hheadp; /* history head pointer */
char *(*ftime)(); /* time date string (26 bytes). */
/* you pass the time and date */
/* as params (*env->ftime)(t,d) */
int (*reply)(); /* routine to read console */
/* (*env->reply)(prompt,retstr, */
/* MAXLEN,FALSE|TRUE) */
int (*gt_reg)(); /* routine to get a region */
long (*sz_func)(); /* routine to get buffer size */
int (*kf_exe)(); /* execute a function */
short (*kf_get)(); /* get keycode given funcname */
char *(*fn_get)(); /* get funcname given keycode */
char *pnam; /* name of program being run */
} ENVIR;
extern char *malloc();
extern BUFFER *bopen();
extern char *strcpy(), *strncpy(), *alias(), *index(), *rindex();
extern ENVIR *gahp();
extern ENVIR *envirptr;