home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / xbase / foxupdat / upd_dk.exe / WIZARD / DKSETUP.PRG next >
Text File  |  1993-10-07  |  104KB  |  3,018 lines

  1. *!*****************************************************************************
  2. *!
  3. *:     Program: DKSETUP.PRG
  4. *!
  5. *!*****************************************************************************
  6. * Microsoft FoxPro SetupWizard -- FoxPro 2.5 for Windows
  7. * This program is designed to simplify the process of creating the installation
  8. *   disks for a FoxPro developer to install a FoxPro application on a user's machine.
  9. * Copyright, Microsoft Corp., 1993
  10. * Written by Walter J. Kennamer
  11.  
  12. PROCEDURE dksetup
  13. EXTERNAL SCREEN dkscrn1, dkscrn2, dkscrn3, dkscrn4, dkscrn5, dkscrn6, dkscrn7,;
  14.    dkscrn8, dkscrn9, dkscrn10
  15. EXTERNAL LIBRARY foxtools.fll
  16. PRIVATE ALL
  17.  
  18. * Carriage return/line feed
  19. #DEFINE c_crlf CHR(13)+CHR(10)
  20.  
  21. * View file name
  22. #DEFINE c_vuename      dksetup.vue
  23. #DEFINE c_vuename_str "DKSETUP.VUE"
  24.  
  25. * File names for standard files used by Wizard or by SETUP.EXE
  26. #DEFINE c_setupinf    "SETUP.INF"
  27. #DEFINE c_setuplst    "SETUP.LST"
  28. #DEFINE c_eslfile     "FOXW250B.ESL"
  29.  
  30. * File names for obsolete compressed files
  31. #DEFINE c_oldesl      "FOXW2500.ESL"
  32. #DEFINE c_oldesl1     "FOXW250A.ESL"
  33.  
  34. * Default max 512-byte units before file split.  May be changed in INI file 
  35. #DEFINE c_units        710    
  36.  
  37. * User push button actions
  38. #DEFINE c_cancel 0
  39. #DEFINE c_back   1
  40. #DEFINE c_next   2
  41. #DEFINE c_done   3
  42.  
  43. * Error message codes
  44. #DEFINE c_status  1
  45. #DEFINE c_warning 2
  46. #DEFINE c_fatal   3
  47. #DEFINE c_entry   4   && data entry validation error
  48. #DEFINE c_entry1  5   && data entry validation error, with option to cancel
  49. #DEFINE c_entry2  6   && data entry validation error, with Yes/No prompt
  50.  
  51. * Error numbers--indexes into error_array
  52. #DEFINE en_extension   1
  53. #DEFINE en_foxtools    2
  54. #DEFINE en_dir1        3
  55. #DEFINE en_dir2        4
  56. #DEFINE en_dir3        5
  57. #DEFINE en_noexe       6
  58. #DEFINE en_fxtver      7
  59. #DEFINE en_nortfiles   8 
  60. #DEFINE en_missing     9
  61. #DEFINE en_notfound   10
  62. #DEFINE en_getfile    11
  63. #DEFINE en_hidden     12
  64. #DEFINE en_blanksrc   13
  65. #DEFINE en_noreq      14
  66. #DEFINE en_ufopen     15
  67. #DEFINE en_cprserr    16
  68. #DEFINE en_toobig     17
  69. #DEFINE en_blankexe   18
  70. #DEFINE en_exemiss    19
  71. #DEFINE en_exem1      20
  72. #DEFINE en_toolong    21
  73. #DEFINE en_nocompress 22
  74. #DEFINE en_missreq    23
  75. #DEFINE en_nogroup    24
  76. #DEFINE en_oldver     25
  77. #DEFINE en_cprsdead   26
  78. #DEFINE en_badpath    27
  79. #DEFINE en_nocfg      28
  80. #DEFINE en_baddir     29
  81. #DEFINE en_dir4       30
  82.  
  83. * Displayed as message box title
  84. #DEFINE e_error_title "Microsoft FoxPro Setup-Assistent - Fehler"
  85.  
  86. * Disk types, corresponding to dtype entry in DISKS.DBF
  87. #DEFINE c_dsk144 1
  88. #DEFINE c_dsk12  2
  89. #DEFINE c_dsk720 3
  90.  
  91. * User Modification options
  92. #DEFINE c_modall   1  && User can modify both default directory and PM Group
  93. #DEFINE c_modgroup 2  && User can modify just the PM group
  94. #DEFINE c_modnone  3  && User can modify neither directory or PM Group
  95.  
  96. * The name of the compress directory, off the destination tree
  97. #DEFINE c_cprsdir "COMPRESS"
  98.  
  99. * Preferences constants--no translation needed
  100. #DEFINE c_setupini    SYS(2004)+"DKSETUP.INI"
  101. #DEFINE c_pref        "Preferences"
  102. #DEFINE c_sourcedir   "SourceDirectory"
  103. #DEFINE c_destdir     "DestinationDirectory"
  104. #DEFINE c_runtime     "RuntimeDirectory"
  105. #DEFINE c_make144     "Make1.44MegDisks"
  106. #DEFINE c_make12      "Make1.2MegDisks"
  107. #DEFINE c_make720     "Make720KDisks"
  108. #DEFINE c_instgraph   "InstallGraph"
  109. #DEFINE c_targetdir   "UserDefaultDirectory"
  110. #DEFINE c_appname     "ApplicationName"
  111. #DEFINE c_pmdescript  "ProgManDescript"
  112. #DEFINE c_runanother  "PostExecute"
  113. #DEFINE c_setuptitle  "SetupBanner"
  114. #DEFINE c_copyright   "Copyright"
  115. #DEFINE c_splitsize   "SplitSize"
  116. #DEFINE c_algorithm   "Algorithm"
  117. #DEFINE c_usermod     "UserCanModify"
  118. #DEFINE c_pmgroup     "ProgManGroup"
  119. #DEFINE c_nologo      "SuppressLogo"
  120. #DEFINE c_parameters  "EXEParameters"
  121. #DEFINE c_altcfgfile  "ConfigFile"
  122.  
  123. * Message box responses, from WIN16.H file.
  124. #DEFINE idok            1
  125. #DEFINE idcancel        2
  126. #DEFINE idabort         3
  127. #DEFINE idretry         4
  128. #DEFINE idignore        5
  129. #DEFINE idyes            6
  130. #DEFINE idno            7
  131.  
  132. * Number of columns in the disk statistics array
  133. #DEFINE c_diskcols 3
  134.  
  135. * Extension of files that are given random names
  136. #DEFINE c_randext  "SET"
  137.  
  138. * Strings used in the program
  139. #DEFINE c_product     "Microsoft FoxPro"
  140. #DEFINE c_setupname   "Setup-Assistent"
  141. #DEFINE c_thermprompt "Erstellen der Setup-Disketten..."
  142.  
  143. * SET MESSAGE TO strings -- these need to be translated
  144. #DEFINE s_winonly     "Der Setup-Assistent ben÷tigt FoxPro fⁿr Windows"
  145. #DEFINE s_to1          "zu"
  146. #DEFINE s_to2          "auf"
  147. #DEFINE s_filling     "Suche nach den Dateien der Anwendung"
  148. #DEFINE s_compressing "▄berprⁿfen auf Eindeutigkeit der Dateinamen"
  149. #DEFINE s_batch       "Vorbereiten der Dateikomprimierung"
  150. #DEFINE s_cprs        "Komprimieren der Dateien der Anwendung"
  151. #DEFINE s_canceling   "Setup wird abgebrochen"
  152. #DEFINE s_mkdir       "Ausgabe-Verzeichnisse werden erstellt"
  153. #DEFINE s_copying     "Kopieren von"
  154. #DEFINE s_required    "Installieren der Setup-Unterstⁿtzungsdateien"
  155. #DEFINE s_assign      "Zuweisen der Dateien"
  156. #DEFINE s_ufsize      "Ermitteln der Dateigr÷▀e der nicht komprimierten Dateien"
  157. #DEFINE s_cprssize    "Ermitteln der Dateigr÷▀e der komprimierten Dateien"
  158. #DEFINE s_makeinf     "Erstellen der Setup-Informationsdatei"
  159. #DEFINE s_splitting   "Erneutes Teilen von"
  160. #DEFINE s_again       ". Bitte nicht unterbrechen."
  161. #DEFINE s_setuptitle  "Setup"   && default title
  162. #DEFINE s_setupinit   "Initialisieren von Setup..."
  163. #DEFINE s_escape      "Beenden des Setup-Assistenten"
  164. #DEFINE s_cleanup     "L÷schen der EintrΣge fⁿr"
  165.  
  166. IF SET("TALK") = "ON"
  167.    SET TALK OFF
  168.    m.mtalk = "ON"
  169. ELSE
  170.    m.mtalk = "OFF"
  171. ENDIF
  172.  
  173. * SET state variables.  Declared here so as to be visible in both init and cleanup.
  174. STORE "" TO m.mtrbet,m.mecho,m.mdebug,m.mstep,m.mudfparms,m.mcompat,m.mexact,;
  175.    m.mnear,m.munique,m.mansi,m.mcarry, m.mstatus, m.mescape, m.merror, m.mlibrary, ;
  176.    m.mdefault, m.mpoint, m.mdecimals
  177.  
  178. IF _WINDOWS
  179.    DO init
  180.    DO main
  181.    DO cleanup
  182. ELSE
  183.    WAIT WINDOW s_winonly NOWAIT
  184. ENDIF
  185. RETURN
  186. *!*****************************************************************************
  187. *!
  188. *!     Procedure: MAIN
  189. *!
  190. *!*****************************************************************************
  191. PROCEDURE main
  192. DIMENSION error_array[30]
  193. error_array = ""
  194. error_array[en_extension] = "Die Dateinamenerweiterung mu▀ .EXE, .COM, .PIF oder .BAT lauten."
  195. error_array[en_foxtools]  = "Der Setup-Assistent ben÷tigt FOXTOOLS.FLL."
  196. error_array[en_fxtver]    = "Der Setup-Assistent ben÷tigt Version 1.01"+c_crlf+"oder h÷her von FOXTOOLS.FLL."
  197. error_array[en_dir1]      = "Die Verzeichnisse mit den Quell- und den komprimierten"+c_crlf+"Dateien dⁿrfen nicht identisch sein."
  198. error_array[en_dir2]      = "Die Quell- und Zielverzeichnisse"+c_crlf+"dⁿrfen nicht identisch sein."
  199. error_array[en_dir3]      = "Das Verzeichnis mit den komprimierten Dateien und"+c_crlf+"das Zielverzeichnis dⁿrfen nicht identisch sein."
  200. error_array[en_noexe]     = "Es sind keine APP-, PRG-, FXP- oder EXE-"+c_crlf+"Dateien in diesem Verzeichnis vorhanden."
  201. error_array[en_nortfiles] = "Es sind keine Dateien im Distribution Kit-Verzeichnis vorhanden."
  202. error_array[en_missing]   = "(fehlt)"
  203. error_array[en_notfound]  = "konnte nicht gefunden werden."
  204. error_array[en_getfile]   = "Suchen?"
  205. error_array[en_hidden]    = "Versteckte oder Systemdatei gefunden in"
  206. error_array[en_blanksrc]  = "Es mu▀ ein Verzeichnisname angegeben werden."
  207. error_array[en_blankexe]  = "Es mu▀ ein Anwendungsname angegeben werden."
  208. error_array[en_noreq]     = "Eine der ben÷tigten Dateien konnte unerwarteterweise nicht gefunden werden."
  209. error_array[en_ufopen]    = "Fehler beim Ermitteln der Dateigr÷▀e der nicht komprimierten Datei."
  210. error_array[en_cprserr]   = "Fehler beim Komprimieren von"
  211. error_array[en_toobig]    = "Datei ist zu gro▀; sie kann von COMPRESS"+c_crlf+"nicht in 9 oder weniger Teile geteilt werden."
  212. error_array[en_exemiss]   = "Die .EXE-Datei der Anwendung konnte nicht gefunden werden."
  213. error_array[en_exem1]     = "Die .EXE-Datei der Anwendung konnte nicht"+c_crlf+"in der Verzeichnisstruktur der Anwendung gefunden werden."
  214. error_array[en_toolong]   = "Der Kompressionsbefehl ⁿberschreitet die DOS-Grenze von 128 Bytes."+c_crlf;
  215.                             +"Versuchen Sie, Verzeichnisnamen zu kⁿrzen oder COMPRESS in ein Verzeichnis"+c_crlf;
  216.                             +"zu kopieren, das in der Umgebungsvariable PATH aufgefⁿhrt wird."
  217. error_array[en_nocompress]= "COMPRESS.EXE konnte nicht gefunden werden."
  218. error_array[en_missreq]   = "Ben÷tigte Datei fehlt: "+c_crlf
  219. error_array[en_nogroup]   = "Es mu▀ eine Programmgruppe angegeben werden."
  220. error_array[en_oldver]    = "Ihre Datei DKCONTRL.DBF ist nicht mehr aktuell. Bitte l÷schen Sie die Datei."
  221. error_array[en_cprsdead]  = "Fehler wΣhrend der Komprimierung. Der Komprimiervorgang wurde evtl. unterbrochen."
  222. error_array[en_badpath]   = "Dieser Pfad oder Dateiname ist ungⁿltig."
  223. error_array[en_nocfg]     = "Das Feld fⁿr die alternative CONFIG-Datei ist leer."
  224. error_array[en_baddir]    = "Erstellen nicht m÷glich von Verzeichnis"
  225. error_array[en_dir4]      = "Das Zielverzeichnis darf nicht Teil der Verzeichnisstruktur der Anwendung sein."
  226.  
  227. m.g_defdrive   = SET("DEFAULT")
  228.  
  229. * Default values for data items prompted for in the interface.  Once the user runs the 
  230. * Wizard the first time, his previous choices are stored in DKSETUP.INI and become the 
  231. * defaults for future sessions.
  232. m.g_sourcedir  = ""     && the "root" of the application
  233. m.g_cprsdir    = ""     && where the compressed files go
  234. m.g_destdir    = ""     && root of destination tree
  235. m.g_targetdir  = ""     && default directory on ultimate user's machine
  236. m.g_dsk144     = .T.    && make 1.44 meg disks?
  237. m.g_dsk12      = .F.    && make 1.2  meg disks?
  238. m.g_dsk720     = .F.    && make 720K disks?
  239. m.g_instgraph  = .F.    && Install MSGraph?
  240. m.g_pmdescript = ""     && ProgMan description
  241. m.g_pmgroup    = ""     && ProgMan group
  242. m.g_usealtcfg  = 0      && Use alternative CONFIG.FPW file?
  243. m.g_altcfgfile = ""     && name of alternative CONFIG.FPW file
  244. m.g_modoptions = 1      && allow user to modify PM Group and directory?
  245. m.g_nologo     = 1      && suppress FoxPro logo
  246. m.g_appname    = ""     && name of application
  247. m.g_executable = ""     && name of program to run after completion of setup
  248. m.g_title      = ""     && Banner to display during setup
  249. m.g_copyright  = ""     && Copyright notice to display during setup
  250. m.g_parameters = ""     && optional parameters passed to user EXE
  251.  
  252. * Find the runtime files
  253. m.g_runtimedir = SYS(2004)+"DKSETUP"     && where the runtime files are by default
  254.  
  255. * Items that are stored in the INI file but not prompted for.
  256. m.g_splitsize  = c_units * 512   && split files down to this size
  257. m.g_algorithm  = "2"    && compression algorithm.  Can be 2 or 3.  2 is faster.  3 is smaller.
  258.  
  259. * Where is FOXW2500.ESL?
  260. m.g_esl        = SYS(2004)+c_eslfile       && name and location of ESL file
  261. m.g_eslextra   = .F.                       && is the ESL file outside the app tree?
  262.  
  263. * Name of the control file that records the files involved in this setup, their locations
  264. * and sizes, and the disks they are assigned to.  This file is written to the application
  265. * root directory.  It is not installed onto user disks.  
  266. m.g_dkcname   = "DKCONTRL.DBF"
  267. m.g_dbalias   = "DKCONTRL"
  268.  
  269. m.g_firstset  = .T.    && first set of disks (e.g., 1.44 meg) not yet completed
  270. m.g_newctrl   = .T.    && assume we are making a new DKCONTRL database.
  271. m.g_foxprint  = .T.    && is FoxPrint being installed?
  272.  
  273. m.g_thermwidth = 0     && set in Acttherm()
  274.  
  275. * Dimension the array that contains disk statistics (one row per disk).
  276. * Column 1 contains the number of files on the disk.  Column 2 contains the
  277. * actual nominal file size total for the disk.  Column 3 contains the bytes
  278. * in allocated clusters for the disk.
  279. m.g_diskcount = 1
  280. DIMENSION g_disks[1,c_diskcols]
  281. g_disks = 0
  282.  
  283. * Install the FOXTOOLS library.  This library contains many functions used throughout
  284. * the Wizard, including the filename parsing functions, the MessageBox function and the
  285. * CALLDLLs functions that we use to manage the DKSETUP.INI file.
  286. IF FILE(SYS(2004)+"FOXTOOLS.FLL")
  287.    SET LIBRARY TO (SYS(2004)+"FOXTOOLS.FLL") ADDITIVE
  288.    IF foxtoolver() < "1.01"
  289.       DO errormsg WITH en_fxtver, c_fatal
  290.       RETURN
  291.    ENDIF
  292. ELSE
  293.    * Don't use message box here, since the function to display it is inside FoxTools.
  294.    WAIT WINDOW e_foxtools NOWAIT
  295.    RETURN
  296. ENDIF
  297.  
  298. * Retrieve last set of user's responses
  299. DO getpreferences WITH c_setupini
  300.  
  301. * Start the wizard and allow the user to run through the screens
  302. IF dispatch() = c_cancel
  303.    RETURN TO dksetup
  304. ENDIF
  305.  
  306. * Record this set of responses
  307. DO putpreferences WITH c_setupini
  308. DO putpreferences WITH addbs(m.g_sourcedir)+justfname(c_setupini)
  309.  
  310. * Determine the compress directory
  311. m.g_cprsdir = addbs(m.g_destdir) + c_cprsdir
  312.  
  313. * Start the thermometer
  314. DO acttherm WITH c_setupname
  315. =updtherm(5)
  316.  
  317. * Create or open the control database
  318. m.dkcname = getctrl(addbs(m.g_sourcedir)+m.g_dkcname, @m.g_dbalias)
  319.  
  320. =updtherm(10)
  321.  
  322. * Fill in the dkcontrl file with the names of all the files we want to install
  323. DO gatherdir
  324.  
  325. =updtherm(15)
  326.  
  327. * Generate unique compression names for the files in the application tree.
  328. DO genuniq WITH m.dkcname
  329.  
  330. =updtherm(25)
  331.  
  332. * Add the list of required files (e.g., those used by the Setup Toolkit, such as
  333. * SHELL.DLL and VER.DLL) to the dkcontrl database.
  334. DO reqfiles
  335.  
  336. * Install FoxPrint fonts if they are present in the DKSETUP directory
  337. DO fpinst
  338.  
  339. =updtherm(35)
  340.  
  341. * Add any optional components (e.g., Graph runtime) that user has selected
  342. DO optinst
  343.  
  344. * Add the file to be executed at conclusion of setup, if any
  345. DO executinst
  346.  
  347. =updtherm(40)
  348.  
  349. * Lay out the files into disks.  Start with a new array for each set.
  350. IF m.g_dsk144
  351.    m.g_diskcount = 1
  352.    g_disks = 0   && initialize the array to 0
  353.    DO makedisks WITH c_dsk144, m.g_destdir
  354.    m.g_firstset = .F.
  355. ENDIF
  356. IF m.g_dsk12
  357.    m.g_diskcount = 1
  358.    g_disks = 0
  359.    DO makedisks WITH c_dsk12, m.g_destdir
  360.    m.g_firstset = .F.
  361. ENDIF
  362. IF m.g_dsk720
  363.    m.g_diskcount = 1
  364.    g_disks = 0
  365.    DO makedisks WITH c_dsk720, m.g_destdir
  366.    m.g_firstset = .F.
  367. ENDIF
  368.  
  369. =updtherm(100)
  370.  
  371. DO deactthermo
  372.  
  373. DO showsumry
  374.  
  375. *!*****************************************************************************
  376. *!
  377. *!     Procedure: INIT
  378. *!
  379. *!*****************************************************************************
  380. PROCEDURE init
  381. CREATE VIEW c_vuename
  382. CLOSE DATABASES
  383.  
  384. m.mlibrary = SET("LIBRARY",1)
  385. m.mstatus = SET("STATUS BAR")
  386. SET MESSAGE TO c_product + " " + c_setupname    && suppress database names, etc.
  387.  
  388. * These will be restored to their original values when the VUE file is restored.
  389. m.mtrbet = SET("TRBETWEEN")
  390. SET TRBETWEEN OFF
  391. m.mecho = SET("ECHO")
  392. SET ECHO OFF
  393. m.mdebug = SET("DEBUG")
  394. SET DEBUG OFF
  395. m.mstep = SET("STEP")
  396. SET STEP OFF
  397. m.mudfparms = SET("UDFPARMS")
  398. SET UDFPARMS TO VALUE
  399. m.mcompat = SET("COMPATIBLE")
  400. SET COMPATIBLE FOXPLUS
  401. m.mexact = SET("EXACT")
  402. SET EXACT OFF
  403. m.mnear = SET("NEAR")
  404. SET NEAR OFF
  405. m.munique = SET("UNIQUE")
  406. SET UNIQUE OFF
  407. m.mansi = SET("ANSI")
  408. SET ANSI OFF
  409. m.mcarry = SET("CARRY")
  410. SET CARRY OFF
  411. m.mpoint = SET("POINT")
  412. SET POINT TO "."
  413. m.decimals = SET("DECIMALS")
  414. m.mdefault = SET("DEFAULT")+CURDIR()
  415.  
  416. m.mescape = ON("ESCAPE")
  417. ON ESCAPE DO esc_handler
  418. m.merror = ON("ERROR")
  419. ON ERROR DO errorhandler WITH MESSAGE(), c_fatal
  420.  
  421. SELECT 0
  422. USE DISKS EXCLUSIVE
  423. SET ORDER TO TAG dtype
  424.  
  425. SELECT 0
  426. USE required EXCLUSIVE
  427.  
  428. SELECT 0
  429. USE naughty EXCLUSIVE
  430. SET ORDER TO TAG filname
  431.  
  432. *!*****************************************************************************
  433. *!
  434. *!     Procedure: CLEANUP
  435. *!
  436. *!*****************************************************************************
  437. PROCEDURE cleanup
  438. IF WEXIST("thermomete")
  439.    DO deactthermo
  440. ENDIF
  441. IF WEXIST("dksetup")
  442.    RELEASE WINDOW dksetup
  443. ENDIF
  444.  
  445. IF USED("naughty")   
  446.    SELECT naughty
  447.    USE
  448. ENDIF
  449. IF USED("required")   
  450.    SELECT required
  451.    USE
  452. ENDIF
  453. IF USED("disks")   
  454.    SELECT disks
  455.    USE
  456. ENDIF
  457. IF USED("dkcontrl")
  458.    SELECT dkcontrl
  459.    USE
  460. ENDIF        
  461. IF FILE(c_vuename_str)
  462.    SET VIEW TO c_vuename
  463.    DELETE FILE c_vuename
  464. ENDIF
  465.  
  466. ON ESCAPE &mescape
  467. ON ERROR &merror
  468.  
  469. IF !("FOXTOOLS" $ UPPER(m.mlibrary))
  470.    RELEASE LIBRARY (SYS(2004)+"FOXTOOLS.FLL")
  471. ENDIF
  472.  
  473. SET DEFAULT TO &mdefault
  474. SET STATUS BAR &mstatus
  475. SET TRBETWEEN &mtrbet
  476. SET ECHO &mecho
  477. SET DEBUG &mdebug
  478. SET STEP &mstep
  479. SET UDFPARMS TO &mudfparms
  480. SET COMPATIBLE &mcompat
  481. SET EXACT &mexact
  482. SET NEAR &mnear
  483. SET UNIQUE &munique
  484. SET ANSI &mansi
  485. SET CARRY &mcarry
  486. SET TALK &mtalk
  487. SET DECIMALS TO &mdecimals
  488. SET POINT TO "&mpoint"
  489. *!*****************************************************************************
  490. *!
  491. *!     Function: ERRORMSG
  492. *!
  493. *!*****************************************************************************
  494. FUNCTION errormsg
  495. PARAMETER m.msg, m.howbad
  496. PRIVATE m.icons, m.choice
  497.  
  498. * If the first parameter is a number, it's the index into the error_array array
  499. IF TYPE("m.msg") = "N"
  500.    m.msg = error_array[m.msg]
  501. ENDIF
  502.  
  503. * Message box defines
  504. #DEFINE mb_ok                    0
  505. #DEFINE mb_okcancel             1
  506. #DEFINE mb_abortretryignore 2
  507. #DEFINE mb_yesnocancel        3
  508. #DEFINE mb_yesno                4
  509. #DEFINE mb_retrycancel        5
  510. #DEFINE mb_iconhand             16
  511. #DEFINE mb_iconquestion        32
  512. #DEFINE mb_iconexclamation  48
  513. #DEFINE mb_iconasterisk     64
  514.  
  515. #DEFINE mb_iconinformation  mb_iconasterisk
  516. #DEFINE mb_iconstop           mb_iconhand
  517.  
  518. DO CASE
  519. CASE m.howbad = c_entry
  520.    m.icons = mb_iconstop + mb_ok
  521. CASE m.howbad = c_entry1
  522.    m.icons = mb_iconstop + mb_okcancel
  523. CASE m.howbad = c_entry2
  524.    m.icons = mb_iconstop + mb_yesno
  525. CASE m.howbad = c_status
  526.    m.icons = mb_iconexclamation + mb_okcancel
  527. CASE m.howbad = c_warning
  528.    m.icons = mb_iconstop + mb_ok
  529. CASE m.howbad = c_fatal
  530.    m.icons = mb_iconstop + mb_ok
  531. OTHERWISE
  532.    m.icons = mb_iconstop + mb_ok
  533. ENDCASE
  534.  
  535. m.choice = msgbox(msg,e_error_title,m.icons)
  536. DO CASE
  537. CASE m.howbad = c_fatal
  538.    RETURN idcancel
  539. CASE m.howbad = c_entry2
  540.    RETURN m.choice   && Yes or No
  541. CASE (m.howbad = c_warning) ;
  542.       OR (INLIST(m.howbad,c_status,c_entry1) AND m.choice = idcancel)
  543.    RETURN idcancel
  544. OTHERWISE
  545.    RETURN idok
  546. ENDCASE
  547.  
  548. *!*****************************************************************************
  549. *!
  550. *!     Procedure: ESC_HANDLER
  551. *!
  552. *!*****************************************************************************
  553. PROCEDURE esc_handler
  554. WAIT WINDOW s_escape NOWAIT
  555. RETURN TO dksetup
  556.  
  557. *!*****************************************************************************
  558. *!
  559. *!     Procedure: GETHELP
  560. *!
  561. *!*****************************************************************************
  562. PROCEDURE gethelp
  563. PARAMETER seekstrg
  564. m.in_area = SELECT()
  565. IF USED("dkhelp")
  566.    SELECT dkhelp
  567.    SET ORDER TO TAG topics
  568. ELSE
  569.    SELECT 0
  570.    USE dkhelp AGAIN ORDER TAG topics
  571. ENDIF
  572. SEEK seekstrg
  573. IF FOUND()
  574.    DO disphelp.spr
  575. ENDIF
  576. USE
  577. SELECT (m.in_area)
  578.  
  579. *!*****************************************************************************
  580. *!
  581. *!     Procedure: DISPATCH
  582. *!
  583. *!*****************************************************************************
  584. PROCEDURE dispatch
  585. * Manage the navigation from screen to screen
  586.  
  587. m.nextscrn = 1
  588. m.action = c_next
  589. DO WHILE m.action <> c_cancel AND m.action <> c_done
  590.    m.thisscrn = m.nextscrn   && nextscrn was set in the DKSCRNx.SPR program.
  591.    * Form the name of the next screen to go to.  The screens have to be numbered
  592.    * consecutively for this scheme to work properly.
  593.    DO ("dkscrn"+ALLTRIM(STR(nextscrn,2))+".spr") WITH m.action, m.thisscrn, m.nextscrn
  594.    @ 0.213,15.600 CLEAR TO 18.616, 97.800
  595. ENDDO
  596.  
  597. * Free the window that the interface uses
  598. IF WEXIST("DKSETUP")
  599.    RELEASE WINDOW dksetup
  600. ENDIF
  601.  
  602. RETURN m.action
  603.  
  604. *!*****************************************************************************
  605. *!
  606. *!     Procedure: CREATECTRL
  607. *!
  608. *!*****************************************************************************
  609. PROCEDURE createctrl
  610. PARAMETER m.dbfname
  611. *  Create the DBCONTRL file, which lists each file being copied to the destination disks.
  612. *  It has one record per file in the application tree, one record for each piece of a split
  613. *  file, and also contains records for Graph (if chosen), the executable program to run at
  614. *  the conclusion of setup, plus any required setup files or DLLs.
  615. *
  616. *  Its fields are as follows:
  617. *
  618. *   Fname    -- Character type     File name
  619. *   Filsize  -- Numeric            File size (see expndsize for split files, however)
  620. *   Fdate    -- Date               File date last changed
  621. *   Ftime    -- Character          File time
  622. *   Fattrib  -- Character          Attribute string
  623. *   Cprsname -- Character          Name of file when compressed
  624. *   Cprssize -- Numeric            Size of file when compressed
  625. *   Cprsflag -- Logical            Does file need to be compressed this pass?
  626. *   Expndsize-- Numeric            Expanded size, if a split file.  Same as filsize otherwise.
  627. *   Compress -- Logical            Is file ever compressed?
  628. *   Filfound -- Logical            Can the file be found?
  629. *   dest144  -- Numeric            Which 1.44meg disk does it go on?
  630. *   dest12   -- Numeric            Which 1.2 meg disk does it go on?
  631. *   dest720  -- Numeric            Which 720K disk does it go on?
  632. *   Setupfile-- Logical            Required file for SETUP.EXE?
  633. *   Extrafile-- Logical            Optional component (e.g., graph runtime)?
  634. *   Splitfile-- Logical            Is this a part of a split file?
  635. *   Parent   -- Character          Ultimate parent file, if this is a split file
  636. *   UniqueID -- Character          Matches parents and children
  637. PRIVATE ALL
  638. CREATE TABLE (m.dbfname) ( ;
  639.    fname C(80), ;
  640.    filsize N(10,0), ;
  641.    fdate D, ;
  642.    ftime C(10), ;
  643.    fattrib C(5), ;
  644.    cprsname C(12), ;
  645.    cprssize N(10,0), ;
  646.    expndsize N(10,0), ;
  647.    filfound l, ;
  648.    dest144 N(10,0), ;
  649.    dest12 N(10,0), ;
  650.    dest720 N(10,0), ;
  651.    setupfile l, ;
  652.    extrafile l, ;
  653.    cprsflag l, ;
  654.    COMPRESS l, ;
  655.    parent C(12), ;
  656.    splitfile l, ;
  657.    uniqueid C(12) ;
  658.    )
  659.  
  660. * Now construct the indexes we need
  661. INDEX ON UPPER(fname) TAG fname
  662. INDEX ON UPPER(cprsname) TAG cprsname
  663. INDEX ON STR(100000000-cprssize,10)+parent+cprsname TAG cprssize
  664. INDEX ON STR(dest144,3)+cprsname TAG dest144
  665. INDEX ON STR(dest12,3)+cprsname TAG dest12
  666. INDEX ON STR(dest720,3)+cprsname TAG dest720
  667. *!*****************************************************************************
  668. *!
  669. *!     Function: GETCTRL
  670. *!
  671. *!*****************************************************************************
  672. FUNCTION getctrl
  673. PARAMETER m.dbfname, m.aliasname
  674. PRIVATE m.numfiles
  675.  
  676. * First check for a zero-byte DKCONTRL file, which can be left hanging around
  677. * if a previous run of COMPRESS failed.
  678. m.numfiles = ADIR(rtdir,m.dbfname)
  679. IF m.numfiles = 1 AND rtdir[1,2] = 0
  680.    DELETE FILE (m.dbfname)
  681.    IF FILE(forceext(m.dbfname,"CDX"))
  682.       DELETE FILE (forceext(m.dbfname,"CDX"))
  683.    ENDIF
  684. ENDIF
  685.  
  686. * Create the control database if it doesn't already exist.  Open it.  Return the 
  687. * name of the database and the alias, which was passed in by reference.
  688. IF !FILE(m.dbfname) OR !FILE(forceext(m.dbfname,"CDX"))
  689.    DO createctrl WITH m.dbfname
  690.    m.g_newctrl = .T.
  691. ELSE 
  692.    m.g_newctrl = .F.   
  693. ENDIF
  694.  
  695. m.dbfstem = juststem(m.dbfname)
  696. IF USED(m.dbfstem)
  697.    SELECT (m.dbfstem)
  698. ELSE
  699.    SELECT 0
  700.    USE (m.dbfname) AGAIN EXCLUSIVE
  701. ENDIF
  702. IF TYPE("uniqueid") = "U"
  703.    DO errormsg WITH error_array[en_oldver],c_fatal
  704.    RETURN TO dksetup
  705. ENDIF
  706.  
  707. IF EMPTY(TAG(1)) AND FILE(forceext(m.dbfname,"CDX"))
  708.    SET INDEX TO (forceext(m.dbfname,"CDX"))
  709.    REINDEX
  710. ENDIF
  711.    
  712. SET ORDER TO TAG fname
  713. m.aliasname = ALIAS()
  714. RETURN m.dbfname
  715.  
  716. *!*****************************************************************************
  717. *!
  718. *!     Procedure: GATHERDIR
  719. *!
  720. *!*****************************************************************************
  721. PROCEDURE gatherdir
  722. * Read the application tree and record all the files in it.
  723. PRIVATE m.numeslfiles, m.eslaction
  724.  
  725. SET MESSAGE TO s_filling
  726.  
  727. SELECT (m.g_dbalias)
  728. REPLACE ALL filfound WITH .F.    && nothing found yet
  729.  
  730. * These get installed later
  731. DELETE ALL FOR extrafile AND !(UPPER(justfname(fname)) == UPPER(justfname(m.g_esl)))
  732.  
  733. PACK
  734.  
  735. * Filldir is a recursive function that puts the files in g_sourcedir and all
  736. * its subdirectories into the dkcontrl database.
  737. DO filldir WITH addbs(m.g_sourcedir)+"*.*",m.dkcname,"",m.g_dbalias
  738.  
  739. SELECT (m.g_dbalias)
  740. GOTO TOP
  741.  
  742. * Verify that the application EXE file was in there somewhere
  743. LOCATE FOR UPPER(ALLTRIM(justfname(fname))) == UPPER(ALLTRIM(justfname(m.g_appname)))
  744. IF !FOUND()
  745.    DO errormsg WITH error_array[en_exem1],c_fatal
  746.    RETURN TO dksetup
  747. ENDIF
  748.  
  749. DO instesl
  750.  
  751. *!*****************************************************************************
  752. *!
  753. *!     Procedure: FILLDIR
  754. *!
  755. *!*****************************************************************************
  756. PROCEDURE filldir
  757. *
  758. * Note: Recursive procedure!
  759. *
  760. * Find file names in the specified directory and all subdirectories beneath it.  Put
  761. * the filenames in dbfname.  Preface is the path to get to the files in the
  762. * directory we are searching.
  763. *
  764. * Dbalias is the alias of the DBCONTRL file.
  765. *
  766.  
  767. PARAMETER m.dirmask, m.dbfname, m.preface, m.dbalias, m.prevthere
  768. PRIVATE ALL
  769.  
  770. m.in_defa = SET("DEFAULT")+CURDIR()    && both drive and directory name
  771.  
  772. * Get actual filenames (no directories) in this directory
  773. m.numfiles = ADIR(dirlist,m.dirmask)
  774.  
  775. FOR m.i = 1 TO m.numfiles
  776.    * First make sure that this file isn't on the list of files we won't install.  Such
  777.    * files include portions of the FoxPro system that are not licensed to be distributed,
  778.    * miscellaneous files that the SetupWizard puts into the application tree (e.g.,
  779.    * the DKCONTRL files, etc.
  780.    SELECT naughty
  781.    SET ORDER TO TAG filname
  782.    SEEK ALLTRIM(UPPER(justfname(dirlist[m.i,1])))
  783.    IF !FOUND()   && not a prohibited file
  784.       SELECT (m.dbalias)
  785.       SET ORDER TO TAG fname
  786.       m.srchterm = addbs(m.preface) + dirlist[m.i,1]
  787.  
  788.       LOCATE FOR ALLTRIM(UPPER(fname)) == ALLTRIM(UPPER(m.srchterm)) AND EMPTY(parent) ;
  789.          AND !DELETED()
  790.       IF !FOUND()
  791.          APPEND BLANK
  792.          m.prevthere = .F.
  793.       ELSE
  794.          m.prevthere = .T.
  795.       ENDIF
  796.  
  797.       REPLACE fname WITH addbs(m.preface) + dirlist[m.i,1], ;
  798.          filsize WITH dirlist[m.i,2],;
  799.          fdate WITH dirlist[m.i,3],;
  800.          ftime WITH dirlist[m.i,4],;
  801.          fattrib WITH dirlist[m.i,5]
  802.  
  803.       IF !m.prevthere
  804.          REPLACE expndsize WITH filsize
  805.          REPLACE parent WITH ""
  806.          REPLACE splitfile WITH .F.        && assume no split for new file
  807.          REPLACE uniqueid WITH SYS(3)
  808.       ENDIF
  809.  
  810.       REPLACE COMPRESS WITH .T.    && all application files are candidates for compression
  811.       REPLACE filfound WITH .T.
  812.       REPLACE extrafile WITH .F.
  813.       REPLACE setupfile WITH .F.   && not a required file
  814.    ENDIF
  815.    SELECT (m.dbalias)
  816. ENDFOR
  817.  
  818. * Next, get all my child subdirectories. This program structure keeps us from
  819. * having too many big arrays hanging around on the stack as we recurse.
  820. SET DEFAULT TO (justpath(m.dirmask))
  821. m.numfiles = ADIR(dirlist,"","D")
  822. FOR m.i = 1 TO m.numfiles
  823.    IF !INLIST(dirlist[m.i,1], ".","..")
  824.       * recursive call!
  825.       DO filldir WITH addbs(justpath(m.dirmask))+ dirlist[m.i,1]+"\*.*", ;
  826.          m.dbfname, addbs(m.preface) + dirlist[m.i,1], m.dbalias
  827.    ENDIF
  828. ENDFOR
  829.  
  830. SET DEFAULT TO &in_defa
  831.  
  832. *!*****************************************************************************
  833. *!
  834. *!     Procedure: INSTESL
  835. *!
  836. *!*****************************************************************************
  837. PROCEDURE instesl
  838. PRIVATE m.numfiles, m.eslaction, m.cprscount, m.esldir, m.cprsdir, m.origsize
  839.  
  840. * Find the ESL file
  841. SELECT (m.g_dbalias)
  842.  
  843. GOTO TOP
  844. LOCATE FOR UPPER(ALLTRIM(justfname(fname))) == UPPER(ALLTRIM(justfname(m.g_esl)));
  845.    AND !DELETED() AND EMPTY(parent)
  846. IF FOUND()
  847.    m.g_esl = TRIM(fname)
  848.    
  849.    m.numfiles = ADIR(esldir,IIF(extrafile,TRIM(fname),addbs(m.g_sourcedir)+TRIM(fname)))
  850.    
  851.    m.g_eslextra = extrafile
  852.    
  853.    IF m.numfiles > 0
  854.       REPLACE filfound WITH .T.
  855.       * ESL file was in the DKCONTRL file and the original file exists.  Are we updating it?
  856.       m.origsize = filsize
  857.       REPLACE filsize WITH esldir[1,2], ;
  858.               fdate   WITH esldir[1,3], ;
  859.               ftime   WITH esldir[1,4], ;
  860.               fattrib WITH esldir[1,5]
  861.       m.cprscount = ADIR(cprsdir, addbs(m.g_cprsdir)+TRIM(cprsname))
  862.       IF m.cprscount > 0
  863.          IF (fdate > cprsdir[1,3]) OR (fdate = cprsdir[1,3] AND ftime > cprsdir[1,4]) ;
  864.                OR (filsize <> m.origsize)
  865.             * Delete earlier split pieces if we are updating the esl file
  866.             DO zapfrag WITH justfname(fname), justext(cprsname), .F.
  867.          ENDIF
  868.       ENDIF
  869.    ELSE
  870.       REPLACE filfound WITH .F.
  871.    ENDIF
  872. ELSE
  873.    m.eslaction = 1
  874.    DO noesl.spr WITH m.eslaction, c_eslfile
  875.    DO CASE
  876.    CASE m.eslaction = 1
  877.       * Find it.
  878.       m.g_esl = GETFILE("ESL","ESL-Datei","OK")
  879.       IF !EMPTY(m.g_esl)
  880.          m.numeslfiles = ADIR(esldir,m.g_esl)
  881.          IF m.numeslfiles > 0
  882.             APPEND BLANK
  883.             REPLACE fname WITH m.g_esl
  884.             REPLACE filsize WITH esldir[1,2]
  885.             REPLACE fdate WITH esldir[1,3]
  886.             REPLACE ftime WITH esldir[1,4]
  887.             REPLACE fattrib WITH esldir[1,5]
  888.  
  889.             REPLACE expndsize WITH filsize
  890.             REPLACE parent WITH ""
  891.             REPLACE splitfile WITH .F.   
  892.             REPLACE COMPRESS WITH .T.    && all application files are candidates for compression
  893.             REPLACE cprsflag WITH .T.
  894.             REPLACE filfound WITH .T.
  895.             REPLACE extrafile WITH .T.   && not in application tree
  896.             REPLACE setupfile WITH .F.   && not a required file
  897.             REPLACE uniqueID WITH SYS(3)
  898.             m.g_eslextra = .T.
  899.             
  900.             * Delete any occurrences of prior versions of ESL file from DKCONTRL.DBF file
  901.             SET EXACT ON
  902.             SCAN FOR INLIST(ALLTRIM(UPPER(justfname(fname))),UPPER(c_oldesl),UPPER(c_oldesl1))
  903.                IF FILE(addbs(m.g_cprsdir)+ALLTRIM(cprsname))
  904.                   DELETE FILE (addbs(m.g_cprsdir)+ALLTRIM(cprsname))
  905.                ENDIF
  906.                DELETE
  907.             ENDSCAN
  908.             PACK
  909.             SET EXACT OFF
  910.               
  911.          ENDIF
  912.       ELSE
  913.          RETURN TO dksetup
  914.       ENDIF
  915.    CASE m.eslaction = 2
  916.       * Continue
  917.       m.g_esl = SYS(3)  && to avoid any matches
  918.    CASE m.eslaction = 3
  919.       RETURN TO dksetup
  920.    ENDCASE
  921. ENDIF   
  922. GOTO TOP
  923.  
  924. *!*****************************************************************************
  925. *!
  926. *!     Procedure: GENUNIQ
  927. *!
  928. *!*****************************************************************************
  929. PROCEDURE genuniq
  930. PARAMETER m.dbfname
  931. PRIVATE m.startplace, m.thename
  932. * Generate unique names for the file names in "dbfname"
  933.  
  934. SET MESSAGE TO s_compressing
  935.  
  936. SELECT (m.g_dbalias)
  937. SET ORDER TO 0
  938. * Start by assuming that all files compress to their original names, except for
  939. * SCT, FRT, etc. files that have the last two letters of their extensions reversed
  940. * so as not to collide with their SCX and FRX counterparts.  Don't overwrite the
  941. * random names just yet so that we have a fighting chance of detecting whether their
  942. * source file needs to be compressed again.  Don't overwrite split filenames either
  943. * since their cprsnames are already set.
  944.  
  945. * Also account for the $ naming substitution that COMPRESS does.  It puts a $ in the
  946. * last available position of the extension to indicate that this is a compressed file.
  947. SCAN
  948.    DO CASE
  949.    CASE setupfile
  950.       REPLACE cprsname WITH justfname(fname)
  951.    CASE splitfile
  952.       * Leave the compress name alone.  This was a split file.
  953.    CASE !COMPRESS        && file isn't compressed, so use its regular name
  954.       REPLACE cprsname WITH justfname(fname)
  955.    CASE EMPTY(cprsname)
  956.       REPLACE cprsname WITH gencprsname(mapname(justfname(fname)))
  957.    OTHERWISE
  958.       REPLACE cprsname WITH gencprsname(cprsname)
  959.    ENDCASE
  960. ENDSCAN
  961.  
  962. * Ensure that there aren't any filename collisions among files in the application tree.
  963. SET ORDER TO TAG cprsname
  964. SCAN
  965.    m.thename = ALLTRIM(cprsname)
  966.    m.startplace = RECNO()
  967.    SKIP
  968.  
  969.    * Replace any further occurrences of this compressed file name with a random name
  970.    DO WHILE !EOF() AND cprsmatch(m.thename,ALLTRIM(cprsname))
  971.       REPLACE cprsname WITH gencprsname(SYS(3)+"."+c_randext)
  972.  
  973.       * Back to original record, since the last REPLACE moved the index position.  We
  974.       * are in cprsname order and substituting the SYS(3) name moved us someplace else in
  975.       * the index.
  976.       GOTO m.startplace
  977.  
  978.       SKIP
  979.    ENDDO
  980.  
  981.    GOTO m.startplace
  982. ENDSCAN
  983.  
  984. SET ORDER TO TAG fname
  985.  
  986. *!*****************************************************************************
  987. *!
  988. *!     Procedure: MAKEDISKS
  989. *!
  990. *!*****************************************************************************
  991. PROCEDURE makedisks
  992. PARAMETERS m.disktype, m.destination
  993. PRIVATE m.retval
  994.  
  995. * Figure out what needs to be compressed and does the compression.  Allocates
  996. * files to disks.  Copies files to the destination directory tree.
  997.  
  998. IF m.g_firstset
  999.    m.destination = trimpath(m.destination)
  1000.    m.g_cprsdir = trimpath(m.g_cprsdir)
  1001.    
  1002.    * Simple check to handle \FOO\BAR\ when neither FOO nor BAR exists now.  Only
  1003.    * go to two levels, however.
  1004.    IF !EMPTY(justpath(m.destination)) AND justpath(m.destination) <> "\"
  1005.       m.retval = mkdir(justpath(m.destination))
  1006.       IF m.retval <> 0 AND m.retval <> 6
  1007.          DO errormsg WITH error_array[en_baddir] + " " + justpath(m.destination), c_fatal 
  1008.          RETURN TO dksetup
  1009.       ENDIF
  1010.    ENDIF
  1011.    
  1012.    m.retval = mkdir(m.destination)         && silently create the destination/compress directories.
  1013.    IF m.retval <> 0 AND m.retval <> 6
  1014.       DO errormsg WITH error_array[en_baddir] + " " + m.destination, c_fatal 
  1015.       RETURN TO dksetup
  1016.    ENDIF
  1017.    
  1018.    m.retval = mkdir(m.g_cprsdir)
  1019.    IF m.retval <> 0 AND m.retval <> 6
  1020.       DO errormsg WITH error_array[en_baddir] + " " + m.g_cprsdir, c_fatal 
  1021.       RETURN TO dksetup
  1022.    ENDIF
  1023.  
  1024.    * Delete files from DKCONTRL.DBF that couldn't be found.  Don't delete records
  1025.    * for split files, however, unless their parent file was deleted from the application
  1026.    * tree.  Split files aren't in the app directory, but they are in the compressed directory.
  1027.    DO killctrl
  1028.  
  1029.    * Make and execute the batch file to compress files.
  1030.    DO makecprsbatch WITH m.disktype
  1031.  
  1032.    =updtherm(75)
  1033.  
  1034.    * Determine compressed file sizes and update the dkcontrl database.  This procedure
  1035.    * also detects which files were split (if any) and records them in the dkcontrl database.
  1036.    DO getcprssize
  1037. ENDIF
  1038.  
  1039. * Assign compressed files to specific disks in dkcontrl
  1040. DO shuffle WITH m.disktype, m.destination
  1041. DO makeinf WITH m.disktype, addbs(m.g_runtimedir)+c_setupinf
  1042.  
  1043. * Put the INF file onto disk 1 in DBCONTRL.DBF
  1044. =putondisk(c_setupinf, 1,.T.,.T.,.F.,"")
  1045.  
  1046. * Create the SETUP.LST file and put it on disk 1
  1047. DO makelst WITH addbs(m.g_runtimedir)+c_setuplst
  1048. =putondisk(c_setuplst, 1,.T.,.T.,.F.,"")
  1049.  
  1050. g_disks = 0
  1051. g_diskcount = 0
  1052.  
  1053. * Do it again to make sure that the INF file can fit on disk 1
  1054. DO shuffle WITH m.disktype, m.destination
  1055. DO makeinf WITH m.disktype, addbs(m.g_runtimedir)+c_setupinf
  1056.  
  1057. * Copy the files to the destination tree
  1058. DO copyfiles WITH m.disktype, m.destination
  1059.  
  1060. *!*****************************************************************************
  1061. *!
  1062. *!     Procedure: KILLCTRL
  1063. *!
  1064. *!*****************************************************************************
  1065. PROCEDURE killctrl
  1066. PRIVATE m.numfiles, m.thisrec, m.thisid, m.therec, m.therec1, m.killfname
  1067. SELECT (m.g_dbalias)
  1068. SET ORDER TO 0
  1069.  
  1070. * Get rid of any records in the control file that don't have corresponding
  1071. * files in the source tree.  This would occur if the user was updating a previous
  1072. * run of the SetupWizard and had deleted some of his files in the meantime.
  1073. DELETE ALL FOR !filfound AND !splitfile
  1074.  
  1075. * Delete all splitfiles that don't have a record in the compress directory already
  1076. SCAN FOR splitfile
  1077.    m.killfname = ""
  1078.    DO CASE
  1079.    CASE EMPTY(parent) AND !filfound  && this is a parent file that isn't in the app tree
  1080.       m.killfname = ALLTRIM(justfname(fname))
  1081.    CASE !FILE(addbs(m.g_cprsdir) + TRIM(cprsname))   && child 
  1082.       m.killfname = ALLTRIM(justfname(fname))
  1083.    ENDCASE
  1084.    
  1085.    * If any of the pieces are deleted from the compress directory, delete the rest of them
  1086.    * now and also clean out the DKCONTRL file of all references to this file.
  1087.    IF !EMPTY(m.killfname)
  1088.       WAIT WINDOW s_cleanup + " " + m.killfname NOWAIT
  1089.       m.therec = RECNO()
  1090.       GOTO TOP
  1091.       * Scan through all the children
  1092.       SCAN FOR !EMPTY(parent) ;
  1093.              AND UPPER(ALLTRIM(justfname(fname))) == UPPER(ALLTRIM(m.killfname))
  1094.          DELETE
  1095.          * Delete the compressed file, if it exists
  1096.          IF FILE(addbs(m.g_cprsdir) + TRIM(cprsname))
  1097.             DELETE FILE (addbs(m.g_cprsdir) + TRIM(cprsname))
  1098.          ENDIF
  1099.       ENDSCAN
  1100.       * Now get the parent
  1101.       SCAN FOR EMPTY(parent) ;
  1102.               AND UPPER(ALLTRIM(justfname(fname))) == UPPER(ALLTRIM(m.killfname))
  1103.          * Delete the first compressed file if it exists
  1104.          IF FILE(addbs(m.g_cprsdir) + TRIM(cprsname))
  1105.             DELETE FILE  (addbs(m.g_cprsdir) + TRIM(cprsname))
  1106.          ENDIF
  1107.          REPLACE splitfile WITH .F.
  1108.          
  1109.          IF !filfound   && not in application tree either
  1110.             DELETE
  1111.          ENDIF
  1112.          
  1113.       ENDSCAN      
  1114.       GOTO m.therec
  1115.    ENDIF
  1116. ENDSCAN
  1117. PACK
  1118. =inkey(1)
  1119. WAIT CLEAR
  1120. *!*****************************************************************************
  1121. *!
  1122. *!     Procedure: MAKECPRSBATCH
  1123. *!
  1124. *!*****************************************************************************
  1125. PROCEDURE makecprsbatch
  1126. PARAMETER m.dsktype
  1127. PRIVATE m.in_safe, m.i, m.numcprs, m.batname, m.got_one, m.in_area, m.in_defa, m.j, ;
  1128.    m.nextfile, m.pos
  1129.  
  1130. * Use MAKE logic to decide what needs to be compressed.  Create a batch file
  1131. * to call the compression program.
  1132.  
  1133. SET MESSAGE TO s_batch
  1134.  
  1135. * Assume everything needs to be compressed that can be compressed.
  1136. REPLACE ALL cprsflag WITH COMPRESS
  1137.  
  1138. * Now get a list of files that are already in the compress directory from an
  1139. * earlier run of the SetupWizard.
  1140. SET ORDER TO cprsname
  1141. m.numcprs = ADIR(rtdir,addbs(m.g_cprsdir)+"*.*")
  1142. IF m.numcprs > 0
  1143.    =ASORT(rtdir)   && to make sure that children always follow parents
  1144. ENDIF   
  1145. m.i = 1
  1146. DO WHILE m.i <= m.numcprs
  1147.    * If the file exists already, match it with the date of the file in the application
  1148.    * directory.  If it has the same or a later date, don't compress it again.  If it
  1149.    * is earlier, compress it again.
  1150.    *
  1151.    * If there is a file in the compress directory that doesn't correspond to one in the
  1152.    * application directory, it's probably a file that the user deleted.  Delete it from the
  1153.    * compress directory also.
  1154.  
  1155.    SEEK UPPER(ALLTRIM(rtdir[m.i,1]))
  1156.    DO CASE
  1157.    CASE FOUND()  && it's one we want to include and it's already there.
  1158.       DO CASE
  1159.       CASE (rtdir[m.i,3] > fdate OR (rtdir[m.i,3] = fdate AND rtdir[m.i,4] >= TRIM(ftime))) ;
  1160.              AND rtdir[m.i,2] > 0
  1161.          * The compressed file is current.  No need to compress it again.  Also, it isn't a
  1162.          * zero byte file, possibly left over from a previous failed COMPRESS.
  1163.          REPLACE cprsflag WITH .F.
  1164.          REPLACE cprssize WITH rtdir[m.i,2]
  1165.       CASE splitfile
  1166.          * The file exists in the compress directory and in DKCONTRL.  The compress directory
  1167.          * one is older.  Delete it and its relations now so that the user doesn't get a 
  1168.          * confusing question from COMRPESS.EXE about overwriting the file.
  1169.          DO zapfrag WITH justfname(fname), justext(cprsname), .F.
  1170.          REPLACE cprsflag WITH .T., compress WITH .T.
  1171.  
  1172.          * Refresh the directory list now that some files have been deleted
  1173.          * Find the next file to be scanned.  Skip deleted files, which are probably
  1174.          * children of the one we started with that have recently been zapped.
  1175.          m.pos = m.i + 1
  1176.          DO WHILE m.pos <= m.numcprs AND !FILE(addbs(m.g_cprsdir)+rtdir[m.pos,1])
  1177.             m.pos = m.pos + 1
  1178.          ENDDO
  1179.          IF m.pos > m.numcprs
  1180.             m.nextfile = ""
  1181.          ELSE
  1182.             m.nextfile = rtdir[m.pos,1]
  1183.          ENDIF
  1184.          
  1185.          * Get the revised directory
  1186.          m.numcprs = ADIR(rtdir,addbs(m.g_cprsdir)+"*.*")
  1187.          IF m.numcprs > 0
  1188.             =ASORT(rtdir)   && to make sure that children always follow parents
  1189.          ENDIF
  1190.                
  1191.          m.i = m.i - 1   && default position of next file to scan
  1192.          IF !EMPTY(m.nextfile)
  1193.             * Find the next file in the new, revised array
  1194.             FOR m.j = 1 TO m.numcprs
  1195.                IF rtdir[m.j,1] == m.nextfile
  1196.                   m.i = m.j - 1
  1197.                   EXIT
  1198.                ENDIF
  1199.             ENDFOR
  1200.          ENDIF
  1201.          
  1202.       OTHERWISE
  1203.          * The file exists in the compress directory and in DKCONTRL.  The compress directory
  1204.          * one is older.  Delete it now so that the user doesn't get a confusing question from
  1205.          * COMRPESS.EXE about overwriting the file.
  1206.          DELETE FILE (addbs(m.g_cprsdir)+TRIM(cprsname))
  1207.          REPLACE cprsflag WITH .T., compress WITH .T.
  1208.       ENDCASE
  1209.    CASE !m.g_newctrl
  1210.       * The file is there, but not in the DKCONTRL database (which we didn't just create).
  1211.       * Is it a split file?
  1212.       m.stem = juststem(rtdir[m.i,1])
  1213.       IF ISDIGIT(RIGHT(m.stem,1))
  1214.          * Can we find a plausable parent?
  1215.          SEEK CHRTRAN(m.stem,"0123456789","")
  1216.          IF FOUND() AND justext(cprsname) == justext(rtdir[m.i,1])
  1217.             * It appears to be a split file.  Leave it here.
  1218.             REPLACE cprsflag WITH .F.   && don't compress a split file again
  1219.          ELSE
  1220.             DELETE FILE (addbs(m.g_cprsdir) + rtdir[m.i,1])
  1221.          ENDIF
  1222.       ELSE
  1223.          DELETE FILE (addbs(m.g_cprsdir) + rtdir[m.i,1])
  1224.       ENDIF
  1225.    OTHERWISE
  1226.       DELETE FILE (addbs(m.g_cprsdir) + rtdir[m.i,1])
  1227.    ENDCASE
  1228.    
  1229.    m.i = m.i + 1 
  1230. ENDDO
  1231.  
  1232. m.in_defa = SET("DEFAULT") + CURDIR()
  1233. SET DEFAULT TO (m.g_runtimedir)
  1234.  
  1235. * Find the COMPRESS.EXE file.  
  1236. DO CASE
  1237. CASE FILE("COMPRESS.EXE")
  1238.    m.cprsexe = "COMPRESS"               && no need for path information.
  1239. CASE FILE(addbs(m.g_runtimedir)+"COMPRESS.EXE")
  1240.    m.cprsexe = addbs(m.g_runtimedir)+"COMPRESS.EXE"
  1241. CASE FILE(FULLPATH("COMPRESS.EXE",1))   && search DOS path
  1242.    m.cprsexe = "COMPRESS"               && no need for path information.
  1243. CASE FILE(SYS(2004)+"DKSETUP\COMPRESS.EXE")
  1244.    m.cprsexe = SYS(2004)+"DKSETUP\COMPRESS"
  1245. OTHERWISE
  1246.    m.cprsexe = GETFILE("EXE","COMPRESS.EXE")
  1247.    IF EMPTY(m.cprsexe)
  1248.       DO errormsg WITH error_array[en_nocompress], c_fatal
  1249.       RETURN TO dksetup
  1250.    ENDIF
  1251. ENDCASE
  1252.  
  1253. * Create a compression batch file in the current directory.  The file name must match the
  1254. * one that the PIF file is expecting.
  1255. m.batname = "SETUPWIZ.BAT"
  1256. m.in_safe = SET("SAFETY")
  1257. SET SAFETY OFF
  1258. COPY FILE setup.pif TO setupbat.pif
  1259.  
  1260. SET TEXTMERGE TO (m.batname)
  1261. SET TEXTMERGE ON
  1262. SET CONSOLE OFF
  1263. SET DECIMALS TO 0   && don't add extra 0's to file size, etc.
  1264. m.got_one = .F.     && nothing to compress yet
  1265. SCAN FOR cprsflag AND COMPRESS
  1266.    m.got_one = .T.
  1267.    * Make sure line will fit in 128-byte DOS command line
  1268.    IF LEN(m.cprsexe+addbs(m.g_sourcedir)+TRIM(fname)+addbs(m.g_cprsdir)+TRIM(cprsname))+17 > 128
  1269.       SET TEXTMERGE OFF
  1270.       SET TEXTMERGE TO
  1271.       SET CONSOLE ON
  1272.       IF FILE(m.batname)
  1273.          DELETE FILE (m.batname)
  1274.       ENDIF
  1275.       
  1276.       DELETE FILE setupbat.pif
  1277.       DO errormsg WITH error_array[en_toolong],c_fatal
  1278.       RETURN TO dksetup
  1279.    ENDIF
  1280.    IF extrafile
  1281.       * These are files such as the Graph runtime that aren't stored in the application
  1282.       * tree.  Fname contains a complete path specification.
  1283.       \\<<m.cprsexe>> -a<<m.g_algorithm>> -befl -z<<INT(m.g_splitsize/512)>>
  1284.       \\ <<TRIM(fname)>>
  1285.       \\ <<addbs(m.g_cprsdir)+TRIM(cprsname)>>
  1286.       \
  1287.    ELSE
  1288.       * Regular application file.  Fname contains a path relative to the g_sourcedir
  1289.       * directory.  The "710" here determines the size of the chunks that COMPRESS will
  1290.       * split a file into and is not directly related to the cluster size of any specific
  1291.       * disk we are creating.  It's the max number of 512-byte blocks that the output file
  1292.       * will contain before being split.  (710 x 512 = 363,520: two chunks will fit on a
  1293.       * 720K disk, 3 on a 1.2 meg and 4 on a 1.44meg floppy.)
  1294.       \\<<m.cprsexe>> -a<<m.g_algorithm>> -befl -z<<INT(m.g_splitsize/512)>>
  1295.       \\ <<addbs(m.g_sourcedir)+TRIM(fname)>>
  1296.       \\ <<addbs(m.g_cprsdir)+TRIM(cprsname)>>
  1297.       \
  1298.    ENDIF
  1299. ENDSCAN
  1300. SET DECIMALS TO &mdecimals
  1301. SET CONSOLE ON
  1302. SET TEXTMERGE OFF
  1303. SET TEXTMERGE TO
  1304.  
  1305. IF m.got_one
  1306.    m.choice = idyes
  1307.    * Remove the following comment to prompt before beginning compress operation
  1308.    * m.choice = msgbox("Bereit zur Dateikomprimierung. Jetzt beginnen?","Setup-Assistent",35)
  1309.    DO CASE
  1310.    CASE m.choice = idyes
  1311.       SET MESSAGE TO s_cprs
  1312.       RUN setupbat.pif
  1313.    CASE m.choice = idcancel
  1314.       RETURN TO dksetup
  1315.    ENDCASE
  1316. ENDIF
  1317.  
  1318. * See if any files were split.  If so, continue splitting them until they fit.
  1319. DO filsplit
  1320.  
  1321. DELETE FILE (m.batname)
  1322. DELETE FILE setupbat.pif
  1323. SET SAFETY &in_safe
  1324.  
  1325. SET DEFAULT TO &in_defa
  1326. RETURN
  1327.  
  1328.  
  1329. *!*****************************************************************************
  1330. *!
  1331. *!     Procedure: FILSPLIT
  1332. *!
  1333. *!*****************************************************************************
  1334. PROCEDURE filsplit
  1335. PRIVATE m.done, m.i, m.j, m.fnum, m.stem, m.ext, m.nextnum, m.parentrec, ;
  1336.    m.prevrec, m.prevname, m.nextname, m.batname, m.srch, m.prevnum, m.done
  1337.  
  1338. * See if any files were split.  If so, add the new split file to the DKCONTRL database,
  1339. * and compress it.  Keep going until no new split files appear, which means that we've
  1340. * compressed everything down as far as it will go.
  1341.  
  1342. m.batname = "SETUPWIZ.BAT"
  1343. m.in_safe = SET("SAFETY")
  1344. SET SAFETY OFF
  1345. COPY FILE setup.pif TO setupbat.pif
  1346.  
  1347. * Do while more split files turn up in the compressed directory
  1348. m.done = .F.
  1349. DO WHILE !m.done
  1350.    m.done = .T.   && assume no more files to split/compress
  1351.    m.numfiles = ADIR(rtdir,addbs(m.g_cprsdir)+"*.*")
  1352.    IF m.numfiles > 0
  1353.       =ASORT(rtdir,1)
  1354.    ENDIF
  1355.    FOR m.i = 1 TO m.numfiles
  1356.       SELECT (m.g_dbalias)
  1357.       SET ORDER TO TAG cprsname
  1358.       SEEK rtdir[m.i,1]
  1359.       IF !FOUND()
  1360.          * see if it looks like a newly-created split file
  1361.          m.stem = juststem(rtdir[m.i,1])
  1362.          IF ISDIGIT(RIGHT(m.stem,1))
  1363.             m.fnum = getfnum(m.stem)
  1364.             
  1365.             * Can we find a plausable parent?
  1366.             DO CASE
  1367.             CASE m.fnum = 1
  1368.                * Look for stemname ending in 0
  1369.                LOCATE FOR LEFT(juststem(cprsname),LEN(m.stem)-1) == LEFT(m.stem,LEN(m.stem)-1) ;
  1370.                   AND RIGHT(juststem(cprsname),1) = "0" ;
  1371.                   AND justext(cprsname) == justext(rtdir[m.i,1])
  1372.             CASE m.fnum = 2
  1373.                * Look for stemname ending in 1
  1374.                LOCATE FOR LEFT(juststem(cprsname),LEN(m.stem)-1) == LEFT(m.stem,LEN(m.stem)-1) ;
  1375.                   AND (RIGHT(juststem(cprsname),1) == "1") ;
  1376.                   AND justext(cprsname) == justext(rtdir[m.i,1])
  1377.                IF !FOUND()
  1378.                   DO CASE
  1379.                   CASE LEN(juststem(m.stem)) = 8
  1380.                      * Look for stemname ending in non-digit
  1381.                      LOCATE FOR LEN(juststem(cprsname)) >= 7 ;
  1382.                         AND LEFT(juststem(cprsname),7) == LEFT(m.stem,7) ;
  1383.                         AND !ISDIGIT(RIGHT(juststem(cprsname),1)) ;
  1384.                         AND justext(cprsname) == justext(rtdir[m.i,1])
  1385.                   OTHERWISE
  1386.                      * Look for stemname ending in blank
  1387.                      LOCATE FOR LEFT(juststem(cprsname),LEN(m.stem)-1);
  1388.                              == LEFT(m.stem,LEN(m.stem)-1) ;
  1389.                         AND justext(cprsname) == justext(rtdir[m.i,1])
  1390.                   ENDCASE
  1391.                ENDIF   
  1392.             OTHERWISE
  1393.                m.prevnum = ALLTRIM(STR(fnum - 1,4))
  1394.                m.srch    = LEFT(m.stem,LEN(m.stem)-LEN(m.prevnum))+m.prevnum
  1395.                LOCATE FOR LEFT(juststem(cprsname),LEN(m.srch)) == m.srch ; 
  1396.                   AND justext(cprsname) == justext(rtdir[m.i,1])
  1397.             ENDCASE
  1398.             
  1399.             IF FOUND()
  1400.                * Found the previous file
  1401.                m.done = .F.
  1402.  
  1403.                m.parentrec = IIF(EMPTY(parent),uniqueid,parent)
  1404.                m.prevrec   = RECNO()
  1405.                m.prevname  = fname
  1406.  
  1407.                * Make a new record for this new file
  1408.                APPEND BLANK
  1409.                m.childrec = RECNO()
  1410.                REPLACE fname WITH m.prevname, ;
  1411.                   filsize WITH rtdir[m.i,2],;
  1412.                   fdate WITH rtdir[m.i,3],;
  1413.                   ftime WITH rtdir[m.i,4],;
  1414.                   fattrib WITH rtdir[m.i,5]
  1415.                REPLACE cprsname WITH rtdir[m.i,1]
  1416.                REPLACE cprssize WITH rtdir[m.i,2]
  1417.                REPLACE expndsize WITH filsize  && subject to revision
  1418.                REPLACE COMPRESS WITH .T.    && all application files are candidates for compression
  1419.                REPLACE filfound WITH .T.
  1420.                REPLACE extrafile WITH IIF(justfname(fname)==justfname(m.g_esl);
  1421.                    AND m.g_eslextra,.T.,.F.)
  1422.                REPLACE setupfile WITH .F.   && not a required file
  1423.                REPLACE parent WITH m.parentrec
  1424.                REPLACE uniqueID WITH SYS(3)
  1425.                REPLACE splitfile WITH .T.
  1426.  
  1427.                * If we just created file 9 and it is exactly the same size as the maximum
  1428.                * file, then report that we couldn't split this file into enough pieces.
  1429.                IF getfnum(cprsname) = 9 AND cprssize = m.g_splitsize
  1430.                   DO errormsg WITH error_array[en_cprserr]+justfname(fname);
  1431.                      +c_crlf+error_array[en_toobig], e_fatal
  1432.                   RETURN TO dksetup
  1433.                ENDIF
  1434.  
  1435.                * Record the uncompressed size of the last chunk
  1436.                GOTO m.prevrec
  1437.                
  1438.                IF rtdir[m.i,2] >= filsize    && detect previous unsuccessful splits
  1439.                   DO zapfrag WITH justfname(fname), justext(cprsname), .T.
  1440.                   RETURN TO dksetup
  1441.                ENDIF
  1442.                
  1443.                REPLACE expndsize WITH filsize - rtdir[m.i,2]
  1444.                REPLACE splitfile WITH .T.
  1445.  
  1446.                GOTO m.childrec
  1447.  
  1448.                IF rtdir[m.i,2] > m.g_splitsize
  1449.                   * Compress the new one.
  1450.                   m.batname = "SETUPWIZ.BAT"
  1451.                   COPY FILE setup.pif TO setupbat.pif
  1452.                   SET TEXTMERGE TO (m.batname)
  1453.                   SET TEXTMERGE ON
  1454.                   SET CONSOLE OFF
  1455.                   
  1456.                   IF LEN(s_splitting+" "+TRIM(fname)+" "+s_again) <= 60
  1457.                      WAIT WINDOW s_splitting+" "+TRIM(fname)+" "+s_again NOWAIT
  1458.                   ELSE
  1459.                      WAIT WINDOW s_splitting+" "+TRIM(justfname(fname))+" "+s_again NOWAIT
  1460.                   ENDIF
  1461.  
  1462.                   * Rename the fragment to be the original file name, but in the
  1463.                   * compressed directory.
  1464.                   IF FILE(addbs(m.g_cprsdir)+justfname(fname))
  1465.                      DELETE FILE (addbs(m.g_cprsdir)+justfname(fname))
  1466.                   ENDIF
  1467.  
  1468.                   * Rename the excess file back to the original name
  1469.                   RENAME (addbs(m.g_cprsdir))+rtdir[m.i,1] TO (addbs(m.g_cprsdir)+justfname(fname))
  1470.  
  1471.                   m.stem = juststem(rtdir[m.i,1])
  1472.                   m.ext = justext(rtdir[m.i,1])
  1473.                   m.fnum = getfnum(m.stem)
  1474.                   m.nextnum = ALLTRIM(STR(m.fnum+1,4))
  1475.                   m.nextname = LEFT(m.stem,LEN(m.stem) - LEN(m.nextnum)) + m.nextnum + "." + m.ext
  1476.  
  1477.                   \\<<m.cprsexe>> -a<<m.g_algorithm>> -befl -z<<INT(m.g_splitsize / 512)>>
  1478.                   \\ <<addbs(m.g_cprsdir)+justfname(fname)>>
  1479.                   \\ <<addbs(m.g_cprsdir)+rtdir[m.i,1]>>
  1480.                   \
  1481.                   SET TEXTMERGE OFF
  1482.                   SET TEXTMERGE TO
  1483.                   SET CONSOLE ON
  1484.  
  1485.                   RUN setupbat.pif
  1486.  
  1487.                   DELETE FILE (m.batname)
  1488.                   DELETE FILE setupbat.pif
  1489.  
  1490.                   * Delete the previous excess file
  1491.                   IF FILE(addbs(m.g_cprsdir)+justfname(fname))
  1492.                      DELETE FILE (addbs(m.g_cprsdir)+justfname(fname))
  1493.                   ENDIF
  1494.                   
  1495.                   IF !FILE(addbs(m.g_cprsdir)+rtdir[m.i,1])
  1496.                      * Compression was interrupted.  Clean up as best we can.
  1497.                      DO errormsg WITH error_array[en_cprsdead], c_fatal
  1498.                      
  1499.                      * Get rid of the DKCONTRL entries and the compressed files
  1500.                      m.thename = justfname(fname)
  1501.                      SCAN FOR justfname(fname) == m.thename
  1502.                         IF FILE(addbs(m.g_cprsdir) + cprsname)
  1503.                            DELETE FILE (addbs(m.g_cprsdir) + cprsname)
  1504.                         ENDIF
  1505.                         DELETE
  1506.                      ENDSCAN
  1507.                      PACK
  1508.                      
  1509.                      RETURN TO dksetup
  1510.                   ENDIF
  1511.  
  1512.                   SET SAFETY &in_safe
  1513.                ENDIF
  1514.             ENDIF
  1515.          ENDIF
  1516.       ENDIF
  1517.    ENDFOR
  1518. ENDDO
  1519. WAIT CLEAR
  1520.  
  1521. * Detect previous unsuccessful runs.  This is a second level check.  Theoretically,
  1522. * all errors like this should have been caught in killctrl where we match the compress
  1523. * directory files up against the DKCONTRL entries.
  1524. SCAN FOR expndsize <= 0 AND splitfile
  1525.    DO zapfrag WITH justfname(fname), justext(cprsname), .T.
  1526.    RETURN TO dksetup
  1527. ENDSCAN
  1528.  
  1529. *!*****************************************************************************
  1530. *!
  1531. *!     Function: GETFNUM
  1532. *!
  1533. *!*****************************************************************************
  1534. FUNCTION getfnum
  1535. PARAMETER m.filname
  1536. PRIVATE ALL
  1537. RETURN VAL(RIGHT(juststem(m.filname),1))
  1538.  
  1539. *!*****************************************************************************
  1540. *!
  1541. *!     Procedure: GETCPRSSIZE
  1542. *!
  1543. *!*****************************************************************************
  1544. PROCEDURE getcprssize
  1545. * This routine figures out the compressed file sizes of all the files in DKCONTRL.DBF.
  1546.  
  1547. PRIVATE m.i, m.numcprs, m.thestem, m.parentname, m.parentrec, m.thisrec, m.in_msg, ;
  1548.    m.parentstem
  1549.  
  1550. SET MESSAGE TO s_cprssize
  1551.  
  1552. SELECT (m.g_dbalias)
  1553. SET ORDER TO TAG cprsname
  1554. * Get the size of compressed files in the g_cprsdir directory
  1555. m.numcprs = ADIR(rtdir,addbs(m.g_cprsdir)+"*.*")
  1556. FOR m.i = 1 TO m.numcprs
  1557.    SEEK UPPER(ALLTRIM(rtdir[m.i,1]))
  1558.    IF FOUND()  && it's one we want to include and it's already there.
  1559.       REPLACE cprssize WITH rtdir[m.i,2]
  1560.    ENDIF
  1561. ENDFOR
  1562.  
  1563. * Show that files that aren't compressed have the same "compressed" size as the
  1564. * uncompressed size.
  1565. SET ORDER TO 0
  1566. REPLACE ALL cprssize WITH filsize FOR !COMPRESS AND !splitfile
  1567.  
  1568. *!*****************************************************************************
  1569. *!
  1570. *!     Procedure: SHUFFLE
  1571. *!
  1572. *!*****************************************************************************
  1573. PROCEDURE shuffle
  1574. PARAMETER m.disktype, m.rootdir
  1575.  
  1576. * Assign the files to specific disks.  This routine uses the following
  1577. * algorithm to decide which disks to put the files on.  It starts by
  1578. * allocating the setup files to the first disk.  SETUP.EXE requires most of 
  1579. * its files to be on disk1.  Next, it allocates the largest file to the 
  1580. * first disk.  Then it takes the second largest file and puts it on the first
  1581. * disk it will fit on, and so forth. There are other restrictions also.  
  1582. * The number of files that can fit in the root directory is limited '
  1583. * (224 for 1.44 meg disks, for example).  Also, if  a file has been split,
  1584. * all the pieces must appear successively.  SPLIT2 can't be on a disk before 
  1585. * split1.  They don't have to be consecutive (i.e., SPLIT1 could be
  1586. * on disk2 and SPLIT2 could be on disk4).This alorithm will sometimes not 
  1587. * result in the tightest packing, but it will usually produce good results.
  1588.  
  1589. PRIVATE m.cluster, m.totsize, m.dirname, m.maxfilenum
  1590.  
  1591. SELECT DISKS
  1592. SEEK m.disktype
  1593. IF FOUND()
  1594.    m.cluster    = DISKS->clustsize  && cluster size for this type of disk
  1595.    m.totsize    = DISKS->disksize   && max bytes on this disk
  1596.    m.dirname    = DISKS->dname      && name of disk type (e.g., 1.44 megabyte disks)
  1597.    m.maxfilenum = DISKS->maxfiles   && max files in root directory of this type disk
  1598.    SELECT (m.g_dbalias)
  1599.    REPLACE ALL (DISKS->diskfld) WITH 0
  1600. ELSE
  1601.    WAIT WINDOW "Ungⁿltiger Diskettentyp angegeben." NOWAIT   && shouldn't be possible
  1602.    RETURN TO dksetup
  1603. ENDIF
  1604.  
  1605. SELECT (m.g_dbalias)
  1606.  
  1607. * Put the setup files on first
  1608. SCAN FOR setupfile
  1609.    DO diskassgn WITH m.disktype, m.cluster, m.totsize, m.maxfilenum, m.dirname, splitfile
  1610. ENDSCAN
  1611.  
  1612. * Now allocate the remaining ordinary files to disks, making new disks as necessary
  1613. SELECT (m.g_dbalias)
  1614. SET ORDER TO TAG cprssize    && descending order by cprssize
  1615. SCAN FOR !setupfile AND !splitfile
  1616.    DO diskassgn WITH m.disktype, m.cluster, m.totsize, m.maxfilenum, m.dirname, splitfile
  1617. ENDSCAN
  1618.  
  1619. * Finally, allocate the split files to disk in the split order (i.e., split2 comes before
  1620. * split3)
  1621. SCAN FOR splitfile
  1622.    DO diskassgn WITH m.disktype, m.cluster, m.totsize, m.maxfilenum, m.dirname, splitfile
  1623. ENDSCAN
  1624.  
  1625. *!*****************************************************************************
  1626. *!
  1627. *!     Procedure: DISKASSGN
  1628. *!
  1629. *!*****************************************************************************
  1630. PROCEDURE diskassgn
  1631. PARAMETERS m.disktype, m.cluster, m.totsize, m.maxfilenum, m.dirname, m.split
  1632. * Take the current record in the dkcontrl file and assign it to a disk
  1633.  
  1634. PRIVATE m.numdisks, m.asize, m.dnum
  1635.  
  1636. SET MESSAGE TO s_assign + " " + s_to1 + " " +DISKS->dname
  1637.  
  1638. m.asize = allocsize(cprssize, m.cluster)
  1639. IF !m.split
  1640.    m.dnum = 1
  1641.    * Check for available space on each disk, but don't put more files onto the disk than
  1642.    * can fit in the root directory for this disk type (e.g., 224 for 1.44/1.2 meg, 112 for 720K)
  1643.    DO WHILE m.dnum <= m.g_diskcount ;
  1644.          AND ( (m.totsize - g_disks[m.dnum,3] < m.asize) ;
  1645.             OR (g_disks[m.dnum,1] >= m.maxfilenum) )
  1646.       m.dnum = m.dnum + 1
  1647.    ENDDO
  1648.    * If there isn't any room on any of the existing disks, make a new disk
  1649.    IF m.dnum > m.g_diskcount
  1650.       m.g_diskcount = m.g_diskcount + 1
  1651.       DIMENSION g_disks[m.g_diskcount,c_diskcols]
  1652.       g_disks[m.g_diskcount,1] = 1
  1653.       g_disks[m.g_diskcount,2] = cprssize
  1654.       g_disks[m.g_diskcount,3] = m.asize
  1655.    ELSE
  1656.       g_disks[m.dnum,1] = g_disks[m.dnum,1] + 1
  1657.       g_disks[m.dnum,2] = g_disks[m.dnum,2] + cprssize
  1658.       g_disks[m.dnum,3] = g_disks[m.dnum,3] + m.asize
  1659.    ENDIF
  1660. ELSE
  1661.    * Split files have to appear in successive order (SPLIT2 can't show up before SPLIT1).
  1662.    * If there is room, put on the last disk.  Otherwise make a new one.
  1663.    IF g_disks[m.g_diskcount,1] < m.maxfilenum ;
  1664.          AND m.totsize - g_disks[m.g_diskcount,3] >= m.asize
  1665.       * There is room for this file on the last disk
  1666.       g_disks[m.g_diskcount,1] = g_disks[m.g_diskcount,1] + 1
  1667.       g_disks[m.g_diskcount,2] = g_disks[m.g_diskcount,2] + cprssize
  1668.       g_disks[m.g_diskcount,3] = g_disks[m.g_diskcount,3] + m.asize
  1669.    ELSE
  1670.       m.g_diskcount = m.g_diskcount + 1
  1671.       DIMENSION g_disks[m.g_diskcount,c_diskcols]
  1672.       g_disks[m.g_diskcount,1] = 1
  1673.       g_disks[m.g_diskcount,2] = cprssize
  1674.       g_disks[m.g_diskcount,3] = m.asize
  1675.    ENDIF
  1676.    m.dnum = m.g_diskcount
  1677. ENDIF
  1678.  
  1679. SELECT DISKS
  1680. SEEK m.disktype
  1681.  
  1682. IF FOUND()
  1683.    SELECT (m.g_dbalias)
  1684.    REPLACE (DISKS->diskfld) WITH m.dnum
  1685. ENDIF
  1686. SELECT (m.g_dbalias)
  1687.  
  1688. *!*****************************************************************************
  1689. *!
  1690. *!     Procedure: REQFILES
  1691. *!
  1692. *!*****************************************************************************
  1693. PROCEDURE reqfiles
  1694. * Put the files in the REQUIRED.DBF list onto the disks, starting with disk1.
  1695. * These files may be compressed, but if so, then the ones in the g_runtimedir
  1696. * have already been compressed, so I don't have to worry about the ultimate file
  1697. * size on the install disks differing from their size in the g_runtimedir
  1698. * directory.
  1699.  
  1700. PRIVATE m.in_dir, m.thefile, m.gotit, m.i
  1701.  
  1702. SET MESSAGE TO s_required
  1703.  
  1704. * Find the files in the runtime directory.  It's possible that there could
  1705. * be files here that we don't want to install, so we can't just copy the filename
  1706. * information into the dkcontrl file without further checking against the REQUIRED.DBF
  1707. * file, stored inside the app.
  1708. m.numfiles = ADIR(rtdir,addbs(m.g_runtimedir)+"*.*")
  1709. IF m.numfiles = 0
  1710.    DO errormsg WITH error_array[en_nortfiles], c_fatal
  1711.    RETURN TO dksetup
  1712. ENDIF
  1713.  
  1714. SELECT (m.g_dbalias)
  1715. SET ORDER TO TAG fname
  1716.  
  1717. SELECT required
  1718. SCAN
  1719.    m.gotit = .F.
  1720.    * Find the directory information for this file
  1721.    FOR m.i = 1 TO m.numfiles
  1722.       IF ALLTRIM(UPPER(rtdir[m.i,1])) == ALLTRIM(UPPER(required->reqname))
  1723.          * At this point, we have a match between a file we need and a file we found
  1724.          * in the g_runtimedir directory.  Add a record for this file to the dkcontrl
  1725.          * file.
  1726.          SELECT (m.g_dbalias)
  1727.  
  1728.          SEEK UPPER(rtdir[m.i,1])   && seek the file name
  1729.          DO CASE
  1730.          CASE !FOUND()
  1731.             APPEND BLANK
  1732.          CASE DELETED()
  1733.             RECALL
  1734.          ENDCASE
  1735.          REPLACE fname WITH rtdir[m.i,1], ;
  1736.             filsize WITH rtdir[m.i,2], ;
  1737.             fdate WITH rtdir[m.i,3], ;
  1738.             ftime WITH rtdir[m.i,4], ;
  1739.             fattrib WITH rtdir[m.i,5]
  1740.          REPLACE expndsize WITH filsize
  1741.          REPLACE cprsname  WITH fname  && not compressed, so no different name
  1742.          REPLACE COMPRESS  WITH .F.    && required files are never compressed
  1743.          REPLACE filfound  WITH .T.    && we did find it
  1744.          REPLACE extrafile WITH .T.    && not relative to application tree
  1745.          REPLACE setupfile WITH .T.    && this is a required file
  1746.          REPLACE parent    WITH ""     && assume no split
  1747.          REPLACE splitfile WITH .F.
  1748.          REPLACE uniqueid  WITH SYS(3)
  1749.          m.gotit = .T.
  1750.          EXIT   && from the FOR loop
  1751.       ENDIF
  1752.    ENDFOR
  1753.  
  1754.    IF !m.gotit
  1755.       * This shouldn't be possible since any missing files should have been detected
  1756.       * when the runtime directory was specified.
  1757.       DO errormsg WITH TRIM(required->reqname) + " " + error_array[en_notfound], c_fatal
  1758.    ENDIF
  1759.  
  1760.    SELECT required
  1761. ENDSCAN
  1762.  
  1763. SELECT (m.g_dbalias)
  1764. RETURN
  1765.  
  1766. *!*****************************************************************************
  1767. *!
  1768. *!     Procedure: FPINST
  1769. *!
  1770. *!*****************************************************************************
  1771. PROCEDURE fpinst
  1772. PRIVATE m.targ, m.in_area
  1773. * Install FOXPRINT font if all associated files are in the runtime directory
  1774.  
  1775. m.in_area = SELECT()
  1776.  
  1777. SELECT 0
  1778. USE foxprint
  1779. SCAN
  1780.    DO CASE
  1781.    CASE foxprint->reldir = 0   && full path specified
  1782.       m.targ = foxprint->fname
  1783.    CASE foxprint->reldir = 1   && relative to FoxPro dir
  1784.       m.targ = SYS(2004) + foxprint->fname
  1785.    CASE foxprint->reldir = 2   && relative to runtime dir
  1786.       m.targ = addbs(m.g_runtimedir) + foxprint->fname
  1787.    ENDCASE
  1788.    IF !FILE(m.targ)
  1789.       m.g_foxprint = .F.
  1790.    ENDIF
  1791. ENDSCAN
  1792. USE
  1793. SELECT (m.in_area)
  1794. IF m.g_foxprint
  1795.    DO instfromdbf WITH "foxprint.dbf"
  1796. ENDIF
  1797.  
  1798. *!*****************************************************************************
  1799. *!
  1800. *!     Procedure: OPTINST
  1801. *!
  1802. *!*****************************************************************************
  1803. PROCEDURE optinst
  1804. * Install any optional components the user choses.  Each optional component needs
  1805. * to have its own DBF in the SETUP.APP file to list which files are associated with
  1806. * it.
  1807. IF m.g_instgraph
  1808.    DO instfromdbf WITH "msgraph.dbf"
  1809. ENDIF
  1810.  
  1811. *!*****************************************************************************
  1812. *!
  1813. *!     Procedure: INSTFROMDBF
  1814. *!
  1815. *!*****************************************************************************
  1816. PROCEDURE instfromdbf
  1817. PARAMETER m.optfname
  1818. * Put the files in the optfname list onto the disks.
  1819. PRIVATE m.in_area, m.thefile, m.gotit, m.i, m.grphpath, m.numfiles, m.srchname, m.in_dir
  1820.  
  1821. m.in_area = SELECT()
  1822. SELECT 0
  1823. USE (m.optfname) ALIAS optfname EXCLUSIVE AGAIN
  1824. SCAN
  1825.    DO CASE
  1826.    CASE reldir = 0   && file path is full path
  1827.       m.srchname = UPPER(TRIM(optfname->fname))
  1828.       IF !FILE(m.srchname)
  1829.          DO CASE
  1830.          CASE FILE(FULLPATH(m.srchname,1))   && search the DOS PATH for this file
  1831.             m.srchname = FULLPATH(m.srchname,1)
  1832.          CASE FILE(FULLPATH(m.srchname))     && search the FoxPro PATH for this file
  1833.             m.srchname = FULLPATH(m.srchname)
  1834.          OTHERWISE
  1835.             * Just leave it alone and display a GETFILE dialog below
  1836.          ENDCASE
  1837.       ENDIF
  1838.    CASE reldir = 1   && relative to FoxPro directory
  1839.       m.srchname = UPPER(SYS(2004) + TRIM(optfname->fname))
  1840.    CASE reldir = 2   && Relative to runtime files directory
  1841.       m.srchname = addbs(m.g_runtimedir) + TRIM(optfname->fname)
  1842.    ENDCASE
  1843.  
  1844.    m.optpath = justpath(m.srchname)
  1845.  
  1846.    * Find the files.
  1847.    m.numfiles = ADIR(rtdir,m.srchname)
  1848.  
  1849.    IF m.numfiles = 0     && one of the files couldn't be found.  Give option to locate it.
  1850.       DIMENSION rtdir[1,1]
  1851.       IF errormsg(justfname(TRIM(optfname->fname))+" "+error_array[en_notfound]+c_crlf;
  1852.             +error_array[en_getfile], c_entry2) == idyes
  1853.          rtdir[1,1] = GETFILE("","Wo ist "+TRIM(optfname->fname)+"?")
  1854.          IF EMPTY(rtdir[1,1])  && user pressed cancel in GETFILE()
  1855.             WAIT WINDOW s_canceling NOWAIT
  1856.             RETURN TO dksetup
  1857.          ELSE
  1858.             * Get the rest of the file specifications (e.g., size)
  1859.             m.optpath = justpath(rtdir[1,1])
  1860.             m.numfiles = ADIR(rtdir,rtdir[1,1])
  1861.          ENDIF
  1862.       ELSE
  1863.          WAIT WINDOW s_canceling NOWAIT
  1864.          RETURN TO dksetup
  1865.       ENDIF
  1866.    ENDIF
  1867.  
  1868.    SELECT (m.g_dbalias)
  1869.    SET ORDER TO TAG fname
  1870.    SEEK UPPER(rtdir[1,1])
  1871.    DO CASE
  1872.    CASE !FOUND()
  1873.       APPEND BLANK
  1874.    CASE DELETED()
  1875.       RECALL
  1876.    ENDCASE
  1877.    REPLACE fname WITH addbs(m.optpath)+rtdir[1,1], ;
  1878.       filsize WITH rtdir[1,2], ;
  1879.       fdate WITH rtdir[1,3], ;
  1880.       ftime WITH rtdir[1,4], ;
  1881.       fattrib WITH rtdir[1,5], ;
  1882.       cprsname WITH justfname(rtdir[1,1])
  1883.    REPLACE expndsize WITH optfname->expndsize
  1884.    REPLACE cprssize  WITH optfname->cprssize
  1885.    
  1886.    REPLACE filfound WITH .T.       && here it is
  1887.    REPLACE extrafile WITH .T.      && not relative to application tree
  1888.    REPLACE setupfile WITH .F.      && not a file required by setup
  1889.    REPLACE COMPRESS WITH optfname->COMPRESS   && may or may not be compressable
  1890.    REPLACE parent WITH ""          && assume no split
  1891.    REPLACE splitfile WITH .F.
  1892.    REPLACE uniqueid WITH SYS(3)
  1893. ENDSCAN
  1894.  
  1895. SELECT optfname
  1896. USE
  1897.  
  1898. SELECT (m.in_area)
  1899. RETURN
  1900.  
  1901. *!*****************************************************************************
  1902. *!
  1903. *!     Procedure: EXECUTINST
  1904. *!
  1905. *!*****************************************************************************
  1906. PROCEDURE executinst
  1907. PRIVATE m.numfiles, m.cpname, m.therec, m.spath
  1908. * Install file to be executed upon completion of setup.
  1909. IF !EMPTY(m.g_executable) AND FILE(wordnum(m.g_executable,1))
  1910.    * Look up file size, etc.
  1911.    m.numfiles = ADIR(rtdir,wordnum(m.g_executable,1))
  1912.    IF m.numfiles > 0    && it should be
  1913.       SELECT (m.g_dbalias)
  1914.       
  1915.       * See if the file is in the application tree already
  1916.       m.spath = addbs(m.g_sourcedir)
  1917.       LOCATE FOR m.spath == addbs(LEFT(justpath(wordnum(m.g_executable,1)),LEN(m.spath))) ;
  1918.          AND justfname(fname) == justfname(wordnum(m.g_executable,1))
  1919.          
  1920.       IF !FOUND()
  1921.          APPEND BLANK
  1922.          REPLACE fname WITH wordnum(m.g_executable,1) ;
  1923.             filsize WITH rtdir[1,2], ;
  1924.             fdate WITH rtdir[1,3], ;
  1925.             ftime WITH rtdir[1,4], ;
  1926.             fattrib WITH rtdir[1,5]
  1927.          REPLACE expndsize WITH filsize
  1928.          REPLACE filfound WITH .T.       && here it is
  1929.          REPLACE extrafile WITH .T.      && not relative to application tree
  1930.          REPLACE setupfile WITH .F.      && not a file required by setup
  1931.          REPLACE COMPRESS WITH .T.       && is compressable
  1932.          REPLACE parent WITH ""          && not split yet.
  1933.          REPLACE splitfile WITH .F.
  1934.          REPLACE uniqueID WITH SYS(3)
  1935.             
  1936.          * Ensure there isn't a compressed name collision
  1937.          m.therec = RECNO()
  1938.          m.cpname = gencprsname(rtdir[1,1])
  1939.          IF !israndom(cprsname)
  1940.             GOTO TOP
  1941.             LOCATE FOR UPPER(TRIM(cprsname)) == UPPER(m.cpname) ;
  1942.                 AND UPPER(ALLTRIM(fname)) <> UPPER(ALLTRIM(wordnum(m.g_executable,1)))
  1943.             IF FOUND()   && collision
  1944.                GOTO m.therec
  1945.                REPLACE cprsname WITH gencprsname(SYS(3)+"."+c_randext)
  1946.             ELSE
  1947.                GOTO m.therec
  1948.                REPLACE cprsname WITH m.cpname
  1949.             ENDIF
  1950.          ENDIF
  1951.       ENDIF
  1952.    ENDIF
  1953. ENDIF
  1954.  
  1955. *!*****************************************************************************
  1956. *!
  1957. *!     Procedure: COPYFILES
  1958. *!
  1959. *!*****************************************************************************
  1960. PROCEDURE copyfiles
  1961. * Copy files from the compress directory to the correct branch on the destination
  1962. * tree for the disk type selected.
  1963.  
  1964. PARAMETER m.disktype, m.destination
  1965. PRIVATE m.child, m.leafnum, m.leaf, m.outdir, m.batname, m.i, m.fldname
  1966.  
  1967. SELECT DISKS
  1968. SEEK m.disktype
  1969. IF FOUND()
  1970.    m.child = DISKS->diskdir
  1971.    m.fldname = TRIM(DISKS->diskfld)
  1972.    SELECT (m.g_dbalias)
  1973.    CALCULATE MAX(&fldname) TO m.lastdisk
  1974. ELSE
  1975.    WAIT WINDOW "Ungⁿltiger Diskettentyp angegeben." NOWAIT   && shouldn't happen
  1976.    RETURN TO dksetup
  1977. ENDIF
  1978.  
  1979. SELECT (m.g_dbalias)
  1980. SET ORDER TO TAG fname
  1981.  
  1982. SET MESSAGE TO s_mkdir
  1983.  
  1984. * Remove any existing DISK144/DISK12/DISK720 directory
  1985. DO zapdir WITH addbs(m.destination)+m.child, m.error_array
  1986.  
  1987. * Recreate the DISK144/DISK12/DISK720 directory
  1988. =mkdir(addbs(m.destination)+m.child)
  1989.  
  1990. * Make the disk1...diskn directories
  1991. FOR m.i = 1 TO INT(m.lastdisk)
  1992.    =mkdir(addbs(m.destination)+addbs(m.child)+"DISK"+ALLTRIM(STR(m.i,4)))
  1993. ENDFOR
  1994.  
  1995. SET ORDER TO TAG &fldname
  1996. SCAN FOR !EMPTY(cprsname)
  1997.    m.leafnum = &fldname
  1998.    m.leaf    = ALLTRIM(STR(m.leafnum,4))
  1999.  
  2000.    * Construct the name of the eventual output directory
  2001.    SET MESSAGE TO s_copying + " " + PROPER(TRIM(cprsname)) + " " + s_to2 + " " + DISKS->dname
  2002.    m.outdir = addbs(m.destination)+addbs(m.child)+ "DISK" + m.leaf
  2003.    DO CASE
  2004.    CASE setupfile
  2005.       * These come from the runtime directory--usually \FOXPROW\DKSETUP
  2006.       COPY FILE (addbs(m.g_runtimedir) + TRIM(cprsname)) TO (addbs(m.outdir)+TRIM(cprsname))
  2007.    CASE extrafile
  2008.       IF !COMPRESS
  2009.          COPY FILE (TRIM(fname)) TO (addbs(m.outdir)+TRIM(cprsname))
  2010.       ELSE
  2011.          COPY FILE (addbs(m.g_cprsdir) + TRIM(cprsname)) TO (addbs(m.outdir)+TRIM(cprsname))
  2012.       ENDIF
  2013.    OTHERWISE
  2014.       COPY FILE (addbs(m.g_cprsdir) + TRIM(cprsname)) TO (addbs(m.outdir)+TRIM(cprsname))
  2015.    ENDCASE
  2016. ENDSCAN
  2017.  
  2018. *!*****************************************************************************
  2019. *!
  2020. *!     Procedure: MAKEINF
  2021. *!
  2022. *!*****************************************************************************
  2023. PROCEDURE makeinf
  2024. PARAMETER m.disktype, m.setupname
  2025. * Create the SETUP.INF file for each disk type
  2026. PRIVATE m.fldname, m.i, m.numdisks, m.in_safe
  2027.  
  2028. SET MESSAGE TO s_makeinf
  2029.  
  2030. SELECT DISKS
  2031. SEEK m.disktype
  2032. m.fldname = DISKS->diskfld
  2033.  
  2034. SELECT (m.g_dbalias)
  2035. CALCULATE MAX(&fldname) TO m.numdisks
  2036. SET ORDER TO TAG fname
  2037.  
  2038. m.in_safe = SET("SAFETY")
  2039. SET SAFETY OFF
  2040.  
  2041. SET CONSOLE OFF
  2042. SET TEXTMERGE TO (m.setupname)
  2043. SET TEXTMERGE ON
  2044. \\[Source Media Descriptions]
  2045. \
  2046. FOR m.i = 1 TO m.numdisks
  2047.    \\    "<<ALLTRIM(STR(m.i,4))>>",
  2048.    \\"Disk <<ALLTRIM(STR(m.i,4))>>",
  2049.    GOTO TOP
  2050.    LOCATE FOR &fldname = m.i
  2051.    IF FOUND()
  2052.       \\"<<TRIM(cprsname)>>",
  2053.    ENDIF
  2054.    \\"..\DISK<<ALLTRIM(STR(m.i,4))>>"
  2055.    \
  2056. ENDFOR
  2057.  
  2058. * Emit the [Default File Settings] section
  2059. \[Default File Settings]
  2060. \"STF_BACKUP"     = ""
  2061. \"STF_COPY"       = "YES"
  2062. \"STF_DECOMPRESS" = "YES"
  2063. \"STF_OVERWRITE"  = "ALWAYS"
  2064. \"STF_READONLY"   = ""
  2065. \"STF_ROOT"       = ""
  2066. \"STF_SETTIME"    = ""
  2067. \"STF_TIME"       = "0"
  2068. \"STF_VITAL"      = "YES"
  2069.  
  2070. * Emit the setup specific information
  2071. \
  2072. \[FP SETUP]
  2073. \    TITLE=<<m.g_title>>
  2074. IF EMPTY(justdrive(m.g_targetdir))
  2075.    \    PATH=C:\<<IIF(LEFT(m.g_targetdir,1)=='\',SUBSTR(m.g_targetdir,2),m.g_targetdir)>>
  2076. ELSE
  2077.    \    PATH=<<m.g_targetdir>>
  2078. ENDIF   
  2079. \    GROUP=<<IIF(EMPTY(m.g_pmgroup),juststem(m.g_sourcedir),m.g_pmgroup)>>
  2080. DO CASE
  2081. CASE m.g_modoptions = c_modall
  2082.    \    FORCELOC="NO"
  2083. CASE m.g_modoptions = c_modgroup
  2084.    \    FORCELOC="GROUP ONLY"
  2085. CASE m.g_modoptions = c_modnone
  2086.    \    FORCELOC="YES"
  2087. ENDCASE   
  2088. \    COPYRIGHT=<<m.g_copyright>>
  2089. \    ESL=<<justpath(m.g_esl)>>
  2090. \    PROGRAM=<<SYS(2014,m.g_appname,addbs(m.g_sourcedir))>>
  2091.  
  2092. IF m.g_nologo = 1
  2093.    \\ -T
  2094. ENDIF
  2095. IF m.g_usealtcfg = 1 AND !EMPTY(m.g_altcfgfile)
  2096.    \\ -C<<m.g_altcfgfile>>
  2097. ENDIF
  2098. IF !EMPTY(m.g_parameters)
  2099.    \\ <<m.g_parameters>>
  2100. ENDIF
  2101.  
  2102. m.spath = addbs(m.g_sourcedir)
  2103. DO CASE
  2104. CASE EMPTY(m.g_executable)
  2105.    \    RUN=
  2106. CASE words(m.g_executable) = 1
  2107.    \    RUN=<<SYS(2014,m.g_executable,m.spath)>>
  2108. OTHERWISE
  2109.    \    RUN=<<SYS(2014,wordnum(m.g_executable,1),m.spath)>>
  2110.    FOR m.i = 2 TO words(m.g_executable)
  2111.       \\ <<wordnum(m.g_executable,m.i)>>
  2112.    ENDFOR   
  2113. ENDCASE
  2114. \    DESCRIPT=<<m.g_pmdescript>>
  2115.  
  2116. * Emit the section for the setup files
  2117. \
  2118. \[Sysfiles]
  2119. \
  2120. SELECT required
  2121. SCAN FOR CLASS = 1   && files that setup needs to install in the Windows system directory.
  2122.    * Find the file in the DKCONTRL database
  2123.    SELECT (m.g_dbalias)
  2124.    SET ORDER TO TAG fname
  2125.    SEEK TRIM(required->reqname)
  2126.    IF FOUND()
  2127.       m.disknum = &fldname
  2128.       \\    <<m.disknum>>,
  2129.       \\ <<TRIM(required->expndname)>>,
  2130.       \\,,,
  2131.       \\ <<TRIM(required->fdate)>>,,
  2132.       \\ 1033,
  2133.       \\ OLDER,
  2134.       \\ !READONLY,,
  2135.       \\ <<TRIM(required->expndname)>>,,,,
  2136.       \\ <<required->expndsize>>,
  2137.       \\ SYSTEM,
  2138.       \\,,
  2139.       \\ <<TRIM(required->version)>>,
  2140.       \\ VITAL
  2141.       \
  2142.    ELSE
  2143.       DO errormsg WITH error_array[en_missreq]+TRIM(fname), c_fatal   && shouldn't ever happen
  2144.    ENDIF
  2145.    SELECT required
  2146. ENDSCAN
  2147. SELECT (m.g_dbalias)
  2148.  
  2149. * Emit the entries for FOXPRINT if it is being installed
  2150. IF m.g_foxprint
  2151.    SELECT 0
  2152.    USE foxprint
  2153.    SCAN
  2154.       m.filname = justfname(UPPER(TRIM(foxprint->fname)))
  2155.       m.filname = IIF(foxprint->COMPRESS,gencprsname(m.filname),m.filname)
  2156.       SELECT (m.g_dbalias)
  2157.       SET ORDER TO TAG cprsname
  2158.       SEEK (m.filname)
  2159.       IF FOUND()
  2160.          m.disknum = &fldname
  2161.          \\    <<m.disknum>>,
  2162.          \\ <<TRIM(cprsname)>>,
  2163.          \\,,,,,, OLDER, !READONLY,,
  2164.          \\ <<TRIM(justfname(foxprint->expndname))>>,,,,
  2165.          \\ <<foxprint->expndsize>>,,,,,
  2166.          \\ !VITAL
  2167.          \
  2168.       ENDIF
  2169.    ENDSCAN
  2170.    SELECT foxprint
  2171.    USE
  2172.    SELECT (m.g_dbalias)
  2173.    SET ORDER TO TAG fname
  2174. ENDIF
  2175.  
  2176. * Emit the section for Graph files, if that option was selected
  2177. IF m.g_instgraph
  2178.    \
  2179.    \[MSGraph]
  2180.    \
  2181.    SELECT 0
  2182.    USE msgraph
  2183.    m.grphname = justfname(UPPER(TRIM(msgraph->fname)))
  2184.    m.grphname = IIF(msgraph->COMPRESS,gencprsname(m.grphname),m.grphname)
  2185.    SELECT (m.g_dbalias)
  2186.    SET ORDER TO TAG cprsname
  2187.    SEEK (m.grphname)
  2188.    IF FOUND()
  2189.       m.disknum = &fldname
  2190.       \\    <<m.disknum>>,
  2191.       \\ <<TRIM(cprsname)>>,
  2192.       \\,,,,,, OLDER, !READONLY,,
  2193.       \\ <<TRIM(justfname(msgraph->expndname))>>,,,,
  2194.       \\ <<msgraph->expndsize>>,,,,,
  2195.       \\ !VITAL
  2196.    ENDIF
  2197.    SELECT msgraph
  2198.    USE
  2199.    SELECT (m.g_dbalias)
  2200.    SET ORDER TO TAG fname
  2201. ENDIF
  2202.  
  2203. * Emit the [Application] section, containing application files plus the program to run at the
  2204. * conclusion of setup, if any.
  2205. *     6, appabout.prg,,,, 1993-01-18,,,, !READONLY,, foxapp\screens\appabout.prg,,,, 4084,,,,, !VITAL
  2206. \
  2207. \[Application]
  2208. \
  2209. SCAN FOR (!setupfile AND !extrafile) ;
  2210.       OR (extrafile AND (TRIM(UPPER(fname)) == UPPER(wordnum(m.g_executable,1)))) ;
  2211.       OR (extrafile AND m.g_eslextra ;
  2212.          AND (TRIM(UPPER(justfname(fname))) == UPPER(justfname(m.g_esl))))
  2213.    m.disknum = &fldname
  2214.    \\    <<m.disknum>>,
  2215.    \\ <<TRIM(cprsname)>>,
  2216.    DO CASE
  2217.    CASE (extrafile AND (TRIM(UPPER(fname)) == UPPER(wordnum(m.g_executable,1))))
  2218.       \\,
  2219.       \\,,,,,, !READONLY,,
  2220.       \\ <<TRIM(justfname(fname))>>,
  2221.    CASE EMPTY(parent) AND extrafile    && FOXW2500.ESL main piece
  2222.       \\,
  2223.       \\,,,,,, !READONLY,,
  2224.       \\ <<TRIM(justfname(fname))>>,
  2225.    CASE extrafile     && FOXW2500.ESL split piece
  2226.       \\ <<TRIM(justfname(fname))>>,
  2227.       \\,,,,,, !READONLY,,
  2228.       \\,
  2229.    CASE EMPTY(parent)
  2230.       \\,
  2231.       \\,,,,,, !READONLY,,
  2232.       \\ <<TRIM(fname)>>,
  2233.    OTHERWISE  && show that file should be appended to fname
  2234.       \\ <<TRIM(fname)>>,
  2235.       \\,,,,,, !READONLY,,
  2236.       \\,
  2237.    ENDCASE
  2238.    \\,,,
  2239.    IF splitfile     && show expanded size of split file piece.
  2240.       \\ <<expndsize>>,
  2241.    ELSE
  2242.       \\ <<filsize>>,
  2243.    ENDIF
  2244.    \\,,,,
  2245.    \\ !VITAL
  2246.    \
  2247. ENDSCAN
  2248.  
  2249. SET TEXTMERGE OFF
  2250. SET TEXTMERGE TO
  2251. SET CONSOLE ON
  2252. SET SAFETY &in_safe
  2253.  
  2254. RETURN
  2255.  
  2256. *!*****************************************************************************
  2257. *!
  2258. *!     Procedure: MAKELST
  2259. *!
  2260. *!*****************************************************************************
  2261. PROCEDURE makelst
  2262. PARAMETER m.thefile
  2263.  
  2264. SET TEXTMERGE TO (m.thefile)
  2265. SET TEXTMERGE ON
  2266. SET CONSOLE OFF
  2267.  
  2268. \[Params]
  2269. \    WndTitle   = <<IIF(EMPTY(m.g_title),s_setuptitle,m.g_title)>>
  2270. \    WndMess    = <<s_setupinit>>
  2271. \    TmpDirSize = 500
  2272. \    TmpDirName = ~msstfqf.t
  2273. \    CmdLine    = _mstest setup.mst /C "/S %s %s"
  2274. \    DrvModName = DSHELL
  2275. \
  2276. \[Files]
  2277. \    setup.ms_    = setup.mst
  2278. \    setup.in_    = setup.inc
  2279. \    setup.inf    = setup.inf
  2280. \    mscomstf.dl_ = mscomstf.dll
  2281. \    msinsstf.dl_ = msinsstf.dll
  2282. \    msuilstf.dl_ = msuilstf.dll
  2283. \    msshlstf.dl_ = msshlstf.dll
  2284. \    mscuistf.dl_ = mscuistf.dll
  2285. \    msdetstf.dl_ = msdetstf.dll
  2286. \    commdlg.dl_  = commdlg.dll
  2287. \    shell.dl_    = shell.dll
  2288. \    ver.dl_      = ver.dll
  2289. \    _mssetup.su_ = _mssetup.exe
  2290. \    _mstest.ex_  = _mstest.exe
  2291. \
  2292. SET CONSOLE ON
  2293. SET TEXTMERGE OFF
  2294. SET TEXTMERGE TO
  2295.  
  2296. *!*****************************************************************************
  2297. *!
  2298. *!     Procedure: SHOWSUMRY
  2299. *!
  2300. *!*****************************************************************************
  2301. PROCEDURE showsumry
  2302. * Report on the disks we just made
  2303. SET MESSAGE TO ""
  2304. SELECT (m.g_dbalias)
  2305. SET ORDER TO 0
  2306. IF m.g_dsk144
  2307.    DO psm WITH c_dsk144
  2308. ENDIF
  2309. IF m.g_dsk12
  2310.    DO psm WITH c_dsk12
  2311. ENDIF
  2312. IF m.g_dsk720
  2313.    DO psm WITH c_dsk720
  2314. ENDIF
  2315.  
  2316. SELECT (m.g_dbalias)
  2317.  
  2318. *!*****************************************************************************
  2319. *!
  2320. *!     Procedure: PSM
  2321. *!
  2322. *!*****************************************************************************
  2323. PROCEDURE psm
  2324. PARAMETER m.disktype
  2325. SELECT DISKS
  2326. SEEK m.disktype
  2327. IF FOUND()
  2328.    m.fldname = TRIM(DISKS->diskfld)
  2329.    m.clsize  = DISKS->clustsize
  2330.    * Note to translators: the strings like "Disk" do not need to be translated.  They
  2331.    * are field names and are not presented to the user.
  2332.    SELECT &fldname AS "Disk",;
  2333.       COUNT(dkcontrl.fname) AS "Files", ;
  2334.       SUM(allocsize(dkcontrl.cprssize,m.clsize)) AS "Bytes" ;
  2335.       FROM dkcontrl;
  2336.       GROUP BY &fldname ;
  2337.       INTO CURSOR dkset
  2338.    DO putsumry.spr WITH TRIM(DISKS->dname),DISKS->disksize, TRIM(disks->diskfld), m.clsize
  2339.    * Free the cursor we just created
  2340.    IF USED("dkset")
  2341.       SELECT dkset
  2342.       USE
  2343.    ENDIF
  2344. ENDIF
  2345. RETURN
  2346.  
  2347. *!*****************************************************************************
  2348. *!
  2349. *!     Function: PGETNAME
  2350. *!
  2351. *!*****************************************************************************
  2352. FUNCTION pgetname
  2353. PARAMETER m.pathname
  2354. PRIVATE ALL
  2355. m.pname = justfname(pathname)
  2356. IF splitfile
  2357.    m.num = getfnum(cprsname)
  2358.    DO CASE
  2359.    CASE m.num = 0 AND RIGHT(TRIM(juststem(cprsname)),1) = "0"
  2360.       RETURN m.pname + " (0)"
  2361.    CASE m.num = 0 AND RIGHT(TRIM(juststem(cprsname)),1) <> "0"
  2362.       RETURN m.pname + " (1)"
  2363.    OTHERWISE
  2364.       RETURN m.pname + " (" + ALLTRIM(STR(m.num,4)) + ")"
  2365.    ENDCASE
  2366. ELSE
  2367.    RETURN m.pname   
  2368. ENDIF
  2369.  
  2370. *!*****************************************************************************
  2371. *!
  2372. *!     Function: ZAPFRAG
  2373. *!
  2374. *!*****************************************************************************
  2375. PROCEDURE zapfrag
  2376. PARAMETER m.thefile, m.cprsext, m.putprompt
  2377.  
  2378. PRIVATE m.i, m.cleanup, m.jfname, m.thefile, m.cprscount, m.therec
  2379.  
  2380. SELECT (m.g_dbalias)
  2381. m.therec = RECNO()
  2382.  
  2383. m.jfname = justfname(m.thefile)
  2384. m.jstem  = juststem(m.thefile)
  2385. m.stemlen = LEN(m.jstem)
  2386.  
  2387. m.cleanup = 1
  2388. IF m.putprompt 
  2389.    DO badsplit.spr WITH m.thefile, m.cleanup
  2390. ENDIF
  2391.  
  2392. IF m.cleanup = 1
  2393.    * Delete the split file fragments for this file from the compressed directory.
  2394.    m.cprscount =ADIR(cprsfiles,addbs(m.g_cprsdir)+"*.*")
  2395.    FOR m.i = 1 TO m.cprscount
  2396.       DO CASE
  2397.       CASE m.jfname == justfname(cprsfiles[m.i,1])
  2398.          DELETE FILE (addbs(m.g_cprsdir)+cprsfiles[m.i,1])
  2399.       CASE m.jstem == juststem(cprsfiles[m.i,1]) ;
  2400.             AND justext(cprsfiles[m.i,1]) == m.cprsext
  2401.          DELETE FILE (addbs(m.g_cprsdir)+cprsfiles[m.i,1])
  2402.          
  2403.       CASE m.stemlen = 8 ;
  2404.             AND LEN(juststem(cprsfiles[m.i,1])) = 8 ;
  2405.             AND LEFT(m.jstem,7) == LEFT(juststem(cprsfiles[m.i,1]),7) ;
  2406.             AND isdigit(RIGHT(juststem(cprsfiles[m.i,1]),1)) ;
  2407.             AND justext(cprsfiles[m.i,1]) == m.cprsext
  2408.          DELETE FILE (addbs(m.g_cprsdir)+cprsfiles[m.i,1])
  2409.       CASE m.stemlen <= 7 AND isdigit(RIGHT(juststem(cprsfiles[m.i,1]),1)) ;
  2410.             AND justext(cprsfiles[m.i,1]) == m.cprsext
  2411.          * A possible split child file ...
  2412.          IF isdigit(RIGHT(m.jstem,1))
  2413.             * See if this is FAR25.EXE matching FAR26.EX$
  2414.             IF LEFT(m.jstem, m.stemlen - 1) ;
  2415.                == LEFT(juststem(cprsfiles[m.i,1]),LEN(juststem(cprsfiles[m.i,1]))-1)
  2416.                DELETE FILE (addbs(m.g_cprsdir)+cprsfiles[m.i,1])
  2417.             ENDIF
  2418.          ELSE
  2419.             IF m.jstem ;
  2420.                == LEFT(juststem(cprsfiles[m.i,1]),LEN(juststem(cprsfiles[m.i,1]))-1)
  2421.                * A file like FAR.EXE matches FAR2.EX$
  2422.                DELETE FILE (addbs(m.g_cprsdir)+cprsfiles[m.i,1])
  2423.             ENDIF
  2424.          ENDIF
  2425.       ENDCASE
  2426.    ENDFOR
  2427.    
  2428.    * Delete the DKCONTRL entries for the split pieces of this file
  2429.    SELECT (m.g_dbalias)
  2430.    
  2431.    SCAN FOR justfname(fname) == m.thefile AND splitfile AND EMPTY(parent)
  2432.       REPLACE splitfile WITH .F.
  2433.    ENDSCAN
  2434.    
  2435.    SCAN FOR justfname(fname) == m.thefile AND splitfile AND !EMPTY(parent)
  2436.       DELETE   
  2437.    ENDSCAN
  2438.    PACK
  2439. ENDIF
  2440.  
  2441. GOTO m.therec
  2442.  
  2443. RETURN
  2444. *!*****************************************************************************
  2445. *!
  2446. *!     Function: ALLOCSIZE
  2447. *!
  2448. *!*****************************************************************************
  2449. FUNCTION allocsize
  2450. * Compute the allocated size required for a file of size m.nominal on a disk with
  2451. * a cluster size of m.cluster.
  2452. PARAMETERS m.nominal, m.cluster
  2453. DO CASE
  2454. CASE m.cluster = 0
  2455.    RETURN -1   && invalid cluster size.  Test here to prevent division by zero.
  2456. CASE m.nominal = 0
  2457.    RETURN nominal
  2458. CASE m.nominal % m.cluster = 0
  2459.    RETURN m.nominal
  2460. OTHERWISE
  2461.    RETURN ((INT(m.nominal / m.cluster) + 1) * m.cluster)
  2462. ENDCASE
  2463.  
  2464. *!*****************************************************************************
  2465. *!
  2466. *!     Function: GENCPRSNAME
  2467. *!
  2468. *!*****************************************************************************
  2469. FUNCTION gencprsname
  2470. * Assign the compressed filename that COMPRESS.EXE will create
  2471. PARAMETER m.cname
  2472. m.cname = ALLTRIM(m.cname)
  2473. DO CASE
  2474. CASE RIGHT(m.cname,1) = "$"
  2475.    RETURN m.cname   
  2476. CASE LEN(justext(m.cname)) = 3
  2477.    RETURN forceext(m.cname,LEFT(justext(m.cname),2)+"$")
  2478. OTHERWISE
  2479.    RETURN forceext(m.cname,justext(m.cname)+"$")
  2480. ENDCASE
  2481.  
  2482. *!*****************************************************************************
  2483. *!
  2484. *!     Function: PUTONDISK
  2485. *!
  2486. *!*****************************************************************************
  2487. FUNCTION putondisk
  2488. PARAMETER m.fpath, m.diskno, m.extra, m.setup, m.cprs, m.prnt
  2489. * Assign file fpath to disk number m.diskno
  2490. * First find the file
  2491.  
  2492. m.numfiles = ADIR(rtdir,IIF(m.setup,addbs(m.g_runtimedir)+m.fpath,m.fpath))
  2493. IF m.numfiles > 0
  2494.    SELECT (m.g_dbalias)
  2495.    SET ORDER TO TAG fname
  2496.    SEEK m.fpath
  2497.    IF !FOUND()
  2498.       APPEND BLANK
  2499.    ENDIF
  2500.    REPLACE fname WITH m.fpath, ;
  2501.       filsize WITH rtdir[1,2], ;
  2502.       fdate WITH rtdir[1,3], ;
  2503.       ftime WITH rtdir[1,4], ;
  2504.       fattrib WITH rtdir[1,5]
  2505.  
  2506.    REPLACE cprsname WITH IIF(m.cprs,gencprsname(rtdir[1,1]),justfname(fname)), ;
  2507.       filfound WITH .T., ;
  2508.       extrafile WITH m.extra, ;
  2509.       setupfile WITH m.setup, ;
  2510.       COMPRESS WITH m.cprs, ;
  2511.       parent WITH m.prnt
  2512.    REPLACE splitfile WITH IIF(EMPTY(parent), .F., .T.)
  2513.    REPLACE cprssize WITH filsize
  2514.    REPLACE expndsize WITH filsize
  2515.    RETURN RECNO()
  2516. ENDIF
  2517. RETURN 0
  2518. *!*****************************************************************************
  2519. *!
  2520. *!     Function: MAPNAME
  2521. *!
  2522. *!*****************************************************************************
  2523. FUNCTION mapname
  2524. PARAMETER m.filname
  2525. * Compressed filenames have to be unique for Setup.  The compress utility replaces
  2526. * the last letter in the extension with an underscore.  This creates a problem with
  2527. * FoxPro since so many file extensions have the same first two letters (e.g., SCX, SCT).
  2528. * This routine tries to do something reasonable with the file name to make it unique.
  2529.  
  2530. m.theext = UPPER(justext(m.filname))
  2531.  
  2532. DO CASE
  2533. CASE m.theext == "SCT"
  2534.    RETURN forceext(m.filname,"STC")
  2535. CASE m.theext == "MNT"
  2536.    RETURN forceext(m.filname,"MTN")
  2537. CASE m.theext == "PJT"
  2538.    RETURN forceext(m.filname,"PTJ")
  2539. CASE m.theext == "FRT"
  2540.    RETURN forceext(m.filname,"FTR")
  2541. CASE m.theext == "LBT"
  2542.    RETURN forceext(m.filname,"LTB")
  2543. CASE m.theext == "SPX"
  2544.    RETURN forceext(m.filname,"SXP")
  2545. CASE m.theext == "MNX"
  2546.    RETURN forceext(m.filname,"MXN")
  2547. OTHERWISE
  2548.    RETURN m.filname
  2549. ENDCASE
  2550. *!*****************************************************************************
  2551. *!
  2552. *!     Function: ISRANDOM
  2553. *!
  2554. *!*****************************************************************************
  2555. FUNCTION israndom
  2556. * Returns .T. if m.filname appears to be a generated random name
  2557. PARAMETER m.filname
  2558. m.filname = UPPER(ALLTRIM(m.filname))
  2559. IF !EMPTY(m.filname) AND ISDIGIT(LEFT(m.filname,1)) ;
  2560.        AND ( ;
  2561.               (justext(m.filname) == c_randext) ;
  2562.            OR ( ;
  2563.               LEFT(justext(m.filname),2) == LEFT(c_randext,2) ;
  2564.               AND RIGHT(justext(m.filname),1) $ "$_" ;
  2565.               ) ;
  2566.            )
  2567.    RETURN .T.
  2568. ELSE
  2569.    RETURN .F.
  2570. ENDIF
  2571. *!*****************************************************************************
  2572. *!
  2573. *!     Function: CHECKFILES
  2574. *!
  2575. *!*****************************************************************************
  2576. FUNCTION checkfiles
  2577. PARAMETERS showerrormsg
  2578.  
  2579. * Returns TRUE if all files in the REQUIRED.DBF file are found in the g_runtimedir
  2580. * directory.  Used to validate the path entered in the g_runtimedir screen.
  2581. PRIVATE m.in_area, m.filemissing
  2582. m.in_area = SELECT()
  2583. m.filemissing = .F.
  2584. SELECT required
  2585. SCAN
  2586.    IF !FILE(forcepath(TRIM(required->reqname),g_runtimedir))
  2587.       m.filemissing = .T.
  2588.       IF !showerrormsg OR errormsg(ALLTRIM(required->reqname) ;
  2589.             + " " + error_array[en_notfound], c_entry1) = idcancel
  2590.          SELECT (m.in_area)
  2591.          RETURN .F.
  2592.       ENDIF
  2593.    ENDIF
  2594. ENDSCAN
  2595. SELECT (m.in_area)
  2596. RETURN !m.filemissing
  2597.  
  2598. *!*****************************************************************************
  2599. *!
  2600. *!     Function: CPRSMATCH
  2601. *!
  2602. *!*****************************************************************************
  2603. FUNCTION cprsmatch
  2604. * Do two filenames match after the compression program has changed the names?
  2605. PARAMETER fname1, fname2
  2606. DO CASE
  2607. CASE fname1 == fname2
  2608.    RETURN .T.
  2609. CASE LEN(fname1) = 12 AND LEN(fname2) = 12 AND LEFT(fname1,11) == LEFT(fname2,11)
  2610.    RETURN .T.
  2611. OTHERWISE
  2612.    RETURN .F.
  2613. ENDCASE
  2614. *!*****************************************************************************
  2615. *!
  2616. *!     Procedure: ZAPDIR
  2617. *!
  2618. *!*****************************************************************************
  2619. PROCEDURE zapdir
  2620. PARAMETER m.diskroot, m.error_array
  2621. PRIVATE ALL
  2622. * Delete any existing files in the destination tree
  2623.  
  2624. * Delete all the files in any of my children
  2625. m.numfiles = ADIR(rtdir,addbs(m.diskroot)+"*.*","D")
  2626. FOR m.i = 1 TO m.numfiles
  2627.    IF "D" $ rtdir[m.i,5] AND !INLIST(rtdir[m.i,1],"..",".")
  2628.       DO zapdir WITH addbs(m.diskroot)+rtdir[m.i,1], m.error_array
  2629.    ENDIF
  2630. ENDFOR
  2631.  
  2632. * Delete all the regular files in this directory
  2633. m.numfiles = ADIR(rtdir,addbs(m.diskroot)+"*.*")
  2634. FOR m.i = 1 TO m.numfiles
  2635.    DELETE FILE (addbs(m.diskroot)+rtdir[m.i,1])
  2636. ENDFOR
  2637.  
  2638. * Display an error message if there are any hidden or system files
  2639. m.numfiles = ADIR(rtdir,addbs(m.diskroot)+"*.*","SH")
  2640. FOR m.i = 1 TO m.numfiles
  2641.    * Hidden or system file found in C:\FOXPROW\FOO--QUUX.ABC
  2642.    DO errormsg WITH error_array[en_hidden]+m.diskroot+"--" +rtdir[m.i,1], c_warning
  2643. ENDFOR
  2644.  
  2645. IF m.numfiles = 0   && no hidden or system files.
  2646.    =rmdir(m.diskroot)
  2647. ENDIF
  2648.  
  2649. *!*****************************************************************************
  2650. *!
  2651. *!     Function: GETUFSIZE
  2652. *!
  2653. *!*****************************************************************************
  2654. FUNCTION getufsize
  2655. * Get the uncompressed file size for compressed file m.fname
  2656. PARAMETER m.fname
  2657. PRIVATE m.thesize, m.fp, m.buffer, m.numwords, m.theword, m.in_sec
  2658. m.thesize = "0"
  2659. IF FILE(m.fname)
  2660.    COPY FILE size.pif TO ufsize.pif
  2661.    SET TEXTMERGE TO usize.bat
  2662.    SET TEXTMERGE ON
  2663.    SET CONSOLE OFF
  2664.    IF FILE("usize.txt")
  2665.       DELETE FILE usize.txt
  2666.    ENDIF
  2667.    \\DECOMP -Q <<m.fname>> > usize.txt
  2668.    SET TEXTMERGE OFF
  2669.    SET TEXTMERGE TO
  2670.  
  2671.    IF !FILE("usize.bat")
  2672.       WAIT WINDOW "Fehler beim Erstellen der Stapelverarbeitungsdatei."   && shouldn't happen
  2673.    ENDIF
  2674.  
  2675.    * Run minimized.
  2676.    RUN ufsize.pif
  2677.  
  2678.    SET CONSOLE ON
  2679.  
  2680.    IF FILE("usize.bat")
  2681.       DELETE FILE usize.bat
  2682.    ENDIF
  2683.    IF FILE("ufsize.pif")
  2684.       DELETE FILE ufsize.pif
  2685.    ENDIF
  2686.    * Read the usize.txt file and extract the uncompressed size.
  2687.    IF FILE("usize.txt")
  2688.       m.fp = FOPEN("usize.txt")
  2689.       IF m.fp > 0
  2690.          DO WHILE !FEOF(m.fp)
  2691.             m.buffer = FGETS(m.fp)
  2692.             IF UPPER(LEFT(m.buffer,13)) == "DECOMPRESSION"
  2693.                * Start with word 8, which should be the file size
  2694.                m.thesize = wordnum(m.buffer,8)
  2695.                IF ISDIGIT(LEFT(m.thesize,1))
  2696.                   m.thesize = CHRTRAN(m.thesize," ,","")
  2697.                   EXIT
  2698.                ELSE    && find the size
  2699.                   m.numwords = words(m.buffer)
  2700.                   m.i = 1
  2701.                   DO WHILE m.i < m.numwords
  2702.                      m.theword = wordnum(m.buffer,m.i)
  2703.                      IF ISDIGIT(LEFT(m.theword,1))
  2704.                         m.thesize = m.theword
  2705.                         EXIT
  2706.                      ENDIF
  2707.                      m.i = m.i + 1
  2708.                   ENDDO
  2709.                ENDIF
  2710.             ENDIF
  2711.          ENDDO
  2712.          =FCLOSE(m.fp)
  2713.       ELSE
  2714.          DO errormsg WITH error_array[en_ufopen]+": "+m.fname, c_fatal
  2715.       ENDIF
  2716.       DELETE FILE usize.txt
  2717.    ELSE
  2718.       DO errormsg WITH error_array[en_ufopen]+": "+m.fname, c_fatal
  2719.    ENDIF
  2720.    RETURN VAL(m.thesize)
  2721. ELSE
  2722.    RETURN -1
  2723. ENDIF
  2724.  
  2725. *!*****************************************************************************
  2726. *!
  2727. *!     Function:  ISDIR
  2728. *!
  2729. *!*****************************************************************************
  2730. FUNCTION isdir
  2731. * Returns TRUE if m.directory exists as a directory
  2732. PARAMETER m.directory
  2733. PRIVATE ALL
  2734. m.directory = UPPER(ALLTRIM(m.directory))
  2735. IF RIGHT(m.directory,1) = '\'
  2736.    m.directory = LEFT(m.directory,LEN(m.directory)-1)
  2737. ENDIF
  2738. DO CASE
  2739. CASE LEN(m.directory) = 2 AND RIGHT(m.directory,1) = ":"
  2740.    RETURN .T.
  2741. CASE LEN(m.directory) = 3 AND SUBSTR(m.directory,2,1) = ":" AND RIGHT(m.directory,1) = "\"    
  2742.    RETURN .T.
  2743. OTHERWISE 
  2744.    m.parent = justpath(m.directory)
  2745.    m.child  = juststem(m.directory)
  2746.    m.numfiles = ADIR(subdir,addbs(m.parent)+"*.*","D")
  2747.    IF m.numfiles > 0
  2748.       FOR m.i = 1 TO m.numfiles
  2749.          IF subdir[m.i,1] == m.child AND  "D" $ subdir[m.i,5] 
  2750.             RETURN .T.
  2751.          ENDIF
  2752.       ENDFOR
  2753.    ENDIF
  2754. ENDCASE   
  2755. RETURN .F.
  2756.  
  2757. *!*****************************************************************************
  2758. *!
  2759. *!     Function: TRIMPATH
  2760. *!
  2761. *!*****************************************************************************
  2762. FUNCTION trimpath
  2763. * Trim trailing backslash off a directory name, unless it is C:\, D:\, etc.
  2764. PARAMETER m.path
  2765. PRIVATE ALL
  2766. m.path = TRIM(m.path)
  2767. DO CASE
  2768. CASE LEN(m.path) = 1 OR LEN(m.path) = 2  && who knows?  Just return it.
  2769.    RETURN m.path
  2770. CASE LEN(m.path) = 3 AND SUBSTR(m.path,2,1) = ':' AND RIGHT(m.path,1) = '\'  && like C:\
  2771.    RETURN m.path
  2772. CASE RIGHT(m.path,1) = '\'
  2773.    RETURN LEFT(m.path,LEN(m.path)-1)
  2774. OTHERWISE
  2775.    RETURN m.path
  2776. ENDCASE 
  2777.  
  2778. **
  2779. ** Code Associated With Displaying of the Thermometer
  2780. **
  2781.  
  2782. *
  2783. * ACTTHERM(<text>) - Activate thermometer.
  2784. *
  2785. * Activates thermometer.  Update the thermometer with UPDTHERM().
  2786. * Thermometer window is named "thermometer."  Be sure to RELEASE
  2787. * this window when done with thermometer.  Creates the global
  2788. * m.g_thermwidth.
  2789. *
  2790. *!*****************************************************************************
  2791. *!
  2792. *!     Procedure: ACTTHERM
  2793. *!
  2794. *!*****************************************************************************
  2795. PROCEDURE acttherm
  2796. PARAMETER m.text
  2797. PRIVATE m.prompt
  2798. #DEFINE c_dlgface "MS Sans Serif"
  2799. #DEFINE c_dlgsize 8
  2800. #DEFINE c_dlgstyle "B"
  2801. m.prompt = c_thermprompt
  2802. IF TXTWIDTH(m.prompt, c_dlgface, c_dlgsize, c_dlgstyle) > 43
  2803.    DO WHILE TXTWIDTH(m.prompt+"...", c_dlgface, c_dlgsize, c_dlgstyle) > 43
  2804.       m.prompt = LEFT(m.prompt, LEN(m.prompt)-1)
  2805.    ENDDO
  2806.    m.prompt = m.prompt + "..."
  2807. ENDIF
  2808.  
  2809. DEFINE WINDOW thermomete ;
  2810.    AT  INT((SROW() - (( 5.615 * ;
  2811.    FONTMETRIC(1, c_dlgface, c_dlgsize, c_dlgstyle )) / ;
  2812.    FONTMETRIC(1, WFONT(1,""), WFONT( 2,""), WFONT(3,"")))) / 2), ;
  2813.    INT((SCOL() - (( 63.833 * ;
  2814.    FONTMETRIC(6, c_dlgface, c_dlgsize, c_dlgstyle )) / ;
  2815.    FONTMETRIC(6, WFONT(1,""), WFONT( 2,""), WFONT(3,"")))) / 2) ;
  2816.    SIZE 5.615,63.833 ;
  2817.    FONT c_dlgface, c_dlgsize ;
  2818.    STYLE c_dlgstyle ;
  2819.    NOFLOAT ;
  2820.    NOCLOSE ;
  2821.    NONE ;
  2822.    COLOR RGB(0, 0, 0, 192, 192, 192)
  2823. MOVE WINDOW thermomete CENTER
  2824. ACTIVATE WINDOW thermomete NOSHOW
  2825.  
  2826. @ 0.5,3 SAY m.text FONT c_dlgface, c_dlgsize STYLE c_dlgstyle
  2827. @ 1.5,3 SAY m.prompt FONT c_dlgface, c_dlgsize STYLE c_dlgstyle
  2828. @ 0.000,0.000 TO 0.000,63.833 ;
  2829.    COLOR RGB(255, 255, 255, 255, 255, 255)
  2830. @ 0.000,0.000 TO 5.615,0.000 ;
  2831.    COLOR RGB(255, 255, 255, 255, 255, 255)
  2832. @ 0.385,0.667 TO 5.231,0.667 ;
  2833.    COLOR RGB(128, 128, 128, 128, 128, 128)
  2834. @ 0.308,0.667 TO 0.308,63.167 ;
  2835.    COLOR RGB(128, 128, 128, 128, 128, 128)
  2836. @ 0.385,63.000 TO 5.308,63.000 ;
  2837.    COLOR RGB(255, 255, 255, 255, 255, 255)
  2838. @ 5.231,0.667 TO 5.231,63.167 ;
  2839.    COLOR RGB(255, 255, 255, 255, 255, 255)
  2840. @ 5.538,0.000 TO 5.538,63.833 ;
  2841.    COLOR RGB(128, 128, 128, 128, 128, 128)
  2842. @ 0.000,63.667 TO 5.615,63.667 ;
  2843.    COLOR RGB(128, 128, 128, 128, 128, 128)
  2844. @ 3.000,3.333 TO 4.231,3.333 ;
  2845.    COLOR RGB(128, 128, 128, 128, 128, 128)
  2846. @ 3.000,60.333 TO 4.308,60.333 ;
  2847.    COLOR RGB(255, 255, 255, 255, 255, 255)
  2848. @ 3.000,3.333 TO 3.000,60.333 ;
  2849.    COLOR RGB(128, 128, 128, 128, 128, 128)
  2850. @ 4.231,3.333 TO 4.231,60.500 ;
  2851.    COLOR RGB(255, 255, 255, 255, 255, 255)
  2852. m.g_thermwidth = 56.269
  2853.  
  2854. SHOW WINDOW thermomete TOP
  2855. RETURN
  2856.  
  2857. *
  2858. * UPDTHERM(<percent>) - Update thermometer.
  2859. *
  2860. *!*****************************************************************************
  2861. *!
  2862. *!     Procedure: UPDTHERM
  2863. *!
  2864. *!*****************************************************************************
  2865. PROCEDURE updtherm
  2866. PARAMETER m.percent
  2867. PRIVATE m.nblocks, m.percent
  2868.  
  2869. IF !WEXIST("thermomete")
  2870.    DO acttherm WITH c_setupname
  2871. ENDIF
  2872. IF m.g_thermwidth = 0
  2873.    m.g_thermwidth = 56.269
  2874. ENDIF
  2875.  
  2876. ACTIVATE WINDOW thermomete
  2877.  
  2878. * Map to the number of platforms we are generating for
  2879. m.percent = MIN(m.percent,100)
  2880.  
  2881. m.nblocks = (m.percent/100) * (m.g_thermwidth)
  2882. @ 3.000,3.333 TO 4.231,m.nblocks + 3.333 ;
  2883.    PATTERN 1 COLOR RGB(128, 128, 128, 128, 128, 128)
  2884. RETURN
  2885.  
  2886. *
  2887. * DEACTTHERMO - Deactivate and Release thermometer window.
  2888. *
  2889. *!*****************************************************************************
  2890. *!
  2891. *!     Procedure: DEACTTHERMO
  2892. *!
  2893. *!*****************************************************************************
  2894. PROCEDURE deactthermo
  2895. IF WEXIST("thermomete")
  2896.    RELEASE WINDOW thermomete
  2897. ENDIF
  2898. RETURN
  2899.  
  2900. *!*****************************************************************************
  2901. *!
  2902. *!     Procedure: GETPREFERENCES
  2903. *!
  2904. *!*****************************************************************************
  2905. PROCEDURE getpreferences
  2906. PARAMETER m.ini_name
  2907. * Get user's responses from DKSETUP.INI file
  2908. m.g_sourcedir  = getprof(m.ini_name,c_pref,c_sourcedir)
  2909. m.g_destdir    = getprof(m.ini_name,c_pref,c_destdir)
  2910. m.g_runtimedir = getprof(m.ini_name,c_pref,c_runtime)
  2911. m.g_dsk144     = IIF(UPPER(getprof(m.ini_name,c_pref,c_make144))="Y",.T.,.F.)
  2912. m.g_dsk12      = IIF(UPPER(getprof(m.ini_name,c_pref,c_make12))="Y",.T.,.F.)
  2913. m.g_dsk720     = IIF(UPPER(getprof(m.ini_name,c_pref,c_make720))="Y",.T.,.F.)
  2914. m.g_instgraph  = IIF(UPPER(getprof(m.ini_name,c_pref,c_instgraph))="Y",.T.,.F.)
  2915. m.g_targetdir  = getprof(m.ini_name,c_pref,c_targetdir)
  2916. m.g_appname    = getprof(m.ini_name,c_pref,c_appname)
  2917. m.g_pmdescript = getprof(m.ini_name,c_pref,c_pmdescript)
  2918. m.g_pmgroup    = getprof(m.ini_name,c_pref,c_pmgroup)
  2919. m.temp         = getprof(m.ini_name,c_pref,c_usermod)
  2920. IF !EMPTY(m.temp) AND BETWEEN(VAL(m.temp),1,3)
  2921.    m.g_modoptions = VAL(m.temp)
  2922. ENDIF   
  2923. m.temp         = getprof(m.ini_name,c_pref,c_nologo)
  2924. IF !EMPTY(m.temp) AND VAL(m.temp) > 0
  2925.    m.g_nologo     = VAL(m.temp)
  2926. ENDIF
  2927. m.g_altcfgfile = getprof(m.ini_name,c_pref,c_altcfgfile)
  2928. m.g_usealtcfg  = IIF(EMPTY(m.g_altcfgfile),0,1)
  2929. m.g_parameters = getprof(m.ini_name,c_pref,c_parameters)
  2930.  
  2931. m.g_executable = getprof(m.ini_name,c_pref,c_runanother)
  2932. m.g_title      = getprof(m.ini_name,c_pref,c_setuptitle)
  2933. m.g_copyright  = getprof(m.ini_name,c_pref,c_copyright)
  2934.  
  2935. m.temp         = getprof(m.ini_name,c_pref,c_splitsize)
  2936. IF !EMPTY(m.temp) AND VAL(m.temp) > 0
  2937.    m.g_splitsize = VAL(m.temp)
  2938. ENDIF
  2939. m.temp         = getprof(m.ini_name,c_pref,c_algorithm)
  2940. IF !EMPTY(m.temp) AND INLIST(m.temp,"2","3")  && 2 and 3 are only valid values
  2941.    m.g_algorithm = m.temp
  2942. ENDIF
  2943. *!*****************************************************************************
  2944. *!
  2945. *!     Procedure: PUTPREFERENCES
  2946. *!
  2947. *!*****************************************************************************
  2948. PROCEDURE putpreferences
  2949. PARAMETER m.ini_name
  2950. * Store user's responses in DKSETUP.INI file
  2951. = putprof(m.ini_name,c_pref,c_sourcedir,m.g_sourcedir)
  2952. = putprof(m.ini_name,c_pref,c_destdir,m.g_destdir)
  2953. = putprof(m.ini_name,c_pref,c_runtime,m.g_runtimedir)
  2954. = putprof(m.ini_name,c_pref,c_make144,IIF(m.g_dsk144,"Y","N"))
  2955. = putprof(m.ini_name,c_pref,c_make12,IIF(m.g_dsk12,"Y","N"))
  2956. = putprof(m.ini_name,c_pref,c_make720,IIF(m.g_dsk720,"Y","N"))
  2957. = putprof(m.ini_name,c_pref,c_instgraph,IIF(m.g_instgraph,"Y","N"))
  2958. = putprof(m.ini_name,c_pref,c_targetdir,m.g_targetdir)
  2959. = putprof(m.ini_name,c_pref,c_appname,m.g_appname)
  2960. = putprof(m.ini_name,c_pref,c_pmdescript,m.g_pmdescript)
  2961. = putprof(m.ini_name,c_pref,c_pmgroup,m.g_pmgroup)
  2962.  
  2963. = putprof(m.ini_name,c_pref,c_usermod,ALLTRIM(STR(m.g_modoptions,1)))
  2964. = putprof(m.ini_name,c_pref,c_nologo,ALLTRIM(STR(m.g_nologo,1)))
  2965. = putprof(m.ini_name,c_pref,c_altcfgfile,IIF(m.g_usealtcfg=0,"",m.g_altcfgfile))
  2966. = putprof(m.ini_name,c_pref,c_parameters,m.g_parameters)
  2967.  
  2968. = putprof(m.ini_name,c_pref,c_runanother,m.g_executable)
  2969. = putprof(m.ini_name,c_pref,c_setuptitle,m.g_title)
  2970. = putprof(m.ini_name,c_pref,c_copyright,m.g_copyright)
  2971. = putprof(m.ini_name,c_pref,c_splitsize,ALLTRIM(STR(m.g_splitsize,20)))
  2972. = putprof(m.ini_name,c_pref,c_algorithm,m.g_algorithm)
  2973.  
  2974. *!*****************************************************************************
  2975. *!
  2976. *!     Procedure: PUTPROF
  2977. *!
  2978. *!*****************************************************************************
  2979. PROCEDURE putprof
  2980. * Place a profile string into dksetup_ini
  2981. PARAMETER m.ini_name, m.application, m.section, m.pstring
  2982.  
  2983. * Create the INI file if it doesn't exist
  2984. IF !FILE(m.ini_name)
  2985.    fp = FCREATE(m.ini_name)
  2986.    =FPUTS(fp," ")
  2987.    =FCLOSE(fp)
  2988. ENDIF
  2989.  
  2990. m.wfn = regfn("WritePrivateProfileString","CCCC","I")
  2991. RETURN callfn(m.wfn,m.application,m.section,m.pstring,m.ini_name)
  2992.  
  2993. *!*****************************************************************************
  2994. *!
  2995. *!     Function: GETPROF
  2996. *!
  2997. *!*****************************************************************************
  2998. FUNCTION getprof
  2999. * Retrieve a profile string from dksetup_ini
  3000. PARAMETER m.ini_name, m.application, m.section
  3001. PRIVATE ALL
  3002. m.e_buf = REPLICATE(CHR(0),255)
  3003. m.gfn = regfn("GetPrivateProfileString","CCC@CIC","I")
  3004. =callfn(m.gfn,m.application, m.section,CHR(0),@m.e_buf,255,m.ini_name)
  3005. m.e_buf = ALLTRIM(CHRTRAN(m.e_buf,CHR(0)," "))
  3006. RETURN m.e_buf
  3007.  
  3008. *!*****************************************************************************
  3009. *!
  3010. *!     Procedure: ERRORHANDLER
  3011. *!
  3012. *!*****************************************************************************
  3013. PROCEDURE errorhandler
  3014. PARAMETER m.msg, m.code
  3015. DO errormsg WITH m.msg, m.code
  3016. RETURN TO dksetup
  3017.