home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgLangD.iso / FOXP-WIN.300 / DISK5 / VFP5.CAB / GENMENU.PRG < prev    next >
Encoding:
Text File  |  1995-01-11  |  58.6 KB  |  2,025 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. * Modified for FoxPro 3.0 by DTA.
  23. *
  24. PARAMETER m.projdbf, m.recno
  25. PRIVATE ALL
  26. IF SET("TALK") = "ON"
  27.     SET TALK OFF
  28.     m.talkstate = "ON"
  29. ELSE
  30.     m.talkstate = "OFF"
  31. ENDIF
  32. m.escape = SET("ESCAPE")
  33. SET ESCAPE OFF
  34.  
  35. m.trbetween = SET("TRBET")
  36. SET TRBET OFF
  37. m.comp = SET("COMPATIBLE")
  38. SET COMPATIBLE OFF
  39. mdevice = SET("DEVICE")
  40. SET DEVICE TO SCREEN
  41.  
  42. *
  43. * Declare Constants
  44. *
  45. #DEFINE c_esc    CHR(27)
  46. #DEFINE c_null    CHR(0)
  47. #DEFINE c_aliaslen 10
  48. *
  49. * Possible values of Objtype field in SCX database.
  50. *
  51. #DEFINE c_menu        1
  52. #DEFINE c_submenu    2
  53. #DEFINE c_item        3
  54.  
  55. *
  56. * Some of the values of Objcode field in SCX database.
  57. *
  58. #DEFINE    c_global    1
  59. #DEFINE c_proc        80
  60.  
  61. #DEFINE c_maxsnippets    25
  62. #DEFINE c_maxpads        25
  63. #DEFINE c_pjx20flds        33
  64. #DEFINE c_pjxflds        26
  65. #DEFINE c_mnxflds        23
  66. #DEFINE c_20mnxflds        22
  67.  
  68. #DEFINE c_authorlen        45
  69. #DEFINE c_complen        45
  70. #DEFINE c_addrlen        45
  71. #DEFINE c_citylen        20
  72. #DEFINE c_statlen        5
  73. #DEFINE c_ziplen        10
  74. #DEFINE c_countrylen 40
  75.  
  76. #DEFINE c_error_1        "Minor"
  77. #DEFINE c_error_2        "Serious"
  78. #DEFINE c_error_3        "Fatal"
  79.  
  80. IF _MAC
  81.    m.g_dlgface     =    "Geneva"
  82.    m.g_dlgsize     =    10.000
  83.    m.g_dlgstyle =        ""
  84. ELSE
  85.    m.g_dlgface     =    "MS Sans Serif"
  86.    m.g_dlgsize     =    8.000
  87.    m.g_dlgstyle =        "B"
  88. ENDIF
  89.  
  90. #DEFINE c_replace        0
  91. #DEFINE c_append        1
  92. #DEFINE c_before        2
  93. #DEFINE c_after            3
  94.  
  95. #DEFINE c_pathsep  "\"
  96.  
  97. * -dta [BEG] Add support for negotiate
  98. #DEFINE c_neg_flag      "LOCATION"
  99. #DEFINE c_neg_left      1
  100. #DEFINE c_neg_middle    2
  101. #DEFINE c_neg_right     3
  102. * -dta [END] Add support for negotiate
  103.  
  104. * -dta [BEG] Add localization support
  105. #DEFINE c_hdr_author    "Author's Name"
  106. #DEFINE c_hdr_company   "Company Name"
  107. #DEFINE c_hdr_address   "Address"
  108. #DEFINE c_hdr_city      "City"
  109. #DEFINE c_hdr_state     "  "
  110. #DEFINE c_hdr_zip       "Zip"
  111. #DEFINE c_hdr_ctry      "Country"
  112.  
  113. #DEFINE c_hdr_copyright Copyright (c)
  114. #DEFINE c_hdr_descript  Description:
  115. #DEFINE c_hdr_string    This program was automatically generated by GENMENU.
  116.  
  117. #DEFINE c_snip_setup   " Setup Code"
  118. #DEFINE c_snip_cleanup " Cleanup Code & Procedures"
  119. #DEFINE c_snip_init    " Initializing Code"
  120. #DEFINE c_snip_menu    " Menu Definition"
  121.  
  122. #DEFINE c_err_invnumparm     "Invalid number of parameters passed to the generator."
  123. #DEFINE c_err_badgendate     "Generator out of date."
  124. #DEFINE c_err_badrechead     "Missing header record in "
  125. #DEFINE c_err_nocloseapp     "Unable to Close the Application File."
  126. #DEFINE c_err_badmnxpre      "Menu "
  127. #DEFINE c_err_badmnxpost     " is invalid"
  128. #DEFINE c_err_nofileopen     "Cannot open file "
  129. #DEFINE c_err_badnegoval     "Invalid negotiate value in field "
  130. #DEFINE c_err_title          "Genmenu Error"
  131. #DEFINE c_err_lineno         "Line Number: "
  132. #DEFINE c_err_presskey       "Press any key to cleanup and exit..."
  133. #DEFINE c_err_noopenerr      ".ERR could not be opened..."
  134.  
  135. #DEFINE c_msg_gencomplete    "Generation Complete"
  136. #DEFINE c_msg_genmenudefs    "Generating menu definitions..."
  137. #DEFINE c_msg_genpopdefs     "Generating popup definitions..."
  138. #DEFINE c_msg_genprocs       "Generating procedures..."
  139. #DEFINE c_msg_gensetup       "Generating Menu Setup Code..."
  140. #DEFINE c_msg_gencleanup     "Generating Menu Cleanup Code..."
  141. #DEFINE c_msg_genstopped     "Generation process stopped."
  142. #DEFINE c_msg_genmenucode    "Generating Menu Code..."
  143.  
  144. #DEFINE c_ui_whereis         Where is
  145. * -dta [END] Add localization support
  146.  
  147.  
  148. *
  149. * Declare Variables
  150. *
  151. STORE "" TO m.cursor, m.consol, m.bell, m.onerror, m.fields, mfieldsto, ;
  152.     m.exact, m.print, m.fixed, m.delimiters, m.mpoint, m.mcollate,m.mmacdesk
  153. STORE 0 TO m.deci, m.memowidth
  154.  
  155. m.g_error      = .F.
  156. m.g_errlog     = ""
  157. m.g_homedir    = ""
  158. m.g_location   = 0
  159. m.g_menucolor  = 0
  160. m.g_menumark   = ""
  161. m.g_nohandle   = .T.
  162. m.g_nsnippets  = 0
  163. m.g_outfile    = ""
  164. m.g_padloca    = ""
  165. m.g_projalias  = ""
  166. m.g_projdbf    = m.projdbf
  167. m.g_projpath   = ""
  168. m.g_status     = 0
  169. m.g_snippcnt   = 0
  170. m.g_thermwidth = 0
  171. m.g_workarea   = 0
  172. m.g_graphic    = .F.
  173. m.g_20mnx       = .F.
  174.  
  175. m.g_devauthor  = PADR( c_hdr_author ,45," ")
  176. m.g_devcompany = PADR( c_hdr_company ,45, " ")
  177. m.g_devaddress = PADR( c_hdr_address ,45," ")
  178. m.g_devcity    = PADR( c_hdr_city ,20," ")
  179. m.g_devstate   = c_hdr_state
  180. m.g_devzip     = PADR( c_hdr_zip ,10," ")
  181. m.g_devctry    = PADR( c_hdr_ctry ,40," ")
  182.  
  183. m.g_boxstrg = ['─','─','│','│','┌','┐','└','┘','─','─','│','│','┌','┐','└','┘']
  184.  
  185. STORE "" TO m.g_corn1, m.g_corn2, m.g_corn3, m.g_corn4, m.g_corn5, ;
  186.     m.g_corn6, m.g_verti2
  187. STORE "*" TO  m.g_horiz, m.g_verti1
  188.  
  189. *
  190. * Array Declarations
  191. *
  192. * g_mnxfile [1] - Normalized path + name
  193. * g_mnxfile [2] - Basename
  194. * g_mnxfile [3] - Opened originally?
  195. * g_mnxfile [4] - Alias
  196. *
  197. DIMENSION g_mnxfile[4]
  198. g_mnxfile[1] = ""
  199. g_mnxfile[2] = ""
  200. g_mnxfile[3] = .F.
  201. g_mnxfile[4] = ""
  202.  
  203. *
  204. * g_pads - names of generated menu pads
  205. *
  206. DIMENSION g_pads(c_maxpads)
  207.  
  208. *
  209. * g_snippets [*,1] - generated snippet procedure name
  210. * g_snippets [*,2] - recno()
  211. *
  212.  
  213. DIMENSION g_snippets (c_maxsnippets,2)
  214. g_snippets = ""
  215.  
  216. IF AT("WINDOWS", UPPER(VERSION())) <> 0 OR ;
  217.         AT("MAC", UPPER(VERSION())) <> 0
  218.     m.g_graphic = .T.
  219. ELSE
  220.     m.g_graphic = .F.
  221. ENDIF
  222.  
  223. *
  224. * Main program
  225. *
  226. m.onerror = ON("ERROR")
  227. ON ERROR DO errorhandler WITH MESSAGE(), LINENO(), c_error_3
  228.  
  229. IF PARAMETERS()=2
  230.     DO setup
  231.     IF validparams()
  232.         ON ESCAPE DO eschandler
  233.         SET ESCAPE ON
  234.         DO refreshprefs
  235.         DO BUILD
  236.     ENDIF
  237.     DO cleanup
  238. ELSE
  239.     DO errorhandler WITH c_err_invnumparm, LINENO(),c_error_3
  240. ENDIF
  241. ON ERROR &onerror
  242.  
  243. RETURN m.g_status
  244.  
  245. **
  246. ** Setup, Cleanup, Validparams, and Refreshprefs of Main Program
  247. **
  248.  
  249. *
  250. * STARTUP - Create program's environment.
  251. *
  252. * Description:
  253. * Save the user's environment so that we can set it back when
  254. * we are done, then issue various SET commands. The only state
  255. * we cannot conveniently save is SET TALK, because storing the
  256. * state involves an assignment statement, and assignments
  257. * generate unwanted output if TALK is set ON.
  258. *
  259. * Side Effects:
  260. * Creates a temporary file which is deleted in the Cleanup
  261. * procedure executed at the end of MENUGEN.
  262. *
  263. PROCEDURE setup
  264.     CLEAR PROGRAM
  265.     CLEAR GETS
  266.     m.g_workarea = SELECT()
  267.     m.delimiters = SET('TEXTMERGE',1)
  268.     SET TEXTMERGE DELIMITERS TO
  269.     SET UDFPARMS TO VALUE
  270.  
  271.     m.mfieldsto = SET("FIELDS",1)
  272.     m.fields = SET("FIELDS")
  273.     SET FIELDS TO
  274.     SET FIELDS OFF
  275.     m.bell = SET("BELL")
  276.     SET BELL OFF
  277.     m.consol = SET("CONSOLE")
  278.     SET CONSOLE OFF
  279.     m.cursor = SET("CURSOR")
  280.     SET CURSOR OFF
  281.     m.deci = SET("DECIMALS")
  282.     SET DECIMALS TO 0
  283.     mdevice = SET("DEVICE")
  284.     SET DEVICE TO SCREEN
  285.     m.memowidth = SET("MEMOWIDTH")
  286.     SET MEMOWIDTH TO 256
  287.     m.exact = SET("EXACT")
  288.     SET EXACT ON
  289.     m.print = SET("PRINT")
  290.     SET PRINT OFF
  291.     m.fixed = SET("FIXED")
  292.     SET FIXED ON
  293.     mpoint = SET("POINT")
  294.     SET POINT TO "."
  295.     mcollate = SET("COLLATE")
  296.     SET COLLATE TO "machine"
  297.      #if "MAC" $ UPPER(VERSION(1))
  298.         IF _MAC
  299.            m.mmacdesk = SET("MACDESKTOP")
  300.            SET MACDESKTOP ON
  301.        ENDIF
  302.      #endif
  303. *
  304. * CLEANUP - restore environment to pre-execution state.
  305. *
  306. * Description:
  307. * Close all databases opened in the course of the execution of MENUGEN.
  308. * Restore the environment to the pre-execution of MENUGEN.  Delete
  309. * the VIEW file since there is no further use for it.
  310. *
  311. * Side Effects:
  312. * Closes databases.
  313. * Deletes the temporary view file.
  314. *
  315. PROCEDURE cleanup
  316.     PRIVATE m.delilen, m.ldelimi, m.rdelimi
  317.     IF EMPTY(m.g_projalias)
  318.         RETURN
  319.     ENDIF
  320.     SELECT (m.g_projalias)
  321.     USE
  322.     IF NOT EMPTY(g_mnxfile[3])
  323.         IF USED(g_mnxfile[4])
  324.             SELECT (g_mnxfile[4])
  325.             USE
  326.         ENDIF
  327.     ENDIF
  328.     SELECT (m.g_workarea)
  329.  
  330.     m.delilen = LEN(m.delimiters)
  331.     m.ldelimi = SUBSTR(m.delimiters,1,;
  332.         IIF(MOD(m.delilen,2)=0,m.delilen/2,CEILING(m.delilen/2)))
  333.     m.rdelimi = SUBSTR(m.delimiters,;
  334.         IIF(MOD(m.delilen,2)=0,m.delilen/2+1,CEILING(m.delilen/2)+1))
  335.     SET TEXTMERGE DELIMITERS TO m.ldelimi, m.rdelimi
  336.  
  337.    IF (LEN(mfieldsto) > 2048)
  338.       SET FIELDS TO
  339.    ELSE
  340.        SET FIELDS TO &mfieldsto
  341.    ENDIF
  342.  
  343.     IF m.fields = "ON"
  344.            SET FIELDS ON
  345.     ELSE
  346.            SET FIELDS OFF
  347.     ENDIF
  348.     IF m.bell = "ON"
  349.         SET BELL ON
  350.     ENDIF
  351.     IF m.cursor = "ON"
  352.         SET CURSOR ON
  353.     ELSE
  354.         SET CURSOR OFF
  355.     ENDIF
  356.     IF m.consol = "ON"
  357.         SET CONSOLE ON
  358.     ENDIF
  359.     IF m.escape = "ON"
  360.         SET ESCAPE ON
  361.     ELSE
  362.         SET ESCAPE OFF
  363.     ENDIF
  364.     IF m.print = "ON"
  365.         SET PRINT ON
  366.     ENDIF
  367.     IF m.exact = "OFF"
  368.         SET EXACT OFF
  369.     ENDIF
  370.     IF m.fixed = "OFF"
  371.         SET FIXED OFF
  372.     ENDIF
  373.     SET DECIMALS TO m.deci
  374.     SET MEMOWIDTH TO m.memowidth
  375.     SET DEVICE TO &mdevice
  376.     IF m.trbetween = "ON"
  377.         SET TRBET ON
  378.     ENDIF
  379.     IF m.comp = "ON"
  380.         SET COMPATIBLE ON
  381.     ENDIF
  382.     IF m.talkstate = "ON"
  383.         SET TALK ON
  384.     ENDIF
  385.     SET POINT TO "&mpoint"
  386.     SET COLLATE TO "&mcollate"
  387.     SET MESSAGE TO
  388.     #if "MAC" $ UPPER(VERSION(1))
  389.         IF _MAC
  390.           SET MACDESKTOP &mmacdesk
  391.         ENDIF
  392.     #endif
  393.  
  394.     ON ERROR &onerror
  395.  
  396.  
  397. *
  398. * VALIDPARAMS - Validate generator parameters.
  399. *
  400. * Description:
  401. * Attempt to open the project database.  If error encountered then
  402. * on error routine takes over and issues 'CANCEL'.  The output file
  403. * cannot be erased, name not known.
  404. *
  405. FUNCTION validparams
  406.     SELECT 0
  407.     m.g_projalias = IIF(USED("projdbf"),"P"+;
  408.         SUBSTR(LOWER(SYS(3)),2,8),"projdbf")
  409.         
  410.     USE (m.projdbf) ALIAS (m.g_projalias) AGAIN
  411.     
  412.     IF versnum() > "2.5"
  413.        SET NOCPTRANS TO devinfo, symbols, object
  414.     ENDIF
  415.  
  416.     m.g_errlog = stripext(m.projdbf)
  417.     m.g_projpath = SUBSTR(m.projdbf,1,RAT("\",m.projdbf))
  418.  
  419.     IF FCOUNT() <> c_pjxflds
  420.         DO errorhandler WITH c_err_badgendate,LINENO(), c_error_2
  421.         RETURN .F.
  422.     ENDIF
  423.  
  424.     GOTO RECORD m.recno
  425.  
  426.     m.g_outfile = ALLTRIM(SUBSTR(outfile,1,AT(c_null,outfile)-1))
  427.     m.g_outfile = FULLPATH(m.g_outfile, m.g_projpath)
  428.     IF _MAC AND RIGHT(m.g_outfile,1) = ":"
  429.        m.g_outfile = m.g_outfile + justfname(SUBSTR(outfile,1,AT(c_null,outfile)-1))
  430.     ENDIF
  431.     g_mnxfile[1] = FULLPATH(ALLTRIM(name), m.g_projpath)
  432.     IF _MAC AND RIGHT(g_mnxfile[1],1) = ":"
  433.        g_mnxfile[1] = g_mnxfile[1] + justfname(name)
  434.     ENDIF
  435.     g_mnxfile[2] = basename(g_mnxfile[1])
  436.  
  437. *
  438. * REFRESHPREFS - Refresh comment style and developer preferences.
  439. *
  440. * Description:
  441. * Get the newest preferences for documentation style and developer
  442. * data from the project database.
  443. *
  444. PROCEDURE refreshprefs
  445.     PRIVATE m.start, m.savrecno
  446.     m.savrecno = RECNO()
  447.     LOCATE FOR TYPE = "H"
  448.     IF NOT FOUND ()
  449.         DO errorhandler WITH c_err_badrechead + m.g_projdbf,;
  450.             LINENO(), c_error_2
  451.         GOTO RECORD m.savrecno
  452.         RETURN
  453.     ENDIF
  454.  
  455.     m.g_homedir = ALLTRIM(SUBSTR(homedir,1,AT(c_null,homedir)-1))
  456.     IF (RIGHT(m.g_homedir, 1) == "\")
  457.         m.g_homedir = m.g_homedir + "\"
  458.     ENDIF
  459.  
  460.     m.start = 1
  461.     m.g_devauthor = subdevinfo(m.start,c_authorlen,m.g_devauthor)
  462.  
  463.     m.start = m.start + c_authorlen + 1
  464.     m.g_devcompany = subdevinfo(m.start,c_complen,m.g_devcompany)
  465.  
  466.     m.start = m.start + c_complen + 1
  467.     m.g_devaddress = subdevinfo(m.start,c_addrlen,m.g_devaddress)
  468.  
  469.     m.start = m.start + c_addrlen + 1
  470.     m.g_devcity = subdevinfo(m.start,c_citylen,m.g_devcity)
  471.  
  472.     m.start = m.start + c_citylen + 1
  473.     m.g_devstate = subdevinfo(m.start,c_statlen,m.g_devstate)
  474.  
  475.     m.start = m.start + c_statlen + 1
  476.     m.g_devzip = subdevinfo(m.start,c_ziplen,m.g_devzip)
  477.  
  478.     m.start = m.start + c_ziplen + 1
  479.     m.g_devctry = subdevinfo(m.start,c_countrylen,m.g_devctry)
  480.  
  481.     IF cmntstyle = 0
  482.         m.g_corn1 = "╓"
  483.         m.g_corn2 = "╖"
  484.         m.g_corn3 = "╙"
  485.         m.g_corn4 = "╜"
  486.         m.g_corn5 = "╟"
  487.         m.g_corn6    = "╢"
  488.         m.g_horiz = "─"
  489.         m.g_verti1 = "║"
  490.         m.g_verti2 = "║"
  491.     ENDIF
  492.     GOTO RECORD m.savrecno
  493.  
  494. *
  495. * SUBDEVINFO - Substring the DEVINFO memo filed.
  496. *
  497. FUNCTION subdevinfo
  498.     PARAMETER m.start, m.stop, m.default
  499.     PRIVATE m.string
  500.     m.string = SUBSTR(devinfo, m.start, m.stop+1)
  501.     m.string = SUBSTR(m.string, 1, AT(c_null,m.string)-1)
  502.     RETURN IIF(EMPTY(m.string), m.default, m.string)
  503.  
  504. **
  505. ** Menu Code Generator's Main Module.
  506. **
  507.  
  508. *
  509. * BUILD - Generate code for a menu.
  510. *
  511. * Description:
  512. * Call BUILDENABLE to open .MNX database specified by the user.
  513. * If the above is successfully accomplished, then proceed to generate
  514. * the menu code.  After the menu code is generated, call BUILDDISABLE
  515. * to disable code generation between SET TEXTMERGE ON and
  516. * SET TEXTMERGE OFF.
  517. *
  518. PROCEDURE BUILD
  519.     IF NOT buildenable()
  520.         RETURN
  521.     ENDIF
  522.     DO acttherm WITH c_msg_genmenucode
  523.     DO updtherm WITH 10
  524.  
  525.     DO HEADER
  526.     DO gensetupcleanup WITH "setup"
  527.     DO definemenu
  528.     DO definepopups
  529.     DO updtherm WITH 75
  530.     DO globaldefaults
  531.     DO updtherm WITH 95
  532.     DO gensetupcleanup WITH "cleanup"
  533.     DO genprocedures
  534.  
  535.     IF m.g_graphic
  536.         SET MESSAGE TO c_msg_gencomplete
  537.     ENDIF
  538.     DO builddisable
  539.     DO updtherm WITH 100
  540.     DO deactthermo
  541.  
  542. *
  543. * BUILDENABLE - Enable code generation.
  544. *
  545. * Description:
  546. * Call opendb to open .MNX database.
  547. * Call openfile to open file to hold the generated program.
  548. * If error(s) encountered in opendb or openfile then don't do
  549. * anything and exit, otherwise enable code generation with the
  550. * SET TEXTMERGE ON command.
  551. *
  552. * Returns:
  553. * .T. on success; .F. on failure
  554. *
  555. FUNCTION buildenable
  556.     PRIVATE m.stat
  557.     m.stat = opendb(g_mnxfile[1]) AND openfile()
  558.     IF m.stat
  559.         SET TEXTMERGE ON
  560.     ENDIF
  561.     RETURN m.stat
  562.  
  563. *
  564. * BUILDDISABLE - Disable code generation.
  565. *
  566. * Description:
  567. * Issue the command SET TEXTMERGE OFF.
  568. * Close the generated menu code output file.
  569. * If anything goes wrong display appropriate message to the user.
  570. *
  571. PROCEDURE builddisable
  572.     SET ESCAPE OFF
  573.     ON ESCAPE
  574.     SET TEXTMERGE OFF
  575.     IF NOT FCLOSE(_TEXT)
  576.         DO errorhandler WITH c_err_nocloseapp, LINENO(), c_error_2
  577.     ENDIF
  578.  
  579. *
  580. * OPENDB - Prepare database for processing.
  581. *
  582. * Description:
  583. * Attempt to USE a database.  If attempt fails and error is reported
  584. * call ERRORHANDLER routine to display a friendly message.  Return
  585. * with a status of .F..  If attempt succeeds, return with status of .T.
  586. *
  587. * Returns:
  588. * .T. on success; .F. on failure
  589. *
  590. FUNCTION opendb
  591.     PARAMETER m.dbname
  592.     PRIVATE m.dbalias
  593.     ON ERROR DO errorhandler WITH MESSAGE(), LINENO(), c_error_2
  594.  
  595.     m.dbalias = LEFT(basename(m.dbname),c_aliaslen)
  596.     IF USED (m.dbalias)
  597.         SELECT (m.dbalias)
  598.         IF RAT(".MNX",DBF())<>0
  599.             g_mnxfile[3] = .F.
  600.             g_mnxfile[4] = m.dbalias
  601.         ELSE
  602.             g_mnxfile[4] = "M"+SUBSTR(LOWER(SYS(3)),2,8)
  603.             SELECT 0
  604.             USE (m.dbname) AGAIN ALIAS (g_mnxfile[4])
  605.             g_mnxfile[3] = .T.
  606.         ENDIF
  607.     ELSE
  608.         IF illegalname(m.dbalias)
  609.             g_mnxfile[4] = "M"+SUBSTR(LOWER(SYS(3)),2,8)
  610.         ELSE
  611.             g_mnxfile[4] = m.dbalias
  612.         ENDIF
  613.         SELECT 0
  614.         USE (m.dbname) AGAIN ALIAS (g_mnxfile[4])
  615.         g_mnxfile[3] = .T.
  616.     ENDIF
  617.  
  618.     IF FCOUNT() <> c_mnxflds
  619.         IF FCOUNT() = c_20mnxflds
  620.             m.g_20mnx = .T.
  621.         ELSE
  622.             DO errorhandler WITH c_err_badmnxpre + m.dbalias + c_err_badmnxpost, ;
  623.                LINENO(), c_error_2
  624.             RETURN .F.
  625.         ENDIF
  626.     ELSE
  627.         m.g_20mnx = .F.
  628.     ENDIF
  629.  
  630.     ON ERROR DO errorhandler WITH MESSAGE(), LINENO(), c_error_3
  631.     IF m.g_error = .T.
  632.         RETURN .F.
  633.     ENDIF
  634.  
  635. *
  636. * ILLEGALNAME - Check if default alias will be used when this
  637. *               database is USEd. (i.e., 1st letter is not A-Z,
  638. *                a-z or '_', or any one of ramaining letters is not
  639. *                alphanumeric.)
  640. *
  641. FUNCTION illegalname
  642.     PARAMETER m.menuname
  643.     PRIVATE m.start, m.aschar, m.length
  644.     m.length = LEN(m.menuname)
  645.     m.start  = 0
  646.     IF m.length = 1
  647.         *
  648.         * If length 1, then check if default alias can be used,
  649.         * i.e., name is different than A-J and a-j.
  650.         *
  651.         m.aschar = ASC(m.menuname)
  652.         IF (m.aschar >= 65 AND m.aschar <= 74) OR ;
  653.                 (m.aschar >= 97 AND m.aschar <= 106)
  654.             RETURN .T.
  655.         ENDIF
  656.     ENDIF
  657.     DO WHILE m.start < m.length
  658.         m.start  = m.start + 1
  659.         m.aschar = ASC(SUBSTR(m.menuname, m.start, 1))
  660.         IF m.start<>1 AND (m.aschar >= 48 AND m.aschar <= 57)
  661.             LOOP
  662.         ENDIF
  663.         IF NOT ((m.aschar >= 65 AND m.aschar <= 90) OR ;
  664.                 (m.aschar >= 97 AND m.aschar <= 122) OR m.aschar = 95)
  665.             RETURN .T.
  666.         ENDIF
  667.     ENDDO
  668.     RETURN .F.
  669.  
  670. *
  671. * OPENFILE - Create and open the application output file.
  672. *
  673. * Description:
  674. * Create a file that will hold the generated menu code.
  675. * Open the newly created file.  If error(s) encountered
  676. * at any time issue an error message and return .F.
  677. *
  678. * Returns:
  679. * .T. on success; .F. on failure
  680. *
  681. FUNCTION openfile
  682.     PRIVATE m.msg
  683.     _TEXT = FCREATE(m.g_outfile)
  684.     IF (_TEXT = -1)
  685.         m.msg = c_err_nofileopen + m.g_outfile
  686.         DO errorhandler WITH m.msg, LINENO(), c_error_3
  687.         m.g_nohandle = .T.
  688.         RETURN .F.
  689.     ENDIF
  690.     m.g_nohandle = .F.
  691.  
  692. *
  693. * DEFINEMENU - Define main menu and its pads.
  694. *
  695. * Description:
  696. * Issue DEFINE MENU ... command.
  697. * Call a procedure to define all menu pads.
  698. * Call a procedure to generate ON PAD statements when appropriate.
  699. *
  700. PROCEDURE definemenu
  701.  
  702.     IF m.g_graphic
  703.         SET MESSAGE TO c_msg_genmenudefs
  704.     ENDIF
  705.     DO commentblock WITH "menu"
  706.     SELECT (g_mnxfile[4])
  707.     LOCATE FOR objtype = c_menu
  708.     m.g_location = location
  709.     m.g_padloca  = ALLTRIM(name)
  710.  
  711.     LOCATE FOR objtype = c_submenu AND objcode = c_global
  712.  
  713.     m.g_menucolor = SCHEME
  714.     m.g_menumark  = MARK
  715.     IF m.g_location = c_replace
  716.         \SET SYSMENU TO
  717.         \
  718.     ENDIF
  719.     \SET SYSMENU AUTOMATIC
  720.     \
  721.  
  722.     DO updtherm WITH 25
  723.     DO defmenupads
  724.     DO updtherm WITH 35
  725.     DO defonpad
  726.     \
  727.     DO updtherm WITH 45
  728.  
  729. *
  730. * DEFMENUPADS - Define all pads for the menu bar.
  731. *
  732. * Description:
  733. * Scan the menu database for all objects of the type item which
  734. * have the levelname=_MSYSMENU.
  735. * For each such item, generate a statement DEFINE PAD... where
  736. * the name of the pad is the contents of NAME field or (if Name
  737. * field is empty) an automatically generated name.
  738. * Call procedures addkey, addskipfor, and mark to generate
  739. * KEY, SKIPFOR, or MARK clauses when appropriate.
  740. *
  741. PROCEDURE defmenupads
  742.     PRIVATE m.padname, m.prompt
  743. * -dta [BEG] Add support for negotiate
  744.     LOCAL lcNegotiate
  745. * -dta [END] Add support for negotiate    
  746.     SCAN FOR objtype=c_item AND UPPER(levelname)="_MSYSMENU"
  747.         IF NOT EMPTY(ALLTRIM(name))
  748.             g_pads[VAL(Itemnum)] = name
  749.         ELSE
  750.             g_pads[VAL(Itemnum)] = LOWER(SYS(2015))
  751.         ENDIF
  752.         \DEFINE PAD <<g_pads[VAL(Itemnum)]>> OF _MSYSMENU
  753.  
  754.         IF MOD(VAL(itemnum),25)=0
  755.             DIMENSION g_pads[VAL(Itemnum)+25]
  756.         ENDIF
  757.         m.prompt = SUBSTR(PROMPT,1,LEN(PROMPT))
  758.         \\ PROMPT "<<m.prompt>>"
  759.         \\ COLOR SCHEME <<m.g_menucolor>>
  760.  
  761.         IF m.g_menumark<>c_null AND m.g_menumark<>""
  762.             \\ ;
  763.             \    MARK "<<m.g_menumark>>"
  764.         ENDIF
  765.  
  766.         DO CASE
  767.             CASE m.g_location = c_before
  768.                 \\ ;
  769.                 \    BEFORE <<m.g_padloca>>
  770.             CASE m.g_location = c_after
  771.                 \\ ;
  772.                 \    AFTER
  773.                 IF VAL(itemnum) = 1
  774.                     \\ <<m.g_padloca>>
  775.                 ELSE
  776.                     \\ <<g_pads[VAL(Itemnum)-1]>>
  777.                 ENDIF
  778.         ENDCASE
  779.  
  780. * -dta [BEG] Add support for negotiate
  781. *  c_neg_flag is a quote delimited constant for the field that must be evaluated
  782. *  for a legal negotiate value.
  783.         lcNegotiate = EVAL( c_neg_flag )
  784.         IF NOT EMPTY( m.lcNegotiate ) 
  785.            DO CASE
  786.               CASE m.lcNegotiate = c_neg_left
  787.                  \\ ;
  788.                  \    NEGOTIATE LEFT
  789.               CASE m.lcNegotiate = c_neg_middle
  790.                  \\ ;
  791.                  \    NEGOTIATE MIDDLE
  792.               CASE m.lcNegotiate = c_neg_right
  793.                  \\ ;
  794.                  \    NEGOTIATE RIGHT
  795.               OTHERWISE
  796.                  DO errorhandler WITH c_err_badnegoval + c_neg_flag ,;
  797.                     LINENO(),c_error_2
  798.               ENDCASE
  799.         ENDIF
  800.         RELEASE m.negotiate
  801. * -dta [END] Add support for negotiate
  802.  
  803.         DO addkey
  804.         DO addskipfor
  805.         DO addmessage
  806.  
  807.     ENDSCAN
  808.  
  809. *
  810. * DEFONPAD - Generate ON PAD... statements.
  811. *
  812. * Description:
  813. * Generate ON PAD statements for each pad off of the main menu which
  814. * has a submenu associated with it.
  815. * For pads which have no submenus, but there is a command associated
  816. * with them, issue ON SELECTION PAD... statements.  If the code
  817. * associated with a pad is a snippet, then issue a call to the
  818. * generated procedure and place the snippet code in it.
  819. *
  820. PROCEDURE defonpad
  821.     PRIVATE m.padname
  822.     SCAN FOR objtype=c_item AND UPPER(levelname)="_MSYSMENU"
  823.          IF NOT EMPTY(ALLTRIM(name))
  824.                m.padname = name
  825.          ELSE
  826.                m.padname = g_pads[VAL(Itemnum)]
  827.          ENDIF
  828.          m.therec = RECNO()
  829.          SKIP
  830.          IF objtype=c_submenu AND numitems<>0
  831.                \ON PAD <<m.padname>> OF _MSYSMENU
  832.                \\ ACTIVATE POPUP <<LOWER(Name)>>
  833.                GOTO m.therec
  834.          ELSE
  835.                GOTO m.therec
  836.                DO onselection WITH "pad", m.padname, '_MSYSMENU'
  837.          ENDIF
  838.     ENDSCAN
  839.  
  840. *
  841. * DEFINEPOPUPS - Define popups and their bars.
  842. *
  843. * Description:
  844. * Scan the Menu database to find all objecttypes = submenu.
  845. * They all correspond to popups.  For each such object found, issue
  846. * command DEFINE POPUP....  Add MARK, KEY, and SKIP FOR clauses
  847. * if appropriate by calling procedures to handle these tasks.  Call
  848. * procedure Defbars to define all bars of each popup.
  849. *
  850. PROCEDURE definepopups
  851.     PRIVATE m.savrecno, m.popname, m.sch
  852.     IF m.g_graphic
  853.         SET MESSAGE TO c_msg_genpopdefs
  854.     ENDIF
  855.     SCAN FOR objtype=c_submenu AND UPPER(levelname)<>"_MSYSMENU" ;
  856.             AND numitems <> 0
  857.  
  858.         m.savrecno = RECNO()
  859.         m.popname  = ALLTRIM(LOWER(levelname))
  860.         m.sch      = SCHEME
  861.  
  862.         \DEFINE POPUP <<LOWER(Name)>> MARGIN RELATIVE SHADOW
  863.         \\ COLOR SCHEME <<m.sch>>
  864.  
  865.         DO addmark
  866.         DO addkey
  867.         DO defbars WITH m.popname, numitems
  868.         DO defonbar WITH m.popname
  869.         \
  870.         GOTO RECORD m.savrecno
  871.     ENDSCAN
  872.  
  873. *
  874. * DEFBARS - Define bars for each popup.
  875. *
  876. * Description:
  877. * Scan the menu database for all objects of the type item whose
  878. * name equals to the current popup name.
  879. * For each such item, generate a statement DEFINE BAR....
  880. * Call procedures addkey, addskipfor, and addmark to generate
  881. * KEY, SKIPFOR, or MARK clauses when appropriate.
  882. *
  883. PROCEDURE defbars
  884.     PARAMETER m.popname, m.howmany, m.name
  885.     PRIVATE m.itemno, m.prompt
  886.     SCAN FOR objtype=c_item AND LOWER(levelname)=m.popname
  887.         m.itemno = ALLTRIM(itemnum)
  888.  
  889.         IF NOT EMPTY(ALLTRIM(name))
  890.             m.name = name
  891.             \DEFINE BAR <<m.name>> OF <<LOWER(m.popname)>>
  892.         ELSE
  893.             \DEFINE BAR <<m.itemno>> OF <<LOWER(m.popname)>>
  894.         ENDIF
  895.         m.prompt = SUBSTR(PROMPT, 1,LEN(PROMPT))
  896.         \\ PROMPT "<<m.prompt>>"
  897.  
  898.         DO addmark
  899.         DO addkey
  900.         DO addskipfor
  901.         DO addmessage
  902.  
  903.         IF VAL(m.itemno)=m.howmany
  904.             RETURN
  905.         ENDIF
  906.     ENDSCAN
  907.  
  908. *
  909. * DEFONBAR - Generate ON BAR... statements.
  910. *
  911. * Description:
  912. * Generate ON BAR statements for each popup.
  913. * For bars which have no submenus, but there is a command associated
  914. * with them, issue ON SELECTION BAR... statements.  If a snippet is
  915. * associated with the code then generate a call statement to the
  916. * generated procedure containing the snippet code.
  917. *
  918. PROCEDURE defonbar
  919.     PARAMETER m.popname
  920.     PRIVATE m.itemno
  921.     SCAN FOR objtype=c_item AND LOWER(levelname)=m.popname
  922.         IF EMPTY(ALLTRIM(name))
  923.             m.itemno = ALLTRIM(itemnum)
  924.         ELSE
  925.             m.itemno = name
  926.         ENDIF
  927.         SKIP
  928.         IF objtype=c_submenu AND numitems<>0
  929.             \ON BAR <<m.itemno>> OF <<LOWER(m.popname)>>
  930.             \\ ACTIVATE POPUP <<LOWER(Name)>>
  931.             SKIP -1
  932.         ELSE
  933.             SKIP -1
  934.             DO onselection WITH "BAR", m.itemno, m.popname
  935.         ENDIF
  936.     ENDSCAN
  937.  
  938. *
  939. * GLOBALDEFAULTS - Generate global default statements
  940. *
  941. * Description:
  942. * Search the menu database for information needed to generate any of
  943. * the following commands:
  944. * ON SELECTION MENU <name> DO <action>
  945. * ON SELECTION POPUP ALL DO <action>
  946. * ON SELECTION POPUP <name> DO <action>
  947. * It is possible that none of the above mentioned statements will be
  948. * generated.  It is also possible that the action is a snippet of
  949. * code and a call to the generated procedure containing the snippet
  950. * will be generated.
  951. *
  952. * First try to generate ON SELECTION MENU...
  953. * Then try to generate ON POPUP ALL...
  954. * Lastly, try to generate ON SELECTION POPUP...
  955. *
  956. PROCEDURE globaldefaults
  957.     LOCATE FOR objtype = c_menu
  958.     m.mrk = MARK
  959.     IF FOUND() AND MARK <> ""
  960.         IF MARK = c_null
  961.             \SET MARK OF MENU _MSYSMENU TO " "
  962.         ELSE
  963.             \SET MARK OF MENU _MSYSMENU TO "<<Mark>>"
  964.         ENDIF
  965.     ENDIF
  966.     IF FOUND() AND NOT EMPTY(PROCEDURE)
  967.         \ON SELECTION MENU _MSYSMENU
  968.         DO genproccall
  969.     ENDIF
  970.     LOCATE FOR objtype = c_submenu AND objcode = c_global
  971.     IF FOUND() AND NOT EMPTY(PROCEDURE)
  972.         \ON SELECTION POPUP ALL
  973.         DO genproccall
  974.     ENDIF
  975.     SCAN FOR (objtype=c_submenu AND UPPER(levelname)<>"_MSYSMENU";
  976.             AND NOT EMPTY(PROCEDURE))
  977.         \ON SELECTION POPUP <<ALLTRIM(LOWER(Levelname))>>
  978.         DO genproccall
  979.     ENDSCAN
  980.  
  981. **
  982. ** Subroutines for processing menu clause options.
  983. **
  984.  
  985. *
  986. * ADDMARK - Generate a MARK clause whenever appropriate.
  987. *
  988. * Description:
  989. * Add a MARK clause to the current PAD or BAR definition.
  990. * If a field named Mark is not empty, then add the continuation
  991. * character, ";", to the previous line, and then add the MARK... clause.
  992. *
  993. PROCEDURE addmark
  994.     IF MARK<>c_null AND MARK<>""
  995.         \\ ;
  996.             \    MARK "<<Mark>>"
  997.     ENDIF
  998.  
  999. *
  1000. * ADDKEY - Generate KEY... clause whenever appropriate.
  1001. *
  1002. * Description:
  1003. * Add a KEY clause to the current PAD or BAR definition.
  1004. * If a field named Keyname is not empty, then add the continuation
  1005. * character, ";", to the previous line, and then add the KEY... clause.
  1006. *
  1007. PROCEDURE addkey
  1008.     IF NOT EMPTY(keyname)
  1009.         \\ ;
  1010.         \    KEY <<Keyname>>, "<<Keylabel>>"
  1011.     ENDIF
  1012.  
  1013. *
  1014. * ADDSKIPFOR - Generate SKIP FOR... clause whenever appropriate.
  1015. *
  1016. * Description:
  1017. * Add a ADDSKIPFOR clause to the current PAD or BAR definition.
  1018. * If a field named Addskipfor is not empty, then add the continuation
  1019. * character, ";", to the previous line, and then add the SKIP FOR...
  1020. * clause.
  1021. *
  1022. PROCEDURE addskipfor
  1023.     PRIVATE m.skip
  1024.     m.skip = skipfor
  1025.     IF NOT EMPTY(skipfor)
  1026.         \\ ;
  1027.         \    SKIP FOR <<m.skip>>
  1028.     ENDIF
  1029.  
  1030. *
  1031. * ADDMESSAGE - Generate MESSAGE clause whenever appropriate.
  1032. *
  1033. * Description:
  1034. * Add a MESSAGE clause to the current PAD or BAR definition.
  1035. * If a field named MESSAGE is not empty and it is not a 2.0 menu,
  1036. * then add the continuation character, ";", to the previous line,
  1037. * and then add the MESSAGE clause.
  1038. *
  1039. PROCEDURE addmessage
  1040.  
  1041.     IF !m.g_20mnx AND NOT EMPTY(MESSAGE)
  1042.         \\ ;
  1043.         \    MESSAGE <<Message>>
  1044.     ENDIF
  1045.  
  1046. *
  1047. * HEADER - Generate generated program's header.
  1048. *
  1049. * Description:
  1050. * As a part of the automatically generated program's header generate
  1051. * program name, name of the author of the program, copyright notice,
  1052. * company name and address, and the word 'Description:' which will be
  1053. * followed with a short description of the generated code.
  1054. *
  1055. PROCEDURE HEADER
  1056.     \\*       <<m.g_corn1>><<REPLICATE(m.g_horiz,57)>><<m.g_corn2>>
  1057.     \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  1058.     \*       <<m.g_verti1>> <<DATE()>>
  1059.     \\<<PADC(UPPER(ALLTRIM(strippath(m.g_outfile))),IIF(SET("CENTURY")="ON",35,37))," ")>>
  1060.     \\ <<TIME()>>  <<m.g_verti2>>
  1061.     \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  1062.     \*       <<m.g_corn5>><<REPLICATE(m.g_horiz,57)>><<m.g_corn6>>
  1063.     \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  1064.     \*       <<m.g_verti1>> <<m.g_devauthor>>
  1065.     \\<<REPLICATE(" ",56-LEN(m.g_devauthor))>><<m.g_verti2>>
  1066.     \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  1067.     \*       <<m.g_verti1>>
  1068.     \\ c_hdr_copyright <<YEAR(DATE())>>
  1069.     IF LEN(ALLTRIM(m.g_devcompany)) <= 36
  1070.         \\ <<ALLTRIM(m.g_devcompany)>>
  1071.         \\<<REPLICATE(" ",37-LEN(ALLTRIM(m.g_devcompany)))>>
  1072.         \\<<m.g_verti2>>
  1073.     ELSE
  1074.         \\ <<REPLICATE(" ",37)>><<m.g_verti2>>
  1075.         \*       <<m.g_verti1>> <<m.g_devcompany>>
  1076.         \\<<REPLICATE(" ",56-LEN(m.g_devcompany))>><<m.g_verti2>>
  1077.     ENDIF
  1078.  
  1079.     \*       <<m.g_verti1>> <<m.g_devaddress>>
  1080.     \\<<REPLICATE(" ",56-LEN(m.g_devaddress))>><<m.g_verti2>>
  1081.  
  1082.     \*       <<m.g_verti1>> <<ALLTRIM(m.g_devcity)>>, <<m.g_devstate>>
  1083.     \\  <<ALLTRIM(m.g_devzip)>>
  1084.     \\<<REPLICATE(" ",50-(LEN(ALLTRIM(m.g_devcity)+ALLTRIM(m.g_devzip))))>>
  1085.     \\<<m.g_verti2>>
  1086.  
  1087.     IF !INLIST(ALLTRIM(UPPER(m.g_devctry)),"USA","COUNTRY") AND !EMPTY(m.g_devctry)
  1088.        \*       <<m.g_verti1>> <<ALLTRIM(m.g_devctry)>>
  1089.        \\<<REPLICATE(" ",50-(LEN(ALLTRIM(m.g_devctry))))>>
  1090.        \\<<m.g_verti2>>
  1091.     ENDIF
  1092.     \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  1093.     \*       <<m.g_verti1>> c_hdr_descript
  1094.     \\                                            <<m.g_verti2>>
  1095.     \*       <<m.g_verti1>>
  1096.     \\ c_hdr_string
  1097.     \\    <<m.g_verti2>>
  1098.     \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  1099.     \*       <<m.g_corn3>><<REPLICATE(m.g_horiz,57)>><<m.g_corn4>>
  1100.     \
  1101.  
  1102. *
  1103. * GENFUNCHEADER - Generate Comment for Function/Procedure.
  1104. *
  1105. PROCEDURE genfuncheader
  1106.     PARAMETER m.procname
  1107.     PRIVATE m.place, m.prompt
  1108.     m.g_snippcnt = m.g_snippcnt + 1
  1109.     DO CASE
  1110.         CASE objtype = c_menu
  1111.             m.place = "ON SELECTION MENU _MSYSMENU"
  1112.         CASE objtype = c_submenu AND objcode = c_global
  1113.             m.place = "ON SELECTION POPUP ALL"
  1114.         CASE objtype = c_submenu AND objcode <> c_global
  1115.             m.place = "ON SELECTION POPUP "+LOWER(ALLTRIM(name))
  1116.         CASE objtype = c_item AND UPPER(levelname) = "_MSYSMENU"
  1117.             m.place = "ON SELECTION PAD "
  1118.         CASE objtype = c_item AND UPPER(levelname) <> "_MSYSMENU"
  1119.             m.place = "ON SELECTION BAR "+ALLTRIM(itemnum)+;
  1120.                 +" OF POPUP "+LOWER(ALLTRIM(levelname))
  1121.         OTHERWISE
  1122.             m.place = ""
  1123.     ENDCASE
  1124.     \
  1125.     \*       <<m.g_corn1>><<REPLICATE(m.g_horiz,57)>><<m.g_corn2>>
  1126.     \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  1127.     \*       <<m.g_verti1>> <<UPPER(PADR(m.procname,10))>>  <<m.place>>
  1128.     \\<<REPLICATE(" ",44-LEN(m.place))>><<m.g_verti2>>
  1129.     \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  1130.     \*       <<m.g_verti1>> Procedure Origin:
  1131.     \\<<REPLICATE(" ",39)>><<m.g_verti2>>
  1132.     \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  1133.     \*       <<m.g_verti1>> From Menu:
  1134.     \\  <<ALLTRIM(strippath(m.g_outfile))>>
  1135.     \\,            Record:  <<STR(RECNO(),3)>>
  1136.     \\<<REPLICATE(" ",22-LEN(ALLTRIM(strippath(m.g_outfile))+STR(RECNO(),3))))>>
  1137.     \\<<m.g_verti2>>
  1138.     \*       <<m.g_verti1>> Called By:  <<m.place>>
  1139.     \\<<REPLICATE(" ",44-LEN(m.place))>><<m.g_verti2>>
  1140.     IF NOT EMPTY(PROMPT)
  1141.         m.prompt = removemeta()
  1142.         \*       <<m.g_verti1>> Prompt:     <<ALLTRIM(m.prompt)>>
  1143.         \\<<REPLICATE(" ",44-LEN(ALLTRIM(m.prompt)))>><<m.g_verti2>>
  1144.     ENDIF
  1145.     \*       <<m.g_verti1>> Snippet:
  1146.     \\    <<ALLTRIM(STR(m.g_snippcnt,2))>>
  1147.     \\<<REPLICATE(" ",44-LEN(ALLTRIM(STR(m.g_snippcnt,2))))>><<m.g_verti2>>
  1148.     \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  1149.     \*       <<m.g_corn3>><<REPLICATE(m.g_horiz,57)>><<m.g_corn4>>
  1150.     \*
  1151.  
  1152. *
  1153. * REMOVEMETA - Remove meta characters for documentation.
  1154. *
  1155. FUNCTION removemeta
  1156.     PRIVATE m.prompt, m.hotkey
  1157.     m.prompt = PROMPT
  1158.     m.hotkey = AT("\<",m.prompt)
  1159.  
  1160.     IF m.hotkey <> 0
  1161.         m.prompt = STUFF(m.prompt,m.hotkey,2,"")
  1162.     ENDIF
  1163.  
  1164.     m.disabl = AT("\",m.prompt)
  1165.     IF m.disabl <> 0
  1166.         m.prompt = STUFF(m.prompt,m.disabl,1,"")
  1167.     ENDIF
  1168.     RETURN m.prompt
  1169.  
  1170. *
  1171. * COMMENTBLOCK - Generate a comment block.
  1172. *
  1173. PROCEDURE commentblock
  1174.     PARAMETER m.snippet
  1175.     \
  1176.     \*       <<m.g_corn1>><<REPLICATE(m.g_horiz,57)>><<m.g_corn2>>
  1177.     \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  1178.     DO CASE
  1179.         CASE m.snippet == "setup"
  1180.             \*       <<m.g_verti1>>
  1181.             \\ <<PADC( c_snip_setup ,56," ")>>
  1182.         CASE m.snippet == "cleanup"
  1183.             \*       <<m.g_verti1>>
  1184.             \\ <<PADC( c_snip_cleanup ,56," ")>>
  1185.         CASE m.snippet == "init"
  1186.             \*       <<m.g_verti1>>
  1187.             \\ <<PADC( c_snip_init ,56," ")>>
  1188.         CASE m.snippet == "menu"
  1189.             \*       <<m.g_verti1>>
  1190.             \\ <<PADC( c_snip_menu ,56," ")>>
  1191.     ENDCASE
  1192.     \\<<m.g_verti2>>
  1193.     \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  1194.     \*       <<m.g_corn3>><<REPLICATE(m.g_horiz,57)>><<m.g_corn4>>
  1195.     \*
  1196.     \
  1197.  
  1198. **
  1199. ** Supporting routines
  1200. **
  1201.  
  1202. *
  1203. * ONSELECTION - Generate ON SELECTION... statements for menu items.
  1204. *
  1205. * Description:
  1206. * For pads and bars which have no submenu associated with them but
  1207. * instead have a non-empty Command field in the database, issue
  1208. * the ON SELECTION <command> statements.  If a snippet is associated
  1209. * with a pad then issue a call statement to the generated procedure
  1210. * containing the snippet.  Generated snippet procedure will be
  1211. * appended to the end of the output file.
  1212. *
  1213. PROCEDURE onselection
  1214.     PARAMETER m.which, m.name, m.ofname, m.commd
  1215.     PRIVATE m.trimname, m.basename
  1216.     IF EMPTY(PROCEDURE) AND EMPTY(COMMAND)
  1217.         RETURN
  1218.     ENDIF
  1219.     DO CASE
  1220.         CASE m.which == "pad"
  1221.             \ON SELECTION PAD <<m.name>>
  1222.         CASE m.which == "BAR"
  1223.             \ON SELECTION <<m.which+" "+m.name>>
  1224.     ENDCASE
  1225.     \\ OF <<m.ofname>>
  1226.     IF objcode = c_proc
  1227.         DO gensnippname
  1228.         m.trimname = SYS(2014,UPPER(m.g_outfile),UPPER(m.g_homedir))
  1229.         m.trimname = stripext(m.trimname)
  1230.         m.basename = basename(m.trimname)
  1231.         \\ ;
  1232.         \    DO <<g_snippets[g_nsnippets,1]>> ;
  1233.         \    IN LOCFILE("<<m.trimname>>"
  1234.         \\ ,"MPX;MPR|FXP;PRG"
  1235.         \\ ,"
  1236.         \\c_ui_whereis
  1237.         \\ <<m.basename>>?")
  1238.     ELSE
  1239.         m.commd = COMMAND
  1240.         \\ <<m.commd>>
  1241.     ENDIF
  1242.  
  1243. *
  1244. * GENSNIPPNAME - Generate a unique name for snippet procedure.
  1245. *
  1246. * Description:
  1247. * Lookup the #NAME name of this snippet, or alternatively
  1248. * provide a unique name for a snippet of code associated with the
  1249. * generated menu.  Save this name in an array g_snippets.
  1250. *
  1251. PROCEDURE gensnippname
  1252.     g_nsnippets = g_nsnippets + 1
  1253.     g_snippets[g_nsnippets,1] = getcname(procedure)
  1254.     g_snippets[g_nsnippets,2] = RECNO()
  1255.  
  1256.     IF MOD(g_nsnippets,25) = 0
  1257.         DIMENSION g_snippets [g_nsnippets+25,2]
  1258.     ENDIF
  1259.  
  1260. *
  1261. * GENPROCCALL - Generate a call statement to snippet procedure.
  1262. *
  1263. * Description:
  1264. * Generate a call to the snippet procedure in the menu definition
  1265. * code.
  1266. *
  1267. PROCEDURE genproccall
  1268.     PRIVATE m.trimname, m.basename, m.proc
  1269.     IF singleline()
  1270.         m.proc = PROCEDURE
  1271.         \\ <<MLINE(m.proc,1)>>
  1272.     ELSE
  1273.         DO gensnippname
  1274.         m.trimname = SYS(2014,UPPER(m.g_outfile),UPPER(m.g_homedir))
  1275.         m.trimname = stripext(m.trimname)
  1276.         m.basename = basename(m.trimname)
  1277.         \\ ;
  1278.         \    DO <<g_snippets[m.g_nsnippets,1]>> ;
  1279.         \    IN LOCFILE("<<m.trimname>>"
  1280.         \\ ,"MPX;MPR|FXP;PRG"
  1281.         \\ ,"
  1282.         \\c_ui_whereis
  1283.         \\ <<m.basename>>?")
  1284.     ENDIF
  1285.  
  1286. *
  1287. * SINGLELINE - Determine if Memo contains only one line.
  1288. *
  1289. * Description:
  1290. * This procedure is used to decide if an ON SELECTION... statement
  1291. * and a snippet procedure will be needed (i.e., if more than one
  1292. * line of snippet code then its a snippet, otherwise its a command)
  1293. *
  1294. FUNCTION singleline
  1295.     PRIVATE m.size, m.i
  1296.     m.size = MEMLINES(PROCEDURE)
  1297.     IF m.size = 1
  1298.         RETURN .T.
  1299.     ENDIF
  1300.     m.i = m.size
  1301.     DO WHILE m.i > 1
  1302.         m.line = MLINE(PROCEDURE, m.i)
  1303.         IF NOT EMPTY(m.line)
  1304.             RETURN .F.
  1305.         ENDIF
  1306.         m.i = m.i - 1
  1307.     ENDDO
  1308.  
  1309. *
  1310. * GENPROCEDURES - Generate procedure/snippet code.
  1311. *
  1312. * Description:
  1313. * Generate 'PROCEDURE procedurename' statement and its body.
  1314. *
  1315. PROCEDURE genprocedures
  1316.     PRIVATE m.i
  1317.     IF m.g_graphic
  1318.         SET MESSAGE TO c_msg_genprocs
  1319.     ENDIF
  1320.     FOR m.i = 1 TO m.g_nsnippets
  1321.         GOTO RECORD (g_snippets[m.i,2])
  1322.         DO genfuncheader WITH g_snippets[m.i,1]
  1323.         \PROCEDURE <<g_snippets[m.i,1]>>
  1324.         DO writecode WITH procedure
  1325.         \
  1326.     ENDFOR
  1327.  
  1328. *
  1329. * WRITECODE - Write contents of a memo to a low level file.
  1330. *
  1331. * Description:
  1332. * Receive a memo field as a parameter and write its contents out
  1333. * to the currently opened low level file whose handle is stored
  1334. * in the system memory variable _TEXT.  Contents of the system
  1335. * memory variable _pretext will affect the positioning of the
  1336. * generated text.
  1337. *
  1338. PROCEDURE writecode
  1339.     PARAMETER m.memo
  1340.     PRIVATE m.lines, m.i, m.thisline
  1341.     m.lines = MEMLINES(m.memo)
  1342.     _MLINE = 0
  1343.     FOR m.i = 1 TO m.lines
  1344.         m.thisline = MLINE(m.memo, 1, _MLINE)
  1345.         IF LEFT(UPPER(LTRIM(m.thisline)),5) == "#INSE"   && #INSERT
  1346.            DO GenInsertCode WITH m.thisline
  1347.         ELSE
  1348.            IF LEFT(UPPER(LTRIM(m.thisline)),5) <> "#NAME"
  1349.               \<<m.thisline>>
  1350.            ENDIF
  1351.         ENDIF
  1352.     ENDFOR
  1353.  
  1354. *
  1355. * GENSETUPCLEANUP - Generate setup/cleanup code.
  1356. *
  1357. PROCEDURE gensetupcleanup
  1358.     PARAMETER m.choice
  1359.     LOCATE FOR objtype = c_menu
  1360.     DO CASE
  1361.         CASE m.choice == "setup"
  1362.             IF EMPTY(setup)
  1363.                 RETURN
  1364.             ENDIF
  1365.             IF m.g_graphic
  1366.                 SET MESSAGE TO c_msg_gensetup
  1367.             ENDIF
  1368.             DO commentblock WITH m.choice
  1369.             DO writecode WITH setup
  1370.         CASE m.choice == "cleanup"
  1371.             IF EMPTY(cleanup)
  1372.                 RETURN
  1373.             ENDIF
  1374.             IF m.g_graphic
  1375.                 SET MESSAGE TO c_msg_gencleanup
  1376.             ENDIF
  1377.             DO commentblock WITH m.choice
  1378.             DO writecode WITH cleanup
  1379.     ENDCASE
  1380.  
  1381. *
  1382. * STRIPEXT - Strip the extension from a file name.
  1383. *
  1384. * Description:
  1385. * Use the algorithm employed by FoxPRO itself to strip a
  1386. * file of an extension (if any): Find the rightmost dot in
  1387. * the filename.  If this dot occurs to the right of a "\"
  1388. * or ":", then treat everything from the dot rightward
  1389. * as an extension.  Of course, if we found no dot,
  1390. * we just hand back the filename unchanged.
  1391. *
  1392. * Parameters:
  1393. * filename - character string representing a file name
  1394. *
  1395. * Return value:
  1396. * The string "filename" with any extension removed
  1397. *
  1398. FUNCTION stripext
  1399.     PARAMETER m.filename
  1400.     PRIVATE m.dotpos, m.terminator
  1401.     m.dotpos = RAT(".", m.filename)
  1402.     m.terminator = MAX(RAT("\", m.filename), RAT(":", m.filename))
  1403.     IF m.dotpos > m.terminator
  1404.         m.filename = LEFT(m.filename, m.dotpos-1)
  1405.     ENDIF
  1406.     RETURN m.filename
  1407.  
  1408. *
  1409. * STRIPPATH - Strip the path from a file name.
  1410. *
  1411. * Description:
  1412. * Find positions of backslash in the name of the file.  If there is one
  1413. * take everything to the right of its position and make it the new file
  1414. * name.  If there is no slash look for colon.  Again if found, take
  1415. * everything to the right of it as the new name.  If neither slash
  1416. * nor colon are found then return the name unchanged.
  1417. *
  1418. * Parameters:
  1419. * filename - character string representing a file name
  1420. *
  1421. * Return value:
  1422. * The string "filename" with any path removed
  1423. *
  1424. FUNCTION strippath
  1425.     PARAMETER m.filename
  1426.     PRIVATE m.slashpos, m.namelen, m.colonpos
  1427.     m.slashpos = RAT("\", m.filename)
  1428.     IF m.slashpos > 0
  1429.         m.namelen  = LEN(m.filename) - m.slashpos
  1430.         m.filename = RIGHT(m.filename, m.namelen)
  1431.     ELSE
  1432.         m.colonpos = RAT(":", m.filename)
  1433.         IF m.colonpos > 0
  1434.             m.namelen  = LEN(m.filename) - m.colonpos
  1435.             m.filename = RIGHT(m.filename, m.namelen)
  1436.         ENDIF
  1437.     ENDIF
  1438.     RETURN m.filename
  1439.  
  1440. *
  1441. * BASENAME - returns strippath(stripext(filespec))
  1442. *
  1443. FUNCTION basename
  1444.     PARAMETER m.filespec
  1445.     RETURN strippath(stripext(m.filespec))
  1446.  
  1447. *
  1448. * GENINSERTCODE - Emit code from the #insert file, if any
  1449. *
  1450. PROCEDURE GenInsertCode
  1451. PARAMETER strg
  1452. PRIVATE m.word1, m.filname, m.ins_fp, m.buffer
  1453.  
  1454. IF UPPER(LEFT(LTRIM(m.strg),5)) == "#INSE"
  1455.    m.word1 = wordnum(m.strg,1)
  1456.    m.filname = SUBSTR(m.strg,LEN(m.word1)+1)
  1457.    m.filname = ALLTRIM(CHRTRAN(m.filname,CHR(9),""))
  1458.  
  1459.    * Bail out if we can't find the file either explicitly or on the DOS path
  1460.    IF !FILE(m.filname)
  1461.       filname = FULLPATH(m.filname,1)
  1462.       IF !FILE(m.filname)
  1463.          \*Insert file <<m.filname>> could not be found
  1464.          RETURN
  1465.       ENDIF
  1466.    ENDIF
  1467.  
  1468.    ins_fp = FOPEN(m.filname)
  1469.    IF ins_fp > 0
  1470.       \* Inserted from <<strippath(m.filname)>>
  1471.       DO WHILE !feof(ins_fp)
  1472.          m.buffer = fgets(ins_fp)
  1473.          \<<m.buffer>>
  1474.       ENDDO
  1475.       =fclose(m.ins_fp)
  1476.       \* End of inserted lines
  1477.    ENDIF
  1478. ENDIF
  1479. *!*****************************************************************************
  1480. *!
  1481. *!       Function: JUSTPATH
  1482. *!
  1483. *!      Called by: FORCEEXT()         (function  in GENSCRN.PRG)
  1484. *!
  1485. *!*****************************************************************************
  1486. FUNCTION justpath
  1487. * Return just the path name from "filname"
  1488. PARAMETERS m.filname
  1489. PRIVATE ALL
  1490. m.filname = ALLTRIM(UPPER(m.filname))
  1491. IF '\' $ m.filname
  1492.    m.filname = SUBSTR(m.filname,1,RAT('\',m.filname))
  1493.    IF RIGHT(m.filname,1) = '\' AND LEN(m.filname) > 1 ;
  1494.             AND SUBSTR(m.filname,LEN(m.filname)-1,1) <> ':'
  1495.          filname = SUBSTR(m.filname,1,LEN(m.filname)-1)
  1496.    ENDIF
  1497.    RETURN m.filname
  1498. ELSE
  1499.    RETURN ''
  1500. ENDIF
  1501.  
  1502. **
  1503. ** Code Associated with the Thermometer
  1504. **
  1505.  
  1506. *
  1507. * ACTTHERM(<text>) - Activate thermometer.
  1508. *
  1509. * Description:
  1510. * Activates thermometer.  Update the thermometer with UPDTHERM().
  1511. * Thermometer window is named "thermometer."  Be sure to RELEASE
  1512. * this window when done with thermometer.  Creates the global
  1513. * m.g_thermwidth.
  1514. *
  1515. PROCEDURE acttherm
  1516.     PARAMETER m.text
  1517.     PRIVATE m.prompt
  1518.  
  1519.     IF m.g_graphic
  1520.         m.prompt = m.g_outfile
  1521.           m.prompt = thermfname(m.prompt)
  1522.  
  1523.         DO CASE
  1524.         CASE _WINDOWS
  1525.            DEFINE WINDOW thermomete ;
  1526.               AT  INT((SROW() - (( 5.615 * ;
  1527.               FONTMETRIC(1, m.g_dlgface, m.g_dlgsize, m.g_dlgstyle )) / ;
  1528.               FONTMETRIC(1, WFONT(1,""), WFONT( 2,""), WFONT(3,"")))) / 2), ;
  1529.               INT((SCOL() - (( 63.833 * ;
  1530.               FONTMETRIC(6, m.g_dlgface, m.g_dlgsize, m.g_dlgstyle )) / ;
  1531.               FONTMETRIC(6, WFONT(1,""), WFONT( 2,""), WFONT(3,"")))) / 2) ;
  1532.               SIZE 5.615,63.833 ;
  1533.               FONT m.g_dlgface, m.g_dlgsize ;
  1534.               STYLE m.g_dlgstyle ;
  1535.               NOFLOAT ;
  1536.               NOCLOSE ;
  1537.               NONE ;
  1538.               COLOR RGB(0, 0, 0, 192, 192, 192)
  1539.            MOVE WINDOW thermomete CENTER
  1540.            ACTIVATE WINDOW thermomete NOSHOW
  1541.            @ 0.5,3 SAY m.text FONT m.g_dlgface, m.g_dlgsize STYLE m.g_dlgstyle
  1542.            @ 1.5,3 SAY m.prompt FONT m.g_dlgface, m.g_dlgsize STYLE m.g_dlgstyle
  1543.            @ 0.000,0.000 TO 0.000,63.833 ;
  1544.               COLOR RGB(255, 255, 255, 255, 255, 255)
  1545.            @ 0.000,0.000 TO 5.615,0.000 ;
  1546.               COLOR RGB(255, 255, 255, 255, 255, 255)
  1547.            @ 0.385,0.667 TO 5.231,0.667 ;
  1548.               COLOR RGB(128, 128, 128, 128, 128, 128)
  1549.            @ 0.308,0.667 TO 0.308,63.167 ;
  1550.               COLOR RGB(128, 128, 128, 128, 128, 128)
  1551.            @ 0.385,63.000 TO 5.308,63.000 ;
  1552.               COLOR RGB(255, 255, 255, 255, 255, 255)
  1553.            @ 5.231,0.667 TO 5.231,63.167 ;
  1554.               COLOR RGB(255, 255, 255, 255, 255, 255)
  1555.            @ 5.538,0.000 TO 5.538,63.833 ;
  1556.               COLOR RGB(128, 128, 128, 128, 128, 128)
  1557.            @ 0.000,63.667 TO 5.615,63.667 ;
  1558.               COLOR RGB(128, 128, 128, 128, 128, 128)
  1559.            @ 3.000,3.333 TO 4.231,3.333 ;
  1560.               COLOR RGB(128, 128, 128, 128, 128, 128)
  1561.            @ 3.000,60.333 TO 4.308,60.333 ;
  1562.               COLOR RGB(255, 255, 255, 255, 255, 255)
  1563.            @ 3.000,3.333 TO 3.000,60.333 ;
  1564.               COLOR RGB(128, 128, 128, 128, 128, 128)
  1565.            @ 4.231,3.333 TO 4.231,60.333 ;
  1566.               COLOR RGB(255, 255, 255, 255, 255, 255)
  1567.            m.g_thermwidth = 56.269
  1568.         CASE _MAC
  1569.            DEFINE WINDOW thermomete ;
  1570.               AT  INT((SROW() - (( 5.62 * ;
  1571.               FONTMETRIC(1, m.g_dlgface, m.g_dlgsize, m.g_dlgstyle )) / ;
  1572.               FONTMETRIC(1, WFONT(1,""), WFONT( 2,""), WFONT(3,"")))) / 2), ;
  1573.               INT((SCOL() - (( 63.83 * ;
  1574.               FONTMETRIC(6, m.g_dlgface, m.g_dlgsize, m.g_dlgstyle )) / ;
  1575.               FONTMETRIC(6, WFONT(1,""), WFONT( 2,""), WFONT(3,"")))) / 2) ;
  1576.               SIZE 5.62,63.83 ;
  1577.               FONT m.g_dlgface, m.g_dlgsize ;
  1578.               STYLE m.g_dlgstyle ;
  1579.               NOFLOAT ;
  1580.               NOCLOSE ;
  1581.                   NONE ;
  1582.               COLOR RGB(0, 0, 0, 192, 192, 192)
  1583.            MOVE WINDOW thermomete CENTER
  1584.            ACTIVATE WINDOW thermomete NOSHOW
  1585.            @ 0.000,0.000 TO 5.62,63.83 PATTERN 1;
  1586.               COLOR RGB(192, 192, 192, 192, 192, 192)
  1587.               IF ISCOLOR()
  1588.               @ 0.000,0.000 TO 5.62,63.83 PATTERN 1;
  1589.                  COLOR RGB(192, 192, 192, 192, 192, 192)
  1590.               @ 0.000,0.000 TO 0.000,63.83 ;
  1591.                  COLOR RGB(255, 255, 255, 255, 255, 255)
  1592.               @ 0.000,0.000 TO 5.62,0.000 ;
  1593.                  COLOR RGB(255, 255, 255, 255, 255, 255)
  1594.               @ 0.385,0.67 TO 5.23,0.67 ;
  1595.                  COLOR RGB(128, 128, 128, 128, 128, 128)
  1596.               @ 0.31,0.67 TO 0.31,63.17 ;
  1597.                  COLOR RGB(128, 128, 128, 128, 128, 128)
  1598.               @ 0.385,63.000 TO 5.31,63.000 ;
  1599.                  COLOR RGB(255, 255, 255, 255, 255, 255)
  1600.               @ 5.23,0.67 TO 5.23,63.17 ;
  1601.                  COLOR RGB(255, 255, 255, 255, 255, 255)
  1602.               @ 5.54,0.000 TO 5.54,63.83 ;
  1603.                  COLOR RGB(128, 128, 128, 128, 128, 128)
  1604.               @ 0.000,63.67 TO 5.62,63.67 ;
  1605.                  COLOR RGB(128, 128, 128, 128, 128, 128)
  1606.               @ 3.000,3.33 TO 4.23,3.33 ;
  1607.                  COLOR RGB(128, 128, 128, 128, 128, 128)
  1608.               @ 3.000,60.33 TO 4.31,60.33 ;
  1609.                  COLOR RGB(255, 255, 255, 255, 255, 255)
  1610.               @ 3.000,3.33 TO 3.000,60.33 ;
  1611.                  COLOR RGB(128, 128, 128, 128, 128, 128)
  1612.               @ 4.23,3.33 TO 4.23,60.33 ;
  1613.                  COLOR RGB(255, 255, 255, 255, 255, 255)
  1614.               ELSE
  1615.               @ 0.000, 0.000 TO 5.62, 63.830  PEN 2
  1616.                @ 0.230, 0.500 TO 5.39, 63.333  PEN 1
  1617.               ENDIF
  1618.            @ 0.5,3 SAY m.text FONT m.g_dlgface, m.g_dlgsize STYLE m.g_dlgstyle+"T" ;
  1619.               COLOR RGB(0,0,0,192,192,192)
  1620.            @ 1.5,3 SAY m.prompt FONT m.g_dlgface, m.g_dlgsize STYLE m.g_dlgstyle+"T" ;
  1621.               COLOR RGB(0,0,0,192,192,192)
  1622.  
  1623.                 m.g_thermwidth = 56.27
  1624.                 IF !ISCOLOR()
  1625.                    @ 3.000,3.33 TO 4.23, (m.g_thermwidth + 1) + 3.33
  1626.                 ENDIF
  1627.         ENDCASE
  1628.         SHOW WINDOW thermomete TOP
  1629.     ELSE
  1630.         m.prompt = SUBSTR(SYS(2014,UPPER(m.g_outfile)),1,48)+;
  1631.             IIF(LEN(m.g_outfile)>48,"...","")
  1632.  
  1633.         DEFINE WINDOW thermomete;
  1634.             FROM INT((SROW()-6)/2), INT((SCOL()-57)/2) ;
  1635.             TO INT((SROW()-6)/2) + 6, INT((SCOL()-57)/2) + 57;
  1636.             DOUBLE COLOR SCHEME 5
  1637.  
  1638.         ACTIVATE WINDOW thermomete NOSHOW
  1639.  
  1640.         m.g_thermwidth = 50
  1641.         @ 0,3 SAY m.text
  1642.         @ 1,3 SAY UPPER(m.prompt)
  1643.         @ 2,1 TO 4,m.g_thermwidth+4 &g_boxstrg
  1644.  
  1645.         SHOW WINDOW thermomete TOP
  1646.     ENDIF
  1647.  
  1648. *
  1649. * UPDTHERM(<percent>) - Update thermometer.
  1650. *
  1651. PROCEDURE updtherm
  1652. PARAMETER m.percent
  1653. PRIVATE m.nblocks, m.percent
  1654. ACTIVATE WINDOW thermomete
  1655. m.nblocks = (m.percent/100) * (m.g_thermwidth)
  1656. DO CASE
  1657. CASE _WINDOWS
  1658.    @ 3.000,3.333 TO 4.231,m.nblocks + 3.333 ;
  1659.       PATTERN 1 COLOR RGB(128, 128, 128, 128, 128, 128)
  1660. CASE _MAC
  1661.    @ 3.000,3.33 TO 4.23,m.nblocks + 3.33 ;
  1662.       PATTERN 1 COLOR RGB(0, 0, 128, 0, 0, 128)
  1663. OTHERWISE
  1664.    @ 3,3 SAY REPLICATE("█",m.nblocks)
  1665. ENDCASE
  1666.  
  1667. *
  1668. * DEACTTHERMO - Deactivate and Release thermometer window.
  1669. *
  1670. PROCEDURE deactthermo
  1671.     RELEASE WINDOW thermomete
  1672.  
  1673.  
  1674. *!*****************************************************************************
  1675. *!
  1676. *!      Procedure: THERMFNAME
  1677. *!
  1678. *!*****************************************************************************
  1679. FUNCTION thermfname
  1680. PARAMETER m.fname
  1681. PRIVATE m.addelipse, m.g_pathsep, m.g_thermfface, m.g_thermfsize, m.g_thermfstyle
  1682.  
  1683. #define c_space 40
  1684. IF _MAC
  1685.     m.g_thermfface = "Geneva"
  1686.     m.g_thermfsize = 10
  1687.     m.g_thermfstyle = "B"
  1688. ELSE
  1689.     m.g_thermfface = "MS Sans Serif"
  1690.     m.g_thermfsize = 8
  1691.     m.g_thermfstyle = "B"
  1692. ENDIF
  1693.  
  1694. * Translate the filename into Mac native format
  1695. IF _MAC
  1696.     m.g_pathsep = ":"
  1697.     m.fname = LOWER(SYS(2027, m.fname))
  1698. ELSE
  1699.     m.g_pathsep = "\"
  1700. ENDIF
  1701.  
  1702. IF TXTWIDTH(m.fname,m.g_thermfface,m.g_thermfsize,m.g_thermfstyle) > c_space
  1703.     * Make it fit in c_space
  1704.     m.fname = partialfname(m.fname, c_space - 1)
  1705.     m.addelipse = .F.
  1706.     DO WHILE TXTWIDTH(m.fname+'...',m.g_thermfface,m.g_thermfsize,m.g_thermfstyle) > c_space
  1707.         m.fname = LEFT(m.fname, LEN(m.fname) - 1)
  1708.         m.addelipse = .T.
  1709.     ENDDO
  1710.     IF m.addelipse
  1711.         m.fname = m.fname + "..."
  1712.    ENDIF
  1713. ENDIF
  1714. RETURN m.fname
  1715.  
  1716.  
  1717.  
  1718. *!*****************************************************************************
  1719. *!
  1720. *!      Procedure: PARTIALFNAME
  1721. *!
  1722. *!*****************************************************************************
  1723. FUNCTION partialfname
  1724. PARAMETER m.filname, m.fillen
  1725. * Return a filname no longer than m.fillen characters.  Take some chars
  1726. * out of the middle if necessary.  No matter what m.fillen is, this function
  1727. * always returns at least the file stem and extension.
  1728. PRIVATE m.bname, m.elipse, m.remain
  1729. m.elipse = "..." + m.g_pathsep
  1730. IF _MAC
  1731.     m.bname = SUBSTR(m.filname, RAT(":",m.filname)+1)
  1732. ELSE
  1733.     m.bname = justfname(m.filname)
  1734. ENDIF
  1735. DO CASE
  1736. CASE LEN(m.filname) <= m.fillen
  1737.    m.retstr = m.filname
  1738. CASE LEN(m.bname) + LEN(m.elipse) >= m.fillen
  1739.    m.retstr = m.bname
  1740. OTHERWISE
  1741.    m.remain = MAX(m.fillen - LEN(m.bname) - LEN(m.elipse), 0)
  1742.    IF _MAC
  1743.        m.retstr = LEFT(SUBSTR(m.filname,1,RAT(":",m.filname)-1),m.remain) ;
  1744.             +m.elipse+m.bname
  1745.    ELSE
  1746.          m.retstr = LEFT(justpath(m.filname),m.remain)+m.elipse+m.bname
  1747.    ENDIF
  1748. ENDCASE
  1749. RETURN m.retstr
  1750.  
  1751. **
  1752. ** Error Handling Code
  1753. **
  1754.  
  1755. *
  1756. * ERRORHANDLER - Error Processing Center.
  1757. *
  1758. PROCEDURE errorhandler
  1759.     PARAMETERS m.messg, m.lineno, m.code
  1760.     IF ERROR() = 22
  1761.         ON ERROR &onerror
  1762.         DO cleanup
  1763.         CANCEL
  1764.     ENDIF
  1765.  
  1766.     DO CASE
  1767.         CASE m.code == c_error_1  && Minor
  1768.             DO errlog WITH m.messg, m.lineno
  1769.             m.g_status = 1
  1770.         CASE m.code == c_error_2  && Serious
  1771.             DO errlog  WITH m.messg, m.lineno
  1772.             DO errshow WITH m.messg, m.lineno
  1773.             m.g_error = .T.
  1774.             m.g_status = 2
  1775.             ON ERROR
  1776.         CASE m.code == c_error_3  && Fatal
  1777.             IF NOT m.g_nohandle
  1778.                 DO errlog  WITH m.messg, m.lineno
  1779.             ENDIF
  1780.             DO errshow WITH m.messg, m.lineno
  1781.             IF WEXIST("Thermomete") AND WVISIBLE("Thermomete")
  1782.                 RELEASE WINDOW thermometer
  1783.             ENDIF
  1784.             ON ERROR
  1785.             DO cleanup
  1786.             CANCEL
  1787.     ENDCASE
  1788.  
  1789. *
  1790. * ESCHANDLER - Escape handler.
  1791. *
  1792. PROCEDURE eschandler
  1793.     ON ERROR
  1794.     WAIT WINDOW c_msg_genstopped NOWAIT
  1795.     DO builddisable
  1796.     IF m.g_status > 0
  1797.         ERASE (m.g_outfile)
  1798.     ENDIF
  1799.     IF WEXIST("Thermomete") AND WVISIBLE("Thermomete")
  1800.         RELEASE WINDOW thermometer
  1801.     ENDIF
  1802.     DO cleanup
  1803.     CANCEL
  1804.  
  1805. *
  1806. * ERRLOG - Insert error message into the error log.
  1807. *
  1808. PROCEDURE errlog
  1809.     PARAMETER m.messg, m.lineno
  1810.     PRIVATE m.savehandle
  1811.     m.savehandle = _TEXT
  1812.     DO openerrfile
  1813.     SET CONSOLE OFF
  1814.  
  1815.     \\GENERATOR: <<ALLTRIM(m.messg)>>
  1816.     IF NOT EMPTY(m.lineno)
  1817.         \\ LINE NUMBER: <<m.lineno>>
  1818.     ENDIF
  1819.     \
  1820.     = FCLOSE(_TEXT)
  1821.     _TEXT = m.savehandle
  1822.  
  1823. *
  1824. * ERRSHOW - Display error message in the alert box.
  1825. *
  1826. PROCEDURE errshow
  1827.     PARAMETER m.msg, m.lineno
  1828.     PRIVATE m.curcursor
  1829.  
  1830.     IF m.g_graphic
  1831.         DEFINE WINDOW alert ;
  1832.             AT  INT((SROW() - (( 5.615 * ;
  1833.             fontmetric(1, m.g_dlgface, m.g_dlgsize, m.g_dlgstyle )) / ;
  1834.             fontmetric(1, wfont(1,""), wfont(2,""), wfont(3,"")))) / 2), ;
  1835.             INT((SCOL() - (( 63.833 * ;
  1836.             fontmetric(6, m.g_dlgface, m.g_dlgsize, m.g_dlgstyle )) / ;
  1837.             fontmetric(6, wfont(1,""), wfont(2,""), wfont(3,"")))) / 2) ;
  1838.             SIZE 5.615,63.833 ;
  1839.             font m.g_dlgface, m.g_dlgsize ;
  1840.             STYLE m.g_dlgstyle ;
  1841.             NOCLOSE ;
  1842.             DOUBLE ;
  1843.             TITLE c_err_title ;
  1844.             COLOR rgb(0, 0, 0, 255, 255, 255)
  1845.  
  1846.         ACTIVATE WINDOW alert NOSHOW
  1847.  
  1848.         m.msg = SUBSTR(m.msg,1,44)+IIF(LEN(m.msg)>44,"...","")
  1849.         @ 1,(WCOLS()-txtwidth( m.msg ))/2 SAY m.msg
  1850.  
  1851.         m.msg = c_err_lineno + STR(m.lineno, 4)
  1852.         @ 2,(WCOLS()-txtwidth( m.msg ))/2 SAY m.msg
  1853.  
  1854.         m.msg = c_err_presskey
  1855.         @ 3,(WCOLS()-txtwidth( m.msg ))/2 SAY m.msg
  1856.  
  1857.         SHOW WINDOW alert
  1858.     ELSE
  1859.         DEFINE WINDOW alert;
  1860.             FROM INT((SROW()-6)/2), INT((SCOL()-50)/2) TO INT((SROW()-6)/2) + 6, INT((SCOL()-50)/2) + 50 ;
  1861.             FLOAT NOGROW NOCLOSE NOZOOM    SHADOW DOUBLE;
  1862.             COLOR SCHEME 7
  1863.  
  1864.         ACTIVATE WINDOW alert
  1865.  
  1866.         @ 0,0 CLEAR
  1867.         @ 1,0 SAY PADC(SUBSTR(m.msg,1,44)+;
  1868.             IIF(LEN(m.msg)>44,"...",""), WCOLS())
  1869.         @ 2,0 SAY PADC(c_err_lineno + STR(m.lineno, 4), WCOLS())
  1870.         @ 3,0 SAY PADC(c_err_presskey, WCOLS())
  1871.     ENDIF
  1872.  
  1873.     m.curcursor = SET( "CURSOR" )
  1874.     SET CURSOR OFF
  1875.  
  1876.     WAIT ""
  1877.  
  1878.     RELEASE WINDOW alert
  1879.     SET CURSOR &curcursor
  1880.  
  1881.     RELEASE WINDOW alert
  1882.  
  1883. *
  1884. * OPENERRFILE - Open error file.
  1885. *
  1886. PROCEDURE openerrfile
  1887.     PRIVATE m.errfile, m.errhandle
  1888.     m.errfile   = m.g_errlog+".ERR"
  1889.     m.errhandle = FOPEN(m.errfile,2)
  1890.     IF m.errhandle < 0
  1891.         m.errhandle = FCREATE(m.errfile)
  1892.         IF m.errhandle < 0
  1893.             DO errshow WITH c_err_noopenerr, LINENO()
  1894.             m.g_status = 2
  1895.             IF WEXIST("Thermomete") AND WVISIBLE("Thermomete")
  1896.                 RELEASE WINDOW thermometer
  1897.             ENDIF
  1898.             ON ERROR
  1899.             RETURN TO MASTER
  1900.         ENDIF
  1901.     ELSE
  1902.         = FSEEK(m.errhandle,0,2)
  1903.     ENDIF
  1904.     IF SET("TEXTMERGE") = "OFF"
  1905.         SET TEXTMERGE ON
  1906.     ENDIF
  1907.     _TEXT = m.errhandle
  1908.  
  1909. *
  1910. * GETCNAME - Manufacture a procedure name, unless there is a #NAME directive
  1911. *
  1912. FUNCTION getcname
  1913. PARAMETERS snippet
  1914. PRIVATE ALL
  1915. IF proctype = 1
  1916.    numlines = MEMLINES(snippet)
  1917.    IF m.numlines > 0
  1918.       _MLINE = 0
  1919.       m.i = 1
  1920.       DO WHILE m.i <= m.numlines
  1921.          m.thisline = UPPER(ALLTRIM(MLINE(snippet,1, _MLINE)))
  1922.          DO CASE
  1923.          CASE LEFT(m.thisline,5) == "#NAME"
  1924.             RETURN ALLTRIM(SUBSTR(m.thisline,6))
  1925.          CASE EMPTY(m.thisline) OR iscomment(m.thisline)
  1926.             * Do nothing.  Get next line.
  1927.          OTHERWISE
  1928.             EXIT
  1929.          ENDCASE
  1930.          m.i = m.i + 1
  1931.       ENDDO
  1932.    ENDIF
  1933. ENDIF
  1934. RETURN LOWER(SYS(2015))
  1935.  
  1936. *
  1937. * ISCOMMENT - Determine if textline is a comment line.
  1938. *
  1939. FUNCTION IsComment
  1940. PARAMETER m.textline
  1941. PRIVATE m.asterisk, m.isnote, m.ampersand, m.statement
  1942. IF EMPTY(m.textline)
  1943.    RETURN .F.
  1944. ENDIF
  1945. m.statement = UPPER(ALLTRIM(m.textline))
  1946.  
  1947. m.asterisk  = AT("*", LEFT(m.statement,1))
  1948. m.ampersand = AT(CHR(38)+CHR(38), LEFT(m.statement,2))
  1949. m.isnote    = AT("NOTE", LEFT(m.statement,4))
  1950.  
  1951. DO CASE
  1952. CASE (m.asterisk = 1 OR m.ampersand = 1)
  1953.    RETURN .T.
  1954. CASE (m.isnote = 1 ;
  1955.         AND (LEN(m.statement) <= 4 OR SUBSTR(m.statement,5,1) = ' '))
  1956.    * Don't be fooled by something like "notebook = 7"
  1957.    RETURN .T.
  1958. ENDCASE
  1959. RETURN .F.
  1960. *
  1961. * WORDNUM - Returns w_num-th word from string strg
  1962. *
  1963. FUNCTION wordnum
  1964. PARAMETERS strg,w_num
  1965. PRIVATE strg,s1,w_num,ret_str
  1966.  
  1967. m.s1 = ALLTRIM(m.strg)
  1968.  
  1969. * Replace tabs with spaces
  1970. m.s1 = CHRTRAN(m.s1,CHR(9)," ")
  1971.  
  1972. * Reduce multiple spaces to a single space
  1973. DO WHILE AT('  ',m.s1) > 0
  1974.    m.s1 = STRTRAN(m.s1,'  ',' ')
  1975. ENDDO
  1976.  
  1977. ret_str = ""
  1978. DO CASE
  1979. CASE m.w_num > 1
  1980.    DO CASE
  1981.    CASE AT(" ",m.s1,m.w_num-1) = 0   && No word w_num.  Past end of string.
  1982.       m.ret_str = ""
  1983.    CASE AT(" ",m.s1,m.w_num) = 0     && Word w_num is last word in string.
  1984.       m.ret_str = SUBSTR(m.s1,AT(" ",m.s1,m.w_num-1)+1,255)
  1985.    OTHERWISE                         && Word w_num is in the middle.
  1986.       m.strt_pos = AT(" ",m.s1,m.w_num-1)
  1987.       m.ret_str  = SUBSTR(m.s1,strt_pos,AT(" ",m.s1,m.w_num)+1 - strt_pos)
  1988.    ENDCASE
  1989. CASE m.w_num = 1
  1990.    IF AT(" ",m.s1) > 0               && Get first word.
  1991.       m.ret_str = SUBSTR(m.s1,1,AT(" ",m.s1)-1)
  1992.    ELSE                              && There is only one word.  Get it.
  1993.       m.ret_str = m.s1
  1994.    ENDIF
  1995. ENDCASE
  1996. RETURN ALLTRIM(m.ret_str)
  1997. *!*****************************************************************************
  1998. *!
  1999. *!      Function: VERSNUM
  2000. *!
  2001. *!*****************************************************************************
  2002. FUNCTION versnum
  2003. * Return string corresponding to FoxPro version number
  2004. RETURN STRTRAN(SUBS(VERS(),AT(".",VERS())-2),"0","",1,1) 
  2005.  
  2006.  
  2007. *!*****************************************************************************
  2008. *!
  2009. *!       Function: JUSTFNAME
  2010. *!
  2011. *!      Called by: FORCEEXT()         (function  in GENSCRN.PRG)
  2012. *!
  2013. *!*****************************************************************************
  2014. FUNCTION justfname
  2015. PARAMETERS m.filname
  2016. PRIVATE ALL
  2017. IF RAT('\',m.filname) > 0
  2018.    m.filname = SUBSTR(m.filname,RAT('\',m.filname)+1,255)
  2019. ENDIF
  2020. IF AT(':',m.filname) > 0
  2021.    m.filname = SUBSTR(m.filname,AT(':',m.filname)+1,255)
  2022. ENDIF
  2023. RETURN ALLTRIM(UPPER(m.filname))
  2024.  
  2025.