home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 3 / 3510 < prev    next >
Encoding:
Internet Message Format  |  1991-06-20  |  59.2 KB

  1. From: rob@mtdiablo.Concord.CA.US (Rob Bernardo)
  2. Newsgroups: alt.sources
  3. Subject: DMM (Data entry and Menu screen Manager) - version 1.1 part 1/2
  4. Message-ID: <1991Jun18.012151.10052@mtdiablo.Concord.CA.US>
  5. Date: 18 Jun 91 01:21:51 GMT
  6.  
  7.  
  8. From the README file:
  9.  
  10. DMM is a set of C library functions that provide a fairly object-oriented
  11. front end to curses for the management of data entry and menu screens.
  12. It requires the System V version of curses.
  13.  
  14. The sources for these functions are in dmm.c and dmm.h.  A make file is
  15. provided.  The make file and sources compile as is under SUN 0S 4.03, 4.1
  16. and 4.1.1.  They may need minor modifications for compilation on other
  17. flavors of UNIX.
  18.  
  19. A section 3 manual page is included; it details the use of the functions
  20. as well as the look and feel of the screens they produce.
  21.  
  22. A demo program is included and can be compiled using the make file.
  23. Using DMM effectively can be complex and the demo program demonstrates
  24. various DMM facilities and points out highlights of the demo sources.
  25.  
  26. #!/bin/sh
  27. # shar:    Shell Archiver  (v1.22)
  28. #
  29. # This is part 1 of a multipart archive                                    
  30. # do not concatenate these parts, unpack them in order with /bin/sh        
  31. #
  32. #    Run the following text with /bin/sh to create:
  33. #      Makefile
  34. #      README
  35. #      dmm.3
  36. #      dmm.c
  37. #      dmm.h
  38. #      dmmdemo.h
  39. #      dmmdemo1.c
  40. #      dmmdemo2.c
  41. #      dmmdemo3.c
  42. #      dmmdemo4.c
  43. #      dmmdemo5.c
  44. #      dmmdemo6.c
  45. #
  46. if test -r s2_seq_.tmp
  47. then echo "Must unpack archives in sequence!"
  48.      next=`cat s2_seq_.tmp`; echo "Please unpack part $next next"
  49.      exit 1; fi
  50. echo "x - extracting Makefile (Text)"
  51. sed 's/^X//' << 'SHAR_EOF' > Makefile &&
  52. X# @(#)Makefile    1.1 Copyright (c) 1991 Robert Bernardo, rob@mtdiablo.Concord.CA.US,
  53. X# an employee of Pande, Inc.  Permission to use granted only if this
  54. X# notice is not removed from this make file produced from it.
  55. X
  56. XCC = /usr/5bin/cc
  57. X
  58. X
  59. XDEMOOBJS =  dmmdemo1.o dmmdemo2.o dmmdemo3.o dmmdemo4.o dmmdemo5.o dmmdemo6.o
  60. Xdmmdemo: $(DEMOOBJS) dmm.o
  61. X    $(CC) $(DEMOOBJS) dmm.o -lcurses -o dmmdemo
  62. X
  63. Xdmm:    dmm.o
  64. X
  65. Xclean:
  66. X    rm -f *.o dmmdemo core
  67. X
  68. Xlint:
  69. X    lint -I/usr/5include *.c
  70. SHAR_EOF
  71. chmod 0444 Makefile || echo "restore of Makefile fails"
  72. set `wc -c Makefile`;Sum=$1
  73. if test "$Sum" != "462"
  74. then echo original size 462, current size $Sum;fi
  75. echo "x - extracting README (Text)"
  76. sed 's/^X//' << 'SHAR_EOF' > README &&
  77. XThis is the 1.1 version of DMM.  It is a beta version.  Bugs, fixes,
  78. Xcomments and suggestions should be sent to Robert Bernardo, at
  79. Xrob@mtdiablo.Concord.CA.US.
  80. X
  81. XDMM is a set of C library functions that provide a fairly object-oriented
  82. Xfront end to curses for the management of data entry and menu screens.
  83. XIt requires the System V version of curses.
  84. X
  85. XThe sources for these functions are in dmm.c and dmm.h.  A make file is
  86. Xprovided.  The make file and sources compile as is under SUN 0S 4.03, 4.1
  87. Xand 4.1.1.  They may need minor modifications for compilation on other
  88. Xflavors of UNIX.
  89. X
  90. XA section 3 manual page is included; it details the use of the functions
  91. Xas well as the look and feel of the screens they produce.
  92. X
  93. XA demo program is included and can be compiled using the make file.
  94. XUsing DMM effectively can be complex and the demo program demonstrates
  95. Xvarious DMM facilities and points out highlights of the demo sources.
  96. X
  97. X@(#)README    1.1 Copyright (c) 1991 Robert Bernardo,
  98. Xrob@mtdiablo.Concord.CA.US, an employee of Pande, Inc.  Permission to
  99. Xuse DMM granted only if the copyright notice is not removed from any of
  100. Xthe component files nor from any binaries produced from them.
  101. SHAR_EOF
  102. chmod 0444 README || echo "restore of README fails"
  103. set `wc -c README`;Sum=$1
  104. if test "$Sum" != "1183"
  105. then echo original size 1183, current size $Sum;fi
  106. echo "x - extracting dmm.3 (Text)"
  107. sed 's/^X//' << 'SHAR_EOF' > dmm.3 &&
  108. X.\ @(#)dmm.3    1.1
  109. X.TH DMM 3 6/13/91
  110. X.SH NAME
  111. XdmmRun, dmmReview, dmmInit, dmmClose, dmmPutMsgs, dmmPutMsgsTimer, dmmPutMsgsHit, dmmPutMsgsNext, dmmClear, dmmRmMsgs, dmmGetNumLines - manage data entry and menu screens
  112. X.SH SYNOPSIS
  113. X.nf
  114. X.B #include <dmm.h>
  115. X.PP
  116. X.B extern DMMRETTYPE dmmRetType;
  117. X.PP
  118. X.B int dmmRun(startField, screen, menu, drawFlag, valFlag)
  119. X.B int startField;
  120. X.B DMMSCREEN screen;
  121. X.B DMMMENU menu;
  122. X.B DMMDRAWFLAG drawFlag;
  123. X.B DMMVALFLAG valFlag;
  124. X.PP
  125. X.B int dmmReview(screen)
  126. X.B DMMSCREEN screen;
  127. X.PP
  128. X.B void dmmInit()
  129. X.PP
  130. X.B void dmmClose()
  131. X.PP
  132. X.B void dmmPutMsgs(mesgblock)
  133. X.B DMMMESGBLK mesgblock;
  134. X.PP
  135. X.B void dmmPutMsgsTimer(mesgblock, duration)
  136. X.B DMMMESGBLK mesgblock;
  137. X.B unsigned duration;
  138. X.PP
  139. X.B void dmmPutMsgsHit(mesgblock)
  140. X.B DMMMESGBLK mesgblock;
  141. X.PP
  142. X.B void dmmPutMsgsNext(mesgblock)
  143. X.B DMMMESGBLK mesgblock;
  144. X.PP
  145. X.B void dmmClear()
  146. X.PP
  147. X.B void dmmRmMsgs(removetype)
  148. X.B DMMREMOVETYPE removetype;
  149. X.PP
  150. X.B int dmmGetNumLines()
  151. X.fi
  152. X.SH DESCRIPTION
  153. X.IR "Data entry and Menu Manager" ", " DMM ,
  154. Xis a set of functions that
  155. Xprovide a fairly object-oriented interface to
  156. X.I curses
  157. Xand enforce a particular look and feel in managing data entry and 
  158. Xmenu screens.
  159. XThe next two subsections describe this look and feel; subsequent subsections
  160. Xdescribe the use of the functions.
  161. X.SS Screen appearance
  162. X.PP
  163. XThe screen consists of three
  164. X.I curses
  165. Xwindows.
  166. X.PP
  167. XThe top line is an instruction window that displays a general user instruction
  168. Xthat varies with the state that the screen is in.
  169. X.PP
  170. XThe next two lines are used by the menu.
  171. XThe menu is presented as a ring menu.
  172. XA scrollable list of typically one-word menu items is 
  173. Xdisplayed horizontally on the first of the two lines.
  174. XWhen the menu is active, one menu item is considered current and is highlighted.
  175. XThe second line of the menu window is used to display a longer description
  176. Xof the current menu item.
  177. XThrough input keystrokes, the user can make a particular menu item current,
  178. Xand then with a particular keystroke can confirm the
  179. Xcurrently selected menu item as the choice made.
  180. X.PP
  181. XThe rest of the screen is the data entry window. Visually, this window appears
  182. Xto consist of two sorts of items: editable fields and static, non-editable 
  183. Xphrases (used for headings and for labels of the editable fields).
  184. XTypically the two are displayed with different attributes (e.g. editable
  185. Xfields displayed highlighted and the static fields displayed plain).
  186. XWhen the data entry window is active, one editable field is considered
  187. Xcurrent, and the cursor is placed inside it.
  188. XTypically the current editable field is displayed with a different
  189. Xhighlighting attribute from the other editable fields.
  190. XThe user can edit the current field, or move to another field,
  191. Xmaking it current.
  192. XWhen the user enters a keystroke to move to another field, the value of
  193. Xthe then-current field may be audited and,
  194. Xif found in error, an error message displayed and the cursor
  195. Xis moved to its first character position;
  196. Xotherwise the cursor is moved to first character position of that other field,
  197. Xwhich is made current.
  198. X.PP
  199. XWhile the screen is interactive,
  200. Xeither the menu or the data entry window will be active.
  201. XThrough a particular keystroke, the user can switch between these two states.
  202. XTypically, a screen consists of both a menu and a data entry window (though
  203. Xonly one of the two are required) and starts with the data entry window
  204. Xactive and a program-specified field current.
  205. XThe user may enter data in the editable fields and then go to the menu
  206. Xto select an action to happen, such as to go forward with the data as entered,
  207. Xor perhaps to ignore the data and just pop back up to a higher menu.
  208. X.PP
  209. XIn either menu or data entry state, the user can enter a keystroke that
  210. Xdisplays help information.
  211. X.SS User input
  212. X.PP
  213. XThe following user input keystrokes have similar effects 
  214. Xin both menu and data entry states:
  215. X.PD 0
  216. X.TP 20
  217. Xcontrol-g
  218. XToggles between the menu and data entry states.
  219. X.TP 20
  220. Xcontrol-h
  221. XDisplays a screen giving this keystroke-effect information.
  222. X.TP 20
  223. Xcontrol-r
  224. XRedraws the entire screen.
  225. X.TP 20
  226. Xtab, control-n
  227. XMakes the next editable field or menu item current.
  228. X.TP 20
  229. Xcontrol-p
  230. XMakes the preceding editable field or menu item current.
  231. X.PD
  232. X.PP
  233. XThe following user input keystrokes are particular to the menu state:
  234. X.PD 0
  235. X.TP 20
  236. Xcarriage return
  237. XChoses the current menu item.
  238. X.TP 20
  239. Xalpha character
  240. XMakes current the single menu item that begins with the alpha character.
  241. XIf there is not exactly one such menu item, the screen is flashed.
  242. X.PD
  243. X.PP
  244. XThe following user input keystrokes are particular to the data entry state:
  245. X.PD 0
  246. X.TP 20
  247. Xcontrol-c
  248. XClears current editable field from current position to end of field and makes
  249. Xthe next editable field current.
  250. X.TP 20
  251. Xcarriage return
  252. XMakes the the next editable field current.
  253. X.TP 20
  254. Xarrow key
  255. XMoves the cursor in the indicated direction within the current editable field
  256. Xif possible.
  257. X.TP 20
  258. Xdelete
  259. XErases the character to the left of the cursor, i.e. 
  260. Xreplaces it with a blank and moves the cursor left,
  261. Xif not in the first character position in the current editable field.
  262. XIf it is in the last character position, and the last character is not blank,
  263. Xit erases the character under the cursor and leaves the cursor there.
  264. X.TP 20
  265. Xprinting character
  266. XInserts the character in the current editable field at the cursor position
  267. X(and advances the cursor within the field
  268. Xif not at the last character position of the field)
  269. X.PD
  270. X.PP
  271. XAny other keystroke will flash the screen.
  272. X.SS Screen specification
  273. X.PP
  274. XAn invocation of the function
  275. X.B dmmRun
  276. Xmanages the display and operation of a screen
  277. Xand engages the user in interaction with the screen.
  278. X.PP
  279. XThe layout of the data entry window is specified by
  280. X.IR screen ,
  281. Xa null terminated array of pointers to DMMFIELD structures, defined in
  282. X.IR dmm.h .
  283. X.PP
  284. XEach DMMFIELD describes one data entry field. Its elements describe
  285. Xtwo parts of the data entry field. The label elements describe the
  286. Xconstant part of the field, which may be used for display of headings,
  287. Xdata or a label for the editable part. The input elements describe the editable
  288. Xpart, a field on the screen where the user can move the cursor and input data.
  289. XThe editable part of a field is realized as a (nearly) rectangular area within
  290. Xthe window.
  291. X.TP 20
  292. XlabelValue
  293. XA non-editable string to be displayed.
  294. XA NULL value indicates no string to display.
  295. X.TP 20
  296. X.PD 0
  297. XlabelCol,
  298. X.TP 20
  299. X.PD
  300. XlabelLine
  301. XThe coordinates in the data entry window where the first character of
  302. X.I labelValue
  303. Xis displayed.
  304. XA negative line number represents lines from the bottom
  305. Xof the window, the bottom line represented with -1.
  306. X.TP 20
  307. XlabelAttrib
  308. XThe attributes with which the label is displayed, given as the logical
  309. X.IR or -ing
  310. Xof the attribute constants given in <curses.h>, or  0L for no attributes.
  311. X.TP 20
  312. XinputLength
  313. XThe number of data characters to accept from the user for editable part of
  314. Xthe field.
  315. XThis governs the total size of the rectangular input area.
  316. XIf 0,
  317. Xthe field is considered to have no editable part;
  318. Xthis is useful for the presentation of display-only data on the screen,
  319. Xe.g. headings.
  320. X.TP 20
  321. XinputEditValue
  322. XA buffer of length 
  323. X.I inputLength
  324. X+ 1 (for the terminating null) used to store the data as entered or 
  325. Xedited by the user.
  326. X.TP
  327. XinputInitValue
  328. XA string with an initial value to be copied to inputEditValue before user
  329. Xinteraction.
  330. X(This is dependent on the value of 
  331. X.I valFlag
  332. X- see below.)
  333. XThe string must no be longer than
  334. X.I inputLength.
  335. XA NULL value is treated the same as a zero-length string.
  336. X.TP 20
  337. X.PD 0
  338. XinputCol,
  339. X.TP 20
  340. X.PD
  341. XinputLine
  342. XThe coordinates in the data entry window where the upper left corner
  343. Xof the input area is displayed.
  344. XA negative column value designates a column position that
  345. Xis that many intervening columns to the right of the last character of
  346. X.IR labelValue .
  347. XA negative line number represents lines from the bottom
  348. Xof the window, the bottom line represented with -1.
  349. X.TP 20
  350. XinputMaxCols
  351. XThe width of the rectangular input area. If smaller than
  352. X.I inputLength
  353. Xthe rectangular area will be more than one line in height.
  354. XIf 0,
  355. Xthe width is taken from
  356. X.IR inputLength ,
  357. Xi.e. the rectangular area will be exactly one line.
  358. X.TP
  359. X.PD 0
  360. XinputFullLines,
  361. X.TP 20
  362. X.PD
  363. XinputShortCols
  364. XTo be left unset by the calling function and calculated by
  365. X.BR dmmRun .
  366. XThey represent the number of lines of full width in the rectangular area
  367. Xand the number of columns in the last ``remainder'' line of the rectangular
  368. Xarea, respectively.
  369. XActually, because of the ``remainder'' line, the rectangular area is not
  370. Xalways an exact rectangle.
  371. X.TP 20
  372. XinputAttrib
  373. XThe attributes with which the rectangular area is displayed when 
  374. Xthe field is not current.
  375. XSee
  376. X.I labelAttrib
  377. Xfor a description of possible values.
  378. X.TP 20
  379. XinputEditAttrib
  380. XThe attributes with which the rectangular area is displayed when the field
  381. Xis current.
  382. XSee
  383. X.I labelAttrib
  384. Xfor a description of possible values.
  385. XThe value A_INVIS can be used for such things as password fields.
  386. XDespite the warning in <curses.h> that this value is not supported,
  387. Xit is safe to use because its realization within
  388. X.I DMM
  389. Xis independent of that of
  390. X.IR curses .
  391. X.TP 20
  392. XinputInstructVec
  393. XA null terminated array of string pointers which should contain detailed
  394. Xinstructions to the user on how to edit the field.
  395. XThey are displayed, when the field is current,
  396. Xat the bottom of the screen, one string per line.
  397. XA NULL value indicates no instructions to display.
  398. X.TP
  399. XinputNumInstructs
  400. XTo be left unset by the calling function and calculated by
  401. X.B dmmRun
  402. Xas the number of strings in
  403. X.IR inputInstructVec .
  404. X.TP 20
  405. XinputAudit
  406. XA pointer to a function that returns an
  407. X.IR int .
  408. XIt is invoked with 
  409. X.I inputEditValue
  410. Xas its single argument
  411. Xwhen the user enters a keystroke that would make the field non-current.
  412. XThis function is useful for auditing the value of
  413. X.I inputEditValue
  414. Xand displaying audit error messages to the user (using the message display
  415. Xfunctions described below).
  416. XIf NULL, it is not invoked.
  417. XThe function must accept a single 
  418. X.I char *
  419. Xargument and must return one of the following DMMAUDITRETURN values, defined in 
  420. X.IR dmm.h :
  421. X.RS 20
  422. X.TP 20
  423. XdmmAuditOkay
  424. XWhen returned the cursor is advanced to the appropriate editable field.
  425. XUseful when the value of 
  426. X.I inputEditValue
  427. Xis okay.
  428. X.TP 20
  429. XdmmAuditBad
  430. XWhen returned the cursor is moved to the first position of the current input
  431. Xfield.
  432. XUseful when the value of 
  433. X.I inputEditValue
  434. Xis needs correction by the user.
  435. X.TP 20
  436. X.PD 0
  437. XdmmAuditReturnOkay,
  438. X.TP 20
  439. X.PD 
  440. XdmmAuditReturnBad
  441. XUseful when an inter-field audit needs to be performed.
  442. XThese two values cause
  443. X.B dmmRun
  444. Xto return with
  445. X.B dmmRetType
  446. Xset to
  447. X.I dmmOkayField
  448. Xor
  449. X.IR dmmBadField ,
  450. Xrespectively, and the return value of
  451. X.B dmmRun
  452. Xset to the number of the current editable field.
  453. XThe calling function can then do its inter-field audit, such as might be 
  454. Xnecessary when the two fields are month-of-year and day-of-month, where
  455. Xlegal values are interdependent and then reinvoke
  456. X.BR dmmRun .
  457. XSee the discussion of
  458. X.I startField
  459. Xbelow for further details on reinvocations of
  460. X.B dmmRun
  461. Xafter an inter-field audit.
  462. X.RE
  463. X.TP 20
  464. X.PD 0
  465. XnextInField,
  466. X.TP 20
  467. X.PD
  468. XprevInField
  469. XTo be left unset by the calling function and calculated by
  470. X.BR dmmRun .
  471. X.PP
  472. XSome user keystrokes cause the next or preceding editable field to 
  473. Xbecome current.
  474. XThe order of editable fields is taken from the order of the DMMFIELD
  475. Xstructures in
  476. X.IR screen ;
  477. Xthis list is considered circular,
  478. Xe.g. the editable field that comes next after the
  479. Xlast editable field is the first editable field in the
  480. X.I screen
  481. Xarray.
  482. X.PP
  483. XIf there are no fields to display, i.e. if this is a menu-only screen,
  484. X.I screen
  485. Xshould be NULL.
  486. X.PP
  487. XThe menu window is specified by
  488. X.IR menu ,
  489. Xa null terminated array of pointers to DMMENUITEM structures, defined in
  490. X.IR dmm.h .
  491. X.PP
  492. XEach DMMMENUITEM describes one menu item, the elements of which are as follows:
  493. X.TP 20
  494. Xlabel
  495. XA short string to be displayed in the menu item list.
  496. X.TP 20
  497. Xdescript
  498. XA longer, more explanatory string that is displayed on the
  499. Xsecond line of the menu window when
  500. Xthe menu item is current.
  501. X.TP 20
  502. X.PD 0
  503. Xcol,
  504. X.TP 20
  505. X.PD
  506. Xpage
  507. XTo be left unset by the calling function and calculated by
  508. X.BR dmmRun .
  509. X.PP
  510. XIf there is to be no menu for the screen,
  511. X.I menu
  512. Xshould be NULL.
  513. X.PP
  514. XThe value of
  515. X.I drawFlag
  516. Xdetermines whether internal window drawing and calculations need to
  517. Xtake place.
  518. XPermissible values are:
  519. X.TP 20
  520. XdmmNew
  521. XUsed when a screen is displayed for the first time
  522. Xor when a screen is redisplayed after intervening call to
  523. X.B dmmRun
  524. Xhas displayed another screen.
  525. X.TP 20
  526. XdmmOld
  527. XUsed when 
  528. X.B dmmRun
  529. Xis to display the same screen as when it was last called.
  530. XNothing about the 
  531. X.I screen
  532. Xor
  533. X.I menu
  534. Xstructures nor the values that they point to may have been changed
  535. Xsince the last call because the screen in this case is repainted
  536. Xby a simple
  537. X.I wrefresh
  538. Xwith no internal window redrawing or recalculations.
  539. X.PP
  540. XThe value of
  541. X.I valFlag
  542. Xdetermines the initial values of the editable fields. 
  543. XPermissible values are:
  544. X.TP 20
  545. XdmmInitVal
  546. Xcauses the value of
  547. X.I inputInitValue
  548. Xto be copied to
  549. X.I inputEditValue
  550. Xbefore the screen is displayed and user interaction begun.
  551. XThis is useful when a certain screen is to be displayed more than oncer
  552. Xper execution of the program and some of those times it should
  553. Xstart off with certain default values instead of with the edited values.
  554. XThe default value of each field should be placed in the
  555. X.I inputInitVal
  556. Xparameter for the field.
  557. X.TP 20
  558. XdmmEdVal
  559. Xcauses no such copying.
  560. XThe values displayed are those that are already in the
  561. X.I inputEditValue
  562. Xparameters for each field.
  563. X.PP
  564. XThe value of
  565. X.I startField
  566. Xdetermines which field is made current when user interaction is begun;
  567. Xit must be the index in
  568. X.I screen
  569. Xof a DMMFIELD that is editable, i.e. one that has a non-zero
  570. X.IR inputLength .
  571. XThe special value of -1 has a significance according to the value of
  572. X.IR drawFlag .
  573. XIf 
  574. X.I drawFlag
  575. Xis
  576. X.IR dmmNew ,
  577. Xthe starting editable field will be the 
  578. Xfirst editable field (not necessarily the first field) in
  579. X.IR screen .
  580. XIf 
  581. X.I drawFlag is
  582. X.IR dmmOld ,
  583. Xthe starting editable field depends upon the state of affairs when
  584. Xlast invocation of
  585. X.B dmmRun
  586. Xreturned.
  587. XIf it returned due to a menu selection
  588. Xthe starting editable field will be the last current field.
  589. XIf it returned because an
  590. X.I inputAudit
  591. Xfunction returned
  592. X.I dmmAuditReturnOkay 
  593. Xor
  594. X.IR dmmAuditReturnBad ,
  595. Xthe starting editable field will be either the next or preceding editable
  596. Xfield (depending upon whether the user keystroke that invoked the audit
  597. Xwas for moving to the next or preceding field).
  598. XAs described above, this is useful after an inter-field edit has taken place
  599. Xfor a seamless appearance to the separate invocations of
  600. X.BR dmmRun .
  601. XIf the inter-field audit showed valid editable field values, it is useful
  602. Xto reinvoke
  603. X.B dmmRun
  604. Xwith an
  605. X.I drawFlag
  606. Xvalue of 
  607. X.I dmmOld
  608. Xand a
  609. X.I startField
  610. Xvalue of -1.
  611. XIf the inter-field audit indicates that an editable field value needs
  612. Xcorrection by the user,
  613. Xan error message should be displayed and
  614. X.B dmmRun
  615. Xshould be reinvoked with an
  616. X.I drawFlag
  617. Xvalue of
  618. X.I dmmOld
  619. Xand
  620. X.I startField
  621. Xset to the index of the offending field.
  622. X.PP
  623. X.B dmmRun
  624. Xreturns typically when a user choses a menu item (i.e. enters a carriage
  625. Xreturn while in the menu state), but also when an
  626. X.I inputAudit
  627. Xfunction returns
  628. X.I dmmAuditReturnOKay
  629. Xor
  630. X.IR dmmAuditReturnBad .
  631. XIn the former case,
  632. X.B dmmRun
  633. Xreturns the index of the menu item chosen, and sets
  634. X.B dmmRetType
  635. Xto
  636. X.IR dmmMenu .
  637. XIn the latter cases, it returns the index of the associated editable field;
  638. X.B dmmRetType
  639. Xis set to
  640. X.I dmmOkayField
  641. Xor
  642. X.I dmmBadField
  643. Xdepending upon whether the audit function returned
  644. X.I dmmAuditReturnOKay
  645. Xor
  646. X.IR dmmAuditReturnBad ,
  647. Xrespectively.
  648. XA menuless screen must therefore have an
  649. X.I inputAudit
  650. Xfunction that unconditionally returns either
  651. X.I dmmAuditReturnOkay
  652. Xor
  653. X.IR dmmAuditReturnBad ;
  654. Xotherwise there will be nothing the user can input that will cause
  655. X.B dmmRun
  656. Xto return!
  657. X.SS Terminal initialization and cleanup
  658. X.PP
  659. XThe function
  660. X.B dmmRun
  661. Xprovides normal 
  662. X.I curses
  663. Xinitialization (e.g. puts the terminal in raw mode) and creates the various
  664. Xwindows needed for its work.
  665. XWhen all 
  666. X.I curses
  667. Xinteraction is finished in the program, whether through
  668. X.I DMM
  669. Xfunctions
  670. Xor though other functions, the program should invoke
  671. X.B dmmClose
  672. Xto clean up and return the terminal to its previous state.
  673. XThe function
  674. X.B dmmInit
  675. Xprovides the same initialization functionality as
  676. X.B dmmRun
  677. Xwithout the presentation of a screen.
  678. XThis is useful when the program needs to do
  679. X.I curses
  680. Xwork (such as display of data on the screen using any of the message
  681. Xdisplay function described below) prior to the first call of
  682. X.BR dmmRun .
  683. XIf initialization has already been done,
  684. X.B dmmRun
  685. Xwill not do it again (unless, of course, there has been an intervening
  686. Xinvocation of
  687. X.BR dmmClose ).
  688. X.SS Non-interactive display of data
  689. X.PP
  690. XData, such as error messages, may be displayed in the data entry window
  691. Xwithout the user-interaction of a screen.
  692. XThis is useful not only between invocations of
  693. X.B dmmRun 
  694. X(or
  695. X.B dmmInit
  696. Xand
  697. X.BR dmmRun ),
  698. Xbut also within the
  699. X.I inputAudit
  700. Xfunctions to display messages to the user when the user needs to correct
  701. Xan editable field.
  702. X.B dmmPutMsgs
  703. Xis the simplest of the message display functions; it adds a block of
  704. Xmessages to the existing data entry window and leaves them there.
  705. X.I mesgblock
  706. Xis a null-terminated array of DMMMESSAGE structures, defined in
  707. X.IR dmm.h .
  708. XEach DMMMESSAGE describes one message string,
  709. Xthe elements of which are as follows:
  710. X.TP 20
  711. Xvalue
  712. XThe string to be displayed.
  713. X.TP 20
  714. X.PD 0
  715. Xcol,
  716. X.TP 20
  717. X.PD
  718. Xline
  719. XThe coordinates in the data entry window where the first character of
  720. X.I value
  721. Xis displayed.
  722. XA negative value for
  723. X.I line
  724. Xrepresents lines from the bottom
  725. Xof the window, the bottom line represented with -1.
  726. X.TP 20
  727. Xattrib
  728. XThe attributes with which 
  729. X.I value
  730. Xis displayed.
  731. XSee
  732. X.IR labelAttrib ,
  733. Xabove, for a description of possible values.
  734. X.PP
  735. XMessages are cleared from the window with the next invocation of
  736. X.B dmmRun
  737. Xor with an invocation of
  738. X.BR dmmRmMsgs .
  739. XIf
  740. X.I removetype
  741. Xis
  742. X.IR dmmRemoveAll ,
  743. Xall message displayed since the last invocation of
  744. X.B dmmRun
  745. Xor 
  746. X.B dmmInit
  747. Xare removed from the window.
  748. XIf
  749. X.I removetype
  750. Xis
  751. X.IR dmmRemoveLast
  752. Xonly the messages displayed with the last invocation of
  753. X.B dmmPutMsgs
  754. Xare removed.
  755. X.PP
  756. X.B dmmPutMsgsTimer
  757. Xdisplays the messages described by
  758. X.IR mesgblock ,
  759. Xsleeps for
  760. X.I duration
  761. Xseconds, removes them and returns.
  762. X.PP
  763. X.B dmmPutMsgsHit
  764. Xdisplays the messages described by
  765. X.IR mesgblock ,
  766. Xdisplays an instruction in the instruction window for the user to press
  767. Xany key to continue, and when the user enters a keystroke, the messages
  768. Xare removed and the function returns.
  769. X.PP
  770. X.B dmmPutMsgsNext
  771. Xdisplays the messages described by
  772. X.I mesgblock
  773. Xand removes them upon the next user keystroke entered under an invocation of 
  774. X.B dmmRun
  775. X(unless removed first by a call to
  776. X.IR dmmRmMsgs ).
  777. XThe keystroke is interpreted by
  778. X.B dmmRun
  779. Xas it would normally rather than discard it as it is under an invocation of
  780. X.BR dmmPutMsgsHit .
  781. X.PP
  782. X.B dmmClear
  783. Xclears everything from the data entry window,
  784. Xall messages and any display from the last call of
  785. X.BR dmmRun .
  786. XThis is useful prior to using
  787. X.RI non- DMM
  788. Xfunctions for screen manipulation and after a call to 
  789. X.B dmmRun
  790. Xwhen you don't want the data entry portion of the screen displayed any longer.
  791. X.PP
  792. X.B dmmGetNumLines
  793. Xreturns the number of lines in the data entry window.
  794. XThis is useful, for example, when displaying tabular data as a set of messages,
  795. Xand one needs to know how many lines of the table can be displayed in a single
  796. Xscreenful.
  797. X.SS Non-interactive auditing of editable field values
  798. XAs mentioned above, a field's input value is audited under
  799. X.B dmmRun
  800. Xonly when the user input a keystroke that would change the field from current
  801. Xto non-current.
  802. XConsequently, fields that the user doesn't traverse go unaudited under
  803. X.BR dmmRun ,
  804. Xa problem with fields whose initial input value (see discussion
  805. Xof
  806. X.I valFlag
  807. Xabove) is not a valid value;
  808. X(this is often the case,
  809. Xe.g. when there is no default value to give for a field's
  810. X.I initVal
  811. Xbut a value for the field is required nontheless.)
  812. XThe solution is to call
  813. X.BR dmmReview ,
  814. Xwhich invokes the
  815. X.I inputAudit
  816. Xfunction of each editable field and 
  817. Xreturning the index of the first editable field whose
  818. X.I inputAudit
  819. Xreturns either
  820. X.I dmmAuditBad
  821. Xor
  822. X.I dmmAuditReturnBad
  823. Xand by setting 
  824. X.B dmmRetType
  825. Xto
  826. X.IR dmmBadField .
  827. XIf no editable fields have invalid values, it returns -1 and sets
  828. X.B dmmRetType
  829. Xto
  830. X.IR dmmOkayField .
  831. XTherefore, if a screen has initial editable field values that are not valid,
  832. Xit is recommended that the call to 
  833. X.B dmmRun
  834. Xthat presents the screen be followed by a call to
  835. X.B dmmReview
  836. X(given an appropriate return value of
  837. X.BR dmmRun ).
  838. X.SS Data structures as function arguments
  839. X.I dmm.h
  840. X.I typedefs 
  841. Xa number of data structures for use with these functions:
  842. X.PD 0
  843. X.PP
  844. X.nf
  845. X    typedef struct dmmField DMMFIELD, *DMMSCREEN[], **DMMSCREEN2;
  846. X    typedef struct dmmMenuItem DMMMENUITEM, *DMMMENU[], **DMMMENU2;
  847. X    typedef struct dmmMessage DMMMESSAGE, *DMMMESGBLK[], **DMMMESGBLK2;
  848. X.fi
  849. X.PP
  850. XThe first of each triplet are the basic structures used, and the second
  851. Xare the array-of-pointers data types used above as arguments to the 
  852. X.I DMM
  853. Xfunctions.
  854. XHowever, sometimes it is useful (and syntactically equivalent in some contextss)
  855. Xto use a pointer pointer instead of an array of pointers for the argument of
  856. Xthe called function, as are the third of each triplet.
  857. XAn example of a situation in which the pointer pointers are
  858. Xuseful is as follows:
  859. X.PD
  860. X.PP
  861. X.nf
  862. X    int        startField = -1;
  863. X    DMMDRAWFLAG    drawFlag = dmmNew;
  864. X    DMMVALFLAG    valFlag = dmmInitVal;
  865. X        /* initialization of the DMMSCREENs and DMMMENUs
  866. X         * omitted in this example for brevity
  867. X         */
  868. X    DMMSCREEN    normal_screen, root_screen;
  869. X    DMMSCREEN2    screen_to_use;
  870. X    DMMMENU    normal_menu, root_menu;
  871. X    DMMMENU2    menu_to_use;
  872. X    ...
  873. X    if(getuid() == 0) {
  874. X    ...
  875. X    screen_to_use = root_screen;
  876. X    menu_to_use = root_menu;
  877. X    ...
  878. X    } else {
  879. X    ...
  880. X    screen_to_use = normal_screen;
  881. X    menu_to_use = normal_menu;
  882. X    ...
  883. X    }
  884. X    ...
  885. X    dmmRun(startField, screen_to_use, menu_to_use, drawFlag, valFlag);
  886. X.fi
  887. X.SH EXAMPLE
  888. X.PP
  889. XThe sources for a demo program that illustrates good use of
  890. X.I DMM
  891. Xare included with the
  892. X.I DMM
  893. Xsources.
  894. XNotice how the declaration of the various
  895. X.I DMM
  896. Xdata structures as static variables enables easy initialization.
  897. X.SH DIAGNOSTICS
  898. X.PP
  899. X.B dmmRun
  900. Xreturns -1 if the screen is faulty,
  901. X(e.g. a label or input portion of a field or a menu item
  902. Xdoes not fit on the screen,
  903. Xeach menu item label does not begin with a unique alphabetic character,
  904. X.I startField
  905. Xis not the index of an editable field,
  906. Xthere is no menu and the data entry portion has no editable fields,
  907. Xetc.), and
  908. Xa diagnostic message is displayed on the screen.
  909. XNon-error return values for
  910. X.B dmmRun
  911. Xand
  912. X.B dmmReview
  913. Xare described above.
  914. X.SH SEE ALSO
  915. X.PP
  916. X.IR curses (3V)
  917. X.SH AUTHOR
  918. X.PP
  919. XCopyright \(co 1991, Robert Bernardo, rob@mtdiablo.Concord.CA.US,
  920. Xan employee of Pande, Inc.
  921. XPermission to use granted only if this 
  922. Xnotice is not removed from this manual page.
  923. SHAR_EOF
  924. chmod 0444 dmm.3 || echo "restore of dmm.3 fails"
  925. set `wc -c dmm.3`;Sum=$1
  926. if test "$Sum" != "23153"
  927. then echo original size 23153, current size $Sum;fi
  928. echo "x - extracting dmm.c (Text)"
  929. sed 's/^X//' << 'SHAR_EOF' > dmm.c &&
  930. X#ifndef LINT
  931. Xstatic char     dmm_c_id[] = {"@(#)dmm.c    1.1 \
  932. XCopyright (c) 1991 Robert Bernardo, rob@mtdiablo.Concord.CA.US, \
  933. Xan employee of Pande, Inc. \
  934. XPermission to use granted only if this notice is not removed from \
  935. Xthis source file nor from any binaries produced from it."};
  936. X#endif
  937. X
  938. X#include <ctype.h>
  939. X#include <curses.h>
  940. X#include <string.h>
  941. X#include <signal.h>
  942. X#include <term.h>
  943. X#include <sys/ttychars.h>
  944. X#include "dmm.h"
  945. X
  946. X/* see man page for description */
  947. XDMMRETTYPE      dmmRetType;
  948. X
  949. X/* enum for type of cursor change */
  950. Xenum change {
  951. X    previous, stayput, movecursor, next
  952. X};
  953. X
  954. X/* error message data structures */
  955. Xstatic char             errorMsgBuf[BUFSIZ];
  956. Xstatic DMMMESSAGE         errorMsg = {errorMsgBuf, 0, 0, A_REVERSE};
  957. Xstatic DMMMESGBLK         errorMsgBlk = {&errorMsg, 0};
  958. X
  959. X#define CNVRT_LN_NUM(lnnum)    (lnnum < 0 ? LFLINE+lnnum+1 : lnnum)
  960. X#define DISP_ERROR_0(mesg)    {strcpy(errorMsg.value,mesg);    \
  961. X                dmmPutMsgsHit(errorMsgBlk);}
  962. X#define DISP_ERROR_1(fmt,arg)    {sprintf(errorMsg.value,fmt,arg);    \
  963. X                dmmPutMsgsHit(errorMsgBlk);}
  964. X#define DISP_ERROR_2(fmt,a,b)    {sprintf(errorMsg.value,fmt,a,b);    \
  965. X                dmmPutMsgsHit(errorMsgBlk);}
  966. X#define DISP_ERROR_3(fmt,a,b,c) {sprintf(errorMsg.value,fmt,a,b,c); \
  967. X                  dmmPutMsgsHit(errorMsgBlk);}
  968. X
  969. X/* special command input character symbols */
  970. X#define TAB    '\t'
  971. X#define RETURN    '\r'
  972. X#define DELETE    CERASE
  973. X
  974. X/* menu scroll symbols */
  975. X#define LEFT_SCROLL_SYMBOL    "<<"
  976. X#define RIGHT_SCROLL_SYMBOL    ">>"
  977. X
  978. X/* parameters of the windows */
  979. X/*     - number of lines in each window */
  980. X#define MLINES    2        /* menu window */
  981. X#define ILINES    1        /* instruct window */
  982. X#define FLINES    (LINES - MLINES - ILINES)    /* field window */
  983. X
  984. X/*    - menu line functions */
  985. X#define MENU_LABEL_LINE        0
  986. X#define MENU_DESCRIPT_LINE    1
  987. X
  988. X/*     - line number of first line of windows */
  989. X
  990. X#define FILINE    0        /* instruct window */
  991. X#define FMLINE    (FILINE + ILINES)    /* menu window */
  992. X#define FFLINE    (FMLINE + MLINES)    /* field window */
  993. X
  994. X/*     - line number of last line of windows in window (not in screen) */
  995. X#define LFLINE    (FLINES - 1)    /* field window */
  996. X
  997. X#define MENUI_SPACING 2        /* number of spaces between */
  998. X
  999. X/* string constants */
  1000. X/*     - general instruction messages */
  1001. X#define MENU_INSTRUCT        "Cursor to desired item and enter RETURN. Press control-h for help."
  1002. X#define GOTO_MENU_INSTRUCT    "Press control-g to enter menu. Press control-h for help."
  1003. X#define NULL_MENU_INSTRUCT    "Press control-h for help."
  1004. X#define ANY_KEY_INSTRUCT    "Press any key to continue."
  1005. X
  1006. X/*     - diagnostic error messages */
  1007. X#define BAD_FIELDNUM    "Program error! Target field %d beyond max %d.\n"
  1008. X#define NO_INPUT_MSG    "Program error! No input fields nor menu items.\n"
  1009. X#define NOT_IFIELD    "Program error! Target field %d not an input field.\n"
  1010. X#define WIDE_LABEL    "Program error! Menu label %d too wide for screen.\n"
  1011. X#define NON_ALPHA    "Program error! Menu item %d doesn't begin with an alphabetic character."
  1012. X#define LABEL_NO_FIT    "Program error! Label for field %d won't fit on screen.\n"
  1013. X#define IP_NO_FIT    "Program error! Input part of field %d won't fit on screen.\n"
  1014. X
  1015. X#define DMMWATTRSET(win, attrib)    wattrset(win, attrib&~A_INVIS)
  1016. X#define DMMWATTRON(win, attrib)    wattron(win, attrib&~A_INVIS)
  1017. X#define DMMWATTROFF(win, attrib)    wattroff(win, attrib&~A_INVIS)
  1018. X
  1019. X
  1020. X/* global variables */
  1021. X/* general information discoverd about a screen */
  1022. Xstatic int      numFields,    /* number of fields */
  1023. X                numInputParts,    /* number of fields with input parts */
  1024. X                numMenuItems,    /* number of menu items */
  1025. X                numMenuPages,    /* number of menu pages */
  1026. X                curMenuItem,    /* current menu item */
  1027. X                firstInputFld;    /* first field with input part */
  1028. X/* flags needed to manage the removal of messages displayed with
  1029. X * dmmPutMsgsNext() when not called under a call to dmmRun(), e.g. not
  1030. X * under an inputAudit function.
  1031. X */
  1032. Xstatic int      interactive,    /* set when dmm is interactive */
  1033. X                wantNextClear,    /* set when next keystroke should clear
  1034. X                 * messages from screen */
  1035. X                needAddMsgs;    /* set when need to add messages from a
  1036. X                 * dmmPutMsgsNext() called when dmm was not
  1037. X                 * interactive */
  1038. XPMNmsgsWereLast;        /* set when the last messages added were
  1039. X                 * added by dmmPutMsgsNext(). This is needed
  1040. X                 * because if dmmRmMsgs() is called to remove
  1041. X                 * just the last messages, the need to clear
  1042. X                 * the dmmPutMsgsNext() is removed and need
  1043. X                 * not be done on the next user keystroke
  1044. X                 * under dmmRun(). */
  1045. X
  1046. X/* global variables for parameters so they don't have to be passed all over */
  1047. Xstatic DMMSCREEN2 dupeScreen;    /* field vector */
  1048. Xstatic DMMMENU2 dupeMenu;    /* menu vector */
  1049. X/* windows */
  1050. Xstatic WINDOW  *fieldWin,    /* field window */
  1051. X               *fieldWinCopy,    /* saved window between dmmRun() calls */
  1052. X               *fieldWinPreMsg,    /* saved window before messages */
  1053. X               *mesgWin,    /* overlay window of messages */
  1054. X               *instructWin,    /* general instruction window */
  1055. X               *instructWinCopy,/* copy of instruction window */
  1056. X               *menuWin,    /* menu window */
  1057. X               *menuWinCopy;    /* copy menu window */
  1058. X/* miscellaneous */
  1059. Xstatic int      isOpen;        /* 0 if dmmInit needs to be performed */
  1060. X
  1061. Xstatic int      menuIndex[(int) ('z' - 'a' + 1)];    /* index by letter into
  1062. X                             * menu by initial
  1063. X                             * letters of menu
  1064. X                             * labels. */
  1065. X/* structures for help screens */
  1066. X#define KEY_COLUMN    5
  1067. X#define    EFFECT_COLUMN    22
  1068. X#define    INTRO_LINE    0
  1069. X#define    HELP_LINE    (INTRO_LINE + 2)
  1070. X#define    REDRAW_LINE    (HELP_LINE + 1)
  1071. X#define NEXT_LINE    (REDRAW_LINE + 1)
  1072. X#define PREV_LINE    (NEXT_LINE + 1)
  1073. X#define RETURNS_LINE    (PREV_LINE + 1)
  1074. X#define RETURNM_LINE    (RETURNS_LINE + 1)
  1075. X#define DELETE_LINE    (RETURNM_LINE + 1)
  1076. X#define ARROW_LINE    (DELETE_LINE + 1)
  1077. X#define CLEAR_LINE    (ARROW_LINE + 1)
  1078. X#define GOTO_LINE    (CLEAR_LINE + 1)
  1079. X#define NORMALS_LINE    (GOTO_LINE + 1)
  1080. X#define NORMALM_LINE    (NORMALS_LINE + 1)
  1081. X
  1082. Xstatic DMMMESSAGE introHelpKey =
  1083. X{"Key", KEY_COLUMN, INTRO_LINE, A_REVERSE};
  1084. Xstatic DMMMESSAGE helpHelpKey =
  1085. X{"control-h", KEY_COLUMN, HELP_LINE};
  1086. Xstatic DMMMESSAGE redrawHelpKey =
  1087. X{"control-r", KEY_COLUMN, REDRAW_LINE};
  1088. Xstatic DMMMESSAGE nextHelpKey =
  1089. X{"control-n/tab", KEY_COLUMN, NEXT_LINE};
  1090. Xstatic DMMMESSAGE prevHelpKey = {"control-p", KEY_COLUMN, PREV_LINE};
  1091. Xstatic DMMMESSAGE returnHelpKey = {"return", KEY_COLUMN, RETURNS_LINE};
  1092. Xstatic DMMMESSAGE deleteHelpKey = {"delete", KEY_COLUMN, DELETE_LINE};
  1093. Xstatic DMMMESSAGE arrowHelpKey = {"arrow key", KEY_COLUMN, ARROW_LINE};
  1094. Xstatic DMMMESSAGE clearHelpKey = {"control-c", KEY_COLUMN, CLEAR_LINE};
  1095. Xstatic DMMMESSAGE gotoHelpKey = {"control-g", KEY_COLUMN, GOTO_LINE};
  1096. Xstatic DMMMESSAGE normalHelpKey =
  1097. X{"`normal' keys", KEY_COLUMN, NORMALS_LINE};
  1098. X
  1099. Xstatic DMMMESSAGE introEffectKey =
  1100. X{"Effect", EFFECT_COLUMN, INTRO_LINE, A_REVERSE};
  1101. Xstatic DMMMESSAGE helpEffectKey =
  1102. X{"display help (this screen)", EFFECT_COLUMN, HELP_LINE};
  1103. Xstatic DMMMESSAGE redrawEffectKey =
  1104. X{"redraw screen", EFFECT_COLUMN, REDRAW_LINE};
  1105. Xstatic DMMMESSAGE nextEffectKey =
  1106. X{"go to next data field or menu item", EFFECT_COLUMN, NEXT_LINE};
  1107. Xstatic DMMMESSAGE prevEffectKey =
  1108. X{"go to previous data field or menu item", EFFECT_COLUMN, PREV_LINE};
  1109. Xstatic DMMMESSAGE returnScreenEffectKey =
  1110. X{"if in data entry, go to next data field or,", EFFECT_COLUMN, RETURNS_LINE};
  1111. Xstatic DMMMESSAGE returnMenuEffectKey =
  1112. X{"if in menu, accept menu choice", EFFECT_COLUMN, RETURNM_LINE};
  1113. Xstatic DMMMESSAGE deleteEffectKey =
  1114. X{"erase preceding character in current data field", EFFECT_COLUMN, DELETE_LINE};
  1115. Xstatic DMMMESSAGE arrowEffectKey =
  1116. X{"move within current data field", EFFECT_COLUMN, ARROW_LINE};
  1117. Xstatic DMMMESSAGE clearEffectKey =
  1118. X{"clear to end of current data field and go to next",
  1119. XEFFECT_COLUMN, CLEAR_LINE};
  1120. Xstatic DMMMESSAGE gotoEffectKey =
  1121. X{"move from data entry to menu or vice versa", EFFECT_COLUMN, GOTO_LINE};
  1122. Xstatic DMMMESSAGE normalScreenEffectKey =
  1123. X{"if in data entry, input letter into data field or,",
  1124. XEFFECT_COLUMN, NORMALS_LINE};
  1125. Xstatic DMMMESSAGE normalMenuEffectKey =
  1126. X{"if in menu, highlight menu item with same first letter",
  1127. XEFFECT_COLUMN, NORMALM_LINE};
  1128. X
  1129. Xstatic DMMMESGBLK helpMsgVec =
  1130. X{&introHelpKey, &helpHelpKey, &redrawHelpKey, &nextHelpKey,
  1131. X    &prevHelpKey, &returnHelpKey, &deleteHelpKey, &arrowHelpKey, &clearHelpKey,
  1132. X    &gotoHelpKey, &normalHelpKey, &introEffectKey,
  1133. X    &helpEffectKey, &redrawEffectKey, &nextEffectKey, &prevEffectKey,
  1134. X    &returnScreenEffectKey, &deleteEffectKey, &returnMenuEffectKey,
  1135. X    &arrowEffectKey, &clearEffectKey, &gotoEffectKey, &normalScreenEffectKey,
  1136. X&normalMenuEffectKey, 0};
  1137. X/* dmmInit()    put the terminal in the right mode and set up curses with
  1138. X *        the right windows.
  1139. X */
  1140. Xvoid
  1141. XdmmInit ()
  1142. X{
  1143. X    initscr ();
  1144. X    raw ();
  1145. X    nonl ();
  1146. X    noecho ();
  1147. X
  1148. X    /* get terminal in right mode */
  1149. X    putp (init_1string);
  1150. X    putp (init_2string);
  1151. X    putp (init_3string);
  1152. X    putp (cursor_visible);    /* blinking cursor */
  1153. X
  1154. X    /* create windows */
  1155. X    fieldWin = newwin (FLINES, COLS, FFLINE, 0);
  1156. X    fieldWinCopy = newwin (FLINES, COLS, FFLINE, 0);
  1157. X    fieldWinPreMsg = newwin (FLINES, COLS, FFLINE, 0);
  1158. X    mesgWin = newwin (FLINES, COLS, FFLINE, 0);
  1159. X    instructWin = newwin (ILINES, COLS, FILINE, 0);
  1160. X    instructWinCopy = newwin (ILINES, COLS, FILINE, 0);
  1161. X    menuWin = newwin (MLINES, COLS, FMLINE, 0);
  1162. X    menuWinCopy = newwin (MLINES, COLS, FMLINE, 0);
  1163. X
  1164. X    /* leave cursor where code says to */
  1165. X    leaveok (instructWin, FALSE);
  1166. X    leaveok (fieldWin, FALSE);
  1167. X    leaveok (menuWin, FALSE);
  1168. X
  1169. X    /* treat escape sequences as single characters */
  1170. X    keypad (fieldWin, TRUE);
  1171. X    keypad (menuWin, TRUE);
  1172. X
  1173. X    /* set attributes of windows fixed at a single attribute */
  1174. X    DMMWATTRSET (instructWin, A_REVERSE);
  1175. X
  1176. X    isOpen = 1;
  1177. X
  1178. X    return;
  1179. X}
  1180. X
  1181. X
  1182. X/* redraw()    unconditionally redraw the entirety of each window.
  1183. X */
  1184. Xstatic void
  1185. Xredraw ()
  1186. X{
  1187. X    clearok (fieldWin, TRUE);
  1188. X    clearok (instructWin, TRUE);
  1189. X    clearok (menuWin, TRUE);
  1190. X    wnoutrefresh (fieldWin);
  1191. X    wnoutrefresh (instructWin);
  1192. X    wnoutrefresh (menuWin);
  1193. X    doupdate ();
  1194. X    return;
  1195. X}
  1196. X
  1197. X
  1198. X/* dmmClose()    cleanup dmm and close down curses */
  1199. Xvoid
  1200. XdmmClose ()
  1201. X{
  1202. X    delwin (fieldWin);
  1203. X    delwin (fieldWinCopy);
  1204. X    delwin (fieldWinPreMsg);
  1205. X    delwin (mesgWin);
  1206. X    delwin (instructWin);
  1207. X    delwin (instructWinCopy);
  1208. X    delwin (menuWin);
  1209. X    delwin (menuWinCopy);
  1210. X    isOpen = 0;
  1211. X    clear ();
  1212. X    refresh ();
  1213. X    endwin ();
  1214. X    putp (cursor_normal);
  1215. X    return;
  1216. X}
  1217. X
  1218. X
  1219. X/* dmmGetNumLines    return the number of lines in fieldWin */
  1220. Xint
  1221. XdmmGetNumLines ()
  1222. X{
  1223. X    return FLINES;
  1224. X}
  1225. X
  1226. X/* outOfTheWay        put the cursor in a place where it's not distracting */
  1227. Xvoid
  1228. XoutOfTheWay()
  1229. X{
  1230. X    wmove (instructWin, 0, COLS - 1);
  1231. X    wnoutrefresh (instructWin);
  1232. X    return;
  1233. X}
  1234. X
  1235. X
  1236. X/* dmmRmMsgs()    remove messages displayed */
  1237. Xvoid
  1238. XdmmRmMsgs (removeType)
  1239. XDMMREMOVETYPE   removeType;
  1240. X{
  1241. X    /*
  1242. X     * remove residue of dmmPutMsgsNext type of messages as appropriate to
  1243. X     * whether they were last or wether we are clearing all messages not just
  1244. X     * the last messages
  1245. X     */
  1246. X    if ((removeType == dmmRemoveAll) || (PMNmsgsWereLast)) {
  1247. X    wclear (mesgWin);
  1248. X    needAddMsgs = 0;
  1249. X    wantNextClear = 0;
  1250. X    }
  1251. X    /* remove proper "layer" of messages */
  1252. X    overwrite ((removeType == dmmRemoveAll ? fieldWinCopy : fieldWinPreMsg),
  1253. X           fieldWin);
  1254. X    wnoutrefresh (fieldWin);
  1255. X    outOfTheWay();
  1256. X    doupdate();
  1257. X    return;
  1258. X}
  1259. X
  1260. X
  1261. X/* wGetCh()        like wgetch(), but clears any messages displayed by
  1262. X *            dmmPutMesgsNext()
  1263. X */
  1264. Xstatic int
  1265. XwGetCh (win)
  1266. XWINDOW         *win;
  1267. X{
  1268. X    int             keystroke;
  1269. X    /* get keystroke */
  1270. X    keystroke = wgetch (win);
  1271. X
  1272. X    /* if need to clear messages, do so */
  1273. X    if (wantNextClear) {
  1274. X    dmmRmMsgs (dmmRemoveLast);
  1275. X    wantNextClear = 0;
  1276. X    }
  1277. X    /* if mesgWin was used, clear it so stale messages don't get reused */
  1278. X    if (needAddMsgs) {
  1279. X    werase (mesgWin);
  1280. X    needAddMsgs = 0;
  1281. X    }
  1282. X    return keystroke;
  1283. X}
  1284. X
  1285. X
  1286. X/* addMsgs()    add messages to the indicated window */
  1287. Xstatic void
  1288. XaddMsgs (win, mesgBlock)
  1289. XWINDOW         *win;
  1290. XDMMMESGBLK      mesgBlock;
  1291. X{
  1292. X    /* display each item in the message array */
  1293. X    while (*mesgBlock) {
  1294. X    DMMWATTRON (win, (*mesgBlock)->attrib);
  1295. X    mvwaddstr (win, CNVRT_LN_NUM ((*mesgBlock)->line),
  1296. X           (*mesgBlock)->col, (*mesgBlock)->value);
  1297. X    DMMWATTROFF (win, (*mesgBlock)->attrib);
  1298. X    mesgBlock++;
  1299. X    }
  1300. X    wnoutrefresh (win);
  1301. X    return;
  1302. X}
  1303. X
  1304. X
  1305. X/* doPutMsgs()    see comments for dmmPutMsgs, if save is set, write
  1306. X *             messages as well to mesgWin
  1307. X */
  1308. Xstatic void
  1309. XdoPutMsgs (mesgBlock, save)
  1310. XDMMMESGBLK      mesgBlock;
  1311. Xint             save;
  1312. X{
  1313. X
  1314. X    /* save copy of window as it currently is */
  1315. X    overwrite (fieldWin, fieldWinPreMsg);
  1316. X
  1317. X    /* display messages on fieldWin, and on mesgWin as needed */
  1318. X    addMsgs (fieldWin, mesgBlock);
  1319. X    if (save)
  1320. X    addMsgs (mesgWin, mesgBlock);
  1321. X    PMNmsgsWereLast = 0;    /* may be set by outer call to
  1322. X                 * dmmPutMsgsNext() */
  1323. X    outOfTheWay();
  1324. X    doupdate ();
  1325. X}
  1326. X
  1327. X
  1328. X/* dmmPutMsgsNext()    remove messages displayed  until a key is input
  1329. X *             under dmmRun or until explicitly removed
  1330. X */
  1331. Xvoid
  1332. XdmmPutMsgsNext (mesgBlock)
  1333. XDMMMESGBLK      mesgBlock;
  1334. X{
  1335. X    wantNextClear = mesgBlock ? 1 : 0;
  1336. X    if (!interactive)
  1337. X    needAddMsgs = 1;
  1338. X    doPutMsgs (mesgBlock, needAddMsgs);
  1339. X    PMNmsgsWereLast = 1;
  1340. X    return;
  1341. X}
  1342. X
  1343. X
  1344. X/* dmmPutMsgs()        display messages */
  1345. Xvoid
  1346. XdmmPutMsgs (mesgBlock)
  1347. XDMMMESGBLK      mesgBlock;
  1348. X{
  1349. X    doPutMsgs (mesgBlock, 0);
  1350. X    return;
  1351. X}
  1352. X
  1353. X/* dmmClear()        clear everything irretrievably from fieldWin */
  1354. Xvoid
  1355. XdmmClear()
  1356. X{
  1357. X    wclear(mesgWin);
  1358. X    wnoutrefresh(mesgWin);
  1359. X    wclear(fieldWin);
  1360. X    wnoutrefresh(fieldWin);
  1361. X    wclear(fieldWinCopy);
  1362. X    wnoutrefresh(fieldWinCopy);
  1363. X    outOfTheWay();
  1364. X    doupdate();
  1365. X    return;
  1366. X}
  1367. X
  1368. X
  1369. X/* dmmPutMsgsTimer()        display messages for a certain number of secs */
  1370. Xvoid
  1371. XdmmPutMsgsTimer (mesgBlock, duration)
  1372. XDMMMESGBLK      mesgBlock;
  1373. Xunsigned        duration;
  1374. X{
  1375. X    /* display messages */
  1376. X    dmmPutMsgs (mesgBlock);
  1377. X
  1378. X    /* sleep and then redisplay the original window without the messages */
  1379. X    (void) sleep (duration);
  1380. X    dmmRmMsgs (dmmRemoveLast);
  1381. X
  1382. X    return;
  1383. X}
  1384. X
  1385. X
  1386. X/* dispInstruct()    display a message in the general instruction window */
  1387. Xstatic void
  1388. XdispInstruct (msg)
  1389. Xchar           *msg;
  1390. X{
  1391. X    mvwaddstr (instructWin, 0, 0, msg);
  1392. X    wclrtoeol (instructWin);
  1393. X    wnoutrefresh (instructWin);
  1394. X    return;
  1395. X}
  1396. X
  1397. X
  1398. X/* doPutMsgsHit()    display the messages indicated by mesgBlock
  1399. X *            until the user enters a keystroke
  1400. X */
  1401. Xvoid static
  1402. XdoPutMsgsHit (mesgBlock, restoreThem)
  1403. XDMMMESGBLK      mesgBlock;
  1404. Xint             restoreThem;
  1405. X{
  1406. X    register int     x;
  1407. X    overwrite (instructWin, instructWinCopy);
  1408. X    if (restoreThem) {
  1409. X    overwrite (fieldWin, fieldWinCopy);
  1410. X    overwrite (menuWin, menuWinCopy);
  1411. X    wclear (fieldWin);
  1412. X    wclear (menuWin);
  1413. X    wnoutrefresh (menuWin);
  1414. X    }
  1415. X    dispInstruct (ANY_KEY_INSTRUCT);
  1416. X    flushinp ();
  1417. X    dmmPutMsgs (mesgBlock);
  1418. X    wgetch (fieldWin);
  1419. X    flushinp ();
  1420. X    if (restoreThem) {
  1421. X    overwrite (fieldWinCopy, fieldWin);
  1422. X    overwrite (menuWinCopy, menuWin);
  1423. X    wnoutrefresh (fieldWin);
  1424. X    wnoutrefresh (menuWin);
  1425. X    } else
  1426. X    dmmRmMsgs (dmmRemoveLast);
  1427. X    overwrite (instructWinCopy, instructWin);
  1428. X
  1429. X    /* That last overwrite makes the whole window inverse video including
  1430. X     * trailing blanks, not just the message part, so we have to clear
  1431. X     * the trailing spaces while in normal attributes.
  1432. X     */
  1433. X    DMMWATTROFF (instructWin, A_REVERSE);
  1434. X    x = instructWin->_maxx;
  1435. X    while(x--) {
  1436. X    if((mvwinch(instructWin, 0, x) & A_CHARTEXT) != ' ') {
  1437. X        x++;
  1438. X        break;
  1439. X    }
  1440. X    }
  1441. X    wmove(instructWin, 0, x);
  1442. X    wclrtoeol(instructWin);
  1443. X    DMMWATTRON (instructWin, A_REVERSE);
  1444. X    wnoutrefresh (instructWin);
  1445. X    doupdate ();
  1446. X    return;
  1447. X}
  1448. X
  1449. X
  1450. X/* dmmPutMsgsHit()    display a message until the user presses any key */
  1451. Xvoid
  1452. XdmmPutMsgsHit (mesgBlock)
  1453. XDMMMESGBLK      mesgBlock;
  1454. X{
  1455. X    doPutMsgsHit (mesgBlock, 0);
  1456. X    return;
  1457. X}
  1458. X
  1459. X
  1460. X/* dispInField()    display the input part of the specified field
  1461. X *            with the specified attributes.
  1462. X */
  1463. Xstatic void
  1464. XdispInField (fldPtr, attrib)
  1465. Xregister DMMFIELD *fldPtr;
  1466. Xlong            attrib;
  1467. X{
  1468. X    register int    charNum;    /* counter of characters output */
  1469. X    int             doNulls,    /* set if characters run out */
  1470. X                    len;    /* length of field */
  1471. X    if (fldPtr->inputLength) {
  1472. X    DMMWATTRON (fieldWin, attrib);
  1473. X    charNum = 0;
  1474. X    doNulls = (attrib & A_INVIS) ? 1 : 0;
  1475. X    for (charNum = 0, len = fldPtr->inputLength; charNum < len; charNum++) {
  1476. X        if (fldPtr->inputEditValue[charNum] == '\0')
  1477. X        doNulls = 1;    /* we got to end of string, from here to end
  1478. X                 * output blanks */
  1479. X        mvwaddch (fieldWin,
  1480. X              fldPtr->inputLine + (charNum / fldPtr->inputMaxCols),
  1481. X              fldPtr->inputCol + (charNum % fldPtr->inputMaxCols),
  1482. X              doNulls ? ' ' : fldPtr->inputEditValue[charNum]);
  1483. X    }
  1484. X    DMMWATTROFF (fieldWin, attrib);
  1485. X    }
  1486. X    return;
  1487. X}
  1488. X
  1489. X
  1490. X/* calcDflts()    calculate line and column numbers for the label
  1491. X *         and input part of data fields; a negative line
  1492. X *        number represents lines from the window bottom,
  1493. X *        with -1 being the bottom; a negative column for
  1494. X *        the input part of the field indicates the number
  1495. X *        of columns separating it and the end of the label part;
  1496. X *        calculate the number of full length lines and
  1497. X *        the length of the last line (if not full length)
  1498. X *        of the input part.
  1499. X */
  1500. Xstatic void
  1501. XcalcDflts (fldPtr)
  1502. Xregister DMMFIELD *fldPtr;
  1503. X{
  1504. X
  1505. X    /* calculate line numbers */
  1506. X    fldPtr->labelLine = CNVRT_LN_NUM (fldPtr->labelLine);
  1507. X    fldPtr->inputLine = CNVRT_LN_NUM (fldPtr->inputLine);
  1508. X
  1509. X    /* calculate input part column number */
  1510. X    if (fldPtr->inputCol < 0)
  1511. X    fldPtr->inputCol = fldPtr->labelCol
  1512. X        + strlen (fldPtr->labelValue) - fldPtr->inputCol - 1;
  1513. X
  1514. X    /* calculate dimensions of lines of input part from length; if
  1515. X     * inputMaxCols is 0, field will be one line of inputLength chars
  1516. X     */
  1517. X    if (fldPtr->inputMaxCols) {
  1518. X    fldPtr->inputFullLines = fldPtr->inputLength / fldPtr->inputMaxCols;
  1519. X    fldPtr->inputShortCols = fldPtr->inputLength % fldPtr->inputMaxCols;
  1520. X    } else {
  1521. X    fldPtr->inputMaxCols = fldPtr->inputLength;
  1522. X    fldPtr->inputFullLines = 1;
  1523. X    fldPtr->inputShortCols = 0;
  1524. X    }
  1525. X
  1526. X    return;
  1527. X}
  1528. X
  1529. X
  1530. X/* calcMenu()    calculate page and column for each menu item
  1531. X *        and create index for menu; return -1 if
  1532. X *        more than one item label begin with the same
  1533. X *        letter, else 0.
  1534. X */
  1535. Xstatic int
  1536. XcalcMenu ()
  1537. X{
  1538. X    int             letter,
  1539. X                    thisPage,
  1540. X                    nextCol,
  1541. X                    scrollSymSize = strlen (LEFT_SCROLL_SYMBOL),
  1542. X                    numScrollSymbols,
  1543. X                    itemLen,
  1544. X                    itemNum = 0;
  1545. X    /* initialize menu index */
  1546. X    for (letter = 0; letter < (int) ('z' - 'a' + 1); letter++)
  1547. X    menuIndex[letter] = -1;
  1548. X
  1549. X    /* get count of menu items */
  1550. X    while (dupeMenu[itemNum++]);
  1551. X    numMenuItems = itemNum - 1;
  1552. X
  1553. X    /* start on first column of first page */
  1554. X    thisPage = 0;
  1555. X    nextCol = 0;
  1556. X    itemNum = 0;
  1557. X    while (dupeMenu[itemNum]) {
  1558. X
  1559. X    /* register item in index */
  1560. X    letter = (int) *(dupeMenu[itemNum]->label);
  1561. X    if (!(isascii (letter) && isalpha (letter))) {
  1562. X        DISP_ERROR_1 (NON_ALPHA, itemNum);
  1563. X        return -1;
  1564. X    }
  1565. X    if (isupper (letter))
  1566. X        letter = tolower (letter);
  1567. X    letter -= (int) 'a';    /* start from 0, not 'a' */
  1568. X    if (menuIndex[letter] == -1)
  1569. X        menuIndex[letter] = itemNum;
  1570. X    else
  1571. X        menuIndex[letter] = -2;;
  1572. X
  1573. X    itemLen = strlen (dupeMenu[itemNum]->label);
  1574. X
  1575. X    /* check to see that label isn't wider than the window itself if this
  1576. X     * menu has only one item, then we don't need to worry about fitting
  1577. X     * in any scroll symbols; if we are already beyond the first page and
  1578. X     * there are no more items, we need to worry about only one scroll
  1579. X     * symbol also fitting; if we are already beyond the first page and
  1580. X     * there are more items, we need to worry about two scroll symbols
  1581. X     * also fitting.
  1582. X     */
  1583. X    if (numMenuItems == 1)
  1584. X        numScrollSymbols = 0;
  1585. X    else if ((thisPage > 0) && ((itemNum + 1) == numMenuItems))
  1586. X        numScrollSymbols = 1;
  1587. X    else
  1588. X        numScrollSymbols = 2;
  1589. X    if ((itemLen +
  1590. X         (numScrollSymbols * (scrollSymSize + MENUI_SPACING))) > COLS) {
  1591. X        DISP_ERROR_1 (WIDE_LABEL, itemNum);
  1592. X        return -1;
  1593. X    }
  1594. X
  1595. X    /* check to see if it will fit on this page; if not the last item we
  1596. X     * need to make sure on scrolling symbol will fit as well.
  1597. X     */
  1598. X    numScrollSymbols = ((itemNum + 1) == numMenuItems) ? 0 : 1;
  1599. X    if ((itemLen + nextCol +
  1600. X         (numScrollSymbols * (scrollSymSize + MENUI_SPACING))) > COLS) {
  1601. X
  1602. X        /* won't fit on this page, start new page */
  1603. X        thisPage++;
  1604. X        nextCol = scrollSymSize + MENUI_SPACING;
  1605. X    }
  1606. X
  1607. X    /* assign its col and page */
  1608. X    dupeMenu[itemNum]->col = nextCol;
  1609. X    dupeMenu[itemNum]->page = thisPage;
  1610. X    nextCol += (itemLen + MENUI_SPACING);
  1611. X
  1612. X    itemNum++;
  1613. X    }
  1614. X
  1615. X    /* Set global menu variables; hmm ... numMenuItems already set above */
  1616. X    numMenuPages = thisPage + 1;
  1617. X    return 0;
  1618. X}
  1619. X
  1620. X
  1621. X/* dispMenuItem()    display menu item highlighted or not
  1622. X *            and display description field if highlighted
  1623. X */
  1624. Xstatic void
  1625. XdispMenuItem (mitemPtr, highlight)
  1626. XDMMMENUITEM    *mitemPtr;
  1627. Xint             highlight;
  1628. X{
  1629. X    if (mitemPtr) {
  1630. X    if (highlight)
  1631. X        DMMWATTRON (menuWin, A_REVERSE);
  1632. X    mvwaddstr (menuWin, MENU_LABEL_LINE, mitemPtr->col,
  1633. X           mitemPtr->label);
  1634. X    if (highlight) {
  1635. X        DMMWATTROFF (menuWin, A_REVERSE);
  1636. X        mvwaddstr (menuWin, MENU_DESCRIPT_LINE, 0, mitemPtr->descript);
  1637. X        wclrtoeol (menuWin);
  1638. X    }
  1639. X    }
  1640. X    return;
  1641. X}
  1642. X
  1643. X
  1644. X/* dispMenuPage()    display page of menu items containing the
  1645. X *            item indicated; if highlight is TRUE
  1646. X *            highlight the menu item; if force is TRUE,
  1647. X *            redisplay from scratch.
  1648. X */
  1649. Xstatic void
  1650. XdispMenuPage (itemNum, highlight, dmmRenew)
  1651. Xint             itemNum,
  1652. X                highlight,
  1653. X                dmmRenew;
  1654. X{
  1655. X    static int      lastPageDisplayed = -1,
  1656. X                    lastItemHighlighted = -1;
  1657. X    int             itemIndex,
  1658. X                    pageNum;
  1659. X
  1660. X    /* if page is current only redisplay old item unhighlighted and new item
  1661. X     * highlighted, else display whole page from scratch adding right and
  1662. X     * left scrolling symbols as needed
  1663. X     */
  1664. X
  1665. X    if (!dmmRenew && (dupeMenu[itemNum]->page == lastPageDisplayed)) {
  1666. X
  1667. X    if (itemNum != lastItemHighlighted)
  1668. X        if (lastItemHighlighted != -1)
  1669. X        dispMenuItem (dupeMenu[lastItemHighlighted], 0);
  1670. X    dispMenuItem (dupeMenu[itemNum], highlight);
  1671. X
  1672. X    } else {
  1673. X
  1674. X    werase (menuWin);
  1675. X    pageNum = dupeMenu[itemNum]->page;
  1676. X    for (itemIndex = 0; itemIndex < numMenuItems; itemIndex++)
  1677. X        if (dupeMenu[itemIndex]->page == pageNum)
  1678. X        dispMenuItem (dupeMenu[itemIndex],
  1679. X                  ((itemIndex == itemNum) && highlight));
  1680. X
  1681. X    if (pageNum)
  1682. X        mvwaddstr (menuWin, MENU_LABEL_LINE, 0, LEFT_SCROLL_SYMBOL);
  1683. X    if (pageNum + 1 < numMenuPages)
  1684. X        mvwaddstr (menuWin, MENU_LABEL_LINE,
  1685. X          COLS - sizeof (RIGHT_SCROLL_SYMBOL), RIGHT_SCROLL_SYMBOL);
  1686. X
  1687. X    lastPageDisplayed = pageNum;
  1688. X    }
  1689. X    lastItemHighlighted = itemNum;
  1690. X    wnoutrefresh (menuWin);
  1691. X    return;
  1692. X}
  1693. X
  1694. X
  1695. X/* layout()        do layout and calculations for the first display */
  1696. Xstatic int
  1697. Xlayout ()
  1698. X{
  1699. X    register int    fldNum = 0;    /* number of current field */
  1700. X    register DMMFIELD *fieldPtr;
  1701. X    int             inputPartCnt = 0,    /* number of input fields so far */
  1702. X                    lastInFieldNum = -1,
  1703. X                    firstInFieldNum;
  1704. X
  1705. X    /* indicate first input field not yet discovered */
  1706. X    firstInputFld = -1;
  1707. X
  1708. X    /* erase previous contents of windows */
  1709. X    werase (fieldWin);
  1710. X    werase (instructWin);
  1711. X    werase (menuWin);
  1712. X
  1713. X    /* draw field window */
  1714. X    if (dupeScreen) {
  1715. X    while (dupeScreen[fldNum]) {
  1716. X        fieldPtr = dupeScreen[fldNum];
  1717. X
  1718. X        /* check that label fits on screen */
  1719. X        if (fieldPtr->labelValue &&
  1720. X        ((fieldPtr->labelCol + strlen (fieldPtr->labelValue) > COLS)) ||
  1721. X        ((fieldPtr->labelLine + 1> FLINES))) {
  1722. X        DISP_ERROR_1 (LABEL_NO_FIT, fldNum);
  1723. X        return -1;
  1724. X        }
  1725. X
  1726. X        /* display label, if any */
  1727. X        if (fieldPtr->labelValue && *fieldPtr->labelValue) {
  1728. X        DMMWATTRON (fieldWin, fieldPtr->labelAttrib);
  1729. X        mvwaddstr (fieldWin, fieldPtr->labelLine,
  1730. X               fieldPtr->labelCol, fieldPtr->labelValue);
  1731. X        DMMWATTROFF (fieldWin, fieldPtr->labelAttrib);
  1732. X        }
  1733. X
  1734. X        /* if there is an input part, display it */
  1735. X        if (fieldPtr->inputLength) {
  1736. X
  1737. X        /* calculate number of instruction lines */
  1738. X        fieldPtr->inputNumInstructs =
  1739. X            cntInstructs (fieldPtr);
  1740. X
  1741. X        /* set the first input field if not yet found */
  1742. X        if (firstInputFld == -1)
  1743. X            firstInputFld = fldNum;
  1744. X
  1745. X        /* calculate defaults */
  1746. X        calcDflts (fieldPtr);
  1747. X
  1748. X        /* check that input part of field fits on screen */
  1749. X        if ((fieldPtr->inputCol + fieldPtr->inputMaxCols > COLS) ||
  1750. X            (fieldPtr->inputLine + fieldPtr->inputFullLines +
  1751. X             (fieldPtr->inputShortCols ? 1 : 0) > FLINES)) {
  1752. X            DISP_ERROR_1 (IP_NO_FIT, fldNum);
  1753. X            return -1;
  1754. X        }
  1755. X
  1756. X        /* display edited value */
  1757. X        dispInField (fieldPtr, fieldPtr->inputAttrib);
  1758. X
  1759. X        /* set last input field's next pointer to this field and this
  1760. X         * field's prev pointer to last input field
  1761. X         */
  1762. X        if (lastInFieldNum != -1) {
  1763. X            dupeScreen[lastInFieldNum]->nextInField = fldNum;
  1764. X            fieldPtr->prevInField = lastInFieldNum;
  1765. X        } else
  1766. X            firstInFieldNum = fldNum;
  1767. X
  1768. X        lastInFieldNum = fldNum;
  1769. X        inputPartCnt++;
  1770. X        }
  1771. X        fldNum++;
  1772. X    }
  1773. X    if ((firstInFieldNum != -1) && (lastInFieldNum != -1)) {
  1774. X        dupeScreen[firstInFieldNum]->prevInField = lastInFieldNum;
  1775. X        fieldPtr->nextInField = firstInFieldNum;
  1776. X    }
  1777. X    }
  1778. X
  1779. X    /* set globals to values of local register variables */
  1780. X    numFields = fldNum;
  1781. X    numInputParts = inputPartCnt;
  1782. X
  1783. X    /* display menu items and determine menu instruction */
  1784. X    if (dupeMenu) {
  1785. X
  1786. X    /* do menu calculations */
  1787. X    if (calcMenu ())
  1788. X        return -1;
  1789. X
  1790. X    /* display menu page that contains first item; no item highlighted */
  1791. X    dispMenuPage (curMenuItem = 0, 0, 1);
  1792. X    }
  1793. X    return 0;
  1794. X}
  1795. X
  1796. X
  1797. X/* copyInFields()    copy all initial values to edited values of
  1798. X *            input parts of fields and display; a null
  1799. X *            initial value is equivalent to a zero-length
  1800. X *            string.
  1801. X */
  1802. Xstatic void
  1803. XcopyInFields ()
  1804. X{
  1805. X    int             fldNum;    /* counter of field */
  1806. X    DMMFIELD       *fldPtr;
  1807. X    for (fldNum = 0; fldNum < numFields; fldNum++) {
  1808. X    fldPtr = dupeScreen[fldNum];
  1809. X    if (fldPtr->inputLength) {
  1810. X        strncpy (fldPtr->inputEditValue,
  1811. X             fldPtr->inputInitValue ? fldPtr->inputInitValue : "",
  1812. X             fldPtr->inputLength);
  1813. X        fldPtr->inputEditValue[fldPtr->inputLength] = '\0';
  1814. X        dispInField (fldPtr, fldPtr->inputAttrib);
  1815. X    }
  1816. X    }
  1817. X    return;
  1818. X}
  1819. X
  1820. X
  1821. X/* insane()    check the sanity of things, where fldNum is the number
  1822. X *        of the selected starting input field,
  1823. X *        returning 0 if okay, else writing a diagnostic message
  1824. X *        to stderr and returning non-zero.
  1825. X */
  1826. Xstatic int
  1827. Xinsane (fldNum)
  1828. Xint             fldNum;
  1829. X{
  1830. X    /* is the starting field within the proper range? */
  1831. X    if (fldNum > numFields - 1) {
  1832. X    DISP_ERROR_2 (BAD_FIELDNUM, fldNum + 1, numFields);
  1833. X    return 1;
  1834. X    }
  1835. X
  1836. X    /* does the starting field have an input part */
  1837. X    if (numInputParts) {
  1838. X    if (dupeScreen[fldNum]->inputLength < 1) {
  1839. X        DISP_ERROR_1 (NOT_IFIELD, fldNum + 1);
  1840. X        return 1;
  1841. X    }
  1842. X    }
  1843. X
  1844. X    /* is there at least one field with an input part or one menu item */
  1845. X    if (!(numInputParts || numMenuItems)) {
  1846. X    DISP_ERROR_0 (NO_INPUT_MSG);
  1847. X    return 1;
  1848. X    }
  1849. X
  1850. X    return 0;
  1851. X}
  1852. X
  1853. X
  1854. X/* dmmReview()        audit all input fields */
  1855. Xint
  1856. XdmmReview (screen)
  1857. XDMMSCREEN       screen;
  1858. X{
  1859. X    register int    fldNum;    /* field index */
  1860. X    register DMMFIELD *fldPtr;
  1861. X    DMMAUDITRETURN  auditReturnVal;    /* return value of the audit function */
  1862. X
  1863. X    for (fldNum = 0; screen[fldNum]; fldNum++) {
  1864. X    fldPtr = screen[fldNum];
  1865. X    if (fldPtr->inputLength) {
  1866. X        auditReturnVal = fldPtr->inputAudit (fldPtr->inputEditValue);
  1867. X        if ((auditReturnVal == dmmAuditBad)
  1868. X            || (auditReturnVal == dmmAuditReturnBad)) {
  1869. X        dmmRetType = dmmBadField;
  1870. X        return fldNum;
  1871. X        }
  1872. X    }
  1873. X    }
  1874. X    dmmRetType = dmmOkayField;
  1875. X    return -1;
  1876. X}
  1877. X
  1878. X
  1879. X/* cntInstructs(fldPtr)    return the number of instruction lines for
  1880. X *            the specified field number
  1881. X */
  1882. Xstatic int
  1883. XcntInstructs (fldPtr)
  1884. XDMMFIELD       *fldPtr;
  1885. X{
  1886. X    register int    numInstruct = 0,    /* number of instruction lines */
  1887. X                    instructNum = 0;    /* index in inputInstructVec */
  1888. X
  1889. X    if (fldPtr->inputInstructVec) {
  1890. X    while (fldPtr->inputInstructVec[instructNum++]) {
  1891. X        numInstruct++;
  1892. X    }
  1893. X    }
  1894. X    return numInstruct;
  1895. X}
  1896. X
  1897. X
  1898. X/* arriveInField()        display the input field of the specified
  1899. X *                number with the edit attributes and display the
  1900. X *                instructions for that input field
  1901. X */
  1902. Xstatic void
  1903. XarriveInField (fldPtr)
  1904. XDMMFIELD       *fldPtr;
  1905. X{
  1906. X    register int    numInstructs,    /* number of instructions left to
  1907. X                     * display */
  1908. X                    instructLine;    /* line number for displaying next
  1909. X                     * instr */
  1910. X
  1911. X    /* display field in appropriate attributes */
  1912. X    dispInField (fldPtr, fldPtr->inputEditAttrib);
  1913. X
  1914. X    /* display instruction lines in reverse order, bottom up */
  1915. X    numInstructs = fldPtr->inputNumInstructs;
  1916. X    instructLine = LFLINE;
  1917. X    while (numInstructs--)
  1918. X    mvwaddstr (fieldWin,
  1919. X         instructLine--, 0, fldPtr->inputInstructVec[numInstructs]);
  1920. X    return;
  1921. X}
  1922. X
  1923. X
  1924. X/* leaveInField()    display the input field of the specified
  1925. X *                number with the normal attributes and erase
  1926. X *                the instructions for that input field
  1927. X */
  1928. Xstatic void
  1929. XleaveInField (fldPtr)
  1930. XDMMFIELD       *fldPtr;
  1931. X{
  1932. X    register int    numInstructs,    /* number of instructions left to
  1933. X                     * display */
  1934. X                    instructLine;    /* line number for displaying next
  1935. X                     * instr */
  1936. X    /* display field in appropriate attributes */
  1937. X    dispInField (fldPtr, fldPtr->inputAttrib);
  1938. X
  1939. X    /* erase instruction lines starting with the bottom */
  1940. X    numInstructs = fldPtr->inputNumInstructs;
  1941. X    instructLine = LFLINE;
  1942. X    while (numInstructs--) {
  1943. X    wmove (fieldWin, instructLine--, 0);
  1944. X    wclrtoeol (fieldWin);
  1945. X    }
  1946. X    return;
  1947. X}
  1948. X
  1949. X
  1950. X/* chgInField()    change to the first position of a (perhaps
  1951. X *            input field; old is the last input field,
  1952. X *            and delta specifies what the change is to the
  1953. X *            new input field; return the number of the new
  1954. X *            input field.
  1955. X */
  1956. Xstatic int
  1957. XchgInField (old, delta)
  1958. Xint             old;
  1959. Xenum change     delta;
  1960. X{
  1961. X    int             new;    /* number of the new input field */
  1962. X
  1963. X
  1964. X    /* determine new field */
  1965. X    new = ((delta != stayput) ?
  1966. X       (delta == next ?
  1967. X        dupeScreen[old]->nextInField : dupeScreen[old]->prevInField) 
  1968. X       : old);
  1969. X
  1970. X    /* if field actually changed, leave old field and arrive at new field */
  1971. X    if (new != old)
  1972. X    leaveInField (dupeScreen[old]);
  1973. X    arriveInField (dupeScreen[new]);
  1974. X
  1975. X    /* move cursor to first position in new field */
  1976. X    wmove (fieldWin, dupeScreen[new]->inputLine, dupeScreen[new]->inputCol);
  1977. X
  1978. X    return new;
  1979. X}
  1980. X
  1981. X
  1982. X/* adjustFld()    convert trailing blanks of an edited
  1983. X *        field value to nulls and intermediate nulls to blanks.
  1984. X */
  1985. Xstatic void
  1986. XadjustFld (fldPtr)
  1987. Xregister DMMFIELD *fldPtr;
  1988. X{
  1989. X    register int    charCnt = fldPtr->inputLength;    /* counter for
  1990. X                             * characters output */
  1991. X    enum location {
  1992. X    internal, external
  1993. X    };                /* whether before or after the terminating
  1994. X                 * null of inputEditValue */
  1995. X    register enum location state;
  1996. X
  1997. X    state = external;
  1998. X    while (charCnt--) {
  1999. X    switch (state) {
  2000. X    case external:
  2001. X
  2002. X        switch (fldPtr->inputEditValue[charCnt]) {
  2003. X        case '\0':
  2004. X        break;
  2005. X        case ' ':
  2006. X        fldPtr->inputEditValue[charCnt] = '\0';
  2007. X        break;
  2008. X        default:
  2009. X        state = internal;
  2010. X        break;
  2011. X        }
  2012. X        break;
  2013. X
  2014. X    case internal:
  2015. X        if (fldPtr->inputEditValue[charCnt] == '\0')
  2016. X        fldPtr->inputEditValue[charCnt] = ' ';
  2017. X        break;
  2018. X    }
  2019. X    }
  2020. SHAR_EOF
  2021. echo "End of part 1"
  2022. echo "File dmm.c is continued in part 2"
  2023. echo "2" > s2_seq_.tmp
  2024. exit 0
  2025. -- 
  2026. Rob Bernardo                    Mt. Diablo Software Solutions
  2027. email: rob@mtdiablo.Concord.CA.US        phone: (415) 827-4301
  2028.