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;