/*********************************************************************** ZipBoot.cmd, a script to backup the eCS or OS/2 bootdrive Copyright (c) 2016 by Greggory Shaw Info at http://os2notes.net/os2backups.html Please change the following values to your needs! ***********************************************************************/ CALL RxFuncAdd "SYSLoadFuncs","RexxUtil","SYSLoadFuncs" CALL SYSLoadFuncs SIGNAL ON SYNTAX SIGNAL ON HALT Version = '1.1' Date = '11.21.2016' CurrentDir = directory() CALL iPath BackupDir = NewPath || '\Backups\Local\ZipBoot' /*********************************************************************** * Location of the saved backup, this directory must exist! * */ backup_dir= BackupDir /*********************************************************************** You might change this value to 0 to prevent loging the saved files * The logfile will be placed into the backup_dir above. * */ verbose=1 /*********************************************************************** ATTENTION: * In some cases this script may not find the right bootdrive! * Please insert the right value below. * */ bootdrive='' IF BootDrive='' THEN DO BootDrive=sysBootDrive() END /*********************************************************************** * End of user data * ***********************************************************************/ /*********************************************************************** Create the name of the backup file, using the date * File name format: backup_YYYY_MM_DD.zip * */ td=DATE(S) bu_name='ZipBoot_' || td CALL CColor CALL Banner theSelect=getSelection() SELECT WHEN theSelect=1 THEN DO SAY "" call BackupPartition Exit 0; END WHEN theSelect=2 THEN DO SAY "" call RestoreFiles Exit 0; END WHEN theSelect=3 THEN DO SAY "" call RestorePart Exit 0; END WHEN theSelect=4 THEN DO SAY "" call FoxHelp END OTHERWISE NOP END Exit 0; CColor: /*********************************************************************** Set some colors, thanx to Dmitry A.Steklenev for the inspiration * enable ANSI extended screen and keyboard control * */ '@ansi on > nul' color.brown = "1B"x"[0;33m" color.red = "1B"x"[1;31m" color.green = "1B"x"[1;32m" color.yellow = "1B"x"[1;33m" color.blue = "1B"x"[1;34m" color.magenta = "1B"x"[1;35m" color.cyan = "1B"x"[1;36m" color.white = "1B"x"[1;37m" color.gray = "1B"x"[0m" RETURN iPath: String = CurrentDir NewPath = substr(string,1,lastpos('\',translate(string,'\','/'))-1) Return BackupPartition: /*********************************************************************** Start message * */ CLS say '' SAY color.gray || 'Thank you for using '|| color.magenta || 'ZipBoot' ||, color.gray || ', a backup tool for your OS/2 Boot Drive.' SAY '' SAY color.gray || 'Copyright (c) 2016 by '|| color.green || 'Greggory Shaw' SAY '' SAY color.cyan || 'Version 'Version || color.gray || ' - 21 Nov 2016.' say '' say '' say color.gray || 'This program creates a backup of your boot drive ' ||, color.green || bootdrive || color.gray ||' using Info-Zip ( > 2Gb).' say '' say 'The zip file will be located at: ' say '' say color.green || backup_dir say '' say color.red || 'Continue? Y/n' pull YesNo if \ ((YesNo = "Y") | (YesNo = "y") | (YesNo = "J") | (YesNo = "j")) then exit /*********************************************************************** Check if the swapper.dat is placed on the bootdrive and exclude it * Delete file ZipBoot_Current.zip if present */ config_sys=bootdrive'\config.sys' call=SysFileSearch('SWAPPATH',config_sys,'result.') IF SUBSTR(result.1,10,2)=bootdrive THEN DO PARSE VALUE result.1 WITH crap1'='swap_path crap1 crap2 excl_swap=' -x 'swap_path'\swapper.dat' END ELSE excl_swap='' zip_del = 'DEL 'backup_dir'\ZipBoot_Current.zip ' zip_del /*********************************************************************** Create the command line for zip.exe * */ zip_cmd = 'zip.exe -Srg9 'backup_dir'\'bu_name' 'bootdrive'\*' zip_ren = 'copy 'backup_dir'\'bu_name'.zip 'backup_dir'\ZipBoot_Current.zip' IF verbose=1 THEN DO logging=' 2>'backup_dir'\backup_error.log >'backup_dir'\backup.log' END cmd=zip_cmd||excl_swap||logging say '' say color.green || 'Working.......Output has been redirected to log files.' say '' /*********************************************************************** Execute the command line for zip.exe * */ cmd zip_ren CALL BEEP 1000,100 SAY '' SAY color.gray || 'Error and Logging files are located in ' || backup_dir SAY '' SAY 'Change verbose = 1 to 0 to stop logging and re-direct to screen.' SAY '' SAY color.green || "Done!" || color.gray SAY '' pause RETURN getSelection: PROCEDURE QUIT=0 SAY "Select type of option:" SAY "" SAY " 1: Backup Boot Partition" SAY "" SAY " 2: Restore a file" SAY " 3: Restore entire partition" SAY "" SAY " ('h' for help)" SAY " ('q' for exit)" SAY "" Do UNTIL QUIT=1 say '>' parse value SysCurPos() with aktzeile aktspalte newposition=SysCurPos(aktzeile-1,2) pull theChar IF theChar='H' then call ZipHelp IF theChar='Q' then EXIT 1 if LENGTH(theChar)==1 & VERIFY(theChar, "1234")==0 THEN QUIT=1 ELSE call beep 100, 100 call SysCurPos aktzeile-1, 0 SAY "1B"x || "[K" call SysCurPos aktzeile-1, 0 END SAY "" RETURN theChar /*********************************************************************** RestoreFiles * */ RestoreFiles: cls call ccolor SAY '' SAY color.green || 'Restore a specific file(s):' || color.gray SAY '' SAY '' SAY color.green || 'Option one: ' || color.gray || 'Browse the zip file using a file browser. The files will be exacted' SAY ' to the 'Backups' folder. Use the 'Insert' key to move the file.' SAY '' SAY color.green || 'Option two: ' || color.gray || 'Restore a specific file(s) manually up to 3 files three files or' SAY ' directories can be extracted, separate each item with a space.' SAY '' SAY '' SAY '' SAY "Select option:" SAY "" SAY " 1: Browse zip & exact a specific file(s)" SAY "" SAY " 2: Restore a specific file(s)" SAY "" SAY "" SAY " ('q' for exit)" SAY "" key = SysGetKey() parse upper var key key If key = '1' then call GFS2 If key = '2' then Call UnzipFile RETURN UnzipFile: /*********************************************************************** Unzip Files * */ CLS SAY color.green || 'Restore a specific file(s):' SAY '' SAY color.gray || 'This program extracts a single file from the backup image ' SAY 'of your boot drive ' || color.green || bootdrive || color.gray ||' made by "ZipBoot".' SAY '' SAY 'Three files or directories can be extracted, separate each item with a space.' SAY '' SAY 'Example files: ' || color.green || 'config.sys config.001 config.002' || color.gray SAY '' SAY 'Example directories: ' || color.green || ' var\temp\* var\*' || color.gray SAY '' SAY ' 1) VAR\TEMP\* - will extract only the temp directory' SAY ' 2) VAR\* - will extract the entire tree' SAY '' SAY ' ** See UNZIP DOCS for more EXAMPLES' SAY '' SAY '' SAY 'Is this the correct boot drive letter: ' || color.green || BootDrive || color.gray SAY '' key = SysGetKey() parse upper var key key if key <> 'Y' then Call Maintenance SAY '' SAY 'Do you want to unzip the file directly to the boot drive ' || color.green || bootdrive SAY color.red || 'Continue? Y/n' || color.gray SAY '' key = SysGetKey() parse upper var key key if key <> 'Y' then Call UnzipTemp SAY '' SAY 'Enter file to recover, do not add the DRIVE LETTER.' PULL FileName SAY '' SAY 'Is this the correct path: ' || BootDrive || '\' || FileName SAY '' key = SysGetKey() parse upper var key key if key <> 'Y' then EXIT SAY '' /* List files and delete each of them */ /* Create Match list of do-not-deletes, upper case! */ FileName.1=FileName FileName.2='' FileName.3='' FileName.0=3 /* Set stem array length */ /* Read directory and all sub-directories and create file list in stem array filelist, * take care of possible trailing back slash. */ /* We only care about the fully qualified path names and in subfolders as well, * so use "O" option to drop dates, times, attribs, etc. */ rtc = SysFileTree( STRIP( BackupDir, 'T', '\' )||"\*", "filelist", "SFO" ) /* Create worker loops */ Do A = 1 to FileName.0 /* Loop through file list using count in stem base */ If FileName.A = '' Then /* found a match - using upper case to ensure proper matching */ Iterate A /* Jump to the next file in the list and don't process this one! */ Unzip BackupDir || '\' || bu_name || ' ' || FileName.A || ' -d ' || BootDrive || '\' SAY FileName.A /* Add programming code here to check error codes if wanted - for instance cant delete because locked file */ /* If rtc = 0 Then Say FileSpec( filelist.A, 'N' ) 'deleted' */ End pause RETURN UnzipTemp: CurrentDir = CurrentDir || '\Unzip' SAY '' SAY 'Do you want to unzip the file to the temporary directory?' SAY color.green || NewPath || '\Backups' SAY '' SAY color.red || 'Continue? Y/n' || color.gray SAY '' key = SysGetKey() parse upper var key key if key <> 'Y' then Call End SAY '' SAY 'Enter file to recover, do not add the DRIVE LETTER.' PULL FileName SAY '' SAY 'Is this the correct filename: ' || FileName key = SysGetKey() parse upper var key key if key <> 'Y' then End /* List files and delete each of them */ /* Create Match list of do-not-deletes, upper case! */ FileName.1=FileName FileName.2='' FileName.3='' FileName.0=3 /* Set stem array length */ /* Read directory and all sub-directories and create file list in stem array filelist, * take care of possible trailing back slash. */ /* We only care about the fully qualified path names and in subfolders as well, * so use "O" option to drop dates, times, attribs, etc. */ rtc = SysFileTree( STRIP( BackupDir, 'T', '\' )||"\*", "filelist", "SFO" ) /* Create worker loops */ Do A = 1 to FileName.0 /* Loop through file list using count in stem base */ If FileName.A = '' Then /* found a match - using upper case to ensure proper matching */ Iterate A /* Jump to the next file in the list and don't process this one! */ Unzip BackupDir || '\' || 'Zipboot_Current.zip' || ' ' || FileName.A || ' -d ' || NewPath || '\Backups' /* ZIP file */ SAY FileName.A /* Add programming code here to check error codes if wanted - for instance cant delete because locked file */ /* If rtc = 0 Then Say FileSpec( filelist.A, 'N' ) 'deleted' */ End EXIT 0; RestorePart: Call GFS RETURN Banner: /*********************************************************************** Start message * */ SAY '' SAY color.gray || 'Thank you for using '|| color.magenta || 'ZipBoot' ||, color.gray || ', a backup tool for your OS/2 Boot Drive.' SAY '' SAY color.gray || 'Copyright (c) 2016 by '|| color.green || 'Greggory Shaw' SAY '' SAY color.cyan || 'Version 'Version || color.gray || ' - 21 Nov 2016.' SAY '' SAY '' SAY color.gray || 'This program creates a backup of your boot drive ' ||, color.green || bootdrive || color.gray ||' using Info-Zip ( > 2Gb).' SAY '' SAY 'Stand alone version available at http://os2notes.net/os2backups.html' SAY '' SAY '' RETURN Maintenance: SAY '' SAY 'Enter Correct Boot Drive that needs to be restored.' SAY '' PULL BootDrive RETURN SYNTAX: SAY 'SYNTAX ERROR:' errortext( rc ) 'in:' SAY sourceline( sigl ) 'pause' EXIT RETURN HALT: SAY 'HALT occurred in:' SAY sourceline( sigl ) 'pause' EXIT RETURN GFS: /* GFS Generalized File Selector front-end by DGD v3 (mod'd from LD4) */ /* Keyboarding will always beat mousing around! Uses Classic REXX (+ RexxUtil) only. Freeware, but only for OS/2 - ECS. Installation: place this in \OS2, and perhaps edit associations or paths below. SHOULD pick a place for temporary files below, preferably RAMFS. -- ENSURE that any editor used DOES NOT wrap lines! MOST applications will open in foreground; add "/B" into fassoc by the the appropriate executable to open in background. Also, for TEDIT, "/WIN" opens up another VIO, but you may prefer it in the existing window... Automatic adjustment to VIO rows, columns: "mode 100, 40" works nicely. Unfortunately, no known way to maximize window with just Classic REXX. Can now give filter parameter(s) on command line, any number of patterns separated by spaces. To filter just video types, new "/v" switch. Commands implemented: þ or F3 exits þ F1 brings up abbreviated help þ up and down arrow keys move highlight þ left and right arrow keys move into and out of directories þ page-up and page-down do as they're named þ UPPERcase A-Z select drive þ lowercase a-z or 0-9 jumps to next file or dir starting with character þ launches executable associated with file extension (also, when on directory same as right arrow) - .EXEs are run (can be either dangerous or useless without parameters!) - TEXT files -- OR files without an extension -- are passed to TEDIT - .ZIPs are unzipped (requires UNZIP.EXE) to temporary directory (which needs to be specified for your system); also, RAMFS is suggested - .RARs are unpacked to the directory GFS was started in (semi-bug) - video files are opened by MPlayer -- assuming the .exe is in c:\mplayer - music files are sent to Z (opening in background), pre-empting current - .PDFs are opened by GhostView, assuming path is set right - for unassociated file types asks whether to open with TEDIT answering yes adds that extension into list for the session þ attempts to execute, any file þ sets a directory to move files to, useful for sorting into categories þ copies or moves highlighted file to "home" directory þ toggles between copy and move action for þ deletes file or directory (uppercase "Y" required!) READ-ONLY ATTRIBUTES ARE NO OBSTACLE! But System and Hidden still protect. þ sets passwords for RARs and ZIPs þ toggles filter for video files types (as defined in fassoc var) þ switches back and forth between current and a previously set directory þ ctrl- sets the fixed directory */ /* Call SysCurState 'OFF' */ call syscls call constants /* moved to end to un-clutter */ /* semi-CONSTANT */ parse value systextscreensize() with scry scrx scry= scry - 1; scrx= scrx - 1; /* adj to 0, 0 based values */ numeric digits 12 /* necessary to display bytes of gigabytes */ glo_var= 'dirlist.' /* ============== ALL CODE ABOVE is necessary for file_select ============= */ /* ================== Begin FRONT-END SPECIFIC section. =================== */ /* EDIT / ADD ASSOCIATIONS BELOW AS SPECIFIC TO YOUR SYSTEM values before executable go with 'start' command; see > help start .EXE files are all a special case and are invoked .ZIP files require UNZIP.EXE in PATH, and UNZIP32.DLL in LIBPATH commas chain all to 1 string, automagically adds space after ']' */ fassoc= ']', /* dummy ] to avoid anomaly in retrieving first substring */ '/WIN /C C:\OS2\TEDIT.EXE [*.sys *.txt *.pas *.doc *.cmd *.bat *.log *.os2', '*.c *.h *.cpp *.diz *.me *.1st]', /* and files w/o extension */ 'C:\FIREFOX\FIREFOX.EXE [*.htm *.html *.shtml *.asp *.aspx *.php]', 'C:\OS2\VIEW.EXE [*.inf]', 'C:\PMVIEW\PMVIEW.EXE [*.bmp *.jpg *.gif *.png *.tiff]', /* many others... */ 'C:\GS\GSVIEW2\GVPM.EXE [*.pdf]', '/PM C:\MPLAYER\MPLAYER.EXE -really-quiet -fs', /* FULL SCREEN ON */ '[*.avi *.wmv *.mpg *.mpeg *.mov *.flv *.rm *.ram *.rmvb *.m4v *.asf', '*.mp4 *.divx *.vob *.mkv]', /* may be yet others */ '/PM C:\WARPIN\WARPIN.EXE [*.wpi]', 'HANDLE_RAR [*.rar]', /* special case to use optional passwords */ 'HANDLE_TORRENT [*.torrent]', /* only for looking at info... THOUGH would be easy to start ACT running too... */ 'HANDLE_ZIPBOOT [ZipBoot_*.zip]', 'HANDLE_ZIP [*.zip]', /* EXTRA SPECIAL CASE expanded in temporary dir... */ 'HANDLE_Z [*.mp3 *.wav *.m3u *.pls]' /* because stupid Z EATS playlists */ /* ^^^ if no '.EXE' here, calls the procedure of that name */ fassoc= translate(fassoc) /* lower case up there just for readibility */ do t= lastpos(']', fassoc) to 2 by - 1 /* insert a space before each "]" */ if substr(fassoc, t, 1) = ']' then fassoc= insert(' ', fassoc, t - 1) end /* so can ensure 1 and 2 char extensions don't match as part of longer */ /**************************************************************************** PATH Statements * */ curpath= NewPath || '\Backups\Local\ZipBoot' /* case of started in dir */ curfil= '' home_dir= NewPath || '\Backups' /* set HOME DIR, can set to preference */ mark_orig= home_dir; /* v3 three lines to FIX operation from start */ if length(mark_orig) > 3 then mark_orig= mark_orig||'\' /* grrr... */ mark_temp= home_dir /* ^^^ missing slash again a nuisance */ /**************************************************************************** PICK ONE of three places for temp_dir, PREFERABLY a RAMDRIVE. */ temp_dir= directory() /* in whatever directory started in */ /* temp_dir= value('TMP',,'OS2ENVIRONMENT') */ /* usually \tcpip\tmp */ /* temp_dir= 'R:' ramdrive in my system */ temp_dir= temp_dir||'\_G_F_S_T' /* unzip directory, created and erased */ 'mkdir 'temp_dir /* creating TEMP DIR */ rc= sysfiletree(temp_dir, dirlist, 'D') if dirlist.0 = 0 then do say " !!! Can't create"temp_dir" -- Unzipping disabled." temp_dir= '' end else 'rmdir 'temp_dir k= ''; pw= ''; copymove= 0 /* 0 = copy; 1 = move */ parse upper arg filter if filter = '' then filter= '*' if filter = '/V' then call filter_to_video /* remove "if" to make default */ /****************************************************************************/ /* v2 file_select_init breaks off these "static" variables to preserve mode selection after caller handles an "other" key: params: fs_attr, fs_sort, fs_initpos, fs_view, fs_filter defaults: '*****', 'N', 'M', ^MUST SPECIFY ^THESE LAST TWO */ call file_select_init '', '', '', 'DTSAL', 1 /****************************************************************************/ /* customization: select Date, Time, ^ Size, Attributes, and Long form */ /* order here determines column order on screen */ anchorcol= 0 /* 0 = auto, but adjustable to display info to left of details */ call main_loop RETURN 0 /****************************************************************************/ main_loop: /* can be re-entered ONCE by special case handlers (as .zips) */ do until k = k_esc | k = k_f3 /* or F3 exit */ rv= file_select(anchorcol, glo_var, curpath, filter, curfil) /* anchor column^: DETAILS placed to LEFT; FILE NAMES placed to RIGHT */ /* input parameters: parse arg fs_scol, glo_var, curpath, fs_flspc, fs_cur */ /* returns: fs_action' '||fs_n||' '||fs_tags||' ' ||fs_path||fs_filnam(fs_n) */ n= word(rv, 2) /* index to dirlist., used several places */ if pos('D', word(dirlist.n, 4)) = 2 then is_dir = 1; else is_dir = 0 fn= substr(rv, wordindex(rv, 4), length(rv) - wordindex(rv, 4) + 1) k= word(rv, 1) /* the key code returned; see key constants above */ select /* handle "other" than basic keys for navigation and selection */ when k = k_enter & is_dir = 0 then do /* no tags, the ONE at cursor */ call start_one fn call set_current end when k = k_c_enter & is_dir = 0 then do /* provides edit / execute option */ 'START /C /F /PGM "'fn'"' /* pass intact, presumably EXECUTE (apparently */ call set_current /* always merely bails out if not executable) */ end when k = k_del & n > 2 then do /* ask, delete file */ call set_current /* to preserve path but will change curfil below */ t= 0 /* ^ save to prepare for re-entering file_select */ s= ' Delete ' if is_dir = 1 then do call info revcolr||'To delete directory, MUST TYPE UPPERCASE "Y"'||normcolr s= s||'directory' end else s= s||'this file' s= s||'? (Y) ' do until chars() > 0 t= t + 1 call syscurpos fs_sel.fs_lvl - 1, 1 /* CHEAT using file_select variable */ if t // 2 = 1 then call charout, revcolr||s||normcolr else call charout, copies(' ', 25) call syssleep 0.5 end k= ex_read_key() if k = 'Y' | k = 'y' then do if k = 'Y' & is_dir = 1 then call delete_tree fn /* directory */ else do rc= sysfiletree(fn, dl2, 'FO', '---+-', '***-*') /* clear read-only */ call sysfiledelete(fn) /* file */ end if n < dirlist.0 then n= n + 1; else n= n - 1 fn= dirlist.n curfil= substr(fn, wordindex(fn, 5), length(fn) - wordindex(fn, 5) + 1) end k= '' /* so doesn't exit if hit */ end when k = k_home then do /* mark home directory */ t= word(rv, 2) /* get index; check really is dir */ if (t > 2) & (substr(dirlist.t, wordindex(dirlist.t, 4) + 1, 1) = 'D') then do rv= dirlist.t /* only as temp var */ home_dir= filespec("drive", fn)||filespec("path", fn)||, substr(rv, wordindex(rv, 5), length(rv) - wordindex(rv, 5) + 1) end else home_dir= substr(fn, 1, lastpos('\', fn)) /* otherwise, esp floppy... */ call set_current end when k = k_ins then do /* key copies/moves file IMMEDIATELY... */ call set_current if copymove = 0 then do 'copy "'fn'" 'home_dir end else do rc= sysmoveobject(fn, home_dir) if rc = 0 then call beep 1000, 200 else do if n < dirlist.0 then n= n + 1; else n= n - 1 fn= dirlist.n curfil= substr(fn, wordindex(fn, 5), length(fn) - wordindex(fn, 5) + 1) end end end when k = k_a_c then do /* alt-c copy/move toggle */ call set_current /* must be set with EVERY key, is WHY it's duplicated! */ if copymove = 0 then do copymove= 1 end else do copymove= 0 end end when k = k_a_p then do /* set password for rars and zips, used until cleared */ call set_current call info 'Set password (just clears) >' parse pull pw end when k = k_a_v then do /* v3 filter to VIDEO types as defined in fassoc */ call set_current if filter = '*' | fs_filter = 0 then call filter_to_video /* some cheating */ else filter= '*' /* simplistic toggle */ end when k = k_tab then do /* v3 switches back and forth to set location */ call set_current if curpath= mark_orig then do curpath= mark_temp end else do mark_temp= curpath curpath= mark_orig end end when k = k_c_tab then do /* v3 ctrl- SETS bookmark */ call set_current mark_orig= curpath mark_temp= mark_orig end otherwise call set_current /* v3 change from nop eliminates mystery jumps */ end /* select */ end /* key loop */ return set_current: curpath= filespec("drive", fn)||filespec("path", fn) /* these two lines */ curfil= filespec("name", fn) /* prepare based on processed return value */ return filter_to_video: /* v3 grab filter string from first listing ".avi" */ p1= pos('*.AVI', fassoc) /* fassoc was upcased */ p2= pos(']', fassoc, p1) /* yes, this merely _assumes_ is video types */ filter= substr(fassoc, p1, p2 - p1) /* so be sure fassoc is correct */ fs_filter= 1 /* cheat with intimate knowledge to work around a "feature" */ return start_one: parse arg fn1 if lastpos('.', fn1) = 0 then do /* no extension, use tedit */ 'START /WIN /C C:\OS2\TEDIT.EXE "'||fn1'"' end else do ext= translate(substr(fn1, lastpos('.', fn1)))||' ' px= pos(ext, fassoc) if px > 0 then do if ext = '.EXE' then do /* in extension: special case! */ '"'translate(fn1)'"' /* doubled quoted name */ end /* ^ for DOS MUST be upper case (curfil needs orig fn1 though!) */ else do /* this section picks out .exe and any need params */ ws= substr(fassoc, 1, px - 1) /* chop fassoc into work string */ ws= substr(ws, 1, lastpos('[', ws) - 1) /* drops all after '[' */ lp= lastpos(']', ws) + 1 /* find the last ']' so can drop all previous */ ws= substr(ws, lp + 1, length(ws) - lp) /* .EXE with params */ if pos('.EXE', ws) > 0 then do /* executable IS specified to handle */ 'START '||ws||' "'fn1'"' /* execute, with doubled quoted name */ end else do /* call a named procedure to handle special cases (.zip + ?) */ ws= strip(word(ws, 1), 'B') interpret 'call '||ws||' "'fn1'"' /* REXX's most amazing feature */ end end end else do call alert '!!! "'ext'"does not have an association. Open with TEDIT? (y)', ' [Remains associated for session.]' do until chars() > 0 call syssleep 0.5 end k= ex_read_key() if k = 'y' | k = 'Y' then do lp= pos(']', fassoc, pos('TEDIT', fassoc)) - 1 /* v3 add ext to fassoc */ fassoc= insert(ext, fassoc, lp) 'START /C /F /PGM "C:\OS2\TEDIT.EXE" "'fn1'"' end else do call alert 'Associations are set by editing GFS.CMD...' call syssleep 1 end end end /* fix for files without extensions */ return handle_z: /* v3 because stupid Z eats .pls, have to protect them */ parse arg fn2 call protect filespec('D',fn2)||filespec('P', fn2) /* ODDLY, doesn't NEED */ 'echo *quit 1> \pipe\zmp3' /* the drive spec'd... */ 'START /C /B C:\Z28\Z.EXE "'fn2'"' return protect: /* v3 SET read-only on playlists because otherwise Z EATS them */ parse arg m if substr(m, length(m), 1) \= '\' then m= m||'\' rc= SysFileTree(m||'*.PLS', lists, 'FSO', '***-','---+') drop lists. return /************************************************************************** Handle zips files * */ handle_zip: if temp_dir <> '' then do /* passed the create-able check at start-up */ parse arg fn2 /* NOTE THAT unzipped files are only temporary! */ if pw > '' then lp= '-P'||pw; else lp= '' /* but you can go to temp_dir */ call alert 'UNZIPPING to '||temp_dir||'; returns.' call syssleep 0.5 /* to run programs or copy files */ 'mkdir 'temp_dir 'unzip "'fn2'" -d 'temp_dir' 'lp save_fn= fn /* save current */ curpath= temp_dir call main_loop /* re-enter only ONCE */ call delete_tree temp_dir /* if you haven't left a VIO logged into dir! */ k= '' /* cancel key */ fn= save_fn end return /************************************************************************** Handle ZipBOOT files * */ HANDLE_ZIPBOOT: if temp_dir <> '' then do /* passed the create-able check at start-up */ parse arg fn2 /* NOTE THAT unzipped files are only temporary! */ Call CColor CLS SAY color.green || 'Restore your Boot partition:' SAY '' SAY color.gray || 'This program restores your boot partition from the backup image ' SAY 'of your boot drive made by "ZipBoot".' SAY '' SAY 'When restoring a complete partition like this, you are advised to reformat' SAY 'the partition first. ' SAY '' SAY '' SAY 'You must enter the destination drive, example: ' || color.green || ' C:\ ' || color.gray SAY '(any data left over on that drive will be overwritten)' || color.green SAY '' pull UnzipDist SAY '' SAY color.green || 'Unzip ' || fn2 || ' -d ' || UnzipDist || color.gray SAY '' SAY color.gray || 'Is this "Unzip command" correct ???' || color.green key = SysGetKey() parse upper var key key if key <> 'Y' then EXIT SAY '' SAY '' SAY color.gray || 'Is the destination command is correct: ' || color.green || UnzipDist key = SysGetKey() parse upper var key key if key <> 'Y' then EXIT SAY '' SAY '' SAY color.red || 'THIS WILL OVER WRITE YOUR BOOT DRIVE - Continue? Y/n' || color.green key = SysGetKey() parse upper var key key if key <> 'Y' then EXIT SAY '' UnzipCmd = 'unzip.exe ' || fn2 || ' -d ' || UnzipDist UnzipCmd PAUSE EXIT 0; /************************************************************************** Handle rars files * */ handle_rar: /* special cased ONLY to handle optional passwords */ parse arg fn2 /* INHERENT BUGGISH: creates files where GFS was started! */ if pw > '' then lp= '-p'||pw; else lp= '' 'START /F /C /PGM "C:\OS2\UNRAR.EXE" x "'fn2'" 'lp return /* switch here is not specified syntax, ^ but does work... */ /************************************************************************** Handle torrent files * */ handle_torrent: /* v3 HARD-CODED FOR SIMPLICITY, requires act.exe in c:\act */ if temp_dir <> '' then do parse arg fn2 if pw > '' then lp= '-P'||pw; else lp= '' call alert 'Look at torrent info with tedit; F3 exits tedit.' call syssleep 1 'mkdir 'temp_dir fn3= substr(fn2, lastpos('\', fn2) + 1) 'start /pgm /win /n c:\act\act.exe -x "'fn2'" 1> "'temp_dir'\'fn3'.info"' /* ^ IF "start" isn't used, title of gfs window is set to fn2... HUH? */ call syssleep 2 /* to allow time for creation and close */ 'tedit "'temp_dir'\'fn3'.info"' /* in same window is more pleasing */ call delete_tree temp_dir end return /* AS ALWAYS, what seems simple turns out to be tricky... */ delete_tree: parse arg ttd /* section modified from DELTREE.CMD by Mark Polly & Carl Harding */ rc= sysfiletree(ttd||'\*.*', dl2, 'BSO', '***+*', '-**-*') /* for safety, */ rc= sysfiletree(ttd||'\*.*', dl2, 'FSO') /* clears ^ just read-only */ do x = 1 to dl2.0 rc = sysfiledelete(dl2.x) end rc=sysfiletree(ttd||'\*.*', dl2, 'DSO') do x = dl2.0 to 1 by -1 rc=sysrmdir(dl2.x) end rc=sysrmdir(ttd) drop dl2. /* end of cribbed section */ return info: parse arg nfo call syscurpos scry, 1 call charout, ansi_clreol||nfo return /* =============== End of front-end (GFS) specific section. ============== */ /* ============== ALL CODE BELOW is necessary for file_select ============ */ /* NEW v2.1 file_select_init: breaks off these "static" variables to preserve mode selection after caller handles "other" keys */ file_select_init: /* always call before first entry to file_select */ parse arg fs_attr, fs_sort, fs_initpos, fs_view, fs_filter /* defaults: '*****', 'N', 'M', ^SPECIFY ^THESE LAST TWO */ fs_ndx= 0; fs_showln= scry; fs_timr= 0 /* initialize */ fs_sort= translate(fs_sort); fs_initpos= translate(fs_initpos); fs_view= translate(fs_view); if fs_attr = '' then fs_attr= '*****' if pos(fs_sort, 'DENS') = 0 then fs_sort= 'N' /* default: sort on Name */ if pos(fs_initpos, 'HMT') = 0 then fs_initpos= 'M' /* show Middle of list */ fs_mark= '' max_lvl= 15 /* ***** ARBITRARY LIMIT OF 15 DIRECTORY LEVELS. ***** */ return file_select: parse arg fs_scol, glo_var, fs_path, fs_flspc, fs_cur fs_dtlwid= 1; /* too complex to check fs_view correctness, SO UP TO YOU */ if length(fs_view) > 0 then do fs_loop= 1 to length(fs_view) v= substr(fs_view, fs_loop, 1) /* always GET details, CHOOSE which to display */ if v= 'D' then fs_dtlwid= fs_dtlwid + 9 /* date */ if v= 'T' then fs_dtlwid= fs_dtlwid + 6 /* time */ if v= 'S' then fs_dtlwid= fs_dtlwid + 11 /* size */ if v= 'A' then fs_dtlwid= fs_dtlwid + 6 /* attributes */ if v= 'L' then fs_dtlwid= fs_dtlwid + 5 /* show Long (Y2K) form */ end if fs_scol = 0 then fs_scol = fs_dtlwid /* automatic setting */ /* end \ is crucial, ensure ALWAYS present, starting here to count fs_lvls */ if substr(fs_path, length(fs_path), 1) \= '\' then fs_path= fs_path||'\' if fs_mark = '' then fs_mark= fs_path /* init bookmark for */ fs_lvl= 0 do fs_loop= 1 to length(fs_path) if substr(fs_path, fs_loop, 1) = '\' then fs_lvl= fs_lvl + 1 end fs_ndx= get_1_directory(glo_var, fs_path, fs_flspc, fs_attr, fs_filter, 1) if fs_ndx = 2 then do /* only dots back? turn off fs_filter and try for ANY */ fs_filter= 0 fs_ndx= get_1_directory(glo_var, fs_path, fs_flspc, fs_attr, fs_filter, 1) end if fs_ndx > 0 then do /* found whatever is there... (no indent saves space) */ fs_tags= copies('ú', fs_ndx) /* prepare tag "array" */ if fs_sort <> 'N' then call fs_sort_list /* annoying when many files... */ call fs_set_sel call fs_show_new_dir do fs_loop= 0 to fs_showln /* optional-ish; helps set off from other text */ call syscurpos fs_loop, fs_scol - fs_dtlwid call charout, 'Ç' end fs_quit= 0 do while fs_quit < 1 /* begin key control */ if chars() > 0 then do fs_kd= ex_read_key() fs_timr= 0 /* goes into longer sleeps after 10 sec; reset on keypress */ fs_n= fs_ndx_ofs.fs_lvl + fs_sel.fs_lvl /* used several times */ select /* by key */ when fs_kd = k_left then call fs_exit_dir /* left arrow */ when fs_kd = k_right & fs_lvl < max_lvl & fs_n > 2 &, /* right arrow */ substr(fs_filatt(fs_n), 2, 1) = 'D' then call fs_enter_dir when fs_kd = k_up then do /* up arrow */ if fs_sel.fs_lvl > 1 then do call fs_lowlight fs_sel.fs_lvl= fs_sel.fs_lvl - 1 call fs_highlight end else do /* fs_sel.fs_lvl = 1 so scroll down */ if fs_ndx_ofs.fs_lvl > 0 then do fs_ndx_ofs.fs_lvl= fs_ndx_ofs.fs_lvl - 1 call fs_show_section end end end when fs_kd = k_down then do /* down arrow */ if fs_sel.fs_lvl <= fs_maxln - 1 then do call fs_lowlight if fs_n + 1 <= fs_ndx then fs_sel.fs_lvl= fs_sel.fs_lvl + 1 call fs_highlight /* ^ v3 bug fix changed to "fs_n + 1" */ end else do /* fs_sel.fs_lvl >= fs_maxln so scroll up */ if fs_ndx_ofs.fs_lvl < fs_ndx - fs_showln then do if fs_sel.fs_lvl < fs_ndx then fs_ndx_ofs.fs_lvl= fs_ndx_ofs.fs_lvl + 1 call fs_show_section end end end when fs_kd = k_pgup then do /* page up */ fs_ndx_ofs.fs_lvl= fs_ndx_ofs.fs_lvl - fs_showln if fs_ndx_ofs.fs_lvl < 0 then do fs_ndx_ofs.fs_lvl= 0 fs_sel.fs_lvl= 1 end call fs_show_section end when fs_kd = k_c_pgup then do /* ctrl-page up */ fs_ndx_ofs.fs_lvl= 0 fs_sel.fs_lvl= 1 call fs_show_section end when fs_kd = k_pgdn then do /* page down */ if fs_ndx > fs_showln then do if fs_n + fs_showln < fs_ndx then do fs_ndx_ofs.fs_lvl= fs_ndx_ofs.fs_lvl + fs_showln end else do fs_ndx_ofs.fs_lvl= fs_ndx - fs_showln fs_sel.fs_lvl= fs_showln end end else fs_sel.fs_lvl= fs_ndx call fs_show_section end when fs_kd = k_c_pgdn then do /* ctrl-page down */ if fs_ndx > fs_showln then do fs_ndx_ofs.fs_lvl= fs_ndx - fs_showln fs_sel.fs_lvl= fs_showln call fs_show_section end end when fs_kd > '@' & fs_kd < '[' then do /* UPPERcase A-Z, select drive */ if pos(fs_kd, sysdrivemap('A:', 'USED')) > 0 then do /* select new drive */ fs_path= fs_kd||':\' call alert 'Waiting for drive...' fs_lvl= 1 fs_filter= 0 /* cures not finding files when changing drive */ fs_ndx= get_1_directory(glo_var, fs_path, fs_flspc, fs_attr, fs_filter, 1) fs_cur= '' fs_tags= copies('ú', fs_ndx) if fs_sort <> 'N' then call fs_sort_list call fs_set_sel call fs_show_new_dir end end when fs_kd > '`' & fs_kd < '{' |, /* LOWERcase a-z, #s, find 1st char */ fs_kd > '/' & fs_kd < ':' | fs_kd = '.' then do /* OR 0-9, "." */ fs_kd= translate(fs_kd) /* oddly, must now upcase it... */ fs_s= fs_n /* start at current */ if fs_s = fs_ndx then fs_s= 1 /* to end around if starting on last */ fs_f= 0 /* flag to end around if not found */ do until fs_kd = translate(substr(word(dirlist.fs_s, 5), 1, 1)) |, fs_s > fs_ndx /* v3 checks dirs and files and steps thru each */ fs_s= fs_s + 1 if fs_f = 0 & fs_s > fs_ndx then do fs_f= 1 fs_s= 1 end end if fs_s <> fs_n & fs_s <= fs_ndx then do /* found one */ fs_cur= fs_filnam(fs_s) end if fs_kd <> translate(substr(word(dirlist.fs_s, 5), 1, 1)) then do call alert 'Name starting with "'fs_kd'" not found.' call syssleep 0.5 end call fs_set_sel call fs_show_new_dir end when fs_kd = k_a_f then do /* fs_filter toggle */ if fs_filter = 1 then fs_filter= 0; else fs_filter= 1 fs_ndx= get_1_directory(glo_var, fs_path, fs_flspc, fs_attr, fs_filter, 1) fs_tags= copies('ú', fs_ndx) if fs_sort <> 'N' then call fs_sort_list call fs_set_sel call fs_show_new_dir end when fs_kd = k_a_h | fs_kd = k_a_m | fs_kd = k_a_t then do if fs_kd = k_a_h then fs_initpos= 'H' /* uncode from alt-keys */ else if fs_kd = k_a_m then fs_initpos= 'M' else if fs_kd = k_a_t then fs_initpos= 'T' fs_cur= '' /* set off so fs_set_sel uses fs_initpos rather than finds this */ call fs_set_sel call fs_show_new_dir end when fs_kd = k_a_d | fs_kd = k_a_e | fs_kd = k_a_n | fs_kd = k_a_s then do call alert 'Sorting may take a while...' fs_sort= 'N'; call fs_sort_list; /* always sort first by name */ if fs_kd <> k_a_n then do /* results in better ordering */ if fs_kd= k_a_d then fs_sort= 'D' /* uncode sort type from alt-keys */ else if fs_kd= k_a_e then fs_sort= 'E' else if fs_kd= k_a_s then fs_sort= 'S' call fs_sort_list end call fs_show_new_dir end when fs_kd = k_c_up then do /* ctrl-up; SET tag and move up */ if fs_n > 2 then fs_tags= overlay('Û', fs_tags, fs_n) /* don't tag dot dirs */ if fs_sel.fs_lvl > 2 then do call syscurpos fs_sel.fs_lvl - 1, fs_scol call fs_show_tag(fs_n) call fs_lowlight fs_sel.fs_lvl= fs_sel.fs_lvl - 1 call fs_highlight end else do if fs_ndx_ofs.fs_lvl > 0 then do fs_ndx_ofs.fs_lvl= fs_ndx_ofs.fs_lvl - 1 call fs_show_section end end end when fs_kd = ' ' |, /* TOGGLE tag and move down */ fs_kd = k_c_dn then do /* ctrl-down; SET tag and move down */ if fs_n > 2 then do if fs_kd = ' ' & substr(fs_tags, fs_n, 1) = 'Û' then fs_tags= overlay('ú', fs_tags, fs_n) else fs_tags= overlay('Û', fs_tags, fs_n) call syscurpos fs_sel.fs_lvl - 1, fs_scol call fs_show_tag(fs_n) if fs_sel.fs_lvl <= fs_maxln - 1 then do call fs_lowlight if fs_n < fs_ndx then fs_sel.fs_lvl= fs_sel.fs_lvl + 1 call fs_highlight end else do if fs_ndx_ofs.fs_lvl < fs_ndx - fs_showln then do if fs_sel.fs_lvl < fs_ndx - 1 then fs_ndx_ofs.fs_lvl= fs_ndx_ofs.fs_lvl + 1 call fs_show_section end end end end when fs_kd = k_f1 then do /* F1 Help */ call fs_show_instructions fs_scol call fs_show_section end when fs_kd = '`' then do /* v3 if long name, show in box, wait for key */ fs_totlsiz= fs_filnam(fs_n) /* using existing free vars */ if length(fs_totlsiz) > scrx - fs_scol then do call alert 'Full name: "'||fs_totlsiz||'" Hit any key to resume.' do until chars() > 0 call syssleep 0.5 end fs_kd= ex_read_key() fs_kd= '' call fs_show_section end end when fs_kd = k_enter then do /* : if not dir (or dots), return */ if fs_n < 3 then call fs_exit_dir /* ON DOT DIRS, go up */ if fs_n > 2 & fs_lvl < max_lvl & substr(fs_filatt(fs_n), 2, 1) = 'D' then, call fs_enter_dir /* OR could do nothing */ else do fs_action= fs_kd fs_quit= 1 end end otherwise do /* RETURN on all other keys to handle in caller. */ fs_action= fs_kd fs_quit= 1 end end /* select */ end /* if charin > 0 */ else do /* without sleep keyboard poll keeps CPU BUSY */ if fs_timr < 100 then call syssleep 0.1; else call syssleep 0.5 fs_timr= fs_timr + 1 /* counter for longer sleeps after 10 sec idle */ end end /* while fs_quit */ end /* fs_ndx > 0, but may be only dot dirs... */ else do /* don't know will ever get to here... */ fs_action= 'Not_Found' fs_n= 0 fs_rv= '' end return fs_action' '||fs_n||' '||fs_tags||' ' ||fs_path||fs_filnam(fs_n) fs_fildat: /* word 1, year 2 or 4 chars depending whether 'L' in fs_view */ arg fs_ni fs_rv= word(dirlist.fs_ni, 1) if pos('L', fs_view) = 0 then fs_rv= substr(fs_rv, 3, 8) return fs_rv fs_filtim: /* word 2; colon and seconds omitted here if short form */ arg fs_ni fs_rv= word(dirlist.fs_ni, 2) if pos('L', fs_view) = 0 then fs_rv= substr(fs_rv, 1, 5) return fs_rv fs_filsiz: /* word 3 WITH leading spaces for ease in display */ arg fs_ni fs_twi= wordindex(dirlist.fs_ni, 2) + length(word(dirlist.fs_ni, 2)) + 1 return substr(dirlist.fs_ni, fs_twi, 10) /* finds end of word ^TWO */ fs_filatt: /* word 4 attributes */ arg fs_ni return word(dirlist.fs_ni, 4) fs_filnam: /* word 5 --> remainder INCLUDING spaces */ arg fs_ni fs_twi= wordindex(dirlist.fs_ni, 5) return substr(dirlist.fs_ni, fs_twi, length(dirlist.fs_ni) - fs_twi + 1) fs_ellipsis: /* shorten fs_filnam if necessary to fit available space */ arg fs_ni, fs_nw fs_twi= fs_filnam(fs_ni) if length(fs_twi) > fs_nw then fs_twi= left(fs_twi, fs_nw % 2)||'/÷/'||right(fs_twi, (fs_nw % 2) - 3) return fs_twi fs_show_section: /* displays however much of dirlist. fits screen space */ do fs_loop= 0 to scry - 1 /* sim clear screen; remove all of previous */ if length(fs_view) = 0 then call syscurpos fs_loop, fs_scol else call syscurpos fs_loop, fs_scol - fs_dtlwid + 1 call charout, ansi_clreol end fs_totlsiz= 0; fs_width= 0 /* temp counter and then to form up a string */ do fs_loop = 3 to fs_ndx if pos('D', fs_filatt(fs_loop)) = 2 then fs_width= fs_width + 1 else fs_totlsiz= fs_totlsiz + 1 end fs_width= fs_totlsiz||' files þ '||fs_width||' (+ 2) directories' fs_totlsiz= 0 /* always 2 implicit in . and .. ^ */ do fs_loop = 3 to fs_ndx fs_totlsiz= fs_totlsiz + fs_filsiz(fs_loop) end fs_loop= 0 /* 0 based for screen line */ do until fs_loop + fs_ndx_ofs.fs_lvl >= fs_ndx | fs_loop >= fs_maxln fs_n= fs_loop + fs_ndx_ofs.fs_lvl + 1 if length(fs_view) > 0 then do call syscurpos fs_loop, fs_scol - fs_dtlwid + 1 call charout, ansi_clreol do fs_a= 1 to length(fs_view) /* order in fs_view sets displayed order! */ fs_v= substr(fs_view, fs_a, 1) if fs_v= 'D' then call charout, fs_fildat(fs_n)' ' if fs_v= 'T' then call charout, fs_filtim(fs_n)' ' if fs_v= 'A' then call charout, fs_filatt(fs_n)' ' if fs_v= 'S' then call charout, fs_filsiz(fs_n)' ' end end call syscurpos fs_loop, fs_scol call charout, ansi_clreol select when fs_n = 1 then do call charout, d2c(17)||'. '||fs_width end when fs_n = 2 then do call charout, d2c(17)||'.. 'fwc(fs_totlsiz, 0, 'N')' bytes' end when fs_n > 2 then do call fs_show_tag(fs_n) call charout, fs_ellipsis(fs_n, scrx - fs_scol) end end /* select */ fs_loop= fs_loop + 1 end /* do until */ call fs_highlight return fs_show_path: /* assembles bottom line, then truncates to available space */ fs_ps= ' (F1 Help) ['||word(sysdriveinfo(substr(fs_path, 1, 2)), 4)||'] '||, fwc(word(sysdriveinfo(substr(fs_path, 1, 2)), 2), 0, 'M')||, ' þ 'fwc(word(sysdriveinfo(substr(fs_path, 1, 2)), 3), 0, 'M')||, ' '||fs_path fs_totlsiz= 0 fs_width= '' /* now to form string to show filter, fancy because important */ if length(fs_flspc) > 1 & fs_filter = 1 then do fs_width= fs_flspc if length(fs_width) > 11 then fs_width= '{'||substr(fs_flspc, 1, 11)||'...', ||'}' fs_totlsiz= length(fs_width) fs_ps= fs_ps||'_'||revcolr||fs_width fs_totlsiz= length(revcolr) end fs_width= scrx - fs_scol + fs_dtlwid - 1 if length(fs_ps) - fs_totlsiz < fs_width then do do until length(fs_ps) - fs_totlsiz >= fs_width fs_ps= insert('_', fs_ps, lastpos('\', fs_ps)) end end else fs_ps= substr(fs_ps, length(fs_ps) - fs_totlsiz - fs_width + 1, fs_width) call syscurpos scry, fs_scol - fs_dtlwid + 1 /* 0, 0 based */ call charout, fs_ps||normcolr return fs_show_new_dir: /* code needed several times */ if fs_ndx < fs_showln then fs_maxln= fs_ndx; else fs_maxln= fs_showln call fs_show_section call fs_show_path return alert: /* v3 boxed messages will be over-written by next show_new_dir */ parse arg fs_mess fs_width= scrx - fs_scol - 4 /* re-using fs_... vars known to be free */ if fs_width - 4 > length(fs_mess) then fs_width= length(fs_mess) call syscurpos scry % 2 - 1, fs_scol call charout, highcolr||'É'||copies('Í', fs_width + 2)||'»' fs_loop= 0 do until length(fs_mess) = 0 call syscurpos scry % 2 + fs_loop, fs_scol call charout, 'º '||substr(fs_mess, 1, fs_width)||' º' fs_mess= delstr(fs_mess, 1, fs_width) fs_loop= fs_loop + 1 end call syscurpos scry % 2 + fs_loop, fs_scol call charout, 'È'||copies('Í', fs_width + 2)||'¼'||normcolr return fs_exit_dir: /* for left-arrow at any time, or on a dot dir */ if fs_lvl > 1 & length(fs_path) > 3 then do /* backs up one fs_lvl */ call alert 'Waiting for directory...' if fs_lvl > 2 then do fs_loop= length(fs_path) - 1 do until substr(fs_path, fs_loop, 1) = '\' | length(fs_path) < 4 fs_loop= fs_loop - 1 end fs_loop= fs_loop + 1 end else fs_loop= 4 fs_cur= substr(fs_path, fs_loop, length(fs_path) - fs_loop) fs_loop= length(fs_path) do until substr(fs_path, fs_loop, 1) = '\' | length(fs_path) < 4 fs_loop= fs_loop - 1 end fs_path= substr(fs_path, 1, fs_loop) fs_lvl= fs_lvl - 1 /* fs_filter= 0 going up, so off likely better */ /* !!! ^ may want to comment this out for some applications... er, most? */ fs_ndx= get_1_directory(glo_var, fs_path, fs_flspc, fs_attr, fs_filter, 1) fs_tags= copies('ú', fs_ndx) if fs_sort <> 'N' then call fs_sort_list call fs_set_sel call fs_show_new_dir end return fs_enter_dir: /* for right-arrow or on a non-dot dir */ call alert 'Waiting for directory...' fs_cur= '' /* current selection always set off upon enter */ fs_path= fs_path||fs_filnam(fs_n)||'\' fs_lvl= fs_lvl + 1 fs_sel.fs_lvl= 1 fs_ndx= get_1_directory(glo_var, fs_path, fs_flspc, fs_attr, fs_filter, 1) fs_tags= copies('ú', fs_ndx) if fs_sort <> 'N' then call fs_sort_list call fs_set_sel call fs_show_new_dir return fs_highlight: /* show selected item (only the name...) in reverse color */ call syscurpos fs_sel.fs_lvl - 1, fs_scol + 1 call charout, revcolr||fs_ellipsis(fs_ndx_ofs.fs_lvl + fs_sel.fs_lvl, scrx - fs_scol)||normcolr return fs_lowlight: /* show name back in standard color */ call syscurpos fs_sel.fs_lvl - 1, fs_scol + 1 call charout, normcolr||fs_ellipsis(fs_ndx_ofs.fs_lvl + fs_sel.fs_lvl, scrx - fs_scol) return fs_show_tag: /* show tag (for dirs, simulate block w reverse color) */ arg fs_ni if substr(fs_filatt(fs_ni), 2, 1) = 'D' then do if substr(fs_tags, fs_ni, 1) = 'Û' then call charout, revcolr||d2c(16)||normcolr else call charout, d2c(16) end else call charout, substr(fs_tags, fs_ni, 1) return fs_set_sel: /* figures out what part of list to display, and item to select */ fs_n= 0 if length(fs_cur) > 0 then do /* assumes fs_cur is valid... */ fs_cs= 1 /* first search for a matching name */ do until fs_cs >= fs_ndx | pos(fs_cur, fs_filnam(fs_cs)) = 1 fs_cs= fs_cs + 1 end end else fs_cs= fs_ndx + 1 if fs_cs <= fs_ndx then do /* if name match, calc which to highlight */ if fs_cs > fs_showln then do /* split into pages */ fs_ndx_ofs.fs_lvl= fs_cs - fs_showln fs_sel.fs_lvl= fs_showln fs_n= fs_showln % 2 if fs_ndx_ofs.fs_lvl + fs_sel.fs_lvl + fs_n < fs_ndx then do fs_ndx_ofs.fs_lvl= fs_ndx_ofs.fs_lvl + fs_n fs_sel.fs_lvl= fs_sel.fs_lvl - fs_n end end else do /* less than a screenfull */ fs_ndx_ofs.fs_lvl= 0; fs_sel.fs_lvl= fs_cs; end end else do /* no name match, calc a position */ select when fs_initpos = 'H' then do /* show list from Head (top) */ if fs_lvl > 1 & fs_ndx > 2 then fs_sel.fs_lvl= 3; else fs_sel.fs_lvl= 2 fs_ndx_ofs.fs_lvl= 0 end when fs_initpos = 'M' then do /* Middle */ if fs_ndx > fs_showln then do /* more files than screen lines */ fs_sel.fs_lvl= fs_showln % 2 + 1 if (fs_ndx > 2 * fs_showln - 1) then fs_ndx_ofs.fs_lvl= fs_ndx % 2 - fs_sel.fs_lvl else fs_ndx_ofs.fs_lvl= (fs_ndx - fs_showln) % 2 end else do if fs_ndx > 2 then fs_sel.fs_lvl= fs_ndx % 2 + 2; else fs_sel.fs_lvl = 2 fs_ndx_ofs.fs_lvl= 0 end end when fs_initpos = 'T' then do /* Tail (end) */ if fs_ndx > fs_showln then do fs_sel.fs_lvl= fs_showln fs_ndx_ofs.fs_lvl= fs_ndx - fs_showln end else do fs_sel.fs_lvl= fs_ndx fs_ndx_ofs.fs_lvl= 0 end end end /* select */ end /* else of fs_cs <= fs_ndx */ return /* get_1_directory can be invoked directly: gets only ONE level, NO recursion, BUT does all multiple file spec and filtering. Can be used for multiple concurrent lists by specifying stems in glo_var SPACES in file spec's present problems, that I DODGE by not allowing, but could be added if you're ambitious by changing the delimiter of g1_flspc */ get_1_directory: parse arg glo_var, g1_path, g1_flspc, tattr, g1_filter, g1_dirs /* get JUST ONE dir in Long (Y2K) form, and re-format: 2000-09-06 12:43:00 1234567890 A---- C:\os2\SWITCHRX.CMD by removing unnecessary spaces and (known elsewhere) path to: 2000-09-06 12:43:00 1234567890 A---- SWITCHRX.CMD 1 words 2 3 4 5 --> remainder inc spaces */ drop value(glo_var) /* toss any previous list */ g1_addl= '____Date__ _Time___ ___Size___ Attrb .' rc= value(glo_var||'1', g1_addl) /* fake dot dirs for sake of convention */ g1_addl= 'yyyy-mm-dd hh:mm:ss 0 ADHRS ..' rc= value(glo_var||'2', g1_addl) /* though will use the space for info */ g1_addl= 2 /* additional, now is offset for accumulating to glo_var.0 */ if substr(g1_path, length(g1_path), 1) \= '\' then g1_path= g1_path||'\' if g1_filter = 0 then do; g1_flspc= '*'; tattr= '*****'; end; do g1_nspec= 0 to words(g1_flspc) /* space delim'd, so NO OTHER spaces */ g1_ts.0= 0 if g1_nspec > 0 then do rc= SysFileTree(g1_path||word(g1_flspc, g1_nspec), 'g1_ts', 'FTL', tattr) end else do /* check get dirs */ if g1_dirs = 1 then rc= SysFileTree(g1_path||'*', 'g1_ts', 'DTL', tattr) end if g1_ts.0 > 0 then do do g1_n= 1 to g1_ts.0 g1_ts.g1_n= delstr(g1_ts.g1_n, wordindex(g1_ts.g1_n, 3) - 1, 1) g1_ts.g1_n= delstr(g1_ts.g1_n, wordindex(g1_ts.g1_n, 4) - 1, 1) g1_ts.g1_n= delstr(g1_ts.g1_n, wordindex(g1_ts.g1_n, 5) - 1, 1) g1_p= pos(':\', g1_ts.g1_n) - 1 g1_ts.g1_n= delstr(g1_ts.g1_n, g1_p, lastpos('\', g1_ts.g1_n) - g1_p + 1) /* strip out path */ g1_l= g1_n + g1_addl /* arithmetic */ g1_p= value(glo_var||g1_l, g1_ts.g1_n) /* SET (global) glo_var.[g1_n + g1_addl] TO g1_ts.g1_n */ end end g1_addl= g1_addl + g1_ts.0 /* sum # in current list plus all previous */ g1_p= value(glo_var||'0', g1_addl) /* set the number of elements */ end drop g1_ts. return g1_addl /* becomes fs_ndx, # of entries found */ fs_sort_list: /* Don't quibble that it's a slow primitive bubble sort; */ fs_ns= fs_ndx /* makes for easy coding to sort on varied fields. */ /* call alert 'Sorting...' hmm... quite a delay with >300 entries... */ if fs_ns > 3 then do if substr(fs_filnam(2), 2, 1) = '.' then fs_head= 3; else fs_head= 1 fs_head= 3 do while substr(fs_filatt(fs_head), 2, 1) = 'D' /* KEEP DIRS FIRST */ fs_head= fs_head + 1 end if fs_head >= fs_ns then return /* until loop in REXX differs from TP! */ do until fs_head >= fs_ns fs_cnt= fs_head + 1 do until fs_cnt > fs_ns select /* get which field: Date, Extension, Name, or Size */ when fs_sort = 'D' then do fs_v1= word(dirlist.fs_cnt, 1)||word(dirlist.fs_cnt, 2) fs_v2= word(dirlist.fs_head, 1)||word(dirlist.fs_head, 2) end when fs_sort = 'E' then do /* Simplistic. Scrambles re full name. */ parse upper var dirlist.fs_cnt with dummy '.' fs_v1 parse upper var dirlist.fs_head with dummy '.' fs_v2 end when fs_sort = 'N' then do fs_twi= wordindex(dirlist.fs_cnt, 5) fs_v1= substr(dirlist.fs_cnt, fs_twi, length(dirlist.fs_cnt) - fs_twi + 1) fs_twi= wordindex(dirlist.fs_head, 5) fs_v2= substr(dirlist.fs_head, fs_twi, length(dirlist.fs_head) - fs_twi + 1) end when fs_sort = 'S' then do fs_v1= word(dirlist.fs_cnt, 3) fs_v2= word(dirlist.fs_head, 3) end end /* select */ if fs_v1 < fs_v2 then do /* compare and swap */ fs_twi= dirlist.fs_cnt dirlist.fs_cnt= dirlist.fs_head dirlist.fs_head= fs_twi end fs_cnt= fs_cnt + 1 end fs_head= fs_head + 1 end end return fs_show_instructions: procedure expose revcolr normcolr /* custom for GFS */ arg ix if ix > 40 then ix= 40 /* caller handles all screen clean-up, heh */ call charout, revcolr iy= 1 call say_inc 'ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÑÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»' call say_inc 'º arrows: ³ ALT-keys: º' call say_inc 'º 'd2c(30)' up ³ Copy/move modeº' call say_inc 'º 'd2c(31)' down ³ Filter toggle º' call say_inc 'º 'd2c(16)' into directory ³ Password set º' call say_inc 'º 'd2c(17)' out of directory ³ Video filter º' call say_inc 'º ³ sort by: º' call say_inc 'º or F3: exit ³ Date/time º' call say_inc 'º launch by ³ Extension º' call say_inc 'º association ³ Name º' call say_inc 'º will ³ Size º' call say_inc 'º attempt to execute ³ display from: º' call say_inc 'º ³ Head º' call say_inc 'º A-Z: select drive ³ Middle º' call say_inc 'º a-z, 0-9: jump 1st ³ Tail º' call say_inc 'º `: show long name ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄĶ' call say_inc 'º sets destination directory º' call say_inc 'º copies or moves to "home" º' call say_inc 'º file (y) or directory (Y) º' call say_inc 'º [CTRL-] bookmark, set / switch º' call say_inc 'ÇÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄĶ' call say_inc 'º DGDs Generalized File Selector v3 º' call say_inc 'ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ' kd= 0 iy= 1 do while chars() = 0 if kd // 5 = 0 then do call syscurpos iy, ix + 5; call charout, ' Hit any key ' end else do call syscurpos iy, ix + 5; call charout, 'ÍÍÍÍÍÍÍÍÍÍÍÍÍ' end call syssleep 0.5 kd= kd + 1 end kd= ex_read_key() kd= '' call charout, normcolr return say_inc: parse arg it call syscurpos iy, ix call charout, it iy= iy + 1 return fwc: procedure /* format a number with commas; scale = Normal, Kilo-, Mega- */ arg ns, len, scale /* ns = number, len = desired length padded; 0 = none */ nf= '' scale= translate(scale) if scale <> 'K' & scale <> 'M' then scale= '' /* otherwise default */ if scale = 'K' then ns= format(ns / 1024, , 0) /* no padding, no decimal */ if scale = 'M' then ns= format(ns / 1048576, , 0) do p= length(ns) to 4 by -3 nf= ','||substr(ns, p - 2, 3)||nf end if p > 0 then nf= substr(ns, 1, p)||nf nf= nf||scale if len > 0 then nf= copies(' ', len - length(nf) - length(scale))||nf return nf ex_read_key: /* returns two bytes for extended codes */ xrkey= sysgetkey('noecho') if xrkey = d2c(0) | xrkey = d2c(224) then xrkey= xrkey||sysgetkey('noecho') return xrkey constants: /* initialization */ zky= d2c(0); xky= d2c(224) /* prefixes for extended keys */ k_esc= x2c('1b'); k_enter= x2c('0d'); k_bksp= d2c(8); k_tab= d2c(9) k_up= 'àH'; k_down= 'àP'; k_left= 'àK'; k_right= 'àM' k_ins= 'àR'; k_del= 'àS'; k_home= 'àG'; k_end= 'àO' k_pgup= 'àI'; k_pgdn= 'àQ' /* control keys */ k_c_left= 'às'; k_c_right= 'àt'; k_c_up= 'à'||d2c(141); k_c_dn= 'à'||d2c(145) k_c_pgup= 'à'||d2c(132); k_c_pgdn= 'àv'; k_c_enter= d2c(10) k_c_bksp= d2c(127); k_c_tab=zky||d2c(148) /* alt keys */ k_a_left= zky||d2c(155); k_a_right= zky||d2c(157) k_a_up= zky||d2c(152); k_a_dn= zky||d2c(160) k_a_enter= zky||d2c(28) k_a_a= zky||d2c(30); k_a_b= zky||d2c(48); k_a_c= zky||d2c(46) k_a_d= zky||d2c(32); k_a_e= zky||d2c(18); k_a_f= zky||d2c(33) k_a_g= zky||d2c(34); k_a_h= zky||d2c(35); k_a_i= zky||d2c(23) k_a_j= zky||d2c(36); k_a_k= zky||d2c(37); k_a_l= zky||d2c(38) k_a_m= zky||d2c(50); k_a_n= zky||d2c(49); k_a_o= zky||d2c(24) k_a_p= zky||d2c(25); k_a_q= zky||d2c(16); k_a_r= zky||d2c(19) k_a_s= zky||d2c(31); k_a_t= zky||d2c(20); k_a_u= zky||d2c(22) k_a_v= zky||d2c(47); k_a_w= zky||d2c(17); k_a_x= zky||d2c(45) k_a_y= zky||d2c(21); k_a_z= zky||d2c(44) /* function keys; only F1 (Help) used in file_select */ k_f1= zky||';'; k_f2= zky||'<'; k_f3= zky||'='; k_f4= zky||'>' k_f5= zky||'?'; k_f6= zky||'@'; k_f7= zky||'A'; k_f8= zky||'B' k_f9= zky||'C'; k_f10= zky||'D'; k_f11= zky||d2c(133); k_f12= zky||d2c(134) /* text screen colors: used for highlighting */ black= 0; red= 1; green= 2; yellow= 3; blue= 4; magenta= 5; cyan= 6; white= 7; fgnd = 30 /* add color: 30 + 2 = 32 ==> green foreground */ bgnd = 40 /* add color: 40 + 7 = 47 ==> white background */ AEsc= '1B'x||'[' /* define ANSI-ESCape; + 0 = low, 1 = high int*/ normcolr= AEsc||'0;'||fgnd + white||';'||bgnd + black||'m' /* normal */ highcolr= AEsc||'1;'||fgnd + white||';'||bgnd + black||'m' /* bright */ revcolr= AEsc||'0;'||fgnd + black||';'||bgnd + white||'m' /* reversed */ ansi_clreol= AEsc||'K' return RETURN GFS2: /* GFS Generalized File Selector front-end by DGD v3 (mod'd from LD4) */ /* Keyboarding will always beat mousing around! Uses Classic REXX (+ RexxUtil) only. Freeware, but only for OS/2 - ECS. Installation: place this in \OS2, and perhaps edit associations or paths below. SHOULD pick a place for temporary files below, preferably RAMFS. -- ENSURE that any editor used DOES NOT wrap lines! MOST applications will open in foreground; add "/B" into fassoc by the the appropriate executable to open in background. Also, for TEDIT, "/WIN" opens up another VIO, but you may prefer it in the existing window... Automatic adjustment to VIO rows, columns: "mode 100, 40" works nicely. Unfortunately, no known way to maximize window with just Classic REXX. Can now give filter parameter(s) on command line, any number of patterns separated by spaces. To filter just video types, new "/v" switch. Commands implemented: þ or F3 exits þ F1 brings up abbreviated help þ up and down arrow keys move highlight þ left and right arrow keys move into and out of directories þ page-up and page-down do as they're named þ UPPERcase A-Z select drive þ lowercase a-z or 0-9 jumps to next file or dir starting with character þ launches executable associated with file extension (also, when on directory same as right arrow) - .EXEs are run (can be either dangerous or useless without parameters!) - TEXT files -- OR files without an extension -- are passed to TEDIT - .ZIPs are unzipped (requires UNZIP.EXE) to temporary directory (which needs to be specified for your system); also, RAMFS is suggested - .RARs are unpacked to the directory GFS was started in (semi-bug) - video files are opened by MPlayer -- assuming the .exe is in c:\mplayer - music files are sent to Z (opening in background), pre-empting current - .PDFs are opened by GhostView, assuming path is set right - for unassociated file types asks whether to open with TEDIT answering yes adds that extension into list for the session þ attempts to execute, any file þ sets a directory to move files to, useful for sorting into categories þ copies or moves highlighted file to "home" directory þ toggles between copy and move action for þ deletes file or directory (uppercase "Y" required!) READ-ONLY ATTRIBUTES ARE NO OBSTACLE! But System and Hidden still protect. þ sets passwords for RARs and ZIPs þ toggles filter for video files types (as defined in fassoc var) þ switches back and forth between current and a previously set directory þ ctrl- sets the fixed directory */ /* Call SysCurState 'OFF' */ call syscls call constants /* moved to end to un-clutter */ /* semi-CONSTANT */ parse value systextscreensize() with scry scrx scry= scry - 1; scrx= scrx - 1; /* adj to 0, 0 based values */ numeric digits 12 /* necessary to display bytes of gigabytes */ glo_var= 'dirlist.' /* ============== ALL CODE ABOVE is necessary for file_select ============= */ /* ================== Begin FRONT-END SPECIFIC section. =================== */ /* EDIT / ADD ASSOCIATIONS BELOW AS SPECIFIC TO YOUR SYSTEM values before executable go with 'start' command; see > help start .EXE files are all a special case and are invoked .ZIP files require UNZIP.EXE in PATH, and UNZIP32.DLL in LIBPATH commas chain all to 1 string, automagically adds space after ']' */ fassoc= ']', /* dummy ] to avoid anomaly in retrieving first substring */ '/WIN /C C:\OS2\TEDIT.EXE [*.sys *.txt *.pas *.doc *.cmd *.bat *.log *.os2', '*.c *.h *.cpp *.diz *.me *.1st]', /* and files w/o extension */ 'C:\FIREFOX\FIREFOX.EXE [*.htm *.html *.shtml *.asp *.aspx *.php]', 'C:\OS2\VIEW.EXE [*.inf]', 'C:\PMVIEW\PMVIEW.EXE [*.bmp *.jpg *.gif *.png *.tiff]', /* many others... */ 'C:\GS\GSVIEW2\GVPM.EXE [*.pdf]', '/PM C:\MPLAYER\MPLAYER.EXE -really-quiet -fs', /* FULL SCREEN ON */ '[*.avi *.wmv *.mpg *.mpeg *.mov *.flv *.rm *.ram *.rmvb *.m4v *.asf', '*.mp4 *.divx *.vob *.mkv]', /* may be yet others */ '/PM C:\WARPIN\WARPIN.EXE [*.wpi]', 'HANDLE_RAR [*.rar]', /* special case to use optional passwords */ 'HANDLE_TORRENT [*.torrent]', /* only for looking at info... THOUGH would be easy to start ACT running too... */ 'HANDLE_ZIP [*.zip]', /* EXTRA SPECIAL CASE expanded in temporary dir... */ 'HANDLE_Z [*.mp3 *.wav *.m3u *.pls]' /* because stupid Z EATS playlists */ /* ^^^ if no '.EXE' here, calls the procedure of that name */ fassoc= translate(fassoc) /* lower case up there just for readibility */ do t= lastpos(']', fassoc) to 2 by - 1 /* insert a space before each "]" */ if substr(fassoc, t, 1) = ']' then fassoc= insert(' ', fassoc, t - 1) end /* so can ensure 1 and 2 char extensions don't match as part of longer */ /**************************************************************************** PATH Statements * */ curpath= NewPath || '\Backups\Local\ZipBoot' /* case of started in dir */ curfil= '' home_dir= NewPath || '\Backups' /* set HOME DIR, can set to preference */ mark_orig= home_dir; /* v3 three lines to FIX operation from start */ if length(mark_orig) > 3 then mark_orig= mark_orig||'\' /* grrr... */ mark_temp= home_dir /* ^^^ missing slash again a nuisance */ /**************************************************************************** PICK ONE of three places for temp_dir, PREFERABLY a RAMDRIVE. */ temp_dir= directory() /* in whatever directory started in */ /* temp_dir= value('TMP',,'OS2ENVIRONMENT') */ /* usually \tcpip\tmp */ /* temp_dir= 'R:' ramdrive in my system */ temp_dir= temp_dir||'\_G_F_S_T' /* unzip directory, created and erased */ 'mkdir 'temp_dir /* creating TEMP DIR */ rc= sysfiletree(temp_dir, dirlist, 'D') if dirlist.0 = 0 then do say " !!! Can't create"temp_dir" -- Unzipping disabled." temp_dir= '' end else 'rmdir 'temp_dir k= ''; pw= ''; copymove= 0 /* 0 = copy; 1 = move */ parse upper arg filter if filter = '' then filter= '*' if filter = '/V' then call filter_to_video /* remove "if" to make default */ /****************************************************************************/ /* v2 file_select_init breaks off these "static" variables to preserve mode selection after caller handles an "other" key: params: fs_attr, fs_sort, fs_initpos, fs_view, fs_filter defaults: '*****', 'N', 'M', ^MUST SPECIFY ^THESE LAST TWO */ call file_select_init '', '', '', 'DTSAL', 1 /****************************************************************************/ /* customization: select Date, Time, ^ Size, Attributes, and Long form */ /* order here determines column order on screen */ anchorcol= 0 /* 0 = auto, but adjustable to display info to left of details */ call main_loop RETURN 0 /****************************************************************************/ main_loop: /* can be re-entered ONCE by special case handlers (as .zips) */ do until k = k_esc | k = k_f3 /* or F3 exit */ rv= file_select(anchorcol, glo_var, curpath, filter, curfil) /* anchor column^: DETAILS placed to LEFT; FILE NAMES placed to RIGHT */ /* input parameters: parse arg fs_scol, glo_var, curpath, fs_flspc, fs_cur */ /* returns: fs_action' '||fs_n||' '||fs_tags||' ' ||fs_path||fs_filnam(fs_n) */ n= word(rv, 2) /* index to dirlist., used several places */ if pos('D', word(dirlist.n, 4)) = 2 then is_dir = 1; else is_dir = 0 fn= substr(rv, wordindex(rv, 4), length(rv) - wordindex(rv, 4) + 1) k= word(rv, 1) /* the key code returned; see key constants above */ select /* handle "other" than basic keys for navigation and selection */ when k = k_enter & is_dir = 0 then do /* no tags, the ONE at cursor */ call start_one fn call set_current end when k = k_c_enter & is_dir = 0 then do /* provides edit / execute option */ 'START /C /F /PGM "'fn'"' /* pass intact, presumably EXECUTE (apparently */ call set_current /* always merely bails out if not executable) */ end when k = k_del & n > 2 then do /* ask, delete file */ call set_current /* to preserve path but will change curfil below */ t= 0 /* ^ save to prepare for re-entering file_select */ s= ' Delete ' if is_dir = 1 then do call info revcolr||'To delete directory, MUST TYPE UPPERCASE "Y"'||normcolr s= s||'directory' end else s= s||'this file' s= s||'? (Y) ' do until chars() > 0 t= t + 1 call syscurpos fs_sel.fs_lvl - 1, 1 /* CHEAT using file_select variable */ if t // 2 = 1 then call charout, revcolr||s||normcolr else call charout, copies(' ', 25) call syssleep 0.5 end k= ex_read_key() if k = 'Y' | k = 'y' then do if k = 'Y' & is_dir = 1 then call delete_tree fn /* directory */ else do rc= sysfiletree(fn, dl2, 'FO', '---+-', '***-*') /* clear read-only */ call sysfiledelete(fn) /* file */ end if n < dirlist.0 then n= n + 1; else n= n - 1 fn= dirlist.n curfil= substr(fn, wordindex(fn, 5), length(fn) - wordindex(fn, 5) + 1) end k= '' /* so doesn't exit if hit */ end when k = k_home then do /* mark home directory */ t= word(rv, 2) /* get index; check really is dir */ if (t > 2) & (substr(dirlist.t, wordindex(dirlist.t, 4) + 1, 1) = 'D') then do rv= dirlist.t /* only as temp var */ home_dir= filespec("drive", fn)||filespec("path", fn)||, substr(rv, wordindex(rv, 5), length(rv) - wordindex(rv, 5) + 1) end else home_dir= substr(fn, 1, lastpos('\', fn)) /* otherwise, esp floppy... */ call set_current end when k = k_ins then do /* key copies/moves file IMMEDIATELY... */ call set_current if copymove = 0 then do 'copy "'fn'" 'home_dir end else do rc= sysmoveobject(fn, home_dir) if rc = 0 then call beep 1000, 200 else do if n < dirlist.0 then n= n + 1; else n= n - 1 fn= dirlist.n curfil= substr(fn, wordindex(fn, 5), length(fn) - wordindex(fn, 5) + 1) end end end when k = k_a_c then do /* alt-c copy/move toggle */ call set_current /* must be set with EVERY key, is WHY it's duplicated! */ if copymove = 0 then do copymove= 1 end else do copymove= 0 end end when k = k_a_p then do /* set password for rars and zips, used until cleared */ call set_current call info 'Set password (just clears) >' parse pull pw end when k = k_a_v then do /* v3 filter to VIDEO types as defined in fassoc */ call set_current if filter = '*' | fs_filter = 0 then call filter_to_video /* some cheating */ else filter= '*' /* simplistic toggle */ end when k = k_tab then do /* v3 switches back and forth to set location */ call set_current if curpath= mark_orig then do curpath= mark_temp end else do mark_temp= curpath curpath= mark_orig end end when k = k_c_tab then do /* v3 ctrl- SETS bookmark */ call set_current mark_orig= curpath mark_temp= mark_orig end otherwise call set_current /* v3 change from nop eliminates mystery jumps */ end /* select */ end /* key loop */ return set_current: curpath= filespec("drive", fn)||filespec("path", fn) /* these two lines */ curfil= filespec("name", fn) /* prepare based on processed return value */ return filter_to_video: /* v3 grab filter string from first listing ".avi" */ p1= pos('*.AVI', fassoc) /* fassoc was upcased */ p2= pos(']', fassoc, p1) /* yes, this merely _assumes_ is video types */ filter= substr(fassoc, p1, p2 - p1) /* so be sure fassoc is correct */ fs_filter= 1 /* cheat with intimate knowledge to work around a "feature" */ return start_one: parse arg fn1 if lastpos('.', fn1) = 0 then do /* no extension, use tedit */ 'START /WIN /C C:\OS2\TEDIT.EXE "'||fn1'"' end else do ext= translate(substr(fn1, lastpos('.', fn1)))||' ' px= pos(ext, fassoc) if px > 0 then do if ext = '.EXE' then do /* in extension: special case! */ '"'translate(fn1)'"' /* doubled quoted name */ end /* ^ for DOS MUST be upper case (curfil needs orig fn1 though!) */ else do /* this section picks out .exe and any need params */ ws= substr(fassoc, 1, px - 1) /* chop fassoc into work string */ ws= substr(ws, 1, lastpos('[', ws) - 1) /* drops all after '[' */ lp= lastpos(']', ws) + 1 /* find the last ']' so can drop all previous */ ws= substr(ws, lp + 1, length(ws) - lp) /* .EXE with params */ if pos('.EXE', ws) > 0 then do /* executable IS specified to handle */ 'START '||ws||' "'fn1'"' /* execute, with doubled quoted name */ end else do /* call a named procedure to handle special cases (.zip + ?) */ ws= strip(word(ws, 1), 'B') interpret 'call '||ws||' "'fn1'"' /* REXX's most amazing feature */ end end end else do call alert '!!! "'ext'"does not have an association. Open with TEDIT? (y)', ' [Remains associated for session.]' do until chars() > 0 call syssleep 0.5 end k= ex_read_key() if k = 'y' | k = 'Y' then do lp= pos(']', fassoc, pos('TEDIT', fassoc)) - 1 /* v3 add ext to fassoc */ fassoc= insert(ext, fassoc, lp) 'START /C /F /PGM "C:\OS2\TEDIT.EXE" "'fn1'"' end else do call alert 'Associations are set by editing GFS.CMD...' call syssleep 1 end end end /* fix for files without extensions */ return handle_z: /* v3 because stupid Z eats .pls, have to protect them */ parse arg fn2 call protect filespec('D',fn2)||filespec('P', fn2) /* ODDLY, doesn't NEED */ 'echo *quit 1> \pipe\zmp3' /* the drive spec'd... */ 'START /C /B C:\Z28\Z.EXE "'fn2'"' return protect: /* v3 SET read-only on playlists because otherwise Z EATS them */ parse arg m if substr(m, length(m), 1) \= '\' then m= m||'\' rc= SysFileTree(m||'*.PLS', lists, 'FSO', '***-','---+') drop lists. return /************************************************************************** Handle zips files * */ handle_zip: if temp_dir <> '' then do /* passed the create-able check at start-up */ parse arg fn2 /* NOTE THAT unzipped files are only temporary! */ if pw > '' then lp= '-P'||pw; else lp= '' /* but you can go to temp_dir */ call alert 'UNZIPPING to '||temp_dir||'; returns.' call syssleep 0.5 /* to run programs or copy files */ 'mkdir 'temp_dir 'unzip "'fn2'" -d 'temp_dir' 'lp save_fn= fn /* save current */ curpath= temp_dir call main_loop /* re-enter only ONCE */ call delete_tree temp_dir /* if you haven't left a VIO logged into dir! */ k= '' /* cancel key */ fn= save_fn end return /************************************************************************** Handle ZipBOOT files * */ HANDLE_ZIPBOOT: if temp_dir <> '' then do /* passed the create-able check at start-up */ parse arg fn2 /* NOTE THAT unzipped files are only temporary! */ Call CColor CLS SAY color.green || 'Restore your Boot partition:' SAY '' SAY color.gray || 'This program restores your boot partition from the backup image ' SAY 'of your boot drive made by "ZipBoot".' SAY '' SAY 'When restoring a complete partition like this, you are advised to reformat' SAY 'the partition first. Also, a ' || color.green || 'SYSINSTX ' || color.gray ||, 'should executed after the drive is' SAY 'restored.' SAY '' SAY 'You must enter the destination drive, example: ' || color.green || ' C:\ ' || color.gray SAY '(any data left over on that drive will be overwritten)' || color.green SAY '' pull UnzipDist SAY '' SAY color.green || 'Unzip ' || fn2 || ' -d ' || UnzipDist || color.gray SAY '' SAY color.gray || 'Is this "Unzip command" correct ???' || color.green key = SysGetKey() parse upper var key key if key <> 'Y' then EXIT SAY '' SAY '' SAY color.gray || 'Is the destination command is correct: ' || color.green || UnzipDist key = SysGetKey() parse upper var key key if key <> 'Y' then EXIT SAY '' SAY '' SAY color.red || 'THIS WILL OVER WRITE YOUR BOOT DRIVE - Continue? Y/n' || color.green key = SysGetKey() parse upper var key key if key <> 'Y' then EXIT SAY '' UnzipCmd = 'unzip.exe ' || fn2 || ' -d ' || UnzipDist UnzipCmd PAUSE EXIT 0; /************************************************************************** Handle rars files * */ handle_rar: /* special cased ONLY to handle optional passwords */ parse arg fn2 /* INHERENT BUGGISH: creates files where GFS was started! */ if pw > '' then lp= '-p'||pw; else lp= '' 'START /F /C /PGM "C:\OS2\UNRAR.EXE" x "'fn2'" 'lp return /* switch here is not specified syntax, ^ but does work... */ /************************************************************************** Handle torrent files * */ handle_torrent: /* v3 HARD-CODED FOR SIMPLICITY, requires act.exe in c:\act */ if temp_dir <> '' then do parse arg fn2 if pw > '' then lp= '-P'||pw; else lp= '' call alert 'Look at torrent info with tedit; F3 exits tedit.' call syssleep 1 'mkdir 'temp_dir fn3= substr(fn2, lastpos('\', fn2) + 1) 'start /pgm /win /n c:\act\act.exe -x "'fn2'" 1> "'temp_dir'\'fn3'.info"' /* ^ IF "start" isn't used, title of gfs window is set to fn2... HUH? */ call syssleep 2 /* to allow time for creation and close */ 'tedit "'temp_dir'\'fn3'.info"' /* in same window is more pleasing */ call delete_tree temp_dir end return /* AS ALWAYS, what seems simple turns out to be tricky... */ delete_tree: parse arg ttd /* section modified from DELTREE.CMD by Mark Polly & Carl Harding */ rc= sysfiletree(ttd||'\*.*', dl2, 'BSO', '***+*', '-**-*') /* for safety, */ rc= sysfiletree(ttd||'\*.*', dl2, 'FSO') /* clears ^ just read-only */ do x = 1 to dl2.0 rc = sysfiledelete(dl2.x) end rc=sysfiletree(ttd||'\*.*', dl2, 'DSO') do x = dl2.0 to 1 by -1 rc=sysrmdir(dl2.x) end rc=sysrmdir(ttd) drop dl2. /* end of cribbed section */ return info: parse arg nfo call syscurpos scry, 1 call charout, ansi_clreol||nfo return /* =============== End of front-end (GFS) specific section. ============== */ /* ============== ALL CODE BELOW is necessary for file_select ============ */ /* NEW v2.1 file_select_init: breaks off these "static" variables to preserve mode selection after caller handles "other" keys */ file_select_init: /* always call before first entry to file_select */ parse arg fs_attr, fs_sort, fs_initpos, fs_view, fs_filter /* defaults: '*****', 'N', 'M', ^SPECIFY ^THESE LAST TWO */ fs_ndx= 0; fs_showln= scry; fs_timr= 0 /* initialize */ fs_sort= translate(fs_sort); fs_initpos= translate(fs_initpos); fs_view= translate(fs_view); if fs_attr = '' then fs_attr= '*****' if pos(fs_sort, 'DENS') = 0 then fs_sort= 'N' /* default: sort on Name */ if pos(fs_initpos, 'HMT') = 0 then fs_initpos= 'M' /* show Middle of list */ fs_mark= '' max_lvl= 15 /* ***** ARBITRARY LIMIT OF 15 DIRECTORY LEVELS. ***** */ return file_select: parse arg fs_scol, glo_var, fs_path, fs_flspc, fs_cur fs_dtlwid= 1; /* too complex to check fs_view correctness, SO UP TO YOU */ if length(fs_view) > 0 then do fs_loop= 1 to length(fs_view) v= substr(fs_view, fs_loop, 1) /* always GET details, CHOOSE which to display */ if v= 'D' then fs_dtlwid= fs_dtlwid + 9 /* date */ if v= 'T' then fs_dtlwid= fs_dtlwid + 6 /* time */ if v= 'S' then fs_dtlwid= fs_dtlwid + 11 /* size */ if v= 'A' then fs_dtlwid= fs_dtlwid + 6 /* attributes */ if v= 'L' then fs_dtlwid= fs_dtlwid + 5 /* show Long (Y2K) form */ end if fs_scol = 0 then fs_scol = fs_dtlwid /* automatic setting */ /* end \ is crucial, ensure ALWAYS present, starting here to count fs_lvls */ if substr(fs_path, length(fs_path), 1) \= '\' then fs_path= fs_path||'\' if fs_mark = '' then fs_mark= fs_path /* init bookmark for */ fs_lvl= 0 do fs_loop= 1 to length(fs_path) if substr(fs_path, fs_loop, 1) = '\' then fs_lvl= fs_lvl + 1 end fs_ndx= get_1_directory(glo_var, fs_path, fs_flspc, fs_attr, fs_filter, 1) if fs_ndx = 2 then do /* only dots back? turn off fs_filter and try for ANY */ fs_filter= 0 fs_ndx= get_1_directory(glo_var, fs_path, fs_flspc, fs_attr, fs_filter, 1) end if fs_ndx > 0 then do /* found whatever is there... (no indent saves space) */ fs_tags= copies('ú', fs_ndx) /* prepare tag "array" */ if fs_sort <> 'N' then call fs_sort_list /* annoying when many files... */ call fs_set_sel call fs_show_new_dir do fs_loop= 0 to fs_showln /* optional-ish; helps set off from other text */ call syscurpos fs_loop, fs_scol - fs_dtlwid call charout, 'Ç' end fs_quit= 0 do while fs_quit < 1 /* begin key control */ if chars() > 0 then do fs_kd= ex_read_key() fs_timr= 0 /* goes into longer sleeps after 10 sec; reset on keypress */ fs_n= fs_ndx_ofs.fs_lvl + fs_sel.fs_lvl /* used several times */ select /* by key */ when fs_kd = k_left then call fs_exit_dir /* left arrow */ when fs_kd = k_right & fs_lvl < max_lvl & fs_n > 2 &, /* right arrow */ substr(fs_filatt(fs_n), 2, 1) = 'D' then call fs_enter_dir when fs_kd = k_up then do /* up arrow */ if fs_sel.fs_lvl > 1 then do call fs_lowlight fs_sel.fs_lvl= fs_sel.fs_lvl - 1 call fs_highlight end else do /* fs_sel.fs_lvl = 1 so scroll down */ if fs_ndx_ofs.fs_lvl > 0 then do fs_ndx_ofs.fs_lvl= fs_ndx_ofs.fs_lvl - 1 call fs_show_section end end end when fs_kd = k_down then do /* down arrow */ if fs_sel.fs_lvl <= fs_maxln - 1 then do call fs_lowlight if fs_n + 1 <= fs_ndx then fs_sel.fs_lvl= fs_sel.fs_lvl + 1 call fs_highlight /* ^ v3 bug fix changed to "fs_n + 1" */ end else do /* fs_sel.fs_lvl >= fs_maxln so scroll up */ if fs_ndx_ofs.fs_lvl < fs_ndx - fs_showln then do if fs_sel.fs_lvl < fs_ndx then fs_ndx_ofs.fs_lvl= fs_ndx_ofs.fs_lvl + 1 call fs_show_section end end end when fs_kd = k_pgup then do /* page up */ fs_ndx_ofs.fs_lvl= fs_ndx_ofs.fs_lvl - fs_showln if fs_ndx_ofs.fs_lvl < 0 then do fs_ndx_ofs.fs_lvl= 0 fs_sel.fs_lvl= 1 end call fs_show_section end when fs_kd = k_c_pgup then do /* ctrl-page up */ fs_ndx_ofs.fs_lvl= 0 fs_sel.fs_lvl= 1 call fs_show_section end when fs_kd = k_pgdn then do /* page down */ if fs_ndx > fs_showln then do if fs_n + fs_showln < fs_ndx then do fs_ndx_ofs.fs_lvl= fs_ndx_ofs.fs_lvl + fs_showln end else do fs_ndx_ofs.fs_lvl= fs_ndx - fs_showln fs_sel.fs_lvl= fs_showln end end else fs_sel.fs_lvl= fs_ndx call fs_show_section end when fs_kd = k_c_pgdn then do /* ctrl-page down */ if fs_ndx > fs_showln then do fs_ndx_ofs.fs_lvl= fs_ndx - fs_showln fs_sel.fs_lvl= fs_showln call fs_show_section end end when fs_kd > '@' & fs_kd < '[' then do /* UPPERcase A-Z, select drive */ if pos(fs_kd, sysdrivemap('A:', 'USED')) > 0 then do /* select new drive */ fs_path= fs_kd||':\' call alert 'Waiting for drive...' fs_lvl= 1 fs_filter= 0 /* cures not finding files when changing drive */ fs_ndx= get_1_directory(glo_var, fs_path, fs_flspc, fs_attr, fs_filter, 1) fs_cur= '' fs_tags= copies('ú', fs_ndx) if fs_sort <> 'N' then call fs_sort_list call fs_set_sel call fs_show_new_dir end end when fs_kd > '`' & fs_kd < '{' |, /* LOWERcase a-z, #s, find 1st char */ fs_kd > '/' & fs_kd < ':' | fs_kd = '.' then do /* OR 0-9, "." */ fs_kd= translate(fs_kd) /* oddly, must now upcase it... */ fs_s= fs_n /* start at current */ if fs_s = fs_ndx then fs_s= 1 /* to end around if starting on last */ fs_f= 0 /* flag to end around if not found */ do until fs_kd = translate(substr(word(dirlist.fs_s, 5), 1, 1)) |, fs_s > fs_ndx /* v3 checks dirs and files and steps thru each */ fs_s= fs_s + 1 if fs_f = 0 & fs_s > fs_ndx then do fs_f= 1 fs_s= 1 end end if fs_s <> fs_n & fs_s <= fs_ndx then do /* found one */ fs_cur= fs_filnam(fs_s) end if fs_kd <> translate(substr(word(dirlist.fs_s, 5), 1, 1)) then do call alert 'Name starting with "'fs_kd'" not found.' call syssleep 0.5 end call fs_set_sel call fs_show_new_dir end when fs_kd = k_a_f then do /* fs_filter toggle */ if fs_filter = 1 then fs_filter= 0; else fs_filter= 1 fs_ndx= get_1_directory(glo_var, fs_path, fs_flspc, fs_attr, fs_filter, 1) fs_tags= copies('ú', fs_ndx) if fs_sort <> 'N' then call fs_sort_list call fs_set_sel call fs_show_new_dir end when fs_kd = k_a_h | fs_kd = k_a_m | fs_kd = k_a_t then do if fs_kd = k_a_h then fs_initpos= 'H' /* uncode from alt-keys */ else if fs_kd = k_a_m then fs_initpos= 'M' else if fs_kd = k_a_t then fs_initpos= 'T' fs_cur= '' /* set off so fs_set_sel uses fs_initpos rather than finds this */ call fs_set_sel call fs_show_new_dir end when fs_kd = k_a_d | fs_kd = k_a_e | fs_kd = k_a_n | fs_kd = k_a_s then do call alert 'Sorting may take a while...' fs_sort= 'N'; call fs_sort_list; /* always sort first by name */ if fs_kd <> k_a_n then do /* results in better ordering */ if fs_kd= k_a_d then fs_sort= 'D' /* uncode sort type from alt-keys */ else if fs_kd= k_a_e then fs_sort= 'E' else if fs_kd= k_a_s then fs_sort= 'S' call fs_sort_list end call fs_show_new_dir end when fs_kd = k_c_up then do /* ctrl-up; SET tag and move up */ if fs_n > 2 then fs_tags= overlay('Û', fs_tags, fs_n) /* don't tag dot dirs */ if fs_sel.fs_lvl > 2 then do call syscurpos fs_sel.fs_lvl - 1, fs_scol call fs_show_tag(fs_n) call fs_lowlight fs_sel.fs_lvl= fs_sel.fs_lvl - 1 call fs_highlight end else do if fs_ndx_ofs.fs_lvl > 0 then do fs_ndx_ofs.fs_lvl= fs_ndx_ofs.fs_lvl - 1 call fs_show_section end end end when fs_kd = ' ' |, /* TOGGLE tag and move down */ fs_kd = k_c_dn then do /* ctrl-down; SET tag and move down */ if fs_n > 2 then do if fs_kd = ' ' & substr(fs_tags, fs_n, 1) = 'Û' then fs_tags= overlay('ú', fs_tags, fs_n) else fs_tags= overlay('Û', fs_tags, fs_n) call syscurpos fs_sel.fs_lvl - 1, fs_scol call fs_show_tag(fs_n) if fs_sel.fs_lvl <= fs_maxln - 1 then do call fs_lowlight if fs_n < fs_ndx then fs_sel.fs_lvl= fs_sel.fs_lvl + 1 call fs_highlight end else do if fs_ndx_ofs.fs_lvl < fs_ndx - fs_showln then do if fs_sel.fs_lvl < fs_ndx - 1 then fs_ndx_ofs.fs_lvl= fs_ndx_ofs.fs_lvl + 1 call fs_show_section end end end end when fs_kd = k_f1 then do /* F1 Help */ call fs_show_instructions fs_scol call fs_show_section end when fs_kd = '`' then do /* v3 if long name, show in box, wait for key */ fs_totlsiz= fs_filnam(fs_n) /* using existing free vars */ if length(fs_totlsiz) > scrx - fs_scol then do call alert 'Full name: "'||fs_totlsiz||'" Hit any key to resume.' do until chars() > 0 call syssleep 0.5 end fs_kd= ex_read_key() fs_kd= '' call fs_show_section end end when fs_kd = k_enter then do /* : if not dir (or dots), return */ if fs_n < 3 then call fs_exit_dir /* ON DOT DIRS, go up */ if fs_n > 2 & fs_lvl < max_lvl & substr(fs_filatt(fs_n), 2, 1) = 'D' then, call fs_enter_dir /* OR could do nothing */ else do fs_action= fs_kd fs_quit= 1 end end otherwise do /* RETURN on all other keys to handle in caller. */ fs_action= fs_kd fs_quit= 1 end end /* select */ end /* if charin > 0 */ else do /* without sleep keyboard poll keeps CPU BUSY */ if fs_timr < 100 then call syssleep 0.1; else call syssleep 0.5 fs_timr= fs_timr + 1 /* counter for longer sleeps after 10 sec idle */ end end /* while fs_quit */ end /* fs_ndx > 0, but may be only dot dirs... */ else do /* don't know will ever get to here... */ fs_action= 'Not_Found' fs_n= 0 fs_rv= '' end return fs_action' '||fs_n||' '||fs_tags||' ' ||fs_path||fs_filnam(fs_n) fs_fildat: /* word 1, year 2 or 4 chars depending whether 'L' in fs_view */ arg fs_ni fs_rv= word(dirlist.fs_ni, 1) if pos('L', fs_view) = 0 then fs_rv= substr(fs_rv, 3, 8) return fs_rv fs_filtim: /* word 2; colon and seconds omitted here if short form */ arg fs_ni fs_rv= word(dirlist.fs_ni, 2) if pos('L', fs_view) = 0 then fs_rv= substr(fs_rv, 1, 5) return fs_rv fs_filsiz: /* word 3 WITH leading spaces for ease in display */ arg fs_ni fs_twi= wordindex(dirlist.fs_ni, 2) + length(word(dirlist.fs_ni, 2)) + 1 return substr(dirlist.fs_ni, fs_twi, 10) /* finds end of word ^TWO */ fs_filatt: /* word 4 attributes */ arg fs_ni return word(dirlist.fs_ni, 4) fs_filnam: /* word 5 --> remainder INCLUDING spaces */ arg fs_ni fs_twi= wordindex(dirlist.fs_ni, 5) return substr(dirlist.fs_ni, fs_twi, length(dirlist.fs_ni) - fs_twi + 1) fs_ellipsis: /* shorten fs_filnam if necessary to fit available space */ arg fs_ni, fs_nw fs_twi= fs_filnam(fs_ni) if length(fs_twi) > fs_nw then fs_twi= left(fs_twi, fs_nw % 2)||'/÷/'||right(fs_twi, (fs_nw % 2) - 3) return fs_twi fs_show_section: /* displays however much of dirlist. fits screen space */ do fs_loop= 0 to scry - 1 /* sim clear screen; remove all of previous */ if length(fs_view) = 0 then call syscurpos fs_loop, fs_scol else call syscurpos fs_loop, fs_scol - fs_dtlwid + 1 call charout, ansi_clreol end fs_totlsiz= 0; fs_width= 0 /* temp counter and then to form up a string */ do fs_loop = 3 to fs_ndx if pos('D', fs_filatt(fs_loop)) = 2 then fs_width= fs_width + 1 else fs_totlsiz= fs_totlsiz + 1 end fs_width= fs_totlsiz||' files þ '||fs_width||' (+ 2) directories' fs_totlsiz= 0 /* always 2 implicit in . and .. ^ */ do fs_loop = 3 to fs_ndx fs_totlsiz= fs_totlsiz + fs_filsiz(fs_loop) end fs_loop= 0 /* 0 based for screen line */ do until fs_loop + fs_ndx_ofs.fs_lvl >= fs_ndx | fs_loop >= fs_maxln fs_n= fs_loop + fs_ndx_ofs.fs_lvl + 1 if length(fs_view) > 0 then do call syscurpos fs_loop, fs_scol - fs_dtlwid + 1 call charout, ansi_clreol do fs_a= 1 to length(fs_view) /* order in fs_view sets displayed order! */ fs_v= substr(fs_view, fs_a, 1) if fs_v= 'D' then call charout, fs_fildat(fs_n)' ' if fs_v= 'T' then call charout, fs_filtim(fs_n)' ' if fs_v= 'A' then call charout, fs_filatt(fs_n)' ' if fs_v= 'S' then call charout, fs_filsiz(fs_n)' ' end end call syscurpos fs_loop, fs_scol call charout, ansi_clreol select when fs_n = 1 then do call charout, d2c(17)||'. '||fs_width end when fs_n = 2 then do call charout, d2c(17)||'.. 'fwc(fs_totlsiz, 0, 'N')' bytes' end when fs_n > 2 then do call fs_show_tag(fs_n) call charout, fs_ellipsis(fs_n, scrx - fs_scol) end end /* select */ fs_loop= fs_loop + 1 end /* do until */ call fs_highlight return fs_show_path: /* assembles bottom line, then truncates to available space */ fs_ps= ' (F1 Help) ['||word(sysdriveinfo(substr(fs_path, 1, 2)), 4)||'] '||, fwc(word(sysdriveinfo(substr(fs_path, 1, 2)), 2), 0, 'M')||, ' þ 'fwc(word(sysdriveinfo(substr(fs_path, 1, 2)), 3), 0, 'M')||, ' '||fs_path fs_totlsiz= 0 fs_width= '' /* now to form string to show filter, fancy because important */ if length(fs_flspc) > 1 & fs_filter = 1 then do fs_width= fs_flspc if length(fs_width) > 11 then fs_width= '{'||substr(fs_flspc, 1, 11)||'...', ||'}' fs_totlsiz= length(fs_width) fs_ps= fs_ps||'_'||revcolr||fs_width fs_totlsiz= length(revcolr) end fs_width= scrx - fs_scol + fs_dtlwid - 1 if length(fs_ps) - fs_totlsiz < fs_width then do do until length(fs_ps) - fs_totlsiz >= fs_width fs_ps= insert('_', fs_ps, lastpos('\', fs_ps)) end end else fs_ps= substr(fs_ps, length(fs_ps) - fs_totlsiz - fs_width + 1, fs_width) call syscurpos scry, fs_scol - fs_dtlwid + 1 /* 0, 0 based */ call charout, fs_ps||normcolr return fs_show_new_dir: /* code needed several times */ if fs_ndx < fs_showln then fs_maxln= fs_ndx; else fs_maxln= fs_showln call fs_show_section call fs_show_path return alert: /* v3 boxed messages will be over-written by next show_new_dir */ parse arg fs_mess fs_width= scrx - fs_scol - 4 /* re-using fs_... vars known to be free */ if fs_width - 4 > length(fs_mess) then fs_width= length(fs_mess) call syscurpos scry % 2 - 1, fs_scol call charout, highcolr||'É'||copies('Í', fs_width + 2)||'»' fs_loop= 0 do until length(fs_mess) = 0 call syscurpos scry % 2 + fs_loop, fs_scol call charout, 'º '||substr(fs_mess, 1, fs_width)||' º' fs_mess= delstr(fs_mess, 1, fs_width) fs_loop= fs_loop + 1 end call syscurpos scry % 2 + fs_loop, fs_scol call charout, 'È'||copies('Í', fs_width + 2)||'¼'||normcolr return fs_exit_dir: /* for left-arrow at any time, or on a dot dir */ if fs_lvl > 1 & length(fs_path) > 3 then do /* backs up one fs_lvl */ call alert 'Waiting for directory...' if fs_lvl > 2 then do fs_loop= length(fs_path) - 1 do until substr(fs_path, fs_loop, 1) = '\' | length(fs_path) < 4 fs_loop= fs_loop - 1 end fs_loop= fs_loop + 1 end else fs_loop= 4 fs_cur= substr(fs_path, fs_loop, length(fs_path) - fs_loop) fs_loop= length(fs_path) do until substr(fs_path, fs_loop, 1) = '\' | length(fs_path) < 4 fs_loop= fs_loop - 1 end fs_path= substr(fs_path, 1, fs_loop) fs_lvl= fs_lvl - 1 /* fs_filter= 0 going up, so off likely better */ /* !!! ^ may want to comment this out for some applications... er, most? */ fs_ndx= get_1_directory(glo_var, fs_path, fs_flspc, fs_attr, fs_filter, 1) fs_tags= copies('ú', fs_ndx) if fs_sort <> 'N' then call fs_sort_list call fs_set_sel call fs_show_new_dir end return fs_enter_dir: /* for right-arrow or on a non-dot dir */ call alert 'Waiting for directory...' fs_cur= '' /* current selection always set off upon enter */ fs_path= fs_path||fs_filnam(fs_n)||'\' fs_lvl= fs_lvl + 1 fs_sel.fs_lvl= 1 fs_ndx= get_1_directory(glo_var, fs_path, fs_flspc, fs_attr, fs_filter, 1) fs_tags= copies('ú', fs_ndx) if fs_sort <> 'N' then call fs_sort_list call fs_set_sel call fs_show_new_dir return fs_highlight: /* show selected item (only the name...) in reverse color */ call syscurpos fs_sel.fs_lvl - 1, fs_scol + 1 call charout, revcolr||fs_ellipsis(fs_ndx_ofs.fs_lvl + fs_sel.fs_lvl, scrx - fs_scol)||normcolr return fs_lowlight: /* show name back in standard color */ call syscurpos fs_sel.fs_lvl - 1, fs_scol + 1 call charout, normcolr||fs_ellipsis(fs_ndx_ofs.fs_lvl + fs_sel.fs_lvl, scrx - fs_scol) return fs_show_tag: /* show tag (for dirs, simulate block w reverse color) */ arg fs_ni if substr(fs_filatt(fs_ni), 2, 1) = 'D' then do if substr(fs_tags, fs_ni, 1) = 'Û' then call charout, revcolr||d2c(16)||normcolr else call charout, d2c(16) end else call charout, substr(fs_tags, fs_ni, 1) return fs_set_sel: /* figures out what part of list to display, and item to select */ fs_n= 0 if length(fs_cur) > 0 then do /* assumes fs_cur is valid... */ fs_cs= 1 /* first search for a matching name */ do until fs_cs >= fs_ndx | pos(fs_cur, fs_filnam(fs_cs)) = 1 fs_cs= fs_cs + 1 end end else fs_cs= fs_ndx + 1 if fs_cs <= fs_ndx then do /* if name match, calc which to highlight */ if fs_cs > fs_showln then do /* split into pages */ fs_ndx_ofs.fs_lvl= fs_cs - fs_showln fs_sel.fs_lvl= fs_showln fs_n= fs_showln % 2 if fs_ndx_ofs.fs_lvl + fs_sel.fs_lvl + fs_n < fs_ndx then do fs_ndx_ofs.fs_lvl= fs_ndx_ofs.fs_lvl + fs_n fs_sel.fs_lvl= fs_sel.fs_lvl - fs_n end end else do /* less than a screenfull */ fs_ndx_ofs.fs_lvl= 0; fs_sel.fs_lvl= fs_cs; end end else do /* no name match, calc a position */ select when fs_initpos = 'H' then do /* show list from Head (top) */ if fs_lvl > 1 & fs_ndx > 2 then fs_sel.fs_lvl= 3; else fs_sel.fs_lvl= 2 fs_ndx_ofs.fs_lvl= 0 end when fs_initpos = 'M' then do /* Middle */ if fs_ndx > fs_showln then do /* more files than screen lines */ fs_sel.fs_lvl= fs_showln % 2 + 1 if (fs_ndx > 2 * fs_showln - 1) then fs_ndx_ofs.fs_lvl= fs_ndx % 2 - fs_sel.fs_lvl else fs_ndx_ofs.fs_lvl= (fs_ndx - fs_showln) % 2 end else do if fs_ndx > 2 then fs_sel.fs_lvl= fs_ndx % 2 + 2; else fs_sel.fs_lvl = 2 fs_ndx_ofs.fs_lvl= 0 end end when fs_initpos = 'T' then do /* Tail (end) */ if fs_ndx > fs_showln then do fs_sel.fs_lvl= fs_showln fs_ndx_ofs.fs_lvl= fs_ndx - fs_showln end else do fs_sel.fs_lvl= fs_ndx fs_ndx_ofs.fs_lvl= 0 end end end /* select */ end /* else of fs_cs <= fs_ndx */ return /* get_1_directory can be invoked directly: gets only ONE level, NO recursion, BUT does all multiple file spec and filtering. Can be used for multiple concurrent lists by specifying stems in glo_var SPACES in file spec's present problems, that I DODGE by not allowing, but could be added if you're ambitious by changing the delimiter of g1_flspc */ get_1_directory: parse arg glo_var, g1_path, g1_flspc, tattr, g1_filter, g1_dirs /* get JUST ONE dir in Long (Y2K) form, and re-format: 2000-09-06 12:43:00 1234567890 A---- C:\os2\SWITCHRX.CMD by removing unnecessary spaces and (known elsewhere) path to: 2000-09-06 12:43:00 1234567890 A---- SWITCHRX.CMD 1 words 2 3 4 5 --> remainder inc spaces */ drop value(glo_var) /* toss any previous list */ g1_addl= '____Date__ _Time___ ___Size___ Attrb .' rc= value(glo_var||'1', g1_addl) /* fake dot dirs for sake of convention */ g1_addl= 'yyyy-mm-dd hh:mm:ss 0 ADHRS ..' rc= value(glo_var||'2', g1_addl) /* though will use the space for info */ g1_addl= 2 /* additional, now is offset for accumulating to glo_var.0 */ if substr(g1_path, length(g1_path), 1) \= '\' then g1_path= g1_path||'\' if g1_filter = 0 then do; g1_flspc= '*'; tattr= '*****'; end; do g1_nspec= 0 to words(g1_flspc) /* space delim'd, so NO OTHER spaces */ g1_ts.0= 0 if g1_nspec > 0 then do rc= SysFileTree(g1_path||word(g1_flspc, g1_nspec), 'g1_ts', 'FTL', tattr) end else do /* check get dirs */ if g1_dirs = 1 then rc= SysFileTree(g1_path||'*', 'g1_ts', 'DTL', tattr) end if g1_ts.0 > 0 then do do g1_n= 1 to g1_ts.0 g1_ts.g1_n= delstr(g1_ts.g1_n, wordindex(g1_ts.g1_n, 3) - 1, 1) g1_ts.g1_n= delstr(g1_ts.g1_n, wordindex(g1_ts.g1_n, 4) - 1, 1) g1_ts.g1_n= delstr(g1_ts.g1_n, wordindex(g1_ts.g1_n, 5) - 1, 1) g1_p= pos(':\', g1_ts.g1_n) - 1 g1_ts.g1_n= delstr(g1_ts.g1_n, g1_p, lastpos('\', g1_ts.g1_n) - g1_p + 1) /* strip out path */ g1_l= g1_n + g1_addl /* arithmetic */ g1_p= value(glo_var||g1_l, g1_ts.g1_n) /* SET (global) glo_var.[g1_n + g1_addl] TO g1_ts.g1_n */ end end g1_addl= g1_addl + g1_ts.0 /* sum # in current list plus all previous */ g1_p= value(glo_var||'0', g1_addl) /* set the number of elements */ end drop g1_ts. return g1_addl /* becomes fs_ndx, # of entries found */ fs_sort_list: /* Don't quibble that it's a slow primitive bubble sort; */ fs_ns= fs_ndx /* makes for easy coding to sort on varied fields. */ /* call alert 'Sorting...' hmm... quite a delay with >300 entries... */ if fs_ns > 3 then do if substr(fs_filnam(2), 2, 1) = '.' then fs_head= 3; else fs_head= 1 fs_head= 3 do while substr(fs_filatt(fs_head), 2, 1) = 'D' /* KEEP DIRS FIRST */ fs_head= fs_head + 1 end if fs_head >= fs_ns then return /* until loop in REXX differs from TP! */ do until fs_head >= fs_ns fs_cnt= fs_head + 1 do until fs_cnt > fs_ns select /* get which field: Date, Extension, Name, or Size */ when fs_sort = 'D' then do fs_v1= word(dirlist.fs_cnt, 1)||word(dirlist.fs_cnt, 2) fs_v2= word(dirlist.fs_head, 1)||word(dirlist.fs_head, 2) end when fs_sort = 'E' then do /* Simplistic. Scrambles re full name. */ parse upper var dirlist.fs_cnt with dummy '.' fs_v1 parse upper var dirlist.fs_head with dummy '.' fs_v2 end when fs_sort = 'N' then do fs_twi= wordindex(dirlist.fs_cnt, 5) fs_v1= substr(dirlist.fs_cnt, fs_twi, length(dirlist.fs_cnt) - fs_twi + 1) fs_twi= wordindex(dirlist.fs_head, 5) fs_v2= substr(dirlist.fs_head, fs_twi, length(dirlist.fs_head) - fs_twi + 1) end when fs_sort = 'S' then do fs_v1= word(dirlist.fs_cnt, 3) fs_v2= word(dirlist.fs_head, 3) end end /* select */ if fs_v1 < fs_v2 then do /* compare and swap */ fs_twi= dirlist.fs_cnt dirlist.fs_cnt= dirlist.fs_head dirlist.fs_head= fs_twi end fs_cnt= fs_cnt + 1 end fs_head= fs_head + 1 end end return fs_show_instructions: procedure expose revcolr normcolr /* custom for GFS */ arg ix if ix > 40 then ix= 40 /* caller handles all screen clean-up, heh */ call charout, revcolr iy= 1 call say_inc 'ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÑÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»' call say_inc 'º arrows: ³ ALT-keys: º' call say_inc 'º 'd2c(30)' up ³ Copy/move modeº' call say_inc 'º 'd2c(31)' down ³ Filter toggle º' call say_inc 'º 'd2c(16)' into directory ³ Password set º' call say_inc 'º 'd2c(17)' out of directory ³ Video filter º' call say_inc 'º ³ sort by: º' call say_inc 'º or F3: exit ³ Date/time º' call say_inc 'º launch by ³ Extension º' call say_inc 'º association ³ Name º' call say_inc 'º will ³ Size º' call say_inc 'º attempt to execute ³ display from: º' call say_inc 'º ³ Head º' call say_inc 'º A-Z: select drive ³ Middle º' call say_inc 'º a-z, 0-9: jump 1st ³ Tail º' call say_inc 'º `: show long name ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄĶ' call say_inc 'º sets destination directory º' call say_inc 'º copies or moves to "home" º' call say_inc 'º file (y) or directory (Y) º' call say_inc 'º [CTRL-] bookmark, set / switch º' call say_inc 'ÇÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄĶ' call say_inc 'º DGDs Generalized File Selector v3 º' call say_inc 'ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ' kd= 0 iy= 1 do while chars() = 0 if kd // 5 = 0 then do call syscurpos iy, ix + 5; call charout, ' Hit any key ' end else do call syscurpos iy, ix + 5; call charout, 'ÍÍÍÍÍÍÍÍÍÍÍÍÍ' end call syssleep 0.5 kd= kd + 1 end kd= ex_read_key() kd= '' call charout, normcolr return say_inc: parse arg it call syscurpos iy, ix call charout, it iy= iy + 1 return fwc: procedure /* format a number with commas; scale = Normal, Kilo-, Mega- */ arg ns, len, scale /* ns = number, len = desired length padded; 0 = none */ nf= '' scale= translate(scale) if scale <> 'K' & scale <> 'M' then scale= '' /* otherwise default */ if scale = 'K' then ns= format(ns / 1024, , 0) /* no padding, no decimal */ if scale = 'M' then ns= format(ns / 1048576, , 0) do p= length(ns) to 4 by -3 nf= ','||substr(ns, p - 2, 3)||nf end if p > 0 then nf= substr(ns, 1, p)||nf nf= nf||scale if len > 0 then nf= copies(' ', len - length(nf) - length(scale))||nf return nf ex_read_key: /* returns two bytes for extended codes */ xrkey= sysgetkey('noecho') if xrkey = d2c(0) | xrkey = d2c(224) then xrkey= xrkey||sysgetkey('noecho') return xrkey constants: /* initialization */ zky= d2c(0); xky= d2c(224) /* prefixes for extended keys */ k_esc= x2c('1b'); k_enter= x2c('0d'); k_bksp= d2c(8); k_tab= d2c(9) k_up= 'àH'; k_down= 'àP'; k_left= 'àK'; k_right= 'àM' k_ins= 'àR'; k_del= 'àS'; k_home= 'àG'; k_end= 'àO' k_pgup= 'àI'; k_pgdn= 'àQ' /* control keys */ k_c_left= 'às'; k_c_right= 'àt'; k_c_up= 'à'||d2c(141); k_c_dn= 'à'||d2c(145) k_c_pgup= 'à'||d2c(132); k_c_pgdn= 'àv'; k_c_enter= d2c(10) k_c_bksp= d2c(127); k_c_tab=zky||d2c(148) /* alt keys */ k_a_left= zky||d2c(155); k_a_right= zky||d2c(157) k_a_up= zky||d2c(152); k_a_dn= zky||d2c(160) k_a_enter= zky||d2c(28) k_a_a= zky||d2c(30); k_a_b= zky||d2c(48); k_a_c= zky||d2c(46) k_a_d= zky||d2c(32); k_a_e= zky||d2c(18); k_a_f= zky||d2c(33) k_a_g= zky||d2c(34); k_a_h= zky||d2c(35); k_a_i= zky||d2c(23) k_a_j= zky||d2c(36); k_a_k= zky||d2c(37); k_a_l= zky||d2c(38) k_a_m= zky||d2c(50); k_a_n= zky||d2c(49); k_a_o= zky||d2c(24) k_a_p= zky||d2c(25); k_a_q= zky||d2c(16); k_a_r= zky||d2c(19) k_a_s= zky||d2c(31); k_a_t= zky||d2c(20); k_a_u= zky||d2c(22) k_a_v= zky||d2c(47); k_a_w= zky||d2c(17); k_a_x= zky||d2c(45) k_a_y= zky||d2c(21); k_a_z= zky||d2c(44) /* function keys; only F1 (Help) used in file_select */ k_f1= zky||';'; k_f2= zky||'<'; k_f3= zky||'='; k_f4= zky||'>' k_f5= zky||'?'; k_f6= zky||'@'; k_f7= zky||'A'; k_f8= zky||'B' k_f9= zky||'C'; k_f10= zky||'D'; k_f11= zky||d2c(133); k_f12= zky||d2c(134) /* text screen colors: used for highlighting */ black= 0; red= 1; green= 2; yellow= 3; blue= 4; magenta= 5; cyan= 6; white= 7; fgnd = 30 /* add color: 30 + 2 = 32 ==> green foreground */ bgnd = 40 /* add color: 40 + 7 = 47 ==> white background */ AEsc= '1B'x||'[' /* define ANSI-ESCape; + 0 = low, 1 = high int*/ normcolr= AEsc||'0;'||fgnd + white||';'||bgnd + black||'m' /* normal */ highcolr= AEsc||'1;'||fgnd + white||';'||bgnd + black||'m' /* bright */ revcolr= AEsc||'0;'||fgnd + black||';'||bgnd + white||'m' /* reversed */ ansi_clreol= AEsc||'K' return RETURN