/* TECO for DOS Copyright (C) 1986-1991 Matt Fichtenbaum */ /* Based on Ultrix TECO (C) 1986-1990 GenRad Inc., Concord, MA 01742 */ /* These programs may be copied if this copyright notice is included and */ /* only on a "not for sale or profit" basis */ /* te_utils.c utility subroutines 12/01/90 10.08 */ /* 8-bit version 04/18/91 10.00 */ /* improved dly_free_blist 01/12/92 14.48 */ #include "te_defs.h" #include #ifdef FAR_BUFFER #define t_malloc _fmalloc #define t_free _ffree #else #define t_malloc malloc #define t_free free #endif /* routines to handle storage */ /* get a buffcell */ /* if there are no buffcells available, call malloc for more storage */ #define MAX_ALLOC 1024 #define MAX_ALLOC_D 128 static BUFFPTR alloc_addr[MAX_ALLOC]; /* keep track of memory allocated */ static unsigned short alloc_cnt = 0; BUFFPTR get_bcell(void) { BUFFPTR p; unsigned short i; if (freebuff == NULL) { if (alloc_cnt >= MAX_ALLOC) ERROR(E_MEM); p = (BUFFPTR) t_malloc(BLOCKSIZE); if (!p) ERROR(E_MEM); alloc_addr[alloc_cnt++] = p; /* save block address */ freebuff = p; /* take the given address as storage */ for (i = 0; i < (BLOCKSIZE/sizeof(struct buffcell)) - 1; i++) /* for all cells in the new block */ (p+i)->f = p+i+1; /* chain the forward pointers together */ (p+i)->f = NULL; /* make the last one's forward pointer NULL */ } p = freebuff; /* cut out head of "free" list */ freebuff = freebuff->f; p->f = p->b = NULL; p->usecount = 0; return(p); } /* free a list of buffcells */ void free_blist(BUFFPTR p) { BUFFPTR t; if (p != NULL) { for (t = p; t -> f != NULL; t = t -> f); /* find end of ret'd list */ t->f = freebuff; /* put ret'd list at head of "free" list */ freebuff = p; } } /* free a list of buffcells to the "delayed free" list */ /* if use count is only 1, free it immediately, else delay it */ void dly_free_blist(BUFFPTR p) { BUFFPTR t; if (p != NULL) { if (--p->usecount <= 0) free_blist(p); /* this was last use - free it now */ else { for (t = p; t -> f != NULL; t = t -> f); /* find end of ret'd list */ t->b = NULL; /* null out the end's "b" pointer */ t->f = dly_freebuff; /* put ret'd list at head of "free" list */ if (dly_freebuff != NULL) dly_freebuff->b = t; /* chain old list to this one */ dly_freebuff = p; p->b = (BUFFPTR) &dly_freebuff; } } } /* excise a list from the "delayed free" list and free it now */ /* called when a no-longer-valid macro finishes executing */ void free_dlyd_blist(BUFFPTR p) { BUFFPTR t; if (--p->usecount <= 0) { /* * free a list segment from the "delayed free" list: find the end of the list segment, * marked by a null back pointer, and excise that segment */ for (t = p; t->f != NULL && t->b != NULL; t++); /* find end of list: t points to last cell */ if (t->f != NULL) t->f->b = p->b; /* following list's "back" pointer points to preceding list */ p->b->f = t->f; /* preceding list's "forward" pointer points to following list */ free_blist(p); } } /* reset all used q-reg's use counts to 1, initially or after error */ void reset_q_usecounts() { short i; for (i = 1; i <= NQREGS + 5 + NEXTQREGS; i++) if (qreg[i].f != NULL) qreg[i].f->usecount = 1; } /* get a data cell */ /* if there are no cells available, get some memory and make more */ static struct is *alloc_addr_d[MAX_ALLOC_D]; static unsigned short alloc_cnt_d = 0; struct is *get_dcell(void) { struct is *t; unsigned short i; if (freedcell == NULL) { if (alloc_cnt_d >= MAX_ALLOC_D) ERROR(E_MEM); t = freedcell = (struct is *) _nmalloc(DBLOCKSIZE); /* get some memory */ if (!t) ERROR(E_MEM); alloc_addr_d[alloc_cnt_d++] = t; for (i = 0; i < (DBLOCKSIZE/sizeof(struct is)) - 1; i++) { (t+i)->f = t+i+1; /* chain the fwd pointers together */ (t+i)->f = NULL; /* make the last one's forward pointer NULL */ } } t = freedcell; /* cut out head of "free" list */ freedcell = freedcell->f; t->f = NULL; return(t); } /* build a buffer: called with address of a qh */ /* if no buffer there, get a cell and link it in */ void make_buffer(struct qh *p) { if (!(p->f)) { p->f = get_bcell(); p->f->b = (BUFFPTR) p; p->f->usecount = 0; } } /* routines to advance one character forward or backward */ /* argument is the address of a qp */ /* fwdc, backc return 1 if success, 0 if beyond extremes of buffer) */ /* fwdcx extends buffer if failure */ short fwdc(struct qp *arg) { if ((*arg).c >= CELLSIZE-1) /* test char count for max */ { if ((*arg).p->f == NULL) return(0); /* last cell: fail */ else { (*arg).p = (*arg).p->f; /* chain through list */ (*arg).c = 0; /* and reset char count */ } } else ++(*arg).c; /* otherwise just incr char count */ ++(*arg).dot; return(1); } void fwdcx(struct qp *arg) { if ((*arg).c >= CELLSIZE-1) /* test char count for max */ { if ((*arg).p->f == NULL) /* last cell: extend */ { (*arg).p->f = get_bcell(); (*arg).p->f->b = (*arg).p; } (*arg).p = (*arg).p->f; /* chain through list */ (*arg).c = 0; /* and reset char count */ } else ++(*arg).c; /* otherwise just incr char count */ ++(*arg).dot; } short backc(struct qp *arg) { if ((*arg).c <= 0) /* test char count for min */ { if ((*arg).p->b->b == NULL) return(0); /* first cell: fail */ else { (*arg).p = (*arg).p->b; /* chain through list */ (*arg).c = CELLSIZE-1; /* reset char count */ } } else --(*arg).c; /* otherwise just decr char count */ --(*arg).dot; return(1); } /* return storage obtained from heap */ void free_mem(void) { while (alloc_cnt > 0) /* for each block obtained */ t_free(alloc_addr[--alloc_cnt]); /* call free to free it */ while (alloc_cnt_d > 0) _nfree(alloc_addr_d[--alloc_cnt_d]); } /* set up a pointer to a particular text buffer position */ void set_pointer(long pos, struct qp *ptr) /* first arg is position, 2nd is addr of pointer */ { BUFFPTR t; long i; if (!pbuff->f) { pbuff->f = get_bcell(); /* if no text buffer, make one */ pbuff->f->b = (BUFFPTR) &pbuff->f; } for (i = pos/CELLSIZE, t = pbuff->f; (i > 0) && (t->f != NULL); i--) t = t->f; ptr->p = t; ptr->c = pos % CELLSIZE; ptr->dot = pos; ptr->z = pbuff->z; } /* routines to get next character from command buffer */ /* getcmdc0, when reading beyond command string, pops */ /* macro stack and continues. */ /* getcmdc, in similar circumstances, reports an error */ /* if pushcmdc() has returned any chars, read them first */ /* routines type characters as read, if argument != 0 */ unsigned char getcmdc0(short trace) { while (cptr.dot >= cptr.z) /* if at end of this level, pop macro stack */ { if (msp > &mstack[0]) /* if we're popping a macro */ if (--cptr.head->usecount <= 0) /* decrement the use count, and if it's 0 */ free_dlyd_blist(cptr.head); /* then immediately free that storage */ if (--msp < &mstack[0]) /* pop stack; if top level */ { msp = &mstack[0]; /* restore stack pointer */ cmdc = ESC; /* return an ESC (ignored) */ exitflag = 1; /* set to terminate execution */ return(cmdc); /* exit "while" and return */ } } cmdc = cptr.p->ch[cptr.c++]; /* get char */ ++cptr.dot; /* increment character count */ if (trace) type_char(cmdc); /* trace */ if (cptr.c > CELLSIZE-1) /* and chain if need be */ { cptr.p = cptr.p->f; cptr.c = 0; } return(cmdc); } unsigned char getcmdc(short trace) { if (cptr.dot++ >= cptr.z) ERROR((msp <= &mstack[0]) ? E_UTC : E_UTM); else { cmdc = cptr.p->ch[cptr.c++]; /* get char */ if (trace) type_char(cmdc); /* trace */ if (cptr.c > CELLSIZE-1) /* and chain if need be */ { cptr.p = cptr.p->f; cptr.c = 0; } } return(cmdc); } /* peek at next char in command string, return 1 if it is equal (case independent) to argument */ short peekcmdc(unsigned char arg) { return(((cptr.dot < cptr.z) && (mapch_l[cptr.p->ch[cptr.c]] == mapch_l[arg])) ? 1 : 0); }