home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / M_EXT23.ZIP / M_EXT.ASM < prev    next >
Assembly Source File  |  1989-08-18  |  58KB  |  1,605 lines

  1.                 page    60,128
  2.                 title   m_ext.asm -- Microsoft Editor Extension
  3.  
  4. ; (c) Copyright Ken Waldron, 1989.
  5. ;               P.O. Box 69807 Stn K, Vancouver, B.C. V5K 4Y7
  6. ;
  7. ;   Permission is granted to use this code and assembled versions of it
  8. ;   for non-commercial purposes, and to distribute these on electronic
  9. ;   bulletin boards provided no special fee is charged for downloading
  10. ;   them. For other uses, please obtain written permission. Microsoft
  11. ;   and Wordstar are registered trademarks of Microsoft Corporation and
  12. ;   Micropro International, respectively.
  13.  
  14. ; Purpose:
  15. ;
  16. ;   This file defines an extension for the Microsoft Editor. The
  17. ;   editor, M.EXE, is shipped with MASM 5.x and MSC 5.x. Documentation
  18. ;   supplied by Microsoft describes how to write an editor extension in
  19. ;   MSC. This extension is written using MASM because I don't own MSC.
  20. ;   I wrote it initially to install a word delete function (see
  21. ;   Pdelword). I tried using an editor macro (pword sdelete), but its
  22. ;   appetite for punctuation, brackets, etc. made it unsuitable for
  23. ;   editing source code. More functions have since been added. All
  24. ;   low-level editor functions have been declared external, and there
  25. ;   are text macros to simplify access to editor ARG structures, so it
  26. ;   should be fairly straightforward to add new functions, however you
  27. ;   will need the editor manual and the skel.* and ext.* files supplied
  28. ;   with the editor to figure it all out.
  29.  
  30. ; New editor functions defined:
  31. ;
  32. ;   Changecase
  33. ;   Pdelword
  34. ;   Quik
  35. ;   Transpose
  36. ;   Fill
  37. ;   Number
  38. ;   Enqueue
  39. ;   Dequeue
  40. ;
  41. ; These are documented where defined below.
  42.  
  43. ; To use
  44. ;
  45. ;   NOTE:  If you've used earlier versions, please note that
  46. ;   =====  the extension name has been changed to m_ext.ZXT.
  47. ;
  48. ;   Place following command in tools.ini file (just after [M] label):
  49. ;      load:m_ext.zxt
  50. ;   Assign the new commands to desired key-chords.  For example:
  51. ;      Changecase:alt+C
  52. ;      Pdelword:alt+T
  53. ;      Quik:ctrl+Q
  54.  
  55. ; To compile:
  56. ;
  57. ;   masm [/Dnomsg] /Mx m_ext;
  58. ;   link /NOI exthdr.obj m_ext.obj, m_ext;
  59. ;   ren m_ext.exe m_ext.ZXT
  60. ;
  61. ;   MASM version 5.1 is required.
  62. ;
  63. ;   exthdr.obj is supplied with the Microsoft editor (if you're using
  64. ;   the protected mode version of the editor, link with exthdrp.obj,
  65. ;   however I don't know if the extension will work in protected mode
  66. ;   as I haven't tried it).
  67. ;
  68. ;   Ignore "warning L4021: no stack segment" from the linker.
  69. ;
  70. ;   When the extension is loaded it announces itself by displaying a
  71. ;   message. If "nomsg" is defined, then the message is suppressed.
  72. ;
  73. ;   An option has been added to control which functions are assembled.
  74. ;   To exclude a function, define a symbol of the form "nofunction",
  75. ;   where "function" is the name of the function to be excluded (to
  76. ;   exclude the queue functions, define "noqueue"). These definitions
  77. ;   may appear on the MASM command line (e.g. /Dnoquik) or may be
  78. ;   inserted in this file just before the data segment.
  79.  
  80. ; Release history:
  81. ;
  82. ; 30-Mar-1989  Release 1.0
  83. ;
  84. ; 02-Apr-1989  Release 1.1
  85. ;              Corrected command type of Pdelword.
  86. ;              Added Quik function.
  87. ;              Added assembler switch to control "loaded" message.
  88. ;
  89. ; 21-Apr-1989  Beta 2.0
  90. ;              Tightened and cleaned up code considerably.
  91. ;              Modified Changecase. It now accepts NOARG or BOXARG, but
  92. ;              no longer accepts STREAMARG (the old code may be found
  93. ;              at the end of this file).
  94. ;              Added Transpose and Fill functions.
  95. ;
  96. ; 01-May-1989  Beta 2.01
  97. ;              Speeded up Fill.
  98. ;              Added Number function.
  99. ;
  100. ; 04-May-1989  Release 2.1
  101. ;              Tidied up documentation.
  102. ;
  103. ; 07-May-1989  Beta 2.11
  104. ;              Corrected misspelled "nomsg" in WhenLoaded.
  105. ;
  106. ; 09-May-1989  Beta 2.2
  107. ;              Tightened code (dispensed with inefficient "push"
  108. ;              macros) and improved documentation.
  109. ;              Added Enqueue and Dequeue functions.
  110. ;
  111. ; 14-May-1989  Release 2.3
  112. ;              Added assembly-time option to control which functions
  113. ;              are included in the extension.
  114. ;              Created a separate documentation file.
  115. ;
  116. ; 16-May-1989  Beta 2.31
  117. ;              Corrected misspelled "noquik" on line 286.
  118. ;              Corrected numbase range check in Number.
  119. ;              A function that accepts a markarg does not need to test
  120. ;              that the markarg is of a type it can handle; args that
  121. ;              resolve to types not specified in the command type of
  122. ;              the function are rejected by the editor, so I've removed
  123. ;              some redundant tests and corrected the docs.
  124. ;              Renamed extension to m_ext.ZXT to preclude accidental
  125. ;              loading by DOS (it hangs the computer).
  126. ;
  127. ; 18-Aug-1989  Release 2.32
  128. ;              Increased size of linebuf to make room for NUL in lines
  129. ;              of maximum length (fixes fatal bug in Pdelword and Fill).
  130.  
  131. ; Considerations for interfacing with MSC:
  132. ;
  133. ;   Chars are passed as ints, with char itself in low byte.
  134. ;
  135. ;   Long ints (or pointers) are stored with low-order word (or offset)
  136. ;   first, but passed by pushing high-order word (or segment) first. 1
  137. ;   byte values are returned in AL, 2 byte values in AX, and 4 byte
  138. ;   values AX (low-order) and DX (high-order).
  139. ;
  140. ;   Only si, di, ds, bp are guarranteed to be preserved across calls.
  141. ;
  142. ;   NULL == 0 (or 0L in compact, large and huge models).
  143. ;
  144. ;   For functions using C calling convention, push parameters right-to-
  145. ;   left.  For functions using pascal convention, push left-to-right.
  146.  
  147. ; Considerations for interfacing with Microsoft editor:
  148. ;
  149. ;   Buffer filled by GETLINE is NUL-terminated. PUTLINE expects same.
  150. ;
  151. ;   Don't store strings to be passed to the editor in segment .CONST.
  152. ;
  153. ;   The fMeta parameter passed to extension functions is equal to 1 if
  154. ;   the Meta key was pressed and 0 otherwise (the editor docs imply
  155. ;   that fMeta will be TRUE (-1) if the Meta key was pressed).
  156.  
  157. ; Considerations for modifying the following code:
  158. ;
  159. ;   When an extension function is called, the editor passes it a far
  160. ;   pointer to an ARG structure which defines the selected text. The
  161. ;   functions below use a convention of loading the pointer into es:di
  162. ;   shortly after they are called, and accessing members of the ARG
  163. ;   structure with macros that refer to es:di. Nasty bugs can result if
  164. ;   you fail to preserve es across calls to built-in editor functions,
  165. ;   since most of them trash it.
  166.  
  167.                 .model  compact, c
  168.  
  169.                 public  WhenLoaded, swiTable, cmdTable
  170.  
  171.                 extrn   pascal REPLACE: near
  172.                 extrn   pascal MOVECUR: near
  173.                 extrn   pascal DELLINE: near
  174.                 extrn   pascal DELBOX: near
  175.                 extrn   pascal DELSTREAM: near
  176.                 extrn   pascal GETLINE: near
  177.                 extrn   pascal ADDFILE: near
  178.                 extrn   pascal DELFILE: near
  179.                 extrn   pascal FILENAMETOHANDLE: near
  180.                 extrn   pascal REMOVEFILE: near
  181.                 extrn   pascal COPYLINE: near
  182.                 extrn   pascal COPYBOX: near
  183.                 extrn   pascal COPYSTREAM: near
  184.                 extrn   pascal PFILETOTOP: near
  185.                 extrn   pascal DISPLAY: near
  186.                 extrn   pascal FILEREAD: near
  187.                 extrn   pascal FILEWRITE: near
  188.                 extrn   pascal SETKEY: near
  189.                 extrn   pascal DOMESSAGE: near
  190.                 extrn   pascal PUTLINE: near
  191.                 extrn   pascal BADARG: near
  192.                 extrn   pascal FILELENGTH: near
  193.                 extrn   pascal GETCURSOR: near
  194.                 extrn   pascal FEXECUTE: near
  195.                 extrn   pascal READCMD: near
  196.                 extrn   pascal READCHAR: near
  197.                 extrn   pascal KBUNHOOK: near
  198.                 extrn   pascal KBHOOK: near
  199.  
  200. ; Some macros to clarify idiomatic instruction usages.
  201.  
  202. zero            macro   reg
  203.                 xor     reg,reg                 ; set register to 0
  204.                 endm
  205.  
  206. setzf           macro
  207.                 cmp     ax,ax                   ; set zero flag
  208.                 endm
  209.  
  210. cmpz            macro   reg
  211.                 or      reg,reg                 ; compare register to 0
  212.                 endm
  213.  
  214. ; The following equates define the bits of a word which specifies how
  215. ; command arguments are to be processed.
  216.  
  217. NOARG           equ     0001h
  218. TEXTARG         equ     0002h
  219. NULLARG         equ     0004h
  220. NULLEOL         equ     0008h
  221. NULLEOW         equ     0010h
  222. LINEARG         equ     0020h
  223. STREAMARG       equ     0040h
  224. BOXARG          equ     0080h
  225. NUMARG          equ     0100h
  226. MARKARG         equ     0200h
  227. BOXSTR          equ     0400h
  228. KEEPMETA        equ     2000h
  229. WINDOWFUNC      equ     4000h
  230. CURSORFUNC      equ     8000h
  231.  
  232. ; Switch types.
  233.  
  234. SWI_BOOLEAN     equ     0
  235. SWI_NUMERIC     equ     1
  236. SWI_SCREEN      equ     4
  237. SWI_SPECIAL     equ     5
  238. RADIX10         equ     0Ah SHL 8
  239. RADIX16         equ     10h SHL 8
  240.  
  241. ; Maximum line length.
  242.  
  243. BUFLEN          equ     250
  244.  
  245. ; Return values.
  246.  
  247. TRUE            equ     -1
  248. FALSE           equ     0
  249.  
  250. ; Text macros to access ARG structure members, assuming that es:di
  251. ; points to the ARG structure.
  252.  
  253. argType$        equ     <word ptr es:[di+ 0]>
  254.  
  255. noarg$y         equ     <word ptr es:[di+ 2]>
  256. noarg$x         equ     <word ptr es:[di+ 6]>
  257.  
  258. textarg$cArg    equ     <word ptr es:[di+ 2]>
  259. textarg$y       equ     <word ptr es:[di+ 4]>
  260. textarg$x       equ     <word ptr es:[di+ 8]>
  261. textarg$pText   equ     <word ptr es:[di+10]>
  262.  
  263. nullarg$cArg    equ     <word ptr es:[di+ 2]>
  264. nullarg$y       equ     <word ptr es:[di+ 4]>
  265. nullarg$x       equ     <word ptr es:[di+ 8]>
  266.  
  267. linearg$cArg    equ     <word ptr es:[di+ 2]>
  268. linearg$yStart  equ     <word ptr es:[di+ 4]>
  269. linearg$yEnd    equ     <word ptr es:[di+ 8]>
  270.  
  271. streamarg$cArg   equ    <word ptr es:[di+ 2]>
  272. streamarg$yStart equ    <word ptr es:[di+ 4]>
  273. streamarg$xStart equ    <word ptr es:[di+ 8]>
  274. streamarg$yEnd   equ    <word ptr es:[di+10]>
  275. streamarg$xEnd   equ    <word ptr es:[di+14]>
  276.  
  277. boxarg$cArg     equ     <word ptr es:[di+ 2]>
  278. boxarg$yTop     equ     <word ptr es:[di+ 4]>
  279. boxarg$yBottom  equ     <word ptr es:[di+ 8]>
  280. boxarg$xLeft    equ     <word ptr es:[di+12]>
  281. boxarg$xRight   equ     <word ptr es:[di+14]>
  282.  
  283.                 .data
  284.  
  285. ; Variables.
  286.  
  287. linebuf         db      "Editor extension loaded.  (c) 1989 Ken Waldron.",0
  288.                 db      (BUFLEN + 1 - ($ - linebuf)) dup (0)
  289. cfile           dw      0                       ; current file handle
  290. col             dw      0                       ; current column
  291. row             dw      0,0                     ; current row
  292.  
  293.               ifndef nofill
  294. fillmargin      dw      72                      ; right margin for Fill
  295.               endif
  296.  
  297.               ifndef nonumber
  298. numcount        dw      0                       ; counter for Number
  299. numstep         dw      1                       ; step value for Number
  300. numwidth        dw      6                       ; field width for Number
  301. numbase         dw      10                      ; print radix for Number
  302. numpad          dw      32                      ; pad char for Number
  303.               endif
  304.  
  305.               ifndef noqueue
  306. qfile           dw      0                       ; queue file handle
  307.               endif
  308.  
  309. ; Constants.
  310.  
  311. nulstr          db      0
  312.  
  313.               ifndef nochangecase
  314. Changecase_name db      "Changecase",0
  315.               endif
  316.  
  317.               ifndef nopdelword
  318. Pdelword_name   db      "Pdelword",0
  319.               endif
  320.  
  321.               ifndef noquik
  322. Quik_name       db      "Quik",0
  323. Quik_E_cmd      db      "Meta Up",0
  324. Quik_R_cmd      db      "Arg Mpage",0
  325. Quik_S_cmd      db      "Meta Begline",0
  326. Quik_D_cmd      db      "Endline",0
  327. Quik_X_cmd      db      "Meta Down",0
  328. Quik_C_cmd      db      "Arg Ppage",0
  329.               endif
  330.  
  331.               ifndef notranspose
  332. Transpose_name  db      "Transpose",0
  333.               endif
  334.  
  335.               ifndef nofill
  336. Fill_name       db      "Fill",0
  337. fillmargin_name db      "fillmargin",0
  338. fillfile_name   db      "<fill>",0
  339.               endif
  340.  
  341.               ifndef nonumber
  342. Number_name     db      "Number",0
  343. numcount_name   db      "numcount",0
  344. numstep_name    db      "numstep",0
  345. numwidth_name   db      "numwidth",0
  346. numbase_name    db      "numbase",0
  347. numpad_name     db      "numpad",0
  348.               endif
  349.  
  350.               ifndef noqueue
  351. Enqueue_name    db      "Enqueue",0
  352. Dequeue_name    db      "Dequeue",0
  353. queuefile_name  db      "<queue>",0
  354.               endif
  355.  
  356. ; Switch table.
  357.  
  358. swiTable        label   byte
  359.  
  360.               ifndef nofill
  361.                 dd      fillmargin_name         ; far pointer to switch name
  362.                 dd      fillmargin              ; far pointer to switch
  363.                 dw      SWI_NUMERIC + RADIX10   ; int switch type
  364.               endif
  365.  
  366.               ifndef nonumber
  367.                 dd      numcount_name
  368.                 dd      numcount
  369.                 dw      SWI_NUMERIC + RADIX10
  370.  
  371.                 dd      numstep_name
  372.                 dd      numstep
  373.                 dw      SWI_NUMERIC + RADIX10
  374.  
  375.                 dd      numwidth_name
  376.                 dd      numwidth
  377.                 dw      SWI_NUMERIC + RADIX10
  378.  
  379.                 dd      numbase_name
  380.                 dd      numbase
  381.                 dw      SWI_NUMERIC + RADIX10
  382.  
  383.                 dd      numpad_name
  384.                 dd      numpad
  385.                 dw      SWI_NUMERIC + RADIX10
  386.               endif
  387.  
  388.                 dd      0                       ; NULL far pointer
  389.                 dd      0                       ; NULL far pointer
  390.                 dw      0                       ; int 0
  391.  
  392. ; Command table.
  393.  
  394. cmdTable        label   byte
  395.  
  396.               ifndef nochangecase
  397.                 dd      Changecase_name         ; far pointer to function name
  398.                 dd      Changecase              ; far pointer to function
  399.                 dw      0                       ; int editor scratch area
  400.                 dw      NOARG or BOXARG or MARKARG or KEEPMETA
  401.                                                 ; int command type
  402.               endif
  403.  
  404.               ifndef nopdelword
  405.                 dd      Pdelword_name
  406.                 dd      Pdelword
  407.                 dw      0
  408.                 dw      NOARG or KEEPMETA
  409.               endif
  410.  
  411.               ifndef noquik
  412.                 dd      Quik_name
  413.                 dd      Quik
  414.                 dw      0
  415.                 dw      CURSORFUNC or KEEPMETA
  416.               endif
  417.  
  418.               ifndef notranspose
  419.                 dd      Transpose_name
  420.                 dd      Transpose
  421.                 dw      0
  422.                 dw      NOARG or KEEPMETA
  423.               endif
  424.  
  425.               ifndef nofill
  426.                 dd      Fill_name
  427.                 dd      Fill
  428.                 dw      0
  429.                 dw      LINEARG or MARKARG or NUMARG or KEEPMETA
  430.               endif
  431.  
  432.               ifndef nonumber
  433.                 dd      Number_name
  434.                 dd      Number
  435.                 dw      0
  436.                 dw      NOARG or NULLARG
  437.               endif
  438.  
  439.               ifndef noqueue
  440.                 dd      Enqueue_name
  441.                 dd      Enqueue
  442.                 dw      0
  443.                 dw      NOARG or LINEARG or MARKARG or NUMARG
  444.  
  445.                 dd      Dequeue_name
  446.                 dd      Dequeue
  447.                 dw      0
  448.                 dw      NOARG
  449.               endif
  450.  
  451.                 dd      0                       ; NULL far pointer
  452.                 dd      0                       ; NULL far pointer
  453.                 dw      0                       ; int 0
  454.                 dw      0                       ; int 0
  455.  
  456.                 .code
  457.  
  458.                 assume  ss:nothing
  459.  
  460. ; Utility procedures.
  461.  
  462. setup           proc
  463.  
  464.                 mov     ax,@data
  465.                 mov     ds,ax
  466.  
  467.                 ; Get current file handle into cfile.
  468.                 mov     ax,offset nulstr
  469.                 push    ds
  470.                 push    ax
  471.                 zero    ax
  472.                 push    ax
  473.                 push    ax
  474.                 call    FILENAMETOHANDLE
  475.                 mov     cfile,ax
  476.  
  477.                 ret
  478.  
  479. setup           endp
  480.  
  481.  
  482. isdigit         proc
  483.  
  484.                 ; Set zero flag if al '0'..'9', otherwise clear.
  485.  
  486.                 cmp     al,'0'
  487.                 jb      no
  488.                 cmp     al,'9'
  489.                 jbe     yes
  490.  
  491.   no:           ret
  492.  
  493.   yes:          setzf
  494.                 ret
  495.  
  496. isdigit         endp
  497.  
  498.  
  499. isalpha         proc
  500.  
  501.                 ; Set zero flag if al is alpha, otherwise clear.
  502.  
  503.                 cmp     al,'A'
  504.                 jb      no
  505.                 cmp     al,'Z'
  506.                 jbe     yes
  507.                 cmp     al,'a'
  508.                 jb      no
  509.                 cmp     al,'z'
  510.                 jbe     yes
  511.  
  512.   no:           ret
  513.  
  514.   yes:          setzf
  515.                 ret
  516.  
  517. isalpha         endp
  518.  
  519.  
  520. xgetline        proc    uses es
  521.  
  522.                 ; Get current row of current file into linebuf.
  523.  
  524.                 push    row[2]                  ; GETLINE( line,
  525.                 push    row[0]                  ;
  526.                 mov     ax,offset linebuf       ;          buf,
  527.                 push    ds                      ;
  528.                 push    ax                      ;
  529.                 push    cfile                   ;          pfile
  530.                 call    GETLINE                 ;                )
  531.                 ret
  532.  
  533. xgetline        endp
  534.  
  535.  
  536. xputline        proc    uses es
  537.  
  538.                 ; Put linebuf to current file at current row.
  539.  
  540.                 push    row[2]                  ; PUTLINE( line,
  541.                 push    row[0]                  ;
  542.                 mov     ax,offset linebuf       ;          buf,
  543.                 push    ds                      ;
  544.                 push    ax                      ;
  545.                 push    cfile                   ;          pFile
  546.                 call    PUTLINE                 ;                )
  547.                 ret
  548.  
  549. xputline        endp
  550.  
  551.  
  552. xgetcursor      proc    uses es
  553.  
  554.                 ; Get current cursor position into row, col.
  555.  
  556.                 push    ds
  557.                 mov     ax,offset col
  558.                 push    ax
  559.                 push    ds
  560.                 mov     ax,offset row
  561.                 push    ax
  562.                 call    GETCURSOR
  563.  
  564.                 ret
  565.  
  566. xgetcursor      endp
  567.  
  568.  
  569. ; Changecase
  570. ;      Toggles the case of an alphabetic character under the cursor.
  571. ;
  572. ; Arg boxarg Changecase
  573. ; Arg markarg Changecase       [the area referenced must be a box]
  574. ;      Changes upper-case characters in specified box to lower-case.
  575. ;
  576. ; Arg Arg boxarg Changecase
  577. ; Arg Arg markarg Changecase   [the area referenced must be a box]
  578. ;      Changes lower-case characters in specified box to upper-case.
  579. ;
  580. ; Returns FALSE if the argument is invalid, otherwise TRUE.
  581.  
  582.               ifndef nochangecase
  583. Changecase      proc    far pascal uses si di ds, \
  584.                         argData: word, pArg: far ptr, fMeta: word
  585.  
  586.                 call    setup
  587.  
  588.                 ; Get ARG struct pointer into es:di
  589.                 les     di,pArg
  590.  
  591.                 ; Determine argument type and act accordingly.
  592.                 test    argType$,BOXARG
  593.                 jnz     doboxarg
  594.  
  595.                 ; NOARG, so toggle case of char under cursor.
  596.   donoarg:      mov     ax,noarg$y[0]           ; init current row
  597.                 mov     row[0],ax
  598.                 mov     ax,noarg$y[2]
  599.                 mov     row[2],ax
  600.                 call    xgetline                ; get current line
  601.                 mov     bx,noarg$x
  602.                 cmp     ax,bx                   ; cursor beyond eol?
  603.                 jbe     nochange
  604.                 mov     al,byte ptr linebuf[bx]
  605.                 call    isalpha                 ; isalpha?
  606.                 jnz     nochange
  607.                 xor     al,020h                 ; toggle case
  608.                 push    ax                      ; REPLACE( c,
  609.                 push    bx                      ;          x,
  610.                 push    noarg$y[2]              ;          y,
  611.                 push    noarg$y[0]              ;
  612.                 push    cfile                   ;          pFile,
  613.                 mov     ax,FALSE                ;          fInsert
  614.                 push    ax                      ;
  615.                 call    REPLACE                 ;                  )
  616.     nochange:   jmp     short done
  617.  
  618.                 ; Loop over lines in box, changing case per cArg.
  619.   doboxarg:     mov     ax,boxarg$yTop[0]       ; init current row
  620.                 mov     row[0],ax
  621.                 mov     ax,boxarg$yTop[2]
  622.                 mov     row[2],ax
  623.  
  624.     dobox:      call    xgetline                ; get current line
  625.  
  626.                 ; Process cx chars at linebuf[bx], where bx=xLeft and
  627.                 ; cx=min(xRight+1,length)-xLeft.  If cx<=1 skip line.
  628.                 ; ax presently holds line length returned by GETLINE.
  629.                 mov     bx,boxarg$xLeft
  630.                 mov     cx,boxarg$xRight
  631.                 inc     cx
  632.                 cmp     ax,cx                   ; xRight beyond eol?
  633.                 ja      @F                      ;   no  -- use xRight
  634.                 mov     cx,ax                   ;   yes -- use length
  635.         @@:     sub     cx,bx                   ; any chars to process?
  636.                 jbe     nextln                  ;   no
  637.  
  638.                 ; Process the line buffer.  Upcase if cArg > 1.
  639.                 mov     si,offset linebuf
  640.                 add     si,bx
  641.                 mov     ax,'AZ'                 ; toggle A..Z (lowcase)
  642.                 cmp     boxarg$cArg,1
  643.                 je      ccase
  644.                 mov     ax,'az'                 ; toggle a..z (upcase)
  645.     ccase:      cmp     byte ptr [si],ah
  646.                 jb      @F
  647.                 cmp     byte ptr [si],al
  648.                 ja      @F
  649.                 xor     byte ptr [si],020h      ; toggle case
  650.         @@:     inc     si
  651.                 loop    ccase
  652.  
  653.                 ; Replace current line with processed buffer.
  654.                 call    xputline
  655.  
  656.                 ; Bump line index, and check whether we're done.
  657.     nextln:     mov     ax,row[0]
  658.                 mov     dx,row[2]
  659.                 add     ax,1
  660.                 adc     dx,0
  661.                 mov     row[0],ax
  662.                 mov     row[2],dx
  663.                 cmp     dx,boxarg$yBottom[2]    ; beyond last line?
  664.                 jg      done
  665.                 cmp     ax,boxarg$yBottom[0]
  666.                 jg      done
  667.                 jmp     short dobox
  668.  
  669.                 ; Return TRUE
  670.   done:         mov     ax,TRUE
  671.                 ret
  672.  
  673. Changecase      endp
  674.               endif
  675.  
  676.  
  677. ; Pdelword
  678. ;      Deletes the character under the cursor and any characters
  679. ;      immediately following which are in the same class. There are two
  680. ;      main character classes: alphanumeric characters and space. Others
  681. ;      (including tab and end-of-line) are in classes of their own.
  682. ;      Deleted text is not copied to the clipboard. The deletions are
  683. ;      undoable.
  684. ;
  685. ; Always returns TRUE.
  686.  
  687.               ifndef nopdelword
  688. Pdelword        proc    far pascal uses si di ds, \
  689.                         argData: word, pArg: far ptr, fMeta: word
  690.  
  691.                 call    setup
  692.  
  693.                 ; Get ARG struct pointer into es:di
  694.                 les     di,pArg
  695.  
  696.                 ; Init current row and get current line into buffer.
  697.                 mov     ax,noarg$y[0]
  698.                 mov     row[0],ax
  699.                 mov     ax,noarg$y[2]
  700.                 mov     row[2],ax
  701.                 call    xgetline
  702.  
  703.                 ; Get buffer pointer into ds:si.
  704.                 mov     si,offset linebuf
  705.  
  706.                 ; Cursor beyond last char of current line? If so, set up
  707.                 ; to delete line break. Line length returned by GETLINE
  708.                 ; is in ax.
  709.                 cmp     noarg$x,ax              ; col < line length?
  710.                 jl      @F
  711.                 add     row[0],1                ; increment row
  712.                 adc     row[2],0
  713.                 jmp     short delete
  714.  
  715.                 ; Set buffer pointer to starting col.
  716.         @@:     add     si,noarg$x
  717.  
  718.                 ; Determine class of current char, scan forward to next
  719.                 ; char not in same class (or NUL at end of line), and
  720.                 ; set up to delete to that char.
  721.                 mov     al,[si]                 ; get char at cursor
  722.                 cmp     al,' '                  ;   and classify it
  723.                 jz      space
  724.                 call    isdigit
  725.                 jz      alnum
  726.                 call    isalpha
  727.                 jz      alnum
  728.  
  729.                 ; Char at cursor is in class of its own.
  730.                 inc     si
  731.                 jmp     short delete
  732.  
  733.                 ; Char at cursor is a space.
  734.   space:        inc     si
  735.                 cmp     byte ptr [si],' '
  736.                 jz      space
  737.                 jmp     short delete
  738.  
  739.                 ; Char at cursor is alphanumeric.
  740.   alnum:        inc     si
  741.                 mov     al,[si]
  742.                 call    isdigit
  743.                 jz      alnum
  744.                 call    isalpha
  745.                 jz      alnum
  746.  
  747.   delete:       sub     si,offset linebuf
  748.                 push    cfile                   ; DELSTREAM( pFile,
  749.                 push    noarg$x                 ;            xStart,
  750.                 push    noarg$y[2]              ;            yStart,
  751.                 push    noarg$y[0]              ;
  752.                 push    si                      ;            xEnd,
  753.                 push    row[2]                  ;            yEnd
  754.                 push    row[0]                  ;
  755.                 call    DELSTREAM               ;                   )
  756.  
  757.                 ; Return TRUE
  758.                 mov     ax,TRUE
  759.                 ret
  760.  
  761. Pdelword        endp
  762.               endif
  763.  
  764.  
  765. ; Quik
  766. ;      I attach this function to ctrl+Q to implement the Wordstar quick
  767. ;      cursor movement commands. It is a replacement for the WS.ZXT
  768. ;      extension supplied with the editor. Changes the interpretation
  769. ;      of ctrl+Q S|D|E|X|R|C slightly, and does not support ctrl+Q
  770. ;      A|F|K|Y. Avoids the need to load two extension files, saving
  771. ;      time and memory, and lets me make ctrl+Q do exactly what I want
  772. ;      (even assign its functionality to a different key than ctrl+Q).
  773. ;
  774. ; Returns the value of the command string executed.
  775.  
  776.               ifndef noquik
  777. Quik            proc    far pascal \
  778.                         argData: word, pArg: far ptr, fMeta: word
  779.  
  780.                 ; Get next keystroke. Look at scan code in ah, put
  781.                 ; offset of appropriate command string in cx, and
  782.                 ; execute it. The scan code for an alpha key is same
  783.                 ; whether or not ctrl, shift, alt have been pressed.
  784.  
  785.                 call    READCHAR
  786.  
  787.                 mov     cx,offset Quik_E_cmd
  788.                 cmp     ah,012h                 ; E
  789.                 je      @F
  790.  
  791.                 mov     cx,offset Quik_R_cmd
  792.                 cmp     ah,013h                 ; R
  793.                 je      @F
  794.  
  795.                 mov     cx,offset Quik_S_cmd
  796.                 cmp     ah,01fh                 ; S
  797.                 je      @F
  798.  
  799.                 mov     cx,offset Quik_D_cmd
  800.                 cmp     ah,020h                 ; D
  801.                 je      @F
  802.  
  803.                 mov     cx,offset Quik_X_cmd
  804.                 cmp     ah,02dh                 ; X
  805.                 je      @F
  806.  
  807.                 mov     cx,offset Quik_C_cmd
  808.                 cmp     ah,02eh                 ; C
  809.                 je      @F
  810.  
  811.                 mov     cx,offset nulstr        ; default (empty string)
  812.  
  813.                 ; Execute (possibly NUL) command and return what it returns.
  814.         @@:     mov     bx,@data                ; segment of command string
  815.                 push    bx
  816.                 push    cx                      ; offset          "
  817.                 call    FEXECUTE
  818.                 ret
  819.  
  820. Quik            endp
  821.               endif
  822.  
  823.  
  824. ; Transpose
  825. ;      Exchanges the character under the cursor with the following
  826. ;      character. If the cursor is at or beyond the last character on
  827. ;      the line, then the last two characters on the line are
  828. ;      exchanged.
  829. ;
  830. ; Always returns TRUE.
  831.  
  832.               ifndef notranspose
  833. Transpose       proc    far pascal uses si di ds, \
  834.                         argData: word, pArg: far ptr, fMeta: word
  835.  
  836.                 call    setup
  837.  
  838.                 ; Get ARG struct pointer into es:di
  839.                 les     di,pArg
  840.  
  841.                 ; Init row.
  842.                 mov     ax,noarg$y[0]
  843.                 mov     row[0],ax
  844.                 mov     ax,noarg$y[2]
  845.                 mov     row[2],ax
  846.  
  847.                 ; Get current line, compare length with cursor column,
  848.                 ; and act accordingly.
  849.                 call    xgetline
  850.                 sub     ax,1
  851.                 jle     done                    ; < 2 chars on line?
  852.                 mov     bx,noarg$x
  853.                 cmp     bx,ax
  854.                 jl      change                  ; cursor inside line?
  855.                 mov     bx,ax                   ; cursor at/beyond last char
  856.                 dec     bx
  857.  
  858.   change:       mov     ax,word ptr linebuf[bx]
  859.                 xchg    al,ah
  860.                 mov     word ptr linebuf[bx],ax
  861.                 call    xputline
  862.  
  863.   done:         mov     ax,TRUE
  864.                 ret
  865.  
  866. Transpose       endp
  867.               endif
  868.  
  869.  
  870. ; Arg linearg Fill
  871. ; Arg numarg Fill
  872. ; Arg markarg Fill     [the area referenced must be a linearg]
  873. ;
  874. ;      Fills the selected lines by rearranging text to the right of the
  875. ;      cursor to fit as many words as possible on each line between the
  876. ;      cursor column and the fill margin. The default fill margin is at
  877. ;      column 72 (this can be changed by assigning a different value to
  878. ;      the numeric switch "fillmargin"). Words are delimited by spaces.
  879. ;      Extra spaces and lines are lost after filling. If a single word
  880. ;      is too long to fit between the cursor column and the fill margin
  881. ;      then the word will spill over the margin.
  882. ;
  883. ; Returns FALSE if the argument is invalid, or if the fillmargin is
  884. ; less than the initial cursor column or greater than BUFLEN. Otherwise
  885. ; returns TRUE.
  886. ;
  887. ; Tip: Fill can be used to break a group of lines into a list of words.
  888. ;      Set fillmargin to 1, mark the lines, and Fill.
  889. ;
  890. ; Bugs:
  891. ;      If the editor switch "trailspace" is on, then trailing spaces
  892. ;      are treated as a word.
  893. ;
  894. ;      Lines which end up "empty" after filling are deleted, even if
  895. ;      they contain text to the left of the cursor.
  896. ;
  897. ;      After a call to Fill, only that one Fill can be undone; the rest
  898. ;      of the undo stack is lost (I don't know why).
  899.  
  900.  
  901.               ifndef nofill
  902. Fill            proc    far pascal uses si di ds, \
  903.                         argData: word, pArg: far ptr, fMeta: word
  904.  
  905.                 local   leftmarg: word, ffile: word, \
  906.                         fcol: word, frow_lo: word, frow_hi: word
  907.  
  908.                 call    setup
  909.  
  910.                 ; Get ARG struct pointer into es:di
  911.                 les     di,pArg
  912.  
  913.                 ; Set left margin to initial cursor column.
  914.                 call    xgetcursor
  915.                 mov     ax,col
  916.                 mov     leftmarg,ax
  917.  
  918.                 ; If fillmargin out of range, return FALSE.
  919.                 mov     ax,FALSE
  920.                 mov     bx,fillmargin
  921.                 cmp     bx,BUFLEN
  922.                 jle     @F
  923.                 jmp     exit
  924.         @@:     cmp     bx,leftmarg
  925.                 jg      @F
  926.                 jmp     exit
  927.  
  928.                 ; Store a zero in si for various uses below.
  929.         @@:     zero    si
  930.  
  931.                 ; Create Fill pseudo file.
  932.                 push    es
  933.                 push    ds
  934.                 mov     ax,offset fillfile_name
  935.                 push    ax
  936.                 call    ADDFILE
  937.                 pop     es
  938.                 mov     ffile,ax
  939.  
  940.                 ; Copy any text to left of leftmarg to fill file.
  941.                 mov     bx,leftmarg
  942.                 sub     bx,1
  943.                 jbe     @F
  944.                 push    es
  945.                 push    cfile                   ; COPYBOX( pFileSrc,
  946.                 push    ffile                   ;          pFileDst,
  947.                 push    si                      ;          xLeft, = 0
  948.                 push    linearg$yStart[2]       ;          yTop,
  949.                 push    linearg$yStart[0]       ;
  950.                 push    bx                      ;          xRight,
  951.                 push    linearg$yEnd[2]         ;          yBottom,
  952.                 push    linearg$yEnd[0]         ;
  953.                 push    si                      ;          xDst,  = 0
  954.                 push    si                      ;          yDst   = 0L
  955.                 push    si                      ;
  956.                 call    COPYBOX                 ;                    )
  957.                 pop     es
  958.  
  959.                 ; Init current row and col for getword. Bias current
  960.                 ; row to first selected line - 1, and set col to -1 to
  961.                 ; signal that a new line must be read.
  962.         @@:     mov     ax,linearg$yStart[0]
  963.                 mov     dx,linearg$yStart[2]
  964.                 sub     ax,1
  965.                 sbb     dx,0
  966.                 mov     row[0],ax
  967.                 mov     row[2],dx
  968.                 mov     col,-1
  969.  
  970.                 ; Init fill row and col.
  971.                 mov     frow_lo,si              ; 0L
  972.                 mov     frow_hi,si
  973.                 mov     bx,leftmarg
  974.                 mov     fcol,bx
  975.  
  976.                 ; Build filled block in fill file. While getword
  977.                 ; returns word length in cx > 0, write word at
  978.                 ; linebuf[si] to fill file. When a row is filled
  979.                 ; bump row index.
  980.  
  981.   dofill:       mov     cx,leftmarg
  982.                 call    getword
  983.                 cmpz    cx
  984.                 jz      cleanup
  985.  
  986.                 ; Would appending this word exceed the fill margin?
  987.                 mov     bx,fcol
  988.                 add     bx,cx
  989.                 cmp     bx,fillmargin
  990.                 jle     @F
  991.  
  992.                 ; Yes, so reset column, and bump row.
  993.                 mov     bx,leftmarg
  994.                 mov     fcol,bx
  995.                 add     frow_lo,1
  996.                 adc     frow_hi,0
  997.  
  998.                 ; Append word.
  999.         @@:     push    es
  1000.                 push    cfile                   ; COPYSTREAM( pFileSrc,
  1001.                 push    ffile                   ;             pFileDst,
  1002.                 mov     bx,si                   ;             xStart,
  1003.                 push    bx                      ;
  1004.                 mov     ax,row[0]               ;             yStart,
  1005.                 mov     dx,row[2]               ;
  1006.                 push    dx                      ;
  1007.                 push    ax                      ;
  1008.                 add     bx,cx                   ;             xEnd,
  1009.                 push    bx                      ;
  1010.                 push    dx                      ;             yEnd,
  1011.                 push    ax                      ;
  1012.                 push    fcol                    ;             xDst,
  1013.                 inc     cx                      ; skip a space after word
  1014.                 add     fcol,cx                 ;
  1015.                 push    frow_hi                 ;             yDst
  1016.                 push    frow_lo                 ;
  1017.                 call    COPYSTREAM              ;                        )
  1018.                 pop     es
  1019.                 jmp     short dofill
  1020.  
  1021.                 ; Delete the original lines.
  1022.   cleanup:      push    es
  1023.                 push    cfile                   ; DELLINE( pFile,
  1024.                 push    linearg$yStart[2]       ;          yStart,
  1025.                 push    linearg$yStart[0]       ;
  1026.                 push    linearg$yEnd[2]         ;          yEnd
  1027.                 push    linearg$yEnd[0]         ;
  1028.                 call    DELLINE                 ;                 )
  1029.                 pop     es
  1030.  
  1031.                 ; Insert filled lines in current file.
  1032.                 zero    ax
  1033.                 push    es
  1034.                 push    ffile                   ; COPYLINE( pFileSrc,
  1035.                 push    cfile                   ;           pFileDst,
  1036.                 push    ax                      ;           yStart, = 0L
  1037.                 push    ax                      ;
  1038.                 push    frow_hi                 ;           yEnd,
  1039.                 push    frow_lo                 ;
  1040.                 push    linearg$yStart[2]       ;           yDst
  1041.                 push    linearg$yStart[0]       ;
  1042.                 call    COPYLINE                ;                    )
  1043.                 pop     es
  1044.  
  1045.                 ; Delete fill file and return TRUE.
  1046.                 push    ffile
  1047.                 call    REMOVEFILE
  1048.                 mov     ax,TRUE
  1049.   exit:         ret
  1050.  
  1051. Fill            endp
  1052.  
  1053.  
  1054. getword         proc
  1055.  
  1056.                 ; Called by Fill. Scans selected text from left margin
  1057.                 ; forward for next word. If no more words returns 0 in
  1058.                 ; cx, otherwise returns word length in cx, and si
  1059.                 ; indexes start of word in linebuf. Expects to receive
  1060.                 ; left margin in cx.
  1061.  
  1062.                 ; Need new line?
  1063.                 mov     si,col
  1064.                 cmp     si,-1
  1065.                 jne     skipspace
  1066.  
  1067.                 ; Yes. Reset si.
  1068.                 mov     si,cx                   ; cx=left margin
  1069.  
  1070.                 ; If already at end of selected text then fail.
  1071.   nextline:     mov     ax,row[0]
  1072.                 mov     dx,row[2]
  1073.                 add     ax,1
  1074.                 adc     dx,0
  1075.                 cmp     dx,linearg$yEnd[2]
  1076.                 jg      fail
  1077.                 cmp     ax,linearg$yEnd[0]
  1078.                 jg      fail
  1079.                 mov     row[0],ax
  1080.                 mov     row[2],dx
  1081.  
  1082.                  ; Get line into linebuf.
  1083.                 call    xgetline
  1084.  
  1085.                 ; If line empty, try next line.
  1086.                 cmp     ax,si
  1087.                 jle     nextline
  1088.  
  1089.                 ; We've got a line. Bias si.
  1090.                 dec     si
  1091.  
  1092.                 ; Get next word.
  1093.   skipspace:    inc     si
  1094.                 cmp     byte ptr linebuf[si],' '
  1095.                 je      skipspace
  1096.                 mov     bx,si                   ; save beginning of word
  1097.   scanword:     cmp     byte ptr linebuf[si],0  ; end of line?
  1098.                 je      iseol
  1099.                 inc     si
  1100.                 cmp     byte ptr linebuf[si],' '; end of word?
  1101.                 jne     scanword
  1102.                 jmp     short noteol
  1103.  
  1104.   iseol:        mov     col,-1
  1105.                 jmp     short done
  1106.  
  1107.   noteol:       mov     col,si
  1108.  
  1109.   done:         mov     cx,si
  1110.                 sub     cx,bx
  1111.                 mov     si,bx
  1112.                 ret
  1113.  
  1114.   fail:         zero    cx
  1115.                 ret
  1116.  
  1117. getword         endp
  1118.               endif
  1119.  
  1120.  
  1121. ; [Meta] Number
  1122. ;      This function is used to generate integer sequences. Each time
  1123. ;      it is called, Number inserts a string representing the current
  1124. ;      value of "numcount" as a base "numbase" integer at the cursor
  1125. ;      position, then increments numcount by the amount of "numstep"
  1126. ;      (which may be negative, in which case numcount is decremented).
  1127. ;      If the Meta prefix is used then the number is right adjusted in
  1128. ;      a field "numwidth" columns wide, padded with the character of
  1129. ;      ASCII value "numpad" (if the number is too long for the field
  1130. ;      then numwidth is ignored).
  1131. ;
  1132. ; [Meta] Arg Number
  1133. ;      As above, except that numcount is not incremented.
  1134. ;
  1135. ; [Meta] Arg Arg Number
  1136. ;      As in first paragraph above, except that numcount is first
  1137. ;      initialized to zero.
  1138. ;
  1139. ; Always returns TRUE.
  1140. ;
  1141. ; Numeric switches        Default value        Legal values
  1142. ; recognized by Number
  1143. ; --------------------    ----------------     -----------------------
  1144. ;      numcount                 0              -32768..32767
  1145. ;      numstep                  1              -32768..32767
  1146. ;      numwidth                 6              1..BUFLEN
  1147. ;      numbase                 10              2..36
  1148. ;      numpad                  32  (space)     1..255
  1149. ;
  1150. ; Bugs:
  1151. ;      Expect weirdness if switches are set out of range. If numbase is
  1152. ;      out of range, Number will use the default base 10 to avoid fatal
  1153. ;      math errors. If numpad is zero, then if padding is used, the NUL
  1154. ;      padding character(s) will truncate the current line before the
  1155. ;      number is inserted. If numpad is otherwise out of range the
  1156. ;      padding character is unpredictable. If numwidth is out of range
  1157. ;      it will be ignored. If numcount is incremented out of range it
  1158. ;      will simply wrap around, changing its sign. If you undo Number,
  1159. ;      numcount will NOT be decremented by the undo.
  1160.  
  1161.               ifndef nonumber
  1162. Number          proc    far pascal uses si di ds, \
  1163.                         argData: word, pArg: far ptr, fMeta: word
  1164.  
  1165.                 call    setup
  1166.  
  1167.                 ; Get cursor position.
  1168.                 call    xgetcursor
  1169.  
  1170.                 ; Get ARG struct pointer into es:di
  1171.                 les     di,pArg
  1172.  
  1173.                 ; Get numcount into ax.
  1174.                 mov     ax,numcount
  1175.  
  1176.                 ; If no arg, continue.
  1177.                 test    argType$,NULLARG
  1178.                 jz      bumpnum
  1179.  
  1180.                 ; If arg count = 1, don't bump numcount.
  1181.                 cmp     nullarg$cArg,1
  1182.                 je      buildnum
  1183.  
  1184.                 ; Arg count > 1, so zero numcount.
  1185.                 zero    ax
  1186.                 mov     numcount,ax
  1187.  
  1188.                 ; Increment numcount.
  1189.   bumpnum:      mov     bx,numstep
  1190.                 add     numcount,bx
  1191.  
  1192.                 ; Build number in linebuf.
  1193.   buildnum:     zero    si
  1194.                 zero    cx                      ; assume no minus sign
  1195.  
  1196.                 ; numcount positive?
  1197.                 cmpz    ax
  1198.                 jge     @F
  1199.  
  1200.                 ; No, so note this, and flip sign.
  1201.                 inc     cx                      ; we do need a minus sign
  1202.                 neg     ax
  1203.  
  1204.                 ; If numbase is out of range, use default radix 10.
  1205.         @@:     mov     bx,numbase
  1206.                 cmp     bx,36
  1207.                 jg      @F
  1208.                 cmp     bx,2
  1209.                 jl      @F
  1210.                 jmp     short gendigits
  1211.         @@:     mov     bx,10
  1212.  
  1213.                 ; Generate digits in reverse order.
  1214.   gendigits:    cwd
  1215.                 idiv    bx
  1216.                 add     dl,'0'
  1217.                 cmp     dl,'9'
  1218.                 jle     @F
  1219.                 add     dl,'a'-'0'-10
  1220.         @@:     mov     linebuf[si],dl
  1221.                 inc     si
  1222.                 cmpz    ax
  1223.                 jnz     gendigits
  1224.  
  1225.                 ; Put minus sign if needed.
  1226.                 cmpz    cx
  1227.                 jz      padnum
  1228.                 mov     linebuf[si],'-'
  1229.                 inc     si
  1230.  
  1231.                 ; Pad if requested and needed.
  1232.   padnum:       cmp     word ptr fMeta,1
  1233.                 jne     putnum
  1234.                 mov     cx,numwidth
  1235.                 sub     cx,si
  1236.                 jle     putnum
  1237.                 mov     ax,si                   ; don't pad if width too great
  1238.                 add     ax,cx
  1239.                 cmp     ax,BUFLEN
  1240.                 jg      putnum
  1241.                 mov     ax,numpad
  1242.         @@:     mov     linebuf[si],al
  1243.                 inc     si
  1244.                 loop    @B
  1245.  
  1246.                 ; Put to file.
  1247.   putnum:       dec     si
  1248.                 push    word ptr linebuf[si]    ; REPLACE( c,
  1249.                 push    col                     ;          x,
  1250.                 push    row[2]                  ;          y,
  1251.                 push    row[0]                  ;
  1252.                 push    cfile                   ;          pFile,
  1253.                 mov     ax,TRUE                 ;          fInsert
  1254.                 push    ax                      ;
  1255.                 call    REPLACE                 ;                  )
  1256.                 inc     col
  1257.                 cmpz    si
  1258.                 jg      putnum
  1259.  
  1260.                 ; Return.
  1261.                 mov     ax,TRUE
  1262.                 ret
  1263.  
  1264. Number          endp
  1265.               endif
  1266.  
  1267.  
  1268. ; [Meta] Enqueue
  1269. ;      Copies the current line to the end of the queue.
  1270. ;
  1271. ; Arg [Arg] [Meta] linearg Enqueue
  1272. ; Arg [Arg] [Meta] numarg Enqueue
  1273. ; Arg [Arg] [Meta] markarg Enqueue [area referenced must be a linearg]
  1274. ;      Copies the selected lines to the end of the queue. If the extra
  1275. ;      Arg prefix is supplied, then the selected lines are deleted
  1276. ;      after they are copied (the deleted lines are not copied to the
  1277. ;      built-in editor clipboard).
  1278. ;
  1279. ; If the Meta prefix is supplied then the contents of the queue are
  1280. ; erased before the new text is appended.
  1281. ;
  1282. ; Returns FALSE if the argument is invalid and TRUE otherwise.
  1283. ;
  1284. ; See also the Dequeue function.
  1285. ;
  1286. ; The queue is a pseudo file maintained by the Enqueue and Dequeue
  1287. ; functions. I use it to gather scattered lines together: Enqueue the
  1288. ; lines in turn, then Dequeue them all at the desired location. The
  1289. ; queue may be used to reverse the order of a group of lines: Enqueue
  1290. ; the lines, then Meta Dequeue them one at a time. The queue is also
  1291. ; handy as an extra clipboard (but note that the queue is strictly
  1292. ; line-oriented).
  1293.  
  1294.               ifndef noqueue
  1295. Enqueue         proc    far pascal uses si di ds, \
  1296.                         argData: word, pArg: far ptr, fMeta: word
  1297.  
  1298.                 call    setup
  1299.  
  1300.                 ; Get queue file handle.
  1301.                 call    getqueue
  1302.  
  1303.                 ; If Meta then clear queue.
  1304.                 cmp     word ptr fMeta,1
  1305.                 jne     @F
  1306.                 push    qfile
  1307.                 call    DELFILE
  1308.  
  1309.                 ; Get index of next available row in queue.
  1310.         @@:     push    qfile
  1311.                 call    FILELENGTH
  1312.                 mov     row[0],ax
  1313.                 mov     row[2],dx
  1314.  
  1315.                 ; Clear si to indicate no delete after copy.
  1316.                 zero    si
  1317.  
  1318.                 ; Get ARG struct pointer into es:di
  1319.                 les     di,pArg
  1320.  
  1321.                 ; Test arg type and act accordingly.
  1322.                 test    argType$,LINEARG
  1323.                 jnz     dolinearg
  1324.  
  1325.                 ; Must be NOARG.
  1326.   donoarg:      mov     ax,noarg$y[0]
  1327.                 mov     bx,noarg$y[2]
  1328.                 mov     cx,ax
  1329.                 mov     dx,bx
  1330.                 jmp     short copy
  1331.  
  1332.                 ; It's a LINEARG.
  1333.   dolinearg:    cmp     linearg$cArg,2
  1334.                 jl      @F
  1335.                 inc     si                      ; do delete after copy
  1336.         @@:     mov     ax,linearg$yStart[0]
  1337.                 mov     bx,linearg$yStart[2]
  1338.                 mov     cx,linearg$yEnd[0]
  1339.                 mov     dx,linearg$yEnd[2]
  1340.  
  1341.                 ; Copy lines to end of queue.
  1342.   copy:         push    ax
  1343.                 push    bx
  1344.                 push    cx
  1345.                 push    dx
  1346.                 push    cfile                   ; COPYLINE( pFileSrc,
  1347.                 push    qfile                   ;           pFileDst,
  1348.                 push    bx                      ;           yStart,
  1349.                 push    ax                      ;
  1350.                 push    dx                      ;           yEnd,
  1351.                 push    cx                      ;
  1352.                 push    row[2]                  ;           yDst
  1353.                 push    row[0]                  ;
  1354.                 call    COPYLINE                ;                    )
  1355.                 pop     dx
  1356.                 pop     cx
  1357.                 pop     bx
  1358.                 pop     ax
  1359.  
  1360.                 ; Delete lines just copied, if requested.
  1361.                 cmpz    si
  1362.                 jz      done
  1363.                 push    cfile                   ; DELLINE( pFile,
  1364.                 push    bx                      ;          yStart,
  1365.                 push    ax                      ;
  1366.                 push    dx                      ;          yEnd
  1367.                 push    cx                      ;
  1368.                 call    DELLINE                 ;                 )
  1369.  
  1370.   done:         mov     ax,TRUE
  1371.                 ret
  1372.  
  1373. Enqueue         endp
  1374.  
  1375.  
  1376. ; Dequeue
  1377. ;      Inserts the contents of the queue at the current line.
  1378. ;
  1379. ; Meta Dequeue
  1380. ;      Inserts the first line of the queue at the current line and
  1381. ;      removes the line from the queue.
  1382. ;
  1383. ; Returns FALSE if queue is empty and TRUE otherwise.
  1384. ;
  1385. ; See the definition of the Enqueue function for more information
  1386. ; about the queue functions and the queue file.
  1387.  
  1388. Dequeue         proc    far pascal uses si di ds, \
  1389.                         argData: word, pArg: far ptr, fMeta: word
  1390.  
  1391.                 call    setup
  1392.  
  1393.                 ; Get queue file handle.
  1394.                 call    getqueue
  1395.  
  1396.                 ; Get queue length into ax:dx
  1397.                 push    qfile
  1398.                 call    FILELENGTH
  1399.  
  1400.                 ; Abort if queue empty.
  1401.                 cmpz    dx
  1402.                 jg      @F
  1403.                 cmpz    ax
  1404.                 jg      @F
  1405.                 mov     ax,FALSE
  1406.                 jmp     short exit
  1407.  
  1408.                 ; Get ARG struct pointer into es:di
  1409.         @@:     les     di,pArg
  1410.  
  1411.                 ; If Meta, set up to copy the first line.
  1412.                 cmp     word ptr fMeta,1
  1413.                 jne     @F
  1414.                 zero    ax
  1415.                 zero    dx
  1416.                 jmp     short copy
  1417.  
  1418.                 ; No Meta, so set up to copy the whole queue.
  1419.         @@:     sub     ax,1
  1420.                 sbb     dx,0
  1421.  
  1422.                 ; Copy as specified.
  1423.   copy:         zero    si
  1424.                 push    qfile                   ; COPYLINE( pFileSrc,
  1425.                 push    cfile                   ;           pFileDst,
  1426.                 push    si                      ;           yStart,
  1427.                 push    si                      ;
  1428.                 push    dx                      ;           yEnd,
  1429.                 push    ax                      ;
  1430.                 push    noarg$y[2]              ;           yDst
  1431.                 push    noarg$y[0]              ;
  1432.                 call    COPYLINE                ;                    )
  1433.  
  1434.                 ; If Meta, delete head of queue.
  1435.                 cmp     word ptr fMeta,1
  1436.                 jne     done
  1437.                 push    qfile                   ; DELLINE( pFile,
  1438.                 push    si                      ;          yStart,
  1439.                 push    si                      ;
  1440.                 push    si                      ;          yEnd
  1441.                 push    si                      ;
  1442.                 call    DELLINE                 ;                 )
  1443.  
  1444.   done:         mov     ax,TRUE
  1445.   exit:         ret
  1446.  
  1447. Dequeue         endp
  1448.  
  1449.  
  1450. getqueue        proc
  1451.  
  1452.                 ; Loads queue file handle into qfile. Creates file if
  1453.                 ; needed. Does not preserve es.
  1454.  
  1455.                 mov     si,offset queuefile_name
  1456.  
  1457.                 push    ds
  1458.                 push    si
  1459.                 zero    ax
  1460.                 push    ax
  1461.                 push    ax
  1462.                 call    FILENAMETOHANDLE
  1463.                 cmpz    ax                      ; NULL?
  1464.                 jnz     done
  1465.  
  1466.                 push    ds
  1467.                 push    si
  1468.                 call    ADDFILE
  1469.  
  1470.   done:         mov     qfile,ax
  1471.                 ret
  1472.  
  1473. getqueue        endp
  1474.               endif
  1475.  
  1476.  
  1477. WhenLoaded      proc
  1478.  
  1479.               ifndef nomsg
  1480.                 mov     ax,@data
  1481.                 push    ax
  1482.                 mov     ax,offset linebuf       ; signon msg is in linebuf
  1483.                 push    ax
  1484.                 call    DOMESSAGE
  1485.               endif
  1486.  
  1487.                 ret
  1488.  
  1489. WhenLoaded      endp
  1490.  
  1491.  
  1492.                 end
  1493.  
  1494.  
  1495. -------------------
  1496.  
  1497. The following is an alternate version of Changecase that accepts a
  1498. streamarg rather than a boxarg. Since this code was last tested, many
  1499. changes have been made to the ARG macros, global variables, utility
  1500. functions, etc, so it **may no longer work**. It is here simply as an
  1501. example of one way to write a function that accepts a streamarg.
  1502.  
  1503. ; Arg streamarg Changecase
  1504. ;      Changes upper-case chars in specified text to lower-case.
  1505. ;
  1506. ; Arg Arg streamarg Changecase
  1507. ;      Changes lower-case chars in specified text to upper-case.
  1508. ;
  1509. ; Always returns TRUE.
  1510.  
  1511. Changecase      proc    far pascal uses si di ds, \
  1512.                         argData: word, pArg: far ptr, fMeta: word
  1513.  
  1514.                 local   lnflag:word
  1515.  
  1516.                 mov     ax,@data
  1517.                 mov     ds,ax
  1518.  
  1519.                 ; Get ARG struct pointer into es:di
  1520.                 les     di,pArg
  1521.  
  1522.                 ; Get current file handle.
  1523.                 pushfp  nulstr
  1524.                 pushfp  NULL
  1525.                 call    FILENAMETOHANDLE
  1526.                 mov     cfile,ax
  1527.  
  1528.                 ; Loop over lines in stream, changing case per cArg.
  1529.                 ; Observe start col on first line, and end col on last
  1530.                 ; (these may be the same line).
  1531.                 mov     ax,streamarg$yStart[0]  ; get starting row
  1532.                 mov     row[0],ax
  1533.                 mov     ax,streamarg$yStart[2]
  1534.                 mov     row[2],ax
  1535.                 mov     lnflag,1                ; 1=first line,2=last,0=other
  1536.  
  1537.   dostream:     push    es
  1538.                 push    row[2]                  ; GETLINE( line,
  1539.                 push    row[0]                  ;
  1540.                 pushfp  linebuf                 ;          buf,
  1541.                 push    cfile                   ;          pfile
  1542.                 call    GETLINE                 ;                )
  1543.                 pop     es
  1544.  
  1545.                 ; We're going to process cx chars at linebuf[bx].
  1546.                 ; Initiallize cx and bx according to which line we're
  1547.                 ; on.  Begin by assuming this is a middle line (bx=0).
  1548.                 ; ax presently holds line length returned by GETLINE.
  1549.                 mov     cx,ax
  1550.                 zero    bx
  1551.  
  1552.                 mov     ax,row[2]
  1553.                 cmp     ax,streamarg$yEnd[2]    ; last line?
  1554.                 jb      @F
  1555.                 mov     ax,row[0]
  1556.                 cmp     ax,streamarg$yEnd[0]
  1557.                 jb      @F
  1558.                 or      lnflag,2                ; set "last line" bit
  1559.                 mov     cx,streamarg$xEnd
  1560.  
  1561.         @@:     test    lnflag,1                ; first line?
  1562.                 jz      @F
  1563.                 xor     lnflag,1                ; clear "first line" bit
  1564.                 mov     bx,streamarg$xStart
  1565.  
  1566.         @@:     sub     cx,bx
  1567.                 jz      nextln                  ; skip empty lines
  1568.  
  1569.                 ; Process the line buffer.  Upcase if cArg > 1.
  1570.                 mov     si,offset linebuf
  1571.                 add     si,bx
  1572.                 cmp     streamarg$cArg,1
  1573.                 ja      @F
  1574.                 mov     ax,'ZA'                 ; set up to locase
  1575.                 jmp     short ccase
  1576.         @@:     mov     ax,'za'                 ; set up to upcase
  1577.     ccase:      cmp     byte ptr [si],al
  1578.                 jb      @F
  1579.                 cmp     byte ptr [si],ah
  1580.                 ja      @F
  1581.                 xor     byte ptr [si],020h      ; toggle case
  1582.         @@:     inc     si
  1583.                 loop    ccase
  1584.  
  1585.                 ; Replace current line with processed buffer.
  1586.                 push    es
  1587.                 push    row[2]                  ; PUTLINE( line,
  1588.                 push    row[0]                  ;
  1589.                 pushfp  linebuf                 ;          buf,
  1590.                 push    cfile                   ;          pfile
  1591.                 call    PUTLINE                 ;                )
  1592.                 pop     es
  1593.  
  1594.                 ; Bump line index, and check whether we're done.
  1595.   nextln:       add     row[0],1
  1596.                 adc     row[2],0
  1597.                 test    lnflag,2                ; was last line processed?
  1598.                 jz      dostream
  1599.  
  1600.                 ; Return TRUE
  1601.                 mov     ax, TRUE
  1602.                 ret
  1603.  
  1604. Changecase      endp
  1605.