home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast.iso / pcmag / vol7n12.zip / FSB.ASM < prev    next >
Assembly Source File  |  1988-03-23  |  30KB  |  992 lines

  1. ;------------------------------------------------
  2. ; FSB.ASM -- "File Search and Browse" for OS/2
  3. ;            (c) 1988, Ziff Communications Co.
  4. ;            PC Magazine * Charles Petzold, 3/88
  5. ;------------------------------------------------
  6. .286P
  7. ;-----------------------------------------------------------
  8. ; Macro to call OS/2 functions without declaring them first
  9. ;-----------------------------------------------------------
  10. OS2Call        MACRO    fnctname
  11.  
  12.     IFNDEF    fnctname
  13.         EXTRN    fnctname:FAR
  14.     ENDIF 
  15.         Call    Far Ptr fnctname
  16.  
  17.         ENDM
  18. ;-----------------------------------
  19. ; Structures used in OS/2 functions
  20. ;-----------------------------------
  21. FileFindBufStr    STRUC
  22.         create_date    dw    ?
  23.         create_time    dw    ?
  24.         access_date    dw    ?
  25.         access_time    dw    ?
  26.         write_date    dw    ?
  27.         write_time    dw    ?
  28.         file_size    dd    ?
  29.         falloc_size    dd    ?
  30.         attributes    dw    ?
  31.         string_len    db    ?
  32.         file_name    db    13 dup (?)
  33. FileFindBufStr    ENDS
  34.  
  35. KeyDataStruc    STRUC
  36.         char_code    db    ?
  37.         scan_code    db    ?
  38.         status        db    ?
  39.         nls_shift    db    ?
  40.         shift_state    dw    ?
  41.         time        dd    ?
  42. KeyDataStruc    ENDS
  43.  
  44. ModeDataStruc    STRUC
  45.         md_length    dw    ?
  46.         md_type        db    ?
  47.         color        db    ?
  48.         col        dw    ?
  49.         row        dw    ?
  50.         hres        dw    ?
  51.         vres        dw    ?
  52. ModeDataStruc    ENDS
  53. ;--------------------------------
  54. ; Define all segments and DGROUP
  55. ;--------------------------------
  56. _TEXT        SEGMENT WORD PUBLIC 'CODE'
  57. _TEXT        ENDS
  58. _DATA        SEGMENT WORD PUBLIC 'DATA'
  59. _DATA        ENDS
  60. _BSS        SEGMENT WORD PUBLIC 'BSS'
  61. _BSS        ENDS
  62. STACK        SEGMENT PARA STACK 'STACK'
  63.         dw    1024 dup (?)
  64. STACK        ENDS
  65. DGROUP        GROUP    _DATA, _BSS, STACK
  66.         ASSUME    CS:_TEXT, DS:DGROUP, SS:DGROUP, ES:DGROUP
  67. ;--------------------------
  68. ; Initialized Data Segment
  69. ;--------------------------
  70. _DATA        SEGMENT
  71.  
  72. SyntaxMsg    db    13, 10, "Syntax: FSB filespec"
  73.         db    13, 10
  74.         db    13, 10, "File Search and Browse "
  75.         db              "(c) 1988, Ziff Communications Co."
  76.         db    13, 10, "PC Magazine ", 254," Charles Petzold, 3/88"
  77. CRLF        db    13, 10, 0
  78.  
  79. DriveError    db    "FSB: Invalid disk drive", 0
  80. StartDirError    db    "FSB: Invalid directory", 0
  81. FileFindError    db    "FSB: Invalid file spec", 0
  82. PipeError    db    "FSB: Cannot not create pipe", 0
  83. ThreadError    db    "FSB: Cannot not create second thread", 0
  84. FileOpenError    db    9, "FSB: Cannot open file for reading", 13, 10, 0
  85. VideoModeError    db    9, "FSB: Unsupported video mode", 13, 10, 0
  86. RootDir        db    "\", 0
  87. Delimiters    db    9, ' ,;=', 0
  88. DoBrowse    db    1
  89.  
  90. _DATA        ENDS
  91. ;----------------------------
  92. ; Uninitialized Data Segment
  93. ;----------------------------
  94. _BSS        SEGMENT
  95.  
  96. FileSpec    dw    ?, ?
  97. LastBackSlash    dw    ?
  98. PipeReadHandle    dw    ?
  99. PipeWriteHandle    dw    ?
  100. ThreadID    dw    ?
  101. ThreadStack    dw    1024 dup (?)
  102. FullFileName    db    80 dup (?)
  103. BytesRead    dw    ?
  104. BytesWritten    dw    ?
  105.  
  106. _BSS        ENDS
  107. ;--------------
  108. ; Code Segment
  109. ;--------------
  110. _TEXT        SEGMENT
  111. ;----------------------------------------------
  112. ; Parse command line to get file specification
  113. ;----------------------------------------------
  114. Entry:        Push    DS            ; Data segment selector
  115.         Pop    ES            ; Transfer it to ES
  116.         Mov    DS, AX            ; DS = Environment selector
  117.         Mov    SI, BX            ; SI = Start of command line
  118.  
  119. SkipProgName:    Lodsb                ; Pull a command line byte
  120.         Or    AL, AL            ; Check if it's zero
  121.         Jnz    SkipProgName        ; If not, continue
  122.  
  123. SkipDelim:    Lodsb                ; Get command line byte
  124.         Or    AL, AL            ; See if it's zero
  125.         Jnz    CheckDelim        ; If not, check for delimiter
  126.         Jmp    DoSyntaxMsg        ; If so, display message
  127.  
  128. CheckDelim:    Mov    CX, 5            ; Five delimiters
  129.         Mov    DI, Offset Delimiters    ; pointer to them
  130.         Repne    Scasb            ; scan for delimiter
  131.         Jz    SkipDelim        ; if delimiter, loop around
  132.  
  133.         Cmp    Byte Ptr [SI], ':'    ; Check if a drive present
  134.         Jnz    NoDiskDrive        ; If not, skip section
  135.  
  136.         And    AL, 0DFh        ; Capitalize it
  137.         Sub    AL, '@'            ; Change from A to 1, etc
  138.         Sub    AH, AH            ; Zero out top byte
  139.  
  140.         Push    AX            ; Change to that drive
  141.         OS2Call DosSelectDisk        ;    by calling OS/2
  142.  
  143.         Mov    DX, Offset DriveError
  144.         Or    AX, AX            ; If AX not zero,
  145.         Jnz    ErrorExit        ;    display message and exit
  146.  
  147.         Add    SI, 2            ; Skip past drive
  148. NoDiskDrive:    Dec    SI            ; First character of rest
  149.         Mov    ES:[FileSpec], SI    ; Save the address
  150.         Mov    ES:[FileSpec + 2], DS
  151. FindEnd:    Lodsb                ; Get a byte
  152.         Cmp    AL, '\'            ; Check if it's a backslash
  153.         Jnz    NotBackSlash        ; If not, continue
  154.  
  155.         Mov    ES:[LastBackSlash], SI    ; If so, save the address
  156. NotBackSlash:    Mov    CX, 6            ; now six delimiters
  157.         Mov    DI, Offset Delimiters    ; pointer to delimiters
  158.         Repne    Scasb            ; scan them
  159.         Jnz    FindEnd            ; if not delimiter, loop around
  160.  
  161.         Mov    Byte Ptr [SI-1], 0    ; terminate with zero
  162. DoChangeDir:    Mov    SI, ES:[LastBackSlash]    ; Address of last back slash
  163.         Or    SI, SI            ; See if any at all
  164.         Jz    NoChangeDir        ; If none, skip this section
  165.  
  166.         Dec    SI            ; Points to last backslash now
  167.         Cmp    SI, ES:[FileSpec]    ; Check if at beginning
  168.         Jnz    ChangeToDir        ; If not, use directory
  169.  
  170.         Inc    Word Ptr ES:[FileSpec]    ; Skip past initial backslash
  171.         Push    DGROUP            ; Segment of new dir
  172.         Push    Offset RootDir        ; Offset of new dir
  173.         Jmp    Short CallChangeDir    ; Change to root directory
  174.  
  175. ChangeToDir:    Mov    Byte Ptr [SI], 0    ; Terinate dir name with zero
  176.         Push    Word Ptr ES:[FileSpec + 2]    ; This is segment
  177.         Push    Word Ptr ES:[FileSpec]        ; This is offset
  178.         Inc    SI            ; Save address of filename
  179.         Mov    ES:[FileSpec], SI    ;    in FileSpec
  180.  
  181. CallChangeDir:    Push    0            ; Reserved bytes
  182.         Push    0
  183.         OS2Call    DosChdir        ; Change directory
  184.  
  185.         Mov    DX, Offset StartDirError
  186.         Or    AX, AX            ; If non-zero return code,
  187.         Jnz    ErrorExit        ;    display message and leave
  188.  
  189. NoChangeDir:    Push    ES            ; Set DS to data segment
  190.         Pop    DS
  191.  
  192.         Call    MainRoutine        ; Go!
  193.  
  194.         Push    1            ; All threads to terminate
  195.         Push    0            ; Return code
  196.         OS2Call    DosExit            ; End the program
  197. ;-------------------------------------
  198. ; Error Exit: DX is pointer to string
  199. ;-------------------------------------
  200. DoSyntaxMsg:    Mov    DX, Offset SyntaxMsg
  201. ErrorExit:    Mov    AX, DGROUP        ; Set DS to data segment
  202.         Mov    DS, AX
  203.         Mov    BX, 2            ; Standard Error handle
  204.         Call    StringLen        ; Get length of DX string
  205.         Mov    CX, AX            ; Move it to CX
  206.         Call    MyDosWrite        ; Display error message
  207.  
  208.         Push    1            ; All threads to terminate
  209.         Push    1            ; Error return code
  210.         OS2Call    DosExit            ; End the program
  211. ;----------------------------------------------------------------
  212. ; Main Routine, create pipe, start second thread, and do browses
  213. ;----------------------------------------------------------------
  214. MainRoutine:    Push    DS            ; Address for read handle
  215.         Push    Offset PipeReadHandle
  216.         Push    DS            ; Address for write handle
  217.         Push    Offset PipeWriteHandle
  218.         Push    16384            ; Size of pipe
  219.         OS2Call    DosMakePipe        ; Create it
  220.  
  221.         Mov    DX, Offset PipeError
  222.         Or    AX, AX            ; If non-zero return code,
  223.         Jnz    ErrorExit        ;    depart from program
  224.  
  225.         Push    CS            ; Address of second thread
  226.         Push    Offset SecondThread
  227.         Push    DS            ; Address for thread ID
  228.         Push    Offset ThreadID
  229.         Push    DS            ; Top of thread stack
  230.         Push    Offset ThreadStack + 2048
  231.         OS2Call    DosCreateThread        ; Create the thread
  232.  
  233.         Mov    DX, Offset ThreadError
  234.         Or    AX, AX            ; Again, if error code,
  235.         Jnz    ErrorExit        ;    get out of this place
  236.  
  237. StartPipeRead:    Mov    CX, 80            ; Read 80 chars from pipe
  238.         Mov    DX, Offset FullFileName    ; Store it here
  239. ReadPipe:    Mov    BX, [PipeReadHandle]    ; Pipe handle
  240.         Call    MyDosRead        ; Read it
  241.  
  242.         Cmp    [BytesRead], 0        ; Check if read no bytes
  243.         Jz    NothingLeft        ; If so, pipe is empty
  244.  
  245.         Add    DX, [BytesRead]        ; Increment destination ptr
  246.         Sub    CX, [BytesRead]        ; Decrement counter
  247.         Jnz    ReadPipe        ; If not 80 bytes, read again
  248.  
  249.         Mov    DX, Offset FileFindError
  250.         Cmp    [FullFileName], 0    ; See if file name present
  251.         Jz    ErrorExit        ; If not, thread had problem
  252.  
  253. NoErrFromThread:Mov    BX, 1            ; Standard output handle
  254.         Mov    DX, Offset FullFileName    ; Full file name
  255.         Call    StringLen        ; Get its length
  256.         Mov    CX, AX            ; Store in CX
  257.         Call    MyDosWrite        ; Write to standard output
  258.  
  259.         Mov    CX, 2            ; Two bytes
  260.         Mov    DX, Offset CRLF        ;    for carriage ret/line feed
  261.         Call    MyDosWrite        ; Write that out also
  262.  
  263.         Cmp    [DoBrowse], 1        ; See if still doing browse
  264.         Jnz    StartPipeRead        ; If not, skip the call
  265.  
  266.         Call    Browse            ; Browse the file
  267.  
  268.         Or    AX, AX            ; If zero returned, continue
  269.         Jz    StartPipeRead
  270.         Cmp    AX, -1            ; If -1, Esc pressed -->
  271.         Jz    NothingLeft        ;   terminate gracefully
  272.  
  273.         Cmp    AX, Offset VideoModeError
  274.         Jnz    ShowBrowseErr        ; If video mode error,
  275.         Mov    [DoBrowse], 0        ;    don't try browse again
  276. ShowBrowseErr:    Mov    BX, 2            ; Standard error output
  277.         Mov    DX, AX            ; Address of error message
  278.         Call    StringLen        ; Find length 
  279.         Mov    CX, AX            ;    and save in CX
  280.         Call    MyDosWrite        ; Dispay the string
  281.  
  282.         Jmp    StartPipeRead        ; And get another file name
  283. NothingLeft:    Ret                ; Return when all done
  284. ;--------------------------------------------------------------------------
  285. ; DosRead and DosWrite routines (BX is handle, DX is buffer, CX is length)
  286. ;--------------------------------------------------------------------------
  287. MyDosRead:    Push    BX            ; Input handle
  288.         Push    DS            ; Segment of buffer
  289.         Push    DX            ; Offset of buffer
  290.         Push    CX            ; Number of bytes to write
  291.         Push    DS            ; Segment for bytes read
  292.         Push    Offset BytesRead    ; Offset for bytes read
  293.         OS2Call    DosRead            ; Read
  294.         Ret
  295.  
  296. MyDosWrite:    Push    BX            ; Output handle
  297.         Push    DS            ; Segment of buffer
  298.         Push    DX            ; Offset of buffer
  299.         Push    CX            ; Number of bytes to write
  300.         Push    DS            ; Segment for bytes written
  301.         Push    Offset BytesWritten    ; Offset for bytes written
  302.         OS2Call    DosWrite        ; Write
  303.         Ret
  304. ;------------------------------------------------------------
  305. ; StringLen routine (DS:DX points to string, AX is returned)
  306. ;------------------------------------------------------------
  307. StringLen:    Push    ES            ; Save some registers
  308.         Push    DI
  309.         Push    CX
  310.  
  311.         Push    DS
  312.         Pop    ES            ; Set ES to DS
  313.         Mov    DI, DX            ; Set DI to address of string
  314.         Mov    CX, -1            ; Initialize CX to big number
  315.         Sub    AL, AL            ; Search for zero
  316.         Repnz    Scasb            ; Do the scan
  317.         Not    CX            ; Invert CX
  318.         Dec    CX            ; Take away one
  319.         Mov    AX, CX            ; That's the length
  320.  
  321.         Pop    CX            ; Restore saved registers
  322.         Pop    DI
  323.         Pop    ES
  324.         Ret
  325.         
  326. _TEXT        ENDS
  327. ;-----------------------------------------------------------------------
  328. ;-----------------------------------------------------------------------
  329. ; SECOND THREAD section to search for files and write to pipe
  330. ;-----------------------------------------------------------------------
  331. ;-----------------------------------------------------------------------
  332. _DATA        SEGMENT
  333.  
  334. BackDir        db    "..", 0
  335. StarDotStar    db    "*.*", 0
  336.  
  337. _DATA        ENDS
  338.  
  339. _BSS        SEGMENT
  340.  
  341. FileFindBuf    FileFindBufStr <>
  342. FileFindBufLen    equ    $ - FileFindBuf
  343. FullPathName    Label    Byte
  344. CurrentDisk    db    ?, ?, ?
  345. CurrentDir    db    64 dup (?)
  346. CurrDirLen    dw    ?
  347. Zeroes        db    80 dup (?)
  348. DriveMap    dd    ?
  349.  
  350. _BSS        ENDS
  351. ;---------------------------------------------------------
  352. ; Second Thread -- Calls FindThem, closes pipe, and exits
  353. ;---------------------------------------------------------
  354. _TEXT        SEGMENT
  355.  
  356. SecondThread:    Push    DS                ; Variable to receive
  357.         Push    Offset CurrentDisk        ;   current drive
  358.         Push    DS                ; Variable to receive
  359.         Push    Offset DriveMap            ;   drive map
  360.         OS2Call    DosQCurDisk
  361.  
  362.         Add    [CurrentDisk], '@'        ; Convert to letter
  363.         Mov    [CurrentDisk + 1], ':'        ; Follow by colon
  364.         Mov    [CurrentDisk + 2], '\'        ;   and backslash
  365.  
  366.         Call    FindThem        ; Do the finds
  367.  
  368. TerminateThread:Push    [PipeWriteHandle]    ; Close the pipe for writing
  369.         OS2Call    DosClose
  370.  
  371.         Push    0            ; Terminate this thread only
  372.         Push    0            ; Result code (ignored)
  373.         OS2Call    DosExit
  374.  
  375. SearchError:    Mov    BX, [PipeWriteHandle]        ; If error, 
  376.         Mov    DX, Offset Zeroes        ;   write zeroes to 
  377.         Mov    CX, 80                ;   pipe
  378.         Call    MyDosWrite
  379.  
  380.         Jmp    TerminateThread            ;   and terminate
  381. ;----------------------------------------------------------------
  382. ; Find Them -- Recursive routine to find files fitting file spec
  383. ;----------------------------------------------------------------
  384. FindThem:    Enter    4, 0        ; Dir Handle is   [BP - 2]
  385.                     ; Search Count is [BP - 4]
  386. ;------------------------------------
  387. ; Get current directory for printing
  388. ;------------------------------------
  389.         Mov    [CurrDirLen], 64    ; Len for current dir
  390.         Push    0            ; Current disk drive
  391.         Push    DS
  392.         Push    Offset CurrentDir    ; Space for current dir
  393.         Push    DS
  394.         Push    Offset CurrDirLen
  395.         OS2Call    DosQCurDir        ; Get current dir
  396.  
  397.         Mov    DX, Offset FullPathName    ; Find length of it
  398.         Call    StringLen
  399.         Cmp    AX, 3            ; See if root
  400.         Jz    NoMoreSlashes        ; If so, skip next part
  401.  
  402.         Mov    SI, DX            ; Add a slash
  403.         Add    SI, AX            ;   at end of directory
  404.         Mov    Byte Ptr [SI], '\'
  405.         Mov    Byte Ptr [SI + 1], 0
  406.         Inc    AX
  407. NoMoreSlashes:    Mov    [CurrDirLen], AX    ; Save total length
  408. ;----------------------
  409. ; Search for the files
  410. ;----------------------
  411.         Mov    Word Ptr [BP - 2], -1    ; Initial directory Handle
  412.         Mov    Word Ptr [BP - 4], 1    ; Search for one file
  413.  
  414.         Push    [FileSpec + 2]        ; segment of find file name
  415.         Push    [FileSpec]        ; offset of find file name
  416.         Push    SS            ; segment of directory handle
  417.         Lea    AX, [BP - 2]        ; offset of directory handle
  418.         Push    AX
  419.         Push    07h            ; attribute
  420.         Push    DS            ; segment of buffer
  421.         Push    Offset FileFindBuf    ; offset of buffer
  422.         Push    FileFindBufLen        ; length of buffer
  423.         Push    DS            ; segment of search count
  424.         Lea    AX, [BP - 4]        ; offset of search count
  425.         Push    AX
  426.         Push    0            ; Reserved
  427.         Push    0
  428.         OS2Call   DosFindFirst        ; Find first file
  429.  
  430. FindResult1:    Or    AX, AX            ; See if error
  431.         Jz    NoFindError1        ; If not skip next
  432.         Cmp    AX, 18            ; See if no more files
  433.         Jz    FindAllDone1        ; If so, done with search
  434.         Jmp    SearchError        ; Process error 
  435.  
  436. NoFindError1:    Cmp    Word Ptr [BP - 4], 0    ; See if zero files found
  437.         Jz    FindAllDone1        ; If so, done with search
  438.  
  439.         Mov    BX, [PipeWriteHandle]    ; Write drive and
  440.         Mov    DX, Offset FullPathName    ;   directory path
  441.         Mov    CX, [CurrDirLen]    ;   to pipe
  442.         Mov    SI, CX
  443.         Call    MyDosWrite
  444.  
  445.         Mov    DX, Offset FileFindBuf.file_name
  446.         Mov    CL, [FileFindBuf.string_len]    ; Write file name
  447.         Sub    CH, CH                ;   to pipe
  448.         Add    SI, CX
  449.         Call    MyDosWrite
  450.  
  451.         Mov    DX, Offset Zeroes    ; Pad with zeroes
  452.         Mov    CX, 80            ;   written to pipe
  453.         Sub    CX, SI
  454.         Call    MyDosWrite
  455.  
  456.         Push    [BP - 2]        ; Directory Handle
  457.         Push    DS            ; segment of buffer
  458.         Push    Offset FileFindBuf    ; offset of buffer
  459.         Push    FileFindBufLen        ; length of buffer
  460.         Push    DS            ; segment of count
  461.         Lea    AX, [BP - 4]        ; offset of count
  462.         Push    AX
  463.         OS2Call    DosFindNext        ; Find next file
  464.  
  465.         Jmp    FindResult1        ; Loop around
  466.  
  467. FindAllDone1:    Push    [BP - 2]        ; directory handle
  468.         OS2Call    DosFindClose        ; close it
  469. ;-------------------------------
  470. ; Now search for subdirectories
  471. ;-------------------------------
  472.         Mov    Word Ptr [BP - 2], -1    ; Initial directory handle
  473.         Mov    Word Ptr [BP - 4], 1    ; Search for one directory
  474.  
  475.         Push    DS            ; segment of spec
  476.         Push    Offset StarDotStar    ; offset of spec
  477.         Push    SS            ; segment of handle
  478.         Lea    AX, [BP - 2]        ; offset of handle
  479.         Push    AX
  480.         Push    10h            ; attribute (dirs only)
  481.         Push    DS            ; segment of buffer
  482.         Push    Offset FileFindBuf    ; offset of buffer
  483.         Push    FileFindBufLen        ; length of buffer
  484.         Push    DS            ; segment of count
  485.         Lea    AX, [BP - 4]        ; offset of count
  486.         Push    AX
  487.         Push    0            ; reserved
  488.         Push    0
  489.         OS2Call    DosFindFirst        ; Find first dir
  490.  
  491. FindResult2:    Or    AX, AX            ; Check if error
  492.         Jz    NoFindError2
  493.         Cmp    AX, 18            ; Check if all finished
  494.         Jz    FindAllDone2
  495.         Jmp    SearchError
  496.  
  497. NoFindError2:    Cmp    Word Ptr [BP - 4], 0    ; Check if no dirs found
  498.         Jz    FindAllDone2
  499.         Test    [FileFindBuf.attributes], 10h    ; See if directory
  500.         Jz    FindTheNext
  501.         Cmp    [FileFindBuf.file_name], '.'    ; Exclude '.' and '..'
  502.         Jz    FindTheNext
  503.  
  504.         Push    DS            ; Change the directory
  505.         Push    Offset FileFindBuf.file_name
  506.         Push    0
  507.         Push    0
  508.         OS2Call    DosChdir
  509.  
  510.         Call    FindThem        ; Recursive call
  511.  
  512.         Push    DS            ; Change to '..' directory
  513.         Push    Offset BackDir
  514.         Push    0
  515.         Push    0
  516.         OS2Call    DosChdir
  517.  
  518. FindTheNext:    Push    [BP - 2]        ; search handle
  519.         Push    DS            ; segment of buffer
  520.         Push    Offset FileFindBuf    ; offset of buffer
  521.         Push    FileFindBufLen        ; length of buffer
  522.         Push    DS            ; segment of count
  523.         Lea    AX, [BP - 4]        ; offset of count
  524.         Push    AX
  525.         OS2Call    DosFindNext        ; Find next directory
  526.  
  527.         Jmp    FindResult2
  528.  
  529. FindAllDone2:    Push    [BP - 2]        ; directory handle
  530.         OS2Call    DosFindClose        ; close it
  531.  
  532.         Leave
  533.         Ret               
  534. _TEXT        ENDS
  535. ;-----------------------------------------------------------------------
  536. ;-----------------------------------------------------------------------
  537. ; BROWSE section to display files after names are read from pipe
  538. ;-----------------------------------------------------------------------
  539. ;-----------------------------------------------------------------------
  540. _DATA        SEGMENT
  541.                
  542.         db    'ATTR1='
  543. Attribute1    db    1Eh        ; Attribute for file text
  544.         db    'ATTR2='
  545. Attribute2    db    4Fh        ; Attribute for file name
  546.         db    'SHIFT='
  547. ShiftHoriz    db    8        ; Horizontal shift screen default
  548. FileOffset    dw    -1, -1
  549. Dispatch    dw    Home,  Up,    PgUp,  Dummy,  Left
  550.         dw    Dummy, Right, Dummy, EndKey, Down, PgDn
  551.  
  552. _DATA        ENDS
  553.  
  554. _BSS        SEGMENT
  555.  
  556. ModeData    ModeDataStruc <>
  557. KeyData        KeyDataStruc <>
  558. Buffer        db    16384 dup (?)
  559. BufferMid    db    16384 dup (?)
  560. BufferEnd    Label    Byte
  561. ScreenSize    dw    ?
  562. ScreenStart    dw    ?
  563. EndOfFile    dw    ?
  564. HorizOffset    dw    ?
  565. RightMargin    dw    ?
  566. ScreenAddr    Label    DWord
  567. ScreenOff    dw    ?
  568. ScreenSeg    dw    ?
  569. FileHandle    dw    ?
  570. OpenAction    dw    ?
  571. NewPointer    dd    ?
  572. ScreenSaveSel    dw    ?
  573.  
  574. _BSS        ENDS
  575. ;---------------------------
  576. ; Open the File for reading
  577. ;---------------------------
  578. _TEXT        SEGMENT
  579.  
  580. Browse:        Mov    [FileOffset], -1    ; Initialize these pointers
  581.         Mov    [FileOffset + 2], -1
  582.  
  583.         Push    DS            ; segment of name
  584.         Push    Offset FullFileName    ; offset of name
  585.         Push    DS            ; segment for handle
  586.         Push    Offset FileHandle    ; offset for handle
  587.         Push    DS            ; segment for 'action'
  588.         Push    Offset OpenAction    ; offset for 'acton'
  589.         Sub    AX, AX
  590.         Push    AX            ; high size (ignored)
  591.         Push    AX            ; low size (ignored)
  592.         Push    AX            ; attribute (ignored)
  593.         Push    1            ; open if file exists
  594.         Push    0A0h            ; read only / deny write
  595.         Push    AX            ; reserved
  596.         Push    AX            ; reserved
  597.  
  598.         OS2Call    DosOpen            ; Open File
  599.  
  600.         Or    AX, AX            ; Check if error
  601.         Jz    GotTheFile        ; If not, continue
  602.  
  603.         Mov    AX, Offset FileOpenError
  604.         Ret        
  605. GotTheFile:
  606. ;-----------------------------
  607. ; Get Screen Mode Information
  608. ;-----------------------------
  609.         Mov    [ModeData.md_length], 12    ; length of structure
  610.  
  611.         Push    DS            ; segment of structure
  612.         Push    Offset ModeData        ; offset of structure
  613.         Push    0            ; reserved
  614.         OS2Call    VioGetMode        ; get video mode
  615.  
  616.         Or    AX, AX            ; See if error (only if
  617.         Jz    NotDetached        ;   program is detached)
  618. VideoError:    Mov    AX, Offset VideoModeError
  619.         Ret
  620.  
  621. NotDetached:    Test    [ModeData.md_type], 2    ; See if graphics mode
  622.         Jnz    VideoError        ; If so, do not continue
  623.         Mov    AX, [ModeData.col]    ; character columns
  624.         Mul    [ModeData.row]        ; character rows
  625.         Jc    VideoError        ; Leave if exceeds 64K
  626.         Add    AX, AX            ; Ditto here
  627.         Jc    VideoError
  628.         Mov    [ScreenSize], AX    ; Save screen size in bytes
  629.  
  630.         Push    DS            ; Segment for address
  631.         Push    Offset ScreenAddr    ; Offset for address
  632.         Push    DS            ; Segment for size
  633.         Push    Offset ScreenSize    ; Offset for size
  634.         Push    0            ; Reserved
  635.         OS2Call    VioGetBuf        ; Get logical video buffer
  636.  
  637.         Or    AX, AX            ; Leave if an error
  638.         Jnz    VideoError
  639. ;---------------------------------------
  640. ; Allocate memory and save screen in it
  641. ;---------------------------------------
  642.         Push    [ScreenSize]        ; Size of segment
  643.         Push    DS            ; Segment for selector
  644.         Push    Offset ScreenSaveSel    ; Offset for selector
  645.         Push    0            ; No sharing
  646.         OS2Call    DosAllocSeg        ; Allocate segment
  647.  
  648.         Or    AX, AX            ; If error, leave
  649.         Jnz    VideoError
  650.  
  651.         Push    [ScreenSaveSel]        ; Segment for destination
  652.         Sub    AX, AX
  653.         Push    AX            ; Offset for destination
  654.         Push    DS            ; Segment of screen size
  655.         Push    Offset ScreenSize    ; Offset of screen size
  656.         Push    AX            ; Starting row
  657.         Push    AX            ; Starting column
  658.         Push    AX            ; Reserved
  659.         OS2Call    VioReadCellStr        ; Save the screen
  660.  
  661.         Call    SetExitList        ; Will restore on exit
  662. ;---------------------------------------
  663. ; Get keyboard key and decide on action
  664. ;---------------------------------------
  665.         Call    Home            ; Read file in
  666.         Mov    [ScreenStart],SI    ; Set buffer address
  667. KeyLoop:    Push    ThreadID        ; Don't let the search
  668.         OS2Call    DosSuspendThread     ;    slow down the update
  669.  
  670.         Call    UpDateScreen        ; Update the screen
  671.  
  672.         Push    ThreadID
  673.         OS2Call    DosResumeThread     ; Let the search resume
  674.  
  675. GetKey:        Push    DS            ; Segment of structure
  676.         Push    Offset KeyData        ; Offset of structure
  677.         Push    0            ; Wait for key
  678.         Push    0            ; Reserved
  679.         OS2Call    KbdCharIn        ; Read key
  680.  
  681.         Mov    AL, [KeyData.char_code]    ; Get character code
  682.         Cmp    AL, ' '            ; A space means do next
  683.         Je    SpaceLeave        ;    file
  684.         Cmp    AL,27            ; Check if ESC
  685.         Je    EscLeave        ; If so, terminate 
  686.         Cmp    AL, 0E0h        ; E0 for enhanced keyboard
  687.         Jz    ScanCode        ;   extended keys
  688.         Or    AL, AL            ; Check if extended
  689.         Jnz    GetKey            ; If not, try again
  690. ScanCode:       Mov    AL, [KeyData.scan_code]    ; Get scan code
  691.         Sub    AL,71            ; Subtract Home key value
  692.         Jb    GetKey            ; If below that, not valid
  693.         Cmp    AL,(81 - 71)        ; Check if above PgDn
  694.         Ja    GetKey            ; If so, ignore it
  695.         Sub    AH,AH            ; Zero out top byte
  696.         Add    AX,AX            ; Double for word access
  697.         Mov    BX,AX            ; Offset in dispatch table
  698.         Mov    SI,[ScreenStart]    ; Set current buffer pointer
  699.         Call    [Dispatch + BX]        ; Do the call
  700.         Mov    [ScreenStart],SI    ; Set new buffer pointer
  701.         Jmp    KeyLoop            ; And update the screen
  702. ;--------------------------------------------
  703. ; Terminate -- Restore screen and close file
  704. ;--------------------------------------------
  705. SpaceLeave:    Call    ExitRoutine        ; Restore screen
  706.         Call    UnsetExitList        ; Take away exit list
  707.         Sub    AX, AX            ; 0 means continue with files
  708.         Ret                ; Return
  709.  
  710. EscLeave:    Call    ExitRoutine        ; Restore screen
  711.         Call    UnsetExitList        ; Take away exit list
  712.         Mov    AX, -1            ; -1 means stop program
  713.         Ret                ; Return
  714. ;-------------------------------------
  715. ; Exit List Processing for Ctrl-Break
  716. ;-------------------------------------
  717. SetExitList:    Push    1            ; Set an exit list
  718.         Push    CS            ; Segment of routine
  719.         Push    Offset ExitList        ; Offset of routine
  720.         OS2Call    DosExitList
  721.         Ret
  722.  
  723. UnsetExitList:    Push    2            ; Unset an exit list
  724.         Push    CS            ; Segment of routine
  725.         Push    Offset ExitList        ; Offset of routine
  726.         OS2Call    DosExitList
  727.         Ret
  728.  
  729. ExitRoutine:    Push    [ScreenSaveSel]        ; Segment of saved screen
  730.         Push    0            ; Offset of saved screen
  731.         Push    [ScreenSize]        ; Length of saved screen
  732.         Push    0            ; Starting row
  733.         Push    0            ; Starting column
  734.         Push    0            ; Reserved
  735.         OS2Call    VioWrtCellStr        ; Restore screen
  736.  
  737.         Push    [FileHandle]        ; File handle
  738.         OS2Call    DosClose        ; Close it
  739.         Ret
  740.  
  741. ExitList:    Call    ExitRoutine        ; Do exit routine
  742.         Push    3            ; Then continue exiting
  743.         Push    0
  744.         Push    0
  745.         OS2Call    DosExitList
  746. ;---------------------
  747. ; Cursor Key Routines
  748. ;---------------------
  749. Home:        Sub    BX,BX            ; For zeroing out values
  750.         Mov    AX,[FileOffset]        ; Check if read in file
  751.         Or    AX,[FileOffset + 2]
  752.         Mov    [FileOffset],BX        ; Zero out file address
  753.         Mov    [FileOffset + 2],BX
  754.         Mov    [HorizOffset],BX    ; Zero out horizontal offset    
  755.         Mov    SI,Offset Buffer    ; Reset buffer pointer    
  756.         Jz    Dummy            ; Skip file read if in already
  757.         Mov    DX,Offset Buffer    ; Area to read file in
  758.         Mov    CX,32768        ; Number of bytes to read
  759.         Call    FileRead        ; Read in file
  760. Dummy:        Ret
  761.  
  762. Up:        Call    GetPrevChar        ; Get previous char in buffer
  763.         Jc    UpDone            ; If none available, finish
  764. UpLoop:        Call    GetPrevChar        ; Get previous char again
  765.         Jc    UpDone            ; if none, we're done
  766.         Cmp    AL,10            ; Check if line feed
  767.         Jnz    UpLoop            ; If not, try again 
  768.         Call    GetNextChar        ; Get char after line feed
  769. UpDone:        Ret
  770.  
  771. PgUp:        Mov    CX,Word Ptr [ModeData.row]    ; Number of lines
  772.         Dec    CX                ;   less title line
  773.  
  774. PgUpLoop:    Call    Up            ; Do UP that many times
  775.         Loop    PgUpLoop
  776.         Ret
  777.  
  778. Left:        Mov    [HorizOffset],0        ; Reset Horizontal Offset
  779.         Ret
  780.  
  781. Right:        Mov    AL,[ShiftHoriz]        ; Get places to shift
  782.         Sub    AH,AH
  783.         Add    [HorizOffset],AX    ; Move that many right
  784.         Ret
  785.  
  786. EndKey:        Mov    BX,SI            ; Save buffer pointer
  787.         Call    PgDn            ; Go page down
  788.         Cmp    BX,SI            ; Check if we did so
  789.         Jnz    EndKey            ; If so, do it again
  790.         Ret
  791.  
  792. Down:        Call    GetNextChar        ; Get next character
  793.         Jc    NoMoreDown        ; If no more, we're done
  794. DownLoop:    Call    GetNextChar        ; Get one again
  795.         Jc    UpLoop            ; If no more, find prev LF
  796.         Cmp    AL,10            ; See if line feed
  797.         Jnz    DownLoop        ; If not, continue
  798. NoMoreDown:    Ret
  799.  
  800. PgDn:        Mov    CX,Word Ptr [ModeData.row]    ; Number of lines
  801.         Dec    CX                ;   less title line
  802.  
  803. PgDnLoop:    Call    Down            ; Do DOWN that many times
  804.         Loop    PgDnLoop
  805.         Ret
  806. ;---------------
  807. ; Update Screen
  808. ;---------------
  809. UpdateScreen:    Push    ES
  810.  
  811.         Les    DI,[ScreenAddr]        ; Address of display
  812.         Mov    CX,ScreenSize        ; Number of bytes in screen
  813.         Shr    CX,1            ; Half for number of chars
  814.         Mov    AL,' '            ; Will blank screen
  815.         Mov    AH,[Attribute1]        ; With screen attribute
  816.         Rep    Stosw            ; Blank it
  817.         Mov    CX, [ModeData.col]    ; Number of character cols
  818.         Mov    DI, [ScreenOff]        ; Offset of screen
  819.         Mov    SI, Offset FullFileName    ; File name
  820.  
  821. DisplayName:    Lodsb                ; Get character
  822.         Or    AL, AL            ; See if end
  823.         Jz    EndOfName
  824.         Mov    AH, [Attribute2]    ; Use second attribute
  825.         Stosw                ; Display it
  826.         Loop    DisplayName
  827.  
  828. EndOfName:    Mov    SI,[ScreenStart]    ; Address of data in buffer
  829.         Mov    DL, 1            ; Start with second line
  830.         Mov    AL, Byte Ptr [ModeData.col]    ; Length of row
  831.         Sub    AH,AH
  832.         Add    AX,[HorizOffset]    ; Add Horizontal Offset
  833.         Mov    [RightMargin],AX    ; That's right display margin
  834.  
  835. LineLoop:    Sub    BX,BX            ; Column Number
  836.         Mov    AL, Byte Ptr [ModeData.col]    ; Use Line Length
  837.         Mul    DL            ;   and Line Number
  838.         Add    AX,AX            ;     to recalculate
  839.         Mov    DI,AX            ;       display destination
  840.         Add    DI,[ScreenOff]        ; Add beginning address    
  841.  
  842. CharLoop:    Call    GetNextChar        ; Get next character
  843.         Jc    EndOfScreen        ; If no more, we're done
  844.         Cmp    AL,13            ; Check for carriage return
  845.         Je    CharLoop        ; Do nothing if so
  846.         Cmp    AL,10            ; Check for line feed
  847.         Je    LineFeed        ; Do routine if so
  848.         Cmp    AL,9            ; Check for tab
  849.         Je    Tab            ; Do routine if so
  850.         Mov    CX,1            ; Just 1 char to display
  851.  
  852. PrintChar:    Cmp    BX,[HorizOffset]    ; See if we can print it
  853.         Jb    NoPrint        
  854.         Cmp    BX,[RightMargin]    ; See if within margin
  855.         Jae    NoPrint
  856.         Mov    AH,[Attribute1]        ; Attribute for display
  857.  
  858. WriteIt:    Stosw                ; Write without retrace wait
  859. NoPrint:    Inc    BX            ; Bump up line counter
  860.         Loop    PrintChar        ; Do it CX times
  861.         Jmp    CharLoop        ; Then go back to top
  862.  
  863. Tab:        Mov    AX,BX            ; Current column number
  864.         And    AX,07h            ; Take lower three bits
  865.         Mov    CX,8
  866.         Sub    CX,AX            ; Subtract from 8
  867.         Mov    AL,' '            ; Will print CX blanks
  868.         Jmp    PrintChar
  869.  
  870. LineFeed:    Inc    DL            ; Next line
  871.         Cmp    DL,Byte Ptr [ModeData.row]    ; See if down at bottom
  872.         Jb    LineLoop        ; If not, continue
  873.  
  874. EndOfScreen:    Push    0            ; Offset of buffer
  875.         Push    [ScreenSize]        ; Size of buffer
  876.         Push    0            ; Reserved
  877.         OS2Call    VioShowBuf        ; Update the screen
  878.  
  879.         Pop    ES            ; All done -- leave
  880.         Ret
  881. ;--------------------------------
  882. ; Get Next Character from buffer
  883. ;--------------------------------
  884. ;        (Input is SI pointing to buffer, Returns AL, CY if no more)
  885.  
  886. GetNextChar:    Cmp    SI, [EndOfFile]        ; See if at end of file
  887.         Jae    NoMoreNext        ; If so, no more chars
  888.         Cmp    SI, Offset BufferEnd    ; See if at end of buffer
  889.         Jb    CanGetNext        ; If not, just get character
  890.  
  891.         Push    CX            ; Otherwise save registers
  892.         Push    DX
  893.         Push    DI
  894.         Push    ES
  895.         Push    DS            ; Set ES to DS
  896.         Pop    ES            ;   (could be different)
  897.  
  898.         Mov    SI,Offset BufferMid    ; Move 2nd buffer half
  899.         Mov    DI,Offset Buffer    ;   to 1st buffer half    
  900.         Mov    CX,16384       
  901.         Sub    [ScreenStart],CX    ; New buffer pointer
  902.         Rep    Movsb            ; Move them
  903.         Mov    SI,DI            ; SI also buffer pointer
  904.         Add    [FileOffset],32768    ; Adjust file addr to read
  905.         Adc    [FileOffset + 2],0 
  906.         Mov    DX,Offset BufferMid    ; Place to read file
  907.         Mov    CX,16384        ; Number of bytes
  908.         Call    FileRead        ; Read the file
  909.         Sub    [FileOffset],16384    ; Now adjust so reflects
  910.         Sbb    [FileOffset + 2],0    ;   1st half of buffer
  911.  
  912.         Pop    ES            ; Get back registers
  913.         Pop    DI
  914.         Pop    DX
  915.         Pop    CX
  916.  
  917.         Jmp    GetNextChar        ; And try again to get char
  918. CanGetNext:    Lodsb                ; Get the character
  919.         And    AL, 7Fh
  920.         Stc
  921. NoMoreNext:    Cmc                ; So CY set if no more
  922.         Ret                
  923. ;------------------------------------
  924. ; Get Previous Character from buffer
  925. ;------------------------------------
  926. GetPrevChar:    Cmp    SI,Offset Buffer    ; See if at top of buffer
  927.         Ja    CanGetPrev        ; If not, just get character
  928.         Mov    AX,[FileOffset]        ; See if at top of file
  929.         Or    AX,[FileOffset + 2]
  930.         Jz    AtTopAlready        ; If so, can't get anymore
  931.  
  932.         Push    CX            ; Save some registers
  933.         Push    DX
  934.         Push    ES
  935.         Push    DS
  936.         Pop    ES
  937.  
  938.         Mov    SI,Offset Buffer    ; Move 1st half of buffer
  939.         Mov    DI,Offset BufferMid    ;   to 2nd half of buffer
  940.         Mov    CX, 16384
  941.         Add    [ScreenStart], CX    ; New buffer pointer
  942.         Rep    Movsb            ; Do the move
  943.         Sub    [FileOffset], 16384    ; Adjust file addr for read
  944.         Sbb    [FileOffset + 2], 0
  945.         Mov    DX, Offset Buffer    ; Area to read file into
  946.         Mov    CX, 16384        ; Number of bytes
  947.         Call    FileRead        ; Read the file
  948.  
  949.         Pop    ES
  950.         Pop    DX            ; Get back registers
  951.         Pop    CX
  952.  
  953. CanGetPrev:    Dec    SI            ; Move pointer back
  954.         Mov    AL,[SI]            ; Get the character
  955.         And    AL, 7Fh            ; Wipe out high byte
  956.         Stc                ; CY flag reset for success
  957. AtTopAlready:    Cmc                ; CY flag set for no more
  958.         Ret
  959. ;--------------------------------------------
  960. ; Read CX bytes from the file into DX buffer
  961. ;--------------------------------------------
  962. FileRead:    Push    AX            ; Save some registers
  963.         Push    BX
  964.         Mov    [EndOfFile], -1        ; Initialize this
  965.  
  966.         Push    [FileHandle]        ; File handle
  967.         Push    [FileOffset + 2]    ; New pointer (high)
  968.         Push    [FileOffset]        ; New pointer (low)
  969.         Push    0            ; Action
  970.         Push    DS            ; Segment for new pointer
  971.         Push    Offset NewPointer    ; Offset for new pointer
  972.         OS2Call    DosChgFilePtr
  973.  
  974.         Mov    BX, [FileHandle]    ; Read from the file
  975.         Call    MyDosRead
  976.  
  977.         Or    AX, AX            ; See if error
  978.         Mov    AX, [BytesRead]
  979.         Jz    NoReadError        ; If no error, continue
  980.         Sub    AX, AX            ; Otherwise read zero bytes
  981. NoReadError:    Cmp    AX,CX            ; See if 32K has been read
  982.         Je    GotItAll        ; If so, we're home free
  983.         Add    AX,DX            ; Otherwise add to buffer addr
  984.         Mov    [EndOfFile],AX        ; And save as end of file
  985.  
  986. GotItAll:    Pop    BX
  987.         Pop    AX
  988.         Ret
  989.  
  990. _TEXT        ENDS
  991.         END    Entry
  992.