Category : Dbase (Clipper, FoxBase, etc) Languages Source Code
Archive   : PACKLOOK.ZIP
Filename : PACKLOOK.PRG
*º System Name: PACKED FILES LISTING PROGRAM º*
*º Module Name: PACKLOOK.PRG º*
*º Description: Takes a ZIP, ARC or LZH format compressed º*
*º file and lists the contents of the file. º*
*º Also lists information on each file in the º*
*º compressed file. º*
*º Notes......: Must be loaded with the file name. º*
*º PACKLOOK
*º Pressing F1 pretty well explains it. There º*
*º is a help box for both the main and sort º*
*º screens. º*
*º This program doesn't need the pack programs º*
*º to run. º*
*º Author.....: Micheal Todd Charron º*
*º Date.......: Oct. 16 1990 º*
*º History....: Just waiting for the shower one day, decided º*
*º it would be a challenge. By no means is this º*
*º finished or the definitive Clipper pack list º*
*º utility. Forget a History, I'm wondering if º*
*º it has a future. Play with it, add to it, º*
*º make it better, I dare you. Point out it's º*
*º shortfalls to me. I promise I won't call º*
*º you names to your face. º*
*º º*
*º Copyright..: (c) Micro Tech Consultant Services, 1990 º*
*º (c) The people at Nantucket Canada, 1990 º*
*º Is this possible? º*
*ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ*
#include "fileio.ch"
#include "funcs.ch"
#include "inkey.ch"
// Defines position in the SEND INFO array
#define INFO_SIZE 1
#define POS_YEAR_MON 2
#define POS_MON_DAY 3
#define POS_MINUTES 4
#define POS_MIN_HOUR 5
#define POS_ORIGINAL 6
#define POS_PACKED 7
#define CB_FINISHED 8
#define CB_FILE_TYPE 9
#define CB_FILE_NAME 10
// Defines position in the PACKED FILES INFO array
#define F_NAME 1
#define F_NAME_LONG 2
#define F_DATE 3
#define F_TIME 4
#define F_ORIGINAL 5
#define F_PACKED 6
#define F_RATIO 7
#define F_COMPRESS 8
#define F_NUMBER 9
// Declaration of Variables
LOCAL aSendInfo, aPacked := {}
LOCAL cDefCol, cFName
LOCAL nHandle, nNoOfRows
// Takes pack file name from command line
PARAMETER cCommandLine
// Checks to see if a file name was put on the command line.
IF cCommandLine == Nil .OR. ( ! ( ".ZIP" $ UPPER( cCommandLine ) );
.AND. ! ( ".ARC" $ UPPER( cCommandLine ) );
.AND. ! ( ".LZH" $ UPPER( cCommandLine ) ) )
? "Try putting a ZIP, ARC or LZH file on the command line. Jeez!"
QUIT
ENDIF
// Checks to see if the file exists
IF ! FILE( cCommandLine )
? "Try putting a valid file name on the command line. Amateurs!"
QUIT
ENDIF
SETCURSOR( 0 )
CLS
Panel()
// Help not available at this point
@24, 0 CLEAR
@24, 71 SAY 'F1 - HELP'
// Draws the "files found" box
// Gives people something to look at while the program gathers info
SETCOLOR( 'w+/b' )
Shad( 10, 28, 12, 48, .T., 'w+/b' )
@11, 30 SAY 'Files Found: 0'
// SEND INFO arrays
// Following arrays are created with positions of information
// in the cFileInfo string and with code blocks that are unique
// to each format. The code blocks let me generalize the info
// gathering function so that I can add more formats later.
DO CASE
CASE ( ".ZIP" $ UPPER( cCommandLine ) )
aSendInfo := { 30, 14, 13, 11, 12, 23, 19,;
{ |cFileInfo| ( 'PK'+ CHR( 3 ) + CHR( 4 ) +;
CHR( 10 ) ) $ cFileInfo },;
{ |cFileInfo| FileType( ASC( SUBSTR( cFileInfo, 9, 1 ) ) ) },;
{ |cFileInfo, nHandle|;
cFName := SPACE( ASC( SUBSTR( cFileInfo,;
27, 1 ) ) ), FREAD( nHandle, @cFName, LEN( cFName ) ),;
cFName } }
CASE ( ".ARC" $ UPPER( cCommandLine ) )
aSendInfo := { 29, 21, 20, 22, 23, 26, 16,;
{ |cFileInfo| ( cFileInfo = CHR( 26 ) ) .AND.;
( SUBSTR( cFileInfo, 2, 1 ) $ ( CHR( 9 ) +;
CHR( 8 ) + CHR( 2 ) + CHR( 3 ) ) ) },;
{ |cFileInfo| FileType( ASC( SUBSTR( cFileInfo, 2, 1 ) ) ) },;
{ |cFileInfo| cFName := SUBSTR( cFileInfo, 3, 13 ),;
SUBSTR( cFName, 1, AT( CHR( 0 ), cFName ) - 1 ) } }
CASE ( ".LZH" $ UPPER( cCommandLine ) )
aSendInfo := { 22, 19, 18, 16, 17, 12, 8,;
{ |cFileInfo| ( '-lh' $ cFileInfo ) },;
{ |cFileInfo| PADC( SUBSTR( UPPER( cFileInfo ), 3, 5 ), 10 ) },;
{ |cFileInfo, nHandle|;
cFName := SPACE( ASC( SUBSTR( cFileInfo,;
22, 1 ) ) + 2 ),;
FREAD( nHandle, @cFName, LEN( cFName ) ),;
SUBSTR( cFName, 1, LEN( cFName ) - 2 ) } }
ENDCASE
// Passes an undefined array which will be built in the PACKINFO function
// Returns number of rows in order to control the movement through
// the array.
nNoOfRows := PackInfo( cCommandLine, aPacked, aSendInfo)
IF nNoOfRows == 0
CLS
?
? "EITHER This isn't a ZIP, ARC or LZH file."
? "OR Back to the drawing board for me."
? "OR You have a damaged packed file. This just isn't your day."
?
INKEY( 10 )
ELSE
BrowsePacked( aPacked, nNoOfRows, cCommandLine )
ENDIF
SETCURSOR( 1 )
Credit()
RETURN
* * * *
*
* Function PackInfo
*
FUNCTION PackInfo( cCommandLine, aPacked, aInfo )
LOCAL cFileInfo, cFName
LOCAL nFileCount := 0, nHandle := FOPEN( cCommandLine )
DO WHILE .T.
// Reads the individual file info from the packed file
cFileInfo := SPACE( aInfo[ INFO_SIZE ] )
FREAD( nHandle, @cFileInfo, aInfo[ INFO_SIZE ] )
// Pulls the code block from the passed array and
// evaluates it.
// The code block looks for information unique to
// the compression format
IF ! EVAL( aInfo[ CB_FINISHED ], cFileInfo )
EXIT
ENDIF
nFileCount ++
// Adds an undefined second dimension on to the
// array.
AADD( aPacked, {} )
// Evaluates the code block that reads the packed files
// file name.
cFName := EVAL( aInfo[ CB_FILE_NAME ], cFileInfo, nHandle )
// Some compression formats allow directory paths to be
// included with the file name. This pulls just the file
// name from the cFName string. The next element is
// filled with the whole thing.
AADD( aPacked[ nFileCount ],;
SUBSTR( cFName, RAT( '/', cFName ) + 1 ) )
AADD( aPacked[ nFileCount ], cFName )
// Calculates the Date of the file
AADD( aPacked[ nFileCount ],;
CalcDate( ASC( SUBSTR( cFileInfo,;
aInfo[ POS_YEAR_MON ], 1 ) ),;
ASC( SUBSTR( cFileInfo, aInfo[ POS_MON_DAY ],;
1 ) ) ) )
// Calculates the Time of the file
AADD( aPacked[ nFileCount ],;
CalcTime( ASC( SUBSTR( cFileInfo,;
aInfo[ POS_MINUTES ], 1 ) ),;
ASC( SUBSTR( cFileInfo, aInfo[ POS_MIN_HOUR ],;
1 ) ) ) )
// Calculates the size of the file before compression
AADD( aPacked[ nFileCount ],;
BIN2L( SUBSTR( cFileInfo, aInfo[ POS_ORIGINAL ],;
4 ) ) )
// Calculates the size of the file after compression
AADD( aPacked[ nFileCount ],;
BIN2L( SUBSTR( cFileInfo, aInfo[ POS_PACKED ],;
4 ) ) )
// Calculates the ratio of the file compression to the
// full size of the file
AADD( aPacked[ nFileCount ],;
Ratio( aPacked[ nFileCount, F_ORIGINAL ],;
aPacked[ nFileCount, F_PACKED ] ) )
// Fills the element with the type of the compression
AADD( aPacked[ nFileCount ], EVAL( aInfo[ CB_FILE_TYPE ],;
cFileInfo ) )
// Inserts the position of the file in the pack file
AADD( aPacked[ nFileCount ], nFileCount )
// Moves the file pointer to the next section
FSEEK( nHandle, aPacked[ nFileCount, F_PACKED ], FS_RELATIVE )
// Displays the number of files found
@11, 43 SAY STR( nFileCount, 4, 0 )
ENDDO
// Returns the number of files found in order to pass the value
// to the tbrowse function. This is for control of the boundrys of
// array.
RETURN nFileCount
* * * *
*
* Function BrowsePacked()
*
FUNCTION BrowsePacked( aPacked, nLenArray, cCommandLine )
LOCAL cDefCol, cDefColor, cHilite, cNoOfFiles
LOCAL lExit
LOCAL nArrPos := 1, nKey, nLeftCol, nRightCol, nSortPick
LOCAL oBrowse := TBROWSENEW( 2, 3, 19, 74 ), oColumn
// Draws the background box of the tbrowse
SETCOLOR( 'w+/b' )
Shad( 1, 2, 21, 75, .T., 'w+/b' )
// Displays the pack file name and the number of packed files
// files contained in it.
cDefColor := SETCOLOR( 'gr+/b' )
@20, 5 SAY UPPER( cCommandLine )
cNoOfFiles := LTRIM( STR( nLenArray ) ) + ' Files'
@20, ( 73 - LEN( cNoOfFiles ) ) SAY cNoOfFiles
SETCOLOR( cDefColor )
// Sets up the heading, column, and footing separator characters.
oBrowse:HEADSEP := 'ÂÄ'
oBrowse:COLSEP := '³'
oBrowse:FOOTSEP := 'ÁÄ'
// Sets up the color table in order for the COLORBLOCK instance
// variable to pick the colors from it.
oBrowse:COLORSPEC := 'w+/b, w+/n, w+/r, w+/br, n/bg, n/w, n/g'
// Controls movement through the array.
oBrowse:SKIPBLOCK := { | nMove | SkipArray( nMove, @nArrPos, nLenArray ) }
// FILE NAME column
oColumn := TBColumnNew( ' FILE NAME',;
{ || PADR( IF( Len( aPacked[ nArrPos, F_NAME_LONG ] ) <>;
Len( aPacked[ nArrPos, F_NAME ] ), CHR( 7 ), ' ' ) +;
aPacked[ nArrPos, F_NAME ], 14 ) } )
oColumn:COLORBLOCK := { || RColor( aPacked[ nArrPos, F_COMPRESS ] ) }
oColumn:WIDTH := 14
oBrowse:ADDCOLUMN( oColumn )
// FILE DATE column
oColumn := TBColumnNew( ' DATE',;
{ || PADC( aPacked[ nArrPos, F_DATE ], 10 ) } )
oColumn:COLORBLOCK := { || RColor( aPacked[ nArrPos, F_COMPRESS ] ) }
oColumn:WIDTH := 10
oBrowse:ADDCOLUMN( oColumn )
// FILE TIME column
oColumn := TBColumnNew( ' TIME',;
{ || PADC( aPacked[ nArrPos, F_TIME ], 7 ) } )
oColumn:COLORBLOCK := { || RColor( aPacked[ nArrPos, F_COMPRESS ] ) }
oColumn:WIDTH := 7
oBrowse:ADDCOLUMN( oColumn )
// FILE ORIGINAL SIZE column
oColumn := TBColumnNew( ' ORIGINAL',;
{ || STR( aPacked[ nArrPos, F_ORIGINAL ], 9, 0 ) + ' ' } )
oColumn:COLORBLOCK := { || RColor( aPacked[ nArrPos, F_COMPRESS ] ) }
oColumn:WIDTH := 10
oBrowse:ADDCOLUMN( oColumn )
// FILE PACKED SIZE column
oColumn := TBColumnNew( ' PACKED',;
{ || STR( aPacked[ nArrPos, F_PACKED ], 9, 0 ) + ' ' } )
oColumn:COLORBLOCK := { || RColor( aPacked[ nArrPos, F_COMPRESS ] ) }
oColumn:WIDTH := 10
oBrowse:ADDCOLUMN( oColumn )
// FILE RATIO ( original to packed ) column
oColumn := TBColumnNew( 'RATIO',;
{ || aPacked[ nArrPos, F_RATIO ] } )
oColumn:COLORBLOCK := { || RColor( aPacked[ nArrPos, F_COMPRESS ] ) }
oColumn:WIDTH := 5
oBrowse:ADDCOLUMN( oColumn )
// COMPRESSION TYPE column
oColumn := TBColumnNew( ' TYPE',;
{ || aPacked[ nArrPos, F_COMPRESS ] } )
oColumn:COLORBLOCK := { || RColor( aPacked[ nArrPos, F_COMPRESS ] ) }
oColumn:WIDTH := 10
oBrowse:ADDCOLUMN( oColumn )
// Sets the cell highlighting off
oBrowse:AUTOLITE := .F.
// Returns the right and left boundaries of the browse
nLeftCol := oBrowse:nLEFT
nRightCol := oBrowse:nRIGHT
// Assign a value to nKey to start off the DO WHILE loop
nKey := 0
DO WHILE .T.
// Will loop through the DO WHILE until all changes
// to the tbrowse have been taken care of.
DO WHILE ! ( oBrowse:STABILIZE() )
ENDDO
// Saves the screen at the current row position and changes
// it to bright white on black.
cHilite := SAVESCREEN( ROW(), nLeftCol, ROW(), nRightCol )
RESTSCREEN( ROW(), nLeftCol, ROW(), nRightCol,;
TRANSFORM( cHilite, REPLICATE( "X", 72 ) ) )
nKey := INKEY( 0 )
// Restores the screen to it's original color.
RESTSCREEN( ROW(), nLeftCol, ROW(), nRightCol, cHilite )
DO CASE
CASE nKey == K_F1
MainHelp( aPacked )
CASE nKey == K_DOWN
oBrowse:DOWN()
CASE nKey == K_UP
oBrowse:UP()
CASE nKey == K_PGDN
oBrowse:PAGEDOWN()
CASE nKey == K_PGUP
oBrowse:PAGEUP()
CASE nKey == K_F9
// Sort function
PickSort( oBrowse, aPacked )
ENDCASE
IF nKey == K_F10
lExit := TimeToExit()
IF lExit
EXIT
ENDIF
ENDIF
ENDDO
RETURN Nil
* * * *
*
* Function Ratio()
*
// Calculates the ratio of the Packed size to the Original size and
// returns it as a string.
FUNCTION Ratio( nOriginal, nPacked )
RETURN ( STR( 100 - INT( ( nPacked / nOriginal ) * 100 ), 3, 0 ) + '% ' )
* * * *
*
* Function FileType()
*
// Calculates the compression scheme that was used on the file.
FUNCTION FileType( nFileType )
LOCAL cFileType
DO CASE
CASE nFileType == 9
cFileType := ' Squashed '
CASE nFileType == 8
cFileType := ' Crunched '
CASE nFileType == 6
cFileType := ' Implode '
CASE nFileType == 3
cFileType := ' Packed '
CASE nFileType == 1
cFileType := ' Shrunk '
CASE nFileType == 0 .OR. nFileType == 2
cFileType := ' Stored '
ENDCASE
RETURN cFileType
* * * *
*
* Function SkipArray()
*
// Controls movement through the browse.
FUNCTION SkipArray( nMove, nArrPos, nArrayLength )
// Checks to see if the movement will be outside the bounds
// of the array and if so, restricts the tbrowse's movements.
IF nMove > 0
IF ( nArrPos + nMove ) > nArrayLength
nMove := nArrayLength - nArrPos
ENDIF
ELSE
IF ( nArrPos + nMove ) < 1
nMove := 1 - nArrPos
ENDIF
ENDIF
nArrPos += nMove
RETURN nMove
* * * *
*
* Function RColor()
*
// Checks the array for the compression type and then returns the
// appropriate pointers for the color table.
FUNCTION RColor( cCompress )
LOCAL aReturnArray
DO CASE
CASE cCompress = ' Sq'
aReturnArray := { 7, 2 }
CASE cCompress = ' C' .OR. cCompress = ' I' .OR. ( 'LH1' $ cCompress )
aReturnArray := { 3, 2 }
CASE cCompress = ' P' .OR. cCompress = ' Sh'
aReturnArray := { 4, 2 }
CASE cCompress = ' St' .OR. ( 'LH0' $ cCompress )
aReturnArray := { 6, 2 }
ENDCASE
RETURN aReturnArray
* * * *
*
* Function CalcDate()
*
// Calculates the file date.
FUNCTION CALCDATE( nYearMon, nMonDay )
LOCAL nMonth, nYearInt
nYearInt := IF( nYearMon > 39, ( ( nYearMon-40 ) / 2 ),;
( ( nYearMon/2 ) + 80 ) )
nMonth := INT( ( nMonDay - 1 ) / 32 )
IF ( nYearMon % 2 ) = 1
nMonth += 8
ENDIF
RETURN CTOD( PadNumL( nMonth ) + '/' +;
PadNumL( INT( ( ( nMonDay - 1 ) % 32 ) + 1 ) ) + '/' +;
PadNumL( INT( nYearInt ) ) )
* * * *
*
* Function CalcTime()
*
// Calculates the file time.
FUNCTION CALCTIME( nMinutes, nHourMin )
LOCAL nHour
nHour := INT( nHourMin / 8 )
nMinutes /= 32
nMinutes += ( nHourMin - ( nHour * 8 ) ) * 8
RETURN ( PadNumL( nHour ) + ':' + PadNumL( INT( nMinutes ) ) )
* * * *
*
* Function PadNumL()
*
// Returns a string for a number padded with zeros.
FUNCTION PadNumL( nNum )
RETURN PADL( LTRIM( STR( nNum ) ), 2, '0' )
* * * *
*
* Function PickSort()
*
// Picks the column that is to be sorted.
FUNCTION PickSort( oBrowse, aPacked )
LOCAL aSortNums := { F_NAME, F_DATE, F_TIME, F_ORIGINAL, F_PACKED,;
F_RATIO, F_COMPRESS },;
aColumn := { Nil, Nil, Nil, Nil, Nil, Nil, Nil }
LOCAL nKey
LOCAL oCol
nKey := 0
// Terminates the loop with ENTER, ESCAPE or F2.
DO WHILE nKey != K_ESC .AND. nKey != K_ENTER .AND. nKey != K_F9
DO WHILE ! (oBrowse:STABILIZE())
ENDDO
// Retrieves the object for the current column.
oCol := GetColObject( oBrowse )
IF aColumn[ oBrowse:COLPOS ] == Nil
// If nothing is saved for this column SAVECOLUMN
// returns an array of column info.
aColumn[ oBrowse:COLPOS ] := SaveColumn( oCol )
ENDIF
// Changes the whole column to bright white on black.
HiliteCol( aColumn[ oBrowse:COLPOS ] )
nKey :=INKEY( 0 )
DO CASE
CASE nKey == K_F1
RestColumn( aColumn[ oBrowse:COLPOS ] )
SortHelp()
CASE nKey == K_RIGHT
// Restores the original colors for the column
RestColumn( aColumn[ oBrowse:COLPOS ] )
oBrowse:RIGHT()
CASE nKey == K_LEFT
// Restores the original colors for the column
RestColumn( aColumn[ oBrowse:COLPOS ] )
oBrowse:LEFT()
CASE nKey == K_F9
// Restores the sort to it's original order.
Sorting()
ASORT( aPacked,,,;
{ |x, y| x[ F_NUMBER ] < y[ F_NUMBER ] } )
oBrowse:REFRESHALL()
CASE nKey == K_ENTER
// Sorts on the selected column.
Sorting()
ASORT( aPacked,,,;
{ |x, y| x[ aSortNums[ oBrowse:COLPOS ] ] < ;
y[ aSortNums[ oBrowse:COLPOS ] ] } )
oBrowse:REFRESHALL()
CASE nKey == K_ESC
oBrowse:REFRESHALL()
ENDCASE
ENDDO
RETURN Nil
* * * *
*
* Function GetColumnObject()
*
// Returns the object for the current column
FUNCTION GetColObject( oBrowse )
RETURN ( oBrowse:GETCOLUMN( oBrowse:COLPOS ) )
* * * *
*
* Function HiliteCol()
*
// Hilites the current column. Pulls the coordinates out of the
// passed array.
FUNCTION HiliteCol( aColumn )
RESTSCREEN( 4, aColumn[1], 18, aColumn[2],;
TRANSFORM( aColumn[3], REPLICATE( 'X',;
LEN( aColumn[3] ) / 2 ) ) )
RETURN Nil
* * * *
*
* Function SaveColumn()
*
// Returns the info for the current column, in an array.
FUNCTION SaveColumn( oColumn )
LOCAL nLC := COL(), nRC := ( COL() + oColumn:WIDTH - 1 )
RETURN { nLC, nRC, SAVESCREEN( 4, nLC, 18, nRC ) }
* * * *
*
* Function RestColumn()
*
// Restores the column colors from the passed array.
FUNCTION RestColumn( aColumn )
RESTSCREEN( 4, aColumn[1], 18, aColumn[2], aColumn[3] )
RETURN Nil
* * * *
*
* Function TimeToExit()
*
// Draws a dialog box asking for exit confirmation.
FUNCTION TimeToExit()
LOCAL cDefCol, cFullScreen
LOCAL nExitChoice, nReturnVal
nReturnVal := .F.
cFullScreen := SAVESCREEN( 0, 0, 24, 79 )
SETCOLOR( 'n/g' )
BoxShad( 9, 24, 13, 54, 'n/g' )
@10, 26 SAY 'Do you really want to Exit?'
@12, 33 PROMPT ' YES '
@12, 41 PROMPT ' NO '
MENU TO nExitChoice
IF nExitChoice == 1
nReturnVal := .T.
ENDIF
RESTSCREEN( 0, 0, 24, 79, cFullScreen )
RETURN nReturnVal
* * * *
*
* Function MainHelp()
*
// Help box for the main screen.
FUNCTION MainHelp( aPacked )
LOCAL cDefCol, cFullScreen := SAVESCREEN( 0, 0, 24, 79 )
LOCAL nRequired := 0
SETCOLOR( 'n/g' )
BoxShad( 5, 27, 17, 51, 'n/g' )
@6, 29 SAY CHR( 25 ) + ' Down'
@7, 29 SAY CHR( 24 ) + ' Up'
@8, 29 SAY 'PGDN Next Screen'
@9, 29 SAY 'PGUP Previous Screen'
@10, 29 SAY 'F9 Sort by Column'
@11, 29 SAY 'F10 Exit'
@12, 28 TO 12, 50
@13, 29 SAY 'Disk Space Required:'
@15, 29 SAY 'Disk Space Free:'
SETCOLOR( 'b/g' )
AEVAL( aPacked, {|nElement| nRequired += nElement[ F_ORIGINAL ] } )
@14, 29 SAY PADC( LTRIM( ( TRANSFORM( nRequired, "999,999,999" ) +;
' bytes' ) ), 21 )
@16, 29 SAY PADC( LTRIM( ( TRANSFORM( DISKSPACE(), "999,999,999" ) +;
' bytes') ), 21 )
INKEY( 0 )
RESTSCREEN( 0, 0, 24, 79, cFullScreen )
RETURN Nil
* * * *
*
* Function SortHelp()
*
// Help box for picking a column to sort on.
FUNCTION SortHelp()
LOCAL cDefCol, cFullScreen := SAVESCREEN( 0, 0, 24, 79 )
SETCOLOR( 'n/g' )
BoxShad( 8, 27, 14, 51, 'n/g' )
@9, 29 SAY CHR( 26 ) + ' Next Column'
@10, 29 SAY CHR( 27 ) + ' Previous Column'
@11, 29 SAY 'F9 Original'
@12, 29 SAY 'ENTER Sort on Column'
@13, 29 SAY 'ESC Abort'
INKEY( 0 )
RESTSCREEN( 0, 0, 24, 79, cFullScreen )
RETURN Nil
* * * *
*
* Function Sorting()
*
FUNCTION Sorting()
SETCOLOR( 'n*/g' )
BoxShad( 9, 33, 11, 46, 'n/g' )
@10, 35 SAY 'Sorting...'
RETURN Nil
Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!
This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.
But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/