home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 5 / 05.iso / a / a106 / 2.ddi / GENMENU.PR_ / GENMENU.bin
Encoding:
Text File  |  1994-04-28  |  49.7 KB  |  1,724 lines

  1. *
  2. * GENMENU - Menu code generator.
  3. *
  4. * Copyright (c) 1990 - 1993 Microsoft Corp.
  5. * 1 Microsoft Way
  6. * Redmond, WA 98052
  7. *
  8. * Description:
  9. * This program generates menu code which was designed in the
  10. * FoxPro 2.5 MENU BUILDER.
  11. *
  12. * Notes:
  13. * In this program, for clarity/readability reasons, we use variable
  14. * names that are longer than 10 characters.  Note, however, that only
  15. * the first 10 characters are significant.
  16. *
  17. * Modification History:
  18. * December 13, 1990             JAC             Program Created
  19. *
  20. * Modifed for FoxPro 2.5 by WJK.
  21. *
  22. PARAMETER m.projdbf, m.recno
  23. PRIVATE ALL
  24. IF SET("TALK") = "ON"
  25.     SET TALK OFF
  26.     m.talkstate = "ON"
  27. ELSE
  28.     m.talkstate = "OFF"
  29. ENDIF
  30. m.escape = SET("ESCAPE")
  31. SET ESCAPE OFF
  32. m.trbetween = SET("TRBET")
  33. SET TRBET OFF
  34. m.comp = SET("COMPATIBLE")
  35. SET COMPATIBLE OFF
  36. mdevice = SET("DEVICE")
  37. SET DEVICE TO SCREEN
  38.  
  39. *
  40. * Declare Constants
  41. *
  42. #DEFINE c_esc   CHR(27)
  43. #DEFINE c_null  CHR(0)
  44.  
  45. *
  46. * Possible values of Objtype field in SCX database.
  47. *
  48. #DEFINE c_menu          1
  49. #DEFINE c_submenu       2
  50. #DEFINE c_item          3
  51.  
  52. *
  53. * Some of the values of Objcode field in SCX database.
  54. *
  55. #DEFINE c_global        1
  56. #DEFINE c_proc          80
  57.  
  58. #DEFINE c_maxsnippets   25
  59. #DEFINE c_maxpads               25
  60. #DEFINE c_pjx20flds             33
  61. #DEFINE c_pjxflds               31
  62. #DEFINE c_mnxflds               23
  63. #DEFINE c_20mnxflds             22
  64.  
  65. #DEFINE c_authorlen             45
  66. #DEFINE c_complen               45
  67. #DEFINE c_addrlen               45
  68. #DEFINE c_citylen               20
  69. #DEFINE c_statlen               5
  70. #DEFINE c_ziplen                10
  71. #DEFINE c_countrylen 40
  72.  
  73. #DEFINE c_error_1               "Minor"
  74. #DEFINE c_error_2               "Serious"
  75. #DEFINE c_error_3               "Fatal"
  76.  
  77. #DEFINE c_dlgface               "MS Sans Serif"
  78. #DEFINE c_dlgsize               8.000
  79. #DEFINE c_dlgstyle              "B"
  80.  
  81. #DEFINE c_replace               0
  82. #DEFINE c_append                1
  83. #DEFINE c_before                2
  84. #DEFINE c_after                 3
  85.  
  86. *
  87. * Declare Variables
  88. *
  89. STORE "" TO m.cursor, m.consol, m.bell, m.onerror, ;
  90.     m.exact, m.print, m.fixed, m.delimiters, m.mpoint, m.mcollate
  91. STORE 0 TO m.deci, m.memowidth
  92.  
  93. m.g_error      = .F.
  94. m.g_errlog     = ""
  95. m.g_homedir    = ""
  96. m.g_location   = 0
  97. m.g_menucolor  = 0
  98. m.g_menumark   = ""
  99. m.g_nohandle   = .T.
  100. m.g_nsnippets  = 0
  101. m.g_outfile    = ""
  102. m.g_padloca    = ""
  103. m.g_projalias  = ""
  104. m.g_projdbf    = m.projdbf
  105. m.g_projpath   = ""
  106. m.g_status     = 0
  107. m.g_snippcnt   = 0
  108. m.g_thermwidth = 0
  109. m.g_workarea   = 0
  110. m.g_graphic    = .F.
  111. m.g_20mnx          = .F.
  112.  
  113. m.g_devauthor  = PADR("Author's Name",45," ")
  114. m.g_devcompany = PADR("Company Name",45, " ")
  115. m.g_devaddress = PADR("Address",45," ")
  116. m.g_devcity    = PADR("City",20," ")
  117. m.g_devstate   = "  "
  118. m.g_devzip     = PADR("Zip",10," ")
  119. m.g_devctry    = PADR("Country",40," ")
  120.  
  121. *m.g_boxstrg = ['─','─','│','│','┌','┐','└','┘','─','─','│','│','┌','┐','└','┘']
  122. m.g_boxstrg = [ 8,8,'│','│','┌','┐','└','┘',8,8,'│','│','┌','┐','└','┘']
  123.  
  124. STORE "" TO m.g_corn1, m.g_corn2, m.g_corn3, m.g_corn4, m.g_corn5, ;
  125.     m.g_corn6, m.g_verti2
  126. STORE "*" TO  m.g_horiz, m.g_verti1
  127.  
  128. *
  129. * Array Declarations
  130. *
  131. * g_mnxfile [1] - Normalized path + name
  132. * g_mnxfile [2] - Basename
  133. * g_mnxfile [3] - Opened originally?
  134. * g_mnxfile [4] - Alias
  135. *
  136. DIMENSION g_mnxfile[4]
  137. g_mnxfile[1] = ""
  138. g_mnxfile[2] = ""
  139. g_mnxfile[3] = .F.
  140. g_mnxfile[4] = ""
  141.  
  142. *
  143. * g_pads - names of generated menu pads
  144. *
  145. DIMENSION g_pads(c_maxpads)
  146.  
  147. *
  148. * g_snippets [*,1] - generated snippet procedure name
  149. * g_snippets [*,2] - recno()
  150. *
  151.  
  152. DIMENSION g_snippets (c_maxsnippets,2)
  153. g_snippets = ""
  154.  
  155. IF AT("WINDOWS", UPPER(VERSION())) <> 0 OR ;
  156.         AT("MAC", UPPER(VERSION())) <> 0
  157.     m.g_graphic = .T.
  158. ELSE
  159.     m.g_graphic = .F.
  160. ENDIF
  161.  
  162. *
  163. * Main program
  164. *
  165. m.onerror = ON("ERROR")
  166. ON ERROR DO errorhandler WITH MESSAGE(), LINENO(), c_error_3
  167.  
  168. IF PARAMETERS()=2
  169.     DO setup
  170.     IF validparams()
  171.         ON ESCAPE DO eschandler
  172.         SET ESCAPE ON
  173.         DO refreshprefs
  174.         DO BUILD
  175.     ENDIF
  176.     DO cleanup
  177. ELSE
  178.     DO errorhandler WITH "Invalid number of parameters passed to"+;
  179.         " the generator",LINENO(),c_error_3
  180. ENDIF
  181. ON ERROR &onerror
  182.  
  183. RETURN m.g_status
  184.  
  185. **
  186. ** Setup, Cleanup, Validparams, and Refreshprefs of Main Program
  187. **
  188.  
  189. *
  190. * STARTUP - Create program's environment.
  191. *
  192. * Description:
  193. * Save the user's environment so that we can set it back when
  194. * we are done, then issue various SET commands. The only state
  195. * we cannot conveniently save is SET TALK, because storing the
  196. * state involves an assignment statement, and assignments
  197. * generate unwanted output if TALK is set ON.
  198. *
  199. * Side Effects:
  200. * Creates a temporary file which is deleted in the Cleanup
  201. * procedure executed at the end of MENUGEN.
  202. *
  203. PROCEDURE setup
  204.     CLEAR PROGRAM
  205.     CLEAR GETS
  206.     m.g_workarea = SELECT()
  207.     m.delimiters = SET('TEXTMERGE',1)
  208.     SET TEXTMERGE DELIMITERS TO
  209.     SET UDFPARMS TO VALUE
  210.  
  211.     m.bell = SET("BELL")
  212.     SET BELL OFF
  213.     m.consol = SET("CONSOLE")
  214.     SET CONSOLE OFF
  215.     m.cursor = SET("CURSOR")
  216.     SET CURSOR OFF
  217.     m.deci = SET("DECIMALS")
  218.     SET DECIMALS TO 0
  219.     mdevice = SET("DEVICE")
  220.     SET DEVICE TO SCREEN
  221.     m.memowidth = SET("MEMOWIDTH")
  222.     SET MEMOWIDTH TO 256
  223.     m.exact = SET("EXACT")
  224.     SET EXACT ON
  225.     m.print = SET("PRINT")
  226.     SET PRINT OFF
  227.     m.fixed = SET("FIXED")
  228.     SET FIXED ON
  229.     mpoint = SET("POINT")
  230.     SET POINT TO "."
  231.     mcollate = SET("COLLATE")
  232.     SET COLLATE TO "machine"
  233. *
  234. * CLEANUP - restore environment to pre-execution state.
  235. *
  236. * Description:
  237. * Close all databases opened in the course of the execution of MENUGEN.
  238. * Restore the environment to the pre-execution of MENUGEN.  Delete
  239. * the VIEW file since there is no further use for it.
  240. *
  241. * Side Effects:
  242. * Closes databases.
  243. * Deletes the temporary view file.
  244. *
  245. PROCEDURE cleanup
  246.     PRIVATE m.delilen, m.ldelimi, m.rdelimi
  247.     IF EMPTY(m.g_projalias)
  248.         RETURN
  249.     ENDIF
  250.     SELECT (m.g_projalias)
  251.     USE
  252.     IF NOT EMPTY(g_mnxfile[3])
  253.         IF USED(g_mnxfile[4])
  254.             SELECT (g_mnxfile[4])
  255.             USE
  256.         ENDIF
  257.     ENDIF
  258.     SELECT (m.g_workarea)
  259.  
  260.     m.delilen = LEN(m.delimiters)
  261.     m.ldelimi = SUBSTR(m.delimiters,1,;
  262.         IIF(MOD(m.delilen,2)=0,m.delilen/2,CEILING(m.delilen/2)))
  263.     m.rdelimi = SUBSTR(m.delimiters,;
  264.         IIF(MOD(m.delilen,2)=0,m.delilen/2+1,CEILING(m.delilen/2)+1))
  265.     SET TEXTMERGE DELIMITERS TO m.ldelimi, m.rdelimi
  266.  
  267.     IF m.bell = "ON"
  268.         SET BELL ON
  269.     ENDIF
  270.     IF m.cursor = "ON"
  271.         SET CURSOR ON
  272.     ELSE
  273.         SET CURSOR OFF
  274.     ENDIF
  275.     IF m.consol = "ON"
  276.         SET CONSOLE ON
  277.     ENDIF
  278.     IF m.escape = "ON"
  279.         SET ESCAPE ON
  280.     ELSE
  281.         SET ESCAPE OFF
  282.     ENDIF
  283.     IF m.print = "ON"
  284.         SET PRINT ON
  285.     ENDIF
  286.     IF m.exact = "OFF"
  287.         SET EXACT OFF
  288.     ENDIF
  289.     IF m.fixed = "OFF"
  290.         SET FIXED OFF
  291.     ENDIF
  292.     SET DECIMALS TO m.deci
  293.     SET MEMOWIDTH TO m.memowidth
  294.     SET DEVICE TO &mdevice
  295.     IF m.trbetween = "ON"
  296.         SET TRBET ON
  297.     ENDIF
  298.     IF m.comp = "ON"
  299.         SET COMPATIBLE ON
  300.     ENDIF
  301.     IF m.talkstate = "ON"
  302.         SET TALK ON
  303.     ENDIF
  304.     SET POINT TO "&mpoint"
  305.     SET COLLATE TO "&mcollate"
  306.     SET MESSAGE TO
  307.  
  308.     ON ERROR &onerror
  309.  
  310.  
  311. *
  312. * VALIDPARAMS - Validate generator parameters.
  313. *
  314. * Description:
  315. * Attempt to open the project database.  If error encountered then
  316. * on error routine takes over and issues 'CANCEL'.  The output file
  317. * cannot be erased, name not known.
  318. *
  319. FUNCTION validparams
  320.     SELECT 0
  321.     m.g_projalias = IIF(USED("projdbf"),"P"+;
  322.         SUBSTR(LOWER(SYS(3)),2,8),"projdbf")
  323.     USE (m.projdbf) ALIAS (m.g_projalias)
  324.     IF versnum() > "2.5"
  325.        SET NOCPTRANS TO devinfo, arranged, symbols, object
  326.     ENDIF
  327.  
  328.     m.g_errlog = stripext(m.projdbf)
  329.     m.g_projpath = SUBSTR(m.projdbf,1,RAT("\",m.projdbf))
  330.  
  331.     IF FCOUNT() <> c_pjxflds
  332.         DO errorhandler WITH "Generator out of date.",;
  333.             LINENO(), c_error_2
  334.         RETURN .F.
  335.     ENDIF
  336.  
  337.     GOTO RECORD m.recno
  338.  
  339.     m.g_outfile = ALLTRIM(SUBSTR(outfile,1,AT(c_null,outfile)-1))
  340.     m.g_outfile = FULLPATH(m.g_outfile, m.g_projpath)
  341.     g_mnxfile[1] = FULLPATH(ALLTRIM(name), m.g_projpath)
  342.     g_mnxfile[2] = basename(g_mnxfile[1])
  343.  
  344. *
  345. * REFRESHPREFS - Refresh comment style and developer preferences.
  346. *
  347. * Description:
  348. * Get the newest preferences for documentation style and developer
  349. * data from the project database.
  350. *
  351. PROCEDURE refreshprefs
  352.     PRIVATE m.start, m.savrecno
  353.     m.savrecno = RECNO()
  354.     LOCATE FOR TYPE = "H"
  355.     IF NOT FOUND ()
  356.         DO errorhandler WITH "Missing header record in "+m.g_projdbf,;
  357.             LINENO(), c_error_2
  358.         GOTO RECORD m.savrecno
  359.         RETURN
  360.     ENDIF
  361.  
  362.     m.g_homedir = ALLTRIM(SUBSTR(homedir,1,AT(c_null,homedir)-1))
  363.  
  364.     m.start = 1
  365.     m.g_devauthor = subdevinfo(m.start,c_authorlen,m.g_devauthor)
  366.  
  367.     m.start = m.start + c_authorlen + 1
  368.     m.g_devcompany = subdevinfo(m.start,c_complen,m.g_devcompany)
  369.  
  370.     m.start = m.start + c_complen + 1
  371.     m.g_devaddress = subdevinfo(m.start,c_addrlen,m.g_devaddress)
  372.  
  373.     m.start = m.start + c_addrlen + 1
  374.     m.g_devcity = subdevinfo(m.start,c_citylen,m.g_devcity)
  375.  
  376.     m.start = m.start + c_citylen + 1
  377.     m.g_devstate = subdevinfo(m.start,c_statlen,m.g_devstate)
  378.  
  379.     m.start = m.start + c_statlen + 1
  380.     m.g_devzip = subdevinfo(m.start,c_ziplen,m.g_devzip)
  381.  
  382.     m.start = m.start + c_ziplen + 1
  383.     m.g_devctry = subdevinfo(m.start,c_countrylen,m.g_devctry)
  384.  
  385.     IF cmntstyle = 0
  386. *       m.g_corn1 = "╓"
  387.         m.g_corn1 = "*"
  388. *       m.g_corn2 = "╖"
  389.         m.g_corn2 = "*"
  390. *       m.g_corn3 = "╙"
  391.         m.g_corn3 = "*"
  392. *       m.g_corn4 = "╜"
  393.         m.g_corn4 = "*"
  394. *       m.g_corn5 = "╟"
  395.         m.g_corn5 = "*"
  396. *       m.g_corn6       = "╢"
  397.         m.g_corn6       = "*"
  398. *       m.g_horiz = "─"
  399.         m.g_horiz = "*"
  400. *       m.g_verti1 = "║"
  401.         m.g_verti1 = "*"
  402. *       m.g_verti2 = "║"
  403.         m.g_verti2 = "*"
  404.     ENDIF
  405.     GOTO RECORD m.savrecno
  406.  
  407. *
  408. * SUBDEVINFO - Substring the DEVINFO memo filed.
  409. *
  410. FUNCTION subdevinfo
  411.     PARAMETER m.start, m.stop, m.default
  412.     PRIVATE m.string
  413.     m.string = SUBSTR(devinfo, m.start, m.stop+1)
  414.     m.string = SUBSTR(m.string, 1, AT(c_null,m.string)-1)
  415.     RETURN IIF(EMPTY(m.string), m.default, m.string)
  416.  
  417. **
  418. ** Menu Code Generator's Main Module.
  419. **
  420.  
  421. *
  422. * BUILD - Generate code for a menu.
  423. *
  424. * Description:
  425. * Call BUILDENABLE to open .MNX database specified by the user.
  426. * If the above is successfully accomplished, then proceed to generate
  427. * the menu code.  After the menu code is generated, call BUILDDISABLE
  428. * to disable code generation between SET TEXTMERGE ON and
  429. * SET TEXTMERGE OFF.
  430. *
  431. PROCEDURE BUILD
  432.     IF NOT buildenable()
  433.         RETURN
  434.     ENDIF
  435.     DO acttherm WITH "Generating Menu Code..."
  436.     DO updtherm WITH 10
  437.  
  438.     DO HEADER
  439.     DO gensetupcleanup WITH "setup"
  440.     DO definemenu
  441.     DO definepopups
  442.     DO globaldefaults
  443.     DO gensetupcleanup WITH "cleanup"
  444.     DO genprocedures
  445.  
  446.     IF m.g_graphic
  447.         SET MESSAGE TO 'Generation Complete'
  448.     ENDIF
  449.     DO builddisable
  450.     DO updtherm WITH 100
  451.     DO deactthermo
  452.  
  453. *
  454. * BUILDENABLE - Enable code generation.
  455. *
  456. * Description:
  457. * Call opendb to open .MNX database.
  458. * Call openfile to open file to hold the generated program.
  459. * If error(s) encountered in opendb or openfile then don't do
  460. * anything and exit, otherwise enable code generation with the
  461. * SET TEXTMERGE ON command.
  462. *
  463. * Returns:
  464. * .T. on success; .F. on failure
  465. *
  466. FUNCTION buildenable
  467.     PRIVATE m.stat
  468.     m.stat = opendb(g_mnxfile[1]) AND openfile()
  469.     IF m.stat
  470.         SET TEXTMERGE ON
  471.     ENDIF
  472.     RETURN m.stat
  473.  
  474. *
  475. * BUILDDISABLE - Disable code generation.
  476. *
  477. * Description:
  478. * Issue the command SET TEXTMERGE OFF.
  479. * Close the generated menu code output file.
  480. * If anything goes wrong display appropriate message to the user.
  481. *
  482. PROCEDURE builddisable
  483.     SET ESCAPE OFF
  484.     ON ESCAPE
  485.     SET TEXTMERGE OFF
  486.     IF NOT FCLOSE(_TEXT)
  487.         DO errorhandler WITH "Unable to Close the Application File",;
  488.             LINENO(), c_error_2
  489.     ENDIF
  490.  
  491. *
  492. * OPENDB - Prepare database for processing.
  493. *
  494. * Description:
  495. * Attempt to USE a database.  If attempt fails and error is reported
  496. * call ERRORHANDLER routine to display a friendly message.  Return
  497. * with a status of .F..  If attempt succeeds, return with status of .T.
  498. *
  499. * Returns:
  500. * .T. on success; .F. on failure
  501. *
  502. FUNCTION opendb
  503.     PARAMETER m.dbname
  504.     PRIVATE m.dbalias
  505.     ON ERROR DO errorhandler WITH MESSAGE(), LINENO(), c_error_2
  506.  
  507.     m.dbalias = basename(m.dbname)
  508.     IF USED (m.dbalias)
  509.         SELECT (m.dbalias)
  510.         IF RAT(".MNX",DBF())<>0
  511.             g_mnxfile[3] = .F.
  512.             g_mnxfile[4] = m.dbalias
  513.         ELSE
  514.             g_mnxfile[4] = "M"+SUBSTR(LOWER(SYS(3)),2,8)
  515.             SELECT 0
  516.             USE (m.dbname) AGAIN ALIAS (g_mnxfile[4])
  517.             g_mnxfile[3] = .T.
  518.         ENDIF
  519.     ELSE
  520.         IF illegalname(m.dbalias)
  521.             g_mnxfile[4] = "M"+SUBSTR(LOWER(SYS(3)),2,8)
  522.         ELSE
  523.             g_mnxfile[4] = m.dbalias
  524.         ENDIF
  525.         SELECT 0
  526.         USE (m.dbname) AGAIN ALIAS (g_mnxfile[4])
  527.         g_mnxfile[3] = .T.
  528.     ENDIF
  529.  
  530.     IF FCOUNT() <> c_mnxflds
  531.         IF FCOUNT() = c_20mnxflds
  532.             m.g_20mnx = .T.
  533.         ELSE
  534.             DO errorhandler WITH "Menu "+m.dbalias+" is invalid",LINENO(),;
  535.                 c_error_2
  536.             RETURN .F.
  537.         ENDIF
  538.     ELSE
  539.         m.g_20mnx = .F.
  540.     ENDIF
  541.  
  542.     ON ERROR DO errorhandler WITH MESSAGE(), LINENO(), c_error_3
  543.     IF m.g_error = .T.
  544.         RETURN .F.
  545.     ENDIF
  546.  
  547. *
  548. * ILLEGALNAME - Check if default alias will be used when this
  549. *               database is USEd. (i.e., 1st letter is not A-Z,
  550. *                               a-z or '_', or any one of ramaining letters is not
  551. *                               alphanumeric.)
  552. *
  553. FUNCTION illegalname
  554.     PARAMETER m.menuname
  555.     PRIVATE m.start, m.aschar, m.length
  556.     m.length = LEN(m.menuname)
  557.     m.start  = 0
  558.     IF m.length = 1
  559.         *
  560.         * If length 1, then check if default alias can be used,
  561.         * i.e., name is different than A-J and a-j.
  562.         *
  563.         m.aschar = ASC(m.menuname)
  564.         IF (m.aschar >= 65 AND m.aschar <= 74) OR ;
  565.                 (m.aschar >= 97 AND m.aschar <= 106)
  566.             RETURN .T.
  567.         ENDIF
  568.     ENDIF
  569.     DO WHILE m.start < m.length
  570.         m.start  = m.start + 1
  571.         m.aschar = ASC(SUBSTR(m.menuname, m.start, 1))
  572.         IF m.start<>1 AND (m.aschar >= 48 AND m.aschar <= 57)
  573.             LOOP
  574.         ENDIF
  575.         IF NOT ((m.aschar >= 65 AND m.aschar <= 90) OR ;
  576.                 (m.aschar >= 97 AND m.aschar <= 122) OR m.aschar = 95)
  577.             RETURN .T.
  578.         ENDIF
  579.     ENDDO
  580.     RETURN .F.
  581.  
  582. *
  583. * OPENFILE - Create and open the application output file.
  584. *
  585. * Description:
  586. * Create a file that will hold the generated menu code.
  587. * Open the newly created file.  If error(s) encountered
  588. * at any time issue an error message and return .F.
  589. *
  590. * Returns:
  591. * .T. on success; .F. on failure
  592. *
  593. FUNCTION openfile
  594.     PRIVATE m.msg
  595.     _TEXT = FCREATE(m.g_outfile)
  596.     IF (_TEXT = -1)
  597.         m.msg = "Cannot open file "+m.g_outfile
  598.         DO errorhandler WITH m.msg, LINENO(), c_error_3
  599.         m.g_nohandle = .T.
  600.         RETURN .F.
  601.     ENDIF
  602.     m.g_nohandle = .F.
  603.  
  604. *
  605. * DEFINEMENU - Define main menu and its pads.
  606. *
  607. * Description:
  608. * Issue DEFINE MENU ... command.
  609. * Call a procedure to define all menu pads.
  610. * Call a procedure to generate ON PAD statements when appropriate.
  611. *
  612. PROCEDURE definemenu
  613.  
  614.     IF m.g_graphic
  615.         SET MESSAGE TO 'Generating menu definitions...'
  616.     ENDIF
  617.     DO commentblock WITH "menu"
  618.     SELECT (g_mnxfile[4])
  619.     LOCATE FOR objtype = c_menu
  620.     m.g_location = location
  621.     m.g_padloca  = ALLTRIM(name)
  622.  
  623.     LOCATE FOR objtype = c_submenu AND objcode = c_global
  624.  
  625.     m.g_menucolor = SCHEME
  626.     m.g_menumark  = MARK
  627.     IF m.g_location = c_replace
  628.         \SET SYSMENU TO
  629.         \
  630.     ENDIF
  631.     \SET SYSMENU AUTOMATIC
  632.     \
  633.  
  634.     DO defmenupads
  635.     DO defonpad
  636.     \
  637.     DO updtherm WITH 25
  638.  
  639. *
  640. * DEFMENUPADS - Define all pads for the menu bar.
  641. *
  642. * Description:
  643. * Scan the menu database for all objects of the type item which
  644. * have the levelname=_MSYSMENU.
  645. * For each such item, generate a statement DEFINE PAD... where
  646. * the name of the pad is the contents of NAME field or (if Name
  647. * field is empty) an automatically generated name.
  648. * Call procedures addkey, addskipfor, and mark to generate
  649. * KEY, SKIPFOR, or MARK clauses when appropriate.
  650. *
  651. PROCEDURE defmenupads
  652.     PRIVATE m.padname, m.prompt
  653.     SCAN FOR objtype=c_item AND UPPER(levelname)="_MSYSMENU"
  654.         IF NOT EMPTY(ALLTRIM(name))
  655.             g_pads[VAL(Itemnum)] = name
  656.         ELSE
  657.             g_pads[VAL(Itemnum)] = LOWER(SYS(2015))
  658.         ENDIF
  659.         \DEFINE PAD <<g_pads[VAL(Itemnum)]>> OF _MSYSMENU
  660.  
  661.         IF MOD(VAL(itemnum),25)=0
  662.             DIMENSION g_pads[VAL(Itemnum)+25]
  663.         ENDIF
  664.         m.prompt = SUBSTR(PROMPT,1,LEN(PROMPT))
  665.         \\ PROMPT "<<m.prompt>>"
  666.         \\ COLOR SCHEME <<m.g_menucolor>>
  667.  
  668.         IF m.g_menumark<>c_null AND m.g_menumark<>""
  669.             \\ ;
  670.             \   MARK "<<m.g_menumark>>"
  671.         ENDIF
  672.  
  673.         DO CASE
  674.             CASE m.g_location = c_before
  675.                 \\ ;
  676.                 \       BEFORE <<m.g_padloca>>
  677.             CASE m.g_location = c_after
  678.                 \\ ;
  679.                 \       AFTER
  680.                 IF VAL(itemnum) = 1
  681.                     \\ <<m.g_padloca>>
  682.                 ELSE
  683.                     \\ <<g_pads[VAL(Itemnum)-1]>>
  684.                 ENDIF
  685.         ENDCASE
  686.  
  687.         DO addkey
  688.         DO addskipfor
  689.         DO addmessage
  690.  
  691.     ENDSCAN
  692.     DO updtherm WITH 35
  693.  
  694. *
  695. * DEFONPAD - Generate ON PAD... statements.
  696. *
  697. * Description:
  698. * Generate ON PAD statements for each pad off of the main menu which
  699. * has a submenu associated with it.
  700. * For pads which have no submenus, but there is a command associated
  701. * with them, issue ON SELECTION PAD... statements.  If the code
  702. * associated with a pad is a snippet, then issue a call to the
  703. * generated procedure and place the snippet code in it.
  704. *
  705. PROCEDURE defonpad
  706.     PRIVATE m.padname
  707.     SCAN FOR objtype=c_item AND UPPER(levelname)="_MSYSMENU"
  708.         IF NOT EMPTY(ALLTRIM(name))
  709.             m.padname = name
  710.         ELSE
  711.             m.padname = g_pads[VAL(Itemnum)]
  712.         ENDIF
  713.         SKIP
  714.         IF objtype=c_submenu AND numitems<>0
  715.             \ON PAD <<m.padname>> OF _MSYSMENU
  716.             \\ ACTIVATE POPUP <<LOWER(Name)>>
  717.             SKIP -1
  718.         ELSE
  719.             SKIP -1
  720.             DO onselection WITH "pad", m.padname, '_MSYSMENU'
  721.         ENDIF
  722.     ENDSCAN
  723.     DO updtherm WITH 45
  724.  
  725. *
  726. * DEFINEPOPUPS - Define popups and their bars.
  727. *
  728. * Description:
  729. * Scan the Menu database to find all objecttypes = submenu.
  730. * They all correspond to popups.  For each such object found, issue
  731. * command DEFINE POPUP....  Add MARK, KEY, and SKIP FOR clauses
  732. * if appropriate by calling procedures to handle these tasks.  Call
  733. * procedure Defbars to define all bars of each popup.
  734. *
  735. PROCEDURE definepopups
  736.     PRIVATE m.savrecno, m.popname, m.sch
  737.     IF m.g_graphic
  738.         SET MESSAGE TO 'Generating popup definitions...'
  739.     ENDIF
  740.     SCAN FOR objtype=c_submenu AND UPPER(levelname)<>"_MSYSMENU" ;
  741.             AND numitems <> 0
  742.  
  743.         m.savrecno = RECNO()
  744.         m.popname  = ALLTRIM(LOWER(levelname))
  745.         m.sch      = SCHEME
  746.  
  747.         \DEFINE POPUP <<LOWER(Name)>> MARGIN RELATIVE SHADOW
  748.         \\ COLOR SCHEME <<m.sch>>
  749.  
  750.         DO addmark
  751.         DO addkey
  752.         DO defbars WITH m.popname, numitems
  753.         DO defonbar WITH m.popname
  754.         \
  755.         GOTO RECORD m.savrecno
  756.     ENDSCAN
  757.     DO updtherm WITH 65
  758.  
  759. *
  760. * DEFBARS - Define bars for each popup.
  761. *
  762. * Description:
  763. * Scan the menu database for all objects of the type item whose
  764. * name equals to the current popup name.
  765. * For each such item, generate a statement DEFINE BAR....
  766. * Call procedures addkey, addskipfor, and addmark to generate
  767. * KEY, SKIPFOR, or MARK clauses when appropriate.
  768. *
  769. PROCEDURE defbars
  770.     PARAMETER m.popname, m.howmany, m.name
  771.     PRIVATE m.itemno, m.prompt
  772.     SCAN FOR objtype=c_item AND LOWER(levelname)=m.popname
  773.         m.itemno = ALLTRIM(itemnum)
  774.  
  775.         IF NOT EMPTY(ALLTRIM(name))
  776.             m.name = name
  777.             \DEFINE BAR <<m.name>> OF <<LOWER(m.popname)>>
  778.         ELSE
  779.             \DEFINE BAR <<m.itemno>> OF <<LOWER(m.popname)>>
  780.         ENDIF
  781.         m.prompt = SUBSTR(PROMPT, 1,LEN(PROMPT))
  782.         \\ PROMPT "<<m.prompt>>"
  783.  
  784.         DO addmark
  785.         DO addkey
  786.         DO addskipfor
  787.         DO addmessage
  788.  
  789.         IF VAL(m.itemno)=m.howmany
  790.             DO updtherm WITH 75
  791.             RETURN
  792.         ENDIF
  793.     ENDSCAN
  794.  
  795. *
  796. * DEFONBAR - Generate ON BAR... statements.
  797. *
  798. * Description:
  799. * Generate ON BAR statements for each popup.
  800. * For bars which have no submenus, but there is a command associated
  801. * with them, issue ON SELECTION BAR... statements.  If a snippet is
  802. * associated with the code then generate a call statement to the
  803. * generated procedure containing the snippet code.
  804. *
  805. PROCEDURE defonbar
  806.     PARAMETER m.popname
  807.     PRIVATE m.itemno
  808.     SCAN FOR objtype=c_item AND LOWER(levelname)=m.popname
  809.         IF EMPTY(ALLTRIM(name))
  810.             m.itemno = ALLTRIM(itemnum)
  811.         ELSE
  812.             m.itemno = name
  813.         ENDIF
  814.         SKIP
  815.         IF objtype=c_submenu AND numitems<>0
  816.             \ON BAR <<m.itemno>> OF <<LOWER(m.popname)>>
  817.             \\ ACTIVATE POPUP <<LOWER(Name)>>
  818.             SKIP -1
  819.         ELSE
  820.             SKIP -1
  821.             DO onselection WITH "BAR", m.itemno, m.popname
  822.         ENDIF
  823.     ENDSCAN
  824.     DO updtherm WITH 85
  825.  
  826. *
  827. * GLOBALDEFAULTS - Generate global default statements
  828. *
  829. * Description:
  830. * Search the menu database for information needed to generate any of
  831. * the following commands:
  832. * ON SELECTION MENU <name> DO <action>
  833. * ON SELECTION POPUP ALL DO <action>
  834. * ON SELECTION POPUP <name> DO <action>
  835. * It is possible that none of the above mentioned statements will be
  836. * generated.  It is also possible that the action is a snippet of
  837. * code and a call to the generated procedure containing the snippet
  838. * will be generated.
  839. *
  840. * First try to generate ON SELECTION MENU...
  841. * Then try to generate ON POPUP ALL...
  842. * Lastly, try to generate ON SELECTION POPUP...
  843. *
  844. PROCEDURE globaldefaults
  845.     LOCATE FOR objtype = c_menu
  846.     m.mrk = MARK
  847.     IF FOUND() AND MARK <> ""
  848.         IF MARK = c_null
  849.             \SET MARK OF MENU _MSYSMENU TO " "
  850.         ELSE
  851.             \SET MARK OF MENU _MSYSMENU TO "<<Mark>>"
  852.         ENDIF
  853.     ENDIF
  854.     IF FOUND() AND NOT EMPTY(PROCEDURE)
  855.         \ON SELECTION MENU _MSYSMENU
  856.         DO genproccall
  857.     ENDIF
  858.     LOCATE FOR objtype = c_submenu AND objcode = c_global
  859.     IF FOUND() AND NOT EMPTY(PROCEDURE)
  860.         \ON SELECTION POPUP ALL
  861.         DO genproccall
  862.     ENDIF
  863.     SCAN FOR (objtype=c_submenu AND UPPER(levelname)<>"_MSYSMENU";
  864.             AND NOT EMPTY(PROCEDURE))
  865.         \ON SELECTION POPUP <<ALLTRIM(LOWER(Levelname))>>
  866.         DO genproccall
  867.     ENDSCAN
  868.     DO updtherm WITH 95
  869.  
  870. **
  871. ** Subroutines for processing menu clause options.
  872. **
  873.  
  874. *
  875. * ADDMARK - Generate a MARK clause whenever appropriate.
  876. *
  877. * Description:
  878. * Add a MARK clause to the current PAD or BAR definition.
  879. * If a field named Mark is not empty, then add the continuation
  880. * character, ";", to the previous line, and then add the MARK... clause.
  881. *
  882. PROCEDURE addmark
  883.     IF MARK<>c_null AND MARK<>""
  884.         \\ ;
  885.             \   MARK "<<Mark>>"
  886.     ENDIF
  887.  
  888. *
  889. * ADDKEY - Generate KEY... clause whenever appropriate.
  890. *
  891. * Description:
  892. * Add a KEY clause to the current PAD or BAR definition.
  893. * If a field named Keyname is not empty, then add the continuation
  894. * character, ";", to the previous line, and then add the KEY... clause.
  895. *
  896. PROCEDURE addkey
  897.     IF NOT EMPTY(keyname)
  898.         \\ ;
  899.         \       KEY <<Keyname>>, "<<Keylabel>>"
  900.     ENDIF
  901.  
  902. *
  903. * ADDSKIPFOR - Generate SKIP FOR... clause whenever appropriate.
  904. *
  905. * Description:
  906. * Add a ADDSKIPFOR clause to the current PAD or BAR definition.
  907. * If a field named Addskipfor is not empty, then add the continuation
  908. * character, ";", to the previous line, and then add the SKIP FOR...
  909. * clause.
  910. *
  911. PROCEDURE addskipfor
  912.     PRIVATE m.skip
  913.     m.skip = skipfor
  914.     IF NOT EMPTY(skipfor)
  915.         \\ ;
  916.         \       SKIP FOR <<m.skip>>
  917.     ENDIF
  918.  
  919. *
  920. * ADDMESSAGE - Generate MESSAGE clause whenever appropriate.
  921. *
  922. * Description:
  923. * Add a MESSAGE clause to the current PAD or BAR definition.
  924. * If a field named MESSAGE is not empty and it is not a 2.0 menu,
  925. * then add the continuation character, ";", to the previous line,
  926. * and then add the MESSAGE clause.
  927. *
  928. PROCEDURE addmessage
  929.  
  930.     IF !m.g_20mnx AND NOT EMPTY(MESSAGE)
  931.         \\ ;
  932.         \       MESSAGE <<Message>>
  933.     ENDIF
  934.  
  935. *
  936. * HEADER - Generate generated program's header.
  937. *
  938. * Description:
  939. * As a part of the automatically generated program's header generate
  940. * program name, name of the author of the program, copyright notice,
  941. * company name and address, and the word 'Description:' which will be
  942. * followed with a short description of the generated code.
  943. *
  944. PROCEDURE HEADER
  945.     \\*       <<m.g_corn1>><<REPLICATE(m.g_horiz,57)>><<m.g_corn2>>
  946.     \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  947.     \*       <<m.g_verti1>> <<DATE()>>
  948.     \\<<PADC(UPPER(ALLTRIM(strippath(m.g_outfile))),IIF(SET("CENTURY")="ON",35,37))," ")>>
  949.     \\ <<TIME()>>  <<m.g_verti2>>
  950.     \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  951.     \*       <<m.g_corn5>><<REPLICATE(m.g_horiz,57)>><<m.g_corn6>>
  952.     \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  953.     \*       <<m.g_verti1>> <<m.g_devauthor>>
  954.     \\<<REPLICATE(" ",56-LEN(m.g_devauthor))>><<m.g_verti2>>
  955.     \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  956.     \*       <<m.g_verti1>>
  957.     \\ Copyright (c) <<YEAR(DATE())>>
  958.     IF LEN(ALLTRIM(m.g_devcompany)) <= 36
  959.         \\ <<ALLTRIM(m.g_devcompany)>>
  960.         \\<<REPLICATE(" ",37-LEN(ALLTRIM(m.g_devcompany)))>>
  961.         \\<<m.g_verti2>>
  962.     ELSE
  963.         \\ <<REPLICATE(" ",37)>><<m.g_verti2>>
  964.         \*       <<m.g_verti1>> <<m.g_devcompany>>
  965.         \\<<REPLICATE(" ",56-LEN(m.g_devcompany))>><<m.g_verti2>>
  966.     ENDIF
  967.  
  968.     \*       <<m.g_verti1>> <<m.g_devaddress>>
  969.     \\<<REPLICATE(" ",56-LEN(m.g_devaddress))>><<m.g_verti2>>
  970.  
  971.     \*       <<m.g_verti1>> <<ALLTRIM(m.g_devcity)>>, <<m.g_devstate>>
  972.     \\  <<ALLTRIM(m.g_devzip)>>
  973.     \\<<REPLICATE(" ",50-(LEN(ALLTRIM(m.g_devcity)+ALLTRIM(m.g_devzip))))>>
  974.     \\<<m.g_verti2>>
  975.  
  976.     IF !INLIST(ALLTRIM(UPPER(m.g_devctry)),"USA","COUNTRY") AND !EMPTY(m.g_devctry)
  977.        \*       <<m.g_verti1>> <<ALLTRIM(m.g_devctry)>>
  978.        \\<<REPLICATE(" ",50-(LEN(ALLTRIM(m.g_devctry))))>>
  979.        \\<<m.g_verti2>>
  980.     ENDIF
  981.  
  982.     \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  983.     \*       <<m.g_verti1>> Description:
  984.     \\                                            <<m.g_verti2>>
  985.     \*       <<m.g_verti1>>
  986.     \\ This program was automatically generated by GENMENU.
  987.     \\    <<m.g_verti2>>
  988.     \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  989.     \*       <<m.g_corn3>><<REPLICATE(m.g_horiz,57)>><<m.g_corn4>>
  990.     \
  991.  
  992. *
  993. * GENFUNCHEADER - Generate Comment for Function/Procedure.
  994. *
  995. PROCEDURE genfuncheader
  996.     PARAMETER m.procname
  997.     PRIVATE m.place, m.prompt
  998.     m.g_snippcnt = m.g_snippcnt + 1
  999.     DO CASE
  1000.         CASE objtype = c_menu
  1001.             m.place = "ON SELECTION MENU _MSYSMENU"
  1002.         CASE objtype = c_submenu AND objcode = c_global
  1003.             m.place = "ON SELECTION POPUP ALL"
  1004.         CASE objtype = c_submenu AND objcode <> c_global
  1005.             m.place = "ON SELECTION POPUP "+LOWER(ALLTRIM(name))
  1006.         CASE objtype = c_item AND UPPER(levelname) = "_MSYSMENU"
  1007.             m.place = "ON SELECTION PAD "
  1008.         CASE objtype = c_item AND UPPER(levelname) <> "_MSYSMENU"
  1009.             m.place = "ON SELECTION BAR "+ALLTRIM(itemnum)+;
  1010.                 +" OF POPUP "+LOWER(ALLTRIM(levelname))
  1011.         OTHERWISE
  1012.             m.place = ""
  1013.     ENDCASE
  1014.     \
  1015.     \*       <<m.g_corn1>><<REPLICATE(m.g_horiz,57)>><<m.g_corn2>>
  1016.     \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  1017.     \*       <<m.g_verti1>> <<UPPER(PADR(m.procname,10))>>  <<m.place>>
  1018.     \\<<REPLICATE(" ",44-LEN(m.place))>><<m.g_verti2>>
  1019.     \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  1020.     \*       <<m.g_verti1>> Procedure Origin:
  1021.     \\<<REPLICATE(" ",39)>><<m.g_verti2>>
  1022.     \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  1023.     \*       <<m.g_verti1>> From Menu:
  1024.     \\  <<ALLTRIM(strippath(m.g_outfile))>>
  1025.     \\,            Record:  <<STR(RECNO(),3)>>
  1026.     \\<<REPLICATE(" ",22-LEN(ALLTRIM(strippath(m.g_outfile))+STR(RECNO(),3))))>>
  1027.     \\<<m.g_verti2>>
  1028.     \*       <<m.g_verti1>> Called By:  <<m.place>>
  1029.     \\<<REPLICATE(" ",44-LEN(m.place))>><<m.g_verti2>>
  1030.     IF NOT EMPTY(PROMPT)
  1031.         m.prompt = removemeta()
  1032.         \*       <<m.g_verti1>> Prompt:     <<ALLTRIM(m.prompt)>>
  1033.         \\<<REPLICATE(" ",44-LEN(ALLTRIM(m.prompt)))>><<m.g_verti2>>
  1034.     ENDIF
  1035.     \*       <<m.g_verti1>> Snippet:
  1036.     \\    <<ALLTRIM(STR(m.g_snippcnt,2))>>
  1037.     \\<<REPLICATE(" ",44-LEN(ALLTRIM(STR(m.g_snippcnt,2))))>><<m.g_verti2>>
  1038.     \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  1039.     \*       <<m.g_corn3>><<REPLICATE(m.g_horiz,57)>><<m.g_corn4>>
  1040.     \*
  1041.  
  1042. *
  1043. * REMOVEMETA - Remove meta characters for documentation.
  1044. *
  1045. FUNCTION removemeta
  1046.     PRIVATE m.prompt, m.hotkey
  1047.     m.prompt = PROMPT
  1048.     m.hotkey = AT("\<",m.prompt)
  1049.  
  1050.     IF m.hotkey <> 0
  1051.         m.prompt = STUFF(m.prompt,m.hotkey,2,"")
  1052.     ENDIF
  1053.  
  1054.     m.disabl = AT("\",m.prompt)
  1055.     IF m.disabl <> 0
  1056.         m.prompt = STUFF(m.prompt,m.disabl,1,"")
  1057.     ENDIF
  1058.     RETURN m.prompt
  1059.  
  1060. *
  1061. * COMMENTBLOCK - Generate a comment block.
  1062. *
  1063. PROCEDURE commentblock
  1064.     PARAMETER m.snippet
  1065.     \
  1066.     \*       <<m.g_corn1>><<REPLICATE(m.g_horiz,57)>><<m.g_corn2>>
  1067.     \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  1068.     DO CASE
  1069.         CASE m.snippet == "setup"
  1070.             \*       <<m.g_verti1>>
  1071.             \\ <<PADC(" Setup Code",56," ")>>
  1072.         CASE m.snippet == "cleanup"
  1073.             \*       <<m.g_verti1>>
  1074.             \\ <<PADC(" Cleanup Code & Procedures",56," ")>>
  1075.         CASE m.snippet == "init"
  1076.             \*       <<m.g_verti1>>
  1077.             \\ <<PADC(" Initializing Code",56," ")>>
  1078.         CASE m.snippet == "menu"
  1079.             \*       <<m.g_verti1>>
  1080.             \\ <<PADC(" Menu Definition",56," ")>>
  1081.     ENDCASE
  1082.     \\<<m.g_verti2>>
  1083.     \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  1084.     \*       <<m.g_corn3>><<REPLICATE(m.g_horiz,57)>><<m.g_corn4>>
  1085.     \*
  1086.     \
  1087.  
  1088. **
  1089. ** Supporting routines
  1090. **
  1091.  
  1092. *
  1093. * ONSELECTION - Generate ON SELECTION... statements for menu items.
  1094. *
  1095. * Description:
  1096. * For pads and bars which have no submenu associated with them but
  1097. * instead have a non-empty Command field in the database, issue
  1098. * the ON SELECTION <command> statements.  If a snippet is associated
  1099. * with a pad then issue a call statement to the generated procedure
  1100. * containing the snippet.  Generated snippet procedure will be
  1101. * appended to the end of the output file.
  1102. *
  1103. PROCEDURE onselection
  1104.     PARAMETER m.which, m.name, m.ofname, m.commd
  1105.     PRIVATE m.trimname, m.basename
  1106.     IF EMPTY(PROCEDURE) AND EMPTY(COMMAND)
  1107.         RETURN
  1108.     ENDIF
  1109.     DO CASE
  1110.         CASE m.which == "pad"
  1111.             \ON SELECTION PAD <<m.name>>
  1112.         CASE m.which == "BAR"
  1113.             \ON SELECTION <<m.which+" "+m.name>>
  1114.     ENDCASE
  1115.     \\ OF <<m.ofname>>
  1116.     IF objcode = c_proc
  1117.         DO gensnippname
  1118.         m.trimname = SYS(2014,m.g_outfile,m.g_homedir)
  1119.         m.trimname = stripext(m.trimname)
  1120.         m.basename = basename(m.trimname)
  1121.         \\ ;
  1122.         \       DO <<g_snippets[g_nsnippets,1]>> ;
  1123.         \       IN LOCFILE("<<m.trimname>>"
  1124.         \\ ,"MPX;MPR|FXP;PRG"
  1125.         \\ ,"Where is <<m.basename>>?")
  1126.     ELSE
  1127.         m.commd = COMMAND
  1128.         \\ <<m.commd>>
  1129.     ENDIF
  1130.  
  1131. *
  1132. * GENSNIPPNAME - Generate a unique name for snippet procedure.
  1133. *
  1134. * Description:
  1135. * Lookup the #NAME name of this snippet, or alternatively
  1136. * provide a unique name for a snippet of code associated with the
  1137. * generated menu.  Save this name in an array g_snippets.
  1138. *
  1139. PROCEDURE gensnippname
  1140.     g_nsnippets = g_nsnippets + 1
  1141.     g_snippets[g_nsnippets,1] = getcname(procedure)
  1142.     g_snippets[g_nsnippets,2] = RECNO()
  1143.  
  1144.     IF MOD(g_nsnippets,25) = 0
  1145.         DIMENSION g_snippets [g_nsnippets+25,2]
  1146.     ENDIF
  1147.  
  1148. *
  1149. * GENPROCCALL - Generate a call statement to snippet procedure.
  1150. *
  1151. * Description:
  1152. * Generate a call to the snippet procedure in the menu definition
  1153. * code.
  1154. *
  1155. PROCEDURE genproccall
  1156.     PRIVATE m.trimname, m.basename, m.proc
  1157.     IF singleline()
  1158.         m.proc = PROCEDURE
  1159.         \\ <<MLINE(m.proc,1)>>
  1160.     ELSE
  1161.         DO gensnippname
  1162.         m.trimname = SYS(2014,m.g_outfile,m.g_homedir)
  1163.         m.trimname = stripext(m.trimname)
  1164.         m.basename = basename(m.trimname)
  1165.         \\ ;
  1166.         \       DO <<g_snippets[m.g_nsnippets,1]>> ;
  1167.         \       IN LOCFILE("<<m.trimname>>"
  1168.         \\ ,"MPX;MPR|FXP;PRG"
  1169.         \\ ,"Where is <<m.basename>>?")
  1170.     ENDIF
  1171.  
  1172. *
  1173. * SINGLELINE - Determine if Memo contains only one line.
  1174. *
  1175. * Description:
  1176. * This procedure is used to decide if an ON SELECTION... statement
  1177. * and a snippet procedure will be needed (i.e., if more than one
  1178. * line of snippet code then its a snippet, otherwise its a command)
  1179. *
  1180. FUNCTION singleline
  1181.     PRIVATE m.size, m.i
  1182.     m.size = MEMLINES(PROCEDURE)
  1183.     IF m.size = 1
  1184.         RETURN .T.
  1185.     ENDIF
  1186.     m.i = m.size
  1187.     DO WHILE m.i > 1
  1188.         m.line = MLINE(PROCEDURE, m.i)
  1189.         IF NOT EMPTY(m.line)
  1190.             RETURN .F.
  1191.         ENDIF
  1192.         m.i = m.i - 1
  1193.     ENDDO
  1194.  
  1195. *
  1196. * GENPROCEDURES - Generate procedure/snippet code.
  1197. *
  1198. * Description:
  1199. * Generate 'PROCEDURE procedurename' statement and its body.
  1200. *
  1201. PROCEDURE genprocedures
  1202.     PRIVATE m.i
  1203.     IF m.g_graphic
  1204.         SET MESSAGE TO 'Generating procedures...'
  1205.     ENDIF
  1206.     FOR m.i = 1 TO m.g_nsnippets
  1207.         GOTO RECORD (g_snippets[m.i,2])
  1208.         DO genfuncheader WITH g_snippets[m.i,1]
  1209.         \PROCEDURE <<g_snippets[m.i,1]>>
  1210.         DO writecode WITH procedure
  1211.         \
  1212.     ENDFOR
  1213.  
  1214. *
  1215. * WRITECODE - Write contents of a memo to a low level file.
  1216. *
  1217. * Description:
  1218. * Receive a memo field as a parameter and write its contents out
  1219. * to the currently opened low level file whose handle is stored
  1220. * in the system memory variable _TEXT.  Contents of the system
  1221. * memory variable _pretext will affect the positioning of the
  1222. * generated text.
  1223. *
  1224. PROCEDURE writecode
  1225.     PARAMETER m.memo
  1226.     PRIVATE m.lines, m.i, m.thisline
  1227.     m.lines = MEMLINES(m.memo)
  1228.     _MLINE = 0
  1229.     FOR m.i = 1 TO m.lines
  1230.         m.thisline = MLINE(m.memo, 1, _MLINE)
  1231.         IF LEFT(UPPER(LTRIM(m.thisline)),5) == "#INSE"   && #INSERT
  1232.            DO GenInsertCode WITH m.thisline
  1233.         ELSE
  1234.            IF LEFT(UPPER(LTRIM(m.thisline)),5) <> "#NAME"
  1235.               \<<m.thisline>>
  1236.            ENDIF
  1237.         ENDIF
  1238.     ENDFOR
  1239.  
  1240. *
  1241. * GENSETUPCLEANUP - Generate setup/cleanup code.
  1242. *
  1243. PROCEDURE gensetupcleanup
  1244.     PARAMETER m.choice
  1245.     LOCATE FOR objtype = c_menu
  1246.     DO CASE
  1247.         CASE m.choice == "setup"
  1248.             IF EMPTY(setup)
  1249.                 RETURN
  1250.             ENDIF
  1251.             IF m.g_graphic
  1252.                 SET MESSAGE TO 'Generating Menu Setup Code...'
  1253.             ENDIF
  1254.             DO commentblock WITH m.choice
  1255.             DO writecode WITH setup
  1256.         CASE m.choice == "cleanup"
  1257.             IF EMPTY(cleanup)
  1258.                 RETURN
  1259.             ENDIF
  1260.             IF m.g_graphic
  1261.                 SET MESSAGE TO 'Generating Menu Cleanup Code...'
  1262.             ENDIF
  1263.             DO commentblock WITH m.choice
  1264.             DO writecode WITH cleanup
  1265.     ENDCASE
  1266.  
  1267. *
  1268. * STRIPEXT - Strip the extension from a file name.
  1269. *
  1270. * Description:
  1271. * Use the algorithm employed by FoxPRO itself to strip a
  1272. * file of an extension (if any): Find the rightmost dot in
  1273. * the filename.  If this dot occurs to the right of a "\"
  1274. * or ":", then treat everything from the dot rightward
  1275. * as an extension.  Of course, if we found no dot,
  1276. * we just hand back the filename unchanged.
  1277. *
  1278. * Parameters:
  1279. * filename - character string representing a file name
  1280. *
  1281. * Return value:
  1282. * The string "filename" with any extension removed
  1283. *
  1284. FUNCTION stripext
  1285.     PARAMETER m.filename
  1286.     PRIVATE m.dotpos, m.terminator
  1287.     m.dotpos = RAT(".", m.filename)
  1288.     m.terminator = MAX(RAT("\", m.filename), RAT(":", m.filename))
  1289.     IF m.dotpos > m.terminator
  1290.         m.filename = LEFT(m.filename, m.dotpos-1)
  1291.     ENDIF
  1292.     RETURN m.filename
  1293.  
  1294. *
  1295. * STRIPPATH - Strip the path from a file name.
  1296. *
  1297. * Description:
  1298. * Find positions of backslash in the name of the file.  If there is one
  1299. * take everything to the right of its position and make it the new file
  1300. * name.  If there is no slash look for colon.  Again if found, take
  1301. * everything to the right of it as the new name.  If neither slash
  1302. * nor colon are found then return the name unchanged.
  1303. *
  1304. * Parameters:
  1305. * filename - character string representing a file name
  1306. *
  1307. * Return value:
  1308. * The string "filename" with any path removed
  1309. *
  1310. FUNCTION strippath
  1311.     PARAMETER m.filename
  1312.     PRIVATE m.slashpos, m.namelen, m.colonpos
  1313.     m.slashpos = RAT("\", m.filename)
  1314.     IF m.slashpos > 0
  1315.         m.namelen  = LEN(m.filename) - m.slashpos
  1316.         m.filename = RIGHT(m.filename, m.namelen)
  1317.     ELSE
  1318.         m.colonpos = RAT(":", m.filename)
  1319.         IF m.colonpos > 0
  1320.             m.namelen  = LEN(m.filename) - m.colonpos
  1321.             m.filename = RIGHT(m.filename, m.namelen)
  1322.         ENDIF
  1323.     ENDIF
  1324.     RETURN m.filename
  1325.  
  1326. *
  1327. * BASENAME - returns strippath(stripext(filespec))
  1328. *
  1329. FUNCTION basename
  1330.     PARAMETER m.filespec
  1331.     RETURN strippath(stripext(m.filespec))
  1332.  
  1333. *
  1334. * GENINSERTCODE - Emit code from the #insert file, if any
  1335. *
  1336. PROCEDURE GenInsertCode
  1337. PARAMETER strg
  1338. PRIVATE m.word1, m.filname, m.ins_fp, m.buffer
  1339.  
  1340. IF UPPER(LEFT(LTRIM(m.strg),5)) == "#INSE"
  1341.    m.word1 = wordnum(m.strg,1)
  1342.    m.filname = SUBSTR(m.strg,LEN(m.word1)+1)
  1343.    m.filname = ALLTRIM(CHRTRAN(m.filname,CHR(9),""))
  1344.  
  1345.    * Bail out if we can't find the file either explicitly or on the DOS path
  1346.    IF !FILE(m.filname)
  1347.       filname = FULLPATH(m.filname,1)
  1348.       IF !FILE(m.filname)
  1349.          \*Insert file <<m.filname>> could not be found
  1350.          RETURN
  1351.       ENDIF
  1352.    ENDIF
  1353.  
  1354.    ins_fp = FOPEN(m.filname)
  1355.    IF ins_fp > 0
  1356.       \* Inserted from <<strippath(m.filname)>>
  1357.       DO WHILE !feof(ins_fp)
  1358.          m.buffer = fgets(ins_fp)
  1359.          \<<m.buffer>>
  1360.       ENDDO
  1361.       =fclose(m.ins_fp)
  1362.       \* End of inserted lines
  1363.    ENDIF
  1364. ENDIF
  1365.  
  1366. **
  1367. ** Code Associated with the Thermometer
  1368. **
  1369.  
  1370. *
  1371. * ACTTHERM(<text>) - Activate thermometer.
  1372. *
  1373. * Description:
  1374. * Activates thermometer.  Update the thermometer with UPDTHERM().
  1375. * Thermometer window is named "thermometer."  Be sure to RELEASE
  1376. * this window when done with thermometer.  Creates the global
  1377. * m.g_thermwidth.
  1378. *
  1379. PROCEDURE acttherm
  1380.     PARAMETER m.text
  1381.     PRIVATE m.prompt
  1382.  
  1383.     IF m.g_graphic
  1384.         m.prompt = LOWER(m.g_outfile)
  1385.         IF txtwidth(m.prompt, c_dlgface, c_dlgsize, c_dlgstyle) > 43
  1386.             DO WHILE txtwidth(m.prompt+"...", c_dlgface, c_dlgsize, c_dlgstyle) > 43
  1387.                 m.prompt = LEFT(m.prompt, LEN(m.prompt)-1)
  1388.             ENDDO
  1389.             m.prompt = m.prompt + "..."
  1390.         ENDIF
  1391.  
  1392.         DEFINE WINDOW thermomete ;
  1393.             AT  INT((SROW() - (( 5.615 * ;
  1394.             fontmetric(1, c_dlgface, c_dlgsize, c_dlgstyle )) / ;
  1395.             fontmetric(1, wfont(1,""), wfont(2,""), wfont(3,"")))) / 2), ;
  1396.             INT((SCOL() - (( 63.833 * ;
  1397.             fontmetric(6, c_dlgface, c_dlgsize, c_dlgstyle )) / ;
  1398.             fontmetric(6, wfont(1,""), wfont(2,""), wfont(3,"")))) / 2) ;
  1399.             SIZE 5.615,63.833 ;
  1400.             font c_dlgface, c_dlgsize ;
  1401.             STYLE c_dlgstyle ;
  1402.             NOFLOAT ;
  1403.             NOCLOSE ;
  1404.             NONE ;
  1405.             COLOR rgb(0, 0, 0, 192, 192, 192)
  1406.  
  1407.         ACTIVATE WINDOW thermomete NOSHOW
  1408.  
  1409.         @ 0.5,3 SAY m.text font c_dlgface, c_dlgsize STYLE c_dlgstyle
  1410.         @ 1.5,3 SAY m.prompt font c_dlgface, c_dlgsize STYLE c_dlgstyle
  1411.         @ 0.000,0.000 TO 0.000,63.833 ;
  1412.             COLOR rgb(255, 255, 255, 255, 255, 255)
  1413.         @ 0.000,0.000 TO 5.615,0.000 ;
  1414.             COLOR rgb(255, 255, 255, 255, 255, 255)
  1415.         @ 0.385,0.667 TO 5.231,0.667 ;
  1416.             COLOR rgb(128, 128, 128, 128, 128, 128)
  1417.         @ 0.308,0.667 TO 0.308,63.167 ;
  1418.             COLOR rgb(128, 128, 128, 128, 128, 128)
  1419.         @ 0.385,63.000 TO 5.308,63.000 ;
  1420.             COLOR rgb(255, 255, 255, 255, 255, 255)
  1421.         @ 5.231,0.667 TO 5.231,63.167 ;
  1422.             COLOR rgb(255, 255, 255, 255, 255, 255)
  1423.         @ 5.538,0.000 TO 5.538,63.833 ;
  1424.             COLOR rgb(128, 128, 128, 128, 128, 128)
  1425.         @ 0.000,63.667 TO 5.615,63.667 ;
  1426.             COLOR rgb(128, 128, 128, 128, 128, 128)
  1427.         @ 3.000,3.333 TO 4.231,3.333 ;
  1428.             COLOR rgb(128, 128, 128, 128, 128, 128)
  1429.         @ 3.000,60.333 TO 4.308,60.333 ;
  1430.             COLOR rgb(255, 255, 255, 255, 255, 255)
  1431.         @ 3.000,3.333 TO 3.000,60.333 ;
  1432.             COLOR rgb(128, 128, 128, 128, 128, 128)
  1433.         @ 4.231,3.333 TO 4.231,60.500 ;
  1434.             COLOR rgb(255, 255, 255, 255, 255, 255)
  1435.         m.g_thermwidth = 56.269
  1436.  
  1437.         SHOW WINDOW thermomete TOP
  1438.     ELSE
  1439.         m.prompt = SUBSTR(SYS(2014,m.g_outfile),1,48)+;
  1440.             IIF(LEN(m.g_outfile)>48,"...","")
  1441.  
  1442.         DEFINE WINDOW thermomete;
  1443.             FROM INT((SROW()-6)/2), INT((SCOL()-57)/2) ;
  1444.             TO INT((SROW()-6)/2) + 6, INT((SCOL()-57)/2) + 57;
  1445.             DOUBLE COLOR SCHEME 5
  1446.  
  1447.         ACTIVATE WINDOW thermomete NOSHOW
  1448.  
  1449.         m.g_thermwidth = 50
  1450.         @ 0,3 SAY m.text
  1451.         @ 1,3 SAY UPPER(m.prompt)
  1452.         @ 2,1 TO 4,m.g_thermwidth+4 &g_boxstrg
  1453.  
  1454.         SHOW WINDOW thermomete TOP
  1455.     ENDIF
  1456.  
  1457. *
  1458. * UPDTHERM(<percent>) - Update thermometer.
  1459. *
  1460. PROCEDURE updtherm
  1461.     PARAMETER m.percent
  1462.     PRIVATE m.nblocks, m.percent
  1463.     ACTIVATE WINDOW thermomete
  1464.     m.nblocks = (m.percent/100) * (m.g_thermwidth)
  1465.     IF m.g_graphic
  1466.         @ 3.000,3.333 TO 4.231,m.nblocks + 3.333 ;
  1467.             pattern 1 COLOR rgb(128, 128, 128, 128, 128, 128)
  1468.     ELSE
  1469.  
  1470. * CGC MMM               1994.2.21
  1471. *        @ 3,3 SAY REPLICATE("█",m.nblocks)
  1472.         @ 3,3 SAY REPLICATE("ä",m.nblocks)
  1473. * CGC MMM
  1474.  
  1475.     ENDIF
  1476.  
  1477. *
  1478. * DEACTTHERMO - Deactivate and Release thermometer window.
  1479. *
  1480. PROCEDURE deactthermo
  1481.     RELEASE WINDOW thermomete
  1482.  
  1483. **
  1484. ** Error Handling Code
  1485. **
  1486.  
  1487. *
  1488. * ERRORHANDLER - Error Processing Center.
  1489. *
  1490. PROCEDURE errorhandler
  1491.     PARAMETERS m.messg, m.lineno, m.code
  1492.     IF ERROR() = 22
  1493.         ON ERROR &onerror
  1494.         DO cleanup
  1495.         CANCEL
  1496.     ENDIF
  1497.  
  1498.     DO CASE
  1499.         CASE m.code == "Minor"
  1500.             DO errlog WITH m.messg, m.lineno
  1501.             m.g_status = 1
  1502.         CASE m.code == "Serious"
  1503.             DO errlog  WITH m.messg, m.lineno
  1504.             DO errshow WITH m.messg, m.lineno
  1505.             m.g_error = .T.
  1506.             m.g_status = 2
  1507.             ON ERROR
  1508.         CASE m.code == "Fatal"
  1509.             IF NOT m.g_nohandle
  1510.                 DO errlog  WITH m.messg, m.lineno
  1511.             ENDIF
  1512.             DO errshow WITH m.messg, m.lineno
  1513.             IF WEXIST("Thermomete") AND WVISIBLE6.269
  1514.  
  1515.      
  1516.    
  1517.     ne_Fo    000 Te
  1518.         @c_dl    <cI thermometDURE deactth m.meH m.messg, m.line 1.5,3 SAY m.prom    O)mess.333o psinen   eacti ne_Fo         CASE m.cod5,3 SAY m.     piLOR'Pbr, 255t fon      @ 2,1 TO 4, 3,3upCoWIN       @ 1,3 S  @LE6.2prom255)N      WIN       @ 1,3 SE6.2p 
  1519. * =,Elineno       COse         1,3 nenermwi COLOR rgb(128, 1     @c_dl         @ 5.231,0.667 TOY)<Sg rgb(128, 128, 12SrsbTeeftbil, 12667 TOYg, m.line 1SYS(2014,m.g_outfs 1,3@LE6OLO ;
  1520.    +31, @ 0. WI'gstyle
  1521.   yledthsty0.3rcentYg, m.l
  1522.    , 255, 255,fs 1  @ 5.231,0128andle
  1523.         .li   FROM INT((SROW()-   OW()-   OW()-   Os 1,3@LE6O5, 255)
  1524.   DO errlo  @\r * m 4A   oxstrg
  1525.  
  1526.  255, 255, 2GAtso,hA3850128andle
  1527.       
  1528.  3 SE(iR    e
  1529.   INT((SROW(.538,0.000 TO 5.5 5.5A   o , 267 T TO 4.2m.g_outfile),1,48m 5.5I)128, 1eac,0.000 ;er.
  1530. *
  1531. PROCEDURE
  1532.  255, s 1,3@LE6OLO ;
  1533.  gb(M_0 OW() ELSEM_0 OW() 8andle
  1534.       
  1535.  255, 255, 255LSEM_0 OW() 8andl EL3rcentYg, m.l
  1536.   IBLE6.269
  1537.  
  1538.     P 1p231,0  COs TO 4.20    o<cI  .269
  1539. .l
  1540.     WIN           PARAM()-GCOL 128, 128667 TOURE
  1541.  255, s 1,3@  .269
  1542. .l
  1543.     WI255,)
  1544.       LSEM   @)
  1545.       LSEM   @ 255RM1nhermom * m 4VISIBLE6.269
  1546.  
  1547.  ME2G detnC.Dr WIrmom * m 4VISIBLO 4.231,603upoo
  1548.  
  1549. g, m.lineno
  1550.       P 1p25I)1281nhermom * menReK.5, 3@LE6OL=m.g    m.g_   IF ER
  1551.             END
  1552.         @c_mO+;
  1553.          )"ont/100) *
  1554.     IF m.g_grap255, s 1,3@LE6OLO;
  1555.   Mbfile)>48,"...".26cks = (>48rgb(1    Tnlc  , 2O;
  1556.  3,3up      @ 0.000,63.
  1557. C_Llm-7 (>3l8, 128, 128)
  1558.    ont/100) NTf m.LO ;Y UPPER( m.percentandle
  1559.       m.lineno00,6, @ 0. WI'gsDUREom * menReK.5, 3@ae TO.l
  1560.     8, 128, 128,3@L5, 255)128, 128,l_ 0,100) *
  1561.     IF om * menReK.5OCEDURE updthermDUREom c  , 2O0'2RHERM(<p  , 2O;
  1562.  3,3up;
  1563.            a)>4EACT = 56menReK.5,  \mg_Pi"DIF
  1564.     ENm.gDEF 255, 255)
  1565.    DEACIIF(LEN(m.g_outfi,n8)mOSE6.2p 
  1566. * =,ElinenThermomete") AND ,6, 231,0( mfintLrrh &km.g_error = rrhSE ERROR()gDWh(.   M_0 OW() ELSEM_0 Ea,3 uN1_tlh ) 0. WI'gsty M_0 OW()centg Center m.messg, gDEFWI'gLO;cks + 3       @c_mL
  1567. * CGC D2Ointy   28,     .1
  1568.   adlb"1TIVwidth)
  1569.      255<ase theRE upwidth)
  1570.      255< 255RM1
  1571.    ldPutf  IF>P<NnmNmO<scACGC MMM
  1572. 8, 128, 128, 12;cks + 3       , @ 0. WI'
  1573.  
  1574. ssg,8, 128, 128, 12;dth)
  1575.     3       @c_mL
  1576. * IF>P<error = .T.
  1577.     Rbase,6, 231, = .T.
  1578.     O 4,m.g_tM(<1
  1579.    led.T.5, 2o
  1580.        O 4,m.     , @ 0. WI'
  1581. ",m.nbloc55,    
  1582. PROCEDth 0 OW() ELSEM      led.T.5, 2orlog  WITH 
  1583.      255<aO;LAmLO ;Y UT   LO ;Y UT   LO ;Y  DO errshow WITH leOCE    +4 &GC MMM, 128, 128)
  1584.    oig       @c_mL
  1585. * IF>P<er uN1_+0=ndle
  1586.   ITH leOCE    +4 ST(h)
  1587.      255< 2551 COLORIVwidthm.nblITH m.messg, m.lith)
  1588.     3          @c_mL
  1589. * M
  1590.  
  1591.       22
  1592.        T("e t  +4 ST(h)
  1593.          1iRcNtnsdERM(<p  , 2O;
  1594.  3T   Lssg,
  1595.     ENDIF
  1596.       tus H m.mes)
  1597. , 2oE6.< 2 t  +4 ST(htW z,H m.m COsno
  1598.            R**
  1599. ** Error Ha1iRcNtnsdERM(<p    DO<1
  1600.    ledfi,n8)mOSE     255<aO;  WIyte    ,RcNt 2oE6.< 2 t  enttHDf(tLrrh &km.g_err    @c_mAY REPtm,fn1,3nbW, moE6.< 55< e
  1601. e1 T      , @ 0. WI'ATE("█",m.nblointLr6.< 55< e
  1602. e1 T  inenrmomete") AND WVInbW, mo  @c_mL
  1603. * IF>P<.< 55< m.g_grapIF ER
  1604.    269
  1605.  
  1606.  trg
  1607.  
  1608.  25<p  m.m, 255, 255 ne_Fo   ls + 3 m.m, 25l (mp, 2o
  1609.               CASE m.c(m.g_outfi,n8)Yg, msR",oessm.l
  1610.  gDEFWI'grrshow WITfi,n8)YmsR",oessm
  1611.     IF m.g_grap25I)12     m.g_status OR
  1612. 6OLO;
  1613.   Mbf"i,aP]rAP"...".26cks = (>4l
  1614.  gDEFWI'grrsrineno
  1615.  Dth  eacti ne_Fo    COs TO 4.vm.n, 255, 2GAtso,       COseliS  @LE6.2prom25Fr5=KPe)> 4.vm.n,      i   FRO  DERIVwidthm.nblITH CbCNCP_dc'Pwd  i   FRO  DERI  o<cI  .269
  1616. cti ne_ef 
  1617.   26EE
  1618.    hr      @cOLO;
  1619.   MbRDe_Fon,     .5,3 SAY      Ih3 IDnuVm.mes8)YMbfile)>48,"..TaG deactth m.meH m.g, m.l.269
  1620. .l
  1621.        CASE y M_0 OW()centg 0 OW()centg OCEDUREWI'gs    @  WI'
  1622.  
  1623. ssg,8, n"  @c_dl   ssg
  1624.     FRO mo  @c_mL
  1625. * 0 OW() 8andl EL3r0 O      .meH m.messg, m    
  1626.            ac,0.000   pi
  1627.    +31, @ 0. WIPBv>xu
  1628. 6OLO;
  1629.   M ACE[e,>u.Ca4AnH5'
  1630. ",m.nb< 55< m.    COse         ANDok3 MPuLc @coxstrm.c          WI255,CEDUREPBv>xu
  1631. 6OLO;
  1632.   M AC
  1633.   M A  o<cI  .2r\bT M Am.messg
  1634.    1,3@  .2g, gDEFWI ls + 3 m.mineno00,6,ieTP   
  1635.  
  1636. fnctSnpi s OR
  1637. 6OLO;
  1638. , 25
  1639.  00   mes) pi
  1640.    +31,s   l
  1641.  gDEFWI'grrss OR
  1642. 6OLO;
  1643. 2GAg OCEDUREWI'gs  WI' EL    OLO;
  1644.   Ms TO.l, 25CE[e,>u.CaleOeliLO;
  1645. , 25
  1646.  00H00,63.
  1647. C_L@ 0. WI'gstyle
  1648.    MbRDe_Fon,.26cks = (>4l
  1649. no
  1650.  Dth  eacti>4l
  1651. no
  1652.  Dth  eno
  1653.  Dth  k&edt  o1MbRI* M
  1654.   tus H0LI* M
  1655.   tus H0LI*LO;nUeEm5RM1 2O0Dth  eno
  1656.  D
  1657.         @c_mO+F>P<ln o=(F68, >P<er uN1_+0=nd( m2GAg OCEDUR1_+0=nd( m2GM(<p    DO<1
  1658.    lO;nUeEm5 4VISIBLAg O6, @ 0.   
  1659.  3 SE(iR    er m.mesee2 t nt/100) NTf<+)
  1660.   D     2GAtso,hA3850128e,6, 231, = .I' EL    OLO;
  1661.   gTE7 (>3 uN1_+0=nd( N1SIBLO 4.231,603s = (>4l
  1662.  gDE'ATE("█",m.ls +   RpR",oessm
  1663.     IF mEM  hSE ERROR()gDWh(.Mi4    Dth  eag,
  1664.     ENDI0=nd( N1SIBLriYg  RpR",oes .26lm-7 (>y      M"6Ch&5bg <nH5' #+ 6'aNSx2O;nter m.messg, gDEITH CbCNCPcb'R OW()    2S1
  1665.     o<cI  .26m.g)Ei xDTO 4.H CuVm.mes8)YMbfi
  1666.    ledfi,nnReK.5, 3.5OCEDURE updther
  1667.    1m.gEFWI ls + 3 m.miEM_0E E  eacti>4l, 25meH m.p    DO<  @c_mL
  1668. fing3I,6,uiA7isO;
  1669.   gTE7 ,uiA7isO;
  1670.  c_mO+F>P<ln o=(F6
  1671.   gTE7E7 ,uiA7isO;
  1672.  EM_ TO 4.vm.n, 255, <amL
  1673. omn.obEsHnml, 2  gTE7 ;Y 4pw ) 26_+0=nd( m2GM(<p  8, H;
  1674.  3,3up;
  1675.      iLOR3,n   M"6Ch&5bg <nH5CteSa& C2O;2tIHnHL P UeEl r1aoA).26"M"6Ch&5I  oadlb"1TIFl <nu.CaLwp=
  1676.  c=
  1677.  c=
  1678. Em5RM1 2OuN1_+0=nd 2OuN1_
  1679.  3,3up128, 128, 12;dthxN1_
  1680.  c_mO+F>P<ln o='tHrn3  iL
  1681.  3 SE(iR    er m;dthxNN(LENRI* MiL
  1682.  3 SIR  v>xuL
  1683.  Miu
  1684. 6O MiL
  1685. Nv>xuL
  1686. S1
  1687.     OLO;
  1688.   gLENiL
  1689.  3 SIR  v>O MiL
  1690. Nv>xuL
  1691. S1
  1692. iL
  1693.  3 SIR  31,603s =5, 2orlog  WITH 3s uL
  1694.  Miu
  1695. 6O MiL
  1696. NSdhxNor = .T.b1 Miui,aa+
  1697.  3 ) 2 255<6O MiL
  1698. NS8, 12;dthp 
  1699.  MiL
  1700. Nv>xuL
  1701. S1
  1702. itN,  e")8, 11,603s =5, 2oAg O6='tHr2O;f tEt,Lr> IF>Pl, 2  gTE7 ;meswidth)
  1703.      255<8, 1 LssDthnkm.g_;Y    O 4,m.g_t<1
  1704.    led.T.5, 2obEMcDO 
  1705.  tuL
  1706. S1
  1707. itN,h 0.rfnaToR(5oceF(ti,( N1S3 uNMM, 128, 128)
  1708.   tuL
  1709. S1
  1710. i
  1711.    ,603s =5, 2 2 2 2 2 I>Iw 2 1
  1712. iiiiiiiiii"e3 STH YOieeEm5ti,( N1IHnHL P UeEl r1aoo  +yl1eN        Ih3.p    DI f'ERI O;f t
  1713.  3,e IhrmO 4,m.g_tM(<1
  1714.    uiAttHI>I   i("e t  +S8, +0=.gEFWI ls + ibre( N1IHnHL P UeEl uL
  1715. InEl uL
  1716. InEl    255< 25 eaco0LGuL
  1717. Fipo 12;
  1718.     a
  1719. InInEl e( N.T.b1 Miui,aa+
  1720.  3ete5
  1721. 6O MiLY Us)Emi <p,6,*
  1722. Inile)>    2S1 Dt_mL
  1723. * IF>P<er< 25 eacobatA(<p 3ethrmO 4,m.glm-7uL
  1724. Fip'ttN6O 11,603s =5, 2oAg<P0trcE*IF>P< 2 2@c_Ag<P0t.TaG deacts)Em