[comp.sys.atari.st] MicroEmaxen and argument passing in shells

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;