Path: utzoo!utgpu!news-server.csri.toronto.edu!bonnie.concordia.ca!uunet!cis.ohio-state.edu!zaphod.mps.ohio-state.edu!mips!pacbell.com!pacbell!mtdiablo!rob From: rob@mtdiablo.Concord.CA.US (Rob Bernardo) Newsgroups: alt.sources Subject: DMM (Data entry and Menu screen Manager) - version 1.1 part 2/2 Message-ID: <1991Jun18.012419.10146@mtdiablo.Concord.CA.US> Date: 18 Jun 91 01:24:19 GMT References: <1991Jun18.012151.10052@mtdiablo.Concord.CA.US> Organization: Mt. Diablo Software Solutions Lines: 1591 #!/bin/sh # this is part 2 of a multipart archive # do not concatenate these parts, unpack them in order with /bin/sh # file dmm.c continued # CurArch=2 if test ! -r s2_seq_.tmp then echo "Please unpack part 1 first!" exit 1; fi ( read Scheck if test "$Scheck" != $CurArch then echo "Please unpack part $Scheck next!" exit 1; else exit 0; fi ) < s2_seq_.tmp || exit 1 echo "x - Continuing file dmm.c" sed 's/^X//' << 'SHAR_EOF' >> dmm.c X return; X} X X X/* This replaces the standard curses overlay(), which is broken: X * it does not preserve the attributes of the copied characters X */ Xstatic void XoverLay (srcWin, dstWin) XWINDOW *srcWin, X *dstWin; X{ X register int x, X y; X register chtype mychar; X for (y = 0; y < srcWin->_maxy; y++) { X for (x = 0; x < srcWin->_maxx; x++) { X mychar = mvwinch (srcWin, y, x); X if (((mychar & A_CHARTEXT) != ' ') X || ((mychar & A_ATTRIBUTES) != A_NORMAL)) X mvwinsch (dstWin, y, x, mychar); X } X } X return; X} X X X X/* fieldMgr() manage user interactions with the field window; X * start by first positioning in the infput field X * designated by fldNum; if fldNum is -1, use the X * default input field, determined from the last X * call to this function; X * set the default field for use in the next call to X * this function before returning. X * return -1 if the user wants to leave for the menu; X * else return the field number of a field if the X * audit routine for that field returns dmmAuditReturnOkay X * or dmmAuditReturnBad, which means that the screen X * handler must return to the application software; X */ Xstatic int XfieldMgr (fldNum) Xregister int fldNum; X{ X register int curCol, /* current column number in field */ X curLine, /* current line number in field */ X curChar; /* current char position in field */ X enum change delta; /* what to do upon user input keystroke */ X int key, /* user's input keystroke */ X len; /* length of field being manipulated */ X static dfltInputFld; /* default field for next call */ X char *instructMesg; /* message for instruct line */ X X /* display general instructions about how to go to menu */ X if (numMenuItems) X instructMesg = GOTO_MENU_INSTRUCT; X else X instructMesg = NULL_MENU_INSTRUCT; X dispInstruct (instructMesg); X X /* first field: instruction and attribute */ X fldNum = (fldNum == -1) ? dfltInputFld : fldNum; X arriveInField (dupeScreen[fldNum]); X X /* separate parts of refresh for sake of dispInstruct() above */ X wnoutrefresh (fieldWin); X doupdate (); X X /* add messages as needed */ X if (needAddMsgs) { X overwrite (fieldWin, fieldWinPreMsg); X overLay (mesgWin, fieldWin); X } X /* position cursor in appropriate field */ X (void) chgInField (fldNum, stayput); X curCol = curLine = curChar = 0; X X /* process user input */ X while (1) { X delta = stayput; /* default is no chg in field/cursor pos. Any X * of the below choices that change the X * screen but stayput need to do their own X * wrefresh() */ X X switch (key = wGetCh (fieldWin)) { X X case CTRL (h): X /* display help */ X doPutMsgsHit (helpMsgVec, 1); X break; X X case CTRL (g): X /* submit screen as is; set default field to current field and go X * to menu X */ X adjustFld (dupeScreen[fldNum]); X leaveInField (dupeScreen[dfltInputFld = fldNum]); X return -1; X X case CTRL (c): X /* clear to end of field, audit, move to next field */ X for (len = dupeScreen[fldNum]->inputLength; X curChar < len; curChar++) X dupeScreen[fldNum]->inputEditValue[curChar] = '\0'; X dispInField (dupeScreen[fldNum], X dupeScreen[fldNum]->inputEditAttrib); X delta = next; X break; X X case RETURN: X case TAB: X case CTRL (n): X /* audit and move to next field */ X delta = next; X break; X X case CTRL (p): X /* audit and move to previous field */ X delta = previous; X break; X X case CTRL (r): X /* redraw screen */ X redraw (); X break; X X case KEY_LEFT: X /* move cursor to left if possible */ X if (curCol) { X curCol--; X curChar--; X delta = movecursor; X } else X flash(); X break; X X case KEY_RIGHT: X /* move cursor to right if possible */ X if (((curLine < dupeScreen[fldNum]->inputFullLines) && X (curCol + 1 < dupeScreen[fldNum]->inputMaxCols)) || X (curCol + 1 < dupeScreen[fldNum]->inputShortCols)) { X curCol++; X curChar++; X delta = movecursor; X } else X flash(); X break; X X case KEY_UP: X /* move cursor up if possible */ X if (curLine != 0) { X curLine--; X curChar -= dupeScreen[fldNum]->inputMaxCols; X delta = movecursor; X } else X flash(); X break; X X case KEY_DOWN: X /* move cursor down if possible */ X if ((curLine + 1 < dupeScreen[fldNum]->inputFullLines) || X ((curLine + 1 == dupeScreen[fldNum]->inputFullLines) && X (curCol < dupeScreen[fldNum]->inputShortCols))) { X curLine++; X curChar += dupeScreen[fldNum]->inputMaxCols; X delta = movecursor; X } else X flash(); X break; X X case DELETE: X /* erase character to left of cursor and move cursor left, X * except if we are in last character position and last X * character is not a space, then erase last character X * and don't move cursor. X * Obviously, erase nothing if we are in the first character X * position last is not also a last character position. X */ X if((curChar + 1 == dupeScreen[fldNum]->inputLength) && X (dupeScreen[fldNum]->inputEditValue[curChar] != ' ')) { X X /* erase last character internally */ X dupeScreen[fldNum]->inputEditValue[curChar] = ' '; X X } else { X X /* do nothing if we are in the first character position X * which is not also the last character position */ X if (!curChar) { X flash(); X break; X } X X /* erase last character internally */ X dupeScreen[fldNum]->inputEditValue[--curChar] = ' '; X X /* retreat the cursor */ X if (curCol) X curCol--; X else { X curLine--; X curCol = dupeScreen[fldNum]->inputMaxCols - 1; X } X } X X /* display space on screen */ X DMMWATTRON (fieldWin, dupeScreen[fldNum]->inputEditAttrib); X mvwaddch (fieldWin, X dupeScreen[fldNum]->inputLine + curLine, X dupeScreen[fldNum]->inputCol + curCol, ' '); X DMMWATTROFF (fieldWin, dupeScreen[fldNum]->inputEditAttrib); X X delta = movecursor; X break; X X default: X /* process only if a printing character */ X if (isascii (key) && isprint (key)) { X X /* display character, or if A_INVIS display space */ X DMMWATTRON (fieldWin, dupeScreen[fldNum]->inputEditAttrib); X mvwaddch (fieldWin, X dupeScreen[fldNum]->inputLine + curLine, X dupeScreen[fldNum]->inputCol + curCol, X (dupeScreen[fldNum]->inputEditAttrib & A_INVIS) ? X ' ' : (char) key); X DMMWATTROFF (fieldWin, dupeScreen[fldNum]->inputEditAttrib); X X /* store internally */ X dupeScreen[fldNum]->inputEditValue[curChar] = (char) key; X X /* if not at end of field, move cursor */ X if (curChar + 1 < dupeScreen[fldNum]->inputLength) { X /* either move to next col in same line or first col of X * next line X */ X curChar++; X if (((curLine < dupeScreen[fldNum]->inputFullLines) && X (curCol + 1 < dupeScreen[fldNum]->inputMaxCols)) || X (curCol + 1 < dupeScreen[fldNum]->inputShortCols)) X curCol++; X else { X curCol = 0; X curLine++; X } X delta = movecursor; X } X } else X flash (); X break; X } X X /* now check if cursor position of field is to be changed */ X switch (delta) { X X case next: X case previous: X /* advance or retreat a field */ X X /* remove trailing blanks and internal nulls */ X adjustFld (dupeScreen[fldNum]); X X /* audit field */ X if (dupeScreen[fldNum]->inputAudit) { X X switch (dupeScreen[fldNum]->inputAudit X (dupeScreen[fldNum]->inputEditValue)) { X X case dmmAuditReturnOkay: X /* must leave screen handler; first show any changes to X * field value and set default field according to user's X * last keystroke X */ X dmmRetType = dmmOkayField; X leaveInField (dupeScreen[fldNum]); X wrefresh (fieldWin); X dfltInputFld = delta == next ? X dupeScreen[fldNum]->nextInField : X dupeScreen[fldNum]->prevInField; X return fldNum; X X case dmmAuditReturnBad: X /* must leave screen handler; first show any changes to X * field value and set default field according to user's X * last keystroke X */ X dmmRetType = dmmBadField; X leaveInField (dupeScreen[fldNum]); X wrefresh (fieldWin); X dfltInputFld = delta == next ? X dupeScreen[fldNum]->nextInField : X dupeScreen[fldNum]->prevInField; X return fldNum; X X case dmmAuditBad: X /* failed; stay in this field */ X delta = stayput; X break; X X case dmmAuditOkay: X /* audit okay; go to another field */ X break; X } X } X X /* show any changes to field value */ X fldNum = chgInField (fldNum, delta); X curCol = curLine = curChar = 0; X wrefresh (fieldWin); X break; X X case stayput: X case movecursor: X /* move cursor to current column and line position in current X * input field as just set or left as was X */ X wmove (fieldWin, dupeScreen[fldNum]->inputLine + curLine, X dupeScreen[fldNum]->inputCol + curCol); X wrefresh (fieldWin); X break; X } X } X} X X X/* leaveMenu() leave menu; X * if menuitem is < 0, erase whole menu, X * else unhighlight indicated item X */ Xstatic void XleaveMenu (itemNum) Xint itemNum; X{ X if (itemNum < 0) { X wclear (menuWin); X wnoutrefresh (menuWin); X } else X dispMenuPage (itemNum, 0, 0); X return; X} X X X/* menuMgr manage user interactions with the menu window; X * return the number of the menu item selected X * or -1 if the user wants to leave the menu without X * a selection. X */ Xstatic int XmenuMgr () X{ X int key; X X /* display the current page of the menu with the current item highlighted */ X dispMenuPage (curMenuItem, 1, 1); X X /* display general menu instruction */ X dispInstruct (MENU_INSTRUCT); X X /* add messages as needed */ X if (needAddMsgs) { X overwrite (fieldWin, fieldWinPreMsg); X overLay (mesgWin, fieldWin); X wnoutrefresh (fieldWin); X } X X /* process user input */ X while (1) { X X /* refresh instruct and menu page on screen, as needed */ X outOfTheWay(); X doupdate (); X X switch (key = wGetCh (menuWin)) { X X case CTRL (h): X /* display help */ X doPutMsgsHit (helpMsgVec, 1); X break; X X case CTRL (r): X /* redraw screen */ X redraw (); X break; X X case CTRL (g): X /* leave menu for input part of screen */ X leaveMenu (curMenuItem); X return -1; X X case RETURN: X /* submit this choice */ X leaveMenu (-1); X return curMenuItem; X X case TAB: X case CTRL (n): X /* move to next item */ X if (++curMenuItem >= numMenuItems) X curMenuItem = 0; X dispMenuPage (curMenuItem, 1, 0); X break; X X case CTRL (p): X /* move to previous item */ X if (--curMenuItem < 0) X curMenuItem = numMenuItems - 1; X dispMenuPage (curMenuItem, 1, 0); X break; X X default: X /* find single menu item with matching first character */ X if (isascii (key) && isalpha (key)) { X if (isupper (key)) X key = tolower (key); X if (menuIndex[key - 'a'] >= 0) { X dispMenuPage (curMenuItem = menuIndex[key - 'a'], 1, 0); X break; X } X } X flash (); X break; X } X } X} X X X/* dmmRun manage menu and data entry screen - see man page for fuller X * description X */ Xint XdmmRun (startField, screen, menu, dmmDrawFlag, dmmValFlag) Xint startField; XDMMDRAWFLAG dmmDrawFlag; XDMMVALFLAG dmmValFlag; XDMMSCREEN screen; XDMMMENU menu; X{ X int itemNum; /* menu or field number */ X void (*oldSignalValue) (); /* current state for signal X * SIGALRM */ X X /* copy parameters to global variables */ X dupeScreen = screen; X dupeMenu = menu; X X /* initialize windows if needed */ X if (!isOpen) X dmmInit (); X X /* get rid of type-ahead input */ X flushinp (); X X /* process dmmDrawFlag */ X switch (dmmDrawFlag) { X X case dmmNew: X X /* the first display of a screen - do initial layout calculations */ X if (layout ()) X return -1; X X /* determine field for cursor */ X if (startField == -1) X startField = firstInputFld; X X /* do sanity checking */ X if (insane (startField)) X return -1; X X /* display screen */ X redraw (); X X break; X X X case dmmOld: X /* restore saved screen and redisplay menu with first item X * highlighted; let a -1 startField stand - fieldMgr() will X * interpret it to mean the last input field saved on the last call X * of dmmRun(). X */ X X /* This overwrite gets rid of any messages displayed by X * dmmPutMsgsNext(), and so the needAddMsgs flag is used to get them X * reinstated in fieldMgr() and menuMgr(). X */ X overwrite (fieldWinCopy, fieldWin); X redraw (); X if (dupeMenu) X dispMenuPage (0, 0, 1); X break; X X } X X /* copy inputInitValue's if indicated by dmmValFlag */ X if (dmmValFlag == dmmInitVal) X copyInFields (); X X /* process user input */ X X /* ignore SIGALRM to avoid a bug in wgetch() that fails to cancel an X * alarm() it sets after unsetting the catching of SIGALRM; this must be X * reset to current value before returning. X */ X oldSignalValue = signal (SIGALRM, SIG_IGN); X X interactive = 1; X X while (1) { X X /* manage fields with input parts, if any */ X if (numInputParts) { X if ((itemNum = fieldMgr (startField)) != -1) X break; X startField = itemNum; X } X X /* manage menu items, if any */ X if (numMenuItems) { X if ((itemNum = menuMgr ()) != -1) { X dmmRetType = dmmMenu; X break; X } X doupdate (); X } X } X X /* remove instruction and update screen */ X dispInstruct (""); X doupdate (); X X /* save copy of screen for restoral with dmmOld option */ X overwrite (fieldWin, fieldWinCopy); X X /* undo ignoring of alarm signal */ X (void) signal (SIGALRM, oldSignalValue); X X interactive = 0; X X return itemNum; X} SHAR_EOF echo "File dmm.c is complete" chmod 0444 dmm.c || echo "restore of dmm.c fails" set `wc -c dmm.c`;Sum=$1 if test "$Sum" != "44980" then echo original size 44980, current size $Sum;fi echo "x - extracting dmm.h (Text)" sed 's/^X//' << 'SHAR_EOF' > dmm.h && X#ifndef LINT Xstatic char dmm_h_id[] = {"@(#)dmm.h 1.1 \ XCopyright (c) 1991 Robert Bernardo, rob@mtdiablo.Concord.CA.US, \ Xan employee of Pande, Inc. \ XPermission to use granted only if this notice is not removed from \ Xthis source file nor from any binaries produced from it."}; X X#endif X X/* data display and entry field descriptor */ Xtypedef struct dmmField { X char *labelValue; X int labelCol, X labelLine; X long labelAttrib; X char *inputEditValue, X *inputInitValue; X int inputCol, X inputLine, X inputLength, X inputMaxCols, X inputFullLines, X inputShortCols; X long inputAttrib, X inputEditAttrib; X char **inputInstructVec; X int inputNumInstructs; X enum dmmAuditReturn (*inputAudit) (); X int nextInField, X prevInField; X} DMMFIELD, *DMMSCREEN[], **DMMSCREEN2; X X/* menu item descriptor */ Xtypedef struct dmmMenuItem { X char *label, X *descript; X int col, X page; X} DMMMENUITEM, *DMMMENU[], **DMMMENU2; X X/* message descriptor */ Xtypedef struct dmmMessage { X char *value; X int col, X line; X long attrib; X} DMMMESSAGE, *DMMMESGBLK[], **DMMMESGBLK2; X X/* return values for inputAudit() */ Xtypedef enum dmmAuditReturn { X dmmAuditOkay, dmmAuditBad, dmmAuditReturnOkay, dmmAuditReturnBad X} DMMAUDITRETURN; X X/* DrawFlag values */ Xtypedef enum dmmDrawFlag { X dmmNew, dmmOld X} DMMDRAWFLAG; X X/* ValFlag values */ Xtypedef enum dmmValFlag { X dmmInitVal, dmmEdVal X} DMMVALFLAG; X X/* dmmRetType values */ Xtypedef enum dmmRetType { X dmmOkayField, dmmBadField, dmmMenu X} DMMRETTYPE; X X/* dmmRemoveType values */ Xtypedef enum dmmRemoveType { X dmmRemoveAll, dmmRemoveLast X} DMMREMOVETYPE; X Xextern enum dmmRetType dmmRetType; Xextern void dmmPutMsgs(), X dmmPutMsgsTimer(), X dmmPutMsgsHit(), X dmmPutMsgsNext(), X dmmRmMsgs(), X dmmInit(), X dmmClear(), X dmmClose(); X X#ifndef A_INVIS X#define A_INVIS 000020000000L X#endif SHAR_EOF chmod 0444 dmm.h || echo "restore of dmm.h fails" set `wc -c dmm.h`;Sum=$1 if test "$Sum" != "2793" then echo original size 2793, current size $Sum;fi echo "x - extracting dmmdemo.h (Text)" sed 's/^X//' << 'SHAR_EOF' > dmmdemo.h && X#ifndef LINT Xstatic char dmmdemo_h_id[] = {"@(#)dmmdemo.h 1.1 \ XCopyright (c) 1991 Robert Bernardo, rob@mtdiablo.Concord.CA.US, \ Xan employee of Pande, Inc. \ XPermission to use granted only if this notice is not removed from \ Xthis source file nor from any binaries produced from it."}; X#endif X X#define NUMBERCOL 5 X#define BODYCOL (NUMBERCOL + 3) X Xextern void calcdate(), X msgdemo(), X getcomment(), X monthmenu(); SHAR_EOF chmod 0444 dmmdemo.h || echo "restore of dmmdemo.h fails" set `wc -c dmmdemo.h`;Sum=$1 if test "$Sum" != "432" then echo original size 432, current size $Sum;fi echo "x - extracting dmmdemo1.c (Text)" sed 's/^X//' << 'SHAR_EOF' > dmmdemo1.c && X#ifndef LINT Xstatic char dmmdemo_1_c_id[] = {"@(#)dmmdemo1.c 1.1 \ XCopyright (c) 1991 Robert Bernardo, rob@mtdiablo.Concord.CA.US, \ Xan employee of Pande, Inc. \ XPermission to use granted only if this notice is not removed from \ Xthis source file nor from any binaries produced from it."}; X#endif X#include X#include "dmm.h" X#include "dmmdemo.h" X X/* messages */ Xstatic DMMMESSAGE intro1 = X{"Welcome to the DMM demonstration program. This program will use DMM", X0, 0, 0}, X X intro2 = X{"functions to present a variety of screens. For each screen, it will", X0, 1, 0}, X X intro3 = X{"state the associated source file and list its salient features.", X0, 2, 0}, X X intro4 = X{"The source for this screen is in dmmdemo1.c.", X0, 4, 0}, X X intro5 = X{"1. It has just called dmmInit() to start up curses (putting the", XNUMBERCOL, 5, 0}, X X intro6 = X{"terminal into raw mode, etc.) and to initialize the DMM windows.", XBODYCOL, 6, 0}, X X intro7 = X{"2. This block of messages is displayed with a call do dmmPutMsgsHit().", XNUMBERCOL, 7, 0}, X X intro8 = X{"Notice the top line if this screen. After the next message, you", XBODYCOL, 8, 0}, X X intro9 = X{"will be presented with a menuless screen. The top line always has", XBODYCOL, 9, 0}, X X intro10 = X{"an appropriate general instruction when a call to dmmRun() presents", XBODYCOL, 10, 0}, X X intro11 = X{"a screen. Pay attention to it throughout this demo. Remember that", XBODYCOL, 11, 0}, X X intro12 = X{"control-H displays a useful help screen during a dmmRun() call.", XBODYCOL, 12, 0}, X X intro13 = X{"The source for the menuless screen is in dmmdemo2.c Enter any log name", X0, 0, 0}, X X intro14 = X{"and any password; it doesn't matter. The simulated login procedure is", X0, 1, 0}, X X intro15 = X{"hardcoded to reject them the first time and succeed the second, so you", X0, 2, 0}, X X intro16 = X{"will need to try a second time. Next time you run this program, enter 'y'", X0, 3, 0}, X X intro17 = X{"to the \"give up\" question and see what happens.", X0, 4, 0}, X X intro18 = X{"Note the following:", X0, 6, 0}, X X intro19 = X{"1. Negative column numbers are used to separate the labels from the", XNUMBERCOL, 7, 0}, X X intro20 = X{"input areas by a certain number of blank spaces.", XBODYCOL, 8, 0}, X X intro21 = X{"2. The audit functions for the \"give up\" (if you enter 'y') and ", XNUMBERCOL, 9, 0}, X X intro22 = X{"\"password\" fields return values that cause dmmRun() to return. Because ", XBODYCOL, 10, 0}, X X intro23 = X{"this is a menuless screen and no menu selection can be made, such is", XBODYCOL, 11, 0}, X X intro24 = X{"necessary so that dmmRun() doesn't just go on indefinitely.", XBODYCOL, 12, 0}, X X intro25 = X{"3. See how the data type DMMSCREEN2 is used for a pointer.", XNUMBERCOL, 13, 0}, X X intro26 = X{"4. Data entered into the password field is invisible.", XNUMBERCOL, 14, 0}, X sizemsg1 = X{"The DMM demo requires your screen (or window) to have at least 24", X0, 0, A_REVERSE}, X sizemsg2 = X{"lines and 80 columns.", X0, 1, A_REVERSE}, X byemsg = X{"End of the DMM demonstration. Good bye.", X0, 0, A_REVERSE}; X X X X Xstatic DMMMESGBLK introA = {&intro1, &intro2, &intro3, &intro4, &intro5, X &intro6, &intro7, &intro8, &intro9, &intro10, X &intro11, &intro12, 0}, X X introB = {&intro13, &intro14, &intro15, &intro16, X &intro17, &intro18, &intro19, &intro20, X &intro21, &intro22, &intro23, &intro24, X &intro25, &intro26, 0}, X X requirements = {&sizemsg1, &sizemsg2, 0}, X X byemsgblk = {&byemsg, 0}; X Xmain() X{ X dmmInit(); /* start up curses; init DMM windows */ X if((COLS < 80) || (LINES < 24)) { /* make sure screen is large enough */ X dmmPutMsgsHit(requirements); X dmmClose(); X exit(1); X } X X dmmPutMsgsHit(introA); /* display a message until user hits X * a key */ X dmmPutMsgsHit(introB); X if (login() == 0) { /* if login goes okay, do rest of X * demo screens X */ X monthmenu(); X msgdemo(); X calcdate(); X getcomment(); X } X dmmPutMsgsTimer(byemsgblk, 2); X dmmClose(); /* shut down curses and DMM windows */ X exit(0); X} SHAR_EOF chmod 0444 dmmdemo1.c || echo "restore of dmmdemo1.c fails" set `wc -c dmmdemo1.c`;Sum=$1 if test "$Sum" != "4642" then echo original size 4642, current size $Sum;fi echo "x - extracting dmmdemo2.c (Text)" sed 's/^X//' << 'SHAR_EOF' > dmmdemo2.c && X#ifndef LINT Xstatic char dmmdemo_2_c_id[] = {"@(#)dmmdemo2.c 1.1 \ XCopyright (c) 1991 Robert Bernardo, rob@mtdiablo.Concord.CA.US, \ Xan employee of Pande, Inc. \ XPermission to use granted only if this notice is not removed from \ Xthis source file nor from any binaries produced from it."}; X#endif X#include X#include X#include "dmm.h" X X/* field sizes */ X#define USERNAMELEN 10 X#define PASSWDLEN 8 X#define YESNOLEN 1 X X/* editable buffers */ Xstatic char username[USERNAMELEN + 1], X giveup[YESNOLEN + 1], X passwd[PASSWDLEN + 1], X auditbuf[80]; X X/* instruction fields */ Xstatic char *usernameinstr[] = {"Enter your user name", 0}, X *giveupinstr[] = {"Enter y or n", 0}, X *passwdinstr[] = {"Enter your password", 0}; X X/* data fields */ X#define GIVEUPLINE 2 X#define LNSPACING 2 X#define LABELCOL 10 X#define USERNAMELINE (GIVEUPLINE + LNSPACING) X#define PASSWDLINE (USERNAMELINE + LNSPACING) X#define MSGLINE (PASSWDLINE + LNSPACING) Xextern DMMAUDITRETURN giveupaudit(), X auditUsername(), X auditPasswd(); X Xstatic DMMFIELD giveupfld = {"Give up logging in?", LABELCOL, X GIVEUPLINE, 0, giveup, "n", -2, GIVEUPLINE, X YESNOLEN, 0, 0, 0, A_REVERSE, A_UNDERLINE, X giveupinstr, 0, giveupaudit, 0}, X X usernamefld = {"User name", LABELCOL, X USERNAMELINE, 0, username, 0, -2, X USERNAMELINE, USERNAMELEN, 0, 0, 0, X A_REVERSE, A_UNDERLINE, usernameinstr, X 0, auditUsername, 0}, X X passwdfld = {"Password", LABELCOL, PASSWDLINE, 0, X passwd, 0, -2, PASSWDLINE, X PASSWDLEN, 0, 0, 0, A_REVERSE | A_INVIS, X A_UNDERLINE | A_INVIS, passwdinstr, 0, X auditPasswd, 0}; X X/* data field arrays */ Xstatic DMMSCREEN loginscreen1 = {&usernamefld, &passwdfld, 0}, X loginscreen2 = {&giveupfld, &usernamefld, &passwdfld, 0}; X X/* messages */ Xstatic DMMMESSAGE plswaitmsg = {"Please wait", 0, 0, A_REVERSE}, X auditmsg = {auditbuf, 0, -2, A_REVERSE}; X Xstatic DMMMESGBLK plswaitmsgblk = {&plswaitmsg, 0}, X auditmsgblk = {&auditmsg, 0}; X X XDMMAUDITRETURN Xgiveupaudit(value) Xchar *value; X{ X if (*value == 'y' || *value == 'Y') X return dmmAuditReturnOkay; X if (*value != 'n' && *value == 'N') X return dmmAuditBad; X return dmmAuditOkay; X} X XDMMAUDITRETURN XauditPasswd(value) Xchar *value; /* unused but required */ X{ X return dmmAuditReturnOkay; X} X XDMMAUDITRETURN XauditUsername(username) Xchar *username; X{ X extern int errno; X X if (!*username) X strcpy(auditbuf, "A user name must be specified"); X else X return dmmAuditOkay; X dmmPutMsgsNext(auditmsgblk); X return dmmAuditBad; X} X X/* return 0 if user logs in correctly, else -1 */ Xint Xlogin() X{ X X int retcode, X tries = 0; X DMMSCREEN2 screen; X X /* use the screen without give-up capabilities first time around */ X screen = loginscreen1; X while (1) { X X /* solicit login information */ X retcode = dmmRun(-1, screen, (DMMMENU2) 0, dmmNew, dmmInitVal); X if (retcode == -1) X return -1; X X /* check if user wants to give up */ X if (*giveup == 'y' || *giveup == 'Y') X return -1; X X /* process login information in dummy fashion */ X dmmPutMsgs(plswaitmsgblk); X sleep(2); X if (tries++) X return 0; X X /* use the screen with give-up capabilities on subsequent tries */ X screen = loginscreen2; X } X} SHAR_EOF chmod 0444 dmmdemo2.c || echo "restore of dmmdemo2.c fails" set `wc -c dmmdemo2.c`;Sum=$1 if test "$Sum" != "3637" then echo original size 3637, current size $Sum;fi echo "x - extracting dmmdemo3.c (Text)" sed 's/^X//' << 'SHAR_EOF' > dmmdemo3.c && X#ifndef LINT Xstatic char dmmdemo_3_c_id[] = {"@(#)dmmdemo3.c 1.1 \ XCopyright (c) 1991 Robert Bernardo, rob@mtdiablo.Concord.CA.US, \ Xan employee of Pande, Inc. \ XPermission to use granted only if this notice is not removed from \ Xthis source file nor from any binaries produced from it."}; X#endif X#include X#include "dmm.h" X#include "dmmdemo.h" X X/* messages */ Xstatic DMMMESSAGE month = {"January", 10, 2, A_REVERSE}, X days = {"S M T W T F S ", 5, 3, A_UNDERLINE}, X week1 = {" 1 2 3 4 5 6", 5, 4, 0}, X week2 = {"7 8 9 10 11 12 13", 5, 5, 0}, X week3 = {"14 15 16 17 18 19 20", 5, 6, 0}, X week4 = {"21 22 23 24 25 26 27", 5, 7, 0}, X week5 = {"28 29 30 31", 5, 8, 0}; X Xstatic DMMMESGBLK calendar = {&month, &days, &week1, &week2, X&week3, &week4, &week5, 0}; X X/* menu */ Xstatic DMMMENUITEM jan = {"January", "Display calendar for January"}, X feb = {"February", "Display calendar for February"}, X mar = {"March", "Display calendar for March"}, X apr = {"April", "Display calendar for April"}, X may = {"May", "Display calendar for May"}, X jun = {"June", "Display calendar for June"}, X jul = {"July", "Display calendar for July"}, X aug = {"August", "Display calendar for August"}, X sep = {"September", "Display calendar for September"}, X oct = {"October", "Display calendar for October"}, X nov = {"November", "Display calendar for November"}, X dec = {"December", "Display calendar for December"}; X Xstatic DMMMENU menu = {&jan, &feb, &mar, &apr, &may, &jun, X &jul, &aug, &sep, &oct, &nov, &dec, 0}; X X X/* data screen */ X/* Notice that on the following fields, since they have no input part, only the X * first three elements need be specified, letting the rest default to X * zero, a feature of their being static X */ Xstatic DMMFIELD msg1 = X{"Select any menu item; it doesn't matter which. A dummy calendar will be", X0, 1, 0}, X X msg2 = X{"displayed. The source for this screen is in dmmdemo3.c. Note the following:", X0, 2, 0}, X X msg3 = X{"1. The is a menu-only screen because the data fields have only", XNUMBERCOL, 3, 0}, X X msg4 = X{"label parts and no input parts.", XBODYCOL, 4, 0}, X X msg5 = X{"2. The menu is long enough to scroll. Notice that the end scrolls to the", XNUMBERCOL, 5, 0}, X X msg6 = X{"beginning and vice versa.", XBODYCOL, 6, 0}, X X msg7 = X{"3. The menu has some items with shared first letters and other items with", XNUMBERCOL, 7, 0}, X X msg8 = X{"unique first letters by which they are selectable.", XBODYCOL, 8, 0}, X X msg9 = X{"4. Messages lines can have a variety of attributes; see the calendar.", XNUMBERCOL, 9, 0}; X Xstatic DMMSCREEN msgscreen = {&msg1, &msg2, &msg3, &msg4, &msg5, X&msg6, &msg7, &msg8, &msg9, 0}; X X Xvoid Xmonthmenu() X{ X dmmRun(-1, msgscreen, menu, dmmNew, dmmInitVal); X /* normally we'd process the return code of dmmRun() and learn the month X * that was selected from the menu and then display the proper calendar. X * But this is just a demo and we'll display the same calendar no matter X * what month was chosen. */ X dmmClear(); /* remove data entry/display part of X * screen */ X dmmPutMsgsHit(calendar); /* display calendar */ X return; X} SHAR_EOF chmod 0444 dmmdemo3.c || echo "restore of dmmdemo3.c fails" set `wc -c dmmdemo3.c`;Sum=$1 if test "$Sum" != "3773" then echo original size 3773, current size $Sum;fi echo "x - extracting dmmdemo4.c (Text)" sed 's/^X//' << 'SHAR_EOF' > dmmdemo4.c && X#ifndef LINT Xstatic char dmmdemo_4_c_id[] = {"@(#)dmmdemo4.c 1.1 \ XCopyright (c) 1991 Robert Bernardo, rob@mtdiablo.Concord.CA.US, \ Xan employee of Pande, Inc. \ XPermission to use granted only if this notice is not removed from \ Xthis source file nor from any binaries produced from it."}; X#endif X#include "dmm.h" X X/* messages */ Xstatic DMMMESSAGE msgA1 = X{"The source for this next set of messages is in dmmdemo4.c. It demonstrates", X0, 0, 0}, X msgA2 = X{"various message display functions. This message is displayed with a call", X0, 1, 0}, X msgA3 = X{"to dmmPutMsgsHit(), and will go away upon your next keystroke. After that", X0, 2, 0}, X msgA4 = X{"a message will be displayed with dmmPutMsgsTimer for a few seconds. Then", X0, 3, 0}, X msgA5 = X{"three short messages will be displayed. The last will be removed with", X0, 4, 0}, X msgA6 = X{"a call to dmmRmMsgs(dmmRemoveLast), and then all messages will be removed", X0, 5, 0}, X msgA7 = X{"with a call to dmmRmMsgs(dmmRemoveAll).", X0, 6, 0}, X msgB1 = X{"This is the message displayed with dmmPutMsgsTimer() for a few seconds.", X0, 1, 0}, X msgC1 = X{"This is the first of three messages.", X0, 1, 0}, X msgD1 = X{"This is the second of three messages.", X0, 3, 0}, X msgE1 = X{"This is the last of three messages.", X0, 5, 0}, X msgE2 = X{"It will go away first, then all messages will be removed.", X0, 6, 0}; X Xstatic DMMMESGBLK msgblkA = {&msgA1, &msgA2, &msgA3, &msgA4, &msgA5, X &msgA6, &msgA7, 0}, X msgblkB = {&msgB1, 0}, X msgblkC = {&msgC1, 0}, X msgblkD = {&msgD1, 0}, X msgblkE = {&msgE1, &msgE2, 0}; X Xvoid Xmsgdemo() X{ X dmmPutMsgsHit(msgblkA); X dmmPutMsgsTimer(msgblkB, (unsigned)3); X dmmPutMsgs(msgblkC); X sleep(1); X dmmPutMsgs(msgblkD); X sleep(1); X dmmPutMsgs(msgblkE); X sleep(3); X dmmRmMsgs(dmmRemoveLast); X sleep(3); X dmmRmMsgs(dmmRemoveAll); X sleep(2); X return; X} SHAR_EOF chmod 0444 dmmdemo4.c || echo "restore of dmmdemo4.c fails" set `wc -c dmmdemo4.c`;Sum=$1 if test "$Sum" != "1886" then echo original size 1886, current size $Sum;fi echo "x - extracting dmmdemo5.c (Text)" sed 's/^X//' << 'SHAR_EOF' > dmmdemo5.c && X#ifndef LINT Xstatic char dmmdemo_5_c_id[] = {"@(#)dmmdemo5.c 1.1 \ XCopyright (c) 1991 Robert Bernardo, rob@mtdiablo.Concord.CA.US, \ Xan employee of Pande, Inc. \ XPermission to use granted only if this notice is not removed from \ Xthis source file nor from any binaries produced from it."}; X#endif X#include X#include X#include "dmm.h" X#include "dmmdemo.h" X X#define MONTHLEN 2 X#define DAYLEN 2 X#define YEARLEN 2 X#define MONTHCOL 10 X#define DAYCOL (MONTHCOL + MONTHLEN) X#define YEARCOL (DAYCOL + DAYLEN + 1) X#define DATELINE 10 X X/* messages */ Xstatic char dayofweek[80]; X Xstatic DMMMESSAGE msgA1 = X{"The source for the next screen (and these messages) is in dmmdemo5.c.", X0, 0, 0}, X msgA2 = X{"That screen shows a fairly prototypical logic in processing of various", X0, 1, 0}, X msgA3 = X{"return values and conditions. The screen solicits a date from the user", X0, 2, 0}, X msgA4 = X{"and the rest of the code simulates calculation of the day of the week of", X0, 3, 0}, X msgA5 = X{"the date.", X0, 4, 0}, X msgA6 = X{"Note the following:", X0, 6, 0}, X msgA7 = X{"1. Look at the overall logic of the function calcdate(). It is a", XNUMBERCOL, 7, 0}, X msgA8 = X{"forever loop with a single call to dmmRun(). Notice that some of", XBODYCOL, 8, 0}, X msgA9 = X{"various arguments to dmmRun(), namely startfield, drawflag and", XBODYCOL, 9, 0}, X msgA10 = X{"valflag, get set to different values on different iterations of", XBODYCOL, 10, 0}, X msgA11 = X{"the forever loop according to various conditions.", XBODYCOL, 11, 0}, X msgB1 = X{"2. dmmReview() is used to check the input field values after dmmRun()", XNUMBERCOL, 0, 0}, X msgB2 = X{"returns. This is needed because the default initial values of the", XBODYCOL, 1, 0}, X msgB3 = X{"input fields are not valid values. Notice how if dmmReview()", XBODYCOL, 2, 0}, X msgB4 = X{"indicates an invalid field value, startfield, drawflag and valflag", XBODYCOL, 3, 0}, X msgB5 = X{"are set to re-present the screen with the cursor in the offending", XBODYCOL, 4, 0}, X msgB6 = X{"field. If dmmReview() shows that all field values are valid, the", XBODYCOL, 5, 0}, X msgB7 = X{"day of the week is displayed as a message alongside the input fields,", XBODYCOL, 6, 0}, X msgB8 = X{"which are still on the screen, and then the screen is redisplayed", XBODYCOL, 7, 0}, X msgB9 = X{"afresh.", XBODYCOL, 8, 0}, X msgC1 = X{"3. The three input fields have audit functions that return", XNUMBERCOL, 0, 0}, X msgC2 = X{"dmmAuditReturnOkay so that dmmRun() returns for the surrounding", XBODYCOL, 1, 0}, X msgC3 = X{"code to perform an inter-field audit. (The inter-field audit is here", XBODYCOL, 2, 0}, X msgC4 = X{"only as an example. In a real program, it would be better not to have", XBODYCOL, 3, 0}, X msgC5 = X{"the audit functions return dmmAuditReturnOkay, and just perform an", XBODYCOL, 4, 0}, X msgC6 = X{"inter-field audit after dmmReview returns from verifying the validity", XBODYCOL, 5, 0}, X msgC7 = X{"of the fields separately.) Notice how startfield, drawflag and valflag", XBODYCOL, 6, 0}, X msgC8 = X{"are set if the inter-field audit fails and if it succeeds.", XBODYCOL, 7, 0}, X msgD1 = X{"4. A negative line number is used for the error messages to place the", XNUMBERCOL, 0, 0}, X msgD2 = X{"message a certain number of lines from the bottom. Notice that it is ", XBODYCOL, 1, 0}, X msgD3 = X{"placed so as not to conflict with the bottom lines used by the", XBODYCOL, 2, 0}, X msgD4 = X{"instruction messages.", XBODYCOL, 3, 0}, X errormsg = {0, 0, -3, A_REVERSE}, X dayofweekmsg = {dayofweek, YEARCOL + 4, DATELINE, 0}; X Xstatic DMMMESGBLK msgblkA = {&msgA1, &msgA2, &msgA3, &msgA4, &msgA5, X &msgA6, &msgA7, &msgA8, &msgA9, &msgA10, X &msgA11, 0}, X msgblkB = {&msgB1, &msgB2, &msgB3, &msgB4, &msgB5, X &msgB6, &msgB7, &msgB8, &msgB9, 0}, X msgblkC = {&msgC1, &msgC2, &msgC3, &msgC4, &msgC5, X &msgC6, &msgC7, &msgC8, 0}, X msgblkD = {&msgD1, &msgD2, &msgD3, &msgD4, 0}, X errormsgblk = {&errormsg, 0}, X dayofweekmsgblk = {&dayofweekmsg, 0}; X X/* menu */ Xstatic DMMMENUITEM calcitem = {"Calculate", "Calculate day of week"}, X quititem = {"Quit", "Quit this part of demo program"}; X Xstatic DMMMENU menu = {&calcitem, &quititem, 0}; X X/* fields and screen */ Xstatic char *monthinstruct[] = {"Enter month as two digits", X "An example of a multiline instruction", 0}, X *dayinstruct[] = X {"Enter day of months as two digits", 0}, X *yearinstruct[] = {"Enter year as two digits", 0}; X Xextern DMMAUDITRETURN monthaudit(), X dayaudit(), X yearaudit(); X Xstatic char monthbuf[MONTHLEN + 1], X daybuf[DAYLEN + 1], X yearbuf[YEARLEN + 1]; X Xstatic DMMFIELD month = {0, 0, 0, 0, monthbuf, 0, MONTHCOL, DATELINE, X MONTHLEN, 0, 0, 0, A_REVERSE, A_UNDERLINE, X monthinstruct, 0, monthaudit}, X X day = {"/", DAYCOL, DATELINE, 0, daybuf, 0, -1, X DATELINE, DAYLEN, 0, 0, 0, A_REVERSE, X A_UNDERLINE, dayinstruct, 0, dayaudit}, X X year = {"/", YEARCOL, DATELINE, 0, yearbuf, 0, -1, X DATELINE, YEARLEN, 0, 0, 0, A_REVERSE, X A_UNDERLINE, yearinstruct, 0, yearaudit}; X Xstatic DMMSCREEN screen = {&month, &day, &year, 0}; X Xstatic int daysinmonth[] = X {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; Xstatic char *daysofweek[] = {"Monday", "Tuesday", "Wednesday", X "Thursday", "Friday", "Saturday", "Sunday"}; X Xvoid Xcalcdate() X{ X int retcode, X startfield = -1, X dayint, X monthint, X yearint; X DMMDRAWFLAG drawflag = dmmNew; X DMMVALFLAG valflag = dmmInitVal; X X dmmPutMsgsHit(msgblkA); X dmmPutMsgsHit(msgblkB); X dmmPutMsgsHit(msgblkC); X dmmPutMsgsHit(msgblkD); X while (1) { X if((retcode = dmmRun(startfield, screen, menu, drawflag, valflag)) X == -1) X return; X dayint = atoi(daybuf); X monthint = atoi(monthbuf); X yearint = atoi(yearbuf); X if (dmmRetType == dmmMenu) { X X /* user selected a menu item; if it was 'quit', return, else user X * wants day of week calculated */ X if (retcode == 1) X /* user selected 'quit' menu item */ X return; X X /* audit input values before calculating day of week */ X if ((retcode = dmmReview(screen)) == -1) { X /* all individual values okay - display day of week */ X sprintf(dayofweek, "falls on a %s", X daysofweek[(dayint + monthint + yearint) % 7]); X dmmPutMsgsHit(dayofweekmsgblk); X X /* redisplay fresh screen */ X startfield = -1; X drawflag = dmmNew; X valflag = dmmInitVal; X } else { X /* bad input value -- go back to offending field of last X * screen for user to correct it */ X startfield = retcode; X drawflag = dmmOld; X valflag = dmmEdVal; X } X } else { X /* an audit function must have returned - do the interfield audit X * that fits the input the user gave so far */ X if ((*monthbuf && *daybuf) && X ((*yearbuf && !validdayofmonthandyear(dayint, monthint, yearint)) X || !validdayofmonth(dayint, monthint))) { X /* bad day of month */ X startfield = 1; /* index of day field */ X drawflag = dmmOld; X valflag = dmmEdVal; X } else { X /* continue with appropriate field */ X startfield = -1; X drawflag = dmmOld; X valflag = dmmEdVal; X } X } X } X} X Xvaliddayofmonthandyear(dayofmonth, month, year) Xint dayofmonth, /* presumed between 1 and 31 */ X month, /* presumed between 1 and 12 */ X year; /* presumed between 0 and 99 */ X{ X if ((dayofmonth > daysinmonth[month]) || X ((dayofmonth == 29) && (month == 2) && X (year % 4 != 0) || (year % 100 == 0))) { X errormsg.value = "Not that many days in that month"; X dmmPutMsgsNext(errormsgblk); X return 0; X } X return 1; X} X Xvaliddayofmonth(dayofmonth, month) Xint dayofmonth, /* presumed between 1 and 31 */ X month; /* presumed between 1 and 12 */ X{ X if (dayofmonth > daysinmonth[month]) { X errormsg.value = "Not that many days in that month"; X dmmPutMsgsNext(errormsgblk); X return 0; X } X return 1; X} X XDMMAUDITRETURN Xmonthaudit(month) Xchar *month; X{ X int monthint = atoi(month); X X /* check for valid month */ X if ((strlen(month) != MONTHLEN) || (monthint < 1) || (monthint > 12)) { X errormsg.value = "Month must be given as two digits, 01 through 12"; X dmmPutMsgsNext(errormsgblk); X return dmmAuditBad; X } X /* need to check month against day of month */ X return dmmAuditReturnOkay; X} X XDMMAUDITRETURN Xdayaudit(day) Xchar *day; X{ X int dayint = atoi(day); X X /* check for valid day of month */ X if ((strlen(day) != DAYLEN) || (dayint < 1) || (dayint > 31)) { X errormsg.value = "Day must be given as two digits, 01 through 31"; X dmmPutMsgsHit(errormsgblk); X return dmmAuditBad; X } X /* need to check day of month against month */ X return dmmAuditReturnOkay; X} X XDMMAUDITRETURN Xyearaudit(year) Xchar *year; X{ X /* check for valid year */ X if ((strlen(year) != YEARLEN) || (!isdigit(*year)) || (!isdigit(*(year + 1)))) { X errormsg.value = "Year must be given as two digits, 00 through 99"; X dmmPutMsgsNext(errormsgblk); X return dmmAuditBad; X } X return dmmAuditReturnOkay; X} SHAR_EOF chmod 0444 dmmdemo5.c || echo "restore of dmmdemo5.c fails" set `wc -c dmmdemo5.c`;Sum=$1 if test "$Sum" != "9605" then echo original size 9605, current size $Sum;fi echo "x - extracting dmmdemo6.c (Text)" sed 's/^X//' << 'SHAR_EOF' > dmmdemo6.c && X#ifndef LINT Xstatic char dmmdemo_6_c_id[] = {"@(#)dmmdemo6.c 1.1 \ XCopyright (c) 1991 Robert Bernardo, rob@mtdiablo.Concord.CA.US, \ Xan employee of Pande, Inc. \ XPermission to use granted only if this notice is not removed from \ Xthis source file nor from any binaries produced from it."}; X#endif X#include X#include "dmm.h" X#include "dmmdemo.h" X X/* messages */ Xstatic DMMMESSAGE infomsg1 = X{"The source for the next screen (and these messages) is in dmmdemo6.c.", X0, 0, 0}, X infomsg2 = X{"Note the following:", X0, 1, 0}, X infomsg3 = X{"1. The first screen has one input field that spans more than one line.", XNUMBERCOL, 2, 0}, X infomsg4 = X{"This is achieved by having the inputMaxcols datum in the", XBODYCOL, 3, 0}, X infomsg5 = X{"DMMFIELD structure be non-zero and less than the inputLength", XBODYCOL, 4, 0}, X infomsg6 = X{"datum. Play around with the arrow keys.", XBODYCOL, 5, 0}, X infomsg7 = X{"2. The second screen is like the first, except that a line number is", XNUMBERCOL, 6, 0}, X infomsg8 = X{"put out of range. Since the screen cannot be displayed as indicated", XBODYCOL, 7, 0}, X infomsg9 = X{"by the DMMSCREEN data, dmmRun() displays a diagnostic message and", XBODYCOL, 8, 0}, X infomsg10 = X{"returns -1. Notice how dmmGetNumLines() can be used to ascertain", XBODYCOL, 9, 0}, X infomsg11 = X{"the number of lines available in the data entry window.", XBODYCOL, 10, 0}, X infomsg12 = X{"This is the last part of the demonstration.", X0, 12, 0}; X Xstatic DMMMESGBLK infomsgblk = {&infomsg1, &infomsg2, &infomsg3, X &infomsg4, &infomsg5, &infomsg6, X &infomsg7, &infomsg8, &infomsg9, X &infomsg10, &infomsg11, &infomsg12, 0}; X X/* menu */ Xstatic DMMMENUITEM mailit = {"Mail", "Mail comment to administrator"}, X dontmailit = {"Quit", "Quit this part of demo program"}; X Xstatic DMMMENU menu = {&mailit, &dontmailit, 0}; X X/* fields and screen */ Xstatic char *commentinstruct[] = {"Enter comment for administrator", X 0}; X X#define COMMENTSIZE 700 Xstatic char commentbuf[COMMENTSIZE + 1]; X Xstatic DMMFIELD comment = {"Comment", 10, 0, 0, commentbuf, 0, 10, 2, X COMMENTSIZE, 60, 0, 0, A_REVERSE, A_REVERSE, X commentinstruct, 0, 0}; X Xstatic DMMSCREEN screen = {&comment, 0}; X Xvoid Xgetcomment() X{ X int numlines; X X dmmPutMsgsHit(infomsgblk); X dmmRun(-1, screen, menu, dmmNew, dmmInitVal); X numlines = dmmGetNumLines(); X comment.labelLine = numlines; X dmmRun(-1, screen, menu, dmmNew, dmmInitVal); X return; X} SHAR_EOF chmod 0444 dmmdemo6.c || echo "restore of dmmdemo6.c fails" set `wc -c dmmdemo6.c`;Sum=$1 if test "$Sum" != "2582" then echo original size 2582, current size $Sum;fi rm -f s2_seq_.tmp echo "You have unpacked the last part" exit 0 -- Rob Bernardo Mt. Diablo Software Solutions email: rob@mtdiablo.Concord.CA.US phone: (415) 827-4301