home *** CD-ROM | disk | FTP | other *** search
- /*
- menu.c
-
- % menu_Open, menu_Printf, etc.
-
- Menu Generator
-
- C-scape 3.2
- Copyright (c) 1986, 1987, 1988 by Oakland Group, Inc.
- ALL RIGHTS RESERVED.
- written by stephen ng.
- rewritten by Joe DeSantis.
-
- Revision History:
- -----------------
- 3/02/86 sng moved static row, col, and fieldno variables in Printf
- to the data structure, so that you can now make
- more than one menu.
- 3/14/86 sng added new function GetRecordVar to support changed
- field updating.
- 3/22/86 sng rewrote menu_printf to accept % expansion.
- 3/23/86 sng fixed bug that assumed the textbuf had as many lines
- as the menu.
- 3/27/86 sng rewrote set_fa to allow % expansion inside fields.
- 4/06/86 sng permitted (per documentation) multiple flushes.
- 4/16/86 sng menu_Printf now
- 1) takes objects of different sizes
- 2) uses new @ syntax instead of & syntax
- 4/22/86 sng rewrote menu_printf as state machine, now does quoting
- stack, state are both global vars. added (last week)
- grid, and support for up, down, left, right fields
- 4/24/86 sng added menu_Merge2Record, address of string no longer
- passed in menu_Printf.
- 4/28/86 sng added field data manipulators.
- 5/05/86 sng removed "variable" string, because field now holds
- that information.
- 5/19/86 sng assert now checks to see that closed items aren't used
- 5/22/86 sng added color parsing support.
- 5/24/86 sng added type support.
- 6/16/86 sng menus with no fields in them are now acceptable.
- 7/08/86 sng fixed make_grid NULL pointer assignment bug,
- put asserts on a single line for easier grep'ing,
- fixed memory non-deallocation bug in menu_Close.
- 7/09/86 sng #defined out xprint for size.
- 7/11/86 sng made fields xarray.
- 7/19/86 sng removed memory hacks--menu_Printf now returns all
- insufficient memory conditions via dos errno variable
- menu_Close checks to see if it's necessary to flush
- first.
- 10/21/86 sng double %'s weren't handled in percent()--now they are
- 10/31/86 jmd removed ifdefs and externs
- 10/31/86 jmd menu_Open now checks if the text buf opened OK.
- 11/06/86 sng restored some documentation
- 12/03/86 jmd set_color is now a macro
- documented menu_Printf()
- fixed '@['
- made state a local variable.
- cleaned up state machine.
- 12/04/86 jmd added repeat syntax.
- 12/18/86 jmd Adjusted tb_ commands.
- 12/30/86 jmd Check return value of xa_make()
- 1/14/87 jmd Made default TB size a static variable so that it
- can be modified at run time if needed.
- 1/26/87 jmd Removed menu width restrictions.
- 2/07/87 jmd Rewrote menu_Printf with new token parser.
- set_color is now done in line.
- 2/08/87 jmd check length of token_buf as chars are added.
- process when ever token_buf is full. This
- eliminates the 512 char limit.
- 2/11/87 jmd took strlen out of menu_SetTB
- 2/21/87 jmd replaced asserts
- 3/19/87 jmd Increased percent buffer to 511 bytes
- 4/20/87 jmd passed menu to support routines to improve
- error messages
- 4/21/87 jmd fixed repeat syntax, added @fpd[]
- 5/04/87 jmd Replaced the grid
- 5/07/87 jmd added grid hint, rewrote percent, got rid of strchr
- 5/26/87 jmd split up files.
- 6/05/87 jmd added check for end of string
- 7/23/87 jmd removed quote condition for colors ---> "@c[@]]"
- 9/09/87 jmd added NO_PROTO option
- 9/23/87 jmd added STACK_PLUS option, field_funcs_ptr definition.
- 11/15/87 jmd changed memcpy to memmove
- 11/16/87 jmd put back quote condition for colors ---> "@c[@]]"
- 3/06/88 jmd UNIX symbol is now CS_UNIX
- 3/08/88 jmd Added STRATUS decls, added FANCY_PCT check
- 3/28/88 jmd Changed percent() so that it no longer temporarily
- alters the format string.
- 4/10/88 jmd Added call to AddFieldToGrid()
- Removed menu_GetSize function
- 4/11/88 jmd added width to field_Open
- 4/12/88 jmd added @fw[] syntax to menu_Printf()
- 4/30/88 jmd moved buffers into menu structure
- 5/09/88 jmd added WIDE fields
- 5/12/88 jmd fixed test for missing repeat string (p became *p)
- 5/19/88 jmd fixed update of menu->col when using field widths
- 6/23/88 jmd converted generic pointers to VOID*
- 6/24/88 jmd converted to new xarray calls
- 8/16/88 jmd added calls to omalloc, oak_Errno
- 8/20/88 jmd add list of screen objects
- made set_field() a little nicer
- added stack_inc macro
- 8/21/88 jmd rewrote, menu_Printf now pulls field args off the
- stack as commands are received, no more static data
- field names and object commands now parsed
- 9/28/88 jmd Added @a[] support, fixed menu_Flush (again),
- removed spiel about menus at top of file (finally)
- 10/05/88 jmd Removed start size
- Added %G, %i, %hd... %Lf... support to menu_Printf
- 11/30/88 jmd Add o_itoa
- 12/02/88 jmd Fixed %s == "" bug in next_char,
- added error handling to menu_Open
- 12/20/88 jmd removed Errno test
-
- 2/02/89 jdc independent bob's shouldn't have their position set
- 2/07/89 jmd fixed Lattice uninitialized variable warning
- 3/29/89 jmd Added CSPRIV modifier
- 4/21/89 jmd added new @fD syntax
- (makes data pointers without initializing them)
- 4/24/89 jdc added funcnamea for LNF
- 5/29/89 jdc added varnamea for LNF
- 7/02/89 jdc added frowcount change
- 8/10/89 jmd Field widths can now be 0
- 8/20/89 jmd fixed '\n' in repeat syntax
- 8/24/89 jmd added call to tb_GetCol
-
- 11/04/89 jdc changed toupper & tolower to otoupper & otolower
- 11/29/89 jmd added casts for DG
-
- 12/10/89 jmd added ovarargs, made create data private
- 12/11/89 jmd added @fh, field highlighting command
- 12/17/89 jdc fixed cursor positioning (row in wrap mode)
- 1/05/90 jmd allows negative hichar values
- 3/28/90 jmd ansi-fied
- 4/23/90 jmd added tag to enum
- 4/24/90 jmd added ifdef to menu_P declaration
- 5/17/90 jmd put in a comment to fix de-ansi endif problem
- 8/05/90 jmd added test for sed position when connecting a bob
-
- 8/07/90 jdc fixed @a on '\n' bug, added direct bbc_Attr call
- 9/24/90 jmd added test for tokbuf realloc failure
- 10/20/90 bkd changed ifdef OVARARG to O_VARARG.
- 11/01/90 ted put (void) in arg list of menu_Open.
- 12/18/90 jdc added ja_Ok() in menu_GetField()
-
- Note: Long doubles (%Lf) are not supported. #define LONG_DOUBLE
- and recompile this file if you wish to support them.
- */
-
- #include "menu.h"
- #include "oakarg.h" /* for variable argument macros */
- #include "bordobj.h" /* we need border stuff for bobs */
-
- #include <ctype.h>
-
- /***** Static Functions *****/
-
- OSTATIC char * CSPRIV repeat(menu_type menu, char *tokptr, int *cr_countp);
- OSTATIC char * CSPRIV menu_TokBufReSize(menu_type menu, int newsize);
- OSTATIC char CSPRIV next_char(menu_type menu, char **p);
- OSTATIC void CSPRIV set_pos(char *buffer, menu_type menu);
- OSTATIC field_type CSPRIV set_field(menu_type menu, int dcount, int width, int frow, int fcol);
- OSTATIC boolean CSPRIV set_tb(menu_type m, char *end);
- OSTATIC char * CSPRIV percent(menu_type menu, char *in, char *out);
- OSTATIC int CSPRIV atox(char *string);
- OSTATIC char * CSPRIV o_itoa(int val, char *out);
-
- /***** Private Data types *****/
-
- /* menu create struct (used by menu_Printf, destroyed by menu_Flush) */
- typedef struct _menucreate {
-
- char pct_buf[PCT_BUF_LEN + 1]; /* the percent buffer */
- char *pct; /* pointer into the percent buffer */
- ova_list argp; /* argument pointer */
-
- xarray dptrs; /* array of field data pointers */
-
- } menu_create;
-
- /*** states for menu_Printf() ***/
-
- typedef enum _mpstate {
- RESET,
- COMMAND,
- REPEAT,
- REP_QUOTE,
- P_START,
- P_BUILD,
- P_QUOTE,
- A_START,
- A_BUILD,
- A_QUOTE,
- C_START,
- C_BUILD,
- C_QUOTE,
- F_START,
- F_BUILD,
- F_QUOTE,
- F_REPEAT,
- F_REP_QUOTE,
- F_DCOUNT,
- F_NAME,
- F_WIDTH,
- F_HILITE
- } mp_state;
-
- #define TOK_BUF_START 80 /* starting size of the token buffer */
- #define TOK_GROW 20 /* size the token buffer grows by */
-
- /* Return TRUE if c is a field command */
- #define isfldcmd(c) ((c) == '[' || (c) == 'p' || (c) == 'd' || (c) == 'o' || \
- (c) == 'b' || (c) == '{' || (c) == 'w' || (c) == 'h' || (c) == 'D')
-
- /**** Constructors *****/
-
- menu_type menu_Open(void)
- /*
- DESCRIPTION
-
- This function creates a new menu object and returns a handle to it.
- If there is not enough memory to open a new menu object, the
- function returns NULL.
-
- RETURNS
-
- menu_Open returns a handle to the new menu object. A NULL pointer
- value indicates insufficient memory.
- */
- {
- menu_type m;
-
- if ((m = (menu_type) omalloc(CSA_MENU, sizeof(struct menu_struct))) == NULL) {
- goto Quit1;
- }
-
- /* build menu token buffer */
- /* get a little extra just in case */
- if ((m->token_buf = (char *) omalloc(CSA_TOKBUF, TOK_BUF_START + 3)) == NULL) {
- goto Quit2;
- }
- m->token_size = TOK_BUF_START;
-
- /* build menu sub-components */
-
- m->colcount = 0;
- m->rowcount = 1;
- m->frowcount = 0;
- m->dirty = FALSE;
-
- m->vheight = -1;
- m->vwidth = -1;
-
- if ((m->textbuf = tb_Open()) == NULL) {
- goto Quit3;
- }
-
- if ((m->fa = xa_Open(4)) == NULL) {
- goto Quit4;
- }
- if ((m->fgrid = ia_Open(10)) == NULL) {
- goto Quit5;
- }
- m->fieldcount = 0;
-
- if ((m->boba = ia_Open(4)) == NULL) {
- goto Quit6;
- }
- m->bobcount = 0;
-
- m->namelist = NULL;
- m->dptrlist = NULL;
- m->varblock = NULL;
- m->sedptr = NULL;
-
- m->mp_count = 0; /* count number of times menu_Printf is called */
- m->row = m->col = 0;
- m->color = DEF_COLOR;
- m->old_color = DEF_COLOR;
-
- m->create = NULL; /* Created by menu_Printf as needed */
- m->funcnamea = NULL; /* Created by _sfile_loadmenu as needed */
- m->functypea = NULL; /* Created by _sfile_loadmenu as needed */
- m->varnamea = NULL; /* Created by _sfile_loadmenu as needed */
-
- return(m);
-
- /* error handling: Free memory, return NULL */
-
- Quit6:
- ia_Close(m->fgrid);
- Quit5:
- xa_Close(m->fa);
- Quit4:
- tb_Close(m->textbuf);
- Quit3:
- ofree(CSA_TOKBUF, (VOID *) m->token_buf);
- Quit2:
- ofree(CSA_MENU, (VOID *) m);
- Quit1:
- return(NULL);
- }
-
- #ifdef O_VARARG
- boolean menu_Printf(menu, string ova_alist)
- menu_type menu;
- char *string;
- ova_dcl /* NO semicolon */
- #else
- boolean menu_Printf(menu_type menu, char *string ova_alist)
- /* put this comment here to make the de-ansifier work */
-
- #endif
- /*
- requires: a control_string and the right number of arguments (see
- documentation).
-
- modifies: menu.
-
- effects: printf the control string and arguments into the menu.
-
- repeats are allowed in text and in fields but not in @p, @c, or @[.
- */
- {
- register mp_state state = RESET;
- register int i;
- field_type field;
- bob_type bob;
- char c;
- char *tok, *rpt;
- boolean quit;
- int size, hgt, wid, cr_count;
- char *p, *token_buf;
-
- boolean a_ishex; /* @a info */
-
- boolean skip = FALSE; /* used for @f parsing */
-
- menu_create *createp; /* pointer to create data */
-
- VOID *var; /* field info */
- field_funcs_ptr funcs;
- int frow, fcol;
- boolean protect, fdinit;
- int dcount, fwidth, nameno, fhilite;
-
- /* Create create data if there is none */
- if (menu->create == NULL) {
- if ((menu->create = (VOID *) omalloc(CSA_MCREATE, sizeof(menu_create))) == NULL) {
- return(FALSE);
- }
-
- /* create create xarray */
- if ((((menu_create *)(menu->create))->dptrs = xa_Open(10)) == NULL) {
- ofree(CSA_MCREATE, menu->create);
- return(FALSE);
- }
- }
-
- createp = (menu_create *) menu->create;
- token_buf = menu->token_buf;
-
- menu->mp_count++; /* count number of times menu_Printf is called */
-
- cs_Assert(menu_Ok(menu), CS_M_P_MENU, 0);
-
- ova_start(createp->argp, string);
-
- /* Initialize buffers. */
- createp->pct_buf[0] = '\0';
- createp->pct = createp->pct_buf;
- tok = token_buf;
- rpt = token_buf;
- c = ' ';
- p = string;
-
- /* watch length of token_buf */
- /* compare against menu->token_size when adding chars to token_buf */
-
- for (quit = FALSE; !quit; ) {
- if (!skip) { /* skip during field creation sometimes */
- c = next_char(menu, &p);
- /* end of string should only occur in RESET state */
- cs_Assert((state == RESET || c != '\0'), CS_M_P_EOL, menu->mp_count);
- }
-
- switch (state) {
- case RESET: /* Start */
- if (c == '@') {
- *tok = '\0';
- /* add text to tb */
- if (!set_tb(menu, tok)) {
- goto ERROR;
- }
- tok = token_buf;
- state = COMMAND;
- }
- else if (c == '\n') { /* process newline */
- *tok = '\0';
- /* add text to tb */
- if (!set_tb(menu, tok)) {
- goto ERROR;
- }
- tok = token_buf;
- menu->row++;
- menu->col = 0;
- menu->old_color = menu->color; /* set correct color */
- }
- else if (c == '\0') { /* done */
- *tok = '\0';
- /* add text to tb */
- if (!set_tb(menu, tok)) {
- goto ERROR;
- }
- tok = token_buf;
- quit = TRUE;
- }
- else { /* accumulate text */
- *tok++ = c;
- /* is token_buf filled? */
- if (tok - token_buf >= menu->token_size) {
- /* flush token_buf */
- *tok = '\0';
- /* add text to tb */
- if (!set_tb(menu, tok)) {
- goto ERROR;
- }
- tok = token_buf;
- }
- }
- break;
-
- case COMMAND: /* @ */
- switch (c) {
- case 'p':
- state = P_START;
- break;
- case 'f':
- /* reset field info */
- bob = NULL;
- protect = FALSE;
- dcount = 0;
- fdinit = TRUE;
- fwidth = -1;
- fhilite = -1;
- nameno = -1;
-
- /* pull field var and funcs off the stack */
- /* get variable */
- var = (VOID *) ova_arg(createp->argp, VOID *);
-
- /* field functions */
- funcs = ova_arg(createp->argp, field_funcs_ptr);
-
- /* remember field row, col */
- frow = menu->row;
- fcol = menu->col;
-
- /* process field commands */
- state = F_START;
- break;
- case 'a':
- a_ishex = FALSE;
- state = A_START;
- break;
- case 'c':
- state = C_START;
- break;
- case '[':
- state = REPEAT; /* @[ repeat command*/
- break;
- case '@': /* @@ @] */
- case ']':
- *tok++ = c; /* add '@' or ']' to tb */
- if (tok - token_buf >= menu->token_size) {
- *tok = '\0';
- /* add text to tb */
- if (!set_tb(menu, tok)) {
- goto ERROR;
- }
- tok = token_buf;
- }
- state = RESET;
- break;
- default:
- cs_Assert(FALSE, CS_M_P_AT, menu->mp_count);
- break;
- }
- break;
-
-
- case REPEAT: /* @[... */
- if (c == '@') {
- state = REP_QUOTE;
- }
- else if (c == ']') {
- *tok = '\0'; /* process repeat */
- if ((tok = repeat(menu, token_buf, &cr_count)) == NULL) {
- goto ERROR;
- }
- token_buf = menu->token_buf; /* reset in case repeat realloced */
-
- /* if the repeat has newlines in it, don't add it to the tb */
- if (cr_count > 0) {
- /* advance menu location by '\n' in repeat */
- menu->row += cr_count;
- menu->col = 0;
- }
- else {
- /* add text to tb */
- if (!set_tb(menu, tok)) {
- goto ERROR;
- }
- }
-
- tok = token_buf;
- state = RESET; /* reset */
- }
- else { /* accumulate repeat arg */
- *tok++ = c;
- cs_Assert((tok - token_buf < menu->token_size), CS_M_P_RLEN, menu->mp_count);
- }
- break;
-
- case REP_QUOTE: /* throw away quote character */
- *tok++ = c; /* add arg character */
- cs_Assert((tok - token_buf < menu->token_size), CS_M_P_RLEN, menu->mp_count);
- state = REPEAT;
- break;
-
- case P_START: /* @p */
- cs_Assert(c == '[', CS_M_P_ATP, menu->mp_count);
- state = P_BUILD; /* @p[ */
- break;
-
- case P_BUILD: /* @p[... get args or ']' */
- if (c == '@') {
- state = P_QUOTE;
- }
- else if (c == ']') { /* @p[...] process args */
- *tok = '\0';
- tok = token_buf;
- set_pos(token_buf, menu);
- menu->old_color = menu->color; /* set correct color */
- state = RESET; /* reset */
- }
- else { /* accumulate args */
- *tok++ = c;
- cs_Assert((tok - token_buf < menu->token_size), CS_M_P_PLEN, menu->mp_count);
- }
- break;
-
- case P_QUOTE: /* throw away quote character */
- *tok++ = c; /* add arg character */
- cs_Assert((tok - token_buf < menu->token_size), CS_M_P_PLEN, menu->mp_count);
- state = P_BUILD;
- break;
-
- case A_START: /* @a */
- cs_Assert(c == '[', CS_M_P_ATA, menu->mp_count);
- state = A_BUILD; /* @a[ */
- break;
-
- case A_BUILD: /* @a[ */
- if (c == '@') { /* @a[..@ */
- state = A_QUOTE;
- }
- else if (c == ']') { /* @a[...] process arg */
- *tok = '\0';
- if (a_ishex) {
- /* Attribute is a hex digit */
- menu->color = (byte) atox(token_buf);
- }
- else {
- menu->color = (byte) atoi(token_buf);
- }
- tok = token_buf;
- state = RESET; /* reset */
- }
- else if (c == 'x' || c == 'X') {
- tok = token_buf; /* reset token buf; skip x */
- a_ishex = TRUE;
- }
- else { /* accumulate args */
- *tok++ = c;
- cs_Assert((tok - token_buf < menu->token_size), CS_M_P_ALEN, menu->mp_count);
- }
- break;
-
- case A_QUOTE: /* throw away quote character */
- *tok++ = c; /* add arg character */
- cs_Assert((tok - token_buf < menu->token_size), CS_M_P_ALEN, menu->mp_count);
- state = A_BUILD;
- break;
-
- case C_START: /* @c */
- cs_Assert(c == '[', CS_M_P_ATC, menu->mp_count);
- state = C_BUILD; /* @c[ */
- break;
-
- case C_BUILD: /* @c[ */
- if (c == '@') { /* @c[..@ */
- state = C_QUOTE;
- }
- else if (c == ']') { /* @c[...] process args */
- menu->color = (byte) *token_buf; /* set the menu color */
- tok = token_buf;
- state = RESET; /* reset */
- }
- else { /* accumulate args */
- *tok++ = c;
- cs_Assert((tok - token_buf < menu->token_size), CS_M_P_CLEN, menu->mp_count);
- }
- break;
-
- case C_QUOTE: /* throw away quote character */
- *tok++ = c; /* add arg character */
- cs_Assert((tok - token_buf < menu->token_size), CS_M_P_CLEN, menu->mp_count);
- state = C_BUILD;
- break;
-
- case F_START: /* @f */
- skip = FALSE; /* reset skip */
- switch (c) {
- case '[':
- state = F_BUILD; /* @f[ */
- break;
- case 'p':
- protect = TRUE;
- break;
- case 'd': /* parse count */
- state = F_DCOUNT;
- break;
- case 'D': /* parse count (don't init) */
- fdinit = FALSE;
- state = F_DCOUNT;
- break;
- case 'w': /* parse width */
- state = F_WIDTH;
- break;
- case 'h': /* parse highlighting */
- state = F_HILITE;
- break;
- case 'b':
- /* get bob from stack */
- bob = ova_arg(createp->argp, bob_type);
- break;
- case 'm':
- break;
- case '{':
- state = F_NAME; /* get name */
- break;
- default:
- cs_Assert(FALSE, CS_M_P_ATF, menu->mp_count);
- break;
- }
- break;
-
- case F_DCOUNT: /* @fd */
- if (isfldcmd(c)) {
- *tok = '\0';
- tok = token_buf;
- dcount = atoi(token_buf); /* get data count */
- if (dcount <= 0) {
- dcount = 1;
- }
-
- if (fdinit) {
- /* pull data pointers off arg lists,
- store them in the create data xarray for now
- */
- for (i = 0; i < dcount; i++) {
- xa_Put(createp->dptrs, i, ova_arg(createp->argp, VOID *));
- }
- }
-
- /* skip to process new command */
- skip = TRUE;
- state = F_START;
- }
- else if (isdigit(c)) {
- *tok++ = c; /* add arg character */
- }
- else {
- cs_Assert(FALSE, CS_M_P_ATF, menu->mp_count);
- }
- break;
-
- case F_NAME: /* @f{... */
- if (c == '}') {
- *tok = '\0';
- tok = token_buf;
- /* put name into name list */
- nameno = menu_AddName(menu, tok, menu->fieldcount);
- state = F_START;
- }
- else {
- *tok++ = c; /* add name character */
- /* error: name too long */
- cs_Assert((tok - token_buf < NAME_MAXLEN), CS_M_P_NAME, menu->mp_count);
- }
- break;
-
- case F_WIDTH: /* @fw */
- if (isfldcmd(c)) {
- *tok = '\0';
- tok = token_buf;
- fwidth = atoi(token_buf); /* get field width */
- if (fwidth < 0) {
- fwidth = -1;
- }
- /* skip to process new command */
- skip = TRUE;
- state = F_START;
- }
- else if (isdigit(c)) {
- *tok++ = c; /* add arg character */
- }
- else {
- cs_Assert(FALSE, CS_M_P_ATF, menu->mp_count);
- }
- break;
-
- case F_HILITE: /* @fh */
- if (isfldcmd(c)) {
- *tok = '\0';
- tok = token_buf;
- fhilite = atoi(token_buf); /* get hilite char */
- if (fhilite < 0) {
- fhilite = -1;
- }
- /* skip to process new command */
- skip = TRUE;
- state = F_START;
- }
- else if (isdigit(c) || c == '-') { /* allow negative hichar */
- *tok++ = c; /* add arg character */
- }
- else {
- cs_Assert(FALSE, CS_M_P_ATF, menu->mp_count);
- }
- break;
-
- case F_BUILD: /* @f(pd)[ */
- if (c == '@') {
- state = F_QUOTE;
- }
- else if (c == ']') { /* @f[...] process field */
- *tok = '\0';
- tok = token_buf;
-
- /* put a new field into the menu */
- if ((field = set_field(menu, dcount, fwidth, frow, fcol)) == NULL) {
- goto ERROR;
- }
-
- /* set the field's var and funcs, etc. */
- field_SetVar(field, var);
- field_SetFuncs(field, funcs);
- field_SetProtected(field, protect);
- field_SetNameNo(field, nameno);
-
- if (fhilite >= 0) {
- field_SetHiChar(field, fhilite);
- }
-
- wid = field_GetWidth(field);
- hgt = 1;
- if (bob != NULL) {
- /* add bob to list, attach it to field */
- /* the list contains the field no the bob is attached to */
- if (!menu_SetFieldBob(menu, menu->fieldcount - 1, bob)) {
- goto ERROR;
- }
- /* only dependent bobs get their position set,
- and modify the master menu size */
-
- if (bob_IsDepend(bob)) {
- if (menu->sedptr == NULL) {
- bord_SetPosition(bob, frow, fcol);
- }
- else {
- /* compensate for sed position if it exists */
- bord_SetPosition(bob, frow + win_GetTopRow(menu->sedptr),
- fcol + win_GetLeftCol(menu->sedptr));
- }
- hgt = bord_GetHeight(bob);
- wid = bord_GetWidth(bob);
- }
- }
- /* keep track of menu size, including bobs */
- menu->colcount = (menu->col + wid > menu->colcount) ?
- menu->col + wid :
- menu->colcount;
-
- menu->frowcount = (menu->row + hgt > menu->frowcount) ?
- menu->row + hgt :
- menu->frowcount;
-
- menu->col += field_GetWidth(field);
-
- if (fdinit) {
- /* initialize the field's data pointers,
- pull them out of the xarry we stashed them in.
- */
- for (i = 0; i < dcount; i++) {
- field_InitData(field, xa_Get(createp->dptrs, i), i);
- }
- }
-
- state = RESET; /* reset state machine */
- }
- else { /* add char */
- *tok++ = (c == '#' ? CS_INPUT : c);
- if ((size = (tok - token_buf)) >= menu->token_size) {
- if ((token_buf = menu_TokBufReSize(menu, size + TOK_GROW)) == NULL) {
- goto ERROR;
- }
- tok = token_buf + size;
- }
- }
- break;
-
- case F_QUOTE: /* @f[...@ */
- if (c == '[') { /* @[ repeat command*/
- rpt = tok; /* initialize repeat */
- state = F_REPEAT;
- }
- else { /* throw away quote character*/
- *tok++ = c; /* add arg character */
- if ((size = (tok - token_buf)) >= menu->token_size) {
- if ((token_buf = menu_TokBufReSize(menu, size + TOK_GROW)) == NULL) {
- goto ERROR;
- }
- tok = token_buf + size;
- }
- state = F_BUILD;
- }
- break;
-
- case F_REPEAT: /* @f[...@[... */
- if (c == '@') {
- state = F_REP_QUOTE;
- }
- else if (c == ']') {
- *tok = '\0';
- if ((tok = repeat(menu, rpt, &cr_count)) == NULL) {
- goto ERROR;
- }
- token_buf = menu->token_buf; /* reset in case repeat realloced */
- state = F_BUILD; /* continue... */
- }
- else { /* accumulate repeat arg */
- *tok++ = (c == '#' ? CS_INPUT : c);
- if ((size = (tok - token_buf)) >= menu->token_size) {
- if ((token_buf = menu_TokBufReSize(menu, size + TOK_GROW)) == NULL) {
- goto ERROR;
- }
- tok = token_buf + size;
- }
- }
- break;
-
- case F_REP_QUOTE: /* throw out quote character */
- *tok++ = c; /* add arg character */
- cs_Assert((tok - token_buf < menu->token_size), CS_M_P_FLEN, menu->mp_count);
- state = F_REPEAT; /* continue from where we were */
- break;
-
- default:
- cs_Assert(FALSE, CS_M_P_STATE, menu->mp_count);
- }
- }
-
- ova_end(createp->argp);
- return(TRUE);
-
- ERROR:
- ova_end(createp->argp);
- return(FALSE);
- }
-
- /***** menu_Printf support. these are static, CSPRIV functions *****/
-
- static char * CSPRIV repeat(menu_type menu, char *tokptr, int *cr_countp)
- /*
- Evaluates a repeat command and stuffs the result into the
- menu's token buffer at the location pointed to by tokptr.
- Resizes the token buffer if necessary.
-
- @[3,xyz] ==> "xyzxyzxyz"
-
- Returns a pointer to the end of the string.
- Note: the token buffer could be different after this call (realloc).
- */
- {
- int count, len, offset, i, off;
- char *p;
-
- count = atoi(tokptr);
- for (off = 0; tokptr[off] != ',' && tokptr[off] != '\0'; off++) {
- ;
- }
-
- cs_Assert(tokptr[off] != '\0', CS_M_P_RARG, menu->mp_count);
- off++;
-
- /* compute size of repeat string, and number of '\n's */
- *cr_countp = 0;
- for (p = tokptr + off; *p != '\0'; p++) {
- if (*p == '\n') {
- (*cr_countp)++;
- }
- }
-
- len = p - (tokptr + off);
-
- cs_Assert(len > 0, CS_M_P_RARG, menu->mp_count);
-
- /* check for too big */
- cs_Assert(count >= 0 && (count * len) <= MAX_FIELD_LEN, CS_M_P_RVAL, menu->mp_count);
-
- /* Do we need to resize token buffer? */
- offset = (int) (tokptr - menu->token_buf);
- if ((offset + (count * len)) >= menu->token_size) {
- if (menu_TokBufReSize(menu, (offset + (count * len)) + TOK_GROW) == NULL) {
- return(NULL);
- }
- tokptr = menu->token_buf + offset;
- }
- p = tokptr + off;
-
- if (len == 1) {
- memset((VOID *) tokptr, *p, count);
- tokptr[count] = '\0';
- }
- else {
- memmove((VOID *) tokptr, p, len);
- for (i = count, p = tokptr + len; i > 1; i--, p += len) {
- memmove((VOID *) p, (VOID *) tokptr, len);
- }
- *p = '\0';
- }
-
- /* multiply '\n's by repeat count */
- (*cr_countp) *= count;
-
- return(tokptr + (count * len));
- }
-
- static char * CSPRIV menu_TokBufReSize(menu_type menu, int newsize)
- /*
- reallocates the menu's token buffer to newsize.
- returns a pointer to the new buffer.
- returns NULL if it fails.
- the newsize must be larger than the previous size.
- */
- {
- /* Check if field is too long (same errno as above) */
- cs_Assert(newsize <= MAX_FIELD_LEN + TOK_GROW, CS_M_P_FLEN, menu->mp_count);
-
- /* increase size */
- menu->token_size = newsize;
-
- /* get a little extra just in case */
- menu->token_buf = (char *) orealloc(CSA_TOKBUF, menu->token_buf, menu->token_size + 3);
-
- return(menu->token_buf);
- }
-
- static char CSPRIV next_char(menu_type menu, char **p)
- /*
- This routine returns the next format character to be processed.
- If there is a '%' substitution, the substitution is shoved
- into the percent buffer, and then spit out until it is empty.
- 'p' is the address of the pointer to format string.
- */
- {
- char ret;
- menu_create *createp; /* pointer to create data */
-
- createp = (menu_create *) menu->create;
-
- while (1) {
- /* Loop until we find a character or a valid percent expansion */
- if (*(createp->pct) != '\0') {
- ret = *((createp->pct)++);
- break;
- }
- else if (**p != '%') {
- ret = *((*p)++);
- break;
- }
- else {
- /* put test char at end of pct_buf */
- createp->pct_buf[PCT_BUF_LEN] = '\0';
- *p = percent(menu, *p, createp->pct = createp->pct_buf);
-
- /* if test char has changed we've overrun pct_buf */
- cs_Assert(createp->pct_buf[PCT_BUF_LEN] == '\0', CS_M_NC_PCTOVF, menu->mp_count);
- }
- }
-
- return(ret);
- }
-
- static void CSPRIV set_pos(char *buffer, menu_type menu)
- /*
- modifies: menu.
-
- Processes the arguments in buffer and changes the menu state
- information accordingly.
-
- if there is only one argument set the col only.
- */
- {
- char *p;
-
- /* get arguments */
-
- /* hold value in col for now */
- menu->col = atoi(buffer);
-
- for (p = buffer; *p != ',' && *p != '\0'; p++) {
- ;
- }
-
- /* if there are two args then set the row */
- if (*p != '\0') {
- menu->row = menu->col;
- menu->col = atoi(++p);
- }
- }
-
- static field_type CSPRIV set_field(menu_type menu, int dcount, int width, int frow, int fcol)
- /*
- modifies: fa, row, col.
-
- The field spec is in the menu->token_buf.
-
- effects: creates a new field, puts it into the menu.
- returns the field
- */
- {
- field_type field;
- int fieldno;
-
- cs_Assert(menu_Ok(menu), CS_M_SF_MENU, menu->mp_count);
-
- /* create a new field */
- if ( (field =
- field_Open(menu->token_buf, width, (dcount <= 0) ? 1 : dcount) ) == NULL) {
- return(NULL);
- }
-
- fieldno = menu->fieldcount;
-
- /* put new field into array */
- if (!xa_Put(menu->fa, fieldno, (VOID *) field)) {
- field_Close(field);
- return(NULL);
- }
-
- /* place the field into the grid */
- if (!menu_AddFieldToGrid(menu, fieldno, frow, fcol)) {
- field_Close(field);
- return(NULL);
- }
-
- menu->fieldcount++;
-
- return(field);
- }
-
- static boolean CSPRIV set_tb(menu_type m, char *end)
- /*
- effects: prints menu->token_buf into textbuf.
-
- end points to the end of the current token.
-
- returns: TRUE if successful
- */
- {
- char *buffer;
- int len;
-
- /* ignore if nothing there */
- if ((buffer = m->token_buf) == end) {
-
- /* color change on the the '\n' */
- if (m->color != m->old_color) {
- return(bbc_Attr(m->textbuf->bbc, (long)m->textbuf->len - 1, m->color, 1));
- }
- return(TRUE);
- }
-
- len = (int) (end - buffer);
-
- if (!menu_Puts(m, m->row, m->col, buffer, len, m->color, m->old_color)) {
- return(FALSE);
- }
-
- m->old_color = m->color;
- m->row = tb_GetRow(m->textbuf);
- m->col = tb_GetCol(m->textbuf);
-
- return(TRUE);
- }
-
- static char * CSPRIV percent(menu_type menu, char *in, char *out)
- /*
- effects: does '%' substitution on the in string; places results into
- out string.
-
- modifies: out.
-
- returns: the place in 'in' where conversion finished.
-
- note: It is an error for the % expression to be longer
- than 40 characters!
-
- %*d not supported
- */
- {
- char *last, fmt[41];
- int len;
- boolean exit;
- menu_create *createp; /* pointer to create data */
-
- createp = (menu_create *) menu->create;
-
- /* handle %d and %s as special cases */
- if (*(in + 1) == 'd') {
- o_itoa(ova_arg(createp->argp, int), out);
- return(in + 2);
- }
- else if (*(in + 1) == 's') {
- strcpy(out, ova_arg(createp->argp, char *));
- return(in + 2);
- }
-
- /* find the spec string for sprintf */
- last = in + 1;
- exit = FALSE;
- while(!exit) {
- switch (*last) {
- case 'c':
- case 'd':
- case 'e':
- case 'E':
- case 'f':
- case 'g':
- case 'G':
- case 'i':
- case 'o':
- case 's':
- case 'u':
- case 'x':
- case 'X':
- case '%':
- case '\0':
- len = last - in + 1;
- cs_Assert(len < 40, CS_M_P_CONV, menu->mp_count);
- memmove((VOID *) fmt, (VOID *) in, len);
- fmt[len] = '\0';
- exit = TRUE;
- break;
-
- default:
- last++;
- break;
- }
- }
-
- if ((*(last-1) == 'h') &&
- (*last == 'd' || *last == 'u' || *last == 'o' ||
- *last == 'i' || *last == 'x' || *last == 'X')) {
- sprintf(out, fmt, ova_arg(createp->argp, short));
- }
- else if ((*(last-1) == 'l') &&
- (*last == 'd' || *last == 'u' || *last == 'o' ||
- *last == 'i' || *last == 'x' || *last == 'X')) {
- sprintf(out, fmt, ova_arg(createp->argp, long));
- }
-
- #ifdef LONG_DOUBLE /* define this if you want to support long doubles */
- else if ((*(last-1) == 'L') &&
- (*last == 'e' || *last == 'E' || *last == 'f' ||
- *last == 'G' || *last == 'g')) {
- sprintf(out, fmt, ova_arg(createp->argp, long double));
- }
- #endif
-
- else if (*last == 'e' || *last == 'E' || *last == 'f' ||
- *last == 'G' || *last == 'g') {
- sprintf(out, fmt, ova_arg(createp->argp, double));
- }
- else if (*last == 'd' || *last == 'i' || *last == 'u' || *last == 'o' ||
- *last == 'x' || *last == 'X' || *last == 'c') {
- sprintf(out, fmt, ova_arg(createp->argp, int));
- }
- else if (*last == 's') { /* in */
- sprintf(out, fmt, ova_arg(createp->argp, char *));
- }
- else if (*last == '%') { /* two %'s */
- out[0] = '%';
- out[1] = '\0';
- }
- else {
- cs_Assert(FALSE, CS_M_P_CONV, menu->mp_count);
- }
-
- return(last + 1);
- }
-
- static int CSPRIV atox(char *string)
- /*
- Convert a hex number to an integer.
- Leading spaces and minus signs are NOT allowed.
- This replaces the call to nasty sscanf.
- */
- {
- char *p;
- int val = 0;
-
- for (p = string; isxdigit(*p); p++) {
- val = 16 * val + (isdigit(*p) ? (*p - '0') : (otolower(*p) - 'a' + 10));
- }
-
- return(val);
- }
-
- static char * CSPRIV o_itoa(int val, char *out)
- /*
- Convert an integer to a string
- (replacement for itoa)
- */
- {
- int digit, sign = 0;
- char *p, *q, c;
-
- if (val == 0) {
- out[0] = '0';
- out[1] = '\0';
- return(out);
- }
-
- if (val < 0) {
- val = -val;
- sign = 1;
- }
-
- for(p = out; val > 0; val = val / 10, p++) {
- digit = val % 10;
- *p = (char) (digit + '0');
- }
-
- if (sign) {
- *p++ = '-';
- }
-
- *p = '\0';
-
- /* result is in wrong order, reverse it */
- for (q = out, p--; q < p; q++, p--) {
- c = *p;
- *p = *q;
- *q = c;
- }
-
- return(out);
- }
-
- /**** more menu functions ****/
-
- void menu_Flush(menu_type menu)
- /*
- If a menu_create struct has been created, destroy it
- else do nothing.
- */
- {
- cs_Assert(menu_Ok(menu), CS_M_F_MENU, 0);
-
- if (menu->create != NULL) {
- xa_Close(((menu_create *)(menu->create))->dptrs);
- ofree(CSA_MCREATE, (VOID *) menu->create);
- menu->create = NULL;
- }
- }
-
- /**** Mutators *****/
-
- boolean menu_Ok(menu_type menu)
- /*
- returns: TRUE if passed a good menu, FALSE otherwise.
- */
- {
- if (menu == NULL || menu->textbuf == NULL || menu->fa == NULL ||
- menu->fgrid == NULL || menu->rowcount < 0 || menu->colcount < 0 ||
- menu->fieldcount < 0 ) {
- cs_Assert(menu->rowcount != -555 && menu->colcount != -555 && menu->fieldcount != -555, CS_M_OK_CLS, 0);
- return(FALSE);
- }
- return(TRUE);
- }
-
- /**** Misc ****/
-
- field_type menu_GetField(menu_type menu, int fld)
- /*
- Extracts a field from the field array.
- */
- {
- return((!ja_Ok(menu->fa)) ? NULL : (field_type) xa_Get(menu->fa, fld));
- }
-