home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft_Programmers_Library.7z / MPL / msdos / dossmpl.txt < prev    next >
Encoding:
Text File  |  2013-11-08  |  611.4 KB  |  16,704 lines

  1.  \SAMPCODE
  2.  \SAMPCODE\ADVMSDOS
  3.  \SAMPCODE\ADVMSDOS\CHAP03
  4.  \SAMPCODE\ADVMSDOS\CHAP03\HELLO_C.ASM
  5.  
  6.          title   HELLO.COM --- print hello on terminal
  7.          page    55,132
  8.  
  9.  ;
  10.  ; HELLO-C.ASM   Demonstrates components of a
  11.  ;               functional COM-type assembly
  12.  ;               language program, and an MS-DOS
  13.  ;               function call.
  14.  ;
  15.  ; Copyright (C) 1988 Ray Duncan
  16.  ;
  17.  ; Build:  MASM HELLO-C;
  18.  ;         LINK HELLO-C;
  19.  ;         EXE2BIN HELLO.EXE HELLO.COM
  20.  ;         DEL HELLO.EXE
  21.  ;
  22.  ; Usage:  HELLO
  23.  ;
  24.  
  25.  stdin   equ     0               ; standard input handle
  26.  stdout  equ     1               ; standard output handle
  27.  stderr  equ     2               ; standard error handle
  28.  
  29.  cr      equ     0dh             ; ASCII carriage return
  30.  lf      equ     0ah             ; ASCII line feed
  31.  
  32.  
  33.  _TEXT   segment word public 'CODE'
  34.  
  35.          org     100h            ; COM files always have
  36.                                  ; an origin of 100H
  37.  
  38.          assume  cs:_TEXT,ds:_TEXT,es:_TEXT,ss:_TEXT
  39.  
  40.  print   proc    near            ; entry point from MS-DOS
  41.  
  42.          mov     ah,40h          ; function 40H = write
  43.          mov     bx,stdout       ; handle for standard output
  44.          mov     cx,msg_len      ; length of message
  45.          mov     dx,offset msg   ; address of message
  46.          int     21h             ; transfer to MS-DOS
  47.  
  48.          mov     ax,4c00h        ; exit, return code = 0
  49.          int     21h             ; transfer to MS-DOS
  50.  
  51.  print   endp
  52.  
  53.  
  54.  msg     db      cr,lf           ; message to display
  55.          db      'Hello World!',cr,lf
  56.  
  57.  msg_len equ     $-msg           ; length of message
  58.  
  59.  
  60.  _TEXT   ends
  61.  
  62.          end     print           ; defines entry point
  63.  
  64.  
  65.  \SAMPCODE\ADVMSDOS\CHAP03\HELLO_E.ASM
  66.  
  67.          title   HELLO.EXE --- print Hello on terminal
  68.          page    55,132
  69.  ;
  70.  ; HELLO-E.ASM   Demonstrates components of a
  71.  ;               functional EXE-type assembly
  72.  ;               language program, use of segments,
  73.  ;               and a MS-DOS function call.
  74.  ;
  75.  ; Copyright (C) 1988 Ray Duncan
  76.  ;
  77.  ; Build:   MASM HELLO-E;
  78.  ;          LINK HELLO-E;
  79.  ;
  80.  ; Usage:   HELLO-E
  81.  ;
  82.  
  83.  stdin   equ     0               ; standard input handle
  84.  stdout  equ     1               ; standard output handle
  85.  stderr  equ     2               ; standard error handle
  86.  
  87.  cr      equ     0dh             ; ASCII carriage return
  88.  lf      equ     0ah             ; ASCII line feed
  89.  
  90.  
  91.  _TEXT   segment word public 'CODE'
  92.  
  93.          assume  cs:_TEXT,ds:_DATA,ss:STACK
  94.  
  95.  print   proc    far             ; entry point from MS-DOS
  96.  
  97.          mov     ax,_DATA        ; make our data segment
  98.          mov     ds,ax           ; addressable...
  99.  
  100.          mov     ah,40h          ; function 40h = write
  101.          mov     bx,stdout       ; standard output handle
  102.          mov     cx,msg_len      ; length of message
  103.          mov     dx,offset msg   ; address of message
  104.          int     21h             ; transfer to MS-DOS
  105.  
  106.          mov     ax,4c00h        ; exit, return code = 0
  107.          int     21h             ; transfer to MS-DOS
  108.  
  109.  print   endp
  110.  
  111.  _TEXT   ends
  112.  
  113.  
  114.  _DATA   segment word public 'DATA'
  115.  
  116.  msg     db      cr,lf           ; message to display
  117.          db      'Hello World!',cr,lf
  118.  
  119.  msg_len equ     $-msg           ; length of message
  120.  
  121.  _DATA   ends
  122.  
  123.  
  124.  STACK   segment para stack 'STACK'
  125.  
  126.          db      128 dup (?)
  127.  
  128.  STACK   ends
  129.  
  130.          end     print           ; defines entry point
  131.  
  132.  
  133.  \SAMPCODE\ADVMSDOS\CHAP05
  134.  \SAMPCODE\ADVMSDOS\CHAP05\MOUDEMO.C
  135.  
  136.   /*
  137.      Simple Demo of Int 33H Mouse Driver
  138.      (C) 1988 Ray Duncan
  139.  
  140.      Compile with: CL MOUDEMO.C
  141.  
  142.      Usage:   MOUDEMO  (press both mouse buttons to exit)
  143.  */
  144.  
  145.  #include <stdio.h>
  146.  #include <dos.h>
  147.  
  148.  union REGS regs;
  149.  
  150.  void cls(void);                     /* function prototypes */
  151.  void gotoxy(int, int);
  152.  
  153.  main(int argc, char *argv[])
  154.  {
  155.      int x,y,buttons;                /* some scratch variables */
  156.                                      /* for the mouse state */
  157.  
  158.      regs.x.ax = 0;                  /* reset mouse driver */
  159.      int86(0x33, ®s, ®s);      /* and check status */
  160.  
  161.      if(regs.x.ax == 0)              /* exit if no mouse */
  162.      {   printf("\nMouse not available\n");
  163.          exit(1);
  164.      }
  165.  
  166.      cls();                          /* clear the screen */
  167.      gotoxy(45,0);                   /* and show help info */
  168.      puts("Press Both Mouse Buttons To Exit");
  169.  
  170.      regs.x.ax = 1;                  /* display mouse cursor */
  171.      int86(0x33, ®s, ®s);
  172.  
  173.      do {
  174.          regs.x.ax = 3;              /* get mouse position */
  175.          int86(0x33, ®s, ®s);  /* and button status */
  176.          buttons = regs.x.bx & 3;
  177.          x = regs.x.cx;
  178.          y = regs.x.dx;
  179.  
  180.          gotoxy(0,0);                /* display mouse position */
  181.          printf("X = %3d  Y = %3d", x, y);
  182.  
  183.      } while(buttons != 3);          /* exit if both buttons down */
  184.  
  185.      regs.x.ax = 2;                  /* hide mouse cursor */
  186.      int86(0x33, ®s, ®s);
  187.  
  188.      cls();                          /* display message and exit */
  189.      gotoxy(0,0);
  190.      puts("Have a Mice Day!");
  191.  }
  192.  
  193.  /*
  194.      Clear the screen
  195.  */
  196.  void cls(void)
  197.  {
  198.      regs.x.ax = 0x0600;             /* ROM BIOS video driver */
  199.      regs.h.bh = 7;                  /* Int 10H Function 6 */
  200.      regs.x.cx = 0;                  /* initializes a window */
  201.      regs.h.dh = 24;
  202.      regs.h.dl = 79;
  203.      int86(0x10, ®s, ®s);
  204.  }
  205.  
  206.  /*
  207.      Position cursor to (x,y)
  208.  */
  209.  void gotoxy(int x, int y)
  210.  {
  211.      regs.h.dl = x;                  /* ROM BIOS video driver */
  212.      regs.h.dh = y;                  /* Int 10H Function 2 */
  213.      regs.h.bh = 0;                  /* positions the cursor */
  214.      regs.h.ah = 2;
  215.      int86(0x10, ®s, ®s);
  216.  }
  217.  
  218.  
  219.  \SAMPCODE\ADVMSDOS\CHAP05\TRYBREAK.C
  220.  
  221.  /*
  222.      TRYBREAK.C
  223.  
  224.      Demo of BREAK.ASM Ctrl-Break and Ctrl-C
  225.      interrupt handler, by Ray Duncan
  226.  
  227.      Build:   MASM /Mx BREAK;
  228.               CL TRYBREAK.C BREAK.OBJ
  229.  
  230.      Usage:   TRYBREAK
  231.  
  232.  */
  233.  
  234.  #include <stdio.h>
  235.  
  236.  main(int argc, char *argv[])
  237.  {
  238.      int hit = 0;                    /* flag for keypress */
  239.      int c = 0;                      /* character from keyboard */
  240.      static int flag = 0;            /* true if Ctrl-Break
  241.                                         or Ctrl-C detected */
  242.  
  243.      puts("\n*** TRYBREAK.C running ***\n");
  244.      puts("Press Ctrl-C or Ctrl-Break to test handler,");
  245.      puts("Press the Esc key to exit TRYBREAK.\n");
  246.  
  247.      capture(&flag);                 /* install new Ctrl-C and
  248.                                         Ctrl-Break handler and
  249.                                         pass address of flag */
  250.  
  251.      puts("TRYBREAK has captured interrupt vectors.\n");
  252.  
  253.      while(1)
  254.      {
  255.          hit = kbhit();              /* check for keypress */
  256.                                      /* (MS-DOS sees Ctrl-C
  257.                                         when keyboard polled) */
  258.  
  259.          if(flag != 0)               /* if flag is true, an */
  260.          {                           /* interrupt has occurred */
  261.              puts("\nControl-Break detected.\n");
  262.              flag = 0;               /* reset interrupt flag */
  263.          }
  264.          if(hit != 0)                /* if any key waiting */
  265.          {
  266.              c = getch();            /* read key, exit if Esc */
  267.              if( (c & 0x7f) == 0x1b) break;
  268.              putch(c);               /* otherwise display it */
  269.          }
  270.      }
  271.      release();                      /* restore original Ctrl-C
  272.                                         and Ctrl-Break handlers */
  273.  
  274.      puts("\n\nTRYBREAK has released interrupt vectors.");
  275.  }
  276.  
  277.  \SAMPCODE\ADVMSDOS\CHAP05\BREAK.ASM
  278.  
  279.          title   Ctrl-C & Ctrl-Break Handlers
  280.          page    55,132
  281.  
  282.  ;
  283.  ; Ctrl-C and Ctrl-Break handler for Microsoft C
  284.  ; programs running on IBM PC compatibles
  285.  ;
  286.  ; by Ray Duncan
  287.  ;
  288.  ; Assemble with:  C>MASM /Mx BREAK;
  289.  ;
  290.  ; This module allows C programs to retain control
  291.  ; when the user enters a Ctrl-Break or Ctrl-C.
  292.  ; It uses Microsoft C parameter passing conventions
  293.  ; and assumes the C small memory model.
  294.  ;
  295.  ; The procedure _capture is called to install
  296.  ; a new handler for the Ctrl-C and Ctrl-Break
  297.  ; interrupts (1BH and 23H).  _capture is passed
  298.  ; the address of a static variable, which will be
  299.  ; set to True by the handler whenever a Ctrl-C
  300.  ; or Ctrl-Break is detected.  The C syntax is:
  301.  ;
  302.  ;               static int flag;
  303.  ;               capture(&flag);
  304.  ;
  305.  ; The procedure _release is called by the C program
  306.  ; to restore the original Ctrl-Break and Ctrl-C
  307.  ; handler.  The C syntax is:
  308.  ;
  309.  ;               release();
  310.  ;
  311.  ; The procedure ctrlbrk is the actual interrupt
  312.  ; handler.  It receives control when a software
  313.  ; Int 1BH is executed by the ROM BIOS or Int 23H
  314.  ; is executed by MS-DOS.  It simply sets the C
  315.  ; program's variable to True (1) and returns.
  316.  ;
  317.  
  318.  args    equ     4               ; stack offset of arguments,
  319.                                  ; C small memory model
  320.  
  321.  cr      equ     0dh             ; ASCII carriage return
  322.  lf      equ     0ah             ; ASCII line feed
  323.  
  324.  
  325.  _TEXT   segment word public 'CODE'
  326.  
  327.          assume cs:_TEXT
  328.  
  329.  
  330.          public  _capture
  331.  _capture proc   near            ; take over Control-Break
  332.                                  ; and Ctrl-C interrupt vectors
  333.  
  334.          push    bp              ; set up stack frame
  335.          mov     bp,sp
  336.  
  337.          push    ds              ; save affected registers
  338.          push    di
  339.          push    si
  340.  
  341.                                  ; save address of
  342.                                  ; calling program's "flag"
  343.          mov     ax,word ptr [bp+args]
  344.          mov     word ptr cs:flag,ax
  345.          mov     word ptr cs:flag+2,ds
  346.  
  347.                                  ; save address of original
  348.          mov     ax,3523h        ; Int 23H handler
  349.          int     21h
  350.          mov     word ptr cs:int23,bx
  351.          mov     word ptr cs:int23+2,es
  352.  
  353.          mov     ax,351bh        ; save address of original
  354.          int     21h             ; Int 1BH handler
  355.          mov     word ptr cs:int1b,bx
  356.          mov     word ptr cs:int1b+2,es
  357.  
  358.          push    cs              ; set DS:DX = address
  359.          pop     ds              ; of new handler
  360.          mov     dx,offset _TEXT:ctrlbrk
  361.  
  362.          mov     ax,02523H       ; set Int 23H vector
  363.          int     21h
  364.  
  365.          mov     ax,0251bH       ; set Int 1BH vector
  366.          int     21h
  367.  
  368.          pop     si              ; restore registers
  369.          pop     di
  370.          pop     ds
  371.  
  372.          pop     bp              ; discard stack frame
  373.          ret                     ; and return to caller
  374.  
  375.  _capture endp
  376.  
  377.  
  378.          public  _release
  379.  _release proc   near            ; restore original Ctrl-C
  380.                                  ; and Ctrl-Break handlers
  381.  
  382.          push    bp              ; save registers
  383.          push    ds
  384.          push    di
  385.          push    si
  386.  
  387.          lds     dx,cs:int1b     ; get address of previous
  388.                                  ; Int 1BH handler
  389.  
  390.          mov     ax,251bh        ; set Int 1BH vector
  391.          int     21h
  392.  
  393.          lds     dx,cs:int23     ; get address of previous
  394.                                  ; Int 23H handler
  395.  
  396.          mov     ax,2523h        ; set Int 23H vector
  397.          int     21h
  398.  
  399.          pop     si              ; restore registers
  400.          pop     di              ; and return to caller
  401.          pop     ds
  402.          pop     bp
  403.          ret
  404.  
  405.  _release endp
  406.  
  407.  
  408.  ctrlbrk proc    far             ; Ctrl-C and Ctrl-Break
  409.                                  ; interrupt handler
  410.  
  411.          push    bx              ; save registers
  412.          push    ds
  413.  
  414.  
  415.          lds     bx,cs:flag      ; get address of C program's
  416.                                  ; "flag variable"
  417.  
  418.                                  ; and set the flag "true"
  419.          mov     word ptr ds:[bx],1
  420.  
  421.          pop     ds              ; restore registers
  422.          pop     bx
  423.  
  424.          iret                    ; return from handler
  425.  
  426.  ctrlbrk endp
  427.  
  428.  
  429.  flag    dd      0               ; far pointer to caller's
  430.                                  ; Ctrl-Break or Ctrl-C flag
  431.  
  432.  int23   dd      0               ; address of original
  433.                                  ; Ctrl-C handler
  434.  
  435.  int1b   dd      0               ; address of original
  436.                                  ; Ctrl-Break handler
  437.  
  438.  _TEXT   ends
  439.  
  440.          end
  441.  
  442.  
  443.  \SAMPCODE\ADVMSDOS\CHAP07
  444.  \SAMPCODE\ADVMSDOS\CHAP07\TALK.ASM
  445.  
  446.          title   TALK --- Simple terminal emulator
  447.          page    55,132
  448.          .lfcond             ;list false conditionals too
  449.  
  450.  ;
  451.  ; TALK.ASM  --- Simple IBM PC terminal emulator
  452.  ;
  453.  ; Copyright (c) 1988 Ray Duncan
  454.  ;
  455.  ; Build:  MASM TALK;
  456.  ;         LINK TALK;
  457.  ;
  458.  ; Usage:  TALK
  459.  ;
  460.  
  461.  stdin   equ     0               ; standard input handle
  462.  stdout  equ     1               ; standard output handle
  463.  stderr  equ     2               ; standard error handle
  464.  
  465.  cr      equ     0dh             ; ASCII carriage return
  466.  lf      equ     0ah             ; ASCII line feed
  467.  bsp     equ     08h             ; ASCII backspace
  468.  escape  equ     1bh             ; ASCII escape code
  469.  
  470.  dattr   equ     07h             ; display attribute to use
  471.                                  ; while in emulation mode
  472.  
  473.  bufsiz  equ     4096            ; size of serial port buffer
  474.  
  475.  echo    equ     0               ; 0=full-duplex, -1=half-duplex
  476.  
  477.  true    equ     -1
  478.  false   equ     0
  479.  
  480.  com1    equ     true            ; Use COM1 if nonzero
  481.  com2    equ     not com1        ; Use COM2 if nonzero
  482.  
  483.  pic_mask  equ   21h             ; 8259 int. mask port
  484.  pic_eoi   equ   20h             ; 8259 EOI port
  485.  
  486.          if      com1
  487.  com_data equ    03f8h           ; port assignments for COM1
  488.  com_ier  equ    03f9h
  489.  com_mcr  equ    03fch
  490.  com_sts  equ    03fdh
  491.  com_int  equ    0ch             ; COM1 interrupt number
  492.  int_mask equ    10h             ; IRQ4 mask for 8259
  493.          endif
  494.  
  495.          if      com2
  496.  com_data equ    02f8h           ; port assignments for COM2
  497.  com_ier  equ    02f9h
  498.  com_mcr  equ    02fch
  499.  com_sts  equ    02fdh
  500.  com_int  equ    0bh             ; COM2 interrupt number
  501.  int_mask equ    08h             ; IRQ3 mask for 8259
  502.          endif
  503.  
  504.  _TEXT   segment word public 'CODE'
  505.  
  506.          assume  cs:_TEXT,ds:_DATA,es:_DATA,ss:STACK
  507.  
  508.  talk    proc    far             ; entry point from MS-DOS
  509.  
  510.          mov     ax,_DATA        ; make data segment addressable
  511.          mov     ds,ax
  512.          mov     es,ax
  513.                                  ; initialize display for
  514.                                  ; terminal emulator mode...
  515.  
  516.          mov     ah,15           ; get display width and
  517.          int     10h             ; current display mode
  518.          dec     ah              ; save display width for use
  519.          mov     columns,ah      ; by the screen clear routine
  520.  
  521.          cmp     al,7            ; enforce text display mode
  522.          je      talk2           ; mode 7 ok, proceed
  523.  
  524.          cmp     al,3
  525.          jbe     talk2           ; modes 0-3 ok,proceed
  526.  
  527.          mov     dx,offset msg1
  528.          mov     cx,msg1_len
  529.          jmp     talk6           ; print error message and exit
  530.  
  531.  talk2:  mov     bh,dattr        ; clear screen and home cursor
  532.          call    cls
  533.  
  534.          call    asc_enb         ; capture serial port interrupt
  535.                                  ; vector and enable interrupts
  536.  
  537.          mov     dx,offset msg2  ; display message
  538.          mov     cx,msg2_len     ; 'Terminal emulator running'
  539.          mov     bx,stdout       ; BX = standard output handle
  540.          mov     ah,40h          ; Fxn 40H = write file or device
  541.          int     21h             ; transfer to MS-DOS
  542.  
  543.  talk3:  call    pc_stat         ; keyboard character waiting?
  544.          jz      talk4           ; nothing waiting, jump
  545.  
  546.          call    pc_in           ; read keyboard character
  547.  
  548.          cmp     al,0            ; is it a function key?
  549.          jne     talk32          ; not function key, jump
  550.  
  551.          call    pc_in           ; function key, discard 2nd
  552.                                  ; character of sequence
  553.          jmp     talk5           ; then terminate program
  554.  
  555.  talk32:                         ; keyboard character received
  556.          if      echo
  557.          push    ax              ; if half-duplex, echo
  558.          call    pc_out          ; character to PC display
  559.          pop     ax
  560.          endif
  561.  
  562.          call    com_out         ; write char. to serial port
  563.  
  564.  talk4:  call    com_stat        ; serial port character waiting?
  565.          jz      talk3           ; nothing waiting, jump
  566.  
  567.          call    com_in          ; read serial port character
  568.  
  569.          cmp     al,20h          ; is it control code?
  570.          jae     talk45          ; jump if not
  571.  
  572.          call    ctrl_code       ; control code, process it
  573.  
  574.          jmp     talk3           ; check keyboard again
  575.  
  576.  talk45:                         ; non-control char. received,
  577.          call    pc_out          ; write it to PC display
  578.  
  579.          jmp     talk4           ; see if any more waiting
  580.  
  581.  talk5:                          ; function key detected,
  582.                                  ; prepare to terminate...
  583.  
  584.          mov     bh,07h          ; clear screen and home cursor
  585.          call    cls
  586.  
  587.          mov     dx,offset msg3  ; display farewell message
  588.          mov     cx,msg3_len
  589.  
  590.  talk6:  push    dx              ; save message address
  591.          push    cx              ; and message length
  592.  
  593.          call    asc_dsb         ; disable serial port interrupts
  594.                                  ; and release interrupt vector
  595.  
  596.          pop     cx              ; restore message length
  597.          pop     dx              ; and address
  598.  
  599.          mov     bx,stdout       ; handle for standard output
  600.          mov     ah,40h          ; Fxn 40H = write device
  601.          int     21h             ; transfer to MS-DOS
  602.  
  603.          mov     ax,4c00h        ; terminate program with
  604.          int     21h             ; return code = 0
  605.  
  606.  talk    endp
  607.  
  608.  
  609.  com_stat proc   near            ; Check asynch status, returns
  610.                                  ; Z=false if character ready
  611.                                  ; Z=true if nothing waiting
  612.          push    ax
  613.          mov     ax,asc_in       ; compare ring buffer pointers
  614.          cmp     ax,asc_out
  615.          pop     ax
  616.          ret                     ; return to caller
  617.  
  618.  com_stat endp
  619.  
  620.  
  621.  com_in  proc    near            ; get character from serial
  622.                                  ; port buffer, returns
  623.                                  ; new character in AL
  624.  
  625.          push    bx              ; save register BX
  626.  
  627.  com_in1:                        ; if no char waiting, wait
  628.          mov     bx,asc_out      ; until one is received
  629.          cmp     bx,asc_in
  630.          je      com_in1         ; jump, nothing waiting
  631.  
  632.          mov     al,[bx+asc_buf] ; character is ready,
  633.                                  ; extract it from buffer
  634.  
  635.          inc     bx              ; update buffer pointer
  636.          cmp     bx,bufsiz
  637.          jne     com_in2
  638.          xor     bx,bx           ; reset pointer if wrapped
  639.  com_in2:
  640.          mov     asc_out,bx      ; store updated pointer
  641.          pop     bx              ; restore register BX
  642.          ret                     ; and return to caller
  643.  
  644.  com_in  endp
  645.  
  646.  
  647.  com_out proc    near            ; write character in AL
  648.                                  ; to serial port
  649.  
  650.          push    dx              ; save register DX
  651.          push    ax              ; save character to send
  652.          mov     dx,com_sts      ; DX = status port address
  653.  
  654.  com_out1:                       ; check if transmit buffer
  655.          in      al,dx           ; is empty (TBE bit = set)
  656.          and     al,20h
  657.          jz      com_out1        ; no, must wait
  658.  
  659.          pop     ax              ; get character to send
  660.          mov     dx,com_data     ; DX = data port address
  661.          out     dx,al           ; transmit the character
  662.          pop     dx              ; restore register DX
  663.          ret                     ; and return to caller
  664.  
  665.  com_out endp
  666.  
  667.  
  668.  pc_stat proc    near            ; read keyboard status, returns
  669.                                  ; Z=false if character ready
  670.                                  ; Z=true if nothing waiting.
  671.                                  ; register DX destroyed.
  672.  
  673.          mov     al,in_flag      ; if character already
  674.          or      al,al           ; waiting, return status
  675.          jnz     pc_stat1
  676.  
  677.          mov     ah,6            ; otherwise call MS-DOS to
  678.          mov     dl,0ffh         ; determine keyboard status
  679.          int     21h
  680.  
  681.          jz      pc_stat1        ; jump if no key ready
  682.  
  683.          mov     in_char,al      ; got key, save it for
  684.          mov     in_flag,0ffh    ; "pc_in" routine
  685.  
  686.  pc_stat1:                       ; return to caller with
  687.          ret                     ; Z flag set appropriately
  688.  
  689.  pc_stat endp
  690.  
  691.  
  692.  pc_in   proc    near            ; read keyboard character,
  693.                                  ; return it in AL
  694.                                  ; DX may be destroyed.
  695.  
  696.          mov     al,in_flag      ; key already waiting?
  697.          or      al,al
  698.          jnz     pc_in1          ; yes,return it to caller
  699.  
  700.          call    pc_stat         ; try and read a character
  701.          jmp     pc_in
  702.  
  703.  pc_in1: mov     in_flag,0       ; clear char. waiting flag
  704.          mov     al,in_char      ; and return AL = character
  705.          ret
  706.  
  707.  pc_in   endp
  708.  
  709.  
  710.  pc_out  proc    near            ; write character in AL
  711.                                  ; to the PC's display.
  712.  
  713.          mov     ah,0eh          ; ROM BIOS Fxn 0EH =
  714.                                  ; "teletype output"
  715.          push    bx              ; save register BX
  716.          xor     bx,bx           ; assume page 0
  717.          int     10h             ; transfer to ROM BIOS
  718.          pop     bx              ; restore register BX
  719.          ret                     ; and return to caller
  720.  
  721.  pc_out  endp
  722.  
  723.  
  724.  cls     proc    near            ; clear display using
  725.                                  ; char. attribute in BH
  726.                                  ; registers AX, CX,
  727.                                  ; and DX destroyed.
  728.  
  729.          mov     dl,columns      ; set DL,DH = X,Y of
  730.          mov     dh,24           ; lower right corner
  731.          mov     cx,0            ; set CL,CH=X,Y of
  732.                                  ; upper left corner
  733.          mov     ax,600h         ; ROM BIOS Fxn 06H =
  734.                                  ; "scroll or initialize
  735.                                  ; window"
  736.          int     10h             ; transfer to ROM BIOS
  737.          call    home            ; set cursor at (0,0)
  738.          ret                     ; and return to caller
  739.  
  740.  cls     endp
  741.  
  742.  
  743.  clreol  proc    near            ; clear from cursor to end
  744.                                  ; of line using attribute
  745.                                  ; in BH.  Register AX, CX,
  746.                                  ; and DX destroyed.
  747.  
  748.          call    getxy           ; get current cursor pos'n
  749.          mov     cx,dx           ; current position = "upper
  750.                                  ; left corner" of window
  751.          mov     dl,columns      ; "lower right corner" X is
  752.                                  ; max columns, Y is same
  753.                                  ; as upper left corner
  754.          mov     ax,600h         ; ROM BIOS Fxn 06H =
  755.                                  ; "scroll or initialize
  756.                                  ; window"
  757.          int     10h             ; transfer to ROM BIOS
  758.          ret                     ; return to caller
  759.  
  760.  clreol  endp
  761.  
  762.  
  763.  home    proc    near            ; put cursor at home position
  764.  
  765.          mov     dx,0            ; set (X,Y) = (0,0)
  766.          call    gotoxy          ; position the cursor
  767.          ret                     ; return to caller
  768.  
  769.  home    endp
  770.  
  771.  
  772.  gotoxy  proc    near            ; position the cursor
  773.                                  ; call with DL=X, DH=Y
  774.  
  775.          push    bx              ; save registers
  776.          push    ax
  777.  
  778.          mov     bh,0            ; assume page 0
  779.          mov     ah,2            ; ROM BIOS Fxn 02H =
  780.                                  ; set cursor position
  781.          int     10h             ; transfer to ROM BIOS
  782.  
  783.          pop     ax              ; restore registers
  784.          pop     bx
  785.          ret                     ; and return to caller
  786.  
  787.  gotoxy  endp
  788.  
  789.  
  790.  getxy   proc    near            ; get cursor position,
  791.                                  ; Returns DL=X, DH=Y
  792.  
  793.          push    ax              ; save registers
  794.          push    bx
  795.          push    cx
  796.  
  797.          mov     ah,3            ; ROM BIOS Fxn 03H =
  798.                                  ; get cursor position
  799.          mov     bh,0            ; assume page 0
  800.          int     10h             ; transfer to ROM BIOS
  801.  
  802.          pop     cx              ; restore registers
  803.          pop     bx
  804.          pop     ax
  805.          ret                     ; and return to caller
  806.  
  807.  getxy   endp
  808.  
  809.  
  810.  ctrl_code proc  near            ; process control code
  811.                                  ; call with AL=char
  812.  
  813.          cmp     al,cr           ; if carriage return
  814.          je      ctrl8           ; just send it
  815.  
  816.          cmp     al,lf           ; if line feed
  817.          je      ctrl8           ; just send it
  818.  
  819.          cmp     al,bsp          ; if backspace
  820.          je      ctrl8           ; just send it
  821.  
  822.          cmp     al,26           ; is it cls control code?
  823.          jne     ctrl7           ; no, jump
  824.  
  825.          mov     bh,dattr        ; cls control code, clear
  826.          call    cls             ; screen and home cursor
  827.  
  828.          jmp     ctrl9
  829.  
  830.  ctrl7:
  831.          cmp     al,escape       ; is it Escape character?
  832.          jne     ctrl9           ; no, throw it away
  833.  
  834.          call    esc_seq         ; yes, emulate CRT terminal
  835.          jmp     ctrl9
  836.  
  837.  ctrl8:  call    pc_out          ; send CR, LF, or backspace
  838.                                  ; to the display
  839.  
  840.  ctrl9:  ret                     ; return to caller
  841.  
  842.  ctrl_code endp
  843.  
  844.  
  845.  esc_seq proc    near            ; decode Televideo 950 escape
  846.                                  ; sequence for screen control
  847.  
  848.          call    com_in          ; get next character
  849.          cmp     al,84           ; is it clear to end of line?
  850.          jne     esc_seq1        ; no, jump
  851.  
  852.          mov     bh,dattr        ; yes, clear to end of line
  853.          call    clreol
  854.          jmp     esc_seq2        ; then exit
  855.  
  856.  esc_seq1:
  857.          cmp     al,61           ; is it cursor positioning?
  858.          jne     esc_seq2        ; no jump
  859.  
  860.          call    com_in          ; yes, get Y parameter
  861.          sub     al,33           ; and remove offset
  862.          mov     dh,al
  863.  
  864.          call    com_in          ; get X parameter
  865.          sub     al,33           ; and remove offset
  866.          mov     dl,al
  867.          call    gotoxy          ; position the cursor
  868.  
  869.  esc_seq2:                       ; return to caller
  870.          ret
  871.  
  872.  esc_seq endp
  873.  
  874.  
  875.  asc_enb proc    near            ; capture serial port interrupt
  876.                                  ; vector and enable interrupt
  877.  
  878.                                  ; save address of previous
  879.                                  ; interrupt handler...
  880.          mov     ax,3500h+com_int ; Fxn 35H = get vector
  881.          int     21h             ; transfer to MS-DOS
  882.          mov     word ptr oldvec+2,es
  883.          mov     word ptr oldvec,bx
  884.  
  885.                                  ; now install our handler...
  886.          push    ds              ; save our data segment
  887.          mov     ax,cs           ; set DS:DX = address
  888.          mov     ds,ax           ; of our interrupt handler
  889.          mov     dx,offset asc_int
  890.          mov     ax,2500h+com_int ; Fxn 25H = set vector
  891.          int     21h             ; transfer to MS-DOS
  892.          pop     ds              ; restore data segment
  893.  
  894.          mov     dx,com_mcr      ; set modem control register
  895.          mov     al,0bh          ; DTR and OUT2 bits
  896.          out     dx,al
  897.  
  898.          mov     dx,com_ier      ; set interrupt enable
  899.          mov     al,1            ; register on serial
  900.          out     dx,al           ; port controller
  901.  
  902.          in      al,pic_mask     ; read current 8259 mask
  903.          and     al,not int_mask ; set mask for COM port
  904.          out     pic_mask,al     ; write new 8259 mask
  905.  
  906.          ret                     ; back to caller
  907.  
  908.  asc_enb endp
  909.  
  910.  
  911.  asc_dsb proc    near            ; disable interrupt and
  912.                                  ; release interrupt vector
  913.  
  914.          in      al,pic_mask     ; read current 8259 mask
  915.          or      al,int_mask     ; reset mask for COM port
  916.          out     pic_mask,al     ; write new 8259 mask
  917.  
  918.          push    ds              ; save our data segment
  919.          lds     dx,oldvec       ; load address of
  920.                                  ; previous interrupt handler
  921.          mov     ax,2500h+com_int ; Fxn 25H = set vector
  922.          int     21h             ; transfer to MS-DOS
  923.          pop     ds              ; restore data segment
  924.  
  925.          ret                     ; back to caller
  926.  
  927.  asc_dsb endp
  928.  
  929.  
  930.  asc_int proc    far             ; interrupt service routine
  931.                                  ; for serial port
  932.  
  933.          sti                     ; turn interrupts back on
  934.  
  935.          push    ax              ; save registers
  936.          push    bx
  937.          push    dx
  938.          push    ds
  939.  
  940.          mov     ax,_DATA        ; make our data segment
  941.          mov     ds,ax           ; addressable
  942.  
  943.          cli                     ; clear interrupts for
  944.                                  ; pointer manipulation
  945.  
  946.          mov     dx,com_data     ; DX = data port address
  947.          in      al,dx           ; read this character
  948.  
  949.          mov     bx,asc_in       ; get buffer pointer
  950.          mov     [asc_buf+bx],al ; store this character
  951.          inc     bx              ; bump pointer
  952.          cmp     bx,bufsiz       ; time for wrap?
  953.          jne     asc_int1        ; no, jump
  954.          xor     bx,bx           ; yes,reset pointer
  955.  
  956.  asc_int1:                       ; store updated pointer
  957.          mov     asc_in,bx
  958.  
  959.          sti                     ; turn interrupts back on
  960.  
  961.          mov     al,20h          ; send EOI to 8259
  962.          out     pic_eoi,al
  963.  
  964.          pop     ds              ; restore all registers
  965.          pop     dx
  966.          pop     bx
  967.          pop     ax
  968.  
  969.          iret                    ; return from interrupt
  970.  
  971.  asc_int endp
  972.  
  973.  _TEXT   ends
  974.  
  975.  
  976.  _DATA   segment word public 'DATA'
  977.  
  978.  in_char db      0               ; PC keyboard input char.
  979.  in_flag db      0               ; <>0 if char waiting
  980.  
  981.  columns db      0               ; highest numbered column in
  982.                                  ; current display mode (39 or 79)
  983.  
  984.  msg1    db      cr,lf
  985.          db      'Display must be text mode.'
  986.          db      cr,lf
  987.  msg1_len equ $-msg1
  988.  
  989.  msg2    db      'Terminal emulator running...'
  990.          db      cr,lf
  991.  msg2_len equ $-msg2
  992.  
  993.  msg3    db      'Exit from terminal emulator.'
  994.          db      cr,lf
  995.  msg3_len equ $-msg3
  996.  
  997.  oldvec  dd      0               ; original contents of serial
  998.                                  ; port interrupt vector
  999.  
  1000.  asc_in  dw      0               ; input pointer to ring buffer
  1001.  asc_out dw      0               ; output pointer to ring buffer
  1002.  
  1003.  asc_buf db      bufsiz dup (?)  ; communications buffer
  1004.  
  1005.  _DATA   ends
  1006.  
  1007.  
  1008.  STACK   segment para stack 'STACK'
  1009.  
  1010.          db      128 dup (?)
  1011.  
  1012.  STACK   ends
  1013.  
  1014.          end     talk            ;  defines entry point
  1015.  
  1016.  
  1017.  \SAMPCODE\ADVMSDOS\CHAP08
  1018.  \SAMPCODE\ADVMSDOS\CHAP08\DUMP.C
  1019.  
  1020.  /*
  1021.      DUMP.C      Displays the binary contents of a file in
  1022.                  hex and ASCII on the standard output device.
  1023.  
  1024.      Compile:    C>CL DUMP.C
  1025.  
  1026.      Usage:      C>DUMP unit:path\filename.ext  [ >device ]
  1027.  
  1028.      Copyright (C) 1988 Ray Duncan
  1029.  */
  1030.  
  1031.  #include <stdio.h>
  1032.  #include <io.h>
  1033.  #include <fcntl.h>
  1034.  
  1035.  #define REC_SIZE 16             /* input file record size */
  1036.  
  1037.  main(int argc, char *argv[])
  1038.  {
  1039.      int fd;                     /* input file handle */
  1040.      int status = 0;             /* status from file read */
  1041.      long fileptr = 0L;          /* current file byte offset */
  1042.      char filebuf[REC_SIZE];     /* data from file */
  1043.  
  1044.      if(argc != 2)               /* abort if missing filename */
  1045.      {   fprintf(stderr,"\ndump: wrong number of parameters\n");
  1046.          exit(1);
  1047.      }
  1048.  
  1049.                                  /* open file in binary mode,
  1050.                                     abort if open fails */
  1051.      if((fd = open(argv[1],O_RDONLY | O_BINARY) ) == -1)
  1052.      {   fprintf(stderr, "\ndump: can't find file %s \n", argv[1]);
  1053.          exit(1);
  1054.      }
  1055.  
  1056.                                  /* read and dump records
  1057.                                     until end of file */
  1058.      while((status = read(fd,filebuf,REC_SIZE) ) != 0)
  1059.      {   dump_rec(filebuf, fileptr, status);
  1060.          fileptr += REC_SIZE;
  1061.      }
  1062.  
  1063.      close(fd);                  /* close input file */
  1064.      exit(0);                    /* return success code */
  1065.  }
  1066.  
  1067.  
  1068.  /*
  1069.      Display record (16 bytes) in hex and ASCII on standard output
  1070.  */
  1071.  
  1072.  dump_rec(char *filebuf, long fileptr, int length)
  1073.  {
  1074.      int i;                      /* index to current record */
  1075.  
  1076.      if(fileptr % 128 == 0)      /* display heading if needed */
  1077.          printf("\n\n       0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F");
  1078.  
  1079.      printf("\n%04lX ",fileptr); /* display file offset */
  1080.  
  1081.                                  /* display hex equivalent of
  1082.                                     each byte from file */
  1083.      for(i = 0; i < length; i++)
  1084.          printf(" %02X", (unsigned char) filebuf[i]);
  1085.  
  1086.      if(length != 16)            /* spaces if partial record */
  1087.          for (i=0; i<(16-length); i++) printf("   ");
  1088.  
  1089.                                  /* display ASCII equivalent of
  1090.                                     each byte from file */
  1091.      printf("  ");
  1092.      for(i = 0; i < length; i++)
  1093.      {   if(filebuf[i] < 32 || filebuf[i] > 126) putchar('.');
  1094.          else putchar(filebuf[i]);
  1095.      }
  1096.  }
  1097.  
  1098.  \SAMPCODE\ADVMSDOS\CHAP08\DUMP.ASM
  1099.  
  1100.          title   DUMP --- display file contents
  1101.          page    55,132
  1102.  
  1103.  ;
  1104.  ;  DUMP --- Display contents of file in hex and ASCII
  1105.  ;
  1106.  ;  Build:   C>MASM DUMP;
  1107.  ;           C>LINK DUMP;
  1108.  ;
  1109.  ;  Usage:   C>DUMP unit:\path\filename.exe [ >device ]
  1110.  ;
  1111.  ;  Copyright 1988 Ray Duncan
  1112.  ;
  1113.  
  1114.  cr      equ     0dh             ; ASCII carriage return
  1115.  lf      equ     0ah             ; ASCII line feed
  1116.  tab     equ     09h             ; ASCII tab code
  1117.  blank   equ     20h             ; ASCII space code
  1118.  
  1119.  cmd     equ     80h             ; buffer for command tail
  1120.  
  1121.  blksize equ     16              ; input file record size
  1122.  
  1123.  stdin   equ     0               ; standard input handle
  1124.  stdout  equ     1               ; standard output handle
  1125.  stderr  equ     2               ; standard error handle
  1126.  
  1127.  
  1128.  _TEXT   segment word public 'CODE'
  1129.  
  1130.          assume  cs:_TEXT,ds:_DATA,es:_DATA,ss:STACK
  1131.  
  1132.  
  1133.  dump    proc    far             ; entry point from MS-DOS
  1134.  
  1135.          push    ds              ; save DS:0000 for final
  1136.          xor     ax,ax           ; return to MS-DOS, in case
  1137.          push    ax              ; Function 4CH can't be used.
  1138.  
  1139.          mov     ax,_DATA        ; make our data segment
  1140.          mov     ds,ax           ; addressable via DS register.
  1141.  
  1142.                                  ; check MS-DOS version
  1143.          mov     ax,3000h        ; Fxn 30H = get version
  1144.          int     21h             ; transfer to MS-DOS
  1145.          cmp     al,2            ; major version 2 or later?
  1146.          jae     dump1           ; yes, proceed
  1147.  
  1148.                                  ; if MS-DOS 1.x, display
  1149.                                  ; error message and exit
  1150.          mov     dx,offset msg3  ; DS:DX = message address
  1151.          mov     ah,9            ; Fxn 9 = print string
  1152.          int     21h             ; transfer to MS-DOS
  1153.          ret                     ; then exit the old way
  1154.  
  1155.  dump1:                          ; check if filename present
  1156.          mov     bx,offset cmd   ; ES:BX = command tail
  1157.          call    argc            ; count command arguments
  1158.          cmp     ax,2            ; are there 2 arguments?
  1159.          je      dump2           ; yes, proceed
  1160.  
  1161.                                  ; missing filename, display
  1162.                                  ; error message and exit
  1163.          mov     dx,offset msg2  ; DS:DX = message address
  1164.          mov     cx,msg2_len     ; CX = message length
  1165.          jmp     dump9           ; go display it
  1166.  
  1167.  dump2:                          ; get address of filename
  1168.          mov     ax,1            ; AX = argument number
  1169.                                  ; ES:BX still = command tail
  1170.          call    argv            ; returns ES:BX = address,
  1171.                                  ; and AX = length
  1172.  
  1173.          mov     di,offset fname ; copy filename to buffer
  1174.          mov     cx,ax           ; CX = length
  1175.  
  1176.  dump3:  mov     al,es:[bx]      ; copy one byte
  1177.          mov     [di],al
  1178.          inc     bx              ; bump string pointers
  1179.          inc     di
  1180.          loop    dump3           ; loop until string done
  1181.          mov     byte ptr [di],0 ; add terminal null byte
  1182.  
  1183.          mov     ax,ds           ; make our data segment
  1184.          mov     es,ax           ; addressable by ES too
  1185.  
  1186.                                  ; now open the file
  1187.          mov     ax,3d00h        ; Fxn 3DH = open file
  1188.                                  ; mode 0 = read only
  1189.          mov     dx,offset fname ; DS:DX = filename
  1190.          int     21h             ; transfer to MS-DOS
  1191.          jnc     dump4           ; jump, open successful
  1192.  
  1193.                                  ; open failed, display
  1194.                                  ; error message and exit
  1195.          mov     dx,offset msg1  ; DS:DX = message address
  1196.          mov     cx,msg1_len     ; CX = message length
  1197.          jmp     dump9           ; go display it
  1198.  
  1199.  dump4:  mov     fhandle,ax      ; save file handle
  1200.  
  1201.  dump5:                          ; read block of file data
  1202.          mov     bx,fhandle      ; BX = file handle
  1203.          mov     cx,blksize      ; CX = record length
  1204.          mov     dx,offset fbuff ; DS:DX = buffer
  1205.          mov     ah,3fh          ; Fxn 3FH = read
  1206.          int     21h             ; transfer to MS-DOS
  1207.  
  1208.          mov     flen,ax         ; save actual length
  1209.          cmp     ax,0            ; end of file reached?
  1210.          jne     dump6           ; no, proceed
  1211.  
  1212.          cmp     word ptr fptr,0 ; was this the first read?
  1213.          jne     dump8           ; no, exit normally
  1214.  
  1215.                                  ; display empty file
  1216.                                  ; message and exit
  1217.          mov     dx,offset msg4  ; DS:DX = message address
  1218.          mov     cx,msg4_len     ; CX = length
  1219.          jmp     dump9           ; go display it
  1220.  
  1221.  dump6:                          ; display heading at
  1222.                                  ; each 128 byte boundary
  1223.          test    fptr,07fh       ; time for a heading?
  1224.          jnz     dump7           ; no, proceed
  1225.  
  1226.                                  ; display a heading
  1227.          mov     dx,offset hdg   ; DS:DX = heading address
  1228.          mov     cx,hdg_len      ; CX = heading length
  1229.          mov     bx,stdout       ; BX = standard output
  1230.          mov     ah,40h          ; Fxn 40H = write
  1231.          int     21h             ; transfer to MS-DOS
  1232.  
  1233.  dump7:  call    conv            ; convert binary record
  1234.                                  ; to formatted ASCII
  1235.  
  1236.                                  ; display formatted output
  1237.          mov     dx,offset fout  ; DX:DX = output address
  1238.          mov     cx,fout_len     ; CX = output length
  1239.          mov     bx,stdout       ; BX = standard output
  1240.          mov     ah,40h          ; Fxn 40H = write
  1241.          int     21h             ; transfer to MS-DOS
  1242.  
  1243.          jmp     dump5           ; go get another record
  1244.  
  1245.  dump8:                          ; close input file
  1246.          mov     bx,fhandle      ; BX = file handle
  1247.          mov     ah,3eh          ; Fxn 3EH = close
  1248.          int     21h             ; transfer to MS-DOS
  1249.  
  1250.          mov     ax,4c00h        ; Fxn 4CH = terminate,
  1251.                                  ; return code = 0
  1252.          int     21h             ; transfer to MS-DOS
  1253.  
  1254.  dump9:                          ; display message on
  1255.                                  ; standard error device
  1256.                                  ; DS:DX = message address
  1257.                                  ; CX = message length
  1258.          mov     bx,stderr       ; standard error handle
  1259.          mov     ah,40h          ; Fxn 40H = write
  1260.          int     21h             ; transfer to MS-DOS
  1261.  
  1262.          mov     ax,4c01h        ; Fxn 4CH = terminate,
  1263.                                  ; return code = 1
  1264.          int     21h             ; transfer to MS-DOS
  1265.  
  1266.  dump    endp
  1267.  
  1268.  
  1269.  conv    proc    near            ; convert block of data
  1270.                                  ; from input file
  1271.  
  1272.          mov     di,offset fout  ; clear output format
  1273.          mov     cx,fout_len-2   ; area to blanks
  1274.          mov     al,blank
  1275.          rep stosb
  1276.  
  1277.          mov     di,offset fout  ; convert file offset
  1278.          mov     ax,fptr         ; to ASCII for output
  1279.          call    w2a
  1280.  
  1281.          mov     bx,0            ; init. buffer pointer
  1282.  
  1283.  conv1:  mov     al,[fbuff+bx]   ; fetch byte from buffer
  1284.          mov     di,offset foutb ; point to output area
  1285.  
  1286.                                  ; format ASCII part...
  1287.                                  ; store '.' as default
  1288.          mov     byte ptr [di+bx],'.'
  1289.  
  1290.          cmp     al,blank        ; in range 20H - 7EH?
  1291.          jb      conv2           ; jump, not alphanumeric.
  1292.  
  1293.          cmp     al,7eh          ; in range 20H - 7EH?
  1294.          ja      conv2           ; jump, not alphanumeric.
  1295.  
  1296.          mov     [di+bx],al      ; store ASCII character.
  1297.  
  1298.  conv2:                          ; format hex part...
  1299.          mov     di,offset fouta ; point to output area
  1300.          add     di,bx           ; base addr + (offset*3)
  1301.          add     di,bx
  1302.          add     di,bx
  1303.          call    b2a             ; convert byte to hex
  1304.  
  1305.          inc     bx              ; advance through record
  1306.          cmp     bx,flen         ; entire record converted?
  1307.          jne     conv1           ; no, get another byte
  1308.  
  1309.                                  ; update file pointer
  1310.          add     word ptr fptr,blksize
  1311.  
  1312.          ret
  1313.  
  1314.  conv    endp
  1315.  
  1316.  
  1317.  w2a     proc    near            ; convert word to hex ASCII
  1318.                                  ; call with AX = value
  1319.                                  ;           DI = addr for string
  1320.                                  ; returns AX, DI, CX destroyed
  1321.  
  1322.          push    ax              ; save copy of value
  1323.          mov     al,ah
  1324.          call    b2a             ; convert upper byte
  1325.  
  1326.          pop     ax              ; get back copy
  1327.          call    b2a             ; convert lower byte
  1328.          ret
  1329.  
  1330.  w2a     endp
  1331.  
  1332.  
  1333.  b2a     proc    near            ; convert byte to hex ASCII
  1334.                                  ; call with AL=binary value
  1335.                                  ;           DI=addr for string
  1336.                                  ; returns   AX, DI, CX modified
  1337.  
  1338.          sub     ah,ah           ; clear upper byte
  1339.          mov     cl,16
  1340.          div     cl              ; divide byte by 16
  1341.          call    ascii           ; quotient becomes the first
  1342.          stosb                   ; ASCII character
  1343.          mov     al,ah
  1344.          call    ascii           ; remainder becomes the
  1345.          stosb                   ; second ASCII character
  1346.          ret
  1347.  
  1348.  b2a     endp
  1349.  
  1350.  
  1351.  ascii   proc    near            ; convert value 0-0FH in AL
  1352.                                  ; into "hex ASCII" character
  1353.  
  1354.          add     al,'0'          ; offset to range 0-9
  1355.          cmp     al,'9'          ; is it > 9?
  1356.          jle     ascii2          ; no, jump
  1357.          add     al,'A'-'9'-1    ; offset to range A-F,
  1358.  
  1359.  ascii2: ret                     ; return AL = ASCII char.
  1360.  
  1361.  ascii   endp
  1362.  
  1363.  
  1364.  argc    proc    near            ; count command line arguments
  1365.                                  ; call with ES:BX = command line
  1366.                                  ; returns   AX = argument count
  1367.  
  1368.          push    bx              ; save original BX and CX
  1369.          push    cx              ;  for later
  1370.          mov     ax,1            ; force count >= 1
  1371.  
  1372.  argc1:  mov     cx,-1           ; set flag = outside argument
  1373.  
  1374.  argc2:  inc     bx              ; point to next character
  1375.          cmp     byte ptr es:[bx],cr
  1376.          je      argc3           ; exit if carriage return
  1377.          cmp     byte ptr es:[bx],blank
  1378.          je      argc1           ; outside argument if ASCII blank
  1379.          cmp     byte ptr es:[bx],tab
  1380.          je      argc1           ; outside argument if ASCII tab
  1381.  
  1382.                                  ; otherwise not blank or tab,
  1383.          jcxz    argc2           ; jump if already inside argument
  1384.  
  1385.          inc     ax              ; else found argument, count it
  1386.          not     cx              ; set flag = inside argument
  1387.          jmp     argc2           ; and look at next character
  1388.  
  1389.  argc3:  pop     cx              ; restore original BX and CX
  1390.          pop     bx
  1391.          ret                     ; return AX = argument count
  1392.  
  1393.  argc    endp
  1394.  
  1395.  
  1396.  argv    proc    near            ; get address & length of
  1397.                                  ; command line argument
  1398.                                  ; call with ES:BX = command line
  1399.                                  ;           AX    = argument no.
  1400.                                  ; returns   ES:BX = address
  1401.                                  ;           AX    = length
  1402.  
  1403.          push    cx              ; save original CX and DI
  1404.          push    di
  1405.  
  1406.          or      ax,ax           ; is it argument 0?
  1407.          jz      argv8           ; yes, jump to get program name
  1408.  
  1409.          xor     ah,ah           ; initialize argument counter
  1410.  
  1411.  argv1:  mov     cx,-1           ; set flag = outside argument
  1412.  
  1413.  argv2:  inc     bx              ; point to next character
  1414.          cmp     byte ptr es:[bx],cr
  1415.          je      argv7           ; exit if carriage return
  1416.          cmp     byte ptr es:[bx],blank
  1417.          je      argv1           ; outside argument if ASCII blank
  1418.          cmp     byte ptr es:[bx],tab
  1419.          je      argv1           ; outside argument if ASCII tab
  1420.  
  1421.                                  ; if not blank or tab...
  1422.          jcxz    argv2           ; jump if already inside argument
  1423.  
  1424.          inc     ah              ; else count arguments found
  1425.          cmp     ah,al           ; is this the one we're looking for?
  1426.          je      argv4           ; yes, go find its length
  1427.          not     cx              ; no, set flag = inside argument
  1428.          jmp     argv2           ; and look at next character
  1429.  
  1430.  argv4:                          ; found desired argument, now
  1431.                                  ; determine its length...
  1432.          mov     ax,bx           ; save param. starting address
  1433.  
  1434.  argv5:  inc     bx              ; point to next character
  1435.          cmp     byte ptr es:[bx],cr
  1436.          je      argv6           ; found end if carriage return
  1437.          cmp     byte ptr es:[bx],blank
  1438.          je      argv6           ; found end if ASCII blank
  1439.          cmp     byte ptr es:[bx],tab
  1440.          jne     argv5           ; found end if ASCII tab
  1441.  
  1442.  argv6:  xchg    bx,ax           ; set ES:BX = argument address
  1443.          sub     ax,bx           ; and AX = argument length
  1444.          jmp     argvx           ; return to caller
  1445.  
  1446.  argv7:  xor     ax,ax           ; set AX = 0, argument not found
  1447.          jmp     argvx           ; return to caller
  1448.  
  1449.  argv8:                          ; special handling for argv=0
  1450.          mov     ax,3000h        ; check if DOS 3.0 or later
  1451.          int     21h             ; (force AL=0 in case DOS 1)
  1452.          cmp     al,3
  1453.          jb      argv7           ; DOS 1 or 2, return null param.
  1454.          mov     es,es:[2ch]     ; get environment segment from PSP
  1455.          xor     di,di           ; find the program name by
  1456.          xor     al,al           ; first skipping over all the
  1457.          mov     cx,-1           ; environment variables...
  1458.          cld
  1459.  argv9:  repne scasb             ; scan for double null (can't use
  1460.          scasb                   ; (SCASW since might be odd addr.)
  1461.          jne     argv9           ; loop if it was a single null
  1462.          add     di,2            ; skip count word in environment
  1463.          mov     bx,di           ; save program name address
  1464.          mov     cx,-1           ; now find its length...
  1465.          repne scasb             ; scan for another null byte
  1466.          not     cx              ; convert CX to length
  1467.          dec     cx
  1468.          mov     ax,cx           ; return length in AX
  1469.  
  1470.  argvx:                          ; common exit point
  1471.          pop     di              ; restore original CX and DI
  1472.          pop     cx
  1473.          ret                     ; return to caller
  1474.  
  1475.  argv    endp
  1476.  
  1477.  _TEXT    ends
  1478.  
  1479.  
  1480.  _DATA   segment word public 'DATA'
  1481.  
  1482.  fname   db      64 dup (0)      ; buffer for input filespec
  1483.  
  1484.  fhandle dw      0               ; token from PCDOS for input file.
  1485.  
  1486.  flen    dw      0               ; actual length read
  1487.  
  1488.  fptr    dw      0               ; relative address in file
  1489.  
  1490.  fbuff   db      blksize dup (?) ; data from input file
  1491.  
  1492.  fout    db      'nnnn'          ; formatted output area
  1493.          db      blank,blank
  1494.  fouta   db      16 dup ('nn',blank)
  1495.          db      blank
  1496.  foutb   db      16 dup (blank),cr,lf
  1497.  fout_len equ    $-fout
  1498.  
  1499.  hdg     db      cr,lf           ; heading for each 128 bytes
  1500.          db      7 dup (blank)   ; of formatted output
  1501.          db      '0  1  2  3  4  5  6  7  '
  1502.          db      '8  9  A  B  C  D  E  F',cr,lf
  1503.  hdg_len equ     $-hdg
  1504.  
  1505.  
  1506.  msg1    db      cr,lf
  1507.          db      'dump: file not found'
  1508.          db      cr,lf
  1509.  msg1_len equ    $-msg1
  1510.  
  1511.  msg2    db      cr,lf
  1512.          db      'dump: missing file name'
  1513.          db      cr,lf
  1514.  msg2_len equ    $-msg2
  1515.  
  1516.  msg3    db      cr,lf
  1517.          db      'dump: wrong MS-DOS version'
  1518.          db      cr,lf,'$'
  1519.  
  1520.  msg4    db      cr,lf
  1521.          db      'dump: empty file'
  1522.          db      cr,lf
  1523.  msg4_len equ    $-msg4
  1524.  
  1525.  _DATA   ends
  1526.  
  1527.  
  1528.  STACK   segment para stack 'STACK'
  1529.  
  1530.          db      64 dup (?)
  1531.  
  1532.  STACK   ends
  1533.  
  1534.          end     dump
  1535.  
  1536.  
  1537.  \SAMPCODE\ADVMSDOS\CHAP08\INT24.ASM
  1538.  
  1539.          title   INT24 Critical Error Handler
  1540.          page    55,132
  1541.  
  1542.  ;
  1543.  ; INT24.ASM -- Replacement critical error handler
  1544.  ;
  1545.  ; Copyright (C) September 1987 Ray Duncan
  1546.  ;
  1547.  
  1548.  cr      equ     0dh             ; ASCII carriage return
  1549.  lf      equ     0ah             ; ASCII line feed
  1550.  
  1551.  DGROUP  group   _DATA
  1552.  
  1553.  _DATA   segment word public 'DATA'
  1554.  
  1555.  save24  dd      0               ; previous contents of Int 24H
  1556.                                  ; critical error handler vector
  1557.  
  1558.                                  ; prompt message used by
  1559.                                  ; critical error handler
  1560.  prompt  db      cr,lf,'Critical Error Occurred: '
  1561.          db      'Abort, Retry, Ignore, Fail? $'
  1562.  
  1563.  keys    db      'aArRiIfF'      ; possible user response keys
  1564.  keys_len equ $-keys             ; (both cases of each allowed)
  1565.  
  1566.  codes   db      2,2,1,1,0,0,3,3 ; codes returned to MS-DOS kernel
  1567.                                  ; for corresponding response keys
  1568.  
  1569.  _DATA   ends
  1570.  
  1571.  
  1572.  _TEXT   segment word public 'CODE'
  1573.  
  1574.          assume  cs:_TEXT,ds:DGROUP
  1575.  
  1576.          public  get24
  1577.  get24   proc    near            ; set Int 24H vector to point
  1578.                                  ; to new critical error handler
  1579.  
  1580.          push    ds              ; save segment registers
  1581.          push    es
  1582.  
  1583.          mov     ax,3524h        ; get address of previous
  1584.          int     21h             ; INT 24H handler and save it
  1585.  
  1586.          mov     word ptr save24,bx
  1587.          mov     word ptr save24+2,es
  1588.  
  1589.          push    cs              ; set DS:DX to point to
  1590.          pop     ds              ;   new INT 24H handler
  1591.          mov     dx,offset _TEXT:int24
  1592.          mov     ax,2524h        ; then call MS-DOS to
  1593.          int     21h             ;   set the INT 24H vector
  1594.  
  1595.          pop     es              ; restore segment registers
  1596.          pop     ds
  1597.          ret                     ; and return to caller
  1598.  
  1599.  get24   endp
  1600.  
  1601.  
  1602.          public  res24
  1603.  res24   proc    near            ; restore original contents
  1604.                                  ; of Int 24H vector
  1605.  
  1606.          push    ds              ; save our data segment
  1607.  
  1608.          lds     dx,save24       ; put address of old handler
  1609.          mov     ax,2524h        ; back into INT 24H vector
  1610.          int     21h
  1611.  
  1612.          pop     ds              ; restore data segment
  1613.          ret                     ; and return to caller
  1614.  
  1615.  res24   endp
  1616.  
  1617.  ;
  1618.  ; This is the replacement Critical Error handler.  It
  1619.  ; prompts the user for Abort, Retry, Ignore, or Fail, and
  1620.  ; returns the appropriate code to the MS-DOS kernel.
  1621.  ;
  1622.  int24   proc    far             ; entered from MS-DOS kernel
  1623.  
  1624.          push    bx              ; save registers
  1625.          push    cx
  1626.          push    dx
  1627.          push    si
  1628.          push    di
  1629.          push    bp
  1630.          push    ds
  1631.          push    es
  1632.  
  1633.  int24a: mov     ax,DGROUP       ; display prompt for user
  1634.          mov     ds,ax           ; using Function 9 (print string
  1635.          mov     es,ax           ; terminated by $ character)
  1636.          mov     dx,offset prompt
  1637.          mov     ah,9
  1638.          int     21h
  1639.  
  1640.          mov     ah,1            ; get user's response
  1641.          int     21h             ; Function 1 = read one character
  1642.  
  1643.          mov     di,offset keys  ; look up code for response key
  1644.          mov     cx,keys_len
  1645.          cld
  1646.          repne scasb
  1647.          jnz     int24a          ; prompt again if bad response
  1648.  
  1649.                                  ; set AL = action code for MS-DOS
  1650.                                  ; according to key that was entered:
  1651.                                  ; 0=ignore, 1=retry, 2=abort, 3=fail
  1652.          mov     al,[di+keys_len-1]
  1653.  
  1654.          pop     es              ; restore registers
  1655.          pop     ds
  1656.          pop     bp
  1657.          pop     di
  1658.          pop     si
  1659.          pop     dx
  1660.          pop     cx
  1661.          pop     bx
  1662.          iret                    ; exit critical error handler
  1663.  
  1664.  int24   endp
  1665.  
  1666.  _TEXT   ends
  1667.  
  1668.          end
  1669.  
  1670.  \SAMPCODE\ADVMSDOS\CHAP08\TRYINT24.ASM
  1671.  
  1672.           title     TRYINT24 -- tests critical error handler
  1673.           page      55,132
  1674.  ;
  1675.  ; TRYINT24.ASM - Test program for INT24.ASM
  1676.  ;                replacement critical-error handler
  1677.  ;
  1678.  ; Copyright (C) June 1987 Ray Duncan
  1679.  ;
  1680.  ; Build:   MASM TRYINT24;
  1681.  ;          MASM INT24;
  1682.  ;          LINK TRYINT24+INT24;
  1683.  ;
  1684.  ; Usage:   TRYINT24
  1685.  ;
  1686.  
  1687.  stdin   equ     0               ; standard input device
  1688.  stdout  equ     1               ; standard output device
  1689.  stderr  equ     2               ; standard error device
  1690.  
  1691.  cr      equ     0dh             ; ASCII carriage return
  1692.  lf      equ     0ah             ; ASCII line feed
  1693.  
  1694.  
  1695.  DGROUP  group   _DATA,STACK     ; 'automatic data group'
  1696.  
  1697.          extrn   get24:near
  1698.          extrn   res24:near
  1699.  
  1700.  _TEXT   segment word public 'CODE'
  1701.  
  1702.          assume  cs:_TEXT,ds:DGROUP,ss:STACK
  1703.  
  1704.  main    proc    far             ; entry point from MS-DOS
  1705.  
  1706.          mov     ax,DGROUP       ; set DS = our data segment
  1707.          mov     ds,ax
  1708.  
  1709.          call    get24           ; capture int 24h for our
  1710.                                  ; own handler
  1711.  
  1712.                                  ; display sign-on message...
  1713.          mov     dx,offset DGROUP:msg    ; DS:DX = address of message
  1714.          mov     cx,msg_len      ; CX = length of message
  1715.          mov     bx,stdout       ; BX = handle for std output
  1716.          mov     ah,40h          ; AH = 40h, write file or device
  1717.          int     21h             ; transfer to MS-DOS
  1718.  
  1719.  err:    mov     dl,'*'          ; write character to printer
  1720.          mov     ah,05           ; to generate a critical error
  1721.          int     21h
  1722.          jmp     err
  1723.  
  1724.          call    res24           ; restore previous int 24h handler
  1725.  
  1726.          mov     ax,4c00h        ; no error, terminate program
  1727.          int     21h             ; with return code = 0
  1728.  
  1729.  main2:  call    res24           ; restore previous int 24h handler
  1730.  
  1731.          mov     ax,4c01h        ; error, terminate program
  1732.          int     21h             ; with return code = 1
  1733.  
  1734.  main    endp                    ; end of main procedure
  1735.  
  1736.  _TEXT   ends
  1737.  
  1738.  
  1739.  _DATA   segment word public 'DATA'
  1740.  
  1741.  msg     db      cr,lf,'Int 24H Handler Demo',cr,lf
  1742.  msg_len equ     $-msg
  1743.  
  1744.  _DATA   ends
  1745.  
  1746.  
  1747.  STACK   segment para stack 'STACK'
  1748.  
  1749.          dw      64 dup (?)
  1750.  
  1751.  STACK   ends
  1752.  
  1753.          end     main            ; defines program entry point
  1754.  
  1755.  
  1756.  \SAMPCODE\ADVMSDOS\CHAP11
  1757.  \SAMPCODE\ADVMSDOS\CHAP11\EXTMEM.ASM
  1758.  
  1759.           title     EXTMEM --- get/put extended memory
  1760.           page      55,132
  1761.  
  1762.  ;
  1763.  ; EXTMEM.ASM --- Demonstration of access to
  1764.  ;                extended memory using ROM BIOS
  1765.  ;                Int 15H Function 87H
  1766.  ;
  1767.  ; Copyright (C) June 1988 Ray Duncan
  1768.  ;
  1769.  ; Build:   MASM EXTMEM;
  1770.  ;          LINK EXTMEM;
  1771.  ;
  1772.  ; Usage:   EXTMEM
  1773.  ;
  1774.  
  1775.  stdin   equ     0               ; standard input device
  1776.  stdout  equ     1               ; standard output device
  1777.  stderr  equ     2               ; standard error device
  1778.  
  1779.  cr      equ     0dh             ; ASCII carriage return
  1780.  lf      equ     0ah             ; ASCII line feed
  1781.  
  1782.  
  1783.  DGROUP  group   _DATA,STACK     ; 'automatic data group'
  1784.  
  1785.  
  1786.  _DATA   segment word public 'DATA'
  1787.  
  1788.  bmdt    db      30h dup (0)     ; block move descriptor table
  1789.  
  1790.  buff1   db      80h dup ('?')   ; source buffer
  1791.  buff2   db      80h dup (0)     ; destination buffer
  1792.  
  1793.  _DATA   ends
  1794.  
  1795.  
  1796.  STACK   segment para stack 'STACK'
  1797.  
  1798.          dw      64 dup (?)
  1799.  
  1800.  STACK   ends
  1801.  
  1802.  
  1803.  _TEXT   segment word public 'CODE'
  1804.  
  1805.          assume  cs:_TEXT,ds:DGROUP,ss:STACK
  1806.  
  1807.  main    proc    far             ; entry point from MS-DOS
  1808.  
  1809.          mov     ax,DGROUP       ; set DS = our data segment
  1810.          mov     ds,ax
  1811.          mov     es,ax
  1812.  
  1813.                                  ; copy 'buff1' to extended
  1814.                                  ; memory address 100000H
  1815.          mov     dx,10h          ; DX:AX = destination
  1816.          mov     ax,0            ; extended mem. address
  1817.          mov     bx,seg buff1    ; DS:BX = source conv.
  1818.          mov     ds,bx           ; memory address
  1819.          mov     bx,offset buff1
  1820.          mov     cx,80h          ; CX = bytes to move
  1821.          mov     si,seg bmdt     ; ES:SI = block move
  1822.          mov     es,si           ; descriptor table
  1823.          mov     si,offset bmdt
  1824.          call    putblk          ; request transfer
  1825.  
  1826.  
  1827.                                  ; fill buff2 from extended
  1828.                                  ; memory address 100000H
  1829.          mov     dx,10h          ; DX:AX = source extended
  1830.          mov     ax,0            ; memory address
  1831.          mov     bx,seg buff2    ; DS:BX = destination
  1832.          mov     ds,bx           ; conventional mem. address
  1833.          mov     bx,offset buff2
  1834.          mov     cx,80h          ; CX = bytes to move
  1835.          mov     si,seg bmdt     ; ES:SI = block move
  1836.          mov     es,si           ; descriptor table
  1837.          mov     si,offset bmdt
  1838.          call    getblk          ; request transfer
  1839.  
  1840.          mov     ax,4c00h        ; no error, terminate program
  1841.          int     21h             ; with return code = 0
  1842.  
  1843.  main2:  mov     ax,4c01h        ; error, terminate program
  1844.          int     21h             ; with return code = 1
  1845.  
  1846.  main    endp                    ; end of main procedure
  1847.  
  1848.  
  1849.  
  1850.  
  1851.  getblk  proc    near            ; Transfer block from extended
  1852.                                  ;   memory to real memory
  1853.                                  ; Call with
  1854.                                  ; DX:AX = linear 32-bit
  1855.                                  ;         extended memory address
  1856.                                  ; DS:BX = segment and offset
  1857.                                  ;         destination address
  1858.                                  ; CX    = length in bytes
  1859.                                  ; ES:SI = block move descriptor table
  1860.                                  ; Returns
  1861.                                  ; AH    = 0 if transfer OK
  1862.  
  1863.          mov     es:[si+10h],cx  ; store length into descriptors
  1864.          mov     es:[si+18h],cx
  1865.  
  1866.                                  ; store access rights bytes
  1867.          mov     byte ptr es:[si+15h],93h
  1868.          mov     byte ptr es:[si+1dh],93h
  1869.  
  1870.          mov     es:[si+12h],ax  ; source extended memory address
  1871.          mov     es:[si+14h],dl
  1872.  
  1873.                                  ; convert destination segment
  1874.                                  ; and offset to linear address
  1875.          mov     ax,ds           ; segment * 16
  1876.          mov     dx,16
  1877.          mul     dx
  1878.          add     ax,bx           ; + offset -> linear address
  1879.          adc     dx,0
  1880.  
  1881.          mov     es:[si+1ah],ax  ; store destination address
  1882.          mov     es:[si+1ch],dl
  1883.  
  1884.          shr     cx,1            ; convert length to words
  1885.          mov     ah,87h          ; Int 15H Fxn 87h = block move
  1886.          int     15h             ; transfer to ROM BIOS
  1887.  
  1888.          ret                     ; back to caller
  1889.  
  1890.  getblk  endp
  1891.  
  1892.  
  1893.  putblk  proc    near            ; Transfer block from real
  1894.                                  ;   memory to extended memory
  1895.                                  ; Call with
  1896.                                  ; DX:AX = linear 32-bit
  1897.                                  ;         extended memory address
  1898.                                  ; DS:BX = segment and offset
  1899.                                  ;         source address
  1900.                                  ; CX    = length in bytes
  1901.                                  ; ES:SI = block move descriptor table
  1902.                                  ; Returns
  1903.                                  ; AH    = 0 if transfer OK
  1904.  
  1905.          mov     es:[si+10h],cx  ; store length into descriptors
  1906.          mov     es:[si+18h],cx
  1907.  
  1908.                                  ; store access rights bytes
  1909.          mov     byte ptr es:[si+15h],93h
  1910.          mov     byte ptr es:[si+1dh],93h
  1911.  
  1912.          mov     es:[si+1ah],ax  ; store destination extended
  1913.          mov     es:[si+1ch],dl  ; memory address
  1914.  
  1915.                                  ; convert source segment and
  1916.                                  ; offset to linear address
  1917.          mov     ax,ds           ; segment * 16
  1918.          mov     dx,16
  1919.          mul     dx
  1920.          add     ax,bx           ; + offset -> linear address
  1921.          adc     dx,0
  1922.  
  1923.          mov     es:[si+12h],ax  ; store source address
  1924.          mov     es:[si+14h],dl
  1925.  
  1926.          shr     cx,1            ; convert length to words
  1927.          mov     ah,87h          ; Int 15H Fxn 87h = block move
  1928.          int     15h             ; transfer to ROM BIOS
  1929.  
  1930.          ret                     ; back to caller
  1931.  
  1932.  putblk  endp
  1933.  
  1934.  _TEXT   ends
  1935.  
  1936.          end     main            ; defines program entry point
  1937.  
  1938.  
  1939.  \SAMPCODE\ADVMSDOS\CHAP12
  1940.  \SAMPCODE\ADVMSDOS\CHAP12\SHELL.C
  1941.  
  1942.  /*
  1943.          SHELL.C         Simple extendable command interpreter
  1944.                                  for MS-DOS version 2.0 and later
  1945.  
  1946.          Copyright 1988 Ray Duncan
  1947.  
  1948.          Compile:        C>CL SHELL.C
  1949.  
  1950.          Usage:          C>SHELL
  1951.  */
  1952.  
  1953.  #include <stdio.h>
  1954.  #include <process.h>
  1955.  #include <stdlib.h>
  1956.  #include <signal.h>
  1957.  
  1958.                                                                          /* ma
  1959.                                                                             el
  1960.  #define dim(x) (sizeof(x) / sizeof(x[0]))
  1961.  
  1962.  unsigned intrinsic(char *);                     /* function prototypes */
  1963.  void extrinsic(char *);
  1964.  void get_cmd(char *);
  1965.  void get_comspec(char *);
  1966.  void break_handler(void);
  1967.  void cls_cmd(void);
  1968.  void dos_cmd(void);
  1969.  void exit_cmd(void);
  1970.  
  1971.  struct cmd_table {                                      /* intrinsic commands
  1972.                             char *cmd_name;
  1973.                             int  (*cmd_fxn)();
  1974.                                   }   commands[] =
  1975.  
  1976.                   { "CLS",   cls_cmd,
  1977.                     "DOS",   dos_cmd,
  1978.                     "EXIT",  exit_cmd, };
  1979.  
  1980.  static char com_spec[64];                       /* COMMAND.COM filespec */
  1981.  
  1982.  
  1983.  main(int argc, char *argv[])
  1984.  {
  1985.          char inp_buf[80];               /* keyboard input buffer */
  1986.  
  1987.      get_comspec(com_spec);                      /* get COMMAND.COM filespec *
  1988.  
  1989.                                                                          /* re
  1990.                                                                     for Ctrl-C
  1991.          if(signal(SIGINT, break_handler) == (int(*)()) -1)
  1992.      {
  1993.                  fputs("Can't capture Control-C Interrupt", stderr);
  1994.              exit(1);
  1995.      }
  1996.  
  1997.      while(1)                            /* main interpreter loop */
  1998.      {
  1999.                  get_cmd(inp_buf);           /* get a command */
  2000.          if (! intrinsic(inp_buf) )      /* if it's intrinsic,
  2001.                                         run its subroutine */
  2002.             extrinsic(inp_buf);          /* else pass to COMMAND.COM */
  2003.          }
  2004.  }
  2005.  
  2006.  
  2007.  /*
  2008.          Try and match user's command with intrinsic command
  2009.          table.  If a match is found, run the associated routine
  2010.          and return true, else return false.
  2011.  */
  2012.  
  2013.  unsigned intrinsic(char *input_string)
  2014.  {
  2015.          int i, j;                                               /* some scrat
  2016.  
  2017.                                                                          /* sc
  2018.      while(*input_string == '\x20') input_string++ ;
  2019.  
  2020.                                                                          /* se
  2021.      for(i=0; i < dim(commands); i++)
  2022.      {
  2023.                  j = strcmp(commands[i].cmd_name, input_string);
  2024.  
  2025.          if(j == 0)                                      /* if match, run rout
  2026.          {
  2027.                          (*commands[i].cmd_fxn)();
  2028.              return(1);                          /* and return true */
  2029.          }
  2030.          }
  2031.      return(0);                                          /* no match, return f
  2032.  }
  2033.  
  2034.  
  2035.  /*
  2036.          Process an extrinsic command by passing it
  2037.      to an EXEC'd copy of COMMAND.COM.
  2038.  */
  2039.  
  2040.  void extrinsic(char *input_string)
  2041.  {
  2042.          int status;
  2043.  
  2044.      status = system(input_string);      /* call EXEC function */
  2045.  
  2046.      if(status)                                          /* if failed, display
  2047.                                                                             er
  2048.              fputs("\nEXEC of COMMAND.COM failed\n", stderr);
  2049.  }
  2050.  
  2051.  
  2052.  /*
  2053.          Issue prompt, get user's command from standard input,
  2054.      fold it to upper case.
  2055.  */
  2056.  
  2057.  void get_cmd(char *buffer)
  2058.  {
  2059.          printf("\nsh: ");                   /* display prompt */
  2060.      gets(buffer);                       /* get keyboard entry */
  2061.      strupr(buffer);                     /* fold to upper case */
  2062.  }
  2063.  
  2064.  
  2065.  /*
  2066.          Get the full path and file specification for COMMAND.COM
  2067.          from the "COMSPEC=" variable in the environment.
  2068.  */
  2069.  
  2070.  void get_comspec(char *buffer)
  2071.  {
  2072.          strcpy(buffer, getenv("COMSPEC"));
  2073.  
  2074.      if(buffer[0] == NULL)
  2075.      {
  2076.                  fputs("\nNo COMSPEC in environment\n", stderr);
  2077.              exit(1);
  2078.      }
  2079.  }
  2080.  
  2081.  
  2082.  /*
  2083.          This Ctrl-C handler keeps SHELL from losing control.
  2084.          It just re-issues the prompt and returns.
  2085.  */
  2086.  
  2087.  void break_handler(void)
  2088.  {
  2089.          signal(SIGINT, break_handler);          /* reset handler */
  2090.      printf("\nsh: ");                   /* display prompt */
  2091.  }
  2092.  
  2093.  
  2094.  /*
  2095.          These are the subroutines for the intrinsic commands.
  2096.  */
  2097.  
  2098.  void cls_cmd(void)                                      /* CLS command */
  2099.  {
  2100.          printf("\033[2J");                              /* ANSI escape sequen
  2101.  }
  2102.  
  2103.  void dos_cmd(void)                                      /* DOS command */
  2104.  {
  2105.          int status;
  2106.  
  2107.      status = spawnlp(P_WAIT, com_spec, com_spec, NULL);
  2108.  
  2109.      if (status)
  2110.                  fputs("\nEXEC of COMMAND.COM failed\n",stderr);
  2111.  }
  2112.  
  2113.  void exit_cmd(void)                                     /* EXIT command */
  2114.  {
  2115.          exit(0);                                                        /* te
  2116.  }
  2117.  
  2118.  \SAMPCODE\ADVMSDOS\CHAP12\SHELL.ASM
  2119.  
  2120.          name    shell
  2121.          page    55,132
  2122.          title   SHELL.ASM -- simple MS-DOS shell
  2123.  ;
  2124.  ; SHELL.ASM     Simple extendable command interpreter
  2125.  ;               for MS-DOS version 2.0 and later
  2126.  ;
  2127.  ; Copyright 1988 by Ray Duncan
  2128.  ;
  2129.  ; Build:        C>MASM SHELL;
  2130.  ;               C>LINK SHELL;
  2131.  ;
  2132.  ; Usage:        C>SHELL;
  2133.  ;
  2134.  
  2135.  stdin   equ     0                       ; standard input handle
  2136.  stdout  equ     1                       ; standard output handle
  2137.  stderr  equ     2                       ; standard error handle
  2138.  
  2139.  cr      equ     0dh                     ; ASCII carriage return
  2140.  lf      equ     0ah                     ; ASCII line feed
  2141.  blank   equ     20h                     ; ASCII blank code
  2142.  escape  equ     01bh                    ; ASCII escape code
  2143.  
  2144.  _TEXT   segment word public 'CODE'
  2145.  
  2146.          assume  cs:_TEXT,ds:_DATA,ss:STACK
  2147.  
  2148.  shell   proc    far                     ; at entry DS = ES = PSP
  2149.  
  2150.          mov     ax,_DATA                ; make our data segment
  2151.          mov     ds,ax                   ; addressable
  2152.  
  2153.          mov     ax,es:[002ch]           ; get environment segment
  2154.          mov     env_seg,ax              ; from PSP and save it
  2155.  
  2156.                                          ; release unneeded memory...
  2157.                                          ; ES already = PSP segment
  2158.          mov     bx,100h                 ; BX = paragraphs needed
  2159.          mov     ah,4ah                  ; Function 4AH = resize block
  2160.          int     21h                     ; transfer to MS-DOS
  2161.          jnc     shell1                  ; jump if resize OK
  2162.  
  2163.          mov     dx,offset msg1          ; resize failed, display
  2164.          mov     cx,msg1_length          ; error message and exit
  2165.          jmp     shell4
  2166.  
  2167.  shell1: call    get_comspec             ; get COMMAND.COM filespec
  2168.          jnc     shell2                  ; jump if it was found
  2169.  
  2170.          mov     dx,offset msg3          ; COMSPEC not found in
  2171.          mov     cx,msg3_length          ; environment, display error
  2172.          jmp     shell4                  ; message and exit
  2173.  
  2174.  shell2: mov     dx,offset shell3        ; set Ctrl-C vector (Int 23H)
  2175.          mov     ax,cs                   ; for this program's handler
  2176.          mov     ds,ax                   ; DS:DX = handler address
  2177.          mov     ax,2523H                ; Fxn 25H = set vector
  2178.          int     21h                     ; transfer to MS-DOS
  2179.  
  2180.          mov     ax,_DATA                ; make our data segment
  2181.          mov     ds,ax                   ; addressable again
  2182.          mov     es,ax
  2183.  
  2184.  shell3:                                 ; main interpreter loop
  2185.  
  2186.          call    get_cmd                 ; get a command from user
  2187.  
  2188.          call    intrinsic               ; check if intrinsic function
  2189.          jnc     shell3                  ; yes, it was processed
  2190.  
  2191.          call    extrinsic               ; no, pass it to COMMAND.COM
  2192.          jmp     shell3                  ; then get another command
  2193.  
  2194.  shell4:                                 ; come here if error detected
  2195.                                          ; DS:DX = message address
  2196.                                          ; CX = message length
  2197.          mov     bx,stderr               ; BX = standard error handle
  2198.          mov     ah,40h                  ; Fxn 40H = write
  2199.          int     21h                     ; transfer to MS-DOS
  2200.  
  2201.          mov     ax,4c01h                ; Fxn 4CH = terminate with
  2202.                                          ; return code = 1
  2203.          int     21h                     ; transfer to MS-DOS
  2204.  
  2205.  shell   endp
  2206.  
  2207.  
  2208.  intrinsic proc  near                    ; Decode user entry against
  2209.                                          ; the table "COMMANDS"
  2210.                                          ; If match, run the routine,
  2211.                                          ; and return Carry = False
  2212.                                          ; If no match, Carry = True
  2213.                                          ; return Carry = True.
  2214.  
  2215.          mov     si,offset commands      ; DS:SI = command table
  2216.  
  2217.  intr1:  cmp     byte ptr [si],0         ; end of table?
  2218.          je      intr7                   ; jump, end of table found
  2219.  
  2220.          mov     di,offset inp_buf       ; no, let DI = addr of user input
  2221.  
  2222.  intr2:  cmp     byte ptr [di],blank     ; scan off any leading blanks
  2223.          jne     intr3
  2224.  
  2225.          inc     di                      ; found blank, go past it
  2226.          jmp     intr2
  2227.  
  2228.  intr3:  mov     al,[si]                 ; next character from table
  2229.  
  2230.          or      al,al                   ; end of string?
  2231.          jz      intr4                   ; jump, entire string matched
  2232.  
  2233.          cmp     al,[di]                 ; compare to input character
  2234.          jnz     intr6                   ; jump, found mismatch
  2235.  
  2236.          inc     si                      ; advance string pointers
  2237.          inc     di
  2238.          jmp     intr3
  2239.  
  2240.  intr4:  cmp     byte ptr [di],cr        ; make sure user's entry
  2241.          je      intr5                   ; is the same length...
  2242.          cmp     byte ptr [di],blank     ; next character in entry
  2243.          jne     intr6                   ; must be blank or Return
  2244.  
  2245.  intr5:  call    word ptr [si+1]         ; run the command routine
  2246.  
  2247.          clc                             ; return Carry Flag = False
  2248.          ret                             ; as success flag
  2249.  
  2250.  intr6:  lodsb                           ; look for end of this
  2251.          or      al,al                   ; command string (null byte)
  2252.          jnz     intr6                   ; not end yet, loop
  2253.  
  2254.          add     si,2                    ; skip over routine address
  2255.          jmp     intr1                   ; try to match next command
  2256.  
  2257.  intr7:  stc                             ; command not matched, exit
  2258.          ret                             ; with Carry = True
  2259.  
  2260.  intrinsic endp
  2261.  
  2262.  
  2263.  extrinsic proc  near                    ; process extrinsic command
  2264.                                          ; by passing it to
  2265.                                          ; COMMAND.COM with a
  2266.                                          ; " /C " command tail.
  2267.  
  2268.          mov     al,cr                   ; find length of command
  2269.          mov     cx,cmd_tail_length      ; by scanning for carriage
  2270.          mov     di,offset cmd_tail+1    ; return
  2271.          cld
  2272.          repnz scasb
  2273.  
  2274.          mov     ax,di                   ; calculate command tail
  2275.          sub     ax,offset cmd_tail+2    ; length without carriage
  2276.          mov     cmd_tail,al             ; return, and store it
  2277.  
  2278.                                          ; set command tail address
  2279.          mov     word ptr par_cmd,offset cmd_tail
  2280.          call    exec                    ; and run COMMAND.COM
  2281.          ret
  2282.  
  2283.  extrinsic endp
  2284.  
  2285.  
  2286.  get_cmd proc    near                    ; prompt user, get command
  2287.  
  2288.                                          ; display the shell prompt
  2289.          mov     dx,offset prompt        ; DS:DX = message address
  2290.          mov     cx,prompt_length        ; CX = message length
  2291.          mov     bx,stdout               ; BX = standard output handle
  2292.          mov     ah,40h                  ; Fxn 40H = write
  2293.          int     21h                     ; transfer to MS-DOS
  2294.  
  2295.                                          ; get entry from user
  2296.          mov     dx,offset inp_buf       ; DS:DX = input buffer
  2297.          mov     cx,inp_buf_length       ; CX = max length to read
  2298.          mov     bx,stdin                ; BX = standard input handle
  2299.          mov     ah,3fh                  ; Fxn 3FH = read
  2300.          int     21h                     ; transfer to MS-DOS
  2301.  
  2302.          mov     si,offset inp_buf       ; fold lower case characters
  2303.          mov     cx,inp_buf_length       ; in entry to upper case
  2304.  
  2305.  gcmd1:  cmp     byte ptr [si],'a'       ; check if 'a-z'
  2306.          jb      gcmd2                   ; jump, not in range
  2307.          cmp     byte ptr [si],'z'       ; check if 'a-z'
  2308.          ja      gcmd2                   ; jump, not in range
  2309.          sub     byte ptr [si],'a'-'A'   ; convert to upper case
  2310.  
  2311.  gcmd2:  inc     si                      ; advance through entry
  2312.          loop    gcmd1
  2313.          ret                             ; back to caller
  2314.  
  2315.  get_cmd endp
  2316.  
  2317.  
  2318.  get_comspec proc near                   ; get location of COMMAND.COM
  2319.                                          ; from environment "COMSPEC="
  2320.                                          ; Returns Carry = False
  2321.                                          ; if COMSPEC found.
  2322.                                          ; Returns Carry=True
  2323.                                          ; if no COMSPEC.
  2324.  
  2325.          mov     si,offset com_var       ; DS:SI = string to match...
  2326.          call    get_env                 ; search Environment Block
  2327.          jc      gcsp2                   ; jump if COMSPEC not found
  2328.  
  2329.                                          ; ES:DI points past "="
  2330.          mov     si,offset com_spec      ; DS:SI = local buffer
  2331.  
  2332.  gcsp1:  mov     al,es:[di]              ; copy COMSPEC variable
  2333.          mov     [si],al                 ; to local buffer
  2334.          inc     si
  2335.          inc     di
  2336.          or      al,al                   ; null char? (turns off Carry)
  2337.          jnz     gcsp1                   ; no, get next character
  2338.  
  2339.  gcsp2:  ret                             ; back to caller
  2340.  
  2341.  get_comspec endp
  2342.  
  2343.  
  2344.  get_env proc    near                    ; search environment
  2345.                                          ; Call DS:SI = "NAME="
  2346.                                          ; uses contents of "ENV_SEG"
  2347.                                          ; Returns Carry=False and ES:DI
  2348.                                          ; pointing to parameter if found,
  2349.                                          ; Returns Carry=True if no match
  2350.  
  2351.          mov     es,env_seg              ; get environment segment
  2352.          xor     di,di                   ; initialize env. offset
  2353.  
  2354.  genv1:  mov     bx,si                   ; initialize pointer to name
  2355.          cmp     byte ptr es:[di],0      ; end of environment?
  2356.          jne     genv2                   ; jump, end not found
  2357.  
  2358.          stc                             ; no match, return Carry set
  2359.          ret
  2360.  
  2361.  genv2:  mov     al,[bx]                 ; get character from name
  2362.          or      al,al                   ; end of name? (turns off Carry)
  2363.          jz      genv3                   ; yes, name matched
  2364.  
  2365.          cmp     al,es:[di]              ; compare to environment
  2366.          jne     genv4                   ; jump if match failed
  2367.  
  2368.          inc     bx                      ; advance environment
  2369.          inc     di                      ; and name pointers
  2370.          jmp     genv2
  2371.  
  2372.  genv3:                                  ; match found, Carry = clear,
  2373.          ret                             ; ES:DI = variable
  2374.  
  2375.  genv4:  xor     al,al                   ; scan forward in environment
  2376.          mov     cx,-1                   ; for zero byte
  2377.          cld
  2378.          repnz   scasb
  2379.          jmp     genv1                   ; go compare next string
  2380.  
  2381.  get_env endp
  2382.  
  2383.  
  2384.  exec    proc    near                    ; call MS-DOS EXEC function
  2385.                                          ; to run COMMAND.COM.
  2386.  
  2387.          mov     stkseg,ss               ; save stack pointer
  2388.          mov     stkptr,sp
  2389.  
  2390.                                          ; now run COMMAND.COM
  2391.          mov     dx,offset com_spec      ; DS:DX = filename
  2392.          mov     bx,offset par_blk       ; ES:BX = parameter block
  2393.          mov     ax,4b00h                ; Fxn 4BH = EXEC
  2394.                                          ; Subf. 0 = load and execute
  2395.          int     21h                     ; transfer to MS-DOS
  2396.  
  2397.          mov     ax,_DATA                ; make data segment
  2398.          mov     ds,ax                   ; addressable again
  2399.          mov     es,ax
  2400.  
  2401.          cli                             ; (for bug in some 8088s)
  2402.          mov     ss,stkseg               ; restore stack pointer
  2403.          mov     sp,stkptr
  2404.          sti                             ; (for bug in some 8088s)
  2405.  
  2406.          jnc     exec1                   ; jump if no errors
  2407.  
  2408.                                          ; display error message
  2409.          mov     dx,offset msg2          ; DS:DX = message address
  2410.          mov     cx,msg2_length          ; CX = message length
  2411.          mov     bx,stderr               ; BX = standard error handle
  2412.          mov     ah,40h                  ; Fxn 40H = write
  2413.          int     21h                     ; transfer to MS-DOS
  2414.  
  2415.  exec1:  ret                             ; back to caller
  2416.  
  2417.  exec    endp
  2418.  
  2419.  
  2420.  cls_cmd proc    near                    ; intrinsic CLS command
  2421.  
  2422.          mov     dx,offset cls_str       ; send the ANSI escape
  2423.          mov     cx,cls_str_length       ; sequence to clear
  2424.          mov     bx,stdout               ; the screen
  2425.          mov     ah,40h
  2426.          int     21h
  2427.          ret
  2428.  
  2429.  cls_cmd endp
  2430.  
  2431.  
  2432.  dos_cmd proc    near                    ; intrinsic DOS command
  2433.  
  2434.                                          ; set null command tail
  2435.          mov     word ptr par_cmd,offset nultail
  2436.          call    exec                    ; and run COMMAND.COM
  2437.          ret
  2438.  
  2439.  dos_cmd endp
  2440.  
  2441.  
  2442.  exit_cmd proc   near                    ; intrinsic EXIT Command
  2443.  
  2444.          mov     ax,4c00h                ; call MS-DOS terminate
  2445.          int     21h                     ; function with
  2446.                                          ; return code of zero
  2447.  exit_cmd endp
  2448.  
  2449.  _TEXT   ends
  2450.  
  2451.  
  2452.  STACK   segment para stack 'STACK'      ; declare stack segment
  2453.  
  2454.          dw      64 dup (?)
  2455.  
  2456.  STACK   ends
  2457.  
  2458.  
  2459.  _DATA   segment word public 'DATA'
  2460.  
  2461.  commands equ $                          ; "intrinsic" commands table
  2462.                                          ; each entry is ASCIIZ string
  2463.                                          ; followed by the offset
  2464.                                          ; of the procedure to be
  2465.                                          ; executed for that command.
  2466.          db      'CLS',0
  2467.          dw      cls_cmd
  2468.  
  2469.          db      'DOS',0
  2470.          dw      dos_cmd
  2471.  
  2472.          db      'EXIT',0
  2473.          dw      exit_cmd
  2474.  
  2475.          db      0                       ; end of table
  2476.  
  2477.  com_var db      'COMSPEC=',0            ; environment variable
  2478.  
  2479.                                          ; COMMAND.COM filespec
  2480.  com_spec db     80 dup (0)              ; from environment COMSPEC=
  2481.  
  2482.  nultail db      0,cr                    ; null command tail for
  2483.                                          ; invoking COMMAND.COM
  2484.                                          ; as another shell
  2485.  
  2486.  cmd_tail db     0,' /C '                ; command tail for invoking
  2487.                                          ; COMMAND.COM  as a transient
  2488.  
  2489.  inp_buf db      80 dup (0)              ; command line from Standard Input
  2490.  
  2491.  inp_buf_length equ $-inp_buf
  2492.  cmd_tail_length equ $-cmd_tail-1
  2493.  
  2494.  prompt  db      cr,lf,'sh: '            ; SHELL's user prompt
  2495.  prompt_length equ $-prompt
  2496.  
  2497.  env_seg dw      0                       ; segment of Environment Block
  2498.  
  2499.  msg1    db      cr,lf
  2500.          db      'Unable to release memory.'
  2501.          db      cr,lf
  2502.  msg1_length equ $-msg1
  2503.  
  2504.  msg2    db      cr,lf
  2505.          db      'EXEC of COMMAND.COM failed.'
  2506.          db      cr,lf
  2507.  msg2_length equ $-msg2
  2508.  
  2509.  msg3    db      cr,lf
  2510.          db      'No COMSPEC variable in environment.'
  2511.          db      cr,lf
  2512.  msg3_length equ $-msg3
  2513.  
  2514.  cls_str db      escape,'[2J'            ; ANSI escape sequence
  2515.  cls_str_length equ $-cls_str            ; to clear the screen
  2516.  
  2517.                                          ; EXEC parameter block
  2518.  par_blk dw      0                       ; environment segment
  2519.  par_cmd dd      cmd_tail                ; command line
  2520.          dd      fcb1                    ; file control block #1
  2521.          dd      fcb2                    ; file control block #2
  2522.  
  2523.  fcb1    db      0                       ; file control block #1
  2524.          db      11 dup (' ')
  2525.          db      25 dup (0)
  2526.  
  2527.  fcb2    db      0                       ; file control block #2
  2528.          db      11 dup (' ')
  2529.          db      25 dup (0)
  2530.  
  2531.  stkseg  dw      0                       ; original SS contents
  2532.  stkptr  dw      0                       ; original SP contents
  2533.  
  2534.  _DATA   ends
  2535.  
  2536.          end     shell
  2537.  
  2538.  \SAMPCODE\ADVMSDOS\CHAP13
  2539.  \SAMPCODE\ADVMSDOS\CHAP13\TEST0DIV.ASM
  2540.  
  2541.           title     TEST0DIV - test for ZERODIV.COM
  2542.           page      55,132
  2543.  
  2544.  ;
  2545.  ; TEST0DIV.ASM:  Test program for the ZERODIV.ASM
  2546.  ;                divide-by-zero interrupt handler
  2547.  ;
  2548.  ; Copyright (C) 1988 Ray Duncan
  2549.  ;
  2550.  ; Build:   MASM TEST0DIV;
  2551.  ;          LINK TEST0DIV;
  2552.  ;
  2553.  ; Usage:   ZERODIV      (load divide by zero handler)
  2554.  ;          TEST0DIV     (exercise the handler)
  2555.  ;
  2556.  
  2557.  cr      equ     0dh                     ;ASCII carriage return
  2558.  lf      equ     0ah                     ;ASCII line feed
  2559.  
  2560.  _TEXT   segment word public 'CODE'
  2561.  
  2562.          org     100H
  2563.  
  2564.          assume  cs:_TEXT,ds:_TEXT,es:_TEXT,ss:_TEXT
  2565.  
  2566.  main    proc    near
  2567.  
  2568.          mov     dx,offset signon        ; display sign-on message
  2569.          mov     ah,9
  2570.          int     21h
  2571.  
  2572.          mov     dx,0                    ; try register divide
  2573.          mov     ax,1
  2574.          mov     bx,0
  2575.          div     bx
  2576.  
  2577.          mov     dx,offset msg1          ; display success message
  2578.          mov     ah,9
  2579.          int     21h
  2580.  
  2581.          mov     dx,0                    ; try direct divide
  2582.          mov     ax,1
  2583.          div     word ptr zerow
  2584.  
  2585.          mov     dx,offset msg2          ; display success message
  2586.          mov     ah,9
  2587.          int     21h
  2588.  
  2589.          mov     dx,0                    ; try mod = 1 divide
  2590.          mov     ax,1
  2591.          mov     bx,offset zerow
  2592.          dec     bx
  2593.          div     word ptr [bx+1]
  2594.  
  2595.          mov     dx,offset msg3          ; display success message
  2596.          mov     ah,9
  2597.          int     21h
  2598.  
  2599.          mov     dx,0                    ; try mod = 2 divide
  2600.          mov     ax,1
  2601.          mov     bx,0
  2602.          div     word ptr [bx+offset zerow2]
  2603.  
  2604.          mov     dx,offset msg4          ; display success message
  2605.          mov     ah,9
  2606.          int     21h
  2607.  
  2608.          mov     ax,4c00h                ; exit to MS-DOS
  2609.          int     21h
  2610.  
  2611.  main    endp
  2612.  
  2613.  signon  db      cr,lf,'Zero Divide Test program',cr,lf,'$'
  2614.  
  2615.  msg1    db      cr,lf,'Back from register divide',cr,lf,'$'
  2616.  
  2617.  msg2    db      cr,lf,'Back from direct mem divide',cr,lf,'$'
  2618.  
  2619.  msg3    db      cr,lf,'Back from mod = 1 divide',cr,lf,'$'
  2620.  
  2621.  msg4    db      cr,lf,'Back from mod = 2 divide',cr,lf,'$'
  2622.  
  2623.  zerob   db      0                       ; byte-sized operand
  2624.  zerow   dw      0                       ; word-sized operand
  2625.  
  2626.          db      256 dup (?)             ; some empty space
  2627.  
  2628.  zerow2  dw      0
  2629.  
  2630.  _TEXT   ends
  2631.  
  2632.          end     main
  2633.  
  2634.  
  2635.  \SAMPCODE\ADVMSDOS\CHAP13\ZERODIV.ASM
  2636.  
  2637.           title     ZERODIV --- Divide by zero handler
  2638.           page      55,132
  2639.  
  2640.  ;
  2641.  ; ZERODIV.ASM --- Terminate-and-stay-resident handler
  2642.  ;                 for divide-by-zero interrupts
  2643.  ;
  2644.  ; Copyright 1988 Ray Duncan
  2645.  ;
  2646.  ; Build:        C>MASM ZERODIV;
  2647.  ;               C>LINK ZERODIV;
  2648.  ;               C>EXE2BIN ZERODIV.EXE ZERODIV.COM
  2649.  ;               C>DEL ZERODIV.EXE
  2650.  ;
  2651.  ; Usage:        C>ZERODIV
  2652.  ;
  2653.  
  2654.  cr      equ     0dh             ; ASCII carriage return
  2655.  lf      equ     0ah             ; ASCII line feed
  2656.  beep    equ     07h             ; ASCII bell code
  2657.  backsp  equ     08h             ; ASCII backspace code
  2658.  
  2659.  _TEXT   segment word public 'CODE'
  2660.  
  2661.          org     100H
  2662.  
  2663.          assume  cs:_TEXT,ds:_TEXT,es:_TEXT,ss:_TEXT
  2664.  
  2665.  
  2666.  init    proc    near            ; entry point at load time
  2667.  
  2668.                                  ; capture vector for
  2669.                                  ; interrupt zero ...
  2670.          mov     dx,offset zdiv  ; DS:DX = handler address
  2671.          mov     ax,2500h        ; Fxn 25H = set vector
  2672.                                  ; interrupt type = 0
  2673.          int     21h             ; transfer to MS-DOS
  2674.  
  2675.                                  ; print sign-on message
  2676.          mov     dx,offset msg1  ; DS:DX = message address
  2677.          mov     ah,9            ; Fxn 09H = display string
  2678.          int     21h             ; transfer to MS-DOS
  2679.  
  2680.                                  ; DX = paragraphs to reserve
  2681.          mov     dx,((offset pgm_len+15)/16)+10h
  2682.          mov     ax,3100h        ; Fxn 31H = terminate and
  2683.                                  ; stay resident
  2684.          int     21h             ; transfer to MS-DOS
  2685.  
  2686.  init    endp
  2687.  
  2688.  
  2689.  zdiv    proc    far             ; this is the divide by
  2690.                                  ; zero interrupt handler
  2691.  
  2692.          sti                     ; enable interrupts
  2693.  
  2694.          push    ax              ; save registers
  2695.          push    bx
  2696.          push    cx
  2697.          push    dx
  2698.          push    si
  2699.          push    di
  2700.          push    bp
  2701.          push    ds
  2702.          push    es
  2703.  
  2704.          mov     ax,cs           ; make data addressable
  2705.          mov     ds,ax
  2706.  
  2707.                                  ; display message
  2708.                                  ; "Continue or Quit?"
  2709.          mov     dx,offset msg2  ; DS:DX = message address
  2710.          mov     ah,9            ; Fxn 09H = display string
  2711.          int     21h             ; transfer to MS-DOS
  2712.  
  2713.  zdiv1:  mov     ah,1            ; Fxn 01H = read keyboard
  2714.          int     21h             ; transfer to MS-DOS
  2715.  
  2716.          or      al,20h          ; fold char. to lower case
  2717.  
  2718.          cmp     al,'c'          ; is it C or Q?
  2719.          je      zdiv3           ; jump, it's a C
  2720.  
  2721.          cmp     al,'q'
  2722.          je      zdiv2           ; jump, it's a Q
  2723.  
  2724.                                  ; illegal entry, send beep
  2725.                                  ; and erase the character
  2726.          mov     dx,offset msg3  ; DS:DX = message address
  2727.          mov     ah,9            ; Fxn 09H = display string
  2728.          int     21h             ; transfer to MS-DOS
  2729.  
  2730.          jmp     zdiv1           ; try again
  2731.  
  2732.  zdiv2:                          ; user picked "Quit"
  2733.          mov     ax,4cffh        ; terminate current program
  2734.          int     21h             ; with return code = 255
  2735.  
  2736.  zdiv3:                          ; user picked "Continue"
  2737.                                  ; send CR-LF pair
  2738.          mov     dx,offset msg4  ; DS:DX = message address
  2739.          mov     ah,9            ; Fxn 09H = print string
  2740.          int     21h             ; transfer to MS-DOS
  2741.  
  2742.                                  ; what CPU type is this?
  2743.          xor     ax,ax           ; to find out, we'll put
  2744.          push    ax              ; zero in the CPU flags
  2745.          popf                    ; and see what happens
  2746.          pushf
  2747.          pop     ax
  2748.          and     ax,0f000h       ; 8086/88 forces
  2749.          cmp     ax,0f000h       ; bits 12-15 true
  2750.          je      zdiv5           ; jump if 8086/88
  2751.  
  2752.                                  ; otherwise we must adjust
  2753.                                  ; return address to bypass
  2754.                                  ; the divide instruction...
  2755.          mov     bp,sp           ; make stack addressable
  2756.  
  2757.          lds     bx,[bp+18]      ; get address of the
  2758.                                  ; faulting instruction
  2759.  
  2760.          mov     bl,[bx+1]       ; get addressing byte
  2761.          and     bx,0c7h         ; isolate mod & r/m fields
  2762.  
  2763.          cmp     bl,6            ; mod 0, r/m 6 = direct
  2764.          jne     zdiv4           ; not direct, jump
  2765.  
  2766.          add     word ptr [bp+18],4
  2767.          jmp     zdiv5
  2768.  
  2769.  zdiv4:  mov     cl,6            ; otherwise isolate mod
  2770.          shr     bx,cl           ; field and get instruction
  2771.          mov     bl,cs:[bx+itab] ; size from table
  2772.          add     [bp+18],bx
  2773.  
  2774.  zdiv5:  pop     es              ; restore registers
  2775.          pop     ds
  2776.          pop     bp
  2777.          pop     di
  2778.          pop     si
  2779.          pop     dx
  2780.          pop     cx
  2781.          pop     bx
  2782.          pop     ax
  2783.          iret                    ; return from interrupt
  2784.  
  2785.  zdiv    endp
  2786.  
  2787.  
  2788.  msg1    db      cr,lf           ; load-time signon message
  2789.          db      'Divide by Zero Interrupt '
  2790.          db      'Handler installed.'
  2791.          db      cr,lf,'$'
  2792.  
  2793.  msg2    db      cr,lf,lf        ; interrupt-time message
  2794.          db      'Divide by Zero detected: '
  2795.          db      cr,lf,'Continue or Quit (C/Q) ? '
  2796.          db      '$'
  2797.  
  2798.  msg3    db      beep            ; used if bad entry
  2799.          db      backsp,' ',backsp,'$'
  2800.  
  2801.  msg4    db      cr,lf,'$'       ; carriage return-line feed
  2802.  
  2803.                                  ; instruction size table
  2804.  itab    db      2               ; mod = 0
  2805.          db      3               ; mod = 1
  2806.          db      4               ; mod = 2
  2807.          db      2               ; mod = 3
  2808.  
  2809.  pgm_len equ     $-init          ; program length
  2810.  
  2811.  _TEXT   ends
  2812.  
  2813.          end     init
  2814.  
  2815.  
  2816.  \SAMPCODE\ADVMSDOS\CHAP14
  2817.  \SAMPCODE\ADVMSDOS\CHAP14\DRIVER.ASM
  2818.  
  2819.          title   DRIVER.ASM Device Driver Skeleton
  2820.          page    55,132
  2821.  
  2822.  ;
  2823.  ; DRIVER.ASM   MS-DOS device driver skeleton
  2824.  ;
  2825.  ; The driver command code routines are stubs only and have
  2826.  ; no effect but to return a non-error "Done" status.
  2827.  ;
  2828.  ; Copyright (C) 1988 Ray Duncan
  2829.  ;
  2830.  ; Build:   MASM DRIVER;
  2831.  ;          LINK DRIVER;
  2832.  ;          EXE2BIN DRIVER.EXE DRIVER.SYS
  2833.  ;          DEL DRIVER.EXE
  2834.  ;
  2835.  ; Usage:   DEVICE=DRIVER.SYS  (in file CONFIG.SYS)
  2836.  ;
  2837.  
  2838.  _TEXT   segment word public 'CODE'
  2839.  
  2840.          assume  cs:_TEXT,ds:_TEXT,es:NOTHING
  2841.  
  2842.          org     0
  2843.  
  2844.  MaxCmd  equ     24              ; maximum allowed command code
  2845.                                  ; 12 for MS-DOS 2.x
  2846.                                  ; 16 for MS-DOS 3.0-3.1
  2847.                                  ; 24 for MS-DOS 3.2-3.3
  2848.  
  2849.  cr      equ     0dh             ; ASCII carriage return
  2850.  lf      equ     0ah             ; ASCII line feed
  2851.  eom     equ     '$'             ; end of message signal
  2852.  
  2853.  
  2854.  Header:                         ; device driver header
  2855.          dd      -1              ; link to next device driver
  2856.          dw      0c840h          ; device attribute word
  2857.          dw      Strat           ; "Strategy" routine entry point
  2858.          dw      Intr            ; "Interrupt" routine entry point
  2859.          db      'SKELETON'      ; logical device name
  2860.  
  2861.  
  2862.  RHPtr   dd      ?               ; pointer to request header, passed
  2863.                                  ; by MS-DOS kernel to Strategy routine
  2864.  
  2865.  
  2866.  Dispatch:                       ; Interrupt routine command code
  2867.                                  ; dispatch table.
  2868.          dw      Init            ; 0  = initialize driver
  2869.          dw      MediaChk        ; 1  = media check
  2870.          dw      BuildBPB        ; 2  = build BIOS parameter block
  2871.          dw      IoctlRd         ; 3  = I/O control read
  2872.          dw      Read            ; 4  = read
  2873.          dw      NdRead          ; 5  = non-destructive read
  2874.          dw      InpStat         ; 6  = input status
  2875.          dw      InpFlush        ; 7  = flush input buffers
  2876.          dw      Write           ; 8  = write
  2877.          dw      WriteVfy        ; 9  = write with verify
  2878.          dw      OutStat         ; 10 = output status
  2879.          dw      OutFlush        ; 11 = flush output buffers
  2880.          dw      IoctlWt         ; 12 = I/O control write
  2881.          dw      DevOpen         ; 13 = device open       (MS-DOS 3.0+)
  2882.          dw      DevClose        ; 14 = device close      (MS-DOS 3.0+)
  2883.          dw      RemMedia        ; 15 = removeable media  (MS-DOS 3.0+)
  2884.          dw      OutBusy         ; 16 = output until busy (MS-DOS 3.0+)
  2885.          dw      Error           ; 17 = not used
  2886.          dw      Error           ; 18 = not used
  2887.          dw      GenIOCTL        ; 19 = generic IOCTL     (MS-DOS 3.2+)
  2888.          dw      Error           ; 20 = not used
  2889.          dw      Error           ; 21 = not used
  2890.          dw      Error           ; 22 = not used
  2891.          dw      GetLogDev       ; 23 = get logical device (MS-DOS 3.2+)
  2892.          dw      SetLogDev       ; 24 = set logical device (MS-DOS 3.2+)
  2893.  
  2894.  
  2895.  Strat   proc    far             ; device driver Strategy routine,
  2896.                                  ; called by MS-DOS kernel with
  2897.                                  ; ES:BX = address of request header
  2898.  
  2899.                                  ; save pointer to request header
  2900.          mov     word ptr cs:[RHPtr],bx
  2901.          mov     word ptr cs:[RHPtr+2],es
  2902.  
  2903.          ret                     ; back to MS-DOS kernel
  2904.  
  2905.  Strat   endp
  2906.  
  2907.  
  2908.  Intr    proc  far               ; device driver Interrupt routine,
  2909.                                  ; called by MS-DOS kernel immediately
  2910.                                  ; after call to Strategy routine
  2911.  
  2912.          push    ax              ; save general registers
  2913.          push    bx
  2914.          push    cx
  2915.          push    dx
  2916.          push    ds
  2917.          push    es
  2918.          push    di
  2919.          push    si
  2920.          push    bp
  2921.  
  2922.          push    cs              ; make local data addressable
  2923.          pop     ds              ; by setting DS = CS
  2924.  
  2925.          les     di,[RHPtr]      ; let ES:DI = request header
  2926.  
  2927.                                  ; get BX = command code
  2928.          mov     bl,es:[di+2]
  2929.          xor     bh,bh
  2930.          cmp     bx,MaxCmd       ; make sure it's legal
  2931.          jle     Intr1           ; jump, function code is ok
  2932.          call    Error           ; set error bit, "Unknown Command" code
  2933.          jmp     Intr2
  2934.  
  2935.  Intr1:  shl     bx,1            ; form index to dispatch table
  2936.                                  ; and branch to command code routine
  2937.          call    word ptr [bx+Dispatch]
  2938.  
  2939.          les     di,[RHPtr]      ; ES:DI = addr. of request header
  2940.  
  2941.  Intr2:  or      ax,0100h        ; merge 'Done' bit into status, and
  2942.          mov     es:[di+3],ax    ; store status into request header
  2943.  
  2944.          pop     bp              ; restore general registers
  2945.          pop     si
  2946.          pop     di
  2947.          pop     es
  2948.          pop     ds
  2949.          pop     dx
  2950.          pop     cx
  2951.          pop     bx
  2952.          pop     ax
  2953.          ret                     ; back to MS-DOS kernel
  2954.  
  2955.  
  2956.  ; Command code routines are called by the Interrupt routine
  2957.  ; via the Dispatch table with ES:DI pointing to the request
  2958.  ; header.  Each routine should return AX=0 if function was
  2959.  ; completed successfully, or AX = 8000h + error code if
  2960.  ; function failed.
  2961.  
  2962.  
  2963.  MediaChk proc   near            ; function 1 = Media Check
  2964.  
  2965.          xor     ax,ax
  2966.          ret
  2967.  
  2968.  MediaChk endp
  2969.  
  2970.  
  2971.  BuildBPB proc   near            ; function 2 = Build BPB
  2972.  
  2973.          xor     ax,ax
  2974.          ret
  2975.  
  2976.  BuildBPB endp
  2977.  
  2978.  
  2979.  IoctlRd proc    near            ; function 3 = I/O Control Read
  2980.  
  2981.          xor     ax,ax
  2982.          ret
  2983.  
  2984.  IoctlRd endp
  2985.  
  2986.  
  2987.  Read    proc    near            ; function 4 = Read (Input)
  2988.  
  2989.          xor     ax,ax
  2990.          ret
  2991.  
  2992.  Read    endp
  2993.  
  2994.  
  2995.  NdRead  proc    near            ; function 5 = Non-Destructive Read
  2996.  
  2997.          xor     ax,ax
  2998.          ret
  2999.  
  3000.  NdRead  endp
  3001.  
  3002.  
  3003.  InpStat proc    near            ; function 6 = Input Status
  3004.  
  3005.          xor     ax,ax
  3006.          ret
  3007.  
  3008.  InpStat endp
  3009.  
  3010.  
  3011.  InpFlush proc   near            ; function 7 = Flush Input Buffers
  3012.  
  3013.          xor     ax,ax
  3014.          ret
  3015.  
  3016.  InpFlush endp
  3017.  
  3018.  
  3019.  Write   proc    near            ; function 8 = Write (Output)
  3020.  
  3021.          xor     ax,ax
  3022.          ret
  3023.  
  3024.  Write   endp
  3025.  
  3026.  
  3027.  WriteVfy proc   near            ; function 9 = Write with Verify
  3028.  
  3029.          xor     ax,ax
  3030.          ret
  3031.  
  3032.  WriteVfy endp
  3033.  
  3034.  
  3035.  OutStat proc    near            ; function 10 = Output Status
  3036.  
  3037.          xor     ax,ax
  3038.          ret
  3039.  
  3040.  OutStat endp
  3041.  
  3042.  
  3043.  OutFlush proc   near            ; function 11 = Flush Output Buffers
  3044.  
  3045.          xor     ax,ax
  3046.          ret
  3047.  
  3048.  OutFlush endp
  3049.  
  3050.  
  3051.  IoctlWt proc    near            ; function 12 = I/O Control Write
  3052.  
  3053.          xor     ax,ax
  3054.          ret
  3055.  
  3056.  IoctlWt endp
  3057.  
  3058.  
  3059.  DevOpen proc    near            ; function 13 = Device Open
  3060.  
  3061.          xor     ax,ax
  3062.          ret
  3063.  
  3064.  DevOpen endp
  3065.  
  3066.  
  3067.  DevClose proc   near            ; function 14 = Device Close
  3068.  
  3069.          xor     ax,ax
  3070.          ret
  3071.  
  3072.  DevClose endp
  3073.  
  3074.  
  3075.  RemMedia proc   near            ; function 15 = Removable Media
  3076.  
  3077.          xor     ax,ax
  3078.          ret
  3079.  
  3080.  RemMedia endp
  3081.  
  3082.  
  3083.  OutBusy proc    near            ; function 16 = Output Until Busy
  3084.  
  3085.          xor     ax,ax
  3086.          ret
  3087.  
  3088.  OutBusy endp
  3089.  
  3090.  
  3091.  GenIOCTL proc   near            ; function 19 = Generic IOCTL
  3092.  
  3093.          xor     ax,ax
  3094.          ret
  3095.  
  3096.  GenIOCTL endp
  3097.  
  3098.  
  3099.  GetLogDev proc  near            ; function 23 = Get Logical Device
  3100.  
  3101.          xor     ax,ax
  3102.          ret
  3103.  
  3104.  GetLogDev endp
  3105.  
  3106.  
  3107.  SetLogDev proc  near            ; function 24 = Set Logical Device
  3108.  
  3109.          xor     ax,ax
  3110.          ret
  3111.  
  3112.  SetLogDev endp
  3113.  
  3114.  
  3115.  Error   proc    near            ; bad command code in request header
  3116.  
  3117.          mov     ax,8003h        ; error bit + "Unknown Command" code
  3118.          ret
  3119.  
  3120.  Error   endp
  3121.  
  3122.  
  3123.  Init    proc    near            ; function 0 = initialize driver
  3124.  
  3125.          push    es              ; save address of request header
  3126.          push    di
  3127.  
  3128.          mov     ax,cs           ; convert load address to ASCII
  3129.          mov     bx,offset Ident1
  3130.          call    hexasc
  3131.  
  3132.          mov     ah,9            ; display driver sign-on message
  3133.          mov     dx,offset Ident
  3134.          int     21h
  3135.  
  3136.          pop     di              ; restore request header address
  3137.          pop     es
  3138.  
  3139.                                  ; set addr. of free memory
  3140.                                  ; above driver (break address)
  3141.          mov     word ptr es:[di+14],offset Init
  3142.          mov     word ptr es:[di+16],cs
  3143.  
  3144.          xor     ax,ax           ; return status
  3145.          ret
  3146.  
  3147.  Init    endp
  3148.  
  3149.  
  3150.  hexasc  proc    near            ; converts word to hex ASCII
  3151.                                  ; call with AX = value,
  3152.                                  ; DS:BX = address for string
  3153.                                  ; returns AX, BX destroyed
  3154.  
  3155.          push    cx              ; save registers
  3156.          push    dx
  3157.  
  3158.          mov     dx,4            ; initialize character counter
  3159.  
  3160.  hexasc1:
  3161.          mov     cx,4            ; isolate next four bits
  3162.          rol     ax,cl
  3163.          mov     cx,ax
  3164.          and     cx,0fh
  3165.          add     cx,'0'          ; convert to ASCII
  3166.          cmp     cx,'9'          ; is it 0-9?
  3167.          jbe     hexasc2         ; yes, jump
  3168.          add     cx,'A'-'9'-1    ; add fudge factor for A-F
  3169.  
  3170.  hexasc2:                        ; store this character
  3171.          mov     [bx],cl
  3172.          inc     bx              ; bump string pointer
  3173.  
  3174.          dec     dx              ; count characters converted
  3175.          jnz     hexasc1         ; loop, not four yet
  3176.  
  3177.          pop     dx              ; restore registers
  3178.          pop     cx
  3179.          ret                     ; back to caller
  3180.  
  3181.  hexasc  endp
  3182.  
  3183.  
  3184.  Ident   db      cr,lf,lf
  3185.          db      'Advanced MS-DOS Example Device Driver'
  3186.          db      cr,lf
  3187.          db      'Device driver header at: '
  3188.  Ident1  db      'XXXX:0000'
  3189.          db      cr,lf,lf,eom
  3190.  
  3191.  Intr    endp
  3192.  
  3193.  _TEXT   ends
  3194.  
  3195.          end
  3196.  
  3197.  
  3198.  \SAMPCODE\ADVMSDOS\CHAP15
  3199.  \SAMPCODE\ADVMSDOS\CHAP15\CLEAN.C
  3200.  
  3201.  /*
  3202.      CLEAN.C     Filter to turn document files into
  3203.                  normal text files.
  3204.  
  3205.      Copyright 1988 Ray Duncan
  3206.  
  3207.      Compile:    C>CL CLEAN.C
  3208.  
  3209.      Usage:      C>CLEAN  <infile >outfile
  3210.  
  3211.      All text characters are passed through with high bit stripped
  3212.      off.  Form feeds, carriage returns, and line feeds are passed
  3213.      through.  Tabs are expanded to spaces.  All other control codes
  3214.      are discarded.
  3215.  */
  3216.  
  3217.  #include <stdio.h>
  3218.  
  3219.  #define TAB_WIDTH   8               /* width of a tab stop */
  3220.  
  3221.  #define TAB     '\x09'              /* ASCII tab character */
  3222.  #define LF      '\x0A'              /* ASCII line feed */
  3223.  #define FF      '\x0C'              /* ASCII form feed */
  3224.  #define CR      '\x0D'              /* ASCII carriage return */
  3225.  #define BLANK   '\x20'              /* ASCII space code */
  3226.  #define EOFMK   '\x1A'              /* Ctrl-Z end of file */
  3227.  
  3228.  
  3229.  main(int argc, char *argv[])
  3230.  {
  3231.      char c;                         /* char. from stdin */
  3232.      int col = 0;                    /* column counter */
  3233.  
  3234.      while((c = getchar()) != EOF)   /* read input character */
  3235.      {
  3236.          c &= 0x07F;                 /* strip high bit */
  3237.  
  3238.          switch(c)                   /* decode character */
  3239.          {
  3240.              case LF:                /* if line feed or */
  3241.              case CR:                /* carriage return, */
  3242.                  col=0;              /* reset column count */
  3243.  
  3244.              case FF:                /* if form feed, carriage */
  3245.                  wchar(c);           /* return, or line feed */
  3246.                  break;              /* pass character through */
  3247.  
  3248.              case TAB:               /* if tab expand to spaces */
  3249.                  do wchar(BLANK);
  3250.                  while((++col % TAB_WIDTH) != 0);
  3251.                  break;
  3252.  
  3253.              default:                /* discard other control */
  3254.                  if(c >= BLANK)      /* characters, pass text */
  3255.                  {                   /* characters through */
  3256.                      wchar(c);
  3257.                      col++;          /* bump column counter */
  3258.                  }
  3259.                  break;
  3260.          }
  3261.      }
  3262.      wchar(EOFMK);                   /* write end-of-file mark */
  3263.      exit(0);
  3264.  }
  3265.  
  3266.  
  3267.  /*
  3268.      Write a character to the standard output.  If
  3269.      write fails, display error message and terminate.
  3270.  */
  3271.  
  3272.  wchar(char c)
  3273.  {
  3274.      if((putchar(c) == EOF) && (c != EOFMK))
  3275.      {
  3276.          fputs("clean: disk full",stderr);
  3277.          exit(1);
  3278.      }
  3279.  }
  3280.  
  3281.  \SAMPCODE\ADVMSDOS\CHAP15\PROTO.C
  3282.  
  3283.  /*
  3284.      PROTO.C: prototype character-oriented filter
  3285.  
  3286.      Copyright 1988 Ray Duncan
  3287.  
  3288.      Build:  CL PROTO.C
  3289.  
  3290.  */
  3291.  
  3292.  #include <stdio.h>
  3293.  
  3294.  main(int argc, char *argv[])
  3295.  {
  3296.      char ch;
  3297.  
  3298.      while((ch=getchar()) != EOF)    /* read a character */
  3299.      {
  3300.          ch = translate(ch);         /* translate it if necessary */
  3301.  
  3302.          putchar(ch);                /* write the character */
  3303.      }
  3304.      exit(0);                        /* terminate at end of file */
  3305.  }
  3306.  
  3307.  
  3308.  /*
  3309.      Perform any necessary translation on character
  3310.      from input file.  This example just returns
  3311.      the same character.
  3312.  */
  3313.  
  3314.  int translate(char ch)
  3315.  {
  3316.      return (ch);
  3317.  }
  3318.  
  3319.  \SAMPCODE\ADVMSDOS\CHAP15\CLEAN.ASM
  3320.  
  3321.          title   CLEAN - Text file filter
  3322.          page    55,132
  3323.  ;
  3324.  ; CLEAN.ASM     Filter to turn document files into
  3325.  ;               normal text files.
  3326.  ;
  3327.  ; Copyright 1988 Ray Duncan
  3328.  ;
  3329.  ; Build:        C>MASM CLEAN;
  3330.  ;               C>LINK CLEAN;
  3331.  ;
  3332.  ; Usage:        C>CLEAN  <infile  >outfile
  3333.  ;
  3334.  ; All text characters are passed through with high
  3335.  ; bit stripped off.  Form feeds, carriage returns,
  3336.  ; and line feeds are passed through.  Tabs are expanded
  3337.  ; to spaces.  All other control codes are discarded.
  3338.  ;
  3339.  
  3340.  tab     equ     09h             ; ASCII tab code
  3341.  lf      equ     0ah             ; ASCII line feed
  3342.  ff      equ     0ch             ; ASCII form feed
  3343.  cr      equ     0dh             ; ASCII carriage return
  3344.  blank   equ     020h            ; ASCII space code
  3345.  eof     equ     01ah            ; Ctrl-Z End-of-file
  3346.  
  3347.  tabsiz  equ     8               ; width of tab stop
  3348.  
  3349.  bufsiz  equ     128             ; size of input and
  3350.                                  ; output buffers
  3351.  
  3352.  stdin   equ     0000            ; standard input handle
  3353.  stdout  equ     0001            ; standard output handle
  3354.  stderr  equ     0002            ; standard error handle
  3355.  
  3356.  
  3357.  _TEXT   segment word public 'CODE'
  3358.  
  3359.          assume  cs:_TEXT,ds:_DATA,es:_DATA,ss:STACK
  3360.  
  3361.  clean   proc    far             ; entry point from MS-DOS.
  3362.  
  3363.          push    ds              ; save DS:0000 for final
  3364.          xor     ax,ax           ; return to MS-DOS, in case
  3365.          push    ax              ; Function 4CH can't be used.
  3366.  
  3367.          mov     ax,_DATA        ; make data segment addressable
  3368.          mov     ds,ax
  3369.          mov     es,ax
  3370.  
  3371.          mov     ah,30h          ; check version of MS-DOS
  3372.          int     21h
  3373.          cmp     al,2            ; MS-DOS 2.0 or later?
  3374.          jae     clean1          ; jump if version OK
  3375.  
  3376.                                  ; MS-DOS 1.x, display error
  3377.                                  ; message and exit...
  3378.          mov     dx,offset msg1  ; DS:DX = message address
  3379.          mov     ah,9            ; Fxn 9 = display string
  3380.          int     21h             ; transfer to MS-DOS
  3381.          ret                     ; then exit the old way
  3382.  
  3383.  clean1: call    init            ; initialize input buffer
  3384.  
  3385.  clean2: call    getc            ; get character from input
  3386.          jc      clean9          ; exit if end of stream
  3387.  
  3388.          and     al,07fh         ; strip off high bit
  3389.  
  3390.          cmp     al,blank        ; is it a control char?
  3391.          jae     clean4          ; no, write it
  3392.  
  3393.          cmp     al,eof          ; is it end of file?
  3394.          je      clean8          ; yes, write EOF and exit
  3395.  
  3396.          cmp     al,tab          ; is it a tab?
  3397.          je      clean6          ; yes, expand it to spaces
  3398.  
  3399.          cmp     al,cr           ; is it a carriage return?
  3400.          je      clean3          ; yes, go process it.
  3401.  
  3402.          cmp     al,lf           ; is it a line feed?
  3403.          je      clean3          ; yes, go process it.
  3404.  
  3405.          cmp     al,ff           ; is it a form feed?
  3406.          jne     clean2          ; no, discard it
  3407.  
  3408.  clean3: mov     column,0        ; if CR, LF, or FF
  3409.          jmp     clean5          ; reset column to zero
  3410.  
  3411.  clean4: inc     column          ; if non-control char.
  3412.                                  ; increment column counter
  3413.  
  3414.  clean5: call    putc            ; write char. to stdout
  3415.          jnc     clean2          ; if disk not full,
  3416.                                  ; get another character
  3417.  
  3418.                                  ; write failed...
  3419.          mov     dx,offset msg2  ; DS:DX = error message
  3420.          mov     cx,msg2_len     ; CX = message length
  3421.          mov     bx,stderr       ; BX = standard error handle
  3422.          mov     ah,40h          ; Fxn 40H = write
  3423.          int     21h             ; transfer to MS-DOS
  3424.  
  3425.          mov     ax,4c01h        ; Fxn 4CH = terminate
  3426.                                  ; return code = 1
  3427.          int     21h             ; transfer to MS-DOS
  3428.  
  3429.  clean6: mov     ax,column       ; tab code detected
  3430.          cwd                     ; tabsiz - (column MOD tabsiz)
  3431.          mov     cx,tabsiz       ; is number of spaces needed
  3432.          idiv    cx              ; to move to next tab stop
  3433.          sub     cx,dx
  3434.  
  3435.          add     column,cx       ; also update column counter
  3436.  
  3437.  clean7: push    cx              ; save spaces counter
  3438.  
  3439.          mov     al,blank        ; write an ASCII space
  3440.          call    putc
  3441.  
  3442.          pop     cx              ; restore spaces counter
  3443.          loop    clean7          ; loop until tab stop
  3444.  
  3445.          jmp     clean2          ; get another character
  3446.  
  3447.  clean8: call    putc            ; write EOF mark
  3448.  
  3449.  clean9: call    flush           ; write last output buffer
  3450.          mov     ax,4c00h        ; Fxn 4CH = terminate
  3451.                                  ; return code =0
  3452.          int     21h             ; transfer to MS-DOS
  3453.  
  3454.  clean   endp
  3455.  
  3456.  
  3457.  getc    proc    near            ; get char. from stdin
  3458.                                  ; returns Carry = 1 if
  3459.                                  ; end of input, else
  3460.                                  ; AL = char, Carry = 0
  3461.  
  3462.          mov     bx,iptr         ; get input buffer pointer
  3463.          cmp     bx,ilen         ; end of buffer reached?
  3464.          jne     getc1           ; not yet, jump
  3465.  
  3466.                                  ; more data is needed...
  3467.          mov     bx,stdin        ; BX = standard input handle
  3468.          mov     cx,bufsiz       ; CX = length to read
  3469.          mov     dx,offset ibuff ; DS:DX = buffer address
  3470.          mov     ah,3fh          ; Fxn 3FH = read
  3471.          int     21h             ; transfer to MS-DOS
  3472.          jc      getc2           ; jump if read failed
  3473.  
  3474.          or      ax,ax           ; was anything read?
  3475.          jz      getc2           ; jump if end of input
  3476.  
  3477.          mov     ilen,ax         ; save length of data
  3478.          xor     bx,bx           ; reset buffer pointer
  3479.  
  3480.  getc1:  mov     al,[ibuff+bx]   ; get char. from buffer
  3481.          inc     bx              ; bump buffer pointer
  3482.  
  3483.          mov     iptr,bx         ; save updated pointer
  3484.          clc                     ; return char in AL
  3485.          ret                     ; and Carry = 0 (clear)
  3486.  
  3487.  getc2:  stc                     ; end of input stream
  3488.          ret                     ; return Carry = 1 (set)
  3489.  
  3490.  getc    endp
  3491.  
  3492.  
  3493.  putc    proc    near            ; send char. to stdout
  3494.                                  ; returns Carry = 1 if
  3495.                                  ; error, else Carry = 0
  3496.  
  3497.          mov     bx,optr         ; store character into
  3498.          mov     [obuff+bx],al   ; output buffer
  3499.  
  3500.          inc     bx              ; bump buffer pointer
  3501.          cmp     bx,bufsiz       ; buffer full?
  3502.          jne     putc1           ; no, jump
  3503.  
  3504.          mov     bx,stdout       ; BX = standard output handle
  3505.          mov     cx,bufsiz       ; CX = length to write
  3506.          mov     dx,offset obuff ; DS:DX = buffer address
  3507.          mov     ah,40h          ; Fxn 40H = write
  3508.          int     21h             ; transfer to MS-DOS
  3509.          jc      putc2           ; jump if write failed
  3510.  
  3511.          cmp     ax,cx           ; was write complete?
  3512.          jne     putc2           ; jump if disk full
  3513.  
  3514.          xor     bx,bx           ; reset buffer pointer
  3515.  
  3516.  putc1:  mov     optr,bx         ; save buffer pointer
  3517.          clc                     ; write successful,
  3518.          ret                     ; return Carry = 0 (clear)
  3519.  
  3520.  putc2:  stc                     ; write failed or disk full,
  3521.          ret                     ; return Carry = 1 (set)
  3522.  
  3523.  putc    endp
  3524.  
  3525.  
  3526.  init    proc    near            ; initialize input buffer
  3527.  
  3528.          mov     bx,stdin        ; BX = standard input handle
  3529.          mov     cx,bufsiz       ; CX = length to read
  3530.          mov     dx,offset ibuff ; DS:DX = buffer address
  3531.          mov     ah,3fh          ; Fxn 3FH = read
  3532.          int     21h             ; transfer to MS-DOS
  3533.          jc      init1           ; jump if read failed
  3534.          mov     ilen,ax         ; save actual bytes read
  3535.  init1:  ret
  3536.  
  3537.  init    endp
  3538.  
  3539.  
  3540.  flush   proc    near            ; flush output buffer
  3541.  
  3542.          mov     cx,optr         ; CX = bytes to write
  3543.          jcxz    flush1          ; exit if buffer empty
  3544.          mov     dx,offset obuff ; DS:DX = buffer address
  3545.          mov     bx,stdout       ; BX = standard output handle
  3546.          mov     ah,40h          ; Fxn 40H = write
  3547.          int     21h             ; transfer to MS-DOS
  3548.  flush1: ret
  3549.  
  3550.  flush   endp
  3551.  
  3552.  _TEXT   ends
  3553.  
  3554.  
  3555.  _DATA   segment word public 'DATA'
  3556.  
  3557.  ibuff   db      bufsiz dup (0)  ; input buffer
  3558.  obuff   db      bufsiz dup (0)  ; output buffer
  3559.  
  3560.  iptr    dw      0               ; ibuff pointer
  3561.  ilen    dw      0               ; bytes in ibuff
  3562.  optr    dw      0               ; obuff pointer
  3563.  
  3564.  column  dw      0               ; current column counter
  3565.  
  3566.  msg1    db      cr,lf
  3567.          db      'clean: need MS-DOS version 2 or greater.'
  3568.          db      cr,lf,'$'
  3569.  
  3570.  msg2    db      cr,lf
  3571.          db      'clean: disk is full.'
  3572.          db      cr,lf
  3573.  msg2_len equ    $-msg2
  3574.  
  3575.  _DATA   ends
  3576.  
  3577.  
  3578.  STACK   segment para stack 'STACK'
  3579.  
  3580.          dw      64 dup (?)
  3581.  
  3582.  STACK   ends
  3583.  
  3584.          end     clean
  3585.  
  3586.  \SAMPCODE\ADVMSDOS\CHAP15\PROTO.ASM
  3587.  
  3588.           name      proto
  3589.           page      55,132
  3590.           title     PROTO.ASM --- prototype filter
  3591.  ;
  3592.  ; PROTO.ASM:  prototype character-oriented filter
  3593.  ;
  3594.  ; Copyright 1988 Ray Duncan
  3595.  ;
  3596.  ; Build:  MASM PROTO;
  3597.  ;         LINK PROTO;
  3598.  ;
  3599.  ; Usage:  PROTO
  3600.  ;
  3601.  
  3602.  stdin   equ     0               ; standard input handle
  3603.  stdout  equ     1               ; standard output handle
  3604.  stderr  equ     2               ; standard error handle
  3605.  
  3606.  cr      equ     0dh             ; ASCII carriage return
  3607.  lf      equ     0ah             ; ASCII linefeed
  3608.  
  3609.  
  3610.  _TEXT   segment word public 'CODE'
  3611.  
  3612.          assume  cs:_TEXT,ds:_DATA,ss:STACK
  3613.  
  3614.  main    proc    far             ; entry point from MS-DOS
  3615.  
  3616.          mov     ax,_DATA        ; set DS = our data segment
  3617.          mov     ds,ax
  3618.  
  3619.  main1:                          ; read char. from stdin...
  3620.          mov     dx,offset char  ; DS:DX = buffer address
  3621.          mov     cx,1            ; CX = length to read
  3622.          mov     bx,stdin        ; BX = standard input handle
  3623.          mov     ah,3fh          ; Fxn 3FH = read
  3624.          int     21h             ; transfer to MS-DOS
  3625.          jc      main3           ; if error, terminate
  3626.  
  3627.          cmp     ax,1            ; any character read?
  3628.          jne     main2           ; if end of file, terminate
  3629.  
  3630.          call    translate       ; translate character
  3631.  
  3632.                                  ; write char. to stdout...
  3633.          mov     dx,offset char  ; DS:DX = buffer address
  3634.          mov     cx,1            ; CX = length to write
  3635.          mov     bx,stdout       ; BX = standard output handle
  3636.          mov     ah,40h          ; Fxn 40H = write
  3637.          int     21h             ; transfer to MS-DOS
  3638.          jc      main3           ; if error, terminate
  3639.  
  3640.          cmp     ax,1            ; was character written?
  3641.          jne     main3           ; if disk full, terminate
  3642.  
  3643.          jmp     main1           ; get another character
  3644.  
  3645.  main2:                          ; end of file reached
  3646.          mov     ax,4c00h        ; Fxn 4CH = terminate
  3647.                                  ; return code = 0
  3648.          int     21h             ; transfer to MS-DOS
  3649.  
  3650.  main3:                          ; error or disk full
  3651.          mov     ax,4c01h        ; Fxn 4CH = terminate
  3652.                                  ; return code = 1
  3653.          int     21h             ; transfer to MS-DOS
  3654.  
  3655.  main    endp
  3656.  
  3657.  ;
  3658.  ; Perform any necessary translation on character
  3659.  ; from standard input stored in variable 'char'.
  3660.  ; This example just leaves character unchanged.
  3661.  ;
  3662.  translate proc  near
  3663.  
  3664.          ret                     ; does nothing
  3665.  
  3666.  translate endp
  3667.  
  3668.  _TEXT   ends
  3669.  
  3670.  
  3671.  _DATA   segment word public 'DATA'
  3672.  
  3673.  char    db      0               ; storage for input character
  3674.  
  3675.  _DATA   ends
  3676.  
  3677.  
  3678.  STACK   segment para stack 'STACK'
  3679.  
  3680.          dw      64 dup (?)
  3681.  
  3682.  STACK   ends
  3683.  
  3684.          end     main            ; defines program entry point
  3685.  
  3686.  \SAMPCODE\DOS_ENCY
  3687.  \SAMPCODE\DOS_ENCY\10
  3688.  \SAMPCODE\DOS_ENCY\10\CHILD.ASM
  3689.  
  3690.           name      child
  3691.           title     'CHILD process'
  3692.  ;
  3693.  ; CHILD.EXE --- a simple process loaded by PARENT.EXE
  3694.  ; to demonstrate the MS-DOS EXEC call, Subfunction 00H.
  3695.  ;
  3696.  ; Ray Duncan, June 1987
  3697.  ;
  3698.  
  3699.  stdin   equ     0                       ; standard input
  3700.  stdout  equ     1                       ; standard output
  3701.  stderr  equ     2                       ; standard error
  3702.  
  3703.  cr      equ     0dh                     ; ASCII carriage return
  3704.  lf      equ     0ah                     ; ASCII linefeed
  3705.  
  3706.  
  3707.  DGROUP  group   _DATA,STACK
  3708.  
  3709.  
  3710.  _TEXT   segment byte public 'CODE'      ; executable code segment
  3711.  
  3712.          assume  cs:_TEXT,ds:_DATA,ss:STACK
  3713.  
  3714.  main    proc    far                     ; entry point from MS-DOS
  3715.  
  3716.          mov     ax,_DATA                ; set DS = our data segment
  3717.          mov     ds,ax
  3718.  
  3719.                                          ; display child message ...
  3720.          mov     dx,offset msg           ; DS:DX = address of message
  3721.          mov     cx,msg_len              ; CX = length of message
  3722.          mov     bx,stdout               ; BX = standard output handle
  3723.          mov     ah,40h                  ; AH = fxn 40H, write file/device
  3724.          int     21h                     ; transfer to MS-DOS
  3725.          jc      main2                   ; jump if any error
  3726.  
  3727.          mov     ax,4c00h                ; no error, terminate child
  3728.          int     21h                     ; with return code = 0
  3729.  
  3730.  main2:  mov     ax,4c01h                ; error, terminate child
  3731.          int     21h                     ; with return code = 1
  3732.  
  3733.  main    endp                            ; end of main procedure
  3734.  
  3735.  _TEXT   ends
  3736.  
  3737.  
  3738.  _DATA   segment para public 'DATA'      ; static & variable data segment
  3739.  
  3740.  msg     db      cr,lf,'Child executing!',cr,lf
  3741.  msg_len equ     $-msg
  3742.  
  3743.  _DATA   ends
  3744.  
  3745.  
  3746.  STACK   segment para stack 'STACK'
  3747.  
  3748.          dw      64 dup (?)
  3749.  
  3750.  STACK   ends
  3751.  
  3752.  
  3753.          end     main                    ; defines program entry point
  3754.  
  3755.  \SAMPCODE\DOS_ENCY\10\OVERLAY.ASM
  3756.  
  3757.           name      overlay
  3758.           title     'OVERLAY segment'
  3759.  ;
  3760.  ; OVERLAY.EXE --- a simple overlay segment
  3761.  ; loaded by ROOT.EXE to demonstrate use of
  3762.  ; the MS-DOS EXEC call Subfunction 03H.
  3763.  ;
  3764.  ; The overlay does not contain a STACK segment
  3765.  ; because it uses the ROOT segment's stack.
  3766.  ;
  3767.  ; Ray Duncan, June 1987
  3768.  ;
  3769.  
  3770.  stdin   equ     0                       ; standard input
  3771.  stdout  equ     1                       ; standard output
  3772.  stderr  equ     2                       ; standard error
  3773.  
  3774.  cr      equ     0dh                     ; ASCII carriage return
  3775.  lf      equ     0ah                     ; ASCII linefeed
  3776.  
  3777.  
  3778.  _TEXT   segment byte public 'CODE'      ; executable code segment
  3779.  
  3780.          assume  cs:_TEXT,ds:_DATA
  3781.  ovlay   proc    far                     ; entry point from root segment
  3782.  
  3783.          mov     ax,_DATA                ; set DS = local data segment
  3784.          mov     ds,ax
  3785.  
  3786.                                          ; display overlay message ...
  3787.          mov     dx,offset msg           ; DS:DX = address of message
  3788.          mov     cx,msg_len              ; CX = length of message
  3789.          mov     bx,stdout               ; BX = standard output handle
  3790.          mov     ah,40h                  ; AH = fxn 40H, write file/device
  3791.          int     21h                     ; transfer to MS-DOS
  3792.  
  3793.          ret                             ; return to root segment
  3794.  
  3795.  ovlay   endp                            ; end of ovlay procedure
  3796.  
  3797.  _TEXT   ends
  3798.  
  3799.  
  3800.  _DATA   segment para public 'DATA'      ; static & variable data segment
  3801.  
  3802.  msg     db      cr,lf,'Overlay executing!',cr,lf
  3803.  msg_len equ     $-msg
  3804.  
  3805.  _DATA   ends
  3806.  
  3807.          end
  3808.  
  3809.  \SAMPCODE\DOS_ENCY\10\PARENT.ASM
  3810.  
  3811.           name      parent
  3812.           title     'PARENT --- demonstrate EXEC call'
  3813.  ;
  3814.  ; PARENT.EXE --- demonstration of EXEC to run process
  3815.  ;
  3816.  ; Uses MS-DOS EXEC (Int 21H Function 4BH Subfunction 00H)
  3817.  ; to load and execute a child process named CHILD.EXE,
  3818.  ; then displays CHILD's return code.
  3819.  ;
  3820.  ; Ray Duncan, June 1987
  3821.  ;
  3822.  
  3823.  stdin   equ     0                       ; standard input
  3824.  stdout  equ     1                       ; standard output
  3825.  stderr  equ     2                       ; standard error
  3826.  
  3827.  stksize equ     128                     ; size of stack
  3828.  
  3829.  cr      equ     0dh                     ; ASCII carriage return
  3830.  lf      equ     0ah                     ; ASCII linefeed
  3831.  
  3832.  
  3833.  DGROUP  group   _DATA,_ENVIR,_STACK
  3834.  
  3835.  
  3836.  _TEXT   segment byte public 'CODE'      ; executable code segment
  3837.  
  3838.          assume  cs:_TEXT,ds:_DATA,ss:_STACK
  3839.  
  3840.  
  3841.  stk_seg dw      ?                       ; original SS contents
  3842.  stk_ptr dw      ?                       ; original SP contents
  3843.  
  3844.  
  3845.  main    proc    far                     ; entry point from MS-DOS
  3846.  
  3847.          mov     ax,_DATA                ; set DS = our data segment
  3848.          mov     ds,ax
  3849.  
  3850.                                          ; now give back extra memory
  3851.                                          ; so child has somewhere to run...
  3852.          mov     ax,es                   ; let AX = segment of PSP base
  3853.          mov     bx,ss                   ; and BX = segment of stack base
  3854.          sub     bx,ax                   ; reserve seg stack - seg psp
  3855.          add     bx,stksize/16           ; plus paragraphs of stack
  3856.          mov     ah,4ah                  ; fxn 4AH = modify memory block
  3857.          int     21h
  3858.          jc      main1
  3859.                                          ; display parent message ...
  3860.          mov     dx,offset DGROUP:msg1   ; DS:DX = address of message
  3861.          mov     cx,msg1_len             ; CX = length of message
  3862.          call    pmsg
  3863.  
  3864.          push    ds                      ; save parent's data segment
  3865.          mov     stk_seg,ss              ; save parent's stack pointer
  3866.          mov     stk_ptr,sp
  3867.  
  3868.                                          ; now EXEC the child process...
  3869.          mov     ax,ds                   ; set ES = DS
  3870.          mov     es,ax
  3871.          mov     dx,offset DGROUP:cname  ; DS:DX = child pathname
  3872.          mov     bx,offset DGROUP:pars   ; EX:BX = parameter block
  3873.          mov     ax,4b00h                ; function 4BH subfunction 00H
  3874.          int     21h                     ; transfer to MS-DOS
  3875.  
  3876.          cli                             ; (for bug in some early 8088s)
  3877.          mov     ss,stk_seg              ; restore parent's stack pointer
  3878.          mov     sp,stk_ptr
  3879.          sti                             ; (for bug in some early 8088s)
  3880.          pop     ds                      ; restore DS = our data segment
  3881.  
  3882.          jc      main2                   ; jump if EXEC failed
  3883.  
  3884.                                          ; otherwise EXEC succeeded,
  3885.                                          ; convert and display child's
  3886.                                          ; termination and return codes...
  3887.          mov     ah,4dh                  ; fxn 4DH = get return code
  3888.          int     21h                     ; transfer to MS-DOS
  3889.          xchg    al,ah                   ; convert termination code
  3890.          mov     bx,offset DGROUP:msg4a
  3891.          call    b2hex
  3892.          mov     al,ah                   ; get back return code
  3893.          mov     bx,offset DGROUP:msg4b  ; and convert it
  3894.          call    b2hex
  3895.          mov     dx,offset DGROUP:msg4   ; DS:DX = address of message
  3896.          mov     cx,msg4_len             ; CX = length of message
  3897.          call    pmsg                    ; display it
  3898.  
  3899.          mov     ax,4c00h                ; no error, terminate program
  3900.          int     21h                     ; with return code = 0
  3901.  
  3902.  main1:  mov     bx,offset DGROUP:msg2a  ; convert error code
  3903.          call    b2hex
  3904.          mov     dx,offset DGROUP:msg2   ; display message 'Memory
  3905.          mov     cx,msg2_len             ; resize failed...'
  3906.          call    pmsg
  3907.          jmp     main3
  3908.  
  3909.  main2:  mov     bx,offset DGROUP:msg3a  ; convert error code
  3910.          call    b2hex
  3911.          mov     dx,offset DGROUP:msg3   ; display message 'EXEC
  3912.          mov     cx,msg3_len             ; call failed...'
  3913.          call    pmsg
  3914.  
  3915.  main3:  mov     ax,4c01h                ; error, terminate program
  3916.          int     21h                     ; with return code = 1
  3917.  
  3918.  main    endp                            ; end of main procedure
  3919.  
  3920.  
  3921.  b2hex   proc    near                    ; convert byte to hex ASCII
  3922.                                          ; call with AL = binary value
  3923.                                          ;           BX = addr to store string
  3924.          push    ax
  3925.          shr     al,1
  3926.          shr     al,1
  3927.          shr     al,1
  3928.          shr     al,1
  3929.          call    ascii                   ; become first ASCII character
  3930.          mov     [bx],al                 ; store it
  3931.          pop     ax
  3932.          and     al,0fh                  ; isolate lower 4 bits, which
  3933.          call    ascii                   ; become the second ASCII character
  3934.          mov     [bx+1],al               ; store it
  3935.          ret
  3936.  b2hex   endp
  3937.  
  3938.  
  3939.  ascii   proc    near                    ; convert value 00-0FH in AL
  3940.          add     al,'0'                  ; into a "hex ASCII" character
  3941.          cmp     al,'9'
  3942.          jle     ascii2                  ; jump if in range 00-09H,
  3943.          add     al,'A'-'9'-1            ; offset it to range 0A-0FH,
  3944.  
  3945.  ascii2: ret                             ; return ASCII char. in AL
  3946.  ascii   endp
  3947.  
  3948.  
  3949.  pmsg    proc    near                    ; displays message on standard output
  3950.                                          ; call with DS:DX = address,
  3951.                                          ;              CX = length
  3952.  
  3953.          mov     bx,stdout               ; BX = standard output handle
  3954.          mov     ah,40h                  ; function 40h = write file/device
  3955.          int     21h                     ; transfer to MS-DOS
  3956.          ret                             ; back to caller
  3957.  
  3958.  pmsg    endp
  3959.  
  3960.  _TEXT   ends
  3961.  
  3962.  
  3963.  _DATA   segment para public 'DATA'      ; static & variable data segment
  3964.  
  3965.  cname   db      'CHILD.EXE',0           ; pathname of child process
  3966.  
  3967.  pars    dw      _ENVIR                  ; segment of environment block
  3968.          dd      tail                    ; long address, command tail
  3969.          dd      fcb1                    ; long address, default FCB #1
  3970.          dd      fcb2                    ; long address, default FCB #2
  3971.  
  3972.  tail    db      fcb1-tail-2             ; command tail for child
  3973.          db      'dummy command tail',cr
  3974.  
  3975.  fcb1    db      0                       ; copied into default FCB #1 in
  3976.          db      11 dup (' ')            ; child's program segment prefix
  3977.          db      25 dup (0)
  3978.  
  3979.  fcb2    db      0                       ; copied into default FCB #2 in
  3980.          db      11 dup (' ')            ; child's program segment prefix
  3981.          db      25 dup (0)
  3982.  
  3983.  msg1    db      cr,lf,'Parent executing!',cr,lf
  3984.  msg1_len equ    $-msg1
  3985.  
  3986.  msg2    db      cr,lf,'Memory resize failed, error code='
  3987.  msg2a   db      'xxh.',cr,lf
  3988.  msg2_len equ    $-msg2
  3989.  
  3990.  msg3    db      cr,lf,'EXEC call failed, error code='
  3991.  msg3a   db      'xxh.',cr,lf
  3992.  msg3_len equ    $-msg3
  3993.  
  3994.  msg4    db      cr,lf,'Parent regained control!'
  3995.          db      cr,lf,'Child termination type='
  3996.  msg4a   db      'xxh, return code='
  3997.  msg4b   db      'xxh.',cr,lf
  3998.  msg4_len equ    $-msg4
  3999.  
  4000.  _DATA   ends
  4001.  
  4002.  
  4003.  _ENVIR  segment para public 'DATA'      ; example environment block
  4004.                                          ; to be passed to child
  4005.  
  4006.          db      'PATH=',0               ; basic PATH, PROMPT,
  4007.          db      'PROMPT=$p$_$n$g',0     ; and COMSPEC strings
  4008.          db      'COMSPEC=C:\COMMAND.COM',0
  4009.          db      0                       ; extra null terminates block
  4010.  
  4011.  _ENVIR  ends
  4012.  
  4013.  
  4014.  _STACK  segment para stack 'STACK'
  4015.  
  4016.          db      stksize dup (?)
  4017.  
  4018.  _STACK  ends
  4019.  
  4020.  
  4021.          end     main                    ; defines program entry point
  4022.  
  4023.  \SAMPCODE\DOS_ENCY\10\ROOT.ASM
  4024.  
  4025.           name      root
  4026.           title     'ROOT --- demonstrate EXEC overlay'
  4027.  ;
  4028.  ; ROOT.EXE --- demonstration of EXEC for overlays
  4029.  ;
  4030.  ; Uses MS-DOS EXEC (Int 21H Function 4BH Subfunction 03H)
  4031.  ; to load an overlay named OVERLAY.EXE, calls a routine
  4032.  ; within the OVERLAY, then recovers control and terminates.
  4033.  ;
  4034.  ; Ray Duncan, June 1987
  4035.  ;
  4036.  
  4037.  stdin   equ     0                       ; standard input
  4038.  stdout  equ     1                       ; standard output
  4039.  stderr  equ     2                       ; standard error
  4040.  
  4041.  stksize equ     128                     ; size of stack
  4042.  
  4043.  cr      equ     0dh                     ; ASCII carriage return
  4044.  lf      equ     0ah                     ; ASCII linefeed
  4045.  
  4046.  
  4047.  DGROUP  group   _DATA,_STACK
  4048.  
  4049.  
  4050.  _TEXT   segment byte public 'CODE'      ; executable code segment
  4051.  
  4052.          assume  cs:_TEXT,ds:_DATA,ss:_STACK
  4053.  
  4054.  
  4055.  stk_seg dw      ?                       ; original SS contents
  4056.  stk_ptr dw      ?                       ; original SP contents
  4057.  
  4058.  
  4059.  main    proc    far                     ; entry point from MS-DOS
  4060.  
  4061.          mov     ax,_DATA                ; set DS = our data segment
  4062.          mov     ds,ax
  4063.  
  4064.                                          ; now give back extra memory
  4065.          mov     ax,es                   ; AX = segment of PSP base
  4066.          mov     bx,ss                   ; BX = segment of stack base
  4067.          sub     bx,ax                   ; reserve seg stack - seg psp
  4068.          add     bx,stksize/16           ; plus paragraphs of stack
  4069.          mov     ah,4ah                  ; fxn 4AH = modify memory block
  4070.          int     21h                     ; transfer to MS-DOS
  4071.          jc      main1                   ; jump if resize failed
  4072.  
  4073.                                          ; display message 'Root
  4074.                                          ; 'segment executing...'
  4075.          mov     dx,offset DGROUP:msg1   ; DS:DX = address of message
  4076.          mov     cx,msg1_len             ; CX = length of message
  4077.          call    pmsg
  4078.  
  4079.                                          ; allocate memory for overlay
  4080.          mov     bx,1000h                ; get 64 KB (4096 paragraphs)
  4081.          mov     ah,48h                  ; fxn 48h, allocate mem block
  4082.          int     21h                     ; transfer to MS-DOS
  4083.          jc      main2                   ; jump if allocation failed
  4084.  
  4085.          mov     pars,ax                 ; set load address for overlay
  4086.          mov     pars+2,ax               ; set relocation segment for overlay
  4087.          mov     word ptr entry+2,ax     ; set segment of entry point
  4088.  
  4089.          push    ds                      ; save root's data segment
  4090.          mov     stk_seg,ss              ; save root's stack pointer
  4091.          mov     stk_ptr,sp
  4092.  
  4093.                                          ; now use EXEC to load overlay
  4094.          mov     ax,ds                   ; set ES = DS
  4095.          mov     es,ax
  4096.          mov     dx,offset DGROUP:oname  ; DS:DX = overlay pathname
  4097.          mov     bx,offset DGROUP:pars   ; EX:BX = parameter block
  4098.          mov     ax,4b03h                ; function 4BH, subfunction 03H
  4099.          int     21h                     ; transfer to MS-DOS
  4100.  
  4101.          cli                             ; (for bug in some early 8088s)
  4102.          mov     ss,stk_seg              ; restore root's stack pointer
  4103.          mov     sp,stk_ptr
  4104.          sti                             ; (for bug in some early 8088s)
  4105.          pop     ds                      ; restore DS = our data segment
  4106.  
  4107.          jc      main3                   ; jump if EXEC failed
  4108.  
  4109.                                          ; otherwise EXEC succeeded...
  4110.          push    ds                      ; save our data segment
  4111.          call    dword ptr entry         ; now call the overlay
  4112.          pop     ds                      ; restore our data segment
  4113.  
  4114.                                          ; display message that root
  4115.                                          ; segment regained control...
  4116.          mov     dx,offset DGROUP:msg5   ; DS:DX = address of message
  4117.          mov     cx,msg5_len             ; CX = length of message
  4118.          call    pmsg                    ; display it
  4119.  
  4120.          mov     ax,4c00h                ; no error, terminate program
  4121.          int     21h                     ; with return code = 0
  4122.  
  4123.  main1:  mov     bx,offset DGROUP:msg2a  ; convert error code
  4124.          call    b2hex
  4125.          mov     dx,offset DGROUP:msg2   ; display message 'Memory
  4126.          mov     cx,msg2_len             ; resize failed...'
  4127.          call    pmsg
  4128.          jmp     main4
  4129.  
  4130.  main2:  mov     bx,offset DGROUP:msg3a  ; convert error code
  4131.          call    b2hex
  4132.          mov     dx,offset DGROUP:msg3   ; display message 'Memory
  4133.          mov     cx,msg3_len             ; allocation failed...'
  4134.          call    pmsg
  4135.          jmp     main4
  4136.  
  4137.  main3:  mov     bx,offset DGROUP:msg4a  ; convert error code
  4138.          call    b2hex
  4139.          mov     dx,offset DGROUP:msg4   ; display message 'EXEC
  4140.          mov     cx,msg4_len             ; call failed...'
  4141.          call    pmsg
  4142.  
  4143.  main4:  mov     ax,4c01h                ; error, terminate program
  4144.          int     21h                     ; with return code = 1
  4145.  
  4146.  main    endp                            ; end of main procedure
  4147.  
  4148.  
  4149.  b2hex   proc    near                    ; convert byte to hex ASCII
  4150.                                          ; call with AL = binary value
  4151.                                          ; BX = addr to store string
  4152.          push    ax
  4153.          shr     al,1
  4154.          shr     al,1
  4155.          shr     al,1
  4156.          shr     al,1
  4157.          call    ascii                   ; become first ASCII character
  4158.          mov     [bx],al                 ; store it
  4159.          pop     ax
  4160.          and     al,0fh                  ; isolate lower 4 bits, which
  4161.          call    ascii                   ; become the second ASCII character
  4162.          mov     [bx+1],al               ; store it
  4163.          ret
  4164.  b2hex   endp
  4165.  
  4166.  
  4167.  ascii   proc    near                    ; convert value 00-0FH in AL
  4168.          add     al,'0'                  ; into a "hex ASCII" character
  4169.          cmp     al,'9'
  4170.          jle     ascii2                  ; jump if in range 00-09H,
  4171.          add     al,'A'-'9'-1            ; offset it to range 0A-0FH,
  4172.  ascii2: ret                             ; return ASCII char. in AL.
  4173.  ascii   endp
  4174.  
  4175.  
  4176.  pmsg    proc    near                    ; displays message on standard output
  4177.                                          ; call with DS:DX = address,
  4178.                                          ;              CX = length
  4179.  
  4180.          mov     bx,stdout               ; BX = standard output handle
  4181.          mov     ah,40h                  ; function 40H = write file/device
  4182.          int     21h                     ; transfer to MS-DOS
  4183.          ret                             ; back to caller
  4184.  
  4185.  pmsg    endp
  4186.  
  4187.  _TEXT   ends
  4188.  
  4189.  
  4190.  _DATA   segment para public 'DATA'      ; static & variable data segment
  4191.  
  4192.  oname   db      'OVERLAY.OVL',0         ; pathname of overlay file
  4193.  
  4194.  pars    dw      0                       ; load address (segment) for file
  4195.          dw      0                       ; relocation (segment) for file
  4196.  
  4197.  entry   dd      0                       ; entry point for overlay
  4198.  
  4199.  msg1    db      cr,lf,'Root segment executing!',cr,lf
  4200.  msg1_len equ    $-msg1
  4201.  
  4202.  msg2    db      cr,lf,'Memory resize failed, error code='
  4203.  msg2a   db      'xxh.',cr,lf
  4204.  msg2_len equ    $-msg2
  4205.  
  4206.  msg3    db      cr,lf,'Memory allocation failed, error code='
  4207.  msg3a   db      'xxh.',cr,lf
  4208.  msg3_len equ    $-msg3
  4209.  
  4210.  msg4    db      cr,lf,'EXEC call failed, error code='
  4211.  msg4a   db      'xxh.',cr,lf
  4212.  msg4_len equ    $-msg4
  4213.  
  4214.  msg5    db      cr,lf,'Root segment regained control!',cr,lf
  4215.  msg5_len equ    $-msg5
  4216.  
  4217.  _DATA   ends
  4218.  
  4219.  
  4220.  _STACK  segment para stack 'STACK'
  4221.  
  4222.          db      stksize dup (?)
  4223.  
  4224.  _STACK  ends
  4225.  
  4226.  
  4227.          end     main                    ; defines program entry point
  4228.  
  4229.  \SAMPCODE\DOS_ENCY\11
  4230.  \SAMPCODE\DOS_ENCY\11\HELLO.ASM
  4231.  
  4232.  ;
  4233.  ; Name:          hello
  4234.  ;
  4235.  ; Description:   This RAM-resident (terminate-and-stay-resident) utility
  4236.  ;                displays the message "Hello, World" in response to a
  4237.  ;                software interrupt.
  4238.  ;
  4239.  ; Comments:      Assemble and link to create HELLO.EXE.
  4240.  ;
  4241.  ;                Execute HELLO.EXE to make resident.
  4242.  ;
  4243.  ;                Execute  INT 64h  to display the message.
  4244.  ;
  4245.  
  4246.  
  4247.  TSRInt           EQU     64h
  4248.  STDOUT           EQU     1
  4249.  
  4250.  RESIDENT_TEXT    SEGMENT byte public 'CODE'
  4251.                   ASSUME  cs:RESIDENT_TEXT,ds:RESIDENT_DATA
  4252.  
  4253.  TSRAction        PROC    far
  4254.  
  4255.                   sti                    ; enable interrupts
  4256.  
  4257.                   push    ds             ; preserve registers
  4258.                   push    ax
  4259.                   push    bx
  4260.                   push    cx
  4261.                   push    dx
  4262.  
  4263.                   mov     dx,seg RESIDENT_DATA
  4264.                   mov     ds,dx
  4265.                   mov     dx,offset Message      ; DS:DX -> message
  4266.                   mov     cx,16                  ; CX = length
  4267.                   mov     bx,STDOUT              ; BX = file handle
  4268.                   mov     ah,40h                 ; AH = INT 21h function 40h
  4269.                                                  ; (Write File)
  4270.                   int     21h                    ; display the message
  4271.  
  4272.                   pop     dx                     ; restore registers and exit
  4273.                   pop     cx
  4274.                   pop     bx
  4275.                   pop     ax
  4276.                   pop     ds
  4277.                   iret
  4278.  
  4279.  TSRAction        ENDP
  4280.  
  4281.  RESIDENT_TEXT    ENDS
  4282.  
  4283.  
  4284.  RESIDENT_DATA    SEGMENT word public 'DATA'
  4285.  
  4286.  Message          DB      0Dh,0Ah,'Hello, World',0Dh,0Ah
  4287.  
  4288.  RESIDENT_DATA    ENDS
  4289.  
  4290.  
  4291.  TRANSIENT_TEXT   SEGMENT para public 'TCODE'
  4292.                   ASSUME  cs:TRANSIENT_TEXT,ss:TRANSIENT_STACK
  4293.  
  4294.  HelloTSR PROC    far                    ; At entry:     CS:IP -> SnapTSR
  4295.                                          ;               SS:SP -> stack
  4296.                                          ;               DS,ES -> PSP
  4297.  ; Install this TSR's interrupt handler
  4298.  
  4299.                   mov     ax,seg RESIDENT_TEXT
  4300.                   mov     ds,ax
  4301.                   mov     dx,offset RESIDENT_TEXT:TSRAction
  4302.                   mov     al,TSRInt
  4303.                   mov     ah,25h
  4304.                   int     21h
  4305.  
  4306.  ; Terminate and stay resident
  4307.  
  4308.                   mov     dx,cs          ; DX = paragraph address of start of
  4309.                                          ; transient portion (end of resident
  4310.                                          ; portion)
  4311.                   mov     ax,es          ; ES = PSP segment
  4312.                   sub     dx,ax          ; DX = size of resident portion
  4313.  
  4314.                   mov     ax,3100h       ; AH = INT 21h function number (TSR)
  4315.                                          ; AL = 00H (return code)
  4316.                   int     21h
  4317.  
  4318.  HelloTSR         ENDP
  4319.  
  4320.  TRANSIENT_TEXT   ENDS
  4321.  
  4322.  
  4323.  TRANSIENT_STACK  SEGMENT word stack 'TSTACK'
  4324.  
  4325.                   DB      80h dup(?)
  4326.  
  4327.  TRANSIENT_STACK  ENDS
  4328.  
  4329.  
  4330.                   END     HelloTSR
  4331.  
  4332.  \SAMPCODE\DOS_ENCY\11\INDOS_1.ASM
  4333.  
  4334.          test    ss:[CriticalErrorFlag],0FFH        ;(versions 3.1 and later)
  4335.          jne     NearLabel
  4336.          push    ss:[NearWord]
  4337.          int     28H
  4338.  
  4339.  \SAMPCODE\DOS_ENCY\11\INDOS_2.ASM
  4340.  
  4341.          cmp     ss:[CriticalErrorFlag],00          ;(versions earlier than 3.
  4342.          jne     NearLabel
  4343.          int     28H
  4344.  
  4345.  \SAMPCODE\DOS_ENCY\11\SNAP.ASM
  4346.  
  4347.  ;
  4348.  ; Name:         snap
  4349.  ;
  4350.  ; Description:  This RAM-resident (terminate-and-stay-resident) utility
  4351.  ;               produces a video "snapshot" by copying the contents of the
  4352.  ;               video regeneration buffer to a disk file.  It may be used
  4353.  ;               in 80-column alphanumeric video modes on IBM PCs and PS/2s.
  4354.  ;
  4355.  ; Comments:     Assemble and link to create SNAP.EXE.
  4356.  ;
  4357.  ;               Execute SNAP.EXE to make resident.
  4358.  ;
  4359.  ;               Press Alt-Enter to dump current contents of video buffer
  4360.  ;               to a disk file.
  4361.  ;
  4362.  
  4363.  MultiplexID     EQU     0CAh            ; unique INT 2FH ID value
  4364.  
  4365.  TSRStackSize    EQU     100h            ; resident stack size in bytes
  4366.  
  4367.  KB_FLAG         EQU     17h             ; offset of shift-key status flag in
  4368.                                          ; ROM BIOS keyboard data area
  4369.  
  4370.  KBIns           EQU     80h             ; bit masks for KB_FLAG
  4371.  KBCaps          EQU     40h
  4372.  KBNum           EQU     20h
  4373.  KBScroll        EQU     10h
  4374.  KBAlt           EQU     8
  4375.  KBCtl           EQU     4
  4376.  KBLeft          EQU     2
  4377.  KBRight         EQU     1
  4378.  
  4379.  SCEnter         EQU     1Ch
  4380.  
  4381.  CR              EQU     0Dh
  4382.  LF              EQU     0Ah
  4383.  TRUE            EQU     -1
  4384.  FALSE           EQU     0
  4385.  
  4386.                  PAGE
  4387.  ;----------------------------------------------------------------------------
  4388.  ;
  4389.  ; RAM-resident routines
  4390.  ;
  4391.  ;----------------------------------------------------------------------------
  4392.  
  4393.  RESIDENT_GROUP  GROUP   RESIDENT_TEXT,RESIDENT_DATA,RESIDENT_STACK
  4394.  
  4395.  RESIDENT_TEXT   SEGMENT byte public 'CODE'
  4396.                  ASSUME  cs:RESIDENT_GROUP,ds:RESIDENT_GROUP
  4397.  
  4398.  ;----------------------------------------------------------------------------
  4399.  ; System verification routines
  4400.  ;----------------------------------------------------------------------------
  4401.  
  4402.  VerifyDOSState  PROC    near            ; Returns:    carry flag set if MS-DO
  4403.                                          ;             is busy
  4404.  
  4405.                  push    ds              ; preserve these registers
  4406.                  push    bx
  4407.                  push    ax
  4408.  
  4409.                  lds     bx,cs:ErrorModeAddr
  4410.                  mov     ah,[bx]         ; AH = ErrorMode flag
  4411.  
  4412.                  lds     bx,cs:InDOSAddr
  4413.                  mov     al,[bx]         ; AL = InDOS flag
  4414.  
  4415.                  xor     bx,bx           ; BH = 00H, BL = 00H
  4416.                  cmp     bl,cs:InISR28   ; carry flag set if INT 28H handler
  4417.                                          ; is running
  4418.                  rcl     bl,01h          ; BL = 01H if INT 28H handler is runn
  4419.  
  4420.                  cmp     bx,ax           ; carry flag zero if AH = 00H
  4421.                                          ; and AL <= BL
  4422.  
  4423.                  pop     ax              ; restore registers
  4424.                  pop     bx
  4425.                  pop     ds
  4426.                  ret
  4427.  
  4428.  VerifyDOSState  ENDP
  4429.  
  4430.  
  4431.  VerifyIntState  PROC    near            ; Returns:    carry flag set if hardw
  4432.                                          ;             or ROM BIOS unstable
  4433.  
  4434.                  push    ax              ; preserve AX
  4435.  
  4436.  ; Verify hardware interrupt status by interrogating Intel 8259A Programmable
  4437.  ;  Interrupt Controller
  4438.  
  4439.                  mov     ax,00001011b    ; AH = 0
  4440.                                          ; AL = 0CW3 for Intel 8259A (RR = 1,
  4441.                                          ; RIS = 1)
  4442.                  out     20h,al          ; request 8259A's in-service register
  4443.                  jmp     short L10       ; wait a few cycles
  4444.  L10:            in      al,20h          ; AL = hardware interrupts currently
  4445.                                          ; being serviced (bit = 1 if in-servi
  4446.                  cmp     ah,al
  4447.                  jc      L11             ; exit if any hardware interrupts sti
  4448.                                          ; being serviced
  4449.  
  4450.  ; Verify status of ROM BIOS interrupt handlers
  4451.  
  4452.                  xor     al,al           ; AL = 00H
  4453.  
  4454.                  cmp     al,cs:InISR5
  4455.                  jc      L11             ; exit if currently in INT 05H handle
  4456.  
  4457.                  cmp     al,cs:InISR9
  4458.                  jc      L11             ; exit if currently in INT 09H handle
  4459.  
  4460.                  cmp     al,cs:InISR10
  4461.                  jc      L11             ; exit if currently in INT 10H handle
  4462.  
  4463.                  cmp     al,cs:InISR13   ; set carry flag if currently in
  4464.                                          ; INT 13H handler
  4465.  
  4466.  L11:            pop     ax              ; restore AX and return
  4467.                  ret
  4468.  
  4469.  VerifyIntState  ENDP
  4470.  
  4471.  
  4472.  VerifyTSRState  PROC    near            ; Returns: carry flag set if TSR
  4473.                                          ;          inactive
  4474.  
  4475.                  rol     cs:HotFlag,1    ; carry flag set if (HotFlag = TRUE)
  4476.                  cmc                     ; carry flag set if (HotFlag = FALSE)
  4477.                  jc      L20             ; exit if no hot key
  4478.  
  4479.                  ror     cs:ActiveTSR,1  ; carry flag set if (ActiveTSR = TRUE
  4480.                  jc      L20             ; exit if already active
  4481.  
  4482.                  call    VerifyDOSState
  4483.                  jc      L20             ; exit if MS-DOS unstable
  4484.  
  4485.                  call    VerifyIntState  ; set carry flag if hardware or BIOS
  4486.                                          ; unstable
  4487.  
  4488.  L20:            ret
  4489.  
  4490.  VerifyTSRState  ENDP
  4491.  
  4492.                  PAGE
  4493.  ;----------------------------------------------------------------------------
  4494.  ; System monitor routines
  4495.  ;----------------------------------------------------------------------------
  4496.  
  4497.  ISR5            PROC    far             ; INT 05H handler
  4498.                                          ; (ROM BIOS print screen)
  4499.  
  4500.                  inc     cs:InISR5       ; increment status flag
  4501.  
  4502.                  pushf
  4503.                  cli
  4504.                  call    cs:PrevISR5     ; chain to previous INT 05H handler
  4505.  
  4506.                  dec     cs:InISR5       ; decrement status flag
  4507.                  iret
  4508.  
  4509.  ISR5            ENDP
  4510.  
  4511.  
  4512.  ISR8            PROC    far             ; INT 08H handler (timer tick, IRQ0)
  4513.  
  4514.                  pushf
  4515.                  cli
  4516.                  call    cs:PrevISR8     ; chain to previous handler
  4517.  
  4518.                  cmp     cs:InISR8,0
  4519.                  jne     L31             ; exit if already in this handler
  4520.  
  4521.                  inc     cs:InISR8       ; increment status flag
  4522.  
  4523.                  sti                     ; interrupts are ok
  4524.                  call    VerifyTSRState
  4525.                  jc      L30             ; jump if TSR is inactive
  4526.  
  4527.                  mov     byte ptr cs:ActiveTSR,TRUE
  4528.                  call    TSRapp
  4529.                  mov     byte ptr cs:ActiveTSR,FALSE
  4530.  
  4531.  L30:            dec     cs:InISR8
  4532.  
  4533.  L31:            iret
  4534.  
  4535.  ISR8            ENDP
  4536.  
  4537.  
  4538.  ISR9            PROC    far             ; INT 09H handler
  4539.                                          ; (keyboard interrupt IRQ1)
  4540.  
  4541.                  push    ds              ; preserve these registers
  4542.                  push    ax
  4543.                  push    bx
  4544.  
  4545.                  push    cs
  4546.                  pop     ds              ; DS -> RESIDENT_GROUP
  4547.  
  4548.                  in      al,60h          ; AL = current scan code
  4549.  
  4550.                  pushf                   ; simulate an INT
  4551.                  cli
  4552.                  call    ds:PrevISR9     ; let previous handler execute
  4553.  
  4554.                  mov     ah,ds:InISR9    ; if already in this handler ..
  4555.                  or      ah,ds:HotFlag   ; .. or currently processing hot key
  4556.                  jnz     L43             ; .. jump to exit
  4557.  
  4558.                  inc     ds:InISR9       ; increment status flag
  4559.                  sti                     ; now interrupts are ok
  4560.  
  4561.  ; Check scan code sequence
  4562.  
  4563.                  cmp     ds:HotSeqLen,0
  4564.                  je      L40             ; jump if no hot sequence to match
  4565.  
  4566.                  mov     bx,ds:HotIndex
  4567.                  cmp     al,[bx+HotSequence]     ; test scan code sequence
  4568.                  jne     L41             ; jump if no match
  4569.  
  4570.                  inc     bx
  4571.                  cmp     bx,ds:HotSeqLen
  4572.                  jb      L42             ; jump if not last scan code to match
  4573.  
  4574.  ; Check shift-key state
  4575.  
  4576.  L40:            push    ds
  4577.                  mov     ax,40h
  4578.                  mov     ds,ax           ; DS -> ROM BIOS data area
  4579.                  mov     al,ds:[KB_FLAG] ; AH = ROM BIOS shift-key flags
  4580.                  pop     ds
  4581.  
  4582.                  and     al,ds:HotKBMask ; AL = flags AND "don't care" mask
  4583.                  cmp     al,ds:HotKBFlag
  4584.                  jne     L42             ; jump if shift state does not match
  4585.  
  4586.  ; Set flag when hot key is found
  4587.  
  4588.                  mov     byte ptr ds:HotFlag,TRUE
  4589.  
  4590.  L41:            xor     bx,bx           ; reinitialize index
  4591.  
  4592.  L42:            mov     ds:HotIndex,bx  ; update index into sequence
  4593.                  dec     ds:InISR9       ; decrement status flag
  4594.  
  4595.  L43:            pop     bx              ; restore registers and exit
  4596.                  pop     ax
  4597.                  pop     ds
  4598.                  iret
  4599.  
  4600.  ISR9            ENDP
  4601.  
  4602.  
  4603.  ISR10           PROC    far             ; INT 10H handler (ROM BIOS video I/O
  4604.  
  4605.                  inc     cs:InISR10      ; increment status flag
  4606.  
  4607.                  pushf
  4608.                  cli
  4609.                  call    cs:PrevISR10    ; chain to previous INT 10H handler
  4610.  
  4611.                  dec     cs:InISR10      ; decrement status flag
  4612.                  iret
  4613.  
  4614.  ISR10           ENDP
  4615.  
  4616.  
  4617.  ISR13           PROC    far             ; INT 13H handler
  4618.                                          ; (ROM BIOS fixed disk I/O)
  4619.  
  4620.                  inc     cs:InISR13      ; increment status flag
  4621.  
  4622.                  pushf
  4623.                  cli
  4624.                  call    cs:PrevISR13    ; chain to previous INT 13H handler
  4625.  
  4626.                  pushf                   ; preserve returned flags
  4627.                  dec     cs:InISR13      ; decrement status flag
  4628.                  popf                    ; restore flags register
  4629.  
  4630.                  sti                     ; enable interrupts
  4631.                  ret     2               ; simulate IRET without popping flags
  4632.  
  4633.  ISR13           ENDP
  4634.  
  4635.  
  4636.  ISR1B           PROC    far             ; INT 1BH trap (ROM BIOS Ctrl-Break)
  4637.  
  4638.                  mov     byte ptr cs:Trap1B,TRUE
  4639.                  iret
  4640.  
  4641.  ISR1B           ENDP
  4642.  
  4643.  
  4644.  ISR23           PROC    far             ; INT 23H trap (MS-DOS Ctrl-C)
  4645.  
  4646.                  mov     byte ptr cs:Trap23,TRUE
  4647.                  iret
  4648.  
  4649.  ISR23           ENDP
  4650.  
  4651.  
  4652.  ISR24           PROC    far             ; INT 24H trap (MS-DOS critical error
  4653.  
  4654.                  mov     byte ptr cs:Trap24,TRUE
  4655.  
  4656.                  xor     al,al           ; AL = 00H (MS-DOS 2.x):
  4657.                                          ; ignore the error
  4658.                  cmp     cs:MajorVersion,2
  4659.                  je      L50
  4660.  
  4661.                  mov     al,3            ; AL = 03H (MS-DOS 3.x):
  4662.                                          ; fail the MS-DOS call in which
  4663.                                          ; the critical error occurred
  4664.  L50:            iret
  4665.  
  4666.  ISR24           ENDP
  4667.  
  4668.  
  4669.  ISR28           PROC    far             ; INT 28H handler
  4670.                                          ; (MS-DOS idle interrupt)
  4671.  
  4672.                  pushf
  4673.                  cli
  4674.                  call    cs:PrevISR28    ; chain to previous INT 28H handler
  4675.  
  4676.                  cmp     cs:InISR28,0
  4677.                  jne     L61             ; exit if already inside this handler
  4678.  
  4679.                  inc     cs:InISR28      ; increment status flag
  4680.  
  4681.                  call    VerifyTSRState
  4682.                  jc      L60             ; jump if TSR is inactive
  4683.  
  4684.                  mov     byte ptr cs:ActiveTSR,TRUE
  4685.                  call    TSRapp
  4686.                  mov     byte ptr cs:ActiveTSR,FALSE
  4687.  
  4688.  L60:            dec     cs:InISR28      ; decrement status flag
  4689.  
  4690.  L61:            iret
  4691.  
  4692.  ISR28           ENDP
  4693.  
  4694.  
  4695.  ISR2F           PROC    far             ; INT 2FH handler
  4696.                                          ; (MS-DOS multiplex interrupt)
  4697.                                          ; Caller:  AH = handler ID
  4698.                                          ;          AL = function number
  4699.                                          ; Returns for function 0:  AL = 0FFH
  4700.                                          ; for all other functions:  nothing
  4701.  
  4702.                  cmp     ah,MultiplexID
  4703.                  je      L70             ; jump if this handler is requested
  4704.  
  4705.                  jmp     cs:PrevISR2F    ; chain to previous INT 2FH handler
  4706.  
  4707.  L70:            test    al,al
  4708.                  jnz     MultiplexIRET   ; jump if reserved or undefined funct
  4709.  
  4710.  ; Function 0:  get installed state
  4711.  
  4712.                  mov     al,0FFh         ; AL = 0FFh (this handler is installe
  4713.  
  4714.  MultiplexIRET:  iret                    ; return from interrupt
  4715.  
  4716.  ISR2F           ENDP
  4717.  
  4718.                  PAGE
  4719.  ;
  4720.  ;
  4721.  ; AuxInt21--sets ErrorMode while executing INT 21h to force use of the
  4722.  ;       AuxStack instead of the IOStack.
  4723.  ;
  4724.  ;
  4725.  
  4726.  AuxInt21        PROC    near            ; Caller:     registers for INT 21H
  4727.                                          ; Returns:    registers from INT 21H
  4728.  
  4729.                  push    ds
  4730.                  push    bx
  4731.                  lds     bx,ErrorModeAddr
  4732.                  inc     byte ptr [bx]   ; ErrorMode is now nonzero
  4733.                  pop     bx
  4734.                  pop     ds
  4735.  
  4736.                  int     21h             ; perform MS-DOS function
  4737.  
  4738.                  push    ds
  4739.                  push    bx
  4740.                  lds     bx,ErrorModeAddr
  4741.                  dec     byte ptr [bx]   ; restore ErrorMode
  4742.                  pop     bx
  4743.                  pop     ds
  4744.                  ret
  4745.  
  4746.  AuxInt21        ENDP
  4747.  
  4748.  
  4749.  Int21v          PROC    near            ; perform INT 21H or AuxInt21,
  4750.                                          ; depending on MS-DOS version
  4751.  
  4752.                  cmp     DOSVersion,30Ah
  4753.                  jb      L80             ; jump if earlier than 3.1
  4754.  
  4755.                  int     21h             ; version 3.1 and later
  4756.                  ret
  4757.  
  4758.  L80:            call    AuxInt21        ; versions earlier than 3.1
  4759.                  ret
  4760.  
  4761.  Int21v          ENDP
  4762.  
  4763.                  PAGE
  4764.  ;----------------------------------------------------------------------------
  4765.  ; RAM-resident application
  4766.  ;----------------------------------------------------------------------------
  4767.  
  4768.  TSRapp          PROC    near
  4769.  
  4770.  ; Set up a safe stack
  4771.  
  4772.                  push    ds              ; save previous DS on previous stack
  4773.  
  4774.                  push    cs
  4775.                  pop     ds              ; DS -> RESIDENT_GROUP
  4776.  
  4777.                  mov     PrevSP,sp       ; save previous SS:SP
  4778.                  mov     PrevSS,ss
  4779.  
  4780.                  mov     ss,TSRSS        ; SS:SP -> RESIDENT_STACK
  4781.                  mov     sp,TSRSP
  4782.  
  4783.                  push    es              ; preserve remaining registers
  4784.                  push    ax
  4785.                  push    bx
  4786.                  push    cx
  4787.                  push    dx
  4788.                  push    si
  4789.                  push    di
  4790.                  push    bp
  4791.  
  4792.                  cld                     ; clear direction flag
  4793.  
  4794.  ; Set break and critical error traps
  4795.  
  4796.                  mov     cx,NTrap
  4797.                  mov     si,offset RESIDENT_GROUP:StartTrapList
  4798.  
  4799.  L90:            lodsb                   ; AL = interrupt number
  4800.                                          ; DS:SI -> byte past interrupt number
  4801.  
  4802.                  mov     byte ptr [si],FALSE     ; zero the trap flag
  4803.  
  4804.                  push    ax              ; preserve AX
  4805.                  mov     ah,35h          ; INT 21H function 35H
  4806.                                          ; (get interrupt vector)
  4807.                  int     21h             ; ES:BX = previous interrupt vector
  4808.                  mov     [si+1],bx       ; save offset and segment ..
  4809.                  mov     [si+3],es       ;  .. of previous handler
  4810.  
  4811.                  pop     ax              ; AL = interrupt number
  4812.                  mov     dx,[si+5]       ; DS:DX -> this TSR's trap
  4813.                  mov     ah,25h          ; INT 21H function 25H
  4814.                  int     21h             ; (set interrupt vector)
  4815.                  add     si,7            ; DS:SI -> next in list
  4816.  
  4817.                  loop    L90
  4818.  
  4819.  ; Disable MS-DOS break checking during disk I/O
  4820.  
  4821.                  mov     ax,3300h        ; AH = INT 21H function number
  4822.                                          ; AL = 00H (request current break sta
  4823.                  int     21h             ; DL = current break state
  4824.                  mov     PrevBreak,dl    ; preserve current state
  4825.  
  4826.                  xor     dl,dl           ; DL = 00H (disable disk I/O break
  4827.                                          ; checking)
  4828.                  mov     ax,3301h        ; AL = 01H (set break state)
  4829.                  int     21h
  4830.  
  4831.  ; Preserve previous extended error information
  4832.  
  4833.                  cmp     DOSVersion,30Ah
  4834.                  jb      L91             ; jump if MS-DOS version earlier
  4835.                                          ; than 3.1
  4836.                  push    ds              ; preserve DS
  4837.                  xor     bx,bx           ; BX = 00H (required for function 59H
  4838.                  mov     ah,59h          ; INT 21H function 59H
  4839.                  call    Int21v          ; (get extended error info)
  4840.  
  4841.                  mov     cs:PrevExtErrDS,ds
  4842.                  pop     ds
  4843.                  mov     PrevExtErrAX,ax ; preserve error information
  4844.                  mov     PrevExtErrBX,bx ; in data structure
  4845.                  mov     PrevExtErrCX,cx
  4846.                  mov     PrevExtErrDX,dx
  4847.                  mov     PrevExtErrSI,si
  4848.                  mov     PrevExtErrDI,di
  4849.                  mov     PrevExtErrES,es
  4850.  
  4851.  ; Inform MS-DOS about current PSP
  4852.  
  4853.  L91:            mov     ah,51h          ; INT 21H function 51H (get PSP addre
  4854.                  call    Int21v          ; BX = foreground PSP
  4855.  
  4856.                  mov     PrevPSP,bx      ; preserve previous PSP
  4857.  
  4858.                  mov     bx,TSRPSP       ; BX = resident PSP
  4859.                  mov     ah,50h          ; INT 21H function 50H (set PSP addre
  4860.                  call    Int21v
  4861.  
  4862.  ; Inform MS-DOS about current DTA (not really necessary in this application
  4863.  ; because DTA is not used)
  4864.  
  4865.                  mov     ah,2Fh          ; INT 21H function 2FH
  4866.                  int     21h             ; (get DTA address) into ES:BX
  4867.                  mov     PrevDTAoffs,bx
  4868.                  mov     PrevDTAseg,es
  4869.  
  4870.                  push    ds              ; preserve DS
  4871.                  mov     ds,TSRPSP
  4872.                  mov     dx,80h          ; DS:DX -> default DTA at PSP:0080
  4873.                  mov     ah,1Ah          ; INT 21H function 1AH
  4874.                  int     21h             ; (set DTA address)
  4875.                  pop     ds              ; restore DS
  4876.  
  4877.  ; Open a file, write to it, and close it
  4878.  
  4879.                  mov     ax,0E07h        ; AH = INT 10H function number
  4880.                                          ; (Write Teletype)
  4881.                                          ; AL = 07H (bell character)
  4882.                  int     10h             ; emit a beep
  4883.  
  4884.                  mov     dx,offset RESIDENT_GROUP:SnapFile
  4885.                  mov     ah,3Ch          ; INT 21H function 3CH
  4886.                                          ; (create file handle)
  4887.                  mov     cx,0            ; file attribute
  4888.                  int     21h
  4889.                  jc      L94             ; jump if file not opened
  4890.  
  4891.                  push    ax              ; push file handle
  4892.                  mov     ah,0Fh          ; INT 10H function 0FH
  4893.                                          ; (get video status)
  4894.                  int     10h             ; AL = video mode number
  4895.                                          ; AH = number of character columns
  4896.                  pop     bx              ; BX = file handle
  4897.  
  4898.                  cmp     ah,80
  4899.                  jne     L93             ; jump if not 80-column mode
  4900.  
  4901.                  mov     dx,0B800h       ; DX = color video buffer segment
  4902.                  cmp     al,3
  4903.                  jbe     L92             ; jump if color alphanumeric mode
  4904.  
  4905.                  cmp     al,7
  4906.                  jne     L93             ; jump if not monochrome mode
  4907.  
  4908.                  mov     dx,0B000h       ; DX = monochrome video buffer segmen
  4909.  
  4910.  L92:            push    ds
  4911.                  mov     ds,dx
  4912.                  xor     dx,dx           ; DS:DX -> start of video buffer
  4913.                  mov     cx,80*25*2      ; CX = number of bytes to write
  4914.                  mov     ah,40h          ; INT 21H function 40H (write file)
  4915.                  int     21h
  4916.                  pop     ds
  4917.  
  4918.  L93:            mov     ah,3Eh          ; INT 21H function 3EH (close file)
  4919.                  int     21h
  4920.  
  4921.                  mov     ax,0E07h        ; emit another beep
  4922.                  int     10h
  4923.  
  4924.  ; Restore previous DTA
  4925.  
  4926.  L94:            push    ds              ; preserve DS
  4927.                  lds     dx,PrevDTA      ; DS:DX -> previous DTA
  4928.                  mov     ah,1Ah          ; INT 21H function 1AH (set DTA addre
  4929.                  int     21h
  4930.                  pop     ds
  4931.  
  4932.  ; Restore previous PSP
  4933.  
  4934.                  mov     bx,PrevPSP      ; BX = previous PSP
  4935.                  mov     ah,50h          ; INT 21H function 50H
  4936.                  call    Int21v          ; (set PSP address)
  4937.  
  4938.  ; Restore previous extended error information
  4939.  
  4940.                  mov     ax,DOSVersion
  4941.                  cmp     ax,30AH
  4942.                  jb      L95             ; jump if MS-DOS version earlier than
  4943.                  cmp     ax,0A00h
  4944.                  jae     L95             ; jump if MS OS/2-DOS 3.x box
  4945.  
  4946.                  mov     dx,offset RESIDENT_GROUP:PrevExtErrInfo
  4947.                  mov     ax,5D0Ah
  4948.                  int     21h             ; (restore extended error information
  4949.  
  4950.  ; Restore previous MS-DOS break checking
  4951.  
  4952.  L95:            mov     dl,PrevBreak    ; DL = previous state
  4953.                  mov     ax,3301h
  4954.                  int     21h
  4955.  
  4956.  ; Restore previous break and critical error traps
  4957.  
  4958.                  mov     cx,NTrap
  4959.                  mov     si,offset RESIDENT_GROUP:StartTrapList
  4960.                  push    ds              ; preserve DS
  4961.  
  4962.  L96:            lods    byte ptr cs:[si] ; AL = interrupt number
  4963.                                          ; ES:SI -> byte past interrupt number
  4964.  
  4965.                  lds     dx,cs:[si+1]    ; DS:DX -> previous handler
  4966.                  mov     ah,25h          ; INT 21H function 25H
  4967.                  int     21h             ; (set interrupt vector)
  4968.                  add     si,7            ; DS:SI -> next in list
  4969.                  loop    L96
  4970.  
  4971.                  pop     ds              ; restore DS
  4972.  
  4973.  ; Restore all registers
  4974.  
  4975.                  pop     bp
  4976.                  pop     di
  4977.                  pop     si
  4978.                  pop     dx
  4979.                  pop     cx
  4980.                  pop     bx
  4981.                  pop     ax
  4982.                  pop     es
  4983.  
  4984.                  mov     ss,PrevSS       ; SS:SP -> previous stack
  4985.                  mov     sp,PrevSP
  4986.                  pop     ds              ; restore previous DS
  4987.  
  4988.  ; Finally, reset status flag and return
  4989.  
  4990.                  mov     byte ptr cs:HotFlag,FALSE
  4991.                  ret
  4992.  
  4993.  TSRapp          ENDP
  4994.  
  4995.  
  4996.  RESIDENT_TEXT   ENDS
  4997.  
  4998.  
  4999.  RESIDENT_DATA   SEGMENT word public 'DATA'
  5000.  
  5001.  ErrorModeAddr   DD      ?               ; address of MS-DOS ErrorMode flag
  5002.  InDOSAddr       DD      ?               ; address of MS-DOS InDOS flag
  5003.  
  5004.  NISR            DW      (EndISRList-StartISRList)/8 ; number of installed ISR
  5005.  
  5006.  StartISRList    DB      05h             ; INT number
  5007.  InISR5          DB      FALSE           ; flag
  5008.  PrevISR5        DD      ?               ; address of previous handler
  5009.                  DW      offset RESIDENT_GROUP:ISR5
  5010.  
  5011.                  DB      08h
  5012.  InISR8          DB      FALSE
  5013.  PrevISR8        DD      ?
  5014.                  DW      offset RESIDENT_GROUP:ISR8
  5015.  
  5016.                  DB      09h
  5017.  InISR9          DB      FALSE
  5018.  PrevISR9        DD      ?
  5019.                  DW      offset RESIDENT_GROUP:ISR9
  5020.  
  5021.                  DB      10h
  5022.  InISR10         DB      FALSE
  5023.  PrevISR10       DD      ?
  5024.                  DW      offset RESIDENT_GROUP:ISR10
  5025.  
  5026.                  DB      13h
  5027.  InISR13         DB      FALSE
  5028.  PrevISR13       DD      ?
  5029.                  DW      offset RESIDENT_GROUP:ISR13
  5030.  
  5031.                  DB      28h
  5032.  InISR28         DB      FALSE
  5033.  PrevISR28       DD      ?
  5034.                  DW      offset RESIDENT_GROUP:ISR28
  5035.  
  5036.                  DB      2Fh
  5037.  InISR2F         DB      FALSE
  5038.  PrevISR2F       DD      ?
  5039.                  DW      offset RESIDENT_GROUP:ISR2F
  5040.  
  5041.  EndISRList      LABEL   BYTE
  5042.  
  5043.  TSRPSP          DW      ?               ; resident PSP
  5044.  TSRSP           DW      TSRStackSize    ; resident SS:SP
  5045.  TSRSS           DW      seg RESIDENT_STACK
  5046.  PrevPSP         DW      ?               ; previous PSP
  5047.  PrevSP          DW      ?               ; previous SS:SP
  5048.  PrevSS          DW      ?
  5049.  
  5050.  HotIndex        DW      0               ; index of next scan code in sequence
  5051.  HotSeqLen       DW      EndHotSeq-HotSequence   ; length of hot-key sequence
  5052.  
  5053.  HotSequence     DB      SCEnter         ; hot sequence of scan codes
  5054.  EndHotSeq       LABEL   BYTE
  5055.  
  5056.  HotKBFlag       DB      KBAlt           ; hot value of ROM BIOS KB_FLAG
  5057.  HotKBMask       DB      (KBIns OR KBCaps OR KBNum OR KBScroll) XOR 0FFh
  5058.  HotFlag         DB      FALSE
  5059.  
  5060.  ActiveTSR       DB      FALSE
  5061.  
  5062.  DOSVersion      LABEL   WORD
  5063.                  DB      ?               ; minor version number
  5064.  MajorVersion    DB      ?               ; major version number
  5065.  
  5066.  ; The following data is used by the TSR application:
  5067.  
  5068.  NTrap           DW      (EndTrapList-StartTrapList)/8   ; number of traps
  5069.  
  5070.  StartTrapList   DB      1Bh
  5071.  Trap1B          DB      FALSE
  5072.  PrevISR1B       DD      ?
  5073.                  DW      offset RESIDENT_GROUP:ISR1B
  5074.  
  5075.                  DB      23h
  5076.  Trap23          DB      FALSE
  5077.  PrevISR23       DD      ?
  5078.                  DW      offset RESIDENT_GROUP:ISR23
  5079.  
  5080.                  DB      24h
  5081.  Trap24          DB      FALSE
  5082.  PrevISR24       DD      ?
  5083.                  DW      offset RESIDENT_GROUP:ISR24
  5084.  
  5085.  EndTrapList     LABEL   BYTE
  5086.  
  5087.  PrevBreak       DB      ?               ; previous break-checking flag
  5088.  
  5089.  PrevDTA         LABEL   DWORD           ; previous DTA address
  5090.  PrevDTAoffs     DW      ?
  5091.  PrevDTAseg      DW      ?
  5092.  
  5093.  PrevExtErrInfo  LABEL   BYTE            ; previous extended error information
  5094.  PrevExtErrAX    DW      ?
  5095.  PrevExtErrBX    DW      ?
  5096.  PrevExtErrCX    DW      ?
  5097.  PrevExtErrDX    DW      ?
  5098.  PrevExtErrSI    DW      ?
  5099.  PrevExtErrDI    DW      ?
  5100.  PrevExtErrDS    DW      ?
  5101.  PrevExtErrES    DW      ?
  5102.                  DW      3 dup(0)
  5103.  
  5104.  SnapFile        DB      '\snap.img'     ; output filename in root directory
  5105.  
  5106.  RESIDENT_DATA   ENDS
  5107.  
  5108.  RESIDENT_STACK  SEGMENT word stack 'STACK'
  5109.  
  5110.                  DB      TSRStackSize dup(?)
  5111.  
  5112.  RESIDENT_STACK  ENDS
  5113.  
  5114.                  PAGE
  5115.  ;----------------------------------------------------------------------------
  5116.  ;
  5117.  ; Transient installation routines
  5118.  ;
  5119.  ;----------------------------------------------------------------------------
  5120.  
  5121.  TRANSIENT_TEXT  SEGMENT para public 'TCODE'
  5122.                  ASSUME  cs:TRANSIENT_TEXT,ds:RESIDENT_DATA,ss:RESIDENT_STACK
  5123.  
  5124.  InstallSnapTSR  PROC    far             ; At entry:  CS:IP -> InstallSnapTSR
  5125.                                          ;            SS:SP -> stack
  5126.                                          ;            DS,ES -> PSP
  5127.  ; Save PSP segment
  5128.  
  5129.                  mov     ax,seg RESIDENT_DATA
  5130.                  mov     ds,ax           ; DS  -> RESIDENT_DATA
  5131.  
  5132.                  mov     TSRPSP,es       ; save PSP segment
  5133.  
  5134.  ; Check the MS-DOS version
  5135.  
  5136.                  call    GetDOSVersion   ; AH = major version number
  5137.                                          ; AL = minor version number
  5138.  
  5139.  ; Verify that this TSR is not already installed
  5140.  ;
  5141.  ;       Before executing INT 2Fh in MS-DOS versions 2.x, test whether INT 2FH
  5142.  ;       vector is in use.  If so, abort if PRINT.COM is using it.
  5143.  ;
  5144.  ;       (Thus, in MS-DOS 2.x, if both this program and PRINT.COM are used,
  5145.  ;       this program should be made resident before PRINT.COM.)
  5146.  
  5147.                  cmp     ah,2
  5148.                  ja      L101            ; jump if version 3.0 or later
  5149.  
  5150.                  mov     ax,352Fh        ; AH = INT 21H function number
  5151.                                          ; AL = interrupt number
  5152.                  int     21h             ; ES:BX = INT 2FH vector
  5153.  
  5154.                  mov     ax,es
  5155.                  or      ax,bx           ; jump if current INT 2FH vector ..
  5156.                  jnz     L100            ; .. is nonzero
  5157.  
  5158.                  push    ds
  5159.                  mov     ax,252Fh        ; AH = INT 21H function number
  5160.                                          ; AL = interrupt number
  5161.                  mov     dx,seg RESIDENT_GROUP
  5162.                  mov     ds,dx
  5163.                  mov     dx,offset RESIDENT_GROUP:MultiplexIRET
  5164.  
  5165.                  int     21h             ; point INT 2FH vector to IRET
  5166.                  pop     ds
  5167.                  jmp     short L103      ; jump to install this TSR
  5168.  
  5169.  L100:           mov     ax,0FF00h       ; look for PRINT.COM:
  5170.                  int     2Fh             ; if resident, AH = print queue lengt
  5171.                                          ; otherwise, AH is unchanged
  5172.  
  5173.                  cmp     ah,0FFh         ; if PRINT.COM is not resident ..
  5174.                  je      L101            ; .. use multiplex interrupt
  5175.  
  5176.                  mov     al,1
  5177.                  call    FatalError      ; abort if PRINT.COM already installe
  5178.  
  5179.  L101:           mov     ah,MultiplexID  ; AH = multiplex interrupt ID value
  5180.                  xor     al,al           ; AL = 00H
  5181.                  int     2Fh             ; multiplex interrupt
  5182.  
  5183.                  test    al,al
  5184.                  jz      L103            ; jump if ok to install
  5185.  
  5186.                  cmp     al,0FFh
  5187.                  jne     L102            ; jump if not already installed
  5188.  
  5189.                  mov     al,2
  5190.                  call    FatalError      ; already installed
  5191.  
  5192.  L102:           mov     al,3
  5193.                  call    FatalError      ; can't install
  5194.  
  5195.  ; Get addresses of InDOS and ErrorMode flags
  5196.  
  5197.  L103:           call    GetDOSFlags
  5198.  
  5199.  ; Install this TSR's interrupt handlers
  5200.  
  5201.                  push    es              ; preserve PSP segment
  5202.  
  5203.                  mov     cx,NISR
  5204.                  mov     si,offset StartISRList
  5205.  
  5206.  L104:           lodsb                   ; AL = interrupt number
  5207.                                          ; DS:SI -> byte past interrupt number
  5208.                  push    ax              ; preserve AX
  5209.                  mov     ah,35h          ; INT 21H function 35H
  5210.                  int     21h             ; ES:BX = previous interrupt vector
  5211.                  mov     [si+1],bx       ; save offset and segment ..
  5212.                  mov     [si+3],es       ; .. of previous handler
  5213.  
  5214.                  pop     ax              ; AL = interrupt number
  5215.                  push    ds              ; preserve DS
  5216.                  mov     dx,[si+5]
  5217.                  mov     bx,seg RESIDENT_GROUP
  5218.                  mov     ds,bx           ; DS:DX -> this TSR's handler
  5219.                  mov     ah,25h          ; INT 21H function 25H
  5220.                  int     21h             ; (set interrupt vector)
  5221.                  pop     ds              ; restore DS
  5222.                  add     si,7            ; DS:SI -> next in list
  5223.                  loop    L104
  5224.  
  5225.  ; Free the environment
  5226.  
  5227.                  pop     es              ; ES = PSP segment
  5228.                  push    es              ; preserve PSP segment
  5229.                  mov     es,es:[2Ch]     ; ES = segment of environment
  5230.                  mov     ah,49h          ; INT 21H function 49H
  5231.                  int     21h             ; (free memory block)
  5232.  
  5233.  ; Terminate and stay resident
  5234.  
  5235.                  pop     ax              ; AX = PSP segment
  5236.                  mov     dx,cs           ; DX = paragraph address of start of
  5237.                                          ; transient portion (end of resident
  5238.                                          ; portion)
  5239.                  sub     dx,ax           ; DX = size of resident portion
  5240.  
  5241.                  mov     ax,3100h        ; AH = INT 21H function number
  5242.                                          ; AL = 00H (return code)
  5243.                  int     21h
  5244.  
  5245.  InstallSnapTSR  ENDP
  5246.  
  5247.  
  5248.  GetDOSVersion   PROC    near            ; Caller:   DS = seg RESIDENT_DATA
  5249.                                          ;           ES = PSP
  5250.                                          ; Returns:  AH = major version
  5251.                                          ;           AL = minor version
  5252.                  ASSUME  ds:RESIDENT_DATA
  5253.  
  5254.                  mov     ax,30h          ; INT 21h function 30H:
  5255.                                          ; (get MS-DOS version)
  5256.                  int     21h
  5257.                  cmp     al,2
  5258.                  jb      L110            ; jump if version 1.x
  5259.  
  5260.                  xchg    ah,al           ; AH = major version
  5261.                                          ; AL = minor version
  5262.                  mov     DOSVersion,ax   ; save with major version in
  5263.                                          ; high-order byte
  5264.                  ret
  5265.  
  5266.  L110:           mov     al,00h
  5267.                  call    FatalError      ; abort if version 1.x
  5268.  
  5269.  GetDOSVersion   ENDP
  5270.  GetDOSFlags     PROC    near            ; Caller:     DS = seg RESIDENT_DATA
  5271.                                          ; Returns:    InDOSAddr -> InDOS
  5272.                                          ;             ErrorModeAddr -> ErrorM
  5273.                                          ; Destroys:   AX,BX,CX,DI
  5274.                  ASSUME  ds:RESIDENT_DATA
  5275.  
  5276.  ; Get InDOS address from MS-DOS
  5277.  
  5278.                  push    es
  5279.  
  5280.                  mov     ah,34h          ; INT 21H function number
  5281.                  int     21h             ; ES:BX -> InDOS
  5282.                  mov     word ptr InDOSAddr,bx
  5283.                  mov     word ptr InDOSAddr+2,es
  5284.  
  5285.  ; Determine ErrorMode address
  5286.  
  5287.                  mov     word ptr ErrorModeAddr+2,es     ; assume ErrorMode is
  5288.                                                          ; in the same segment
  5289.                                                          ; as InDOS
  5290.  
  5291.                  mov     ax,DOSVersion
  5292.                  cmp     ax,30Ah
  5293.                  jb      L120            ; jump if MS-DOS version earlier
  5294.                                          ; than 3.1 ..
  5295.                  cmp     ax,0A00h
  5296.                  jae     L120            ; .. or MS OS/2-DOS 3.x box
  5297.  
  5298.                  dec     bx              ; in MS-DOS 3.1 and later, ErrorMode
  5299.                  mov     word ptr ErrorModeAddr,bx       ; is just before InDO
  5300.                  jmp     short L125
  5301.  
  5302.  L120:                                   ; scan MS-DOS segment for ErrorMode
  5303.  
  5304.                  mov     cx,0FFFFh       ; CX = maximum number of bytes to sca
  5305.                  xor     di,di           ; ES:DI -> start of MS-DOS segment
  5306.  
  5307.  L121:           mov     ax,word ptr cs:LF2  ; AX = opcode for INT 28H
  5308.  
  5309.  L122:           repne   scasb           ; scan for first byte of fragment
  5310.                  jne     L126            ; jump if not found
  5311.  
  5312.                  cmp     ah,es:[di]              ; inspect second byte of opco
  5313.                  jne     L122                    ; jump if not INT 28H
  5314.  
  5315.                  mov     ax,word ptr cs:LF1 + 1  ; AX = opcode for CMP
  5316.                  cmp     ax,es:[di][LF1-LF2]
  5317.                  jne     L123                    ; jump if opcode not CMP
  5318.  
  5319.                  mov     ax,es:[di][(LF1-LF2)+2] ; AX = offset of ErrorMode
  5320.                  jmp     short L124              ; in DOS segment
  5321.  
  5322.  L123:           mov     ax,word ptr cs:LF3 + 1  ; AX = opcode for TEST
  5323.                  cmp     ax,es:[di][LF3-LF4]
  5324.                  jne     L121                    ; jump if opcode not TEST
  5325.  
  5326.                  mov     ax,es:[di][(LF3-LF4)+2] ; AX = offset of ErrorMode
  5327.  
  5328.  L124:           mov     word ptr ErrorModeAddr,ax
  5329.  
  5330.  L125:           pop     es
  5331.                  ret
  5332.  
  5333.  ; Come here if address of ErrorMode not found
  5334.  
  5335.  L126:           mov     al,04H
  5336.                  call    FatalError
  5337.  
  5338.  
  5339.  ; Code fragments for scanning for ErrorMode flag
  5340.  
  5341.  LFnear          LABEL   near            ; dummy labels for addressing
  5342.  LFbyte          LABEL   byte
  5343.  LFword          LABEL   word
  5344.                                          ; MS-DOS versions earlier than 3.1
  5345.  LF1:            cmp     ss:LFbyte,0     ; CMP ErrorMode,0
  5346.                  jne     LFnear
  5347.  LF2:            int     28h
  5348.                                          ; MS-DOS versions 3.1 and later
  5349.  
  5350.  LF3:            test    ss:LFbyte,0FFh  ; TEST ErrorMode,0FFH
  5351.                  jne     LFnear
  5352.                  push    ss:LFword
  5353.  LF4:            int     28h
  5354.  
  5355.  GetDOSFlags     ENDP
  5356.  
  5357.  FatalError      PROC    near            ; Caller:   AL = message number
  5358.                                          ;           ES = PSP
  5359.                  ASSUME  ds:TRANSIENT_DATA
  5360.  
  5361.                  push    ax              ; save message number on stack
  5362.  
  5363.                  mov     bx,seg TRANSIENT_DATA
  5364.                  mov     ds,bx
  5365.  
  5366.  ; Display the requested message
  5367.  
  5368.                  mov     bx,offset MessageTable
  5369.                  xor     ah,ah           ; AX = message number
  5370.                  shl     ax,1            ; AX = offset into MessageTable
  5371.                  add     bx,ax           ; DS:BX -> address of message
  5372.                  mov     dx,[bx]         ; DS:BX -> message
  5373.                  mov     ah,09h          ; INT 21H function 09H (display strin
  5374.                  int     21h             ; display error message
  5375.  
  5376.                  pop     ax              ; AL = message number
  5377.                  or      al,al
  5378.                  jz      L130            ; jump if message number is zero
  5379.                                          ; (MS-DOS versions 1.x)
  5380.  
  5381.  ; Terminate (MS-DOS 2.x and later)
  5382.  
  5383.                  mov     ah,4Ch          ; INT 21H function 4CH
  5384.                  int     21h             ; (terminate process with return code
  5385.  
  5386.  ; Terminate (MS-DOS 1.x)
  5387.  
  5388.  L130            PROC    far
  5389.  
  5390.                  push    es              ; push PSP:0000H
  5391.                  xor     ax,ax
  5392.                  push    ax
  5393.                  ret                     ; far return (jump to PSP:0000H)
  5394.  
  5395.  L130            ENDP
  5396.  
  5397.  FatalError      ENDP
  5398.  
  5399.  
  5400.  TRANSIENT_TEXT  ENDS
  5401.  
  5402.                  PAGE
  5403.  ;
  5404.  ;
  5405.  ; Transient data segment
  5406.  ;
  5407.  ;
  5408.  
  5409.  TRANSIENT_DATA  SEGMENT word public 'DATA'
  5410.  
  5411.  MessageTable    DW   Message0           ; MS-DOS version error
  5412.                  DW   Message1           ; PRINT.COM found in MS-DOS 2.x
  5413.                  DW   Message2           ; already installed
  5414.                  DW   Message3           ; can't install
  5415.                  DW   Message4           ; can't find flag
  5416.  
  5417.  Message0        DB   CR,LF,'TSR requires MS-DOS 2.0 or later version',CR,LF,'
  5418.  Message1        DB   CR,LF,'Can''t install TSR:  PRINT.COM active',CR,LF,'$'
  5419.  Message2        DB   CR,LF,'This TSR is already installed',CR,LF,'$'
  5420.  Message3        DB   CR,LF,'Can''t install this TSR',CR,LF,'$'
  5421.  Message4        DB   CR,LF,'Unable to locate MS-DOS ErrorMode flag',CR,LF,'$'
  5422.  
  5423.  TRANSIENT_DATA  ENDS
  5424.  
  5425.                  END     InstallSnapTSR
  5426.  
  5427.  \SAMPCODE\DOS_ENCY\12
  5428.  \SAMPCODE\DOS_ENCY\12\FXN59H_1.ASM
  5429.  
  5430.  myfcb   db      0               ; drive = default
  5431.          db      'MYFILE  '      ; filename, 8 chars
  5432.          db      'DAT'           ; extension, 3 chars
  5433.          db      25 dup (0)      ; remainder of FCB
  5434.          .
  5435.          .
  5436.          .
  5437.          mov     dx,seg myfcb    ; DS:DX = FCB
  5438.          mov     ds,dx
  5439.          mov     dx,offset myfcb
  5440.          mov     ah,0fh          ; function 0FH = Open FCB
  5441.  
  5442.          int     21h             ; transfer to MS-DOS
  5443.          or      al,al           ; test status
  5444.          jz      success         ; jump, open succeeded
  5445.                                  ; open failed, get
  5446.                                  ; extended error info
  5447.          mov     bx,0            ; BX = 00H for ver. 2.x-3.x
  5448.          mov     ah,59h          ; function 59H = Get Info
  5449.          int     21h             ; transfer to MS-DOS
  5450.          or      ax,ax           ; really an error?
  5451.          jz      success         ; no error, jump
  5452.                                  ; test recommended actions
  5453.          cmp     bl,01h
  5454.          jz      retry           ; if BL = 01H retry operation
  5455.          cmp     bl,04h
  5456.          jz      cleanup         ; if BL = 04H clean up and exit
  5457.          cmp     bl,05h
  5458.          jz      panic           ; if BL = 05H exit immediately
  5459.          .
  5460.          .
  5461.          .
  5462.  
  5463.  \SAMPCODE\DOS_ENCY\12\FXN59H_2.ASM
  5464.  
  5465.  myfile  db      'MYFILE.DAT',0  ; ASCIIZ filename
  5466.          .
  5467.          .
  5468.          .
  5469.          mov     dx,seg myfile   ; DS:DX = ASCIIZ filename
  5470.          mov     ds,dx
  5471.          mov     dx,offset myfile
  5472.          mov     ax,3d02h        ; open, read/write
  5473.          int     21h             ; transfer to MS-DOS
  5474.          jnc     success         ; jump, open succeeded
  5475.                                  ; open failed, get
  5476.                                  ; extended error info
  5477.          mov     bx,0            ; BX = 00H for ver. 2.x-3.x
  5478.          mov     ah,59h          ; function 59H = Get Info
  5479.          int     21h             ; transfer to MS-DOS
  5480.          or      ax,ax           ; really an error?
  5481.          jz      success         ; no error, jump
  5482.                                  ; test recommended actions
  5483.          cmp     bl,01h
  5484.          jz      retry           ; if BL = 01H retry operation
  5485.          .
  5486.          .
  5487.          .
  5488.  
  5489.  \SAMPCODE\DOS_ENCY\12\INT24.ASM
  5490.  
  5491.          name    int24
  5492.          title   INT24 Critical Error Handler
  5493.  
  5494.  ;
  5495.  ; INT24.ASM -- Replacement critical error handler
  5496.  ; by Ray Duncan, September 1987
  5497.  ;
  5498.  
  5499.  cr      equ     0dh             ; ASCII carriage return
  5500.  lf      equ     0ah             ; ASCII linefeed
  5501.  
  5502.  DGROUP  group   _DATA
  5503.  
  5504.  _DATA   segment word public 'DATA'
  5505.  
  5506.  save24  dd      0               ; previous contents of Int 24H
  5507.                                  ; critical error handler vector
  5508.  
  5509.                                  ; prompt message used by
  5510.                                  ; critical error handler
  5511.  prompt  db      cr,lf,'Critical Error Occurred: '
  5512.          db      'Abort, Retry, Ignore, Fail? $'
  5513.  
  5514.  keys    db      'aArRiIfF'      ; possible user response keys
  5515.  keys_len equ    $-keys          ; (both cases of each allowed)
  5516.  
  5517.  codes   db      2,2,1,1,0,0,3,3 ; codes returned to MS-DOS kernel
  5518.                                  ; for corresponding response keys
  5519.  
  5520.  _DATA   ends
  5521.  
  5522.  
  5523.  _TEXT   segment word public 'CODE'
  5524.  
  5525.          assume  cs:_TEXT,ds:DGROUP
  5526.  
  5527.          public  get24
  5528.  get24   proc    near            ; set Int 24H vector to point
  5529.                                  ; to new critical error handler
  5530.  
  5531.          push    ds              ; save segment registers
  5532.          push    es
  5533.  
  5534.          mov     ax,3524h        ; get address of previous
  5535.          int     21h             ; INT 24H handler and save it
  5536.  
  5537.          mov     word ptr save24,bx
  5538.          mov     word ptr save24+2,es
  5539.  
  5540.          push    cs              ; set DS:DX to point to
  5541.          pop     ds              ; new INT 24H handler
  5542.          mov     dx,offset _TEXT:int24
  5543.          mov     ax,2524h        ; then call MS-DOS to
  5544.          int     21h             ; set the INT 24H vector
  5545.  
  5546.          pop     es              ; restore segment registers
  5547.          pop     ds
  5548.          ret                     ; and return to caller
  5549.  
  5550.  get24   endp
  5551.  
  5552.  
  5553.          public  res24
  5554.  res24   proc    near            ; restore original contents
  5555.                                  ; of Int 24H vector
  5556.  
  5557.          push    ds              ; save our data segment
  5558.  
  5559.          lds     dx,save24       ; put address of old handler
  5560.          mov     ax,2524h        ; back into INT 24H vector
  5561.          int     21h
  5562.  
  5563.          pop     ds              ; restore data segment
  5564.          ret                     ; and return to caller
  5565.  
  5566.  res24   endp
  5567.  
  5568.  ;
  5569.  ; This is the replacement critical error handler.  It
  5570.  ; prompts the user for Abort, Retry, Ignore, or Fail and
  5571.  ; returns the appropriate code to the MS-DOS kernel.
  5572.  ;
  5573.  int24   proc    far             ; entered from MS-DOS kernel
  5574.  
  5575.          push    bx              ; save registers
  5576.          push    cx
  5577.          push    dx
  5578.          push    si
  5579.          push    di
  5580.          push    bp
  5581.          push    ds
  5582.          push    es
  5583.  
  5584.  int24a: mov     ax,DGROUP       ; display prompt for user
  5585.          mov     ds,ax           ; using function 09H (print string
  5586.          mov     es,ax           ; terminated by $ character)
  5587.          mov     dx,offset prompt
  5588.          mov     ah,09h
  5589.          int     21h
  5590.  
  5591.          mov     ah,01h          ; get user's response
  5592.          int     21h             ; Function 01H = read one character
  5593.  
  5594.          mov     di,offset keys  ; look up code for response key
  5595.          mov     cx,keys_len
  5596.          cld
  5597.          repne scasb
  5598.          jnz     int24a          ; prompt again if bad response
  5599.  
  5600.                                  ; set AL = action code for MS-DOS
  5601.                                  ; according to key that was entered:
  5602.                                  ; 0 = ignore, 1 = retry, 2 = abort, 3 = fail
  5603.          mov     al,[di+keys_len-1]
  5604.  
  5605.          pop     es              ; restore registers
  5606.          pop     ds
  5607.          pop     bp
  5608.          pop     di
  5609.          pop     si
  5610.          pop     dx
  5611.          pop     cx
  5612.          pop     bx
  5613.          iret                    ; exit critical error handler
  5614.  
  5615.  int24   endp
  5616.  
  5617.  _TEXT   ends
  5618.  
  5619.          end
  5620.  
  5621.  \SAMPCODE\DOS_ENCY\12\REST_INT.ASM
  5622.  
  5623.  rest_int proc   near
  5624.          push    ds              ; save our data segment
  5625.          mov     dx,word ptr oldint23
  5626.          mov     ds,word ptr oldint23+2
  5627.          mov     ax,2523h        ; restore original contents
  5628.          int     21h             ; of Int 23H vector
  5629.          pop     ds              ; restore our data segment
  5630.          push    ds              ; then save it again
  5631.          mov     dx,word ptr oldint1B
  5632.          mov     ds,word ptr oldint1B+2
  5633.          mov     ax,251Bh        ; restore original contents
  5634.          int     21h             ; of Int 1BH vector
  5635.          pop     ds              ; get back our data segment
  5636.          ret                     ; return to caller
  5637.  rest_int endp
  5638.  
  5639.  \SAMPCODE\DOS_ENCY\12\SET_INT.ASM
  5640.  
  5641.  _DATA   segment para public 'DATA'
  5642.  oldint1b dd     0               ; original INT 1BH vector
  5643.  oldint23 dd     0               ; original INT 23H vector
  5644.  _DATA   ends
  5645.  _TEXT   segment byte public 'CODE'
  5646.          assume cs:_TEXT,ds:_DATA,es:NOTHING
  5647.  myint1b:                        ; handler for Ctrl-Break
  5648.  myint23:                        ; handler for Ctrl-C
  5649.          iret
  5650.  
  5651.  set_int proc    near
  5652.          mov     ax,351bh        ; get current contents of
  5653.          int     21h             ; Int 1BH vector and save it
  5654.          mov     word ptr oldint1b,bx
  5655.          mov     word ptr oldint1b+2,es
  5656.          mov     ax,3523h        ; get current contents of
  5657.          int     21h             ; Int 23H vector and save it
  5658.          mov     word ptr oldint23,bx
  5659.          mov     word ptr oldint23+2,es
  5660.          push    ds              ; save our data segment
  5661.          push    cs              ; let DS point to our
  5662.          pop     ds              ; code segment
  5663.          mov     dx,offset myint1b
  5664.          mov     ax,251bh        ; set interrupt vector 1BH
  5665.          int     21h             ; to point to new handler
  5666.          mov     dx,offset myint23
  5667.          mov     ax,2523h        ; set interrupt vector 23H
  5668.          int     21h             ; to point to new handler
  5669.          pop     ds              ; restore our data segment
  5670.          ret                     ; back to caller
  5671.  set_int endp
  5672.  _TEXT   ends
  5673.  
  5674.  \SAMPCODE\DOS_ENCY\13
  5675.  \SAMPCODE\DOS_ENCY\13\DIVZERO.ASM
  5676.  
  5677.          name    divzero
  5678.          title   'DIVZERO - Interrupt 00H Handler'
  5679.  ;
  5680.  ; DIVZERO.ASM: Demonstration Interrupt 00H Handler
  5681.  ;
  5682.  ; To assemble, link, and convert to COM file:
  5683.  ;
  5684.  ;       C>MASM DIVZERO;  <Enter>
  5685.  ;       C>LINK DIVZERO;  <Enter>
  5686.  ;       C>EXE2BIN DIVZERO.EXE DIVZERO.COM  <Enter>
  5687.  ;       C>DEL DIVZERO.EXE  <Enter>
  5688.  ;
  5689.  
  5690.  cr      equ     0dh             ; ASCII carriage return
  5691.  lf      equ     0ah             ; ASCII linefeed
  5692.  eos     equ     '$'             ; end of string marker
  5693.  
  5694.  _TEXT   segment word public 'CODE'
  5695.  
  5696.          assume  cs:_TEXT,ds:_TEXT,es:_TEXT,ss:_TEXT
  5697.  
  5698.          org     100h
  5699.  
  5700.  entry:  jmp     start           ; skip over data area
  5701.  
  5702.  intmsg  db      'Divide by Zero Occurred!',cr,lf,eos
  5703.  
  5704.  divmsg  db      'Dividing '     ; message used by demo
  5705.  par1    db      '0000h'         ; dividend goes here
  5706.          db      ' by '
  5707.  par2    db      '00h'           ; divisor goes here
  5708.          db      ' equals '
  5709.  par3    db      '00h'           ; quotient here
  5710.          db      ' remainder '
  5711.  par4    db      '00h'           ; and remainder here
  5712.          db      cr,lf,eos
  5713.  
  5714.  oldint0 dd      ?               ; save old Int 00H vector
  5715.  
  5716.  intflag db      0               ; nonzero if divide by
  5717.                                  ; zero interrupt occurred
  5718.  
  5719.  oldip   dw      0               ; save old IP value
  5720.  
  5721.  
  5722.  ;
  5723.  ; The routine 'int0' is the actual divide by zero
  5724.  ; interrupt handler.  It gains control whenever a
  5725.  ; divide by zero or overflow occurs.  Its action
  5726.  ; is to set a flag and then increment the instruction
  5727.  ; pointer saved on the stack so that the failing
  5728.  ; divide will not be reexecuted after the IRET.
  5729.  ;
  5730.  ; In this particular case we can call MS-DOS to
  5731.  ; display a message during interrupt handling
  5732.  ; because the application triggers the interrupt
  5733.  ; intentionally. Thus, it is known that MS-DOS or
  5734.  ; other interrupt handlers are not in control
  5735.  ; at the point of interrupt.
  5736.  ;
  5737.  
  5738.  int0:   pop     cs:oldip        ; capture instruction pointer
  5739.  
  5740.          push    ax
  5741.          push    bx
  5742.          push    cx
  5743.          push    dx
  5744.          push    di
  5745.          push    si
  5746.          push    ds
  5747.          push    es
  5748.  
  5749.          push    cs              ; set DS = CS
  5750.          pop     ds
  5751.  
  5752.          mov     ah,09h          ; print error message
  5753.          mov     dx,offset _TEXT:intmsg
  5754.          int     21h
  5755.  
  5756.          add     oldip,2         ; bypass instruction causing
  5757.                                  ; divide by zero error
  5758.  
  5759.          mov     intflag,1       ; set divide by 0 flag
  5760.  
  5761.          pop     es              ; restore all registers
  5762.          pop     ds
  5763.          pop     si
  5764.          pop     di
  5765.          pop     dx
  5766.          pop     cx
  5767.          pop     bx
  5768.          pop     ax
  5769.  
  5770.          push    cs:oldip        ; restore instruction pointer
  5771.  
  5772.          iret                    ; return from interrupt
  5773.  
  5774.  
  5775.  ;
  5776.  ; The code beginning at 'start' is the application
  5777.  ; program.  It alters the vector for Interrupt 00H to
  5778.  ; point to the new handler, carries out some divide
  5779.  ; operations (including one that will trigger an
  5780.  ; interrupt) for demonstration purposes, restores
  5781.  ; the original contents of the Interrupt 00H vector,
  5782.  ; and then terminates.
  5783.  ;
  5784.  
  5785.  start:  mov     ax,3500h        ; get current contents
  5786.          int     21h             ; of Int 00H vector
  5787.  
  5788.                                  ; save segment:offset
  5789.                                  ; of previous Int 00H handler
  5790.          mov     word ptr oldint0,bx
  5791.          mov     word ptr oldint0+2,es
  5792.  
  5793.                                  ; install new handler...
  5794.          mov     dx,offset int0  ; DS:DX = handler address
  5795.          mov     ax,2500h        ; call MS-DOS to set
  5796.          int     21h             ; Int 00H vector
  5797.  
  5798.                                  ; now our handler is active,
  5799.                                  ; carry out some test divides.
  5800.  
  5801.          mov     ax,20h          ; test divide
  5802.          mov     bx,1            ; divide by 1
  5803.          call    divide
  5804.  
  5805.          mov     ax,1234h        ; test divide
  5806.          mov     bx,5eh          ; divide by 5EH
  5807.          call    divide
  5808.  
  5809.          mov     ax,5678h        ; test divide
  5810.          mov     bx,7fh          ; divide by 127
  5811.          call    divide
  5812.  
  5813.          mov     ax,20h          ; test divide
  5814.          mov     bx,0            ; divide by 0
  5815.          call    divide          ; (triggers interrupt)
  5816.  
  5817.                                  ; demonstration complete,
  5818.                                  ; restore old handler
  5819.  
  5820.          lds     dx,oldint0      ; DS:DX = handler address
  5821.          mov     ax,2500h        ; call MS-DOS to set
  5822.          int     21h             ; Int 00H vector
  5823.  
  5824.          mov     ax,4c00h        ; final exit to MS-DOS
  5825.          int     21h             ; with return code = 0
  5826.  
  5827.  ;
  5828.  ; The routine 'divide' carries out a trial division,
  5829.  ; displaying the arguments and the results.  It is
  5830.  ; called with AX = dividend and BL = divisor.
  5831.  ;
  5832.  
  5833.  divide  proc    near
  5834.  
  5835.          push    ax              ; save arguments
  5836.          push    bx
  5837.  
  5838.          mov     di,offset par1  ; convert dividend to
  5839.          call    wtoa            ; ASCII for display
  5840.  
  5841.          mov     ax,bx           ; convert divisor to
  5842.          mov     di,offset par2  ; ASCII for display
  5843.          call    btoa
  5844.  
  5845.          pop     bx              ; restore arguments
  5846.          pop     ax
  5847.  
  5848.          div     bl              ; perform the division
  5849.          cmp     intflag,0       ; divide by zero detected?
  5850.          jne     nodiv           ; yes, skip display
  5851.  
  5852.          push    ax              ; no, convert quotient to
  5853.          mov     di,offset par3  ; ASCII for display
  5854.          call    btoa
  5855.  
  5856.          pop     ax              ; convert remainder to
  5857.          xchg    ah,al           ; ASCII for display
  5858.          mov     di,offset par4
  5859.          call    btoa
  5860.  
  5861.          mov     ah,09h          ; show arguments, results
  5862.          mov     dx,offset divmsg
  5863.          int     21h
  5864.  
  5865.  nodiv:  mov     intflag,0       ; clear divide by 0 flag
  5866.          ret                     ; and return to caller
  5867.  
  5868.  divide  endp
  5869.  
  5870.  
  5871.  
  5872.  wtoa    proc    near            ; convert word to hex ASCII
  5873.                                  ; call with AX = binary value
  5874.                                  ;           DI = addr for string
  5875.                                  ; returns AX, CX, DI destroyed
  5876.  
  5877.          push    ax              ; save original value
  5878.          mov     al,ah
  5879.          call    btoa            ; convert upper byte
  5880.          add     di,2            ; increment output address
  5881.          pop     ax
  5882.          call    btoa            ; convert lower byte
  5883.          ret                     ; return to caller
  5884.  
  5885.  wtoa    endp
  5886.  
  5887.  
  5888.  
  5889.  btoa    proc    near            ; convert byte to hex ASCII
  5890.                                  ; call with AL = binary value
  5891.                                  ;           DI = addr to store string
  5892.                                  ; returns AX, CX destroyed
  5893.  
  5894.          mov     ah,al           ; save lower nibble
  5895.          mov     cx,4            ; shift right 4 positions
  5896.          shr     al,cl           ; to get upper nibble
  5897.          call    ascii           ; convert 4 bits to ASCII
  5898.          mov     [di],al         ; store in output string
  5899.          mov     al,ah           ; get back lower nibble
  5900.  
  5901.          and     al,0fh          ; blank out upper one
  5902.          call    ascii           ; convert 4 bits to ASCII
  5903.          mov     [di+1],al       ; store in output string
  5904.          ret                     ; back to caller
  5905.  
  5906.  btoa    endp
  5907.  
  5908.  
  5909.  
  5910.  ascii   proc    near            ; convert AL bits 0-3 to
  5911.                                  ; ASCII {0...9,A...F}
  5912.          add     al,'0'          ; and return digit in AL
  5913.          cmp     al,'9'
  5914.          jle     ascii2
  5915.          add     al,'A'-'9'-1    ; "fudge factor" for A-F
  5916.  ascii2: ret                     ; return to caller
  5917.  
  5918.  ascii   endp
  5919.  
  5920.  _TEXT   ends
  5921.  
  5922.          end     entry
  5923.  
  5924.  \SAMPCODE\DOS_ENCY\13\INT08H.ASM
  5925.  
  5926.          .
  5927.          .
  5928.          .
  5929.  myflag  dw      ?                       ; variable to be incremented
  5930.                                          ; on each timer-tick interrupt
  5931.  
  5932.  oldint8 dd      ?                       ; contains address of previous
  5933.                                          ; timer-tick interrupt handler
  5934.          .
  5935.          .                               ; get the previous contents
  5936.          .                               ; of the Interrupt 0BH vector...
  5937.          mov     ax,3508h                ; AH = 35H (Get Interrupt Vector)
  5938.          int     21h                     ; AL = Interrupt number (08H)
  5939.          mov     word ptr oldint8,bx     ; save the address of
  5940.          mov     word ptr oldint8+2,es   ; the previous Int 08H Handler
  5941.          mov     dx,seg myint8           ; put address of the new
  5942.          mov     ds,dx                   ; interrupt handler into DS:DX
  5943.          mov     dx,offset myint8        ; and call MS-DOS to set vector
  5944.          mov     ax,2508h                ; AH = 25H (Set Interrupt Vector)
  5945.          int     21h                     ; AL = Interrupt number (08H)
  5946.          .
  5947.          .
  5948.          .
  5949.  myint8:                                 ; this is the new handler
  5950.                                          ; for Interrupt 08H
  5951.  
  5952.          inc     cs:myflag               ; increment variable on each
  5953.                                          ; timer-tick interrupt
  5954.  
  5955.          jmp     dword ptr cs:[oldint8]  ; then chain to the
  5956.                                          ; previous interrupt handler
  5957.  
  5958.  \SAMPCODE\DOS_ENCY\13\MYINT8.ASM
  5959.  
  5960.  myint8:                                 ; this is the new handler
  5961.                                          ; for Interrupt 08H
  5962.  
  5963.          mov     ax,1                    ; test and set interrupt-
  5964.          xchg    cs:myflag,ax            ; handling-in-progress semaphore
  5965.  
  5966.          push    ax                      ; save the semaphore
  5967.  
  5968.          pushf                           ; simulate interrupt, allowing
  5969.          call    dword ptr cs:oldint8    ; the previous handler for the
  5970.                                          ; Interrupt 08H vector to run
  5971.  
  5972.          pop     ax                      ; get the semaphore back
  5973.          or      ax,ax                   ; is our interrupt handler
  5974.                                          ; already running?
  5975.  
  5976.          jnz     myint8x                 ; yes, skip this one
  5977.  
  5978.          .                               ; now perform our interrupt
  5979.          .                               ; processing here...
  5980.          .
  5981.  
  5982.          mov     cs:myflag,0             ; clear the interrupt-handling-
  5983.                                          ; in-progress flag
  5984.  
  5985.  myint8x:
  5986.          iret                            ; return from interrupt
  5987.  
  5988.  \SAMPCODE\DOS_ENCY\14
  5989.  \SAMPCODE\DOS_ENCY\14\FIND.C
  5990.  
  5991.  /*
  5992.          FIND.C          Searches text stream for a string.
  5993.  
  5994.          Usage:          FIND "pattern" [< source] [> destination]
  5995.  
  5996.          by Ray Duncan, June 1987
  5997.  
  5998.  */
  5999.  
  6000.  #include <stdio.h>
  6001.  
  6002.  #define TAB     '\x09'                  /* ASCII tab character (^I) */
  6003.  #define BLANK   '\x20'                  /* ASCII space character */
  6004.  
  6005.  #define TAB_WIDTH 8                     /* columns per tab stop */
  6006.  
  6007.  static char input[256];                 /* buffer for line from input */
  6008.  static char output[256];                /* buffer for line to output */
  6009.  static char pattern[256];               /* buffer for search pattern */
  6010.  
  6011.  main(argc,argv)
  6012.  int argc;
  6013.  char *argv[];
  6014.  {       int line=0;                     /* initialize line variable */
  6015.  
  6016.          if ( argc < 2 )                 /* was search pattern supplied? */
  6017.          {       puts("find: missing pattern.");
  6018.                  exit(1);                /* abort if not */
  6019.          }
  6020.          strcpy(pattern,argv[1]);        /* save copy of string to find */
  6021.          strupr(pattern);                /* fold it to uppercase */
  6022.          while( gets(input) != NULL )    /* read a line from input */
  6023.          {       line++;                 /* count lines */
  6024.                  strcpy(output,input);   /* save copy of input string */
  6025.                  strupr(input);          /* fold input to uppercase */
  6026.                                          /* if line contains pattern */
  6027.                  if( strstr(input,pattern) )
  6028.                                          /* write it to standard output */
  6029.                          writeline(line,output);
  6030.          }
  6031.          exit(0);                        /* terminate at end of file */
  6032.  }
  6033.  
  6034.  /*
  6035.          WRITELINE: Write line number and text to standard output,
  6036.          expanding any tab characters to stops defined by TAB_WIDTH.
  6037.  */
  6038.  
  6039.  writeline(line,p)
  6040.  int line;
  6041.  char *p;
  6042.  {       int i=0;                        /* index to original line text */
  6043.          int col=0;                      /* actual output column counter */
  6044.          printf("\n%4d: ",line);         /* write line number */
  6045.          while( p[i]!=NULL )             /* while end of line not reached */
  6046.          {       if(p[i]==TAB)           /* if current char = tab, expand it *
  6047.                  {       do putchar(BLANK);
  6048.                          while((++col % TAB_WIDTH) != 0);
  6049.                  }
  6050.                  else                    /* otherwise just send character */
  6051.                  {       putchar(p[i]);
  6052.                          col++;          /* count columns */
  6053.                  }
  6054.                  i++;                    /* advance through output line */
  6055.          }
  6056.  }
  6057.  
  6058.  \SAMPCODE\DOS_ENCY\14\LC.C
  6059.  
  6060.  /*
  6061.          LC:     a simple character-oriented filter to translate
  6062.                  all uppercase {A-Z} to lowercase {a-z} characters.
  6063.  
  6064.          Usage:  LC [< source] [> destination]
  6065.  
  6066.          Ray Duncan, June 1987
  6067.  
  6068.  */
  6069.  
  6070.  #include <stdio.h>
  6071.  
  6072.  main(argc,argv)
  6073.  int argc;
  6074.  char *argv[];
  6075.  {       char ch;
  6076.                                          /* read a character */
  6077.          while ( (ch=getchar() ) != EOF )
  6078.          {       ch=translate(ch);       /* perform any necessary
  6079.                                             character translation */
  6080.                  putchar(ch);            /* then write character */
  6081.          }
  6082.          exit(0);                        /* terminate at end of file */
  6083.  }
  6084.  
  6085.  /*
  6086.          Translate characters A-Z to lowercase equivalents
  6087.  */
  6088.  
  6089.  int translate(ch)
  6090.  char ch;
  6091.  {       if (ch >= 'A' && ch <= 'Z') ch += 'a'-'A';
  6092.          return (ch);
  6093.  }
  6094.  
  6095.  \SAMPCODE\DOS_ENCY\14\PROTOC.C
  6096.  
  6097.  /*
  6098.          PROTOC.C: a template for a character-oriented filter.
  6099.  
  6100.          Ray Duncan, June 1987
  6101.  */
  6102.  
  6103.  #include <stdio.h>
  6104.  
  6105.  main(argc,argv)
  6106.  int argc;
  6107.  char *argv[];
  6108.  {       char ch;
  6109.  
  6110.          while ( (ch=getchar())!=EOF )   /* read a character */
  6111.          {       ch=translate(ch);       /* translate it if necessary */
  6112.                  putchar(ch);            /* write the character */
  6113.          }
  6114.          exit(0);                        /* terminate at end of file */
  6115.  }
  6116.  
  6117.  /*
  6118.          Perform any necessary translation on character from
  6119.          input file.  Template action just returns same character.
  6120.  */
  6121.  
  6122.  int translate(ch)
  6123.  char ch;
  6124.  {       return (ch);
  6125.  }
  6126.  
  6127.  \SAMPCODE\DOS_ENCY\14\PROTOL.C
  6128.  
  6129.  /*
  6130.          PROTOL.C: a template for a line-oriented filter.
  6131.  
  6132.          Ray Duncan, June 1987.
  6133.  */
  6134.  
  6135.  #include <stdio.h>
  6136.  
  6137.  static char input[256];                 /* buffer for input line */
  6138.  static char output[256];                /* buffer for output line */
  6139.  
  6140.  main(argc,argv)
  6141.  int argc;
  6142.  char *argv[];
  6143.  {       while( gets(input) != NULL )    /* get a line from input stream */
  6144.                                          /* perform any necessary translation
  6145.                                             and possibly write result */
  6146.          {       if (translate()) puts(output);
  6147.          }
  6148.          exit(0);                        /* terminate at end of file */
  6149.  }
  6150.  
  6151.  /*
  6152.          Perform any necessary translation on input line, leaving
  6153.          the resulting text in output buffer.  Value of function
  6154.          is 'true' if output buffer should be written to standard output
  6155.          by main routine, 'false' if nothing should be written.
  6156.  */
  6157.  
  6158.  translate()
  6159.  {       strcpy(output,input);           /* template action is copy input */
  6160.          return(1);                      /* line and return true flag */
  6161.  }
  6162.  
  6163.  \SAMPCODE\DOS_ENCY\14\EXECSORT.ASM
  6164.  
  6165.          name    execsort
  6166.          title   'EXECSORT --- demonstrate EXEC of filter'
  6167.          .sall
  6168.  ;
  6169.  ; EXECSORT.ASM --- demonstration of use of EXEC to run the SORT
  6170.  ; filter as a child process, redirecting its input and output.
  6171.  ; This program requires the files SORT.EXE and MYFILE.DAT in
  6172.  ; the current drive and directory.
  6173.  ;
  6174.  ; Ray Duncan, June 1987
  6175.  ;
  6176.  
  6177.  stdin   equ     0                       ; standard input
  6178.  stdout  equ     1                       ; standard output
  6179.  stderr  equ     2                       ; standard error
  6180.  
  6181.  stksize equ     128                     ; size of stack
  6182.  
  6183.  cr      equ     0dh                     ; ASCII carriage return
  6184.  lf      equ     0ah                     ; ASCII linefeed
  6185.  
  6186.  jerr    macro   target                  ;; Macro to test carry flag
  6187.          local   notset                  ;; and jump if flag set.
  6188.          jnc     notset                  ;; Uses JMP DISP16 to avoid
  6189.          jmp     target                  ;; branch out of range errors
  6190.  notset:
  6191.          endm
  6192.  
  6193.  
  6194.  DGROUP  group   _DATA,_STACK            ; 'automatic data group'
  6195.  
  6196.  
  6197.  _TEXT   segment byte public 'CODE'      ; executable code segment
  6198.  
  6199.          assume  cs:_TEXT,ds:DGROUP,ss:_STACK
  6200.  
  6201.  
  6202.  stk_seg dw      ?                       ; original SS contents
  6203.  stk_ptr dw      ?                       ; original SP contents
  6204.  
  6205.  
  6206.  main    proc    far                     ; entry point from MS-DOS
  6207.  
  6208.          mov     ax,DGROUP               ; set DS = our data segment
  6209.          mov     ds,ax
  6210.  
  6211.                                          ; now give back extra memory so
  6212.                                          ; child SORT has somewhere to run...
  6213.          mov     ax,es                   ; let AX = segment of PSP base
  6214.          mov     bx,ss                   ; and BX = segment of stack base
  6215.          sub     bx,ax                   ; reserve seg stack - seg psp
  6216.          add     bx,stksize/16           ; plus paragraphs of stack
  6217.          mov     ah,4ah                  ; fxn 4AH = modify memory block
  6218.          int     21h                     ; transfer to MS-DOS
  6219.          jerr    main1                   ; jump if resize block failed
  6220.  
  6221.                                          ; prepare stdin and stdout
  6222.                                          ; handles for child SORT process
  6223.  
  6224.          mov     bx,stdin                ; dup the handle for stdin
  6225.          mov     ah,45h
  6226.          int     21h                     ; transfer to MS-DOS
  6227.          jerr    main1                   ; jump if dup failed
  6228.          mov     oldin,ax                ; save dup'd handle
  6229.  
  6230.          mov     dx,offset DGROUP:infile ; now open the input file
  6231.          mov     ax,3d00h                ; mode = read-only
  6232.          int     21h                     ; transfer to MS-DOS
  6233.          jerr    main1                   ; jump if open failed
  6234.  
  6235.          mov     bx,ax                   ; force stdin handle to
  6236.          mov     cx,stdin                ; track the input file handle
  6237.          mov     ah,46h
  6238.          int     21h                     ; transfer to MS-DOS
  6239.          jerr    main1                   ; jump if force dup failed
  6240.  
  6241.          mov     bx,stdout               ; dup the handle for stdout
  6242.          mov     ah,45h
  6243.          int     21h                     ; transfer to MS-DOS
  6244.          jerr    main1                   ; jump if dup failed
  6245.          mov     oldout,ax               ; save dup'd handle
  6246.  
  6247.          mov     dx,offset dGROUP:outfile ; now create the output file
  6248.          mov     cx,0                    ; normal attribute
  6249.          mov     ah,3ch
  6250.          int     21h                     ; transfer to MS-DOS
  6251.          jerr    main1                   ; jump if create failed
  6252.  
  6253.          mov     bx,ax                   ; force stdout handle to
  6254.          mov     cx,stdout               ; track the output file handle
  6255.          mov     ah,46h
  6256.          int     21h                     ; transfer to MS-DOS
  6257.          jerr    main1                   ; jump if force dup failed
  6258.  
  6259.                                          ; now EXEC the child SORT,
  6260.                                          ; which will inherit redirected
  6261.                                          ; stdin and stdout handles
  6262.  
  6263.          push    ds                      ; save EXECSORT's data segment
  6264.          mov     stk_seg,ss              ; save EXECSORT's stack pointer
  6265.          mov     stk_ptr,sp
  6266.  
  6267.          mov     ax,ds                   ; set ES = DS
  6268.          mov     es,ax
  6269.          mov     dx,offset DGROUP:cname  ; DS:DX = child pathname
  6270.          mov     bx,offset DGROUP:pars   ; EX:BX = parameter block
  6271.          mov     ax,4b00h                ; function 4BH, subfunction 00H
  6272.          int     21h                     ; transfer to MS-DOS
  6273.  
  6274.          cli                             ; (for bug in some early 8088s)
  6275.          mov     ss,stk_seg              ; restore execsort's stack pointer
  6276.          mov     sp,stk_ptr
  6277.          sti                             ; (for bug in some early 8088s)
  6278.          pop     ds                      ; restore DS = our data segment
  6279.  
  6280.          jerr    main1                   ; jump if EXEC failed
  6281.  
  6282.          mov     bx,oldin                ; restore original meaning of
  6283.          mov     cx,stdin                ; standard input handle for
  6284.          mov     ah,46h                  ; this process
  6285.          int     21h
  6286.          jerr    main1                   ; jump if force dup failed
  6287.  
  6288.          mov     bx,oldout               ; restore original meaning
  6289.          mov     cx,stdout               ; of standard output handle
  6290.          mov     ah,46h                  ; for this process
  6291.          int     21h
  6292.          jerr    main1                   ; jump if force dup failed
  6293.  
  6294.          mov     bx,oldin                ; close dup'd handle of
  6295.          mov     ah,3eh                  ; original stdin
  6296.          int     21h                     ; transfer to MS-DOS
  6297.          jerr    main1                   ; jump if close failed
  6298.  
  6299.          mov     bx,oldout               ; close dup'd handle of
  6300.          mov     ah,3eh                  ; original stdout
  6301.          int     21h                     ; transfer to MS-DOS
  6302.          jerr    main1                   ; jump if close failed
  6303.  
  6304.                                          ; display success message
  6305.          mov     dx,offset DGROUP:msg1   ; address of message
  6306.          mov     cx,msg1_len             ; message length
  6307.          mov     bx,stdout               ; handle for standard output
  6308.          mov     ah,40h                  ; fxn 40H = write file or device
  6309.          int     21h                     ; transfer to MS-DOS
  6310.          jerr    main1
  6311.  
  6312.          mov     ax,4c00h                ; no error, terminate program
  6313.          int     21h                     ; with return code = 0
  6314.  
  6315.  main1:  mov     ax,4c01h                ; error, terminate program
  6316.          int     21h                     ; with return code = 1
  6317.  
  6318.  main    endp                            ; end of main procedure
  6319.  
  6320.  _TEXT   ends
  6321.  
  6322.  
  6323.  _DATA   segment para public 'DATA'      ; static & variable data segment
  6324.  
  6325.  infile  db      'MYFILE.DAT',0          ; input file for SORT filter
  6326.  outfile db      'MYFILE.SRT',0          ; output file for SORT filter
  6327.  
  6328.  oldin   dw      ?                       ; dup of old stdin handle
  6329.  oldout  dw      ?                       ; dup of old stdout handle
  6330.  
  6331.  cname   db      'SORT.EXE',0            ; pathname of child SORT process
  6332.  
  6333.  pars    dw      0                       ; segment of environment block
  6334.                                          ; (0 = inherit parent's)
  6335.          dd      tail                    ; long address, command tail
  6336.          dd      -1                      ; long address, default FCB #1
  6337.                                          ; (-1 = none supplied)
  6338.          dd      -1                      ; long address, default FCB #2
  6339.                                          ; (-1 = none supplied)
  6340.  
  6341.  tail    db      0,cr                    ; empty command tail for child
  6342.  
  6343.  msg1    db      cr,lf,'SORT was executed as child.',cr,lf
  6344.  msg1_len equ    $-msg1
  6345.  
  6346.  _DATA   ends
  6347.  
  6348.  
  6349.  _STACK  segment para stack 'STACK'
  6350.  
  6351.          db      stksize dup (?)
  6352.  
  6353.  _STACK  ends
  6354.  
  6355.  
  6356.          end     main                    ; defines program entry point
  6357.  
  6358.  \SAMPCODE\DOS_ENCY\14\LC.ASM
  6359.  
  6360.          name    lc
  6361.          title   'LC.ASM --- lowercase filter'
  6362.  ;
  6363.  ; LC.ASM:       a simple character-oriented filter to translate
  6364.  ;               all uppercase {A-Z} to lowercase {a-z}.
  6365.  ;
  6366.  ; Ray Duncan, June 1987
  6367.  ;
  6368.  
  6369.  stdin   equ     0               ; standard input
  6370.  stdout  equ     1               ; standard output
  6371.  stderr  equ     2               ; standard error
  6372.  
  6373.  cr      equ     0dh             ; ASCII carriage return
  6374.  lf      equ     0ah             ; ASCII linefeed
  6375.  
  6376.  
  6377.  DGROUP  group   _DATA,STACK     ; 'automatic data group'
  6378.  
  6379.  
  6380.  _TEXT   segment byte public 'CODE'
  6381.  
  6382.          assume  cs:_TEXT,ds:DGROUP,ss:STACK
  6383.  
  6384.  main    proc    far             ; entry point from MS-DOS
  6385.  
  6386.          mov     ax,DGROUP       ; set DS = our data segment
  6387.          mov     ds,ax
  6388.  
  6389.  main1:                          ; read a character from standard input
  6390.          mov     dx,offset DGROUP:char   ; address to place character
  6391.          mov     cx,1            ; length to read = 1
  6392.          mov     bx,stdin        ; handle for standard input
  6393.          mov     ah,3fh          ; function 3FH = read from file or device
  6394.          int     21h             ; transfer to MS-DOS
  6395.          jc      main3           ; error, terminate
  6396.          cmp     ax,1            ; any character read?
  6397.          jne     main2           ; end of file, terminate program
  6398.  
  6399.          call    translt         ; translate character if necessary
  6400.  
  6401.                                  ; now write character to standard output
  6402.          mov     dx,offset DGROUP:char   ; address of character
  6403.          mov     cx,1            ; length to write = 1
  6404.          mov     bx,stdout       ; handle for standard output
  6405.          mov     ah,40h          ; function 40H = write to file or device
  6406.          int     21h             ; transfer to MS-DOS
  6407.          jc      main3           ; error, terminate
  6408.          cmp     ax,1            ; was character written?
  6409.          jne     main3           ; disk full, terminate program
  6410.          jmp     main1           ; go process another character
  6411.  
  6412.  main2:  mov     ax,4c00h        ; end of file reached, terminate
  6413.          int     21h             ; program with return code = 0
  6414.  
  6415.  main3:  mov     ax,4c01h        ; error or disk full, terminate
  6416.          int     21h             ; program with return code = 1
  6417.  
  6418.  main    endp                    ; end of main procedure
  6419.  
  6420.  ;
  6421.  ; Translate uppercase {A-Z} characters to corresponding
  6422.  ; lowercase characters {a-z}.  Leave other characters unchanged.
  6423.  ;
  6424.  translt proc    near
  6425.  
  6426.          cmp     byte ptr char,'A'
  6427.          jb      transx
  6428.          cmp     byte ptr char,'Z'
  6429.          ja      transx
  6430.          add     byte ptr char,'a'-'A'
  6431.  transx: ret
  6432.  
  6433.  translt endp
  6434.  
  6435.  
  6436.  _TEXT   ends
  6437.  
  6438.  
  6439.  _DATA   segment word public 'DATA'
  6440.  
  6441.  char    db      0               ; temporary storage for input character
  6442.  
  6443.  _DATA   ends
  6444.  
  6445.  
  6446.  STACK   segment para stack 'STACK'
  6447.  
  6448.          dw      64 dup (?)
  6449.  
  6450.  STACK   ends
  6451.  
  6452.  
  6453.          end     main            ; defines program entry point
  6454.  
  6455.  \SAMPCODE\DOS_ENCY\14\PROTOC.ASM
  6456.  
  6457.          name    protoc
  6458.          title   'PROTOC.ASM --- template character filter'
  6459.  ;
  6460.  ; PROTOC.ASM: a template for a character-oriented filter.
  6461.  ;
  6462.  ; Ray Duncan, June 1987
  6463.  ;
  6464.  
  6465.  stdin   equ     0               ; standard input
  6466.  stdout  equ     1               ; standard output
  6467.  stderr  equ     2               ; standard error
  6468.  
  6469.  cr      equ     0dh             ; ASCII carriage return
  6470.  lf      equ     0ah             ; ASCII linefeed
  6471.  
  6472.  
  6473.  DGROUP  group   _DATA,STACK     ; 'automatic data group'
  6474.  
  6475.  
  6476.  _TEXT   segment byte public 'CODE'
  6477.  
  6478.          assume  cs:_TEXT,ds:DGROUP,ss:STACK
  6479.  
  6480.  main    proc    far             ; entry point from MS-DOS
  6481.  
  6482.          mov     ax,DGROUP       ; set DS = our data segment
  6483.          mov     ds,ax
  6484.  
  6485.  main1:                          ; read a character from standard input
  6486.          mov     dx,offset DGROUP:char   ; address to place character
  6487.          mov     cx,1            ; length to read = 1
  6488.          mov     bx,stdin        ; handle for standard input
  6489.          mov     ah,3fh          ; function 3FH = read from file or device
  6490.          int     21h             ; transfer to MS-DOS
  6491.          jc      main3           ; error, terminate
  6492.          cmp     ax,1            ; any character read?
  6493.          jne     main2           ; end of file, terminate program
  6494.  
  6495.          call    translt         ; translate character if necessary
  6496.  
  6497.                                  ; now write character to standard output
  6498.          mov     dx,offset DGROUP:char   ; address of character
  6499.          mov     cx,1            ; length to write = 1
  6500.          mov     bx,stdout       ; handle for standard output
  6501.          mov     ah,40h          ; function 40H = write to file or device
  6502.          int     21h             ; transfer to MS-DOS
  6503.          jc      main3           ; error, terminate
  6504.          cmp     ax,1            ; was character written?
  6505.          jne     main3           ; disk full, terminate program
  6506.          jmp     main1           ; go process another character
  6507.  
  6508.  main2:  mov     ax,4c00h        ; end of file reached, terminate
  6509.          int     21h             ; program with return code = 0
  6510.  
  6511.  main3:  mov     ax,4c01h        ; error or disk full, terminate
  6512.          int     21h             ; program with return code = 1
  6513.  
  6514.  main    endp                    ; end of main procedure
  6515.  
  6516.  ;
  6517.  ; Perform any necessary translation on character from input,
  6518.  ; stored in 'char'.  Template action: leave character unchanged.
  6519.  ;
  6520.  translt proc    near
  6521.  
  6522.          ret                     ; template action: do nothing
  6523.  
  6524.  translt endp
  6525.  
  6526.  
  6527.  _TEXT   ends
  6528.  
  6529.  
  6530.  _DATA   segment word public 'DATA'
  6531.  
  6532.  char    db      0               ; temporary storage for input character
  6533.  
  6534.  _DATA   ends
  6535.  
  6536.  
  6537.  STACK   segment para stack 'STACK'
  6538.  
  6539.          dw      64 dup (?)
  6540.  
  6541.  STACK   ends
  6542.  
  6543.  
  6544.          end     main            ; defines program entry point
  6545.  
  6546.  \SAMPCODE\DOS_ENCY\14\PROTOL.ASM
  6547.  
  6548.          name    protol
  6549.          title   'PROTOL.ASM --- template line filter'
  6550.  ;
  6551.  ; PROTOL.ASM:  a template for a line-oriented filter.
  6552.  ;
  6553.  ; Ray Duncan, June 1987
  6554.  ;
  6555.  
  6556.  stdin   equ     0               ; standard input
  6557.  stdout  equ     1               ; standard output
  6558.  stderr  equ     2               ; standard error
  6559.  
  6560.  cr      equ     0dh             ; ASCII carriage return
  6561.  lf      equ     0ah             ; ASCII linefeed
  6562.  
  6563.  
  6564.  DGROUP  group   _DATA,STACK     ; 'automatic data group'
  6565.  
  6566.  
  6567.  _TEXT   segment byte public 'CODE'
  6568.  
  6569.          assume  cs:_TEXT,ds:DGROUP,es:DGROUP,ss:STACK
  6570.  
  6571.  main    proc    far             ; entry point from MS-DOS
  6572.  
  6573.          mov     ax,DGROUP       ; set DS = ES = our data segment
  6574.          mov     ds,ax
  6575.          mov     es,ax
  6576.  
  6577.  main1:                          ; read a line from standard input
  6578.          mov     dx,offset DGROUP:input  ; address to place data
  6579.          mov     cx,256          ; max length to read = 256
  6580.          mov     bx,stdin        ; handle for standard input
  6581.          mov     ah,3fh          ; function 3FH = read from file or device
  6582.          int     21h             ; transfer to MS-DOS
  6583.          jc      main3           ; if error, terminate
  6584.          or      ax,ax           ; any characters read?
  6585.          jz      main2           ; end of file, terminate program
  6586.  
  6587.          call    translt         ; translate line if necessary
  6588.          or      ax,ax           ; anything to output after translation?
  6589.          jz      main1           ; no, get next line
  6590.  
  6591.                                  ; now write line to standard output
  6592.          mov     dx,offset DGROUP:output ; address of data
  6593.          mov     cx,ax           ; length to write
  6594.          mov     bx,stdout       ; handle for standard output
  6595.          mov     ah,40h          ; function 40H = write to file or device
  6596.          int     21h             ; transfer to MS-DOS
  6597.          jc      main3           ; if error, terminate
  6598.          cmp     ax,cx           ; was entire line written?
  6599.          jne     main3           ; disk full, terminate program
  6600.          jmp     main1           ; go process another line
  6601.  
  6602.  main2:  mov     ax,4c00h        ; end of file reached, terminate
  6603.          int     21h             ; program with return code = 0
  6604.  
  6605.  main3:  mov     ax,4c01h        ; error or disk full, terminate
  6606.          int     21h             ; program with return code = 1
  6607.  
  6608.  main    endp                    ; end of main procedure
  6609.  
  6610.  ;
  6611.  ; Perform any necessary translation on line stored in
  6612.  ; 'input' buffer, leaving result in 'output' buffer.
  6613.  ;
  6614.  ; Call with:    AX = length of data in 'input' buffer.
  6615.  ;
  6616.  ; Return:       AX = length to write to standard output.
  6617.  ;
  6618.  ; Action of template routine is just to copy the line.
  6619.  ;
  6620.  translt proc    near
  6621.  
  6622.                                  ; just copy line from input to output
  6623.          mov     si,offset DGROUP:input
  6624.          mov     di,offset DGROUP:output
  6625.          mov     cx,ax
  6626.          rep movsb
  6627.          ret                     ; return length in AX unchanged
  6628.  
  6629.  translt endp
  6630.  
  6631.  
  6632.  _TEXT   ends
  6633.  
  6634.  
  6635.  _DATA   segment word public 'DATA'
  6636.  
  6637.  input   db      256 dup (?)     ; storage for input line
  6638.  output  db      256 dup (?)     ; storage for output line
  6639.  
  6640.  _DATA   ends
  6641.  
  6642.  
  6643.  STACK   segment para stack 'STACK'
  6644.  
  6645.          dw      64 dup (?)
  6646.  
  6647.  STACK   ends
  6648.  
  6649.  
  6650.          end     main            ; defines program entry point
  6651.  
  6652.  \SAMPCODE\DOS_ENCY\15
  6653.  \SAMPCODE\DOS_ENCY\15\TEMPLATE.ASM
  6654.  
  6655.          name    template
  6656.          title   'TEMPLATE --- installable driver template'
  6657.  
  6658.  ;
  6659.  ; TEMPLATE.ASM:  A program skeleton for an installable
  6660.  ;                device driver (MS-DOS 2.0 or later)
  6661.  ;
  6662.  ; The driver command-code routines are stubs only and have
  6663.  ; no effect but to return a nonerror "Done" status.
  6664.  ;
  6665.  ; Ray Duncan, July 1987
  6666.  ;
  6667.  
  6668.  _TEXT   segment byte public 'CODE'
  6669.  
  6670.          assume  cs:_TEXT,ds:_TEXT,es:NOTHING
  6671.  
  6672.          org     0
  6673.  
  6674.  MaxCmd  equ     24              ; maximum allowed command code
  6675.                                  ; 12 for MS-DOS 2.x
  6676.                                  ; 16 for MS-DOS 3.0-3.1
  6677.                                  ; 24 for MS-DOS 3.2-3.3
  6678.  
  6679.  cr      equ     0dh             ; ASCII carriage return
  6680.  lf      equ     0ah             ; ASCII linefeed
  6681.  eom     equ     '$'             ; end-of-message signal
  6682.  
  6683.  
  6684.  Header:                         ; device driver header
  6685.          dd      -1              ; link to next device driver
  6686.          dw      c840h           ; device attribute word
  6687.          dw      Strat           ; "Strategy" routine entry point
  6688.          dw      Intr            ; "Interrupt" routine entry point
  6689.          db      'TEMPLATE'      ; logical device name
  6690.  
  6691.  
  6692.  RHPtr   dd      ?               ; pointer to request header, passed
  6693.                                  ; by MS-DOS kernel to Strategy routine
  6694.  
  6695.  
  6696.  Dispatch:                       ; Interrupt routine command code
  6697.                                  ; dispatch table
  6698.          dw      Init            ; 0  = initialize driver
  6699.          dw      MediaChk        ; 1  = media check on block device
  6700.          dw      BuildBPB        ; 2  = build BIOS parameter block
  6701.          dw      IoctlRd         ; 3  = I/O control read
  6702.          dw      Read            ; 4  = read (input) from device
  6703.          dw      NdRead          ; 5  = nondestructive read
  6704.          dw      InpStat         ; 6  = return current input status
  6705.          dw      InpFlush        ; 7  = flush device input buffers
  6706.          dw      Write           ; 8  = write (output) to device
  6707.          dw      WriteVfy        ; 9  = write with verify
  6708.          dw      OutStat         ; 10 = return current output status
  6709.          dw      OutFlush        ; 11 = flush output buffers
  6710.          dw      IoctlWt         ; 12 = I/O control write
  6711.          dw      DevOpen         ; 13 = device open       (MS-DOS 3.0+)
  6712.          dw      DevClose        ; 14 = device close      (MS-DOS 3.0+)
  6713.          dw      RemMedia        ; 15 = removable media   (MS-DOS 3.0+)
  6714.          dw      OutBusy         ; 16 = output until busy (MS-DOS 3.0+)
  6715.          dw      Error           ; 17 = not used
  6716.          dw      Error           ; 18 = not used
  6717.          dw      GenIOCTL        ; 19 = generic IOCTL     (MS-DOS 3.2+)
  6718.          dw      Error           ; 20 = not used
  6719.          dw      Error           ; 21 = not used
  6720.          dw      Error           ; 22 = not used
  6721.          dw      GetLogDev       ; 23 = get logical device (MS-DOS 3.2+)
  6722.          dw      SetLogDev       ; 24 = set logical device (MS-DOS 3.2+)
  6723.  
  6724.  
  6725.  Strat   proc    far             ; device driver Strategy routine,
  6726.                                  ; called by MS-DOS kernel with
  6727.                                  ; ES:BX = address of request header
  6728.  
  6729.                                  ; save pointer to request header
  6730.          mov     word ptr cs:[RHPtr],bx
  6731.          mov     word ptr cs:[RHPtr+2],es
  6732.  
  6733.          ret                     ; back to MS-DOS kernel
  6734.  
  6735.  Strat   endp
  6736.  
  6737.  
  6738.  Intr    proc    far             ; device driver Interrupt routine,
  6739.                                  ; called by MS-DOS kernel immediately
  6740.                                  ; after call to Strategy routine
  6741.  
  6742.          push    ax              ; save general registers
  6743.          push    bx
  6744.          push    cx
  6745.          push    dx
  6746.          push    ds
  6747.          push    es
  6748.          push    di
  6749.          push    si
  6750.          push    bp
  6751.  
  6752.          push    cs              ; make local data addressable
  6753.          pop     ds              ; by setting DS = CS
  6754.  
  6755.          les     di,[RHPtr]      ; let ES:DI = request header
  6756.  
  6757.                                  ; get BX = command code
  6758.          mov     bl,es:[di+2]
  6759.          xor     bh,bh
  6760.          cmp     bx,MaxCmd       ; make sure it's valid
  6761.          jle     Intr1           ; jump, function code is ok
  6762.          call    Error           ; set error bit, "Unknown Command" code
  6763.          jmp     Intr2
  6764.  
  6765.  Intr1:  shl     bx,1            ; form index to dispatch table
  6766.                                  ; and branch to command-code routine
  6767.          call    word ptr [bx+Dispatch]
  6768.  
  6769.          les     di,[RHPtr]      ; ES:DI = address of request header
  6770.  
  6771.  Intr2:  or      ax,0100h        ; merge Done bit into status and
  6772.          mov     es:[di+3],ax    ; store status into request header
  6773.  
  6774.          pop     bp              ; restore general registers
  6775.          pop     si
  6776.          pop     di
  6777.          pop     es
  6778.          pop     ds
  6779.          pop     dx
  6780.          pop     cx
  6781.          pop     bx
  6782.          pop     ax
  6783.          ret                     ; return to MS-DOS kernel
  6784.  
  6785.  
  6786.  ; Command-code routines are called by the Interrupt routine
  6787.  ; via the dispatch table with ES:DI pointing to the request
  6788.  ; header. Each routine should return AX = 00H if function was
  6789.  ; completed successfully or AX = 8000H + error code if
  6790.  ; function failed.
  6791.  
  6792.  
  6793.  MediaChk proc   near            ; function 1 = Media Check
  6794.  
  6795.          xor     ax,ax
  6796.          ret
  6797.  
  6798.  MediaChk endp
  6799.  
  6800.  
  6801.  BuildBPB proc   near            ; function 2 = Build BPB
  6802.  
  6803.          xor     ax,ax
  6804.          ret
  6805.  
  6806.  BuildBPB endp
  6807.  
  6808.  
  6809.  IoctlRd proc    near            ; function 3 = I/O Control Read
  6810.  
  6811.          xor     ax,ax
  6812.          ret
  6813.  
  6814.  IoctlRd endp
  6815.  
  6816.  
  6817.  Read    proc    near            ; function 4 = Read (Input)
  6818.  
  6819.          xor     ax,ax
  6820.          ret
  6821.  
  6822.  Read    endp
  6823.  
  6824.  
  6825.  NdRead  proc    near            ; function 5 = Nondestructive Read
  6826.  
  6827.          xor     ax,ax
  6828.          ret
  6829.  
  6830.  NdRead  endp
  6831.  
  6832.  
  6833.  InpStat proc    near            ; function 6 = Input Status
  6834.  
  6835.          xor     ax,ax
  6836.          ret
  6837.  
  6838.  InpStat endp
  6839.  
  6840.  
  6841.  InpFlush proc   near            ; function 7 = Flush Input Buffers
  6842.  
  6843.          xor     ax,ax
  6844.          ret
  6845.  
  6846.  InpFlush endp
  6847.  
  6848.  
  6849.  Write   proc    near            ; function 8 = Write (Output)
  6850.  
  6851.          xor     ax,ax
  6852.          ret
  6853.  
  6854.  Write   endp
  6855.  
  6856.  
  6857.  WriteVfy proc   near            ; function 9 = Write with Verify
  6858.  
  6859.          xor     ax,ax
  6860.          ret
  6861.  
  6862.  WriteVfy endp
  6863.  
  6864.  
  6865.  OutStat proc    near            ; function 10 = Output Status
  6866.  
  6867.          xor     ax,ax
  6868.          ret
  6869.  
  6870.  OutStat endp
  6871.  
  6872.  
  6873.  OutFlush proc   near            ; function 11 = Flush Output Buffers
  6874.  
  6875.          xor     ax,ax
  6876.          ret
  6877.  
  6878.  OutFlush endp
  6879.  
  6880.  
  6881.  IoctlWt proc    near            ; function 12 = I/O Control Write
  6882.  
  6883.          xor     ax,ax
  6884.          ret
  6885.  
  6886.  IoctlWt endp
  6887.  
  6888.  
  6889.  DevOpen proc    near            ; function 13 = Device Open
  6890.  
  6891.          xor     ax,ax
  6892.          ret
  6893.  
  6894.  DevOpen endp
  6895.  
  6896.  
  6897.  DevClose proc   near            ; function 14 = Device Close
  6898.  
  6899.          xor     ax,ax
  6900.          ret
  6901.  
  6902.  DevClose endp
  6903.  
  6904.  
  6905.  RemMedia proc   near            ; function 15 = Removable Media
  6906.  
  6907.          xor     ax,ax
  6908.          ret
  6909.  
  6910.  RemMedia endp
  6911.  
  6912.  
  6913.  OutBusy proc    near            ; function 16 = Output Until Busy
  6914.  
  6915.          xor     ax,ax
  6916.          ret
  6917.  
  6918.  OutBusy endp
  6919.  
  6920.  
  6921.  GenIOCTL proc   near            ; function 19 = Generic IOCTL
  6922.  
  6923.          xor     ax,ax
  6924.          ret
  6925.  
  6926.  GenIOCTL endp
  6927.  
  6928.  
  6929.  GetLogDev proc  near            ; function 23 = Get Logical Device
  6930.  
  6931.          xor     ax,ax
  6932.          ret
  6933.  
  6934.  GetLogDev endp
  6935.  
  6936.  
  6937.  SetLogDev proc  near            ; function 24 = Set Logical Device
  6938.  
  6939.          xor     ax,ax
  6940.          ret
  6941.  
  6942.  SetLogDev endp
  6943.  
  6944.  
  6945.  Error   proc    near            ; bad command code in request header
  6946.  
  6947.          mov     ax,8003h        ; error bit + "Unknown Command" code
  6948.          ret
  6949.  
  6950.  Error   endp
  6951.  
  6952.  
  6953.  Init    proc    near            ; function 0 = initialize driver
  6954.  
  6955.          push    es              ; save address of request header
  6956.          push    di
  6957.  
  6958.          mov     ah,9            ; display driver sign-on message
  6959.          mov     dx,offset Ident
  6960.          int     21h
  6961.  
  6962.          pop     di              ; restore request header address
  6963.          pop     es
  6964.  
  6965.                                  ; set address of free memory
  6966.                                  ; above driver (break address)
  6967.          mov     word ptr es:[di+14],offset Init
  6968.          mov     word ptr es:[di+16],cs
  6969.  
  6970.          xor     ax,ax           ; return status
  6971.          ret
  6972.  
  6973.  Init    endp
  6974.  
  6975.  Ident   db      cr,lf,lf
  6976.          db      'TEMPLATE Example Device Driver'
  6977.          db      cr,lf,eom
  6978.  
  6979.  Intr    endp
  6980.  
  6981.  _TEXT   ends
  6982.  
  6983.          end
  6984.  
  6985.  \SAMPCODE\DOS_ENCY\15\TINYDISK.ASM
  6986.  
  6987.          name    tinydisk
  6988.          title   TINYDISK example block-device driver
  6989.  
  6990.  ; TINYDISK.ASM --- 64 KB RAMdisk
  6991.  ;
  6992.  ; Ray Duncan, July 1987
  6993.  ; Example of a simple installable block-device driver.
  6994.  
  6995.  _TEXT   segment public 'CODE'
  6996.  
  6997.          assume  cs:_TEXT,ds:_TEXT,es:_TEXT
  6998.  
  6999.          org     0
  7000.  
  7001.  MaxCmd  equ     12              ; max driver command code
  7002.                                  ; (no MS-DOS 3.x functions)
  7003.  
  7004.  cr      equ     0dh             ; ASCII carriage return
  7005.  lf      equ     0ah             ; ASCII linefeed
  7006.  blank   equ     020h            ; ASCII space code
  7007.  eom     equ     '$'             ; end-of-message signal
  7008.  
  7009.  Secsize equ     512             ; bytes/sector, IBM-compatible media
  7010.  
  7011.                                  ; device-driver header
  7012.  Header  dd      -1              ; link to next driver in chain
  7013.          dw      0               ; device attribute word
  7014.          dw      Strat           ; "Strategy" routine entry point
  7015.          dw      Intr            ; "Interrupt" routine entry point
  7016.          db      1               ; number of units, this device
  7017.          db      7 dup (0)       ; reserved area (block-device drivers)
  7018.  
  7019.  RHPtr   dd      ?               ; segment:offset of request header
  7020.  
  7021.  Secseg  dw      ?               ; segment base of sector storage
  7022.  
  7023.  Xfrsec  dw      0               ; current sector for transfer
  7024.  Xfrcnt  dw      0               ; sectors successfully transferred
  7025.  Xfrreq  dw      0               ; number of sectors requested
  7026.  Xfraddr dd      0               ; working address for transfer
  7027.  
  7028.  Array   dw      BPB             ; array of pointers to BPB
  7029.                                  ; for each supported unit
  7030.  
  7031.  
  7032.  Bootrec equ     $
  7033.  
  7034.          jmp     $               ; phony JMP at start of
  7035.          nop                     ; boot sector; this field
  7036.                                  ; must be 3 bytes
  7037.  
  7038.          db      'MS   2.0'      ; OEM identity field
  7039.  
  7040.                                  ; BIOS Parameter Block (BPB)
  7041.  BPB     dw      Secsize         ; 00H - bytes per sector
  7042.          db      1               ; 02H - sectors per cluster
  7043.          dw      1               ; 03H - reserved sectors
  7044.          db      1               ; 05H - number of FATs
  7045.          dw      32              ; 06H - root directory entries
  7046.          dw      128             ; 08H - sectors = 64 KB/secsize
  7047.          db      0f8h            ; 0AH - media descriptor
  7048.          dw      1               ; 0BH - sectors per FAT
  7049.  
  7050.  Bootrec_len equ $-Bootrec
  7051.  
  7052.  
  7053.  Strat   proc    far             ; RAMdisk strategy routine
  7054.  
  7055.                                  ; save address of request header
  7056.          mov     word ptr cs:RHPtr,bx
  7057.          mov     word ptr cs:[RHPtr+2],es
  7058.          ret                     ; back to MS-DOS kernel
  7059.  
  7060.  Strat   endp
  7061.  
  7062.  
  7063.  Intr    proc    far             ; RAMdisk interrupt routine
  7064.  
  7065.          push    ax              ; save general registers
  7066.          push    bx
  7067.          push    cx
  7068.          push    dx
  7069.          push    ds
  7070.          push    es
  7071.          push    di
  7072.          push    si
  7073.          push    bp
  7074.  
  7075.          mov     ax,cs           ; make local data addressable
  7076.          mov     ds,ax
  7077.  
  7078.          les     di,[RHPtr]      ; ES:DI = request header
  7079.  
  7080.          mov     bl,es:[di+2]    ; get command code
  7081.          xor     bh,bh
  7082.          cmp     bx,MaxCmd       ; make sure it's valid
  7083.          jle     Intr1           ; jump, function code is ok
  7084.          mov     ax,8003h        ; set Error bit and
  7085.          jmp     Intr3           ; "Unknown Command" error code
  7086.  
  7087.  Intr1:  shl     bx,1            ; form index to dispatch table and
  7088.                                  ; branch to command-code routine
  7089.          call    word ptr [bx+Dispatch]
  7090.                                  ; should return AX = status
  7091.  
  7092.          les     di,[RHPtr]      ; restore ES:DI = request header
  7093.  
  7094.  Intr3:  or      ax,0100h        ; merge Done bit into status and store
  7095.          mov     es:[di+3],ax    ; status into request header
  7096.  
  7097.  Intr4:  pop     bp              ; restore general registers
  7098.          pop     si
  7099.          pop     di
  7100.          pop     es
  7101.          pop     ds
  7102.          pop     dx
  7103.          pop     cx
  7104.          pop     bx
  7105.          pop     ax
  7106.          ret                     ; return to MS-DOS kernel
  7107.  
  7108.  Intr    endp
  7109.  
  7110.  
  7111.  Dispatch:                       ; command-code dispatch table
  7112.                                  ; all command-code routines are
  7113.                                  ; entered with ES:DI pointing
  7114.                                  ; to request header and return
  7115.                                  ; the operation status in AX
  7116.          dw      Init            ;  0 = initialize driver
  7117.          dw      MediaChk        ;  1 = media check on block device
  7118.          dw      BuildBPB        ;  2 = build BIOS parameter block
  7119.          dw      Dummy           ;  3 = I/O control read
  7120.          dw      Read            ;  4 = read (input) from device
  7121.          dw      Dummy           ;  5 = nondestructive read
  7122.          dw      Dummy           ;  6 = return current input status
  7123.          dw      Dummy           ;  7 = flush device input buffers
  7124.          dw      Write           ;  8 = write (output) to device
  7125.          dw      Write           ;  9 = write with verify
  7126.          dw      Dummy           ; 10 = return current output status
  7127.          dw      Dummy           ; 11 = flush output buffers
  7128.          dw      Dummy           ; 12 = I/O control write
  7129.  
  7130.  
  7131.  MediaChk proc  near             ; command code 1 = Media Check
  7132.  
  7133.                                  ; return "not changed" code
  7134.          mov     byte ptr es:[di+0eh],1
  7135.          xor     ax,ax           ; and success status
  7136.          ret
  7137.  
  7138.  MediaChk endp
  7139.  
  7140.  
  7141.  BuildBPB proc  near             ; command code 2 = Build BPB
  7142.  
  7143.                                  ; put BPB address in request header
  7144.          mov     word ptr es:[di+12h],offset BPB
  7145.          mov     word ptr es:[di+14h],cs
  7146.          xor     ax,ax           ; return success status
  7147.          ret
  7148.  
  7149.  BuildBPB endp
  7150.  
  7151.  
  7152.  Read    proc    near            ; command code 4 = Read (Input)
  7153.  
  7154.          call    Setup           ; set up transfer variables
  7155.  
  7156.  Read1:  mov     ax,Xfrcnt       ; done with all sectors yet?
  7157.          cmp     ax,Xfrreq
  7158.          je      Read2           ; jump if transfer completed
  7159.          mov     ax,Xfrsec       ; get next sector number
  7160.          call    Mapsec          ; and map it
  7161.          mov     ax,es
  7162.          mov     si,di
  7163.          les     di,Xfraddr      ; ES:DI = requester's buffer
  7164.          mov     ds,ax           ; DS:SI = RAMdisk address
  7165.          mov     cx,Secsize      ; transfer logical sector from
  7166.          cld                     ; RAMdisk to requestor
  7167.          rep movsb
  7168.          push    cs              ; restore local addressing
  7169.          pop     ds
  7170.          inc     Xfrsec          ; advance sector number
  7171.                                  ; advance transfer address
  7172.          add     word ptr Xfraddr,Secsize
  7173.          inc     Xfrcnt          ; count sectors transferred
  7174.          jmp     Read1
  7175.  
  7176.  Read2:                          ; all sectors transferred
  7177.          xor     ax,ax           ; return success status
  7178.          les     di,RHPtr        ; put actual transfer count
  7179.          mov     bx,Xfrcnt       ; into request header
  7180.          mov     es:[di+12h],bx
  7181.          ret
  7182.  
  7183.  Read    endp
  7184.  
  7185.  
  7186.  Write   proc    near            ; command code 8 = Write (Output)
  7187.                                  ; command code 9 = Write with Verify
  7188.  
  7189.          call    Setup           ; set up transfer variables
  7190.  
  7191.  Write1: mov     ax,Xfrcnt       ; done with all sectors yet?
  7192.          cmp     ax,Xfrreq
  7193.          je      Write2          ; jump if transfer completed
  7194.  
  7195.          mov     ax,Xfrsec       ; get next sector number
  7196.          call    Mapsec          ; and map it
  7197.          lds     si,Xfraddr
  7198.          mov     cx,Secsize      ; transfer logical sector from
  7199.          cld                     ; requester to RAMdisk
  7200.          rep movsb
  7201.          push    cs              ; restore local addressing
  7202.          pop     ds
  7203.          inc     Xfrsec          ; advance sector number
  7204.                                  ; advance transfer address
  7205.          add     word ptr Xfraddr,Secsize
  7206.          inc     Xfrcnt          ; count sectors transferred
  7207.          jmp     Write1
  7208.  
  7209.  Write2:                         ; all sectors transferred
  7210.          xor     ax,ax           ; return success status
  7211.          les     di,RHPtr        ; put actual transfer count
  7212.          mov     bx,Xfrcnt       ; into request header
  7213.          mov     es:[di+12h],bx
  7214.          ret
  7215.  
  7216.  Write   endp
  7217.  
  7218.  
  7219.  Dummy   proc    near            ; called for unsupported functions
  7220.  
  7221.          xor     ax,ax           ; return success flag for all
  7222.          ret
  7223.  
  7224.  Dummy   endp
  7225.  
  7226.  
  7227.  Mapsec  proc    near            ; map sector number to memory address
  7228.                                  ; call with AX = logical sector no.
  7229.                                  ; return ES:DI = memory address
  7230.  
  7231.          mov     di,Secsize/16   ; paragraphs per sector
  7232.          mul     di              ; * logical sector number
  7233.          add     ax,Secseg       ; + segment base of sector storage
  7234.          mov     es,ax
  7235.          xor     di,di           ; now ES:DI points to sector
  7236.          ret
  7237.  
  7238.  Mapsec  endp
  7239.  
  7240.  
  7241.  Setup   proc    near            ; set up for read or write
  7242.                                  ; call ES:DI = request header
  7243.                                  ; extracts address, start, count
  7244.  
  7245.          push    es              ; save request header address
  7246.          push    di
  7247.          mov     ax,es:[di+14h]  ; starting sector number
  7248.          mov     Xfrsec,ax
  7249.          mov     ax,es:[di+12h]  ; sectors requested
  7250.          mov     Xfrreq,ax
  7251.          les     di,es:[di+0eh]  ; requester's buffer address
  7252.          mov     word ptr Xfraddr,di
  7253.          mov     word ptr Xfraddr+2,es
  7254.          mov     Xfrcnt,0        ; initialize sectors transferred count
  7255.          pop     di              ; restore request header address
  7256.          pop     es
  7257.          ret
  7258.  
  7259.  Setup   endp
  7260.  
  7261.  
  7262.  Init    proc    near            ; command code 0 = Initialize driver
  7263.                                  ; on entry ES:DI = request header
  7264.  
  7265.          mov     ax,cs           ; calculate segment base for sector
  7266.          add     ax,Driver_len   ; storage and save it
  7267.          mov     Secseg,ax
  7268.          add     ax,1000h        ; add 1000H paras (64 KB) and
  7269.          mov     es:[di+10h],ax  ; set address of free memory
  7270.          mov     word ptr es:[di+0eh],0
  7271.  
  7272.          call    Format          ; format the RAMdisk
  7273.  
  7274.          call    Signon          ; display driver identification
  7275.  
  7276.          les     di,cs:RHPtr     ; restore ES:DI = request header
  7277.                                  ; set logical units = 1
  7278.          mov     byte ptr es:[di+0dh],1
  7279.                                  ; set address of BPB array
  7280.          mov     word ptr es:[di+12h],offset Array
  7281.          mov     word ptr es:[di+14h],cs
  7282.  
  7283.          xor     ax,ax           ; return success status
  7284.          ret
  7285.  
  7286.  Init    endp
  7287.  
  7288.  
  7289.  Format  proc    near            ; format the RAMdisk area
  7290.  
  7291.          mov     es,Secseg       ; first zero out RAMdisk
  7292.          xor     di,di
  7293.          mov     cx,8000h        ; 32 K words = 64 KB
  7294.          xor     ax,ax
  7295.          cld
  7296.          rep stosw
  7297.  
  7298.          mov     ax,0            ; get address of logical
  7299.          call    Mapsec          ; sector zero
  7300.          mov     si,offset Bootrec
  7301.          mov     cx,Bootrec_len
  7302.          rep movsb               ; and copy boot record to it
  7303.  
  7304.          mov     ax,word ptr BPB+3
  7305.          call    Mapsec          ; get address of 1st FAT sector
  7306.          mov     al,byte ptr BPB+0ah
  7307.          mov     es:[di],al      ; put media ID byte into it
  7308.          mov     word ptr es:[di+1],-1
  7309.  
  7310.          mov     ax,word ptr BPB+3
  7311.          add     ax,word ptr BPB+0bh
  7312.          call    Mapsec          ; get address of 1st directory sector
  7313.          mov     si,offset Volname
  7314.          mov     cx,Volname_len
  7315.          rep movsb               ; copy volume label to it
  7316.  
  7317.          ret                     ; done with formatting
  7318.  
  7319.  Format  endp
  7320.  
  7321.  
  7322.  Signon  proc    near            ; driver identification message
  7323.  
  7324.          les     di,RHPtr        ; let ES:DI = request header
  7325.          mov     al,es:[di+22]   ; get drive code from header,
  7326.          add     al,'A'          ; convert it to ASCII, and
  7327.          mov     drive,al        ; store into sign-on message
  7328.  
  7329.          mov     ah,30h          ; get MS-DOS version
  7330.          int     21h
  7331.          cmp     al,2
  7332.          ja      Signon1         ; jump if version 3.0 or later
  7333.          mov     Ident1,eom      ; version 2.x, don't print drive
  7334.  
  7335.  Signon1:                        ; print sign-on message
  7336.          mov     ah,09H          ; Function 09H = print string
  7337.          mov     dx,offset Ident ; DS:DX = address of message
  7338.          int     21h             ; transfer to MS-DOS
  7339.  
  7340.          ret                     ; back to caller
  7341.  
  7342.  Signon  endp
  7343.  
  7344.  
  7345.  Ident   db      cr,lf,lf        ; driver sign-on message
  7346.          db      'TINYDISK 64 KB RAMdisk'
  7347.          db      cr,lf
  7348.  Ident1  db      'RAMdisk will be drive '
  7349.  Drive   db      'X:'
  7350.          db      cr,lf,eom
  7351.  
  7352.  
  7353.  Volname db      'DOSREF_DISK'   ; volume label for RAMdisk
  7354.          db      08h             ; attribute byte
  7355.          db      10 dup (0)      ; reserved area
  7356.          dw      0               ; time = 00:00
  7357.          dw      0f01h           ; date = August 1, 1987
  7358.          db      6 dup (0)       ; reserved area
  7359.  
  7360.  Volname_len equ $-volname
  7361.  
  7362.  Driver_len dw (($-header)/16)+1 ; driver size in paragraphs
  7363.  
  7364.  _TEXT   ends
  7365.  
  7366.          end
  7367.  
  7368.  \SAMPCODE\DOS_ENCY\17
  7369.  \SAMPCODE\DOS_ENCY\17\SAMPLE.C
  7370.  
  7371.  /* SAMPLE.C -- Demonstration Windows Program */
  7372.  
  7373.  #include <windows.h>
  7374.  #include "sample.h"
  7375.  
  7376.  long FAR PASCAL WndProc (HWND, unsigned, WORD, LONG) ;
  7377.  
  7378.  int PASCAL WinMain (hInstance, hPrevInstance, lpszCmdLine, nCmdShow)
  7379.       HANDLE      hInstance, hPrevInstance ;
  7380.       LPSTR       lpszCmdLine ;
  7381.       int         nCmdShow ;
  7382.       {
  7383.       WNDCLASS    wndclass ;
  7384.       HWND        hWnd ;
  7385.       MSG         msg ;
  7386.       static char szAppName [] = "Sample" ;
  7387.  
  7388.                 /*---------------------------*/
  7389.                 /* Register the Window Class */
  7390.                 /*---------------------------*/
  7391.  
  7392.       if (!hPrevInstance)
  7393.            {
  7394.            wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
  7395.            wndclass.lpfnWndProc   = WndProc ;
  7396.            wndclass.cbClsExtra    = 0 ;
  7397.            wndclass.cbWndExtra    = 0 ;
  7398.            wndclass.hInstance     = hInstance ;
  7399.            wndclass.hIcon         = NULL ;
  7400.            wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
  7401.            wndclass.hbrBackground = GetStockObject (WHITE_BRUSH) ;
  7402.            wndclass.lpszMenuName  = szAppName ;
  7403.            wndclass.lpszClassName = szAppName ;
  7404.  
  7405.            RegisterClass (&wndclass) ;
  7406.            }
  7407.  
  7408.                 /*----------------------------------*/
  7409.                 /* Create the window and display it */
  7410.                 /*----------------------------------*/
  7411.  
  7412.       hWnd = CreateWindow (szAppName, "Demonstration Windows Program",
  7413.                            WS_OVERLAPPEDWINDOW,
  7414.                            (int) CW_USEDEFAULT, 0,
  7415.                            (int) CW_USEDEFAULT, 0,
  7416.                            NULL, NULL, hInstance, NULL) ;
  7417.  
  7418.       ShowWindow (hWnd, nCmdShow) ;
  7419.       UpdateWindow (hWnd) ;
  7420.  
  7421.                  /*----------------------------------------------*/
  7422.                  /* Stay in message loop until a WM_QUIT message */
  7423.                  /*----------------------------------------------*/
  7424.  
  7425.       while (GetMessage (&msg, NULL, 0, 0))
  7426.            {
  7427.            TranslateMessage (&msg) ;
  7428.            DispatchMessage (&msg) ;
  7429.            }
  7430.       return msg.wParam ;
  7431.       }
  7432.  
  7433.  long FAR PASCAL WndProc (hWnd, iMessage, wParam, lParam)
  7434.       HWND         hWnd ;
  7435.       unsigned     iMessage ;
  7436.       WORD         wParam ;
  7437.       LONG         lParam ;
  7438.       {
  7439.       PAINTSTRUCT  ps ;
  7440.       HFONT        hFont ;
  7441.       HMENU        hMenu ;
  7442.       static short xClient, yClient, nCurrentFont = IDM_SCRIPT ;
  7443.       static BYTE  cFamily [] = { FF_SCRIPT, FF_MODERN, FF_ROMAN } ;
  7444.       static char  *szFace [] = { "Script",  "Modern",  "Roman"  } ;
  7445.  
  7446.       switch (iMessage)
  7447.            {
  7448.  
  7449.                      /*---------------------------------------------*/
  7450.                      /* WM_COMMAND message: Change checkmarked font */
  7451.                      /*---------------------------------------------*/
  7452.  
  7453.            case WM_COMMAND:
  7454.                 hMenu = GetMenu (hWnd) ;
  7455.                 CheckMenuItem (hMenu, nCurrentFont, MF_UNCHECKED) ;
  7456.                 nCurrentFont = wParam ;
  7457.                 CheckMenuItem (hMenu, nCurrentFont, MF_CHECKED) ;
  7458.                 InvalidateRect (hWnd, NULL, TRUE) ;
  7459.                 break ;
  7460.  
  7461.                      /*--------------------------------------------*/
  7462.                      /* WM_SIZE message: Save dimensions of window */
  7463.                      /*--------------------------------------------*/
  7464.  
  7465.            case WM_SIZE:
  7466.                 xClient = LOWORD (lParam) ;
  7467.                 yClient = HIWORD (lParam) ;
  7468.                 break ;
  7469.  
  7470.                      /*-----------------------------------------------*/
  7471.                      /* WM_PAINT message: Display "Windows" in Script */
  7472.                      /*-----------------------------------------------*/
  7473.  
  7474.            case WM_PAINT:
  7475.                 BeginPaint (hWnd, &ps) ;
  7476.  
  7477.                 hFont = CreateFont (yClient, xClient / 8,
  7478.                                     0, 0, 400, 0, 0, 0, OEM_CHARSET,
  7479.                                     OUT_STROKE_PRECIS, OUT_STROKE_PRECIS,
  7480.                                     DRAFT_QUALITY, (BYTE) VARIABLE_PITCH |
  7481.                                     cFamily [nCurrentFont - IDM_SCRIPT],
  7482.                                     szFace  [nCurrentFont - IDM_SCRIPT]) ;
  7483.  
  7484.                 hFont = SelectObject (ps.hdc, hFont) ;
  7485.                 TextOut (ps.hdc, 0, 0, "Windows", 7) ;
  7486.  
  7487.                 DeleteObject (SelectObject (ps.hdc, hFont)) ;
  7488.                 EndPaint (hWnd, &ps) ;
  7489.                 break ;
  7490.  
  7491.                      /*---------------------------------------*/
  7492.                      /* WM_DESTROY message: Post Quit message */
  7493.                      /*---------------------------------------*/
  7494.  
  7495.            case WM_DESTROY:
  7496.                 PostQuitMessage (0) ;
  7497.                 break ;
  7498.  
  7499.                      /*---------------------------------------*/
  7500.                      /* Other messages: Do default processing */
  7501.                      /*---------------------------------------*/
  7502.  
  7503.            default:
  7504.                 return DefWindowProc (hWnd, iMessage, wParam, lParam) ;
  7505.            }
  7506.       return 0L ;
  7507.       }
  7508.  
  7509.  \SAMPCODE\DOS_ENCY\17\SAMPLE.H
  7510.  
  7511.  #define IDM_SCRIPT 1
  7512.  #define IDM_MODERN 2
  7513.  #define IDM_ROMAN  3
  7514.  
  7515.  \SAMPCODE\DOS_ENCY\17\SAMPLE.RC
  7516.  
  7517.  #include "sample.h"
  7518.  
  7519.  Sample MENU
  7520.       BEGIN
  7521.            POPUP "&Typeface"
  7522.                 BEGIN
  7523.                      MENUITEM "&Script", IDM_SCRIPT, CHECKED
  7524.                      MENUITEM "&Modern", IDM_MODERN
  7525.                      MENUITEM "&Roman",  IDM_ROMAN
  7526.                 END
  7527.       END
  7528.  
  7529.  \SAMPCODE\DOS_ENCY\17\SAMPLE.DEF
  7530.  
  7531.  NAME           SAMPLE
  7532.  DESCRIPTION    'Demonstration Windows Program'
  7533.  STUB           'WINSTUB.EXE'
  7534.  CODE           MOVABLE
  7535.  DATA           MOVABLE MULTIPLE
  7536.  HEAPSIZE       1024
  7537.  STACKSIZE      4096
  7538.  EXPORTS        WndProc
  7539.  
  7540.  \SAMPCODE\DOS_ENCY\17\SAMPLE.MAK
  7541.  
  7542.  sample.obj : sample.c sample.h
  7543.       cl -c -Gsw -W2 -Zdp sample.c
  7544.  
  7545.  sample.res : sample.rc sample.h
  7546.       rc -r sample.rc
  7547.  
  7548.  sample.exe : sample.obj sample.def sample.res
  7549.       link4 sample, /align:16, /map /line, slibw, sample
  7550.       rc sample.res
  7551.       mapsym sample
  7552.  
  7553.  \SAMPCODE\DOS_ENCY\18
  7554.  \SAMPCODE\DOS_ENCY\18\ASCTBL1.C
  7555.  
  7556.  /*************************************************************************
  7557.   *                                                                       *
  7558.   *  ASCTBL.C                                                             *
  7559.   *   This program generates an ASCII lookup table for all displayable    *
  7560.   *   ASCII and extended IBM PC codes, leaving blanks for nondisplayable  *
  7561.   *   codes.                                                              *
  7562.   *                                                                       *
  7563.   ************************************************************************/
  7564.  
  7565.  #include <ctype.h>
  7566.  #include <stdio.h>
  7567.  
  7568.  main()
  7569.  {
  7570.  int i, j, k;
  7571.         /* Print table title. */
  7572.         printf("\n\n\n                ASCII LOOKUP TABLE\n\n");
  7573.  
  7574.         /* Print column headers. */
  7575.         printf("    ");
  7576.         for (i = 0; i < 16; i++)
  7577.                 printf("%X  ", i);
  7578.         fputchar("\n");
  7579.  
  7580.         /* Print each line of the table. */
  7581.         for ( i = 0, k = 0; i < 16; i++)
  7582.                 {
  7583.                 /* Print first hex digit of symbols on this line. */
  7584.                 printf("%X   ", i);
  7585.                 /* Print each of the 16 symbols for this line. */
  7586.                 for (j = 0; j < 16; j++)
  7587.                         {
  7588.                         /* Filter nonprintable characters. */
  7589.                         if ((k >= 7 && k <= 13) || (k >= 28 && k <= 31))
  7590.                                 printf("   ");
  7591.                         else
  7592.                                 printf("%c  ", k);
  7593.                         k++;
  7594.                         }
  7595.         fputchar("\n");
  7596.         }
  7597.  }
  7598.  
  7599.  \SAMPCODE\DOS_ENCY\18\ASCTBL2.C
  7600.  
  7601.  /*************************************************************************
  7602.   *                                                                       *
  7603.   *  ASCTBL.C                                                             *
  7604.   *   This program generates an ASCII lookup table for all displayable    *
  7605.   *   ASCII and extended IBM PC codes, leaving blanks for nondisplayable  *
  7606.   *   codes.                                                              *
  7607.   *                                                                       *
  7608.   ************************************************************************/
  7609.  
  7610.  #define LINT_ARGS
  7611.  #include <ctype.h>
  7612.  #include <stdio.h>
  7613.  
  7614.  main()
  7615.  {
  7616.  int i, j, k;
  7617.          /* Print table title. */
  7618.          printf("\n\n\n                ASCII LOOKUP TABLE\n\n");
  7619.  
  7620.          /* Print column headers. */
  7621.          printf("    ");
  7622.          for (i = 0; i < 16; i++)
  7623.                  printf("%X  ", i);
  7624.          fputchar('\n');
  7625.  
  7626.          /* Print each line of the table. */
  7627.          for ( i = 0, k = 0; i < 16; i++)
  7628.                  {
  7629.                  /* Print first hex digit of symbols on this line. */
  7630.                  printf("%X   ", i);
  7631.                  /* Print each of the 16 symbols for this line. */
  7632.                  for (j = 0; j < 16; j++)
  7633.                          {
  7634.                          /* Filter nonprintable characters. */
  7635.                          if ((k >= 7 && k <= 13) || (k >= 28 && k <= 31))
  7636.                                  printf("   ");
  7637.                          else
  7638.                                  printf("%c  ", k);
  7639.                          k++;
  7640.                          }
  7641.                  fputchar('\n');
  7642.                  }
  7643.  }
  7644.  
  7645.  \SAMPCODE\DOS_ENCY\18\COMMSCMD.C
  7646.  
  7647.  /***********************************************************************
  7648.  *                                                                      *
  7649.  *  COMMSCMD                                                            *
  7650.  *                                                                      *
  7651.  *  This routine controls the COMMSCOP program that has been in-        *
  7652.  *  stalled as a resident routine.  The operation performed is de-      *
  7653.  *  termined by the command line.  The COMMSCMD program is invoked      *
  7654.  *  as follows:                                                         *
  7655.  *                                                                      *
  7656.  *                COMMSCMD [[cmd][ port]]                               *
  7657.  *                                                                      *
  7658.  *  where cmd is the command to be executed                             *
  7659.  *            STOP   -- stop trace                                      *
  7660.  *            START  -- flush trace buffer and start trace              *
  7661.  *            RESUME -- resume a stopped trace                          *
  7662.  *        port is the COMM port to be traced (1=COM1, 2=COM2, etc.)     *
  7663.  *                                                                      *
  7664.  *  If cmd is omitted, STOP is assumed.  If port is omitted, 1 is       *
  7665.  *  assumed.                                                            *
  7666.  *                                                                      *
  7667.  ***********************************************************************/
  7668.  
  7669.  #include <stdlib.h>
  7670.  #include <stdio.h>
  7671.  #include <dos.h>
  7672.  #define COMMCMD 0x60
  7673.  
  7674.  main(argc, argv)
  7675.  int argc;
  7676.  char *argv[];
  7677.  {
  7678.      int cmd, port, result;
  7679.      static char commands[3] [10] = {"STOPPED", "STARTED", "RESUMED"};
  7680.      union REGS inregs, outregs;
  7681.  
  7682.      cmd = 0;
  7683.      port = 0;
  7684.  
  7685.      if (argc > 1)
  7686.          {
  7687.          if (0 == stricmp(argv[1], "STOP"))
  7688.              cmd = 0;
  7689.          else if (0 == stricmp(argv[1], "START"))
  7690.              cmd = 1;
  7691.          else if (0 == stricmp(argv[1], "RESUME"))
  7692.              cmd = 2;
  7693.          }
  7694.  
  7695.      if (argc == 3)
  7696.          {
  7697.          port = atoi(argv[2]);
  7698.          if (port > 0)
  7699.              port = port - 1;
  7700.          }
  7701.  
  7702.      inregs.h.ah = cmd;
  7703.      inregs.x.dx = port;
  7704.      result = int86(COMMCMD, &inregs, &outregs);
  7705.  
  7706.  
  7707.      printf("\nCommunications tracing %s for port COM%1d:\n",
  7708.              commands[cmd], port + 1);
  7709.  }
  7710.  
  7711.  \SAMPCODE\DOS_ENCY\18\UPERCAS1.C
  7712.  
  7713.  /************************************************************************
  7714.   *                                                                      *
  7715.   * UPPERCAS.C                                                           *
  7716.   *    This routine converts a fixed string to uppercase and prints it.  *
  7717.   *                                                                      *
  7718.   ************************************************************************/
  7719.  
  7720.  #include <ctype.h>
  7721.  #include <string.h>
  7722.  #include <stdio.h>
  7723.  
  7724.  main(argc,argv)
  7725.  
  7726.  int argc;
  7727.  char *argv[];
  7728.  
  7729.  {
  7730.  char    *cp,c;
  7731.  
  7732.          cp = "a string\n";
  7733.  
  7734.          /*  Convert *cp to uppercase and write to standard output  */
  7735.  
  7736.          while (*cp != '\0')
  7737.                  {
  7738.                  c = toupper(*cp++);
  7739.                  putchar(c);
  7740.                  }
  7741.  
  7742.  }
  7743.  
  7744.  \SAMPCODE\DOS_ENCY\18\UPERCAS2.C
  7745.  
  7746.  /************************************************************************
  7747.   *                                                                      *
  7748.   * UPPERCAS.C                                                           *
  7749.   *    This routine converts a fixed string to uppercase and prints it.  *
  7750.   *                                                                      *
  7751.   ***********************************************************************/
  7752.  
  7753.  #include <ctype.h>
  7754.  #undef toupper
  7755.  #undef tolower
  7756.  #include <string.h>
  7757.  #include <stdio.h>
  7758.  
  7759.  main(argc,argv)
  7760.  
  7761.  int argc;
  7762.  char *argv[];
  7763.  
  7764.  {
  7765.  char    *cp,c;
  7766.  
  7767.          cp = "a string\n";
  7768.  
  7769.          /*  Convert *cp to uppercase and write to standard output  */
  7770.  
  7771.          while (*cp != '\0')
  7772.                  {
  7773.                  c = toupper(*cp++);
  7774.                  putchar(c);
  7775.                  }
  7776.  
  7777.  }
  7778.  
  7779.  \SAMPCODE\DOS_ENCY\18\BADSCOP.ASM
  7780.  
  7781.          TITLE   BADSCOP -- BAD VERSION OF COMMUNICATIONS TRACE UTILITY
  7782.  ; ***********************************************************************
  7783.  ; *                                                                     *
  7784.  ; *  BADSCOP --                                                         *
  7785.  ; *     THIS PROGRAM MONITORS THE ACTIVITY ON A SPECIFIED COMM PORT     *
  7786.  ; *     AND PLACES A COPY OF ALL COMM ACTIVITY IN A RAM BUFFER.  EACH   *
  7787.  ; *     ENTRY IN THE BUFFER IS TAGGED TO INDICATE WHETHER THE BYTE      *
  7788.  ; *     WAS SENT BY OR RECEIVED BY THE SYSTEM.                          *
  7789.  ; *                                                                     *
  7790.  ; *     BADSCOP IS INSTALLED BY ENTERING                                *
  7791.  ; *                                                                     *
  7792.  ; *                     BADSCOP                                         *
  7793.  ; *                                                                     *
  7794.  ; *  THIS WILL INSTALL BADSCOP AND SET UP A 64K BUFFER TO BE USED       *
  7795.  ; *  FOR DATA LOGGING.  REMEMBER THAT 2 BYTES ARE REQUIRED FOR          *
  7796.  ; *  EACH COMM BYTE, SO THE BUFFER IS ONLY 32K EVENTS LONG, OR ABOUT    *
  7797.  ; *  30 SECONDS OF CONTINUOUS 9600 BAUD DATA.  IN THE REAL WORLD,       *
  7798.  ; *  ASYNC DATA IS RARELY CONTINUOUS, SO THE BUFFER WILL PROBABLY       *
  7799.  ; *  HOLD MORE THAN 30 SECONDS WORTH OF DATA.                           *
  7800.  ; *                                                                     *
  7801.  ; *  WHEN INSTALLED, BADSCOP INTERCEPTS ALL INT 14H CALLS.  IF THE      *
  7802.  ; *  PROGRAM HAS BEEN ACTIVATED AND THE INT IS EITHER SEND OR RE-       *
  7803.  ; *  CEIVE DATA, A COPY OF THE DATA BYTE, PROPERLY TAGGED, IS PLACED    *
  7804.  ; *  IN THE BUFFER.  IN ANY CASE, DATA IS PASSED ON TO THE REAL         *
  7805.  ; *  INT 14H HANDLER.                                                   *
  7806.  ; *                                                                     *
  7807.  ; *  BADSCOP IS INVOKED BY ISSUING AN INT 60H CALL.  THE INT HAS        *
  7808.  ; *  THE FOLLOWING CALLING SEQUENCE:                                    *
  7809.  ; *                                                                     *
  7810.  ; *       AH -- COMMAND                                                 *
  7811.  ; *             0 -- STOP TRACING, PLACE STOP MARK IN BUFFER            *
  7812.  ; *             1 -- FLUSH BUFFER AND START TRACE                       *
  7813.  ; *             2 -- RESUME TRACE                                       *
  7814.  ; *             3 -- RETURN COMM BUFFER ADDRESSES                       *
  7815.  ; *       DX -- COMM PORT (ONLY USED WITH AH = 1 or 2)                  *
  7816.  ; *             0 -- COM1                                               *
  7817.  ; *             1 -- COM2                                               *
  7818.  ; *                                                                     *
  7819.  ; *  THE FOLLOWING DATA IS RETURNED IN REPONSE TO AH = 3:               *
  7820.  ; *                                                                     *
  7821.  ; *       CX -- BUFFER COUNT IN BYTES                                   *
  7822.  ; *       DX -- SEGMENT ADDRESS OF THE START OF THE BUFFER              *
  7823.  ; *       BX -- OFFSET ADDRESS OF THE START OF THE BUFFER               *
  7824.  ; *                                                                     *
  7825.  ; *  THE COMM BUFFER IS FILLED WITH 2-BYTE DATA ENTRIES OF THE          *
  7826.  ; *  FOLLOWING FORM:                                                    *
  7827.  ; *                                                                     *
  7828.  ; *       BYTE 0 -- CONTROL                                             *
  7829.  ; *            BIT 0 -- ON FOR RECEIVED DATA, OFF FOR TRANS.            *
  7830.  ; *            BIT 7 -- STOP MARK -- INDICATES COLLECTION WAS           *
  7831.  ; *                  INTERRUPTED AND RESUMED.                           *
  7832.  ; *       BYTE 1 -- 8-BIT DATA                                          *
  7833.  ; *                                                                     *
  7834.  ; ***********************************************************************
  7835.  
  7836.          PUBLIC INITIALIZE,CONTROL,VECTOR_INIT,COMMSCOPE
  7837.          PUBLIC OLD_COMM_INT,COUNT,STATUS,PORT,BUFPNTR
  7838.  
  7839.  CSEG    SEGMENT
  7840.          ASSUME  CS:CSEG,DS:CSEG
  7841.          ORG     100H                    ;TO MAKE A COM FILE
  7842.  
  7843.  INITIALIZE:
  7844.          JMP     VECTOR_INIT             ;JUMP TO THE INITIALIZATION
  7845.                                          ; ROUTINE WHICH, TO SAVE SPACE,
  7846.                                          ; IS IN THE COMM BUFFER
  7847.  
  7848.  ;
  7849.  ;  SYSTEM VARIABLES
  7850.  ;
  7851.  OLD_COMM_INT    DD      ?               ;ADDRESS OF REAL COMM INT
  7852.  COUNT           DW      0               ;BUFFER COUNT
  7853.  COMMSCOPE_INT   EQU     60H             ;COMMSCOPE CONTROL INT
  7854.  STATUS          DB      0               ;PROCESSING STATUS
  7855.                                          ; 0 -- OFF
  7856.                                          ; 1 -- ON
  7857.  PORT            DB      0               ;COMM PORT BEING TRACED
  7858.  BUFPNTR         DW      VECTOR_INIT     ;NEXT BUFFER LOCATION
  7859.  
  7860.          SUBTTL  DATA INTERRUPT HANDLER
  7861.  PAGE
  7862.  ; ***********************************************************************
  7863.  ; *                                                                     *
  7864.  ; *  COMMSCOPE                                                          *
  7865.  ; *  THIS PROCEDURE INTERCEPTS ALL INT 14H CALLS AND LOGS THE DATA      *
  7866.  ; *  IF APPROPRIATE.                                                    *
  7867.  ; *                                                                     *
  7868.  ; ***********************************************************************
  7869.  COMMSCOPE       PROC    NEAR
  7870.  
  7871.          TEST    CS:STATUS,1             ;ARE WE ON?
  7872.          JZ      OLD_JUMP                ; NO, SIMPLY JUMP TO OLD HANDLER
  7873.  
  7874.          CMP     AH,00H                  ;SKIP SETUP CALLS
  7875.          JE      OLD_JUMP                ; .
  7876.  
  7877.          CMP     AH,03H                  ;SKIP STATUS REQUESTS
  7878.          JAE     OLD_JUMP                ; .
  7879.  
  7880.          CMP     AH,02H                  ;IS THIS A READ REQUEST?
  7881.          JE      GET_READ                ; YES, GO PROCESS
  7882.  
  7883.  ;
  7884.  ;  DATA WRITE REQUEST -- SAVE IF APPROPRIATE
  7885.  ;
  7886.          CMP     DL,CS:PORT              ;IS WRITE FOR PORT BEING TRACED?
  7887.          JNE     OLD_JUMP                ; NO, JUST PASS IT THROUGH
  7888.  
  7889.          PUSH    DS                      ;SAVE CALLER'S REGISTERS
  7890.          PUSH    BX                      ; .
  7891.          PUSH    CS                      ;SET UP DS FOR OUR PROGRAM
  7892.          POP     DS                      ; .
  7893.          MOV     BX,BUFPNTR              ;GET ADDRESS OF NEXT BUFFER LOCATION
  7894.          MOV     [BX],BYTE PTR 0         ;MARK AS TRANSMITTED BYTE
  7895.          MOV     [BX+1],AL               ;SAVE DATA IN BUFFER
  7896.          INC     COUNT                   ;INCREMENT BUFFER BYTE COUNT
  7897.          INC     COUNT                   ; .
  7898.          INC     BX                      ;POINT TO NEXT LOCATION
  7899.          INC     BX                      ; .
  7900.          MOV     BUFPNTR,BX              ;SAVE NEW POINTER
  7901.          JNZ     WRITE_DONE              ;ZERO INDICATES BUFFER HAS WRAPPED
  7902.  
  7903.          MOV     STATUS,0                ;TURN COLLECTION OFF -- BUFFER FULL
  7904.  WRITE_DONE:
  7905.          POP     BX                      ;RESTORE CALLER'S REGISTERS
  7906.          POP     DS                      ; .
  7907.          JMP     OLD_JUMP                ;PASS REQUEST ON TO BIOS ROUTINE
  7908.  ;
  7909.  ;  PROCESS A READ DATA REQUEST AND WRITE TO BUFFER IF APPROPRIATE
  7910.  ;
  7911.  GET_READ:
  7912.          CMP     DL,CS:PORT              ;IS READ FOR PORT BEING TRACED?
  7913.          JNE     OLD_JUMP                ; NO, JUST PASS IT THROUGH
  7914.  
  7915.          PUSH    DS                      ;SAVE CALLER'S REGISTERS
  7916.          PUSH    BX                      ; .
  7917.          PUSH    CS                      ;SET UP DS FOR OUR PROGRAM
  7918.          POP     DS                      ; .
  7919.  
  7920.          PUSHF                           ;FAKE INT 14H CALL
  7921.          CLI                             ; .
  7922.          CALL    OLD_COMM_INT            ;PASS REQUEST ON TO BIOS
  7923.          TEST    AH,80H                  ;VALID READ?
  7924.          JNZ     READ_DONE               ; NO, SKIP BUFFER UPDATE
  7925.  
  7926.          MOV     BX,BUFPNTR              ;GET ADDRESS OF NEXT BUFFER LOCATION
  7927.          MOV     [BX],BYTE PTR 1         ;MARK AS RECEIVED BYTE
  7928.          MOV     [BX+1],AL               ;SAVE DATA IN BUFFER
  7929.          INC     COUNT                   ;INCREMENT BUFFER BYTE COUNT
  7930.          INC     COUNT                   ; .
  7931.          INC     BX                      ;POINT TO NEXT LOCATION
  7932.          INC     BX                      ; .
  7933.          MOV     BUFPNTR,BX              ;SAVE NEW POINTER
  7934.          JNZ     READ_DONE               ;ZERO INDICATES BUFFER HAS WRAPPED
  7935.  
  7936.          MOV     STATUS,0                ;TURN COLLECTION OFF -- BUFFER FULL
  7937.  READ_DONE:
  7938.          POP     BX                      ;RESTORE CALLER'S REGISTERS
  7939.          POP     DS                      ; .
  7940.          IRET
  7941.  
  7942.  ;
  7943.  ;  JUMP TO COMM BIOS ROUTINE
  7944.  ;
  7945.  OLD_JUMP:
  7946.          JMP     OLD_COMM_INT
  7947.  
  7948.  COMMSCOPE ENDP
  7949.  
  7950.          SUBTTL  CONTROL INTERRUPT HANDLER
  7951.  PAGE
  7952.  ; ***********************************************************************
  7953.  ; *                                                                     *
  7954.  ; *  CONTROL                                                            *
  7955.  ; *     THIS ROUTINE PROCESSES CONTROL REQUESTS.                        *
  7956.  ; *                                                                     *
  7957.  ; ***********************************************************************
  7958.  
  7959.  CONTROL PROC    NEAR
  7960.          CMP     AH,00H                  ;STOP REQUEST?
  7961.          JNE     CNTL_START              ; NO, CHECK START
  7962.          PUSH    DS                      ;SAVE REGISTERS
  7963.          PUSH    BX                      ; .
  7964.          PUSH    CS                      ;SET DS FOR OUR ROUTINE
  7965.          POP     DS
  7966.          MOV     STATUS,0                ;TURN PROCESSING OFF
  7967.          MOV     BX,BUFPNTR              ;PLACE STOP MARK IN BUFFER
  7968.          MOV     [BX],BYTE PTR 80H       ; .
  7969.          MOV     [BX+1],BYTE PTR 0FFH    ; .
  7970.          INC     COUNT                   ;INCREMENT COUNT
  7971.          INC     COUNT                   ; .
  7972.          POP     BX                      ;RESTORE REGISTERS
  7973.          POP     DS                      ; .
  7974.          JMP     CONTROL_DONE
  7975.  
  7976.  CNTL_START:
  7977.          CMP     AH,01H                  ;START REQUEST?
  7978.          JNE     CNTL_RESUME             ; NO, CHECK RESUME
  7979.          MOV     CS:PORT,DL              ;SAVE PORT TO TRACE
  7980.          MOV     CS:BUFPNTR,OFFSET VECTOR_INIT   ;RESET BUFFER TO START
  7981.          MOV     CS:COUNT,0              ;ZERO COUNT
  7982.          MOV     CS:STATUS,1             ;START LOGGING
  7983.          JMP     CONTROL_DONE
  7984.  
  7985.  CNTL_RESUME:
  7986.          CMP     AH,02H                  ;RESUME REQUEST?
  7987.          JNE     CNTL_STATUS             ; NO, CHECK STATUS
  7988.          CMP     CS:BUFPNTR,0            ;END OF BUFFER CONDITION?
  7989.          JE      CONTROL_DONE            ; YES, DO NOTHING
  7990.          MOV     CS:PORT,DL              ;SAVE PORT TO TRACE
  7991.          MOV     CS:STATUS,1             ;START LOGGING
  7992.          JMP     CONTROL_DONE
  7993.  
  7994.  CNTL_STATUS:
  7995.          CMP     AH,03H                  ;RETURN STATUS REQUEST?
  7996.          JNE     CONTROL_DONE            ; NO, ERROR -- DO NOTHING
  7997.          MOV     CX,CS:COUNT             ;RETURN COUNT
  7998.          PUSH    CS                      ;RETURN SEGMENT ADDR OF BUFFER
  7999.          POP     DX                      ; .
  8000.          MOV     BX,OFFSET VECTOR_INIT   ;RETURN OFFSET ADDR OF BUFFER
  8001.  
  8002.  CONTROL_DONE:
  8003.          IRET
  8004.  
  8005.  CONTROL ENDP
  8006.  
  8007.  
  8008.          SUBTTL  INITIALIZE INTERRUPT VECTORS
  8009.  PAGE
  8010.  ; ***********************************************************************
  8011.  ; *                                                                     *
  8012.  ; *  VECTOR_INIT                                                        *
  8013.  ; *  THIS PROCEDURE INITIALIZES THE INTERRUPT VECTORS AND THEN          *
  8014.  ; *  EXITS VIA THE MS-DOS TERMINATE-AND-STAY-RESIDENT FUNCTION.         *
  8015.  ; *  A BUFFER OF 64K IS RETAINED.  THE FIRST AVAILABLE BYTE             *
  8016.  ; *  IN THE BUFFER IS THE OFFSET OF VECTOR_INIT.                        *
  8017.  ; *                                                                     *
  8018.  ; ***********************************************************************
  8019.  
  8020.          EVEN                            ;ASSURE BUFFER ON EVEN BOUNDARY
  8021.  VECTOR_INIT     PROC    NEAR
  8022.  ;
  8023.  ;  GET ADDRESS OF COMM VECTOR (INT 14H)
  8024.  ;
  8025.          MOV     AH,35H
  8026.          MOV     AL,14H
  8027.          INT     21H
  8028.  ;
  8029.  ;  SAVE OLD COMM INT ADDRESS
  8030.  ;
  8031.          MOV     WORD PTR OLD_COMM_INT,BX
  8032.          MOV     AX,ES
  8033.          MOV     WORD PTR OLD_COMM_INT[2],AX
  8034.  ;
  8035.  ;  SET UP COMM INT TO POINT TO OUR ROUTINE
  8036.  ;
  8037.          MOV     DX,OFFSET COMMSCOPE
  8038.          MOV     AH,25H
  8039.          MOV     AL,14H
  8040.          INT     21H
  8041.  ;
  8042.  ;  INSTALL CONTROL ROUTINE INT
  8043.  ;
  8044.          MOV     DX,OFFSET CONTROL
  8045.          MOV     AH,25H
  8046.          MOV     AL,COMMSCOPE_INT
  8047.          INT     21H
  8048.  ;
  8049.  ;  SET LENGTH TO 64K, EXIT AND STAY RESIDENT
  8050.  ;
  8051.          MOV     AX,3100H                ;TERM AND STAY RES COMMAND
  8052.          MOV     DX,1000H                ;64K RESERVED
  8053.          INT     21H                     ;DONE
  8054.  VECTOR_INIT ENDP
  8055.  
  8056.  CSEG    ENDS
  8057.          END     INITIALIZE
  8058.  
  8059.  \SAMPCODE\DOS_ENCY\18\COMMSCOP.ASM
  8060.  
  8061.          TITLE   COMMSCOP -- COMMUNICATIONS TRACE UTILITY
  8062.  ; ***********************************************************************
  8063.  ; *                                                                     *
  8064.  ; *  COMMSCOPE --                                                       *
  8065.  ; *     THIS PROGRAM MONITORS THE ACTIVITY ON A SPECIFIED COMM PORT     *
  8066.  ; *     AND PLACES A COPY OF ALL COMM ACTIVITY IN A RAM BUFFER.  EACH   *
  8067.  ; *     ENTRY IN THE BUFFER IS TAGGED TO INDICATE WHETHER THE BYTE      *
  8068.  ; *     WAS SENT BY OR RECEIVED BY THE SYSTEM.                          *
  8069.  ; *                                                                     *
  8070.  ; *     COMMSCOPE IS INSTALLED BY ENTERING                              *
  8071.  ; *                                                                     *
  8072.  ; *                      COMMSCOP                                       *
  8073.  ; *                                                                     *
  8074.  ; *     THIS WILL INSTALL COMMSCOP AND SET UP A 64K BUFFER TO BE USED   *
  8075.  ; *     FOR DATA LOGGING.  REMEMBER THAT 2 BYTES ARE REQUIRED FOR       *
  8076.  ; *     EACH COMM BYTE, SO THE BUFFER IS ONLY 32K EVENTS LONG, OR ABOUT *
  8077.  ; *     30 SECONDS OF CONTINUOUS 9600 BAUD DATA.  IN THE REAL WORLD,    *
  8078.  ; *     ASYNC DATA IS RARELY CONTINUOUS, SO THE BUFFER WILL PROBABLY    *
  8079.  ; *     HOLD MORE THAN 30 SECONDS WORTH OF DATA.                        *
  8080.  ; *                                                                     *
  8081.  ; *     WHEN INSTALLED, COMMSCOP INTERCEPTS ALL INT 14H CALLS.  IF THE  *
  8082.  ; *     PROGRAM HAS BEEN ACTIVATED AND THE INT IS EITHER SEND OR RE-    *
  8083.  ; *     CEIVE DATA, A COPY OF THE DATA BYTE, PROPERLY TAGGED, IS PLACED *
  8084.  ; *     IN THE BUFFER.  IN ANY CASE, DATA IS PASSED ON TO THE REAL      *
  8085.  ; *     INT 14H HANDLER.                                                *
  8086.  ; *                                                                     *
  8087.  ; *     COMMSCOP IS INVOKED BY ISSUING AN INT 60H CALL.  THE INT HAS    *
  8088.  ; *     THE FOLLOWING CALLING SEQUENCE:                                 *
  8089.  ; *                                                                     *
  8090.  ; *             AH -- COMMAND                                           *
  8091.  ; *                   0 -- STOP TRACING, PLACE STOP MARK IN BUFFER      *
  8092.  ; *                   1 -- FLUSH BUFFER AND START TRACE                 *
  8093.  ; *                   2 -- RESUME TRACE                                 *
  8094.  ; *                   3 -- RETURN COMM BUFFER ADDRESSES                 *
  8095.  ; *             DX -- COMM PORT (ONLY USED WITH AH = 1 or 2)            *
  8096.  ; *                   0 -- COM1                                         *
  8097.  ; *                   1 -- COM2                                         *
  8098.  ; *                                                                     *
  8099.  ; *     THE FOLLOWING DATA IS RETURNED IN RESPONSE TO AH = 3:           *
  8100.  ; *                                                                     *
  8101.  ; *             CX -- BUFFER COUNT IN BYTES                             *
  8102.  ; *             DX -- SEGMENT ADDRESS OF THE START OF THE BUFFER        *
  8103.  ; *             BX -- OFFSET ADDRESS OF THE START OF THE BUFFER         *
  8104.  ; *                                                                     *
  8105.  ; *     THE COMM BUFFER IS FILLED WITH 2-BYTE DATA ENTRIES OF THE       *
  8106.  ; *     FOLLOWING FORM:                                                 *
  8107.  ; *                                                                     *
  8108.  ; *             BYTE 0 -- CONTROL                                       *
  8109.  ; *                  BIT 0 -- ON FOR RECEIVED DATA, OFF FOR TRANS.      *
  8110.  ; *                  BIT 7 -- STOP MARK -- INDICATES COLLECTION WAS     *
  8111.  ; *                              INTERRUPTED AND RESUMED.               *
  8112.  ; *             BYTE 1 -- 8-BIT DATA                                    *
  8113.  ; *                                                                     *
  8114.  ; ***********************************************************************
  8115.  
  8116.  CSEG    SEGMENT
  8117.          ASSUME  CS:CSEG,DS:CSEG
  8118.          ORG     100H                    ;TO MAKE A COMM FILE
  8119.  
  8120.  INITIALIZE:
  8121.          JMP     VECTOR_INIT             ;JUMP TO THE INITIALIZATION
  8122.                                          ; ROUTINE WHICH, TO SAVE SPACE,
  8123.                                          ; IS IN THE COMM BUFFER
  8124.  
  8125.  ;
  8126.  ;  SYSTEM VARIABLES
  8127.  ;
  8128.  OLD_COMM_INT    DD      ?               ;ADDRESS OF REAL COMM INT
  8129.  COUNT           DW      0               ;BUFFER COUNT
  8130.  COMMSCOPE_INT   EQU     60H             ;COMMSCOPE CONTROL INT
  8131.  STATUS          DB      0               ;PROCESSING STATUS
  8132.                                          ; 0 -- OFF
  8133.                                          ; 1 -- ON
  8134.  PORT            DB      0               ;COMM PORT BEING TRACED
  8135.  BUFPNTR         DW      VECTOR_INIT     ;NEXT BUFFER LOCATION
  8136.  
  8137.          SUBTTL  DATA INTERRUPT HANDLER
  8138.  PAGE
  8139.  ; ***********************************************************************
  8140.  ; *                                                                     *
  8141.  ; *  COMMSCOPE                                                          *
  8142.  ; *     THIS PROCEDURE INTERCEPTS ALL INT 14H CALLS AND LOGS THE DATA   *
  8143.  ; *     IF APPROPRIATE.                                                 *
  8144.  ; *                                                                     *
  8145.  ; ***********************************************************************
  8146.  COMMSCOPE       PROC    NEAR
  8147.  
  8148.          TEST    CS:STATUS,1             ;ARE WE ON?
  8149.          JZ      OLD_JUMP                ; NO, SIMPLY JUMP TO OLD HANDLER
  8150.  
  8151.          CMP     AH,00H                  ;SKIP SETUP CALLS
  8152.          JE      OLD_JUMP                ; .
  8153.  
  8154.          CMP     AH,03H                  ;SKIP STATUS REQUESTS
  8155.          JAE     OLD_JUMP                ; .
  8156.  
  8157.          CMP     AH,02H                  ;IS THIS A READ REQUEST?
  8158.          JE      GET_READ                ; YES, GO PROCESS
  8159.  
  8160.  ;
  8161.  ;  DATA WRITE REQUEST -- SAVE IF APPROPRIATE
  8162.  ;
  8163.          CMP     DL,CS:PORT              ;IS WRITE FOR PORT BEING TRACED?
  8164.          JNE     OLD_JUMP                ; NO, JUST PASS IT THROUGH
  8165.  
  8166.          PUSH    DS                      ;SAVE CALLER'S REGISTERS
  8167.          PUSH    BX                      ; .
  8168.          PUSH    CS                      ;SET UP DS FOR OUR PROGRAM
  8169.          POP     DS                      ; .
  8170.          MOV     BX,BUFPNTR              ;GET ADDR OF NEXT BUFFER LOC
  8171.          MOV     [BX],BYTE PTR 0         ;MARK AS TRANSMITTED BYTE
  8172.          MOV     [BX+1],AL               ;SAVE DATA IN BUFFER
  8173.          INC     COUNT                   ;INCREMENT BUFFER BYTE COUNT
  8174.          INC     COUNT                   ; .
  8175.          INC     BX                      ;POINT TO NEXT LOCATION
  8176.          INC     BX                      ; .
  8177.          MOV     BUFPNTR,BX              ;SAVE NEW POINTER
  8178.          JNZ     WRITE_DONE              ;ZERO MEANS BUFFER HAS WRAPPED
  8179.  
  8180.          MOV     STATUS,0                ;TURN COLLECTION OFF
  8181.  WRITE_DONE:
  8182.          POP     BX                      ;RESTORE CALLER'S REGISTERS
  8183.          POP     DS                      ; .
  8184.          JMP     OLD_JUMP                ;PASS REQUEST ON TO BIOS ROUTINE
  8185.  ;
  8186.  ;  PROCESS A READ DATA REQUEST AND WRITE TO BUFFER IF APPROPRIATE
  8187.  ;
  8188.  GET_READ:
  8189.          CMP     DL,CS:PORT              ;IS READ FOR PORT BEING TRACED?
  8190.          JNE     OLD_JUMP                ; NO, JUST PASS IT THROUGH
  8191.  
  8192.          PUSH    DS                      ;SAVE CALLER'S REGISTERS
  8193.          PUSH    BX                      ; .
  8194.          PUSH    CS                      ;SET UP DS FOR OUR PROGRAM
  8195.          POP     DS                      ; .
  8196.  
  8197.          PUSHF                           ;FAKE INT 14H CALL
  8198.          CLI                             ; .
  8199.          CALL    OLD_COMM_INT            ;PASS REQUEST ON TO BIOS
  8200.          TEST    AH,80H                  ;VALID READ?
  8201.          JNZ     READ_DONE               ; NO, SKIP BUFFER UPDATE
  8202.  
  8203.          MOV     BX,BUFPNTR              ;GET ADDR OF NEXT BUFFER LOC
  8204.          MOV     [BX],BYTE PTR 1         ;MARK AS RECEIVED BYTE
  8205.          MOV     [BX+1],AL               ;SAVE DATA IN BUFFER
  8206.          INC     COUNT                   ;INCREMENT BUFFER BYTE COUNT
  8207.          INC     COUNT                   ; .
  8208.          INC     BX                      ;POINT TO NEXT LOCATION
  8209.          INC     BX                      ; .
  8210.          MOV     BUFPNTR,BX              ;SAVE NEW POINTER
  8211.          JNZ     READ_DONE               ;ZERO MEANS BUFFER HAS WRAPPED
  8212.  
  8213.          MOV     STATUS,0                ;TURN COLLECTION OFF
  8214.  READ_DONE:
  8215.          POP     BX                      ;RESTORE CALLER'S REGISTERS
  8216.          POP     DS                      ; .
  8217.          IRET
  8218.  
  8219.  ;
  8220.  ;  JUMP TO COMM BIOS ROUTINE
  8221.  ;
  8222.  OLD_JUMP:
  8223.          JMP     CS:OLD_COMM_INT
  8224.  
  8225.  COMMSCOPE ENDP
  8226.  
  8227.          SUBTTL  CONTROL INTERRUPT HANDLER
  8228.  PAGE
  8229.  ; ***********************************************************************
  8230.  ; *                                                                     *
  8231.  ; *  CONTROL                                                            *
  8232.  ; *     THIS ROUTINE PROCESSES CONTROL REQUESTS.                        *
  8233.  ; *                                                                     *
  8234.  ; ***********************************************************************
  8235.  
  8236.  CONTROL PROC    NEAR
  8237.          CMP     AH,00H                  ;STOP REQUEST?
  8238.          JNE     CNTL_START              ; NO, CHECK START
  8239.          PUSH    DS                      ;SAVE REGISTERS
  8240.          PUSH    BX                      ; .
  8241.          PUSH    CS                      ;SET DS FOR OUR ROUTINE
  8242.          POP     DS
  8243.          MOV     STATUS,0                ;TURN PROCESSING OFF
  8244.          MOV     BX,BUFPNTR              ;PLACE STOP MARK IN BUFFER
  8245.          MOV     [BX],BYTE PTR 80H       ; .
  8246.          MOV     [BX+1],BYTE PTR 0FFH    ; .
  8247.          INC     BX                      ;INCREMENT BUFFER POINTER
  8248.          INC     BX                      ; .
  8249.          MOV     BUFPNTR,BX              ; .
  8250.          INC     COUNT                   ;INCREMENT COUNT
  8251.          INC     COUNT                   ; .
  8252.          POP     BX                      ;RESTORE REGISTERS
  8253.          POP     DS                      ; .
  8254.          JMP     CONTROL_DONE
  8255.  
  8256.  CNTL_START:
  8257.          CMP     AH,01H                  ;START REQUEST?
  8258.          JNE     CNTL_RESUME             ; NO, CHECK RESUME
  8259.          MOV     CS:PORT,DL              ;SAVE PORT TO TRACE
  8260.          MOV     CS:BUFPNTR,OFFSET VECTOR_INIT ;RESET BUFFER TO START
  8261.          MOV     CS:COUNT,0              ;ZERO COUNT
  8262.          MOV     CS:STATUS,1             ;START LOGGING
  8263.          JMP     CONTROL_DONE
  8264.  
  8265.  CNTL_RESUME:
  8266.          CMP     AH,02H                  ;RESUME REQUEST?
  8267.          JNE     CNTL_STATUS             ; NO, CHECK STATUS
  8268.          CMP     CS:BUFPNTR,0            ;END OF BUFFER CONDITION?
  8269.          JE      CONTROL_DONE            ; YES, DO NOTHING
  8270.          MOV     CS:PORT,DL              ;SAVE PORT TO TRACE
  8271.          MOV     CS:STATUS,1             ;START LOGGING
  8272.          JMP     CONTROL_DONE
  8273.  
  8274.  CNTL_STATUS:
  8275.          CMP     AH,03H                  ;RETURN STATUS REQUEST?
  8276.          JNE     CONTROL_DONE            ; NO, ERROR -- DO NOTHING
  8277.          MOV     CX,CS:COUNT             ;RETURN COUNT
  8278.          PUSH    CS                      ;RETURN SEGMENT ADDR OF BUFFER
  8279.          POP     DX                      ; .
  8280.          MOV     BX,OFFSET VECTOR_INIT   ;RETURN OFFSET ADDR OF BUFFER
  8281.  
  8282.  CONTROL_DONE:
  8283.          IRET
  8284.  
  8285.  CONTROL ENDP
  8286.  
  8287.  
  8288.          SUBTTL     INITIALIZE INTERRUPT VECTORS
  8289.  PAGE
  8290.  ; ***********************************************************************
  8291.  ; *                                                                     *
  8292.  ; *  VECTOR_INIT                                                        *
  8293.  ; *     THIS PROCEDURE INITIALIZES THE INTERRUPT VECTORS AND THEN       *
  8294.  ; *     EXITS VIA THE MS-DOS TERMINATE-AND-STAY-RESIDENT FUNCTION.      *
  8295.  ; *     A BUFFER OF 64K IS RETAINED.  THE FIRST AVAILABLE BYTE          *
  8296.  ; *     IN THE BUFFER IS THE OFFSET OF VECTOR_INIT.                     *
  8297.  ; *                                                                     *
  8298.  ; ***********************************************************************
  8299.  
  8300.          EVEN                    ;ASSURE BUFFER ON EVEN BOUNDARY
  8301.  VECTOR_INIT     PROC     NEAR
  8302.  ;
  8303.  ;  GET ADDRESS OF COMM VECTOR (INT 14H)
  8304.  ;
  8305.          MOV     AH,35H
  8306.          MOV     AL,14H
  8307.          INT     21H
  8308.  ;
  8309.  ;  SAVE OLD COMM INT ADDRESS
  8310.  ;
  8311.          MOV     WORD PTR OLD_COMM_INT,BX
  8312.          MOV     AX,ES
  8313.          MOV     WORD PTR OLD_COMM_INT[2],AX
  8314.  ;
  8315.  ;  SET UP COMM INT TO POINT TO OUR ROUTINE
  8316.  ;
  8317.          MOV     DX,OFFSET COMMSCOPE
  8318.          MOV     AH,25H
  8319.          MOV     AL,14H
  8320.          INT     21H
  8321.  ;
  8322.  ;  INSTALL CONTROL ROUTINE INT
  8323.  ;
  8324.          MOV     DX,OFFSET CONTROL
  8325.          MOV     AH,25H
  8326.          MOV     AL,COMMSCOPE_INT
  8327.          INT     21H
  8328.  ;
  8329.  ;  SET LENGTH TO 64K, EXIT AND STAY RESIDENT
  8330.  ;
  8331.          MOV     AX,3100H          ;TERM AND STAY RES COMMAND
  8332.          MOV     DX,1000H          ;64K RESERVED
  8333.          INT     21H               ;DONE
  8334.  VECTOR_INIT ENDP
  8335.  CSEG    ENDS
  8336.          END     INITIALIZE
  8337.  
  8338.  \SAMPCODE\DOS_ENCY\18\TESTCOM1.ASM
  8339.  
  8340.          TITLE TESTCOMM -- TEST COMMSCOP ROUTINE
  8341.  ; ***********************************************************************
  8342.  ; *                                                                     *
  8343.  ; *  TESTCOMM                                                           *
  8344.  ; *     THIS ROUTINE PROVIDES DATA FOR THE COMMSCOP ROUTINE.  IT READS  *
  8345.  ; *     CHARACTERS FROM THE KEYBOARD AND WRITES THEM TO COM1 USING      *
  8346.  ; *     INT 14H.  DATA IS ALSO READ FROM INT 14H AND DISPLAYED ON THE   *
  8347.  ; *     SCREEN.  THE ROUTINE RETURNS TO MS-DOS WHEN Ctrl-C IS PRESSED   *
  8348.  ; *     ON THE KEYBOARD.                                                *
  8349.  ; *                                                                     *
  8350.  ; ***********************************************************************
  8351.  
  8352.  SSEG    SEGMENT PARA STACK 'STACK'
  8353.          DW      128 DUP(?)
  8354.  SSEG    ENDS
  8355.  
  8356.  CSEG    SEGMENT
  8357.          ASSUME  CS:CSEG,SS:SSEG
  8358.  BEGIN   PROC    FAR
  8359.          PUSH    DS                      ;SET UP FOR RET TO MS-DOS
  8360.          XOR     AX,AX                   ; .
  8361.          PUSH    AX                      ; .
  8362.  
  8363.  MAINLOOP:
  8364.          MOV     AH,6                    ;USE MS-DOS CALL TO CHECK FOR
  8365.          MOV     DL,0FFH                 ; KEYBOARD ACTIVITY
  8366.          INT     21                      ; IF NO CHARACTER, JUMP TO
  8367.          JZ      TESTCOMM                ; COMM ACTIVITY TEST
  8368.  
  8369.          CMP     AL,03                   ;WAS CHARACTER A Ctrl-C?
  8370.          JNE     SENDCOMM                ; NO, SEND IT TO SERIAL PORT
  8371.          RET                             ; YES, RETURN TO MS-DOS
  8372.  
  8373.  SENDCOMM:
  8374.          MOV     AH,01                   ;USE INT 14H WRITE FUNCTION TO
  8375.          MOV     DX,0                    ; SEND DATA TO SERIAL PORT
  8376.          INT     14H                     ; .
  8377.  
  8378.  TESTCOMM:
  8379.          MOV     AH,3                    ;GET SERIAL PORT STATUS
  8380.          MOV     DX,0                    ; .
  8381.          INT     14H                     ; .
  8382.          AND     AH,1                    ;ANY DATA WAITING?
  8383.          JZ      MAINLOOP                ; NO, GO BACK TO KEYBOARD TEST
  8384.          MOV     AH,2                    ;READ SERIAL DATA
  8385.          MOV     DX,0                    ; .
  8386.          INT     14H                     ; .
  8387.          MOV     AH,6                    ;WRITE SERIAL DATA TO SCREEN
  8388.          INT     21H                     ; .
  8389.          JMP     MAINLOOP                ;CONTINUE
  8390.  
  8391.  BEGIN   ENDP
  8392.  CSEG    ENDS
  8393.          END     BEGIN
  8394.  
  8395.  \SAMPCODE\DOS_ENCY\18\TESTCOM2.ASM
  8396.  
  8397.       TITLE TESTCOMM -- TEST COMMSCOP ROUTINE
  8398.  ; ***********************************************************************
  8399.  ; *                                                                     *
  8400.  ; *  TESTCOMM                                                           *
  8401.  ; *     THIS ROUTINE PROVIDES DATA FOR THE COMMSCOP ROUTINE.  IT READS  *
  8402.  ; *  CHARACTERS FROM THE KEYBOARD AND WRITES THEM TO COM1 USING         *
  8403.  ; *  INT 14H.  DATA IS ALSO READ FROM INT 14H AND DISPLAYED ON THE      *
  8404.  ; *  SCREEN.  THE ROUTINE RETURNS TO MS-DOS WHEN Ctrl-C IS PRESSED      *
  8405.  ; *  ON THE KEYBOARD.                                                   *
  8406.  ; *                                                                     *
  8407.  ; ***********************************************************************
  8408.  
  8409.  SSEG    SEGMENT PARA STACK 'STACK'
  8410.          DW      128 DUP(?)
  8411.  SSEG    ENDS
  8412.  
  8413.  CSEG    SEGMENT
  8414.          ASSUME  CS:CSEG,SS:SSEG
  8415.  BEGIN   PROC    FAR
  8416.          PUSH    DS                      ;SET UP FOR RET TO MS-DOS
  8417.          XOR     AX,AX                   ; .
  8418.          PUSH    AX                      ; .
  8419.  
  8420.  MAINLOOP:
  8421.          MOV     AH,6                    ;USE DOS CALL TO CHECK FOR
  8422.          MOV     DL,0FFH                 ; KEYBOARD ACTIVITY
  8423.          INT     21H                     ; IF NO CHARACTER, JUMP TO
  8424.          JZ      TESTCOMM                ; COMM ACTIVITY TEST
  8425.  
  8426.          CMP     AL,03                   ;WAS CHARACTER A Ctrl-C?
  8427.          JNE     SENDCOMM                ; NO, SEND IT TO SERIAL PORT
  8428.          RET                             ; YES, RETURN TO MS-DOS
  8429.  
  8430.  SENDCOMM:
  8431.          MOV     AH,01                   ;USE INT 14H WRITE FUNCTION TO
  8432.          MOV     DX,0                    ; SEND DATA TO SERIAL PORT
  8433.          INT     14H                     ; .
  8434.  
  8435.  TESTCOMM:
  8436.          MOV     AH,3                    ;GET SERIAL PORT STATUS
  8437.          MOV     DX,0                    ; .
  8438.          INT     14H                     ; .
  8439.          AND     AH,1                    ;ANY DATA WAITING?
  8440.          JZ      MAINLOOP                ; NO, GO BACK TO KEYBOARD TEST
  8441.          MOV     AH,2                    ;READ SERIAL DATA
  8442.          MOV     DX,0                    ; .
  8443.          INT     14H                     ; .
  8444.          MOV     AH,6                    ;WRITE SERIAL DATA TO SCREEN
  8445.          MOV     DL,AL                   ; .
  8446.          INT     21H                     ; .
  8447.          JMP     MAINLOOP                ;CONTINUE
  8448.  
  8449.  BEGIN   ENDP
  8450.  CSEG    ENDS
  8451.          END     BEGIN
  8452.  
  8453.  \SAMPCODE\DOS_ENCY\18\COMMDUMP.BAS
  8454.  
  8455.  ' **********************************************************************
  8456.  ' *                                                                    *
  8457.  ' *  COMMDUMP                                                          *
  8458.  ' *                                                                    *
  8459.  ' *  This routine dumps the contents of the COMMSCOP trace buffer to   *
  8460.  ' *  the screen in a formatted manner.  Received data is shown in      *
  8461.  ' *  reverse video.  Where possible, the ASCII character for the byte  *
  8462.  ' *  is shown; otherwise a dot is shown.  The value of the byte is     *
  8463.  ' *  displayed in hex below the character.  Points where tracing was   *
  8464.  ' *  stopped are shown by a solid bar.                                 *
  8465.  ' *                                                                    *
  8466.  ' **********************************************************************
  8467.  
  8468.          '
  8469.          '  Establish system constants and variables
  8470.          '
  8471.          DEFINT A-Z
  8472.  
  8473.          DIM INREG(7), OUTREG(7)         'Define register arrays
  8474.  
  8475.          RAX = 0                         'Establish values for 8086
  8476.          RBX = 1                         ' registers
  8477.          RCX = 2                         '  .
  8478.          RDX = 3                         '  .
  8479.          RBP = 4                         '  .
  8480.          RSI = 5                         '  .
  8481.          RDI = 6                         '  .
  8482.          RFL = 7                         '  .
  8483.  
  8484.          '
  8485.          '  Interrogate COMMSCOP to obtain addresses and count of data in
  8486.          '  trace buffer
  8487.          '
  8488.          INREG(RAX) = &H0300             'Request address data and count
  8489.          CALL INT86(&H60, VARPTR(INREG(0)), VARPTR(OUTREG(0)))
  8490.  
  8491.          NUM = OUTREG(RCX)               'Number of bytes in buffer
  8492.          BUFSEG = OUTREG(RDX)            'Buffer segment address
  8493.          BUFOFF = OUTREG(RBX)            'Offset of buffer start
  8494.  
  8495.          IF NUM = 0 THEN END
  8496.  
  8497.          '
  8498.          '  Set screen up and display control data
  8499.          '
  8500.          CLS
  8501.          KEY OFF
  8502.          LOCATE 25, 1
  8503.          PRINT "NUM ="; NUM;"BUFSEG = "; HEX$(BUFSEG); " BUFOFF = ";
  8504.          PRINT HEX$(BUFOFF);
  8505.          LOCATE 4, 1
  8506.          PRINT STRING$(80,"-")
  8507.          DEF SEG = BUFSEG
  8508.  
  8509.          '
  8510.          '  Set up display control variables
  8511.          '
  8512.          DLINE = 1
  8513.          DCOL = 1
  8514.          DSHOWN = 0
  8515.  
  8516.          '
  8517.          '  Fetch and display each character in buffer
  8518.          '
  8519.          FOR I= BUFOFF TO BUFOFF+NUM-2 STEP 2
  8520.              STAT = PEEK(I)
  8521.              DAT = PEEK(I + 1)
  8522.  
  8523.              IF (STAT AND 1) = 0 THEN
  8524.                  COLOR 7, 0
  8525.              ELSE
  8526.                  COLOR 0, 7
  8527.              END IF
  8528.  
  8529.              RLINE = (DLINE-1) * 4 + 1
  8530.              IF (STAT AND &H80) = 0 THEN
  8531.                  LOCATE RLINE, DCOL
  8532.                  C$ = CHR$(DAT)
  8533.                  IF DAT < 32 THEN C$ = "."
  8534.                  PRINT C$;
  8535.                  H$ = RIGHT$("00" + HEX$(DAT), 2)
  8536.                  LOCATE RLINE + 1, DCOL
  8537.                  PRINT LEFT$(H$, 1);
  8538.                  LOCATE RLINE + 2, DCOL
  8539.                  PRINT RIGHT$(H$, 1);
  8540.              ELSE
  8541.                  LOCATE RLINE, DCOL
  8542.                  PRINT CHR$(178);
  8543.                  LOCATE RLINE + 1, DCOL
  8544.                  PRINT CHR$(178);
  8545.                  LOCATE RLINE + 2, DCOL
  8546.                  PRINT CHR$(178);
  8547.              END IF
  8548.  
  8549.              DCOL = DCOL + 1
  8550.              IF DCOL > 80 THEN
  8551.                  COLOR 7, 0
  8552.                  DCOL = 1
  8553.                  DLINE = DLINE + 1
  8554.                  SHOWN = SHOWN + 1
  8555.                  IF SHOWN = 6 THEN
  8556.                      LOCATE 25, 50
  8557.                      COLOR 0, 7
  8558.                      PRINT "ENTER ANY KEY TO CONTINUE:  ";
  8559.                      WHILE LEN(INKEY$) = 0
  8560.                      WEND
  8561.                      COLOR 7, 0
  8562.                      LOCATE 25, 50
  8563.                      PRINT SPACE$(29);
  8564.                      SHOWN = 0
  8565.                  END IF
  8566.                  IF DLINE > 6 THEN
  8567.                      LOCATE 24, 1
  8568.                      PRINT : PRINT : PRINT : PRINT
  8569.                      LOCATE 24, 1
  8570.                      PRINT STRING$(80, "-");
  8571.                      DLINE = 6
  8572.                  ELSE
  8573.                      LOCATE DLINE * 4, 1
  8574.                      PRINT STRING$(80, "-");
  8575.                  END IF
  8576.              END IF
  8577.  
  8578.          NEXT I
  8579.  
  8580.          END
  8581.  
  8582.  \SAMPCODE\DOS_ENCY\18\COMMSCMD.BAS
  8583.  
  8584.  ' ************************************************************************
  8585.  ' *                                                                      *
  8586.  ' *  COMMSCMD                                                            *
  8587.  ' *                                                                      *
  8588.  ' *  This routine controls the COMMSCOP program that has been in-        *
  8589.  ' *  stalled as a resident routine.  The operation performed is de-      *
  8590.  ' *  termined by the command line.  The COMMSCMD program is invoked      *
  8591.  ' *  as follows:                                                         *
  8592.  ' *                                                                      *
  8593.  ' *             COMMSCMD [[cmd][,port]]                                  *
  8594.  ' *                                                                      *
  8595.  ' *  where cmd is the command to be executed                             *
  8596.  ' *             STOP   -- stop trace                                     *
  8597.  ' *             START  -- flush trace buffer and start trace             *
  8598.  ' *             RESUME -- resume a stopped trace                         *
  8599.  ' *        port is the COMM  port to be traced (1=COM1, 2=COM2, etc.)    *
  8600.  ' *                                                                      *
  8601.  ' *  If cmd is omitted, STOP is assumed.  If port is omitted, 1 is       *
  8602.  ' *  assumed.                                                            *
  8603.  ' *                                                                      *
  8604.  ' ************************************************************************
  8605.  
  8606.          '
  8607.          '  Establish system constants and variables
  8608.          '
  8609.          DEFINT A-Z
  8610.  
  8611.          DIM INREG(7), OUTREG(7)         'Define register arrays
  8612.  
  8613.          RAX = 0                         'Establish values for 8086
  8614.          RBX = 1                         '  registers
  8615.          RCX = 2                         '  .
  8616.          RDX = 3                         '  .
  8617.          RBP = 4                         '  .
  8618.          RSI = 5                         '  .
  8619.          RDI = 6                         '  .
  8620.          RFL = 7                         '  .
  8621.  
  8622.          DIM TEXT$(2)
  8623.  
  8624.          TEXT$(0) = "STOPPED"
  8625.          TEXT$(1) = "STARTED"
  8626.          TEXT$(2) = "RESUMED"
  8627.  
  8628.          '
  8629.          '  Process command-line tail
  8630.          '
  8631.          C$ = COMMAND$                   'Get command-line data
  8632.  
  8633.          IF LEN(C$) = 0 THEN             'If no command line specified
  8634.              CMD = 0                     'Set CMD to STOP
  8635.              PORT = 0                    'Set PORT to COM1
  8636.              GOTO SENDCMD
  8637.          END IF
  8638.  
  8639.          COMMA = INSTR(C$, ", ")         'Extract operands
  8640.          IF COMMA = 0 THEN
  8641.              CMDTXT$ = C$
  8642.              PORT = 0
  8643.          ELSE
  8644.              CMDTXT$ = LEFT$(C$, COMMA - 1)
  8645.              PORT = VAL(MID$(C$, COMMA + 1)) - 1
  8646.          END IF
  8647.  
  8648.          IF PORT < 0 THEN PORT = 0
  8649.  
  8650.          IF CMDTXT$ = "STOP" THEN
  8651.              CMD = 0
  8652.          ELSEIF CMDTXT$ = "START" THEN
  8653.              CMD = 1
  8654.          ELSEIF CMDTXT$ = "RESUME" THEN
  8655.              CMD = 2
  8656.          ELSE
  8657.              CMD = 0
  8658.          END IF
  8659.  
  8660.          '
  8661.          '  Send command to COMMSCOP routine
  8662.          '
  8663.  SENDCMD:
  8664.          INREG(RAX) = 256 * CMD
  8665.          INREG(RDX) = PORT
  8666.          CALL INT86(&H60, VARPTR(INREG(0)), VARPTR(OUTREG(0)))
  8667.          '
  8668.          '  Notify user that action is complete
  8669.          '
  8670.          PRINT : PRINT
  8671.          PRINT "Communications tracing "; TEXT$(CMD);
  8672.          IF CMD <> 0 THEN
  8673.              PRINT " for port COM"; MID$(STR$(PORT + 1), 2); ":"
  8674.          ELSE
  8675.              PRINT
  8676.          END IF
  8677.  
  8678.          END
  8679.  
  8680.  \SAMPCODE\DOS_ENCY\18\EXP1.BAS
  8681.  
  8682.  '  EXP.BAS -- COMPUTE EXPONENTIAL WITH INFINITE SERIES
  8683.  '
  8684.  ' ***********************************************************************
  8685.  ' *                                                                     *
  8686.  ' *  EXP                                                                *
  8687.  ' *                                                                     *
  8688.  ' *  This routine computes EXP(x) using the following infinite series:  *
  8689.  ' *                                                                     *
  8690.  ' *                       x    x^2   x^3   x^4   x^5                    *
  8691.  ' *         EXP(x) = 1 + --- + --- + --- + --- + --- + ...              *
  8692.  ' *                       1!    2!    3!    4!    5!                    *
  8693.  ' *                                                                     *
  8694.  ' *                                                                     *
  8695.  ' *  The program requests a value for x and a value for the convergence *
  8696.  ' *  criterion, C.  The program will continue evaluating the terms of   *
  8697.  ' *  the series until the difference between two terms is less than C.  *
  8698.  ' *                                                                     *
  8699.  ' *  The result of the calculation and the number of terms required to  *
  8700.  ' *  converge are printed.  The program will repeat until an x of 0 is  *
  8701.  ' *  entered.                                                           *
  8702.  ' *                                                                     *
  8703.  ' ***********************************************************************
  8704.  
  8705.  '
  8706.  '  Initialize program variables
  8707.  '
  8708.  INITIALIZE:
  8709.          TERMS = 1
  8710.          FACT = 1
  8711.          LAST = 1.E35
  8712.          DELTA = 1.E34
  8713.          EX = 1
  8714.  '
  8715.  '  Input user data
  8716.  '
  8717.          INPUT "Enter number:  "; X
  8718.          IF X = 0 THEN END
  8719.          INPUT "Enter convergence criterion (.0001 for 4 places):  "; C
  8720.  
  8721.  '
  8722.  '  Compute exponential until difference of last 2 terms is < C
  8723.  '
  8724.          WHILE ABS(LAST - DELTA) >= C
  8725.              LAST = DELTA
  8726.              FACT = FACT * TERMS
  8727.              DELTA = X^TERMS / FACT
  8728.              EX = EX + DELTA
  8729.              TERMS = TERMS + 1
  8730.          WEND
  8731.  
  8732.  '
  8733.  '  Display answer and number of terms required to converge
  8734.  '
  8735.          PRINT EX
  8736.          PRINT TERMS; "elements required to converge"
  8737.          PRINT
  8738.  
  8739.          GOTO INITIALIZE
  8740.  
  8741.  \SAMPCODE\DOS_ENCY\18\EXP2.BAS
  8742.  
  8743.  '  EXP.BAS -- COMPUTE EXPONENTIAL WITH INFINITE SERIES
  8744.  '
  8745.  ' ***********************************************************************
  8746.  ' *                                                                     *
  8747.  ' *  EXP                                                                *
  8748.  ' *                                                                     *
  8749.  ' *  This routine computes EXP(x) using the following infinite series:  *
  8750.  ' *                                                                     *
  8751.  ' *                       x    x^2   x^3   x^4   x^5                    *
  8752.  ' *         EXP(x) = 1 + --- + --- + --- + --- + --- + ...              *
  8753.  ' *                       1!    2!    3!    4!    5!                    *
  8754.  ' *                                                                     *
  8755.  ' *                                                                     *
  8756.  ' *  The program requests a value for x and a value for the convergence *
  8757.  ' *  criterion, C.  The program will continue evaluating the terms of   *
  8758.  ' *  the series until the amount added with a term is less than C.      *
  8759.  ' *                                                                     *
  8760.  ' *  The result of the calculation and the number of terms required to  *
  8761.  ' *  converge are printed.  The program will repeat until an x of 0 is  *
  8762.  ' *  entered.                                                           *
  8763.  ' *                                                                     *
  8764.  ' ***********************************************************************
  8765.  
  8766.  '
  8767.  '  INITIALIZE program variables
  8768.  '
  8769.  Initialize:
  8770.          TERMS = 1
  8771.          FACT = 1
  8772.          DELTA = 1.E35
  8773.          EX = 1
  8774.  '
  8775.  '  Input user data
  8776.  '
  8777.          INPUT "Enter number:  "; X
  8778.          IF X = 0 THEN END
  8779.          INPUT "Enter convergence criterion (.0001 for 4 places):  "; C
  8780.  
  8781.  '
  8782.  '  Compute exponential until difference of last 2 terms is < C
  8783.  '
  8784.          WHILE DELTA > C
  8785.              FACT = FACT * TERMS
  8786.              DELTA = X^TERMS / FACT
  8787.              EX = EX + DELTA
  8788.              TERMS = TERMS + 1
  8789.          WEND
  8790.  
  8791.  '
  8792.  '  Display answer and number of terms required to converge
  8793.  '
  8794.          PRINT EX
  8795.          PRINT TERMS; "elements required to converge"
  8796.          PRINT
  8797.  
  8798.          GOTO INITIALIZE
  8799.  
  8800.  \SAMPCODE\DOS_ENCY\19
  8801.  \SAMPCODE\DOS_ENCY\19\HELLO.ASM
  8802.  
  8803.          NAME    HELLO
  8804.  
  8805.  _TEXT   SEGMENT byte public 'CODE'
  8806.  
  8807.          ASSUME  cs:_TEXT,ds:_DATA
  8808.  
  8809.  start:                                  ;program entry point
  8810.          mov     ax,seg msg
  8811.          mov     ds,ax
  8812.          mov     dx,offset msg           ;DS:DX -> msg
  8813.          mov     ah,09h
  8814.          int     21h                     ;perform int 21H function 09H
  8815.                                          ;(Output character string)
  8816.          mov     ax,4C00h
  8817.          int     21h                     ;perform int 21H function 4CH
  8818.                                          ;(Terminate with return code)
  8819.  _TEXT   ENDS
  8820.  
  8821.  
  8822.  _DATA   SEGMENT word public 'DATA'
  8823.  
  8824.  msg     DB      'Hello, world',0Dh,0Ah,'$'
  8825.  
  8826.  _DATA   ENDS
  8827.  
  8828.  
  8829.  _STACK  SEGMENT stack 'STACK'
  8830.  
  8831.          DW      80h dup(?)              ;stack depth = 128 words
  8832.  
  8833.  _STACK  ENDS
  8834.  
  8835.          END     start
  8836.  
  8837.  \SAMPCODE\DOS_ENCY\2
  8838.  \SAMPCODE\DOS_ENCY\2\SHELL.ASM
  8839.  
  8840.  ; SHELL.ASM   A simple program to run an application as an
  8841.  ;             MS-DOS shell program. The program name and
  8842.  ;             startup parameters must be adjusted before
  8843.  ;             SHELL is assembled.
  8844.  ;
  8845.  ; Written by William Wong
  8846.  ;
  8847.  ; To create SHELL.COM:
  8848.  ;
  8849.  ;             C>MASM SHELL;
  8850.  ;             C>LINK SHELL;
  8851.  ;             C>EXE2BIN SHELL.EXE SHELL.COM
  8852.  
  8853.  stderr  equ 2                ; standard error
  8854.  cr      equ 0dh              ; ASCII carriage return
  8855.  lf      equ 0ah              ; ASCII linefeed
  8856.  cseg    segment para public 'CODE'
  8857.  ;
  8858.  ; ----  Set up DS, ES, and SS:SP to run as .COM  ----
  8859.  ;
  8860.          assume  cs:cseg
  8861.  start   proc    far
  8862.          mov     ax,cs           ; set up segment registers
  8863.          add     ax,10h          ; AX = segment after PSP
  8864.          mov     ds,ax
  8865.          mov     ss,ax           ; set up stack pointer
  8866.          mov     sp,offset stk
  8867.          mov     ax,offset shell
  8868.          push    cs              ; push original CS
  8869.          push    ds              ; push segment of shell
  8870.          push    ax              ; push offset of shell
  8871.          ret                     ; jump to shell
  8872.  start   endp
  8873.  ;
  8874.  ; ----  Main program running as .COM  ----
  8875.  ;
  8876.  ; CS, DS, SS = cseg
  8877.  ; Original CS value on top of stack
  8878.  ;
  8879.          assume cs:cseg,ds:cseg,ss:cseg
  8880.  seg_size equ (((offset last) - (offset start)) + 10fh)/16
  8881.  shell   proc    near
  8882.          pop     es              ; ES = segment to shrink
  8883.          mov     bx,seg_size     ; BX = new segment size
  8884.          mov     ah,4ah          ; AH = modify memory block
  8885.          int     21h             ; free excess memory
  8886.          mov     cmd_seg,ds      ; setup segments in
  8887.          mov     fcb1_seg,ds     ; parameter block for EXEC
  8888.          mov     fcb2_seg,ds
  8889.          mov     dx,offset main_loop
  8890.          mov     ax,2523h        ; AX = set Control-C handler
  8891.          int     21h             ; set handler to DS:DX
  8892.          mov     dx,offset main_loop
  8893.          mov     ax,2524h        ; AX = set critical error handler
  8894.          int     21h             ; set handler to DS:DX
  8895.                                  ; Note: DS is equal to CS
  8896.  main_loop:
  8897.          push    ds              ; save segment registers
  8898.          push    es
  8899.          mov     cs:stk_seg,ss   ; save stack pointer
  8900.          mov     cs:stk_off,sp
  8901.          mov     dx,offset pgm_name
  8902.          mov     bx,offset par_blk
  8903.          mov     ax,4b00h        ; AX = EXEC/run program
  8904.          int     21h             ; carry = EXEC failed
  8905.          mov     ss,cs:stk_seg   ; restore stack pointer
  8906.          mov     sp,cs:stk_off
  8907.          pop     es              ; restore segment registers
  8908.          pop     ds
  8909.          jnc     main_loop       ; loop if program run
  8910.          mov     dx,offset load_msg
  8911.          mov     cx,load_msg_length
  8912.          call    print           ; display error message
  8913.          mov     ah,08h          ; AH = read without echo
  8914.          int     21h             ; wait for any character
  8915.          jmp     main_loop       ; execute forever
  8916.  shell   endp
  8917.  ;
  8918.  ; ----  Print string  ----
  8919.  ;
  8920.  ; DS:DX = address of string
  8921.  ; CX    = size
  8922.  ;
  8923.  print   proc    near
  8924.          mov     ah,40h          ; AH = write to file
  8925.          mov     bx,stderr       ; BX = file handle
  8926.          int     21h             ; print string
  8927.          ret
  8928.  print   endp
  8929.  ;
  8930.  ; ----  Message strings  ----
  8931.  ;
  8932.  load_msg db cr,lf
  8933.           db 'Cannot load program.',cr,lf
  8934.           db 'Press any key to try again.',cr,lf
  8935.  load_msg_length equ $-load_msg
  8936.  ;
  8937.  ; ----  Program data area  ----
  8938.  ;
  8939.  stk_seg  dw     0               ; stack segment pointer
  8940.  stk_off  dw     0               ; save area during EXEC
  8941.  pgm_name db     '\NEWSHELL.COM',0 ; any program will do
  8942.  par_blk  dw     0               ; use current environment
  8943.           dw     offset cmd_line ; command-line address
  8944.  cmd_seg  dw     0               ; fill in at initialization
  8945.           dw     offset fcb1     ; default FCB #1
  8946.  fcb1_seg dw     0               ; fill in at initialization
  8947.           dw     offset fcb2     ; default FCB #2
  8948.  fcb2_seg dw     0               ; fill in at initialization
  8949.  cmd_line db     0,cr            ; actual command line
  8950.  fcb1     db     0
  8951.           db     11 dup (' ')
  8952.           db     25 dup ( 0 )
  8953.  fcb2     db     0
  8954.           db     11 dup (' ')
  8955.           db     25 dup ( 0 )
  8956.           dw     200 dup ( 0 )   ; program stack area
  8957.  stk      dw     0
  8958.  last     equ    $               ; last address used
  8959.  cseg     ends
  8960.           end    start
  8961.  
  8962.  \SAMPCODE\DOS_ENCY\4
  8963.  \SAMPCODE\DOS_ENCY\4\FIG4_10.ASM
  8964.  
  8965.  ;Source Module MODULE_C
  8966.  
  8967.  ;Constant declarations ******************************************************
  8968.  
  8969.  CONST   SEGMENT WORD PUBLIC 'CONST'
  8970.  
  8971.  CONST_FIELD_C   DB      'Constant C'    ;declare a MODULE_C constant
  8972.  
  8973.  CONST   ENDS
  8974.  
  8975.  
  8976.  ;Preinitialized data fields *************************************************
  8977.  
  8978.  _DATA   SEGMENT WORD PUBLIC 'DATA'
  8979.  
  8980.  DATA_FIELD_C    DB      'Data C'        ;declare a MODULE_C preinitialized fi
  8981.  
  8982.  _DATA   ENDS
  8983.  
  8984.  
  8985.  ;Uninitialized data fields **************************************************
  8986.  
  8987.  _BSS    SEGMENT WORD PUBLIC 'BSS'
  8988.  
  8989.  BSS_FIELD_C     DB      5 DUP(?)        ;declare a MODULE_C uninitialized fie
  8990.  
  8991.  _BSS    ENDS
  8992.  
  8993.  
  8994.  ;Program text ***************************************************************
  8995.  
  8996.  DGROUP  GROUP   _DATA,CONST,_BSS
  8997.  
  8998.  _TEXT   SEGMENT BYTE PUBLIC 'CODE'
  8999.  
  9000.          ASSUME  CS:_TEXT,DS:DGROUP,ES:NOTHING,SS:NOTHING
  9001.  
  9002.          PUBLIC  PROC_C                  ;referenced in MODULE_A
  9003.  PROC_C  PROC    NEAR
  9004.  
  9005.          RET
  9006.  
  9007.  PROC_C  ENDP
  9008.  
  9009.  _TEXT   ENDS
  9010.  
  9011.          END
  9012.  
  9013.  \SAMPCODE\DOS_ENCY\4\FIG4_15.ASM
  9014.  
  9015.  COMSEG  SEGMENT BYTE PUBLIC 'CODE'
  9016.          ASSUME  CS:COMSEG,DS:COMSEG,ES:COMSEG,SS:COMSEG
  9017.          ORG     0100H
  9018.  
  9019.  BEGIN:
  9020.          JMP     START           ;skip over data fields
  9021.  ;Place your data fields here.
  9022.  
  9023.  START:
  9024.  ;Place your program text here.
  9025.          MOV     AX,4C00H        ;terminate (MS-DOS 2.0 or later only)
  9026.          INT     21H
  9027.  COMSEG  ENDS
  9028.          END     BEGIN
  9029.  
  9030.  \SAMPCODE\DOS_ENCY\4\FIG4_16.ASM
  9031.  
  9032.  CSEG    SEGMENT BYTE PUBLIC 'CODE'      ;establish segment order
  9033.  CSEG    ENDS
  9034.  DSEG    SEGMENT BYTE PUBLIC 'DATA'
  9035.  DSEG    ENDS
  9036.  COMGRP  GROUP   CSEG,DSEG               ;establish joint address base
  9037.  DSEG    SEGMENT
  9038.  ;Place your data fields here.
  9039.  DSEG    ENDS
  9040.  CSEG    SEGMENT
  9041.  
  9042.          ASSUME  CS:COMGRP,DS:COMGRP,ES:COMGRP,SS:COMGRP
  9043.          ORG     0100H
  9044.  
  9045.  BEGIN:
  9046.  ;Place your program text here.  Remember to use
  9047.  ;OFFSET COMGRP:LABEL whenever you use OFFSET.
  9048.          MOV     AX,4C00H                ;terminate (MS-DOS 2.0 or later only)
  9049.          INT     21H
  9050.  CSEG    ENDS
  9051.          END     BEGIN
  9052.  
  9053.  \SAMPCODE\DOS_ENCY\4\FIG4_3.ASM
  9054.  
  9055.  TEXT    SEGMENT PARA PUBLIC 'CODE'
  9056.  
  9057.          ASSUME  CS:TEXT,DS:NOTHING,ES:NOTHING,SS:NOTHING
  9058.  
  9059.  TERM_VECTOR     DD      ?
  9060.  
  9061.  ENTRY_PROC      PROC    FAR
  9062.  
  9063.  ;save pointer to termination vector in PSP
  9064.  
  9065.          MOV     WORD PTR CS:TERM_VECTOR+0,0000h ;save offset of Warm Boot vec
  9066.          MOV     WORD PTR CS:TERM_VECTOR+2,DS    ;save segment address of PSP
  9067.  
  9068.  ;***** Place main task here *****
  9069.  
  9070.  ;determine which MS-DOS version is active, take jump if 2.0 or later
  9071.  
  9072.          MOV     AH,30h          ;load Get MS-DOS Version Number function code
  9073.          INT     21h             ;call MS-DOS to get version number
  9074.          OR      AL,AL           ;see if pre-2.0 MS-DOS
  9075.          JNZ     TERM_0200       ;jump if 2.0 or later
  9076.  
  9077.  ;terminate under pre-2.0 MS-DOS
  9078.  
  9079.          JMP     CS:TERM_VECTOR  ;jump to Warm Boot vector in PSP
  9080.  
  9081.  ;terminate under MS-DOS 2.0 or later
  9082.  
  9083.  TERM_0200:
  9084.          MOV     AX,4C00h        ;load MS-DOS termination function code
  9085.                                  ;and return code
  9086.          INT     21h             ;call MS-DOS to terminate
  9087.  
  9088.  ENTRY_PROC      ENDP
  9089.  
  9090.  TEXT    ENDS
  9091.  
  9092.          END     ENTRY_PROC      ;define entry point
  9093.  
  9094.  \SAMPCODE\DOS_ENCY\4\FIG4_4.ASM
  9095.  
  9096.  TEXT    SEGMENT PARA PUBLIC 'CODE'
  9097.  
  9098.          ASSUME  CS:TEXT,DS:NOTHING,ES:NOTHING,SS:NOTHING
  9099.  
  9100.  ENTRY_PROC      PROC    FAR     ;make proc FAR so RET will be FAR
  9101.  
  9102.  ;Push pointer to termination vector in PSP
  9103.          PUSH    DS              ;push PSP's segment address
  9104.          XOR     AX,AX           ;ax = 0 = offset of Warm Boot vector in PSP
  9105.          PUSH    AX              ;push Warm Boot vector offset
  9106.  
  9107.  ;***** Place main task here *****
  9108.  
  9109.  ;Determine which MS-DOS version is active, take jump if 2.0 or later
  9110.  
  9111.          MOV     AH,30h          ;load Get MS-DOS Version Number function code
  9112.          INT     21h             ;call MS-DOS to get version number
  9113.          OR      AL,AL           ;see if pre-2.0 MS-DOS
  9114.          JNZ     TERM_0200       ;jump if 2.0 or later
  9115.  
  9116.  ;Terminate under pre-2.0 MS-DOS (this is a FAR proc, so RET will be FAR)
  9117.          RET                     ;pop PSP:00H into CS:IP to terminate
  9118.  
  9119.  ;Terminate under MS-DOS 2.0 or later
  9120.  TERM_0200:
  9121.          MOV     AX,4C00h        ;AH = MS-DOS Terminate Process with Return Co
  9122.                                  ;function code, AL = return code of 00H
  9123.          INT     21h             ;call MS-DOS to terminate
  9124.  
  9125.  ENTRY_PROC      ENDP
  9126.  
  9127.  TEXT    ENDS
  9128.  
  9129.          END     ENTRY_PROC      ;declare the program's entry point
  9130.  
  9131.  \SAMPCODE\DOS_ENCY\4\FIG4_8.ASM
  9132.  
  9133.  ;Source Module MODULE_A
  9134.  
  9135.  ;Predeclare all segments to force the linker's segment ordering *************
  9136.  
  9137.  _TEXT   SEGMENT BYTE PUBLIC 'CODE'
  9138.  _TEXT   ENDS
  9139.  
  9140.  _DATA   SEGMENT WORD PUBLIC 'DATA'
  9141.  _DATA   ENDS
  9142.  
  9143.  CONST   SEGMENT WORD PUBLIC 'CONST'
  9144.  CONST   ENDS
  9145.  
  9146.  _BSS    SEGMENT WORD PUBLIC 'BSS'
  9147.  _BSS    ENDS
  9148.  
  9149.  STACK   SEGMENT PARA STACK 'STACK'
  9150.  STACK   ENDS
  9151.  
  9152.  DGROUP  GROUP   _DATA,CONST,_BSS,STACK
  9153.  
  9154.  
  9155.  ;Constant declarations ******************************************************
  9156.  
  9157.  CONST   SEGMENT WORD PUBLIC 'CONST'
  9158.  
  9159.  CONST_FIELD_A   DB      'Constant A'    ;declare a MODULE_A constant
  9160.  
  9161.  CONST   ENDS
  9162.  
  9163.  
  9164.  ;Preinitialized data fields *************************************************
  9165.  
  9166.  _DATA   SEGMENT WORD PUBLIC 'DATA'
  9167.  
  9168.  DATA_FIELD_A    DB      'Data A'        ;declare a MODULE_A preinitialized fi
  9169.  
  9170.  _DATA   ENDS
  9171.  
  9172.  
  9173.  ;Uninitialized data fields **************************************************
  9174.  
  9175.  _BSS    SEGMENT WORD PUBLIC 'BSS'
  9176.  
  9177.  BSS_FIELD_A     DB      5 DUP(?)        ;declare a MODULE_A uninitialized fie
  9178.  
  9179.  _BSS    ENDS
  9180.  
  9181.  
  9182.  ;Program text ***************************************************************
  9183.  
  9184.  _TEXT   SEGMENT BYTE PUBLIC 'CODE'
  9185.  
  9186.          ASSUME  CS:_TEXT,DS:DGROUP,ES:NOTHING,SS:NOTHING
  9187.  
  9188.          EXTRN   PROC_B:NEAR             ;label is in _TEXT segment (NEAR)
  9189.          EXTRN   PROC_C:NEAR             ;label is in _TEXT segment (NEAR)
  9190.  
  9191.  PROC_A  PROC    NEAR
  9192.  
  9193.          CALL    PROC_B                  ;call into MODULE_B
  9194.          CALL    PROC_C                  ;call into MODULE_C
  9195.  
  9196.          MOV     AX,4C00H                ;terminate (MS-DOS 2.0 or later only)
  9197.          INT     21H
  9198.  
  9199.  PROC_A  ENDP
  9200.  
  9201.  _TEXT   ENDS
  9202.  
  9203.  
  9204.  ;Stack **********************************************************************
  9205.  
  9206.  STACK   SEGMENT PARA STACK 'STACK'
  9207.  
  9208.          DW      128 DUP(?)      ;declare some space to use as stack
  9209.  STACK_BASE      LABEL   WORD
  9210.  
  9211.  STACK   ENDS
  9212.  
  9213.  
  9214.  
  9215.          END     PROC_A          ;declare PROC_A as entry point
  9216.  
  9217.  \SAMPCODE\DOS_ENCY\4\FIG4_9.ASM
  9218.  
  9219.  ;Source Module MODULE_B
  9220.  
  9221.  ;Constant declarations ******************************************************
  9222.  
  9223.  CONST   SEGMENT WORD PUBLIC 'CONST'
  9224.  
  9225.  CONST_FIELD_B   DB      'Constant B'    ;declare a MODULE_B constant
  9226.  
  9227.  CONST   ENDS
  9228.  
  9229.  
  9230.  ;Preinitialized data fields *************************************************
  9231.  
  9232.  _DATA   SEGMENT WORD PUBLIC 'DATA'
  9233.  
  9234.  DATA_FIELD_B    DB      'Data B'        ;declare a MODULE_B preinitialized fi
  9235.  
  9236.  _DATA   ENDS
  9237.  
  9238.  
  9239.  ;Uninitialized data fields **************************************************
  9240.  
  9241.  _BSS    SEGMENT WORD PUBLIC 'BSS'
  9242.  
  9243.  BSS_FIELD_B     DB      5 DUP(?)        ;declare a MODULE_B uninitialized fie
  9244.  
  9245.  _BSS    ENDS
  9246.  
  9247.  
  9248.  ;Program text ***************************************************************
  9249.  
  9250.  DGROUP  GROUP   _DATA,CONST,_BSS
  9251.  
  9252.  _TEXT   SEGMENT BYTE PUBLIC 'CODE'
  9253.  
  9254.          ASSUME  CS:_TEXT,DS:DGROUP,ES:NOTHING,SS:NOTHING
  9255.  
  9256.          PUBLIC  PROC_B                  ;reference in MODULE_A
  9257.  PROC_B  PROC    NEAR
  9258.  
  9259.          RET
  9260.  
  9261.  PROC_B  ENDP
  9262.  
  9263.  _TEXT   ENDS
  9264.  
  9265.          END
  9266.  
  9267.  \SAMPCODE\DOS_ENCY\5
  9268.  \SAMPCODE\DOS_ENCY\5\FXN02H.ASM
  9269.  
  9270.          mov     ah,02h          ; function 02H = display character
  9271.          mov     dl,'*'          ; DL = character to display
  9272.          int     21h             ; transfer to MS-DOS
  9273.  
  9274.  \SAMPCODE\DOS_ENCY\5\FXN04H.ASM
  9275.  
  9276.  msg     db      'This is a test message'
  9277.  msg_len equ     $-msg
  9278.          .
  9279.          .
  9280.          .
  9281.          mov     bx,seg msg      ; set DS:BX = address of message
  9282.          mov     ds,bx
  9283.          mov     bx,offset msg
  9284.          mov     cx,msg_len      ; set CX = length of message
  9285.  L1:     mov     dl,[bx]         ; get next character into DL
  9286.          mov     ah,04H          ; function 04H = auxiliary output
  9287.          int     21h             ; transfer to MS-DOS
  9288.          inc     bx              ; bump pointer to output string
  9289.          loop    L1              ; and loop until all chars. sent
  9290.  
  9291.  \SAMPCODE\DOS_ENCY\5\FXN05H.ASM
  9292.  
  9293.  msg     db      'This is a test message'
  9294.  msg_len equ     $-msg
  9295.          .
  9296.          .
  9297.          .
  9298.          mov     bx,seg msg      ; DS:BX = address of message
  9299.          mov     ds,bx
  9300.          mov     bx,offset msg
  9301.          mov     cx,msg_len      ; CX = length of message
  9302.  L1:     mov     dl,[bx]         ; get next character into DL
  9303.          mov     ah,05H          ; function 05H = printer output
  9304.          int     21h             ; transfer to MS-DOS
  9305.          inc     bx              ; bump pointer to output string
  9306.          loop    L1              ; and loop until all chars. sent
  9307.  
  9308.  \SAMPCODE\DOS_ENCY\5\FXN08H.ASM
  9309.  
  9310.          mov     ah,08h          ; function 08H = character input
  9311.                                  ;   without echo
  9312.          int     21h             ; transfer to MS-DOS
  9313.                                  ; now AL = character
  9314.  
  9315.  \SAMPCODE\DOS_ENCY\5\FXN09H.ASM
  9316.  
  9317.  msg     db      'This is a test message','$'
  9318.          .
  9319.          .
  9320.          .
  9321.          mov     dx,seg msg      ; DS:DX = address of text
  9322.          mov     ds,dx           ; to display
  9323.          mov     dx,offset msg
  9324.          mov     ah,09H          ; function 09H = display string
  9325.          int     21h             ; transfer to MS-DOS
  9326.  
  9327.  \SAMPCODE\DOS_ENCY\5\FXN0AH.ASM
  9328.  
  9329.  kbuf    db      80              ; maximum length of read
  9330.          db      0               ; actual length of read
  9331.          db      80 dup (0)      ; keyboard input goes here
  9332.          .
  9333.          .
  9334.          .
  9335.          mov     dx,seg kbuf     ; set DS:DX = address of
  9336.          mov     ds,dx           ; keyboard input buffer
  9337.          mov     dx,offset kbuf
  9338.          mov     ah,0ah          ; function 0AH = read buffered line
  9339.          int     21h             ; transfer to MS-DOS
  9340.                                  ; terminated by a carriage return,
  9341.                                  ; and kbuf+1 = length of input,
  9342.                                  ; not including the carriage return
  9343.  
  9344.  \SAMPCODE\DOS_ENCY\5\FXN3FH.ASM
  9345.  
  9346.  kbuf    db      80 dup (0)      ; buffer for keyboard input
  9347.          .
  9348.          .
  9349.          .
  9350.          mov     dx,seg kbuf     ; set DS:DX = address of
  9351.          mov     ds,dx           ; keyboard input buffer
  9352.          mov     dx,offset kbuf
  9353.          mov     cx,80           ; CX = maximum length of input
  9354.          mov     bx,0            ; standard input handle = 0
  9355.          mov     ah,3fh          ; function 3FH = read file/device
  9356.          int     21h             ; transfer to MS-DOS
  9357.          jc      error           ; jump if function failed
  9358.                                  ; otherwise AX = actual
  9359.                                  ; length of keyboard input,
  9360.                                  ; including carriage-return and
  9361.                                  ; linefeed, and the data is
  9362.                                  ; in the buffer 'kbuf'
  9363.  
  9364.  \SAMPCODE\DOS_ENCY\5\FXN40H_1.ASM
  9365.  
  9366.  msg     db      'This is a test message'
  9367.  msg_len equ     $-msg
  9368.          .
  9369.          .
  9370.          .
  9371.          mov     dx,seg msg      ; DS:DX = address of text
  9372.          mov     ds,dx           ; to display
  9373.          mov     dx,offset msg
  9374.          mov     cx,msg_len      ; CX = length of text
  9375.          mov     bx,1            ; BX = handle for standard output
  9376.          mov     ah,40h          ; function 40H = write file/device
  9377.          int     21h             ; transfer to MS-DOS
  9378.  
  9379.  \SAMPCODE\DOS_ENCY\5\FXN40H_2.ASM
  9380.  
  9381.  msg     db      'This is a test message'
  9382.  msg_len equ     $-msg
  9383.          .
  9384.          .
  9385.          .
  9386.          mov     dx,seg msg      ; DS:DX = address of message
  9387.          mov     ds,dx
  9388.          mov     dx,offset msg
  9389.          mov     cx,msg_len      ; CX = length of message
  9390.          mov     bx,3            ; BX = handle for standard aux.
  9391.          mov     ah,40h          ; function 40H = write file/device
  9392.          int     21h             ; transfer to MS-DOS
  9393.          jc      error           ; jump if write operation failed
  9394.  
  9395.  \SAMPCODE\DOS_ENCY\5\FXN40H_3.ASM
  9396.  
  9397.  msg     db      'This is a test message'
  9398.  msg_len equ     $-msg
  9399.          .
  9400.          .
  9401.          .
  9402.          mov     dx,seg msg      ; DS:DX = address of message
  9403.          mov     ds,dx
  9404.          mov     dx,offset msg
  9405.          mov     cx,msg_len      ; CX = length of message
  9406.          mov     bx,4            ; BX = handle for standard printer
  9407.          mov     ah,40h          ; function 40H = write file/device
  9408.          int     21h             ; transfer to MS-DOS
  9409.          jc      error           ; jump if write operation failed
  9410.  
  9411.  \SAMPCODE\DOS_ENCY\5\INT10H.ASM
  9412.  
  9413.          mov     ah,0eh          ; subfunction 0EH = write character
  9414.                                  ; in teletype mode
  9415.          mov     al,'*'          ; AL = character to display
  9416.          mov     bh,0            ; select display page 0
  9417.          int     10h             ; transfer to ROM BIOS video driver
  9418.  
  9419.  \SAMPCODE\DOS_ENCY\5\INT14H.ASM
  9420.  
  9421.  msg     db      'This is a test message'
  9422.  msg_len equ     $-msg
  9423.          .
  9424.          .
  9425.          .
  9426.          mov     bx,seg msg      ; DS:BX = address of message
  9427.          mov     ds,bx
  9428.          mov     bx,offset msg
  9429.          mov     cx,msg_len      ; CX = length of message
  9430.          mov     dx,0            ; DX = 0 for COM1
  9431.  L1:     mov     al,[bx]         ; get next character into AL
  9432.          mov     ah,01h          ; subfunction 01H = output
  9433.          int     14h             ; transfer to ROM BIOS
  9434.          inc     bx              ; bump pointer to output string
  9435.          loop    L1              ; and loop until all chars. sent
  9436.  
  9437.  \SAMPCODE\DOS_ENCY\5\INT16H.ASM
  9438.  
  9439.          mov     ah,00h          ; subfunction 00H = read character
  9440.          int     16h             ; transfer to ROM BIOS
  9441.                                  ; now AH = scan code, AL = character
  9442.  
  9443.  \SAMPCODE\DOS_ENCY\5\INT17H.ASM
  9444.  
  9445.  msg     db      'This is a test message'
  9446.  msg_len equ     $-msg
  9447.          .
  9448.          .
  9449.          .
  9450.          mov     bx,seg msg      ; DS:BX = address of message
  9451.          mov     ds,bx
  9452.          mov     bx,offset msg
  9453.          mov     cx,msg_len      ; CX = length of message
  9454.          mov     dx,0            ; DX = 0 for LPT1
  9455.  L1:     mov     al,[bx]         ; get next character into AL
  9456.          mov     ah,00H          ; subfunction 00H = output
  9457.          int     17h             ; transfer to ROM BIOS
  9458.          inc     bx              ; bump pointer to output string
  9459.          loop    L1              ; and loop until all chars. sent
  9460.  
  9461.  \SAMPCODE\DOS_ENCY\5\IOCTL_1.ASM
  9462.  
  9463.  info    dw      ?               ; save device information word here
  9464.          .
  9465.          .
  9466.          .
  9467.          mov     ax,4400h        ; AH = function 44H, IOCTL
  9468.                                  ; AL = subfunction 00H, get device
  9469.                                  ; information word
  9470.          mov     bx,0            ; BX = handle for standard input
  9471.          int     21h             ; transfer to MS-DOS
  9472.          mov     info,dx         ; save device information word
  9473.                                  ; (assumes DS = data segment)
  9474.          or      dl,20h          ; set raw mode bit
  9475.          mov     dh,0            ; and clear DH as MS-DOS requires
  9476.          mov     ax,4401h        ; AL = subfunction 01H, set device
  9477.                                  ; information word
  9478.                                  ; (BX still contains handle)
  9479.          int     21h             ; transfer to MS-DOS
  9480.  
  9481.  \SAMPCODE\DOS_ENCY\5\IOCTL_2.ASM
  9482.  
  9483.          mov     ax,4406H        ; AH = function 44H, IOCTL
  9484.                                  ; AL = subfunction 06H, get
  9485.                                  ; input status
  9486.          mov     bx,3            ; BX = handle for standard aux
  9487.          int     21h             ; transfer to MS-DOS
  9488.          or      al,al           ; test status of AUX driver
  9489.          jnz     ready           ; jump if input character ready
  9490.                                  ; else no character is waiting
  9491.  
  9492.  \SAMPCODE\DOS_ENCY\6
  9493.  \SAMPCODE\DOS_ENCY\6\CDVUTL.C
  9494.  
  9495.  /* cdvutl.c - COMDVR Utility
  9496.   *     Jim Kyle - 1987
  9497.   *     for use with COMDVR.SYS Device Driver
  9498.   */
  9499.  
  9500.  #include <stdio.h>                 /* i/o definitions      */
  9501.  #include <conio.h>                 /* special console i/o  */
  9502.  #include <stdlib.h>                /* misc definitions     */
  9503.  #include <dos.h>                   /* defines intdos()     */
  9504.  
  9505.  /*       the following define the driver status bits       */
  9506.  
  9507.  #define HWINT 0x0800           /* MCR, first word, HW Ints gated */
  9508.  #define o_DTR 0x0200           /* MCR, first word, output DTR    */
  9509.  #define o_RTS 0x0100           /* MCR, first word, output RTS    */
  9510.  
  9511.  #define m_PG  0x0010           /* LCR, first word, parity ON     */
  9512.  #define m_PE  0x0008           /* LCR, first word, parity EVEN   */
  9513.  #define m_XS  0x0004           /* LCR, first word, 2 stop bits   */
  9514.  #define m_WL  0x0003           /* LCR, first word, wordlen mask  */
  9515.  
  9516.  #define i_CD  0x8000           /* MSR, 2nd word, Carrier Detect  */
  9517.  #define i_RI  0x4000           /* MSR, 2nd word, Ring Indicator  */
  9518.  #define i_DSR 0x2000           /* MSR, 2nd word, Data Set Ready  */
  9519.  #define i_CTS 0x1000           /* MSR, 2nd word, Clear to Send   */
  9520.  
  9521.  #define l_SRE 0x0040           /* LSR, 2nd word, Xmtr SR Empty   */
  9522.  #define l_HRE 0x0020           /* LSR, 2nd word, Xmtr HR Empty   */
  9523.  #define l_BRK 0x0010           /* LSR, 2nd word, Break Received  */
  9524.  #define l_ER1 0x0008           /* LSR, 2nd word, FrmErr          */
  9525.  #define l_ER2 0x0004           /* LSR, 2nd word, ParErr          */
  9526.  #define l_ER3 0x0002           /* LSR, 2nd word, OveRun          */
  9527.  #define l_RRF 0x0001           /* LSR, 2nd word, Rcvr DR Full    */
  9528.  
  9529.  /*           now define CLS string for ANSI.SYS            */
  9530.  #define CLS    "\033[2J"
  9531.  
  9532.  FILE * dvp;
  9533.  union REGS rvs;
  9534.  int iobf [ 5 ];
  9535.  
  9536.  main ()
  9537.  { cputs ( "\nCDVUTL - COMDVR Utility Version 1.0 - 1987\n" );
  9538.    disp ();                         /* do dispatch loop           */
  9539.  }
  9540.  
  9541.  disp ()                            /* dispatcher; infinite loop  */
  9542.  { int c,
  9543.      u;
  9544.    u = 1;
  9545.    while ( 1 )
  9546.      { cputs ( "\r\n\tCommand (? for help): " );
  9547.        switch ( tolower ( c = getche ()))   /* dispatch           */
  9548.          {
  9549.          case '1' :                 /* select port 1              */
  9550.            fclose ( dvp );
  9551.            dvp = fopen ( "ASY1", "rb+" );
  9552.               u = 1;
  9553.            break;
  9554.  
  9555.          case '2' :                 /* select port 2              */
  9556.            fclose ( dvp );
  9557.            dvp = fopen ( "ASY2", "rb+" );
  9558.            u = 2;
  9559.            break;
  9560.  
  9561.          case 'b' :                 /* set baud rate              */
  9562.            if ( iobf [ 4 ] == 300 )
  9563.              iobf [ 4 ] = 1200;
  9564.            else
  9565.              if ( iobf [ 4 ] == 1200 )
  9566.                iobf [ 4 ] = 2400;
  9567.            else
  9568.              if ( iobf [ 4 ] == 2400 )
  9569.                iobf [ 4 ] = 9600;
  9570.            else
  9571.              iobf [ 4 ] = 300;
  9572.            iocwr ();
  9573.            break;
  9574.  
  9575.          case 'e' :                 /* set parity even            */
  9576.            iobf [ 0 ] |= ( m_PG + m_PE );
  9577.            iocwr ();
  9578.            break;
  9579.  
  9580.          case 'f' :                 /* toggle flow control        */
  9581.            if ( iobf [ 3 ] == 1 )
  9582.              iobf [ 3 ] = 2;
  9583.            else
  9584.              if ( iobf [ 3 ] == 2 )
  9585.                iobf [ 3 ] = 4;
  9586.            else
  9587.              if ( iobf [ 3 ] == 4 )
  9588.                iobf [ 3 ] = 0;
  9589.            else
  9590.              iobf [ 3 ] = 1;
  9591.            iocwr ();
  9592.            break;
  9593.  
  9594.          case 'i' :                 /* initialize MCR/LCR to 8N1 : */
  9595.            iobf [ 0 ] = ( HWINT + o_DTR + o_RTS + m_WL );
  9596.            iocwr ();
  9597.            break;
  9598.  
  9599.          case '?' :                 /* this help list              */
  9600.            cputs ( CLS )            /* clear the display           */
  9601.            center ( "COMMAND LIST \n" );
  9602.  center ( "1 = select port 1           L = toggle word LENGTH  " );
  9603.  center ( "2 = select port 2           N = set parity to NONE  " );
  9604.  center ( "B = set BAUD rate           O = set parity to ODD   " );
  9605.  center ( "E = set parity to EVEN      R = toggle error REPORTS" );
  9606.  center ( "F = toggle FLOW control     S = toggle STOP bits    " );
  9607.  center ( "I = INITIALIZE ints, etc.   Q = QUIT                " );
  9608.           continue;
  9609.  
  9610.          case 'l' :                  /* toggle word length         */
  9611.            iobf [ 0 ] ^= 1;
  9612.            iocwr ();
  9613.            break;
  9614.  
  9615.          case 'n' :                  /* set parity off             */
  9616.            iobf [ 0 ] &=~ ( m_PG + m_PE );
  9617.            iocwr ();
  9618.            break;
  9619.  
  9620.          case 'o' :                  /* set parity odd             */
  9621.            iobf [ 0 ] |= m_PG;
  9622.            iobf [ 0 ] &=~ m_PE;
  9623.            iocwr ();
  9624.            break;
  9625.  
  9626.          case 'r' :                  /* toggle error reports       */
  9627.            iobf [ 2 ] ^= 1;
  9628.            iocwr ();
  9629.            break;
  9630.  
  9631.          case 's' :                  /* toggle stop bits           */
  9632.            iobf [ 0 ] ^= m_XS;
  9633.            iocwr ();
  9634.            break;
  9635.  
  9636.          case 'q' :
  9637.            fclose ( dvp );
  9638.            exit ( 0 );               /* break the loop, get out    */
  9639.          }
  9640.        cputs ( CLS );                /* clear the display          */
  9641.        center ( "CURRENT COMDVR STATUS" );
  9642.        report ( u, dvp );            /* report current status      */
  9643.      }
  9644.  }
  9645.  
  9646.  center ( s ) char * s;              /* centers a string on CRT    */
  9647.  { int i ;
  9648.    for ( i = 80 - strlen ( s ); i > 0; i -= 2 )
  9649.      putch ( ' ' );
  9650.    cputs ( s );
  9651.    cputs ( "\r\n" );
  9652.  }
  9653.  
  9654.  iocwr ()                            /* IOCTL Write to COMDVR      */
  9655.  { rvs . x . ax = 0x4403;
  9656.    rvs . x . bx = fileno ( dvp );
  9657.    rvs . x . cx = 10;
  9658.    rvs . x . dx = ( int ) iobf;
  9659.    intdos ( & rvs, & rvs );
  9660.  }
  9661.  
  9662.  char * onoff ( x ) int x ;
  9663.  { return ( x ? " ON" : " OFF" );
  9664.  }
  9665.  
  9666.  report ( unit ) int unit ;
  9667.  { char temp [ 80 ];
  9668.    rvs . x . ax = 0x4402;
  9669.    rvs . x . bx = fileno ( dvp );
  9670.    rvs . x . cx = 10;
  9671.    rvs . x . dx = ( int ) iobf;
  9672.    intdos ( & rvs, & rvs );         /* use IOCTL Read to get data */
  9673.    sprintf ( temp, "\nDevice ASY%d\t%d BPS, %d-c-%c\r\n\n",
  9674.             unit, iobf [ 4 ],           /* baud rate              */
  9675.             5 + ( iobf [ 0 ] & m_WL ),  /* word length            */
  9676.             ( iobf [ 0 ] & m_PG ?
  9677.               ( iobf [ 0 ] & m_PE ? 'E' : 'O' ) : 'N' ),
  9678.             ( iobf [ 0 ] & m_XS ? '2' : '1' )); /* stop bits      */
  9679.    cputs ( temp );
  9680.  
  9681.    cputs ( "Hardware Interrupts are" );
  9682.    cputs ( onoff ( iobf [ 0 ] & HWINT ));
  9683.    cputs ( ", Data Terminal Rdy" );
  9684.    cputs ( onoff ( iobf [ 0 ] & o_DTR ));
  9685.    cputs ( ", Rqst To Send" );
  9686.    cputs ( onoff ( iobf [ 0 ] & o_RTS ));
  9687.    cputs ( ".\r\n" );
  9688.  
  9689.    cputs ( "Carrier Detect" );
  9690.    cputs ( onoff ( iobf [ 1 ] & i_CD ));
  9691.    cputs ( ", Data Set Rdy" );
  9692.    cputs ( onoff ( iobf [ 1 ] & i_DSR ));
  9693.    cputs ( ", Clear to Send" );
  9694.    cputs ( onoff ( iobf [ 1 ] & i_CTS ));
  9695.    cputs ( ", Ring Indicator" );
  9696.    cputs ( onoff ( iobf [ 1 ] & i_RI ));
  9697.    cputs ( ".\r\n" );
  9698.  
  9699.    cputs ( l_SRE & iobf [ 1 ] ? "Xmtr SR Empty, " : "" );
  9700.    cputs ( l_HRE & iobf [ 1 ] ? "Xmtr HR Empty, " : "" );
  9701.    cputs ( l_BRK & iobf [ 1 ] ? "Break Received, " : "" );
  9702.    cputs ( l_ER1 & iobf [ 1 ] ? "Framing Error, " : "" );
  9703.    cputs ( l_ER2 & iobf [ 1 ] ? "Parity Error, " : "" );
  9704.    cputs ( l_ER3 & iobf [ 1 ] ? "Overrun Error, " : "" );
  9705.    cputs ( l_RRF & iobf [ 1 ] ? "Rcvr DR Full, " : "" );
  9706.    cputs ( "\b\b.\r\n" );
  9707.  
  9708.    cputs ( "Reception errors " );
  9709.    if ( iobf [ 2 ] == 1 )
  9710.      cputs ( "are encoded as graphics in buffer" );
  9711.    else
  9712.      cputs ( "set failure flag" );
  9713.    cputs ( ".\r\n" );
  9714.  
  9715.    cputs ( "Outgoing Flow Control " );
  9716.    if ( iobf [ 3 ] & 4 )
  9717.      cputs ( "by XON and XOFF" );
  9718.    else
  9719.      if ( iobf [ 3 ] & 2 )
  9720.        cputs ( "by RTS and CTS" );
  9721.    else
  9722.      if ( iobf [ 3 ] & 1 )
  9723.        cputs ( "by DTR and DSR" );
  9724.    else
  9725.      cputs ( "disabled" );
  9726.    cputs ( ".\r\n" );
  9727.  }
  9728.  
  9729.  /*end of cdvutl.c */
  9730.  
  9731.  \SAMPCODE\DOS_ENCY\6\CTERM.C
  9732.  
  9733.  /* Terminal Emulator    (cterm.c)
  9734.   *      Jim Kyle, 1987
  9735.   *
  9736.   *      Uses files CH1, CH1A, and CH2 for MASM support...
  9737.   */
  9738.  
  9739.  #include <stdio.h>
  9740.  #include <conio.h>                      /* special console i/o      */
  9741.  #include <stdlib.h>                     /* misc definitions         */
  9742.  #include <dos.h>                        /* defines intdos()         */
  9743.  #include <string.h>
  9744.  #define BRK  'C'-'@'                    /* control characters       */
  9745.  #define ESC  '['-'@'
  9746.  #define XON  'Q'-'@'
  9747.  #define XOFF 'S'-'@'
  9748.  
  9749.  #define True  1
  9750.  #define False  0
  9751.  
  9752.  #define Is_Function_Key(C) ( (C) == ESC )
  9753.  
  9754.  static char capbfr [ 4096 ];            /* capture buffer           */
  9755.  static int wh,
  9756.       ws;
  9757.  
  9758.  static int I,
  9759.      waitchr = 0,
  9760.      vflag = False,
  9761.      capbp,
  9762.      capbc,
  9763.      Ch,
  9764.      Want_7_Bit = True,
  9765.      ESC_Seq_State = 0;        /* escape sequence state variable     */
  9766.  
  9767.  int _cx ,
  9768.       _cy,
  9769.       _atr = 0x07,                       /* white on black           */
  9770.       _pag = 0,
  9771.       oldtop = 0,
  9772.       oldbot = 0x184f;
  9773.  
  9774.  FILE * in_file = NULL;         /* start with keyboard input         */
  9775.  FILE * cap_file = NULL;
  9776.  
  9777.  #include "cterm.h"             /* external declarations, etc.       */
  9778.  
  9779.  int Wants_To_Abort ()          /* checks for interrupt of script    */
  9780.  { return broke ();
  9781.  }
  9782.  void
  9783.  
  9784.  main ( argc, argv ) int argc ; /* main routine                      */
  9785.   char * argv [];
  9786.  { char * cp,
  9787.       * addext ();
  9788.    if ( argc > 1 )                /* check for script filename       */
  9789.      in_file = fopen ( addext ( argv [ 1 ], ".SCR" ), "r" );
  9790.    if ( argc > 2 )                /* check for capture filename      */
  9791.      cap_file = fopen ( addext ( argv [ 2 ], ".CAP" ), "w" );
  9792.    set_int ();                    /* install CH1 module              */
  9793.    Set_Vid ();                    /* get video setup                 */
  9794.    cls ();                        /* clear the screen                */
  9795.    cputs ( "Terminal Emulator" ); /* tell who's working              */
  9796.    cputs ( "\r\n< ESC for local commands >\r\n\n" );
  9797.    Want_7_Bit = True;
  9798.    ESC_Seq_State = 0;
  9799.    Init_Comm ();                  /* set up drivers, etc.            */
  9800.    while ( 1 )                           /* main loop                */
  9801.      { if (( Ch = kb_file ()) > 0 )      /* check local              */
  9802.          { if ( Is_Function_Key ( Ch ))
  9803.              { if ( docmd () < 0 )       /* command                  */
  9804.                  break;
  9805.              }
  9806.            else
  9807.              Send_Byte ( Ch & 0x7F );    /* else send it             */
  9808.          }
  9809.        if (( Ch = Read_Modem ()) >= 0 )  /* check remote             */
  9810.          { if ( Want_7_Bit )
  9811.              Ch &= 0x7F;                 /* trim off high bit        */
  9812.            switch ( ESC_Seq_State )      /* state machine            */
  9813.              {
  9814.              case 0 :                    /* no Esc sequence          */
  9815.                switch ( Ch )
  9816.                  {
  9817.                  case ESC  :             /* Esc char received        */
  9818.                    ESC_Seq_State = 1;
  9819.                    break;
  9820.  
  9821.                  default :
  9822.                    if ( Ch == waitchr )  /* wait if required         */
  9823.                      waitchr = 0;
  9824.                    if ( Ch == 12 )       /* clear screen on FF       */
  9825.                      cls ();
  9826.                    else
  9827.                      if ( Ch != 127 )    /* ignore rubouts           */
  9828.                        { putchx ( (char) Ch );  /* handle all others */
  9829.                          put_cap ( (char) Ch );
  9830.                        }
  9831.                  }
  9832.                break;
  9833.  
  9834.              case 1 : /* ESC -- process any escape sequences here    */
  9835.                switch ( Ch )
  9836.                  {
  9837.                  case 'A' :              /* VT52 up                  */
  9838.                    ;                     /* nothing but stubs here   */
  9839.                    ESC_Seq_State = 0;
  9840.                    break;
  9841.  
  9842.                  case 'B' :              /* VT52 down                */
  9843.                    ;
  9844.                    ESC_Seq_State = 0;
  9845.                    break;
  9846.  
  9847.                  case 'C' :              /* VT52 left                */
  9848.                    ;
  9849.                    ESC_Seq_State = 0;
  9850.                    break;
  9851.  
  9852.                  case 'D' :              /* VT52 right               */
  9853.                    ;
  9854.                    ESC_Seq_State = 0;
  9855.                    break;
  9856.  
  9857.                  case 'E' :              /* VT52 Erase CRT           */
  9858.                    cls ();               /* actually do this one     */
  9859.                    ESC_Seq_State = 0;
  9860.                    break;
  9861.  
  9862.                  case 'H' :              /* VT52 home cursor         */
  9863.                    locate ( 0, 0 );
  9864.                    ESC_Seq_State = 0;
  9865.                    break;
  9866.  
  9867.                  case 'j' :              /* VT52 Erase to EOS        */
  9868.                    deos ();
  9869.                    ESC_Seq_State = 0;
  9870.                    break;
  9871.  
  9872.                  case '[' :      /* ANSI.SYS - VT100 sequence        */
  9873.                    ESC_Seq_State = 2;
  9874.                    break;
  9875.  
  9876.                  default :
  9877.                    putchx ( ESC );       /* pass thru all others     */
  9878.                    putchx ( (char) Ch );
  9879.                    ESC_Seq_State = 0;
  9880.                  }
  9881.                break;
  9882.  
  9883.              case 2 :                    /* ANSI 3.64 decoder        */
  9884.                ESC_Seq_State = 0;        /* not implemented          */
  9885.              }
  9886.          }
  9887.        if ( broke ())                    /* check CH1A handlers      */
  9888.          { cputs ( "\r\n***BREAK***\r\n" );
  9889.            break;
  9890.          }
  9891.      }                                   /* end of main loop         */
  9892.    if ( cap_file )                       /* save any capture         */
  9893.      cap_flush ();
  9894.    Term_Comm ();                         /* restore when done        */
  9895.    rst_int ();                           /* restore break handlers   */
  9896.    exit ( 0 );                           /* be nice to MS-DOS        */
  9897.  }
  9898.  
  9899.  docmd ()                                /* local command shell      */
  9900.  { FILE * getfil ();
  9901.    int wp;
  9902.    wp = True;
  9903.    if ( ! in_file || vflag )
  9904.      cputs ( "\r\n\tCommand: " );        /* ask for command          */
  9905.    else
  9906.      wp = False;
  9907.    Ch = toupper ( kbd_wait ());          /* get response             */
  9908.    if ( wp )
  9909.      putchx ( (char) Ch );
  9910.    switch  ( Ch )                         /* and act on it           */
  9911.      {
  9912.      case 'S' :
  9913.        if ( wp )
  9914.          cputs ( "low speed\r\n" );
  9915.        Set_Baud ( 300 );
  9916.        break;
  9917.  
  9918.      case 'D' :
  9919.        if ( wp )
  9920.          cputs ( "elay (1-9 sec): " );
  9921.        Ch = kbd_wait ();
  9922.        if ( wp )
  9923.          putchx ( (char) Ch );
  9924.        Delay ( 1000 * ( Ch - '0' ));
  9925.        if ( wp )
  9926.          putchx ( '\n' );
  9927.        break;
  9928.  
  9929.      case 'E' :
  9930.        if ( wp )
  9931.          cputs ( "ven Parity\r\n" );
  9932.        Set_Parity ( 2 );
  9933.        break;
  9934.  
  9935.      case 'F' :
  9936.        if ( wp )
  9937.          cputs ( "ast speed\r\n" );
  9938.        Set_Baud ( 1200 );
  9939.        break;
  9940.  
  9941.      case 'H' :
  9942.        if ( wp )
  9943.          { cputs ( "\r\n\tVALID COMMANDS:\r\n" );
  9944.            cputs ( "\tD = delay 0-9 seconds.\r\n" );
  9945.            cputs ( "\tE = even parity.\r\n" );
  9946.            cputs ( "\tF = (fast) 1200-baud.\r\n" );
  9947.            cputs ( "\tN = no parity.\r\n" );
  9948.            cputs ( "\tO = odd parity.\r\n" );
  9949.            cputs ( "\tQ = quit, return to DOS.\r\n" );
  9950.            cputs ( "\tR = reset modem.\r\n" );
  9951.            cputs ( "\tS = (slow) 300-baud.\r\n" );
  9952.            cputs ( "\tU = use script file.\r\n" );
  9953.            cputs ( "\tV = verify file input.\r\n" );
  9954.            cputs ( "\tW = wait for char." );
  9955.          }
  9956.        break;
  9957.  
  9958.      case 'N' :
  9959.        if ( wp )
  9960.          cputs ( "o Parity\r\n" );
  9961.        Set_Parity ( 1 );
  9962.        break;
  9963.  
  9964.      case 'O' :
  9965.        if ( wp )
  9966.          cputs ( "dd Parity\r\n" );
  9967.        Set_Parity ( 3 );
  9968.        break;
  9969.  
  9970.      case 'R' :
  9971.        if ( wp )
  9972.          cputs ( "ESET Comm Port\r\n" );
  9973.        Init_Comm ();
  9974.        break;
  9975.  
  9976.      case 'Q' :
  9977.        if ( wp )
  9978.          cputs ( " = QUIT Command\r\n" );
  9979.        Ch = ( - 1 );
  9980.        break;
  9981.  
  9982.      case 'U' :
  9983.        if ( in_file && ! vflag )
  9984.          putchx ( 'U' );
  9985.        cputs ( "se file: " );
  9986.        getfil ();
  9987.        cputs ( "File " );
  9988.        cputs ( in_file ? "Open\r\n" : "Bad\r\n" );
  9989.        waitchr = 0;
  9990.        break;
  9991.  
  9992.      case 'V' :
  9993.        if ( wp )
  9994.          { cputs ( "erify flag toggled " );
  9995.            cputs ( vflag ? "OFF\r\n" : "ON\r\n" );
  9996.          }
  9997.        vflag = vflag ? False : True;
  9998.        break;
  9999.  
  10000.      case 'W' :
  10001.        if ( wp )
  10002.          cputs ( "ait for: <" );
  10003.        waitchr = kbd_wait ();
  10004.        if ( waitchr == ' ' )
  10005.          waitchr = 0;
  10006.        if ( wp )
  10007.          { if ( waitchr )
  10008.              putchx ( (char) waitchr );
  10009.            else
  10010.              cputs ( "no wait" );
  10011.            cputs ( ">\r\n" );
  10012.          }
  10013.        break;
  10014.  
  10015.      default :
  10016.        if ( wp )
  10017.          { cputs ( "Don't know " );
  10018.            putchx ( (char) Ch );
  10019.            cputs ( "\r\nUse 'H' command for Help.\r\n" );
  10020.          }
  10021.        Ch = '?';
  10022.      }
  10023.    if ( wp )                             /* if window open...        */
  10024.      { cputs ( "\r\n[any key]\r" );
  10025.        while ( Read_Keyboard () == EOF ) /* wait for response        */
  10026.          ;
  10027.      }
  10028.    return Ch ;
  10029.  }
  10030.  
  10031.  kbd_wait ()                             /* wait for input           */
  10032.  { int c ;
  10033.    while (( c = kb_file ()) == ( - 1 ))
  10034.      ;
  10035.    return c & 255;
  10036.  }
  10037.  
  10038.  kb_file ()                              /* input from kb or file    */
  10039.  { int c ;
  10040.    if ( in_file )                        /* USING SCRIPT             */
  10041.      { c = Wants_To_Abort ();            /* use first as flag        */
  10042.        if ( waitchr && ! c )
  10043.          c = ( - 1 );                    /* then for char            */
  10044.        else
  10045.          if ( c || ( c = getc ( in_file )) == EOF || c == 26 )
  10046.            { fclose ( in_file );
  10047.              cputs ( "\r\nScript File Closed\r\n" );
  10048.              in_file = NULL;
  10049.              waitchr = 0;
  10050.              c = ( - 1 );
  10051.            }
  10052.        else
  10053.          if ( c == '\n' )                /* ignore LF's in file      */
  10054.            c = ( - 1 );
  10055.        if ( c == '\\' )                  /* process Esc sequence     */
  10056.          c = esc ();
  10057.        if ( vflag && c != ( - 1 ))       /* verify file char         */
  10058.          { putchx ( '{' );
  10059.            putchx ( (char) c );
  10060.            putchx ( '}' );
  10061.          }
  10062.      }
  10063.    else                                  /* USING CONSOLE            */
  10064.      c = Read_Keyboard ();               /* if not using file        */
  10065.    return ( c );
  10066.  }
  10067.  
  10068.  esc ()                                  /* script translator        */
  10069.  { int c ;
  10070.    c = getc ( in_file );                 /* control chars in file    */
  10071.    switch ( toupper ( c ))
  10072.      {
  10073.      case 'E' :
  10074.        c = ESC;
  10075.        break;
  10076.  
  10077.      case 'N' :
  10078.        c = '\n';
  10079.        break;
  10080.  
  10081.      case 'R' :
  10082.        c = '\r';
  10083.        break;
  10084.  
  10085.      case 'T' :
  10086.        c = '\t';
  10087.        break;
  10088.  
  10089.      case '^' :
  10090.        c = getc ( in_file ) & 31;
  10091.        break;
  10092.      }
  10093.    return ( c );
  10094.  }
  10095.  
  10096.  FILE * getfil ()
  10097.  { char fnm [ 20 ];
  10098.    getnam ( fnm, 15 );                   /* get the name             */
  10099.    if ( ! ( strchr ( fnm, '.' )))
  10100.      strcat ( fnm, ".SCR" );
  10101.    return ( in_file = fopen ( fnm, "r" ));
  10102.  }
  10103.  
  10104.  void getnam ( b, s ) char * b;          /* take input to buffer     */
  10105.   int s ;
  10106.  { while ( s -- > 0 )
  10107.      { if (( * b = kbd_wait ()) != '\r' )
  10108.          putchx ( * b ++ );
  10109.        else
  10110.          break ;
  10111.      }
  10112.    putchx ( '\n' );
  10113.    * b = 0;
  10114.  }
  10115.  
  10116.  char * addext ( b,                      /* add default EXTension    */
  10117.       e ) char * b,
  10118.       * e;
  10119.  { static char bfr [ 20 ];
  10120.    if ( strchr ( b, '.' ))
  10121.      return ( b );
  10122.    strcpy ( bfr, b );
  10123.    strcat ( bfr, e );
  10124.    return ( bfr );
  10125.  }
  10126.  
  10127.  void put_cap ( c ) char c ;
  10128.  { if ( cap_file && c != 13 )            /* strip out CR's           */
  10129.      fputc ( c, cap_file );              /* use MS-DOS buffering     */
  10130.  }
  10131.  
  10132.  void cap_flush ()                       /* end Capture mode         */
  10133.  { if ( cap_file )
  10134.      { fclose ( cap_file );
  10135.        cap_file = NULL;
  10136.        cputs ( "\r\nCapture file closed\r\n" );
  10137.      }
  10138.  }
  10139.  
  10140.  /*      TIMER SUPPORT STUFF (IBMPC/MSDOS)                           */
  10141.  static long timr;                       /* timeout register         */
  10142.  
  10143.  static union REGS rgv ;
  10144.  
  10145.  long getmr ()
  10146.  { long now ;                            /* msec since midnite       */
  10147.    rgv.x.ax = 0x2c00;
  10148.    intdos ( & rgv, & rgv );
  10149.    now = rgv.h.ch;                       /* hours                    */
  10150.    now *= 60L;                           /* to minutes               */
  10151.    now += rgv.h.cl;                      /* plus min                 */
  10152.    now *= 60L;                           /* to seconds               */
  10153.    now += rgv.h.dh;                      /* plus sec                 */
  10154.    now *= 100L;                          /* to 1/100                 */
  10155.    now += rgv.h.dl;                      /* plus 1/100               */
  10156.    return ( 10L * now );                 /* msec value               */
  10157.  }
  10158.  
  10159.  void Delay ( n ) int n ;                /* sleep for n msec         */
  10160.  { long wakeup ;
  10161.    wakeup = getmr () + ( long ) n;       /* wakeup time              */
  10162.    while ( getmr () < wakeup )
  10163.      ;                                   /* now sleep                */
  10164.  }
  10165.  
  10166.  void Start_Timer ( n ) int n ;          /* set timeout for n sec    */
  10167.  { timr = getmr () + ( long ) n * 1000L;
  10168.  }
  10169.  
  10170.  Timer_Expired ()        /* if timeout return 1 else return 0        */
  10171.  { return ( getmr () > timr );
  10172.  }
  10173.  
  10174.  Set_Vid ()
  10175.  { _i_v ();                              /* initialize video         */
  10176.    return 0;
  10177.  }
  10178.  
  10179.  void locate ( row, col ) int row ,
  10180.       col;
  10181.  { _cy = row % 25;
  10182.    _cx = col % 80;
  10183.    _wrpos ( row, col );                  /* use ML from CH2.ASM      */
  10184.  }
  10185.  
  10186.  void deol ()
  10187.  { _deol ();                             /* use ML from CH2.ASM      */
  10188.  }
  10189.  
  10190.  void deos ()
  10191.  { deol ();
  10192.    if ( _cy < 24 )                       /* if not last, clear       */
  10193.      { rgv.x.ax = 0x0600;
  10194.        rgv.x.bx = ( _atr << 8 );
  10195.        rgv.x.cx = ( _cy + 1 ) << 8;
  10196.        rgv.x.dx = 0x184F;
  10197.        int86 ( 0x10, & rgv, & rgv );
  10198.      }
  10199.    locate ( _cy, _cx );
  10200.  }
  10201.  
  10202.  void cls ()
  10203.  { _cls ();                              /* use ML                   */
  10204.  }
  10205.  
  10206.  void cursor ( yn ) int yn ;
  10207.  { rgv.x.cx = yn ? 0x0607 : 0x2607;      /* ON/OFF                   */
  10208.    rgv.x.ax = 0x0100;
  10209.    int86 ( 0x10, & rgv, & rgv );
  10210.  }
  10211.  
  10212.  void revvid ( yn ) int yn ;
  10213.  { if ( yn )
  10214.      _atr = _color ( 8, 7 );             /* black on white           */
  10215.    else
  10216.      _atr = _color ( 15, 0 );            /* white on black           */
  10217.  }
  10218.  
  10219.  putchx ( c ) char c ;                   /* put char to CRT          */
  10220.  { if ( c == '\n' )
  10221.      putch ( '\r' );
  10222.    putch ( c );
  10223.    return c ;
  10224.  }
  10225.  
  10226.  Read_Keyboard ()                    /* get keyboard character
  10227.                                         returns -1 if none present   */
  10228.  { int c ;
  10229.    if ( kbhit ())                        /* no char at all           */
  10230.      return ( getch ());
  10231.    return ( EOF );
  10232.  }
  10233.  
  10234.  /*      MODEM SUPPORT                   */
  10235.  static char mparm,
  10236.       wrk [ 80 ];
  10237.  
  10238.  void Init_Comm ()               /* initialize comm port stuff       */
  10239.  { static int ft = 0;                    /* firstime flag            */
  10240.    if ( ft ++ == 0 )
  10241.      i_m ();
  10242.    Set_Parity ( 1 );                     /* 8,N,1                    */
  10243.    Set_Baud ( 1200 );                    /* 1200 baud                */
  10244.  }
  10245.  
  10246.  #define B1200 0x80                      /* baudrate codes           */
  10247.  #define B300 0x40
  10248.  
  10249.  Set_Baud ( n ) int n ;                  /* n is baud rate           */
  10250.  { if ( n == 300 )
  10251.      mparm = ( mparm & 0x1F ) + B300;
  10252.    else
  10253.      if ( n == 1200 )
  10254.        mparm = ( mparm & 0x1F ) + B1200;
  10255.    else
  10256.      return 0;                           /* invalid speed            */
  10257.    sprintf ( wrk, "Baud rate = %d\r\n", n );
  10258.    cputs ( wrk );
  10259.    set_mdm ( mparm );
  10260.    return n ;
  10261.  }
  10262.  
  10263.  #define PAREVN 0x18                     /* MCR bits for commands    */
  10264.  #define PARODD 0x10
  10265.  #define PAROFF 0x00
  10266.  #define STOP2 0x40
  10267.  #define WORD8 0x03
  10268.  #define WORD7 0x02
  10269.  #define WORD6 0x01
  10270.  
  10271.  Set_Parity ( n ) int n ;                /* n is parity code         */
  10272.  { static int mmode;
  10273.    if ( n == 1 )
  10274.      mmode = ( WORD8 | PAROFF );         /* off                      */
  10275.    else
  10276.      if ( n == 2 )
  10277.        mmode = ( WORD7 | PAREVN );       /* on and even              */
  10278.    else
  10279.      if ( n == 3 )
  10280.        mmode = ( WORD7 | PARODD );       /* on and odd               */
  10281.    else
  10282.      return 0;                           /* invalid code             */
  10283.    mparm = ( mparm & 0xE0 ) + mmode;
  10284.    sprintf ( wrk, "Parity is %s\r\n", ( n == 1 ? "OFF" :
  10285.                                       ( n == 2 ? "EVEN" : "ODD" )));
  10286.    cputs ( wrk );
  10287.    set_mdm ( mparm );
  10288.    return n ;
  10289.  }
  10290.  
  10291.  Write_Modem ( c ) char c ;              /* return 1 if ok, else 0   */
  10292.  { wrtmdm ( c );
  10293.    return ( 1 );                         /* never any error          */
  10294.  }
  10295.  
  10296.  Read_Modem ()
  10297.  { return ( rdmdm ());                   /* from int bfr             */
  10298.  }
  10299.  
  10300.  void Term_Comm ()               /* uninstall comm port drivers      */
  10301.  { u_m ();
  10302.  }
  10303.  
  10304.  /* end of cterm.c */
  10305.  
  10306.  \SAMPCODE\DOS_ENCY\6\CH1.ASM
  10307.  
  10308.          TITLE   CH1.ASM
  10309.  
  10310.  ; CH1.ASM -- support file for CTERM.C terminal emulator
  10311.  ;       set up to work with COM2
  10312.  ;       for use with Microsoft C and SMALL model only...
  10313.  
  10314.  _TEXT   segment byte public 'CODE'
  10315.  _TEXT   ends
  10316.  _DATA   segment byte public 'DATA'
  10317.  _DATA   ends
  10318.  CONST   segment byte public 'CONST'
  10319.  CONST   ends
  10320.  _BSS    segment byte public 'BSS'
  10321.  _BSS    ends
  10322.  
  10323.  DGROUP  GROUP   CONST, _BSS, _DATA
  10324.          assume  cs:_TEXT, DS:DGROUP, ES:DGROUP, SS:DGROUP
  10325.  
  10326.  _TEXT   segment
  10327.  
  10328.          public  _i_m,_rdmdm,_Send_Byte,_wrtmdm,_set_mdm,_u_m
  10329.  
  10330.  bport   EQU     02F8h           ; COM2 base address, use 03F8H for COM1
  10331.  getiv   EQU     350Bh           ; COM2 vectors, use 0CH for COM1
  10332.  putiv   EQU     250Bh
  10333.  imrmsk  EQU     00001000b       ; COM2 mask, use 00000100b for COM1
  10334.  oiv_o   DW      0               ; old int vector save space
  10335.  oiv_s   DW      0
  10336.  
  10337.  bf_pp   DW      in_bf           ; put pointer (last used)
  10338.  bf_gp   DW      in_bf           ; get pointer (next to use)
  10339.  bf_bg   DW      in_bf           ; start of buffer
  10340.  bf_fi   DW      b_last          ; end of buffer
  10341.  
  10342.  in_bf   DB      512 DUP (?)     ; input buffer
  10343.  
  10344.  b_last  EQU     $               ; address just past buffer end
  10345.  
  10346.  bd_dv   DW      0417h           ; baud rate divisors (0=110 bps)
  10347.          DW      0300h           ; code 1 =  150 bps
  10348.          DW      0180h           ; code 2 =  300 bps
  10349.          DW      00C0h           ; code 3 =  600 bps
  10350.          DW      0060h           ; code 4 = 1200 bps
  10351.          DW      0030h           ; code 5 = 2400 bps
  10352.          DW      0018h           ; code 6 = 4800 bps
  10353.          DW      000Ch           ; code 7 = 9600 bps
  10354.  
  10355.  _set_mdm proc   near            ; replaces BIOS 'init' function
  10356.          PUSH    BP
  10357.          MOV     BP,SP           ; establish stackframe pointer
  10358.          PUSH    ES              ; save registers
  10359.          PUSH    DS
  10360.          MOV     AX,CS           ; point them to CODE segment
  10361.          MOV     DS,AX
  10362.          MOV     ES,AX
  10363.          MOV     AH,[BP+4]       ; get parameter passed by C
  10364.          MOV     DX,BPORT+3      ; point to Line Control Reg
  10365.          MOV     AL,80h          ; set DLAB bit (see text)
  10366.          OUT     DX,AL
  10367.          MOV     DL,AH           ; shift param to BAUD field
  10368.          MOV     CL,4
  10369.          ROL     DL,CL
  10370.          AND     DX,00001110b    ; mask out all other bits
  10371.          MOV     DI,OFFSET bd_dv
  10372.          ADD     DI,DX           ; make pointer to true divisor
  10373.          MOV     DX,BPORT+1      ; set to high byte first
  10374.          MOV     AL,[DI+1]
  10375.          OUT     DX,AL           ; put high byte into UART
  10376.          MOV     DX,BPORT        ; then to low byte
  10377.          MOV     AL,[DI]
  10378.          OUT     DX,AL
  10379.          MOV     AL,AH           ; now use rest of parameter
  10380.          AND     AL,00011111b    ; to set Line Control Reg
  10381.          MOV     DX,BPORT+3
  10382.          OUT     DX,AL
  10383.          MOV     DX,BPORT+2      ; Interrupt Enable Register
  10384.          MOV     AL,1            ; Receive type only
  10385.          OUT     DX,AL
  10386.          POP     DS              ; restore saved registers
  10387.          POP     ES
  10388.          MOV     SP,BP
  10389.          POP     BP
  10390.          RET
  10391.  _set_mdm endp
  10392.  
  10393.  _wrtmdm proc    near            ; write char to modem
  10394.  _Send_Byte:                     ; name used by main program
  10395.          PUSH    BP
  10396.          MOV     BP,SP           ; set up pointer and save regs
  10397.          PUSH    ES
  10398.          PUSH    DS
  10399.          MOV     AX,CS
  10400.          MOV     DS,AX
  10401.          MOV     ES,AX
  10402.          MOV     DX,BPORT+4      ; establish DTR, RTS, and OUT2
  10403.          MOV     AL,0Bh
  10404.          OUT     DX,AL
  10405.          MOV     DX,BPORT+6      ; check for on line, CTS
  10406.          MOV     BH,30h
  10407.          CALL    w_tmr
  10408.          JNZ     w_out           ; timed out
  10409.          MOV     DX,BPORT+5      ; check for UART ready
  10410.          MOV     BH,20h
  10411.          CALL    w_tmr
  10412.          JNZ     w_out           ; timed out
  10413.          MOV     DX,BPORT        ; send out to UART port
  10414.          MOV     AL,[BP+4]       ; get char passed from C
  10415.          OUT     DX,AL
  10416.  w_out:  POP     DS              ; restore saved regs
  10417.          POP     ES
  10418.          MOV     SP,BP
  10419.          POP     BP
  10420.          RET
  10421.  _wrtmdm endp
  10422.  
  10423.  _rdmdm  proc    near            ; reads byte from buffer
  10424.          PUSH    BP
  10425.          MOV     BP,SP           ; set up ptr, save regs
  10426.          PUSH    ES
  10427.          PUSH    DS
  10428.          MOV     AX,CS
  10429.          MOV     DS,AX
  10430.          MOV     ES,AX
  10431.          MOV     AX,0FFFFh       ; set for EOF flag
  10432.          MOV     BX,bf_gp        ; use "get" ptr
  10433.          CMP     BX,bf_pp        ; compare to "put"
  10434.          JZ      nochr           ; same, empty
  10435.          INC     BX              ; else char available
  10436.          CMP     BX,bf_fi        ; at end of bfr?
  10437.          JNZ     noend           ; no
  10438.          MOV     BX,bf_bg        ; yes, set to beg
  10439.  noend:  MOV     AL,[BX]         ; get the char
  10440.          MOV     bf_gp,BX        ; update "get" ptr
  10441.          INC     AH              ; zero AH as flag
  10442.  nochr:  POP     DS              ; restore regs
  10443.          POP     ES
  10444.          MOV     SP,BP
  10445.          POP     BP
  10446.          RET
  10447.  _rdmdm  endp
  10448.  
  10449.  w_tmr   proc    near
  10450.          MOV     BL,1            ; wait timer, double loop
  10451.  w_tm1:  SUB     CX,CX           ; set up inner loop
  10452.  w_tm2:  IN      AL,DX           ; check for requested response
  10453.          MOV     AH,AL           ; save what came in
  10454.          AND     AL,BH           ; mask with desired bits
  10455.          CMP     AL,BH           ; then compare
  10456.          JZ      w_tm3           ; got it, return with ZF set
  10457.          LOOP    w_tm2           ; else keep trying
  10458.          DEC     BL              ; until double loop expires
  10459.          JNZ     w_tm1
  10460.          OR      BH,BH           ; timed out, return NZ
  10461.  w_tm3:  RET
  10462.  w_tmr   endp
  10463.  
  10464.  ; hardware interrupt service routine
  10465.  rts_m:  CLI
  10466.          PUSH    DS              ; save all regs
  10467.          PUSH    AX
  10468.          PUSH    BX
  10469.          PUSH    CX
  10470.          PUSH    DX
  10471.          PUSH    CS              ; set DS same as CS
  10472.          POP     DS
  10473.          MOV     DX,BPORT        ; grab the char from UART
  10474.          IN      AL,DX
  10475.          MOV     BX,bf_pp        ; use "put" ptr
  10476.          INC     BX              ; step to next slot
  10477.          CMP     BX,bf_fi        ; past end yet?
  10478.          JNZ     nofix           ; no
  10479.          MOV     BX,bf_bg        ; yes, set to begin
  10480.  nofix:  MOV     [BX],AL         ; put char in buffer
  10481.          MOV     bf_pp,BX        ; update "put" ptr
  10482.          MOV     AL,20h          ; send EOI to 8259 chip
  10483.          OUT     20h,AL
  10484.          POP     DX              ; restore regs
  10485.          POP     CX
  10486.          POP     BX
  10487.          POP     AX
  10488.          POP     DS
  10489.          IRET
  10490.  
  10491.  _i_m    proc    near            ; install modem service
  10492.          PUSH    BP
  10493.          MOV     BP,SP           ; save all regs used
  10494.          PUSH    ES
  10495.          PUSH    DS
  10496.          MOV     AX,CS           ; set DS,ES=CS
  10497.          MOV     DS,AX
  10498.          MOV     ES,AX
  10499.          MOV     DX,BPORT+1      ; Interrupt Enable Reg
  10500.          MOV     AL,0Fh          ; enable all ints now
  10501.          OUT     DX,AL
  10502.  
  10503.  im1:    MOV     DX,BPORT+2      ; clear junk from UART
  10504.          IN      AL,DX           ; read IID reg of UART
  10505.          MOV     AH,AL           ; save what came in
  10506.          TEST    AL,1            ; anything pending?
  10507.          JNZ     im5             ; no, all clear now
  10508.          CMP     AH,0            ; yes, Modem Status?
  10509.          JNZ     im2             ; no
  10510.          MOV     DX,BPORT+6      ; yes, read MSR to clear
  10511.          IN      AL,DX
  10512.  im2:    CMP     AH,2            ; Transmit HR empty?
  10513.          JNZ     im3             ; no (no action needed)
  10514.  im3:    CMP     AH,4            ; Received Data Ready?
  10515.          JNZ     im4             ; no
  10516.          MOV     DX,BPORT        ; yes, read it to clear
  10517.          IN      AL,DX
  10518.  im4:    CMP     AH,6            ; Line Status?
  10519.          JNZ     im1             ; no, check for more
  10520.          MOV     DX,BPORT+5      ; yes, read LSR to clear
  10521.          IN      AL,DX
  10522.          JMP     im1             ; then check for more
  10523.  
  10524.  im5:    MOV     DX,BPORT+4      ; set up working conditions
  10525.          MOV     AL,0Bh          ; DTR, RTS, OUT2 bits
  10526.          OUT     DX,AL
  10527.          MOV     AL,1            ; enable RCV interrupt only
  10528.          MOV     DX,BPORT+1
  10529.          OUT     DX,AL
  10530.          MOV     AX,GETIV        ; get old int vector
  10531.          INT     21h
  10532.          MOV     oiv_o,BX        ; save for restoring later
  10533.          MOV     oiv_s,ES
  10534.          MOV     DX,OFFSET rts_m ; set in new one
  10535.          MOV     AX,PUTIV
  10536.          INT     21h
  10537.          IN      AL,21h          ; now enable 8259 PIC
  10538.          AND     AL,NOT IMRMSK
  10539.          OUT     21h,AL
  10540.          MOV     AL,20h          ; then send out an EOI
  10541.          OUT     20h,AL
  10542.          POP     DS              ; restore regs
  10543.          POP     ES
  10544.          MOV     SP,BP
  10545.          POP     BP
  10546.          RET
  10547.  _i_m    endp
  10548.  
  10549.  _u_m    proc    near            ; uninstall modem service
  10550.          PUSH    BP
  10551.          MOV     BP,SP           ; save registers
  10552.          IN      AL,21h          ; disable COM int in 8259
  10553.          OR      AL,IMRMSK
  10554.          OUT     21h,AL
  10555.          PUSH    ES
  10556.          PUSH    DS
  10557.          MOV     AX,CS           ; set same as CS
  10558.          MOV     DS,AX
  10559.          MOV     ES,AX
  10560.          MOV     AL,0            ; disable UART ints
  10561.          MOV     DX,BPORT+1
  10562.          OUT     DX,AL
  10563.          MOV     DX,oiv_o        ; restore original vector
  10564.          MOV     DS,oiv_s
  10565.          MOV     AX,PUTIV
  10566.          INT     21h
  10567.          POP     DS              ; restore registers
  10568.          POP     ES
  10569.          MOV     SP,BP
  10570.          POP     BP
  10571.          RET
  10572.  _u_m    endp
  10573.  
  10574.  _TEXT   ends
  10575.  
  10576.          END
  10577.  
  10578.  \SAMPCODE\DOS_ENCY\6\CH1A.ASM
  10579.  
  10580.          TITLE   CH1A.ASM
  10581.  
  10582.  ; CH1A.ASM -- support file for CTERM.C terminal emulator
  10583.  ;       this set of routines replaces Ctrl-C/Ctrl-BREAK
  10584.  ;       usage: void set_int(), rst_int();
  10585.  ;               int broke();    /* boolean if BREAK     */
  10586.  ;       for use with Microsoft C and SMALL model only...
  10587.  
  10588.  _TEXT   segment byte public 'CODE'
  10589.  _TEXT   ends
  10590.  _DATA   segment byte public 'DATA'
  10591.  _DATA   ends
  10592.  CONST   segment byte public 'CONST'
  10593.  CONST   ends
  10594.  _BSS    segment byte public 'BSS'
  10595.  _BSS    ends
  10596.  
  10597.  DGROUP  GROUP   CONST, _BSS, _DATA
  10598.          ASSUME  CS:_TEXT, DS:DGROUP, ES:DGROUP, SS:DGROUP
  10599.  
  10600.  _DATA   SEGMENT BYTE PUBLIC 'DATA'
  10601.  
  10602.  OLDINT1B DD     0               ; storage for original INT 1BH vector
  10603.  
  10604.  _DATA   ENDS
  10605.  
  10606.  _TEXT   SEGMENT
  10607.  
  10608.          PUBLIC  _set_int,_rst_int,_broke
  10609.  
  10610.  myint1b:
  10611.          mov     word ptr cs:brkflg,1Bh          ; make it nonzero
  10612.          iret
  10613.  
  10614.  myint23:
  10615.          mov     word ptr cs:brkflg,23h          ; make it nonzero
  10616.          iret
  10617.  
  10618.  brkflg  dw      0               ; flag that BREAK occurred
  10619.  
  10620.  _broke  proc    near            ; returns 0 if no break
  10621.          xor     ax,ax           ; prepare to reset flag
  10622.          xchg    ax,cs:brkflg    ; return current flag value
  10623.          ret
  10624.  _broke  endp
  10625.  
  10626.  _set_int proc near
  10627.          mov     ax,351bh        ; get interrupt vector for 1BH
  10628.          int     21h             ; (don't need to save for 23H)
  10629.          mov     word ptr oldint1b,bx     ; save offset in first word
  10630.          mov     word ptr oldint1b+2,es   ; save segment in second word
  10631.  
  10632.          push    ds              ; save our data segment
  10633.          mov     ax,cs           ; set DS to CS for now
  10634.          mov     ds,ax
  10635.          lea     dx,myint1b      ; DS:DX points to new routine
  10636.          mov     ax,251bh        ; set interrupt vector
  10637.          int     21h
  10638.          mov     ax,cs           ; set DS to CS for now
  10639.          mov     ds,ax
  10640.          lea     dx,myint23      ; DS:DX points to new routine
  10641.          mov     ax,2523h        ; set interrupt vector
  10642.          int     21h
  10643.          pop     ds              ; restore data segment
  10644.          ret
  10645.  _set_int endp
  10646.  
  10647.  _rst_int proc near
  10648.          push    ds              ; save our data segment
  10649.          lds     dx,oldint1b     ; DS:DX points to original
  10650.          mov     ax,251bh        ; set interrupt vector
  10651.          int     21h
  10652.          pop     ds              ; restore data segment
  10653.          ret
  10654.  _rst_int endp
  10655.  
  10656.  _TEXT   ends
  10657.  
  10658.          END
  10659.  
  10660.  \SAMPCODE\DOS_ENCY\6\CH2.ASM
  10661.  
  10662.          TITLE   CH2.ASM
  10663.  
  10664.  ; CH2.ASM -- support file for CTERM.C terminal emulator
  10665.  ;       for use with Microsoft C and SMALL model only...
  10666.  
  10667.  _TEXT   segment byte public 'CODE'
  10668.  _TEXT   ends
  10669.  _DATA   segment byte public 'DATA'
  10670.  _DATA   ends
  10671.  CONST   segment byte public 'CONST'
  10672.  CONST   ends
  10673.  _BSS    segment byte public 'BSS'
  10674.  _BSS    ends
  10675.  
  10676.  DGROUP  GROUP   CONST, _BSS, _DATA
  10677.          assume  CS:_TEXT, DS:DGROUP, ES:DGROUP, SS:DGROUP
  10678.  
  10679.  _TEXT   segment
  10680.  
  10681.          public  __cls,__color,__deol,__i_v,__key,__wrchr,__wrpos
  10682.  
  10683.  atrib   DB      0               ; attribute
  10684.  _colr   DB      0               ; color
  10685.  v_bas   DW      0               ; video segment
  10686.  v_ulc   DW      0               ; upper left corner cursor
  10687.  v_lrc   DW      184Fh           ; lower right corner cursor
  10688.  v_col   DW      0               ; current col/row
  10689.  
  10690.  __key   proc    near            ; get keystroke
  10691.          PUSH    BP
  10692.          MOV     AH,1            ; check status via BIOS
  10693.          INT     16h
  10694.          MOV     AX,0FFFFh
  10695.          JZ      key00           ; none ready, return EOF
  10696.          MOV     AH,0            ; have one, read via BIOS
  10697.          INT     16h
  10698.  key00:  POP     BP
  10699.          RET
  10700.  __key   endp
  10701.  
  10702.  __wrchr proc    near
  10703.          PUSH    BP
  10704.          MOV     BP,SP
  10705.          MOV     AL,[BP+4]       ; get char passed by C
  10706.          CMP     AL,' '
  10707.          JNB     prchr           ; printing char, go do it
  10708.          CMP     AL,8
  10709.          JNZ     notbs
  10710.          DEC     BYTE PTR v_col  ; process backspace
  10711.          MOV     AL,byte ptr v_col
  10712.          CMP     AL,byte ptr v_ulc
  10713.          JB      nxt_c           ; step to next column
  10714.          JMP     norml
  10715.  
  10716.  notbs:  CMP     AL,9
  10717.          JNZ     notht
  10718.          MOV     AL,byte ptr v_col       ; process HTAB
  10719.          ADD     AL,8
  10720.          AND     AL,0F8h
  10721.          MOV     byte ptr v_col,AL
  10722.          CMP     AL,byte ptr v_lrc
  10723.          JA      nxt_c
  10724.          JMP     SHORT   norml
  10725.  
  10726.  notht:  CMP     AL,0Ah
  10727.          JNZ     notlf
  10728.          MOV     AL,byte ptr v_col+1     ; process linefeed
  10729.          INC     AL
  10730.          CMP     AL,byte ptr v_lrc+1
  10731.          JBE     noht1
  10732.          CALL    scrol
  10733.          MOV     AL,byte ptr v_lrc+1
  10734.  noht1:  MOV     byte ptr v_col+1,AL
  10735.          JMP     SHORT   norml
  10736.  
  10737.  notlf:  CMP     AL,0Ch
  10738.          JNZ     ck_cr
  10739.          CALL    __cls           ; process formfeed
  10740.          JMP     SHORT   ignor
  10741.  
  10742.  ck_cr:  CMP     AL,0Dh
  10743.          JNZ     ignor           ; ignore all other CTL chars
  10744.          MOV     AL,byte ptr v_ulc       ; process CR
  10745.          MOV     byte ptr v_col,AL
  10746.          JMP     SHORT   norml
  10747.  
  10748.  prchr:  MOV     AH,_colr        ; process printing char
  10749.          PUSH    AX
  10750.          XOR     AH,AH
  10751.          MOV     AL,byte ptr v_col+1
  10752.          PUSH    AX
  10753.          MOV     AL,byte ptr v_col
  10754.          PUSH    AX
  10755.          CALL    wrtvr
  10756.          MOV     SP,BP
  10757.  nxt_c:  INC     BYTE PTR v_col  ; advance to next column
  10758.          MOV     AL,byte ptr v_col
  10759.          CMP     AL,byte ptr v_lrc
  10760.          JLE     norml
  10761.          MOV     AL,0Dh          ; went off end, do CR/LF
  10762.          PUSH    AX
  10763.          CALL    __wrchr
  10764.          POP     AX
  10765.          MOV     AL,0Ah
  10766.          PUSH    AX
  10767.          CALL    __wrchr
  10768.          POP     AX
  10769.  norml:  CALL    set_cur
  10770.  ignor:  MOV     SP,BP
  10771.          POP     BP
  10772.          RET
  10773.  __wrchr endp
  10774.  
  10775.  __i_v   proc    near            ; establish video base segment
  10776.          PUSH    BP
  10777.          MOV     BP,SP
  10778.          MOV     AX,0B000h       ; mono, B800 for CGA
  10779.          MOV     v_bas,AX        ; could be made automatic
  10780.          MOV     SP,BP
  10781.          POP     BP
  10782.          RET
  10783.  __i_v   endp
  10784.  
  10785.  __wrpos proc    near            ; set cursor position
  10786.          PUSH    BP
  10787.          MOV     BP,SP
  10788.          MOV     DH,[BP+4]       ; row from C program
  10789.          MOV     DL,[BP+6]       ; col from C program
  10790.          MOV     v_col,DX        ; cursor position
  10791.          MOV     BH,atrib        ; attribute
  10792.          MOV     AH,2
  10793.          PUSH    BP
  10794.          INT     10h
  10795.          POP     BP
  10796.          MOV     AX,v_col        ; return cursor position
  10797.          MOV     SP,BP
  10798.          POP     BP
  10799.          RET
  10800.  __wrpos endp
  10801.  
  10802.  set_cur proc    near            ; set cursor to v_col
  10803.          PUSH    BP
  10804.          MOV     BP,SP
  10805.          MOV     DX,v_col        ; use where v_col says
  10806.          MOV     BH,atrib
  10807.          MOV     AH,2
  10808.          PUSH    BP
  10809.          INT     10h
  10810.          POP     BP
  10811.          MOV     AX,v_col
  10812.          MOV     SP,BP
  10813.          POP     BP
  10814.          RET
  10815.  set_cur endp
  10816.  
  10817.  __color proc    near            ; _color(fg, bg)
  10818.          PUSH    BP
  10819.          MOV     BP,SP
  10820.          MOV     AH,[BP+6]       ; background from C
  10821.          MOV     AL,[BP+4]       ; foreground from C
  10822.          MOV     CX,4
  10823.          SHL     AH,CL
  10824.          AND     AL,0Fh
  10825.          OR      AL,AH           ; pack up into 1 byte
  10826.          MOV     _colr,AL        ; store for handler's use
  10827.          XOR     AH,AH
  10828.          MOV     SP,BP
  10829.          POP     BP
  10830.          RET
  10831.  __color endp
  10832.  
  10833.  scrol   proc    near            ; scroll CRT up by one line
  10834.          PUSH    BP
  10835.          MOV     BP,SP
  10836.          MOV     AL,1            ; count of lines to scroll
  10837.          MOV     CX,v_ulc
  10838.          MOV     DX,v_lrc
  10839.          MOV     BH,_colr
  10840.          MOV     AH,6
  10841.          PUSH    BP
  10842.          INT     10h             ; use BIOS
  10843.          POP     BP
  10844.          MOV     SP,BP
  10845.          POP     BP
  10846.          RET
  10847.  scrol   endp
  10848.  
  10849.  __cls   proc    near            ; clear CRT
  10850.          PUSH    BP
  10851.          MOV     BP,SP
  10852.          MOV     AL,0            ; flags CLS to BIOS
  10853.          MOV     CX,v_ulc
  10854.          MOV     v_col,CX        ; set to HOME
  10855.          MOV     DX,v_lrc
  10856.          MOV     BH,_colr
  10857.          MOV     AH,6
  10858.          PUSH    BP
  10859.          INT     10h             ; use BIOS scroll up
  10860.          POP     BP
  10861.          CALL    set_cur         ; cursor to HOME
  10862.          MOV     SP,BP
  10863.          POP     BP
  10864.          RET
  10865.  __cls   endp
  10866.  
  10867.  __deol  proc    near            ; delete to end of line
  10868.          PUSH    BP
  10869.          MOV     BP,SP
  10870.          MOV     AL,' '
  10871.          MOV     AH,_colr        ; set up blanks
  10872.          PUSH    AX
  10873.          MOV     AL,byte ptr v_col+1
  10874.          XOR     AH,AH           ; set up row value
  10875.          PUSH    AX
  10876.          MOV     AL,byte ptr v_col
  10877.  
  10878.  deol1:  CMP     AL,byte ptr v_lrc
  10879.          JA      deol2           ; at RH edge
  10880.          PUSH    AX              ; current location
  10881.          CALL    wrtvr           ; write a blank
  10882.          POP     AX
  10883.          INC     AL              ; next column
  10884.          JMP     deol1           ; do it again
  10885.  
  10886.  deol2:  MOV     AX,v_col        ; return cursor position
  10887.          MOV     SP,BP
  10888.          POP     BP
  10889.          RET
  10890.  __deol  endp
  10891.  
  10892.  wrtvr   proc    near            ; write video RAM (col, row, char/atr)
  10893.          PUSH    BP
  10894.          MOV     BP,SP           ; set up arg ptr
  10895.          MOV     DL,[BP+4]       ; column
  10896.          MOV     DH,[BP+6]       ; row
  10897.          MOV     BX,[BP+8]       ; char/atr
  10898.          MOV     AL,80           ; calc offset
  10899.          MUL     DH
  10900.          XOR     DH,DH
  10901.          ADD     AX,DX
  10902.          ADD     AX,AX           ; adjust bytes to words
  10903.          PUSH    ES              ; save seg reg
  10904.          MOV     DI,AX
  10905.          MOV     AX,v_bas        ; set up segment
  10906.          MOV     ES,AX
  10907.          MOV     AX,BX           ; get the data
  10908.          STOSW                   ; put on screen
  10909.          POP     ES              ; restore regs
  10910.          MOV     SP,BP
  10911.          POP     BP
  10912.          RET
  10913.  wrtvr   endp
  10914.  
  10915.  _TEXT   ends
  10916.  
  10917.          END
  10918.  
  10919.  \SAMPCODE\DOS_ENCY\6\COMDVR.ASM
  10920.  
  10921.  Title   COMDVR  Driver for IBM COM Ports
  10922.  ;       Jim Kyle, 1987
  10923.  ;           Based on ideas from many sources......
  10924.  ;               including Mike Higgins, CLM March 1985;
  10925.  ;               public-domain INTBIOS program from BBS's;
  10926.  ;               COMBIOS.COM from CIS Programmers' SIG; and
  10927.  ;               ADVANCED MS-DOS by Ray Duncan.
  10928.  Subttl  MS-DOS Driver Definitions
  10929.  
  10930.          Comment *       This comments out the Dbg macro.....
  10931.  Dbg     Macro   Ltr1,Ltr2,Ltr3  ; used only to debug driver...
  10932.          Local   Xxx
  10933.          Push    Es              ; save all regs used
  10934.          Push    Di
  10935.          Push    Ax
  10936.          Les     Di,Cs:Dbgptr    ; get pointer to CRT
  10937.          Mov     Ax,Es:[di]
  10938.          Mov     Al,Ltr1         ; move in letters
  10939.          Stosw
  10940.          Mov     Al,Ltr2
  10941.          Stosw
  10942.          Mov     Al,Ltr3
  10943.          Stosw
  10944.          Cmp     Di,1600         ; top 10 lines only
  10945.          Jb      Xxx
  10946.          Xor     Di,Di
  10947.  Xxx:    Mov     Word Ptr Cs:Dbgptr,Di
  10948.          Pop     Ax
  10949.          Pop     Di
  10950.          Pop     Es
  10951.          Endm
  10952.          *                       ; asterisk ends commented-out region
  10953.  ;
  10954.  ;               Device Type Codes
  10955.  DevChr  Equ     8000h   ; this is a character device
  10956.  DevBlk  Equ     0000h   ; this is a block (disk) device
  10957.  DevIoc  Equ     4000h   ; this device accepts IOCTL requests
  10958.  DevNon  Equ     2000h   ; non-IBM disk driver (block only)
  10959.  DevOTB  Equ     2000h   ; MS-DOS 3.x out until busy supported (char)
  10960.  DevOCR  Equ     0800h   ; MS-DOS 3.x open/close/rm supported
  10961.  DevX32  Equ     0040h   ; MS-DOS 3.2 functions supported
  10962.  DevSpc  Equ     0010h   ; accepts special interrupt 29H
  10963.  DevClk  Equ     0008h   ; this is the CLOCK device
  10964.  DevNul  Equ     0004h   ; this is the NUL device
  10965.  DevSto  Equ     0002h   ; this is standard output
  10966.  DevSti  Equ     0001h   ; this is standard input
  10967.  ;
  10968.  ;               Error Status BITS
  10969.  StsErr  Equ     8000h   ; general error
  10970.  StsBsy  Equ     0200h   ; device busy
  10971.  StsDne  Equ     0100h   ; request completed
  10972.  ;
  10973.  ;               Error Reason values for lower-order bits
  10974.  ErrWp   Equ     0       ; write protect error
  10975.  ErrUu   Equ     1       ; unknown unit
  10976.  ErrDnr  Equ     2       ; drive not ready
  10977.  ErrUc   Equ     3       ; unknown command
  10978.  ErrCrc  Equ     4       ; cyclical redundancy check error
  10979.  ErrBsl  Equ     5       ; bad drive request structure length
  10980.  ErrSl   Equ     6       ; seek error
  10981.  ErrUm   Equ     7       ; unknown media
  10982.  ErrSnf  Equ     8       ; sector not found
  10983.  ErrPop  Equ     9       ; printer out of paper
  10984.  ErrWf   Equ     10      ; write fault
  10985.  ErrRf   Equ     11      ; read fault
  10986.  ErrGf   Equ     12      ; general failure
  10987.  ;
  10988.  ;       Structure of an I/O request packet header.
  10989.  ;
  10990.  Pack    Struc
  10991.  Len     Db      ?       ; length of record
  10992.  Prtno   Db      ?       ; unit code
  10993.  Code    Db      ?       ; command code
  10994.  Stat    Dw      ?       ; return status
  10995.  Dosq    Dd      ?       ; (unused MS-DOS queue link pointer)
  10996.  Devq    Dd      ?       ; (unused driver queue link pointer)
  10997.  Media   Db      ?       ; media code on read/write
  10998.  Xfer    Dw      ?       ; xfer address offset
  10999.  Xseg    Dw      ?       ; xfer address segment
  11000.  Count   Dw      ?       ; transfer byte count
  11001.  Sector  Dw      ?       ; starting sector value (block only)
  11002.  Pack    Ends
  11003.  
  11004.  Subttl  IBM-PC Hardware Driver Definitions
  11005.  page
  11006.  ;
  11007.  ;               8259 data
  11008.  PIC_b   Equ     020h    ; port for EOI
  11009.  PIC_e   Equ     021h    ; port for Int enabling
  11010.  EOI     Equ     020h    ; EOI control word
  11011.  ;
  11012.  ;               8250 port offsets
  11013.  RxBuf   Equ     0F8h    ; base address
  11014.  Baud1   Equ     RxBuf+1 ; baud divisor high byte
  11015.  IntEn   Equ     RxBuf+1 ; interrupt enable register
  11016.  IntId   Equ     RxBuf+2 ; interrupt identification register
  11017.  Lctrl   Equ     RxBuf+3 ; line control register
  11018.  Mctrl   Equ     RxBuf+4 ; modem control register
  11019.  Lstat   Equ     RxBuf+5 ; line status register
  11020.  Mstat   Equ     RxBuf+6 ; modem status register
  11021.  ;
  11022.  ;               8250 LCR constants
  11023.  Dlab    Equ     10000000b ; divisor latch access bit
  11024.  SetBrk  Equ     01000000b ; send break control bit
  11025.  StkPar  Equ     00100000b ; stick parity control bit
  11026.  EvnPar  Equ     00010000b ; even parity bit
  11027.  GenPar  Equ     00001000b ; generate parity bit
  11028.  Xstop   Equ     00000100b ; extra stop bit
  11029.  Wd8     Equ     00000011b ; word length = 8
  11030.  Wd7     Equ     00000010b ; word length = 7
  11031.  Wd6     Equ     00000001b ; word length = 6
  11032.  ;
  11033.  ;               8250 LSR constants
  11034.  xsre    Equ     01000000b ; xmt SR empty
  11035.  xhre    Equ     00100000b ; xmt HR empty
  11036.  BrkRcv  Equ     00010000b ; break received
  11037.  FrmErr  Equ     00001000b ; framing error
  11038.  ParErr  Equ     00000100b ; parity error
  11039.  OveRun  Equ     00000010b ; overrun error
  11040.  rdta    Equ     00000001b ; received data ready
  11041.  AnyErr  Equ     BrkRcv+FrmErr+ParErr+OveRun
  11042.  ;
  11043.  ;               8250 MCR constants
  11044.  LpBk    Equ     00010000b ; UART out loops to in (test)
  11045.  Usr2    Equ     00001000b ; Gates 8250 interrupts
  11046.  Usr1    Equ     00000100b ; aux user1 output
  11047.  SetRTS  Equ     00000010b ; sets RTS output
  11048.  SetDTR  Equ     00000001b ; sets DTR output
  11049.  ;
  11050.  ;               8250 MSR constants
  11051.  CDlvl   Equ     10000000b ; carrier detect level
  11052.  RIlvl   Equ     01000000b ; ring indicator level
  11053.  DSRlvl  Equ     00100000b ; DSR level
  11054.  CTSlvl  Equ     00010000b ; CTS level
  11055.  CDchg   Equ     00001000b ; Carrier Detect change
  11056.  RIchg   Equ     00000100b ; Ring Indicator change
  11057.  DSRchg  Equ     00000010b ; DSR change
  11058.  CTSchg  Equ     00000001b ; CTS change
  11059.  ;
  11060.  ;               8250 IER constants
  11061.  S_Int   Equ     00001000b ; enable status interrupt
  11062.  E_Int   Equ     00000100b ; enable error interrupt
  11063.  X_Int   Equ     00000010b ; enable transmit interrupt
  11064.  R_Int   Equ     00000001b ; enable receive interrupt
  11065.  Allint  Equ     00001111b ; enable all interrupts
  11066.  
  11067.  Subttl  Definitions for THIS Driver
  11068.  page
  11069.  ;
  11070.  ;               Bit definitions for the output status byte
  11071.  ;                      ( this driver only )
  11072.  LinIdl  Equ     0ffh    ; if all bits off, xmitter is idle
  11073.  LinXof  Equ     1       ; output is suspended by XOFF
  11074.  LinDSR  Equ     2       ; output is suspended until DSR comes on again
  11075.  LinCTS  Equ     4       ; output is suspended until CTS comes on again
  11076.  ;
  11077.  ;               Bit definitions for the input status byte
  11078.  ;                       ( this driver only )
  11079.  BadInp  Equ     1       ; input line errors have been detected
  11080.  LostDt  Equ     2       ; receiver buffer overflowed, data lost
  11081.  OffLin  Equ     4       ; device is off line now
  11082.  ;
  11083.  ;               Bit definitions for the special characteristics words
  11084.  ;                       ( this driver only )
  11085.  ;               InSpec controls how input from the UART is treated
  11086.  ;
  11087.  InEpc   Equ     0001h   ; errors translate to codes with parity bit on
  11088.  ;
  11089.  ;               OutSpec controls how output to the UART is treated
  11090.  ;
  11091.  OutDSR  Equ     0001h   ; DSR is used to throttle output data
  11092.  OutCTS  Equ     0002h   ; CTS is used to throttle output data
  11093.  OutXon  Equ     0004h   ; XON/XOFF is used to throttle output data
  11094.  OutCdf  Equ     0010h   ; carrier detect is off-line signal
  11095.  OutDrf  Equ     0020h   ; DSR is off-line signal
  11096.  ;
  11097.  Unit    Struc           ; each unit has a structure defining its state:
  11098.  Port    Dw      ?       ; I/O port address
  11099.  Vect    Dw      ?       ; interrupt vector offset (NOT interrupt number!)
  11100.  Isradr  Dw      ?       ; offset to interrupt service routine
  11101.  OtStat  Db      Wd8     ; default LCR bit settings during INIT,
  11102.                          ; output status bits after
  11103.  InStat  Db      Usr2+SetRTS+SetDTR   ; MCR bit settings during INIT,
  11104.                          ; input status bits after
  11105.  InSpec  Dw      InEpc   ; special mode bits for INPUT
  11106.  OutSpec Dw      OutXon  ; special mode bits for OUTPUT
  11107.  Baud    Dw      96      ; current baud rate divisor value (1200 b)
  11108.  Ifirst  Dw      0       ; offset of first character in input buffer
  11109.  Iavail  Dw      0       ; offset of next available byte
  11110.  Ibuf    Dw      ?       ; pointer to input buffer
  11111.  Ofirst  Dw      0       ; offset of first character in output buffer
  11112.  Oavail  Dw      0       ; offset of next avail byte in output buffer
  11113.  Obuf    Dw      ?       ; pointer to output buffer
  11114.  Unit    Ends
  11115.  
  11116.  ;
  11117.  ;       Beginning of driver code and data
  11118.  ;
  11119.  Driver  Segment
  11120.          Assume  Cs:driver, ds:driver, es:driver
  11121.          Org     0               ; drivers start at 0
  11122.  
  11123.          Dw      Async2,-1       ; pointer to next device
  11124.          Dw      DevChr + DevIoc ; character device with IOCTL
  11125.          Dw      Strtegy         ; offset of Strategy routine
  11126.          Dw      Request1        ; offset of interrupt entry point 1
  11127.          Db      'ASY1    '      ; device 1 name
  11128.  Async2:
  11129.          Dw      -1,-1           ; pointer to next device: MS-DOS fills in
  11130.          Dw      DevChr + DevIoc ; character device with IOCTL
  11131.          Dw      Strtegy         ; offset of Strategy routine
  11132.          Dw      Request2        ; offset of interrupt entry point 2
  11133.          Db      'ASY2    '      ; device 2 name
  11134.  
  11135.  ;dbgptr dd      0b0000000h
  11136.  ;
  11137.  ;         Following is the storage area for the request packet pointer
  11138.  ;
  11139.  PackHd  Dd      0
  11140.  ;
  11141.  ;         baud rate conversion table
  11142.  Asy_baudt Dw           50,2304          ; first value is desired baud rate
  11143.            Dw           75,1536          ; second is divisor register value
  11144.            Dw          110,1047
  11145.            Dw          134, 857
  11146.            Dw          150, 786
  11147.            Dw          300, 384
  11148.            Dw          600, 192
  11149.            Dw         1200,  96
  11150.            Dw         1800,  64
  11151.            Dw         2000,  58
  11152.            Dw         2400,  48
  11153.            Dw         3600,  32
  11154.            Dw         4800,  24
  11155.            Dw         7200,  16
  11156.            Dw         9600,  12
  11157.  
  11158.  ; table of structures
  11159.  ;       ASY1 defaults to the COM1 port, INT 0CH vector, XON,
  11160.  ;       no parity, 8 databits, 1 stop bit, and 1200 baud
  11161.  Asy_tab1:
  11162.          Unit    <3f8h,30h,asy1isr,,,,,,,,in1buf,,,out1buf>
  11163.  
  11164.  ;       ASY2 defaults to the COM2 port, INT 0BH vector, XON,
  11165.  ;       no parity, 8 databits, 1 stop bit, and 1200 baud
  11166.  Asy_tab2:
  11167.          Unit    <2f8h,2ch,asy2isr,,,,,,,,in2buf,,,out2buf>
  11168.  
  11169.  Bufsiz  Equ     256        ; input buffer size
  11170.  Bufmsk  =       Bufsiz-1   ; mask for calculating offsets modulo bufsiz
  11171.  In1buf  Db      Bufsiz DUP (?)
  11172.  Out1buf Db      Bufsiz DUP (?)
  11173.  In2buf  Db      Bufsiz DUP (?)
  11174.  Out2buf Db      Bufsiz DUP (?)
  11175.  ;
  11176.  ;               Following is a table of offsets to all the driver functions
  11177.  
  11178.  Asy_funcs:
  11179.          Dw      Init            ;  0 initialize driver
  11180.          Dw      Mchek           ;  1 media check (block only)
  11181.          Dw      BldBPB          ;  2 build BPB (block only)
  11182.          Dw      Ioctlin         ;  3 IOCTL read
  11183.          Dw      Read            ;  4 read
  11184.          Dw      Ndread          ;  5 nondestructive read
  11185.          Dw      Rxstat          ;  6 input status
  11186.          Dw      Inflush         ;  7 flush input buffer
  11187.          Dw      Write           ;  8 write
  11188.          Dw      Write           ;  9 write with verify
  11189.          Dw      Txstat          ; 10 output status
  11190.          Dw      Txflush         ; 11 flush output buffer
  11191.          Dw      Ioctlout        ; 12 IOCTL write
  11192.  ; Following are not used in this driver.....
  11193.          Dw      Zexit           ; 13 open (3.x only, not used)
  11194.          Dw      Zexit           ; 14 close (3.x only, not used)
  11195.          Dw      Zexit           ; 15 rem med (3.x only, not used)
  11196.          Dw      Zexit           ; 16 out until bsy (3.x only, not used)
  11197.          Dw      Zexit           ; 17
  11198.          Dw      Zexit           ; 18
  11199.          Dw      Zexit           ; 19 generic IOCTL request (3.2 only)
  11200.          Dw      Zexit           ; 20
  11201.          Dw      Zexit           ; 21
  11202.          Dw      Zexit           ; 22
  11203.          Dw      Zexit           ; 23 get logical drive map (3.2 only)
  11204.          Dw      Zexit           ; 24 set logical drive map (3.2 only)
  11205.  
  11206.  Subttl  Driver Code
  11207.  Page
  11208.  ;
  11209.  ;       The Strategy routine itself:
  11210.  ;
  11211.  Strtegy Proc    Far
  11212.  ;       dbg     'S','R',' '
  11213.          Mov     Word Ptr CS:PackHd,BX   ; store the offset
  11214.          Mov     Word Ptr CS:PackHd+2,ES ; store the segment
  11215.          Ret
  11216.  Strtegy Endp
  11217.  ;
  11218.  Request1:                       ; async1 has been requested
  11219.          Push    Si              ; save SI
  11220.          Lea     Si,Asy_tab1     ; get the device unit table address
  11221.          Jmp     Short   Gen_request
  11222.  
  11223.  Request2:                       ; async2 has been requested
  11224.          Push    Si              ; save SI
  11225.          Lea     Si,Asy_tab2     ; get unit table two's address
  11226.  
  11227.  Gen_request:
  11228.  ;       dbg     'R','R',' '
  11229.          Pushf                   ; save all regs
  11230.          Cld
  11231.          Push    Ax
  11232.          Push    Bx
  11233.          Push    Cx
  11234.          Push    Dx
  11235.          Push    Di
  11236.          Push    Bp
  11237.          Push    Ds
  11238.          Push    Es
  11239.          Push    Cs              ; set DS = CS
  11240.          Pop     Ds
  11241.          Les     Bx,PackHd       ; get packet pointer
  11242.          Lea     Di,Asy_funcs    ; point DI to jump table
  11243.          Mov     Al,es:code[bx]  ; command code
  11244.          Cbw
  11245.          Add     Ax,Ax           ; double to word
  11246.          Add     Di,ax
  11247.          Jmp     [di]            ; go do it
  11248.  ;
  11249.  ;       Exit from driver request
  11250.  ;
  11251.  ExitP   Proc    Far
  11252.  Bsyexit:
  11253.          Mov     Ax,StsBsy
  11254.          Jmp     Short   Exit
  11255.  
  11256.  Mchek:
  11257.  BldBPB:
  11258.  Zexit:  Xor     Ax,Ax
  11259.  Exit:   Les     Bx,PackHd       ; get packet pointer
  11260.          Or      Ax,StsDne
  11261.          Mov     Es:Stat[Bx],Ax  ; set return status
  11262.          Pop     Es              ; restore registers
  11263.          Pop     Ds
  11264.          Pop     Bp
  11265.          Pop     Di
  11266.          Pop     Dx
  11267.          Pop     Cx
  11268.          Pop     Bx
  11269.          Pop     Ax
  11270.          Popf
  11271.          Pop     Si
  11272.          Ret
  11273.  ExitP   Endp
  11274.  
  11275.  Subttl  Driver Service Routines
  11276.  Page
  11277.  
  11278.  ;       Read data from device
  11279.  
  11280.  Read:
  11281.  ;       dbg     'R','d',' '
  11282.          Mov     Cx,Es:Count[bx] ; get requested nbr
  11283.          Mov     Di,Es:Xfer[bx]  ; get target pointer
  11284.          Mov     Dx,Es:Xseg[bx]
  11285.          Push    Bx              ; save for count fixup
  11286.          Push    Es
  11287.          Mov     Es,Dx
  11288.          Test    InStat[si],BadInp Or LostDt
  11289.          Je      No_lerr         ; no error so far...
  11290.          Add     Sp,4            ; error, flush SP
  11291.          And     InStat[si],Not ( BadInp Or LostDt )
  11292.          Mov     Ax,ErrRf        ; error, report it
  11293.          Jmp     Exit
  11294.  No_lerr:
  11295.          Call    Get_in          ; go for one
  11296.          Or      Ah,Ah
  11297.          Jnz     Got_all         ; none to get now
  11298.          Stosb                   ; store it
  11299.          Loop    No_lerr         ; go for more
  11300.  Got_all:
  11301.          Pop     Es
  11302.          Pop     Bx
  11303.          Sub     Di,Es:Xfer[bx]  ; calc number stored
  11304.          Mov     Es:Count[bx],Di ; return as count
  11305.          Jmp     Zexit
  11306.  
  11307.  ;       Nondestructive read from device
  11308.  
  11309.  Ndread:
  11310.          Mov     Di,ifirst[si]
  11311.          Cmp     Di,iavail[si]
  11312.          Jne     Ndget
  11313.          Jmp     Bsyexit         ; buffer empty
  11314.  Ndget:
  11315.          Push    Bx
  11316.          Mov     Bx,ibuf[si]
  11317.          Mov     Al,[bx+di]
  11318.          Pop     Bx
  11319.          Mov     Es:media[bx],al ; return char
  11320.          Jmp     Zexit
  11321.  
  11322.  ;       Input status request
  11323.  
  11324.  Rxstat:
  11325.          Mov     Di,ifirst[si]
  11326.          Cmp     Di,iavail[si]
  11327.          Jne     Rxful
  11328.          Jmp     Bsyexit         ; buffer empty
  11329.  Rxful:
  11330.          Jmp     Zexit           ; have data
  11331.  
  11332.  ;       Input flush request
  11333.  
  11334.  Inflush:
  11335.          Mov     Ax,iavail[si]
  11336.          Mov     Ifirst[si],ax
  11337.          Jmp     Zexit
  11338.  
  11339.  ;       Output data to device
  11340.  
  11341.  Write:
  11342.  ;       dbg     'W','r',' '
  11343.          Mov     Cx,es:count[bx]
  11344.          Mov     Di,es:xfer[bx]
  11345.          Mov     Ax,es:xseg[bx]
  11346.          Mov     Es,ax
  11347.  Wlup:
  11348.          Mov     Al,es:[di]      ; get the byte
  11349.          Inc     Di
  11350.  Wwait:
  11351.          Call    Put_out         ; put away
  11352.          Cmp     Ah,0
  11353.          Jne     Wwait           ; wait for room!
  11354.          Call    Start_output    ; get it going
  11355.          Loop    Wlup
  11356.  
  11357.          Jmp     Zexit
  11358.  
  11359.  ;       Output status request
  11360.  
  11361.  Txstat:
  11362.          Mov     Ax,ofirst[si]
  11363.          Dec     Ax
  11364.          And     Ax,bufmsk
  11365.          Cmp     Ax,oavail[si]
  11366.          Jne     Txroom
  11367.          Jmp     Bsyexit         ; buffer full
  11368.  Txroom:
  11369.          Jmp     Zexit           ; room exists
  11370.  
  11371.  ;       IOCTL read request, return line parameters
  11372.  
  11373.  Ioctlin:
  11374.          Mov     Cx,es:count[bx]
  11375.          Mov     Di,es:xfer[bx]
  11376.          Mov     Dx,es:xseg[bx]
  11377.          Mov     Es,dx
  11378.          Cmp     Cx,10
  11379.          Je      Doiocin
  11380.          Mov     Ax,errbsl
  11381.          Jmp     Exit
  11382.  Doiocin:
  11383.          Mov     Dx,port[si]     ; base port
  11384.          Mov     Dl,Lctrl        ; line status
  11385.          Mov     Cx,4            ; LCR, MCR, LSR, MSR
  11386.  Getport:
  11387.          In      Al,dx
  11388.          Stos    Byte Ptr [DI]
  11389.          Inc     Dx
  11390.          Loop    Getport
  11391.  
  11392.          Mov     Ax,InSpec[si]   ; spec in flags
  11393.          Stos    Word Ptr [DI]
  11394.          Mov     Ax,OutSpec[si]  ; out flags
  11395.          Stos    Word Ptr [DI]
  11396.          Mov     Ax,baud[si]     ; baud rate
  11397.          Mov     Bx,di
  11398.          Mov     Di,offset Asy_baudt+2
  11399.          Mov     Cx,15
  11400.  Baudcin:
  11401.          Cmp     [di],ax
  11402.          Je      Yesinb
  11403.          Add     Di,4
  11404.          Loop    Baudcin
  11405.  Yesinb:
  11406.          Mov     Ax,-2[di]
  11407.          Mov     Di,bx
  11408.          Stos    Word Ptr [DI]
  11409.          Jmp     Zexit
  11410.  
  11411.  ;       Flush output buffer request
  11412.  
  11413.  Txflush:
  11414.          Mov     Ax,oavail[si]
  11415.          Mov     Ofirst[si],ax
  11416.          Jmp     Zexit
  11417.  
  11418.  ;       IOCTL request: change line parameters for this driver
  11419.  
  11420.  Ioctlout:
  11421.          Mov     Cx,es:count[bx]
  11422.          Mov     Di,es:xfer[bx]
  11423.          Mov     Dx,es:xseg[bx]
  11424.          Mov     Es,dx
  11425.          Cmp     Cx,10
  11426.          Je      Doiocout
  11427.          Mov     Ax,errbsl
  11428.          Jmp     Exit
  11429.  
  11430.  Doiocout:
  11431.          Mov     Dx,port[si]     ; base port
  11432.          Mov     Dl,Lctrl        ; line ctrl
  11433.          Mov     Al,es:[di]
  11434.          Inc     Di
  11435.          Or      Al,Dlab         ; set baud
  11436.          Out     Dx,al
  11437.          Clc
  11438.          Jnc     $+2
  11439.          Inc     Dx              ; mdm ctrl
  11440.          Mov     Al,es:[di]
  11441.          Or      Al,Usr2         ; Int Gate
  11442.          Out     Dx,al
  11443.          Add     Di,3            ; skip LSR,MSR
  11444.          Mov     Ax,es:[di]
  11445.          Add     Di,2
  11446.          Mov     InSpec[si],ax
  11447.          Mov     Ax,es:[di]
  11448.          Add     Di,2
  11449.          Mov     OutSpec[si],ax
  11450.          Mov     Ax,es:[di]      ; set baud
  11451.          Mov     Bx,di
  11452.          Mov     Di,offset Asy_baudt
  11453.          Mov     Cx,15
  11454.  Baudcout:
  11455.          Cmp     [di],ax
  11456.          Je      Yesoutb
  11457.          Add     Di,4
  11458.          Loop    Baudcout
  11459.  
  11460.          Mov     Dl,Lctrl        ; line ctrl
  11461.          In      Al,dx           ; get LCR data
  11462.          And     Al,not Dlab     ; strip
  11463.          Clc
  11464.          Jnc     $+2
  11465.          Out     Dx,al           ; put back
  11466.          Mov     Ax,ErrUm        ; "unknown media"
  11467.          Jmp     Exit
  11468.  
  11469.  Yesoutb:
  11470.          Mov     Ax,2[di]        ; get divisor
  11471.          Mov     Baud[si],ax     ; save to report later
  11472.          Mov     Dx,port[si]     ; set divisor
  11473.          Out     Dx,al
  11474.          Clc
  11475.          Jnc     $+2
  11476.          Inc     Dx
  11477.          Mov     Al,ah
  11478.          Out     Dx,al
  11479.          Clc
  11480.          Jnc     $+2
  11481.          Mov     Dl,Lctrl        ; line ctrl
  11482.          In      Al,dx           ; get LCR data
  11483.          And     Al,not Dlab     ; strip
  11484.          Clc
  11485.          Jnc     $+2
  11486.          Out     Dx,al           ; put back
  11487.          Jmp     Zexit
  11488.  
  11489.  Subttl  Ring Buffer Routines
  11490.  Page
  11491.  
  11492.  Put_out Proc    Near    ; puts AL into output ring buffer
  11493.          Push    Cx
  11494.          Push    Di
  11495.          Pushf
  11496.          Cli
  11497.          Mov     Cx,oavail[si]   ; put ptr
  11498.          Mov     Di,cx
  11499.          Inc     Cx              ; bump
  11500.          And     Cx,bufmsk
  11501.          Cmp     Cx,ofirst[si]   ; overflow?
  11502.          Je      Poerr           ; yes, don't
  11503.          Add     Di,obuf[si]     ; no
  11504.          Mov     [di],al         ; put in buffer
  11505.          Mov     Oavail[si],cx
  11506.  ;       dbg     'p','o',' '
  11507.          Mov     Ah,0
  11508.          Jmp     Short   Poret
  11509.  Poerr:
  11510.          Mov     Ah,-1
  11511.  Poret:
  11512.          Popf
  11513.          Pop     Di
  11514.          Pop     Cx
  11515.          Ret
  11516.  Put_out Endp
  11517.  
  11518.  Get_out Proc    Near    ; gets next character from output ring buffer
  11519.          Push    Cx
  11520.          Push    Di
  11521.          Pushf
  11522.          Cli
  11523.          Mov     Di,ofirst[si]   ; get ptr
  11524.          Cmp     Di,oavail[si]   ; put ptr
  11525.          Jne     Ngoerr
  11526.          Mov     Ah,-1           ; empty
  11527.          Jmp     Short   Goret
  11528.  Ngoerr:
  11529.  ;       dbg     'g','o',' '
  11530.          Mov     Cx,di
  11531.          Add     Di,obuf[si]
  11532.          Mov     Al,[di]         ; get char
  11533.          Mov     Ah,0
  11534.          Inc     Cx              ; bump ptr
  11535.          And     Cx,bufmsk       ; wrap
  11536.          Mov     Ofirst[si],cx
  11537.  Goret:
  11538.          Popf
  11539.          Pop     Di
  11540.          Pop     Cx
  11541.          Ret
  11542.  Get_out Endp
  11543.  
  11544.  Put_in  Proc    Near    ; puts the char from AL into input ring buffer
  11545.          Push    Cx
  11546.          Push    Di
  11547.          Pushf
  11548.          Cli
  11549.          Mov     Di,iavail[si]
  11550.          Mov     Cx,di
  11551.          Inc     Cx
  11552.          And     Cx,bufmsk
  11553.          Cmp     Cx,ifirst[si]
  11554.          Jne     Npierr
  11555.          Mov     Ah,-1
  11556.          Jmp     Short   Piret
  11557.  Npierr:
  11558.          Add     Di,ibuf[si]
  11559.          Mov     [di],al
  11560.          Mov     Iavail[si],cx
  11561.  ;       dbg     'p','i',' '
  11562.          Mov     Ah,0
  11563.  Piret:
  11564.          Popf
  11565.          Pop     Di
  11566.          Pop     Cx
  11567.          Ret
  11568.  Put_in  Endp
  11569.  
  11570.  Get_in  Proc    Near    ; gets one from input ring buffer into AL
  11571.          Push    Cx
  11572.          Push    Di
  11573.          Pushf
  11574.          Cli
  11575.          Mov     Di,ifirst[si]
  11576.          Cmp     Di,iavail[si]
  11577.          Je      Gierr
  11578.          Mov     Cx,di
  11579.          Add     Di,ibuf[si]
  11580.          Mov     Al,[di]
  11581.          Mov     Ah,0
  11582.  ;       dbg     'g','i',' '
  11583.          Inc     Cx
  11584.          And     Cx,bufmsk
  11585.          Mov     Ifirst[si],cx
  11586.          Jmp     Short   Giret
  11587.  Gierr:
  11588.          Mov     Ah,-1
  11589.  Giret:
  11590.          Popf
  11591.          Pop     Di
  11592.          Pop     Cx
  11593.          Ret
  11594.  Get_in  Endp
  11595.  
  11596.  Subttl  Interrupt Dispatcher Routine
  11597.  Page
  11598.  
  11599.  Asy1isr:
  11600.          Sti
  11601.          Push    Si
  11602.          Lea     Si,asy_tab1
  11603.          Jmp     Short   Int_serve
  11604.  
  11605.  Asy2isr:
  11606.          Sti
  11607.          Push    Si
  11608.          Lea     Si,asy_tab2
  11609.  
  11610.  Int_serve:
  11611.          Push    Ax              ; save all regs
  11612.          Push    Bx
  11613.          Push    Cx
  11614.          Push    Dx
  11615.          Push    Di
  11616.          Push    Ds
  11617.          Push    Cs              ; set DS = CS
  11618.          Pop     Ds
  11619.  Int_exit:
  11620.  ;       dbg     'I','x',' '
  11621.          Mov     Dx,Port[si]     ; base address
  11622.          Mov     Dl,IntId        ; check Int ID
  11623.          In      Al,Dx
  11624.          Cmp     Al,00h          ; dispatch filter
  11625.          Je      Int_modem
  11626.          Jmp     Int_mo_no
  11627.  Int_modem:
  11628.  ;       dbg     'M','S',' '
  11629.          Mov     Dl,Mstat
  11630.          In      Al,dx           ; read MSR content
  11631.          Test    Al,CDlvl        ; carrier present?
  11632.          Jnz     Msdsr           ; yes, test for DSR
  11633.          Test    OutSpec[si],OutCdf      ; no, is CD off line?
  11634.          Jz      Msdsr
  11635.          Or      InStat[si],OffLin
  11636.  Msdsr:
  11637.          Test    Al,DSRlvl       ; DSR present?
  11638.          Jnz     Dsron           ; yes, handle it
  11639.          Test    OutSpec[si],OutDSR      ; no, is DSR throttle?
  11640.          Jz      Dsroff
  11641.          Or      OtStat[si],LinDSR       ; yes, throttle down
  11642.  Dsroff:
  11643.          Test    OutSpec[si],OutDrf      ; is DSR off line?
  11644.          Jz      Mscts
  11645.          Or      InStat[si],OffLin       ; yes, set flag
  11646.          Jmp     Short   Mscts
  11647.  Dsron:
  11648.          Test    OtStat[si],LinDSR       ; throttled for DSR?
  11649.          Jz      Mscts
  11650.          Xor     OtStat[si],LinDSR       ; yes, clear it out
  11651.          Call    Start_output
  11652.  Mscts:
  11653.          Test    Al,CTSlvl       ; CTS present?
  11654.          Jnz     Ctson           ; yes, handle it
  11655.          Test    OutSpec[si],OutCTS      ; no, is CTS throttle?
  11656.          Jz      Int_exit2
  11657.          Or      OtStat[si],LinCTS       ; yes, shut it down
  11658.          Jmp     Short   Int_exit2
  11659.  Ctson:
  11660.          Test    OtStat[si],LinCTS       ; throttled for CTS?
  11661.          Jz      Int_exit2
  11662.          Xor     OtStat[si],LinCTS       ; yes, clear it out
  11663.          Jmp     Short   Int_exit1
  11664.  Int_mo_no:
  11665.          Cmp     Al,02h
  11666.          Jne     Int_tx_no
  11667.  Int_txmit:
  11668.  ;       dbg     'T','x',' '
  11669.  Int_exit1:
  11670.          Call    Start_output    ; try to send another
  11671.  Int_exit2:
  11672.          Jmp     Int_exit
  11673.  Int_tx_no:
  11674.          Cmp     Al,04h
  11675.          Jne     Int_rec_no
  11676.  Int_receive:
  11677.  ;       dbg     'R','x',' '
  11678.          Mov     Dx,port[si]
  11679.          In      Al,dx           ; take char from 8250
  11680.          Test    OutSpec[si],OutXon  ; is XON/XOFF enabled?
  11681.          Jz      Stuff_in        ; no
  11682.          Cmp     Al,'S' And 01FH ; yes, is this XOFF?
  11683.          Jne     Isq             ; no, check for XON
  11684.          Or      OtStat[si],LinXof ; yes, disable output
  11685.          Jmp     Int_exit2       ; don't store this one
  11686.  Isq:
  11687.          Cmp     Al,'Q' And 01FH ; is this XON?
  11688.          Jne     Stuff_in        ; no, save it
  11689.          Test    OtStat[si],LinXof ; yes, waiting?
  11690.          Jz      Int_exit2       ; no, ignore it
  11691.          Xor     OtStat[si],LinXof ; yes, clear the XOFF bit
  11692.          Jmp     Int_exit1       ; and try to resume xmit
  11693.  Int_rec_no:
  11694.          Cmp     Al,06h
  11695.          Jne     Int_done
  11696.  Int_rxstat:
  11697.  ;       dbg     'E','R',' '
  11698.          Mov     Dl,Lstat
  11699.          In      Al,dx
  11700.          Test    InSpec[si],InEpc ; return them as codes?
  11701.          Jz      Nocode          ; no, just set error alarm
  11702.          And     Al,AnyErr       ; yes, mask off all but error bits
  11703.          Or      Al,080h
  11704.  Stuff_in:
  11705.          Call    Put_in          ; put input char in buffer
  11706.          Cmp     Ah,0            ; did it fit?
  11707.          Je      Int_exit3       ; yes, all OK
  11708.          Or      InStat[si],LostDt  ; no, set DataLost bit
  11709.  Int_exit3:
  11710.          Jmp     Int_exit
  11711.  Nocode:
  11712.          Or      InStat[si],BadInp
  11713.          Jmp     Int_exit3
  11714.  Int_done:
  11715.          Clc
  11716.          Jnc     $+2
  11717.          Mov     Al,EOI          ; all done now
  11718.          Out     PIC_b,Al
  11719.          Pop     Ds              ; restore regs
  11720.          Pop     Di
  11721.          Pop     Dx
  11722.          Pop     Cx
  11723.          Pop     Bx
  11724.          Pop     Ax
  11725.          Pop     Si
  11726.          Iret
  11727.  
  11728.  Start_output    Proc    Near
  11729.          Test    OtStat[si],LinIdl ; Blocked?
  11730.          Jnz     Dont_start      ; yes, no output
  11731.          Mov     Dx,port[si]     ; no, check UART
  11732.          Mov     Dl,Lstat
  11733.          In      Al,Dx
  11734.          Test    Al,xhre         ; empty?
  11735.          Jz      Dont_start      ; no
  11736.          Call    Get_out         ; yes, anything waiting?
  11737.          Or      Ah,Ah
  11738.          Jnz     Dont_start      ; no
  11739.          Mov     Dl,RxBuf        ; yes, send it out
  11740.          Out     Dx,al
  11741.  ;       dbg     's','o',' '
  11742.  Dont_start:
  11743.          ret
  11744.  Start_output    Endp
  11745.  
  11746.  Subttl  Initialization Request Routine
  11747.  Page
  11748.  
  11749.  Init:   Lea     Di,$            ; release rest...
  11750.          Mov     Es:Xfer[bx],Di
  11751.          Mov     Es:Xseg[bx],Cs
  11752.  
  11753.          Mov     Dx,Port[si]     ; base port
  11754.          Mov     Dl,Lctrl
  11755.          Mov     Al,Dlab         ; enable divisor
  11756.          Out     Dx,Al
  11757.          Clc
  11758.          Jnc     $+2
  11759.          Mov     Dl,RxBuf
  11760.          Mov     Ax,Baud[si]     ; set baud
  11761.          Out     Dx,Al
  11762.          Clc
  11763.          Jnc     $+2
  11764.          Inc     Dx
  11765.          Mov     Al,Ah
  11766.          Out     Dx,Al
  11767.          Clc
  11768.          Jnc     $+2
  11769.  
  11770.          Mov     Dl,Lctrl        ; set LCR
  11771.          Mov     Al,OtStat[si]   ; from table
  11772.          Out     Dx,Al
  11773.          Mov     OtStat[si],0    ; clear status
  11774.          Clc
  11775.          Jnc     $+2
  11776.          Mov     Dl,IntEn        ; IER
  11777.          Mov     Al,AllInt       ; enable ints in 8250
  11778.          Out     Dx,Al
  11779.          Clc
  11780.          Jnc     $+2
  11781.          Mov     Dl,Mctrl        ; set MCR
  11782.          Mov     Al,InStat[si]   ; from table
  11783.          Out     Dx,Al
  11784.          Mov     InStat[si],0    ; clear status
  11785.  
  11786.  ClRgs:  Mov     Dl,Lstat        ; clear LSR
  11787.          In      Al,Dx
  11788.          Mov     Dl,RxBuf        ; clear RX reg
  11789.          In      Al,Dx
  11790.          Mov     Dl,Mstat        ; clear MSR
  11791.          In      Al,Dx
  11792.          Mov     Dl,IntId        ; IID reg
  11793.          In      Al,Dx
  11794.          In      Al,Dx
  11795.          Test    Al,1            ; int pending?
  11796.          Jz      ClRgs           ; yes, repeat
  11797.  
  11798.          Cli
  11799.          Xor     Ax,Ax           ; set int vec
  11800.          Mov     Es,Ax
  11801.          Mov     Di,Vect[si]
  11802.          Mov     Ax,IsrAdr[si]   ; from table
  11803.          Stosw
  11804.          Mov     Es:[di],cs
  11805.  
  11806.          In      Al,PIC_e        ; get 8259
  11807.          And     Al,0E7h         ; com1/2 mask
  11808.          Clc
  11809.          Jnb     $+2
  11810.          Out     PIC_e,Al
  11811.          Sti
  11812.  
  11813.          Mov     Al,EOI          ; now send EOI just in case
  11814.          Out     PIC_b,Al
  11815.  
  11816.  ;       dbg     'D','I',' '     ; driver installed
  11817.          Jmp     Zexit
  11818.  
  11819.  Driver  Ends
  11820.          End
  11821.  
  11822.  \SAMPCODE\DOS_ENCY\6\ENGINE.ASM
  11823.  
  11824.          TITLE   engine
  11825.  
  11826.  CODE    SEGMENT PUBLIC 'CODE'
  11827.  
  11828.          ASSUME  CS:CODE,DS:CODE,ES:CODE,SS:CODE
  11829.  
  11830.          ORG     0100h
  11831.  
  11832.  START:  mov     dx,offset devnm ; open named device (ASY1)
  11833.          mov     ax,3d02h
  11834.          int     21h
  11835.          mov     handle,ax       ; save the handle
  11836.          jc      quit
  11837.  alltim: call    getmdm          ; main engine loop
  11838.          call    putcrt
  11839.          call    getkbd
  11840.          call    putmdm
  11841.          jmp     alltim
  11842.  quit:   mov     ah,4ch          ; come here to quit
  11843.          int     21h
  11844.  
  11845.  getmdm  proc                    ; get input from modem
  11846.          mov     cx,256
  11847.          mov     bx,handle
  11848.          mov     dx,offset mbufr
  11849.          mov     ax,3F00h
  11850.          int     21h
  11851.          jc      quit
  11852.          mov     mdlen,ax
  11853.          ret
  11854.  getmdm  endp
  11855.  
  11856.  getkbd  proc                    ; get input from keyboard
  11857.          mov     kblen,0         ; first zero the count
  11858.          mov     ah,11           ; key pressed?
  11859.          int     21h
  11860.          inc     al
  11861.          jnz     nogk            ; no
  11862.          mov     ah,7            ; yes, get it
  11863.          int     21h
  11864.          cmp     al,3            ; was it Ctrl-C?
  11865.          je      quit            ; yes, get out
  11866.          mov     kbufr,al        ; no, save it
  11867.          inc     kblen
  11868.          cmp     al,13           ; was it Enter?
  11869.          jne     nogk            ; no
  11870.          mov     byte ptr kbufr+1,10 ; yes, add LF
  11871.          inc     kblen
  11872.  nogk:   ret
  11873.  getkbd  endp
  11874.  
  11875.  putmdm  proc                    ; put output to modem
  11876.          mov     cx,kblen
  11877.          jcxz    nopm
  11878.          mov     bx,handle
  11879.          mov     dx,offset kbufr
  11880.          mov     ax,4000h
  11881.          int     21h
  11882.          jc      quit
  11883.  nopm:   ret
  11884.  putmdm  endp
  11885.  
  11886.  putcrt  proc                    ; put output to CRT
  11887.          mov     cx,mdlen
  11888.          jcxz    nopc
  11889.          mov     bx,1
  11890.          mov     dx,offset mbufr
  11891.          mov     ah,40h
  11892.          int     21h
  11893.          jc      quit
  11894.  nopc:   ret
  11895.  putcrt  endp
  11896.  
  11897.  devnm   db      'ASY1',0        ; miscellaneous data and buffers
  11898.  handle  dw      0
  11899.  kblen   dw      0
  11900.  mdlen   dw      0
  11901.  mbufr   db      256 dup (0)
  11902.  kbufr   db      80 dup (0)
  11903.  
  11904.  CODE    ENDS
  11905.          END     START
  11906.  
  11907.  \SAMPCODE\DOS_ENCY\6\ENGINE_1.ASM
  11908.  
  11909.  ;Incomplete (and Unworkable) Implementation
  11910.  
  11911.  LOOP:   MOV     AH,08h          ; read keyboard, no echo
  11912.          INT     21h
  11913.          MOV     DL,AL           ; set up to send
  11914.          MOV     AH,04h          ; send to AUX device
  11915.          INT     21h
  11916.          MOV     AH,03h          ; read from AUX device
  11917.          INT     21h
  11918.          MOV     DL,AL           ; set up to send
  11919.          MOV     AH,02h          ; send to screen
  11920.          INT     21h
  11921.          JMP     LOOP            ; keep doing it
  11922.  
  11923.  \SAMPCODE\DOS_ENCY\6\ENGINE_2.ASM
  11924.  
  11925.  ;Improved, (but Still Unworkable) Implementation
  11926.  
  11927.  LOOP:   MOV     AH,0Bh          ; test keyboard for char
  11928.          INT     21h
  11929.          OR      AL,AL           ; test for zero
  11930.          JZ      RMT             ; no char avail, skip
  11931.          MOV     AH,08h          ; have char, read it in
  11932.          INT     21h
  11933.          MOV     DL,AL           ; set up to send
  11934.          MOV     AH,04h          ; send to AUX device
  11935.          INT     21h
  11936.  RMT:
  11937.          MOV     AH,03h          ; read from AUX device
  11938.          INT     21h
  11939.          MOV     DL,AL           ; set up to send
  11940.          MOV     AH,02h          ; send to screen
  11941.          INT     21h
  11942.          JMP     LOOP            ; keep doing it
  11943.  
  11944.  \SAMPCODE\DOS_ENCY\6\UART.ASM
  11945.  
  11946.          MOV     DX,03FBh        ; base port COM1 (03F8) + LCR (3)
  11947.          MOV     AL,080h         ; enable Divisor Latch
  11948.          OUT     DX,AL
  11949.          MOV     DX,03F8h        ; set for Baud0
  11950.          MOV     AX,96           ; set divisor to 1200 BPS
  11951.          OUT     DX,AL
  11952.          INC     DX              ; to offset 1 for Baud1
  11953.          MOV     AL,AH           ; high byte of divisor
  11954.          OUT     DX,AL
  11955.          MOV     DX,03FBh        ; back to the LCR offset
  11956.          MOV     AL,03           ; DLAB = 0, Parity = N, WL = 8
  11957.          OUT     DX,AL
  11958.          MOV     DX,03F9h        ; offset 1 for IER
  11959.          MOV     AL,0Fh          ; enable all ints in 8250
  11960.          OUT     DX,AL
  11961.          MOV     DX,03FCh        ; COM1 + MCR (4)
  11962.          MOV     AL,0Bh          ; OUT2 + RTS + DTR bits
  11963.          OUT     DX,AL
  11964.  CLRGS:
  11965.          MOV     DX,03FDh        ; clear LSR
  11966.          IN      AL,DX
  11967.          MOV     DX,03F8h        ; clear RX reg
  11968.          IN      AL,DX
  11969.          MOV     DX,03FEh        ; clear MSR
  11970.          IN      AL,DX
  11971.          MOV     DX,03FAh        ; IID reg
  11972.          IN      AL,DX
  11973.          IN      AL,DX           ; repeat to be sure
  11974.          TEST    AL,1            ; int pending?
  11975.          JZ      CLRGS           ; yes, repeat
  11976.  
  11977.  \SAMPCODE\DOS_ENCY\7
  11978.  \SAMPCODE\DOS_ENCY\7\CMDTAIL.ASM
  11979.  
  11980.  cmdtail equ     80h             ; PSP offset of command tail
  11981.  fname   db      64 dup (?)
  11982.  fhandle dw      ?
  11983.  
  11984.          .
  11985.          .
  11986.          .
  11987.                                  ; assume that DS already
  11988.                                  ; contains segment of PSP
  11989.  
  11990.                                  ; prepare to copy filename...
  11991.          mov     si,cmdtail      ; DS:SI = command tail
  11992.          mov     di,seg fname    ; ES:DI = buffer to receive
  11993.          mov     es,di           ; filename from command tail
  11994.          mov     di,offset fname
  11995.          cld                     ; safety first!
  11996.  
  11997.          lodsb                   ; check length of command tail
  11998.          or      al,al
  11999.          jz      error           ; jump, command tail empty
  12000.  
  12001.  label1:                         ; scan off leading spaces
  12002.          lodsb                   ; get next character
  12003.          cmp     al,20h          ; is it a space?
  12004.          jz      label1          ; yes, skip it
  12005.  
  12006.  label2:
  12007.          cmp     al,0dh          ; look for terminator
  12008.          jz      label3          ; quit if return found
  12009.          cmp     al,20h
  12010.          jz      label3          ; quit if space found
  12011.          stosb                   ; else copy this character
  12012.          lodsb                   ; get next character
  12013.          jmp     label2
  12014.  
  12015.  label3:
  12016.          xor     al,al           ; store final NULL to
  12017.          stosb                   ; create ASCIIZ string
  12018.  
  12019.                                  ; now open the file...
  12020.          mov     dx,seg fname    ; DS:DX = address of
  12021.          mov     ds,dx           ; pathname for file
  12022.          mov     dx,offset fname
  12023.          mov     ax,3d02h        ; Function 3DH = open r/w
  12024.          int     21h             ; transfer to MS-DOS
  12025.          jnc     label4          ; jump if file found
  12026.  
  12027.          cmp     ax,2            ; error 2 = file not found
  12028.          jnz     error           ; jump if other error
  12029.                                  ; else make the file...
  12030.          xor     cx,cx           ; CX = normal attribute
  12031.          mov     ah,3ch          ; Function 3CH = create
  12032.          int     21h             ; transfer to MS-DOS
  12033.          jc      error           ; jump if create failed
  12034.  
  12035.  label4:
  12036.          mov     fhandle,ax      ; save handle for file
  12037.          .
  12038.          .
  12039.          .
  12040.  
  12041.  \SAMPCODE\DOS_ENCY\7\COPYFILE.ASM
  12042.  
  12043.  fcb1    db      0               ; drive = default
  12044.          db      'MYFILE  '      ; 8 character filename
  12045.          db      'DAT'           ; 3 character extension
  12046.          db      25 dup (0)      ; remainder of fcb1
  12047.  fcb2    db      0               ; drive = default
  12048.          db      'MYFILE  '      ; 8 character filename
  12049.          db      'BAK'           ; 3 character extension
  12050.          db      25 dup (0)      ; remainder of fcb2
  12051.  buff    db      512 dup (?)     ; buffer for file I/O
  12052.          .
  12053.          .
  12054.          .
  12055.                                  ; open MYFILE.DAT...
  12056.          mov     dx,seg fcb1     ; DS:DX = address of FCB
  12057.          mov     ds,dx
  12058.          mov     dx,offset fcb1
  12059.          mov     ah,0fh          ; Function 0FH = open
  12060.          int     21h             ; transfer to MS-DOS
  12061.          or      al,al           ; did open succeed?
  12062.          jnz     error           ; jump if open failed
  12063.                                  ; create MYFILE.BAK...
  12064.          mov     dx,offset fcb2  ; DS:DX = address of FCB
  12065.          mov     ah,16h          ; Function 16H = create
  12066.          int     21h             ; transfer to MS-DOS
  12067.          or      al,al           ; did create succeed?
  12068.          jnz     error           ; jump if create failed
  12069.                                  ; set record length to 512
  12070.          mov     word ptr fcb1+0eh,512
  12071.          mov     word ptr fcb2+0eh,512
  12072.                                  ; set DTA to our buffer...
  12073.          mov     dx,offset buff  ; DS:DX = buffer address
  12074.          mov     ah,1ah          ; Function 1AH = set DTA
  12075.          int     21h             ; transfer to MS-DOS
  12076.  loop:                           ; read MYFILE.DAT
  12077.          mov     dx,offset fcb1  ; DS:DX = FCB address
  12078.          mov     ah,14h          ; Function 14H = seq. read
  12079.          int     21h             ; transfer to MS-DOS
  12080.          or      al,al           ; was read successful?
  12081.          jnz     done            ; no, quit
  12082.                                  ; write MYFILE.BAK...
  12083.          mov     dx,offset fcb2  ; DS:DX = FCB address
  12084.          mov     ah,15h          ; Function 15H = seq. write
  12085.          int     21h             ; transfer to MS-DOS
  12086.          or      al,al           ; was write successful?
  12087.          jnz     error           ; jump if write failed
  12088.          jmp     loop            ; continue to end of file
  12089.  done:                           ; now close files...
  12090.          mov     dx,offset fcb1  ; DS:DX = FCB for MYFILE.DAT
  12091.          mov     ah,10h          ; Function 10H = close file
  12092.          int     21h             ; transfer to MS-DOS
  12093.          or      al,al           ; did close succeed?
  12094.          jnz     error           ; jump if close failed
  12095.          mov     dx,offset fcb2  ; DS:DX = FCB for MYFILE.BAK
  12096.          mov     ah,10h          ; Function 10H = close file
  12097.          int     21h             ; transfer to MS-DOS
  12098.          or      al,al           ; did close succeed?
  12099.          jnz     error           ; jump if close failed
  12100.          .
  12101.          .
  12102.          .
  12103.  
  12104.  \SAMPCODE\DOS_ENCY\7\FXN13H.ASM
  12105.  
  12106.  delfcb  db      0               ; default drive
  12107.          db      'A???????'      ; wildcard filename
  12108.          db      'BAK'           ; extension
  12109.          db      25 dup (0)      ; remainder of FCB
  12110.  
  12111.          .
  12112.          .
  12113.          .
  12114.          mov     dx,seg delfcb   ; DS:DX = FCB address
  12115.          mov     ds,dx
  12116.          mov     dx,offset delfcb
  12117.          mov     ah,13h          ; Function 13H = delete
  12118.          int     21h             ; transfer to MS-DOS
  12119.          or      al,al           ; did function succeed?
  12120.          jnz     error           ; jump if delete failed
  12121.          .
  12122.          .
  12123.          .
  12124.  
  12125.  \SAMPCODE\DOS_ENCY\7\FXN17H.ASM
  12126.  
  12127.  renfcb  db      0               ; default drive
  12128.          db      '????????'      ; wildcard filename
  12129.          db      'ASM'           ; old extension
  12130.          db      5 dup (0)       ; reserved area
  12131.          db      '????????'      ; wildcard filename
  12132.          db      'COD'           ; new extension
  12133.          db      15 dup (0)      ; remainder of FCB
  12134.  
  12135.          .
  12136.          .
  12137.          .
  12138.          mov     dx,seg renfcb   ; DS:DX = address of
  12139.          mov     ds,dx           ; "special" FCB
  12140.          mov     dx,offset renfcb
  12141.          mov     ah,17h          ; Function 17H = rename
  12142.          int     21h             ; transfer to MS-DOS
  12143.          or      al,al           ; did function succeed?
  12144.          jnz     error           ; jump if rename failed
  12145.          .
  12146.          .
  12147.          .
  12148.  
  12149.  \SAMPCODE\DOS_ENCY\7\FXN3CH.ASM
  12150.  
  12151.  fname   db      'C:\LETTERS\MEMO.TXT',0
  12152.  fhandle dw      ?
  12153.          .
  12154.          .
  12155.          .
  12156.          mov     dx,seg fname    ; DS:DX = address of
  12157.          mov     ds,dx           ; pathname for file
  12158.          mov     dx,offset fname
  12159.          xor     cx,cx           ; CX = normal attribute
  12160.          mov     ah,3ch          ; Function 3CH = create
  12161.          int     21h             ; transfer to MS-DOS
  12162.          jc      error           ; jump if create failed
  12163.          mov     fhandle,ax      ; else save file handle
  12164.          .
  12165.          .
  12166.          .
  12167.  
  12168.  \SAMPCODE\DOS_ENCY\7\FXN41H.ASM
  12169.  
  12170.  fname   db      'C:\WORK\MYFILE.DAT',0
  12171.          .
  12172.          .
  12173.          .
  12174.          mov     dx,seg fname    ; DS:DX = address of filename
  12175.          mov     ds,dx
  12176.          mov     dx,offset fname
  12177.          mov     ah,41h          ; Function 41H = delete
  12178.          int     21h             ; transfer to MS-DOS
  12179.          jc      error           ; jump if delete failed
  12180.          .
  12181.          .
  12182.          .
  12183.  
  12184.  \SAMPCODE\DOS_ENCY\7\FXN43H.ASM
  12185.  
  12186.  fname   db      'C:\BACKUP\MYFILE.DAT',0
  12187.          .
  12188.          .
  12189.          .
  12190.          mov     dx,seg fname    ; DS:DX = address of filename
  12191.          mov     ds,dx
  12192.          mov     dx,offset fname
  12193.          mov     cx,1            ; CX = attribute (read-only)
  12194.          mov     al,1            ; AL = mode (0 = get, 1 = set)
  12195.          mov     ah,43h          ; Function 43H = get/set attr
  12196.          int     21h             ; transfer to MS-DOS
  12197.          jc      error           ; jump if set attrib. failed
  12198.          .
  12199.          .
  12200.          .
  12201.  
  12202.  \SAMPCODE\DOS_ENCY\7\FXN45H.ASM
  12203.  
  12204.  fhandle dw      ?               ; handle from previous open
  12205.  
  12206.          .
  12207.          .
  12208.          .
  12209.                                  ; duplicate the handle...
  12210.          mov     bx,fhandle      ; BX = handle for file
  12211.          mov     ah,45h          ; Function 45H = dup handle
  12212.          int     21h             ; transfer to MS-DOS
  12213.          jc      error           ; jump if function call failed
  12214.  
  12215.                                  ; now close the new handle...
  12216.          mov     bx,ax           ; BX = duplicated handle
  12217.          mov     ah,3eh          ; Function 3EH = close
  12218.          int     21h             ; transfer to MS-DOS
  12219.          jc      error           ; jump if close failed
  12220.          mov     bx,fhandle      ; replace closed handle with active handle
  12221.          .
  12222.          .
  12223.          .
  12224.  
  12225.  \SAMPCODE\DOS_ENCY\7\FXN56H.ASM
  12226.  
  12227.  file1   db      '\WORK\MYFILE.DAT',0
  12228.  file2   db      '\BACKUP\MYFILE.OLD',0
  12229.          .
  12230.          .
  12231.          .
  12232.          mov     dx,seg file1    ; DS:DX = old filename
  12233.          mov     ds,dx
  12234.          mov     es,dx
  12235.          mov     dx,offset file1
  12236.          mov     di,offset file2 ; ES:DI = new filename
  12237.          mov     ah,56h          ; Function 56H = rename
  12238.          int     21h             ; transfer to MS-DOS
  12239.          jc      error           ; jump if rename failed
  12240.          .
  12241.          .
  12242.          .
  12243.  
  12244.  \SAMPCODE\DOS_ENCY\7\FXN5AH.ASM
  12245.  
  12246.  fname   db      'C:\TEMP\'      ; generated ASCIIZ filename
  12247.          db      13 dup (0)      ; is appended by MS-DOS
  12248.  
  12249.  fhandle dw      ?
  12250.          .
  12251.          .
  12252.          .
  12253.          mov     dx,seg fname    ; DS:DX = address of
  12254.          mov     ds,dx           ; path for temporary file
  12255.          mov     dx,offset fname
  12256.          xor     cx,cx           ; CX = normal attribute
  12257.          mov     ah,5ah          ; Function 5AH = create
  12258.                                  ; temporary file
  12259.          int     21h             ; transfer to MS-DOS
  12260.          jc      error           ; jump if create failed
  12261.          mov     fhandle,ax      ; else save file handle
  12262.          .
  12263.          .
  12264.          .
  12265.  
  12266.  \SAMPCODE\DOS_ENCY\7\MYFILE.ASM
  12267.  
  12268.  file1   db      'MYFILE.DAT',0
  12269.  file2   db      'MYFILE.BAK',0
  12270.  
  12271.  handle1 dw      ?               ; handle for MYFILE.DAT
  12272.  handle2 dw      ?               ; handle for MYFILE.BAK
  12273.  
  12274.  buff    db      512 dup (?)     ; buffer for file I/O
  12275.          .
  12276.          .
  12277.          .
  12278.                                  ; open MYFILE.DAT...
  12279.          mov     dx,seg file1    ; DS:DX = address of filename
  12280.          mov     ds,dx
  12281.          mov     dx,offset file1
  12282.          mov     ax,3d00h        ; Function 3DH = open (read-only)
  12283.          int     21h             ; transfer to MS-DOS
  12284.          jc      error           ; jump if open failed
  12285.          mov     handle1,ax      ; save handle for file
  12286.  
  12287.                                  ; create MYFILE.BAK...
  12288.          mov     dx,offset file2 ; DS:DX = address of filename
  12289.          mov     cx,0            ; CX = normal attribute
  12290.          mov     ah,3ch          ; Function 3CH = create
  12291.          int     21h             ; transfer to MS-DOS
  12292.          jc      error           ; jump if create failed
  12293.          mov     handle2,ax      ; save handle for file
  12294.  
  12295.  loop:                           ; read MYFILE.DAT
  12296.          mov     dx,offset buff  ; DS:DX = buffer address
  12297.          mov     cx,512          ; CX = length to read
  12298.          mov     bx,handle1      ; BX = handle for MYFILE.DAT
  12299.          mov     ah,3fh          ; Function 3FH = read
  12300.          int     21h             ; transfer to MS-DOS
  12301.          jc      error           ; jump if read failed
  12302.          or      ax,ax           ; were any bytes read?
  12303.          jz      done            ; no, end of file reached
  12304.  
  12305.                                  ; write MYFILE.BAK
  12306.          mov     dx,offset buff  ; DS:DX = buffer address
  12307.          mov     cx,ax           ; CX = length to write
  12308.          mov     bx,handle2      ; BX = handle for MYFILE.BAK
  12309.          mov     ah,40h          ; Function 40H = write
  12310.          int     21h             ; transfer to MS-DOS
  12311.          jc      error           ; jump if write failed
  12312.          cmp     ax,cx           ; was write complete?
  12313.          jne     error           ; jump if disk full
  12314.          jmp     loop            ; continue to end of file
  12315.  
  12316.  done:                           ; now close files...
  12317.          mov     bx,handle1      ; handle for MYFILE.DAT
  12318.          mov     ah,3eh          ; Function 3EH = close file
  12319.          int     21h             ; transfer to MS-DOS
  12320.          jc      error           ; jump if close failed
  12321.  
  12322.          mov     bx,handle2      ; handle for MYFILE.BAK
  12323.          mov     ah,3eh          ; Function 3EH = close file
  12324.          int     21h             ; transfer to MS-DOS
  12325.          jc      error           ; jump if close failed
  12326.  
  12327.          .
  12328.          .
  12329.          .
  12330.  
  12331.  \SAMPCODE\DOS_ENCY\7\OPENFILE.ASM
  12332.  
  12333.  kbuf    db      64,0,64 dup (0)
  12334.  prompt  db      0dh,0ah,'Enter filename: $'
  12335.  myfcb   db      37 dup (0)
  12336.  
  12337.          .
  12338.          .
  12339.          .
  12340.                                  ; display the prompt...
  12341.          mov     dx,seg prompt   ; DS:DX = prompt address
  12342.          mov     ds,dx
  12343.          mov     es,dx
  12344.          mov     dx,offset prompt
  12345.          mov     ah,09H          ; Function 09H = print string
  12346.          int     21h             ; transfer to MS-DOS
  12347.  
  12348.                                  ; now input filename...
  12349.          mov     dx,offset kbuf  ; DS:DX = buffer address
  12350.          mov     ah,0ah          ; Function 0AH = enter string
  12351.          int     21h             ; transfer to MS-DOS
  12352.  
  12353.                                  ; parse filename into FCB...
  12354.          mov     si,offset kbuf+2 ; DS:SI = address of filename
  12355.          mov     di,offset myfcb ; ES:DI = address of fcb
  12356.          mov     ax,2900h        ; Function 29H = parse name
  12357.          int     21h             ; transfer to MS-DOS
  12358.          or      al,al           ; jump if bad drive or
  12359.          jnz     error           ; wildcard characters in name
  12360.  
  12361.                                  ; try to open file...
  12362.          mov     dx,offset myfcb ; DS:DX = FCB address
  12363.          mov     ah,0fh          ; Function 0FH = open file
  12364.          int     21h             ; transfer to MS-DOS
  12365.          or      al,al           ; check status
  12366.          jz      proceed         ; jump if open successful
  12367.  
  12368.                                  ; else create file...
  12369.          mov     dx,offset myfcb ; DS:DX = FCB address
  12370.          mov     ah,16h          ; Function 16H = create
  12371.          int     21h             ; transfer to MS-DOS
  12372.          or      al,al           ; did create succeed?
  12373.          jnz     error           ; jump if create failed
  12374.  
  12375.  proceed:
  12376.          .                       ; file has been opened or
  12377.          .                       ; created, and FCB is valid
  12378.          .                       ; for read/write operations...
  12379.  
  12380.  \SAMPCODE\DOS_ENCY\7\POINTER1.ASM
  12381.  
  12382.  fhandle dw      ?               ; handle from previous open
  12383.  buff    db      512 dup (?)     ; buffer for data from file
  12384.  
  12385.          .
  12386.          .
  12387.          .
  12388.                                  ; position the file pointer...
  12389.          mov     cx,0            ; CX = high part of file offset
  12390.          mov     dx,32768        ; DX = low part of file offset
  12391.          mov     bx,fhandle      ; BX = handle for file
  12392.          mov     al,0            ; AL = positioning mode
  12393.          mov     ah,42h          ; Function 42H = position
  12394.          int     21h             ; transfer to MS-DOS
  12395.          jc      error           ; jump if function call failed
  12396.  
  12397.                                  ; now read 512 bytes from file
  12398.          mov     dx,offset buff  ; DS:DX = address of buffer
  12399.          mov     cx,512          ; CX = length of 512 bytes
  12400.          mov     bx,fhandle      ; BX = handle for file
  12401.          mov     ah,3fh          ; Function 3FH = read
  12402.          int     21h             ; transfer to MS-DOS
  12403.          jc      error           ; jump if read failed
  12404.          cmp     ax,512          ; was 512 bytes read?
  12405.          jne     error           ; jump if partial rec. or EOF
  12406.          .
  12407.          .
  12408.          .
  12409.  
  12410.  \SAMPCODE\DOS_ENCY\7\POINTER2.ASM
  12411.  
  12412.  fhandle dw      ?               ; handle from previous open
  12413.  
  12414.          .
  12415.          .
  12416.          .
  12417.                                  ; position the file pointer
  12418.                                  ; to the end of file...
  12419.          mov     cx,0            ; CX = high part of offset
  12420.          mov     dx,0            ; DX = low part of offset
  12421.          mov     bx,fhandle      ; BX = handle for file
  12422.          mov     al,2            ; AL = positioning mode
  12423.          mov     ah,42h          ; Function 42H = position
  12424.          int     21h             ; transfer to MS-DOS
  12425.          jc      error           ; jump if function call failed
  12426.  
  12427.                                  ; if call succeeded, DX:AX
  12428.                                  ; now contains the file size
  12429.          .
  12430.          .
  12431.          .
  12432.  
  12433.  \SAMPCODE\DOS_ENCY\8
  12434.  \SAMPCODE\DOS_ENCY\8\DIRDUMP.C
  12435.  
  12436.  /* DIRDUMP.C */
  12437.  
  12438.  #define AllAttributes   0x3F            /* bits set for all attributes */
  12439.  
  12440.  main()
  12441.  {
  12442.          static  char CurrentDir[64];
  12443.          int     ErrorCode;
  12444.          int     FileCount = 0;
  12445.  
  12446.          struct
  12447.          {
  12448.            char    reserved[21];
  12449.            char    attrib;
  12450.            int     time;
  12451.            int     date;
  12452.            long    size;
  12453.            char    name[13];
  12454.          }         DTA;
  12455.  
  12456.  /* display current directory name */
  12457.  
  12458.          ErrorCode = GetCurrentDir( CurrentDir );
  12459.          if( ErrorCode )
  12460.          {
  12461.            printf( "\nError %d:  GetCurrentDir", ErrorCode );
  12462.            exit( 1 );
  12463.          }
  12464.  
  12465.          printf( "\nCurrent directory is \\%s", CurrentDir );
  12466.  
  12467.  
  12468.  /* display files and attributes */
  12469.  
  12470.          SetDTA( &DTA );                 /* pass DTA to MS-DOS */
  12471.  
  12472.          ErrorCode = FindFirstFile( "*.*", AllAttributes );
  12473.  
  12474.          while( !ErrorCode )
  12475.          {
  12476.            printf( "\n%12s -- ", DTA.name );
  12477.            ShowAttributes( DTA.attrib );
  12478.            ++FileCount;
  12479.  
  12480.            ErrorCode = FindNextFile( );
  12481.          }
  12482.  
  12483.  /* display file count and exit */
  12484.  
  12485.          printf( "\nCurrent directory contains %d files\n", FileCount );
  12486.          return( 0 );
  12487.  }
  12488.  
  12489.  
  12490.  ShowAttributes( a )
  12491.  int     a;
  12492.  {
  12493.          int     i;
  12494.          int     mask = 1;
  12495.  
  12496.          static char *AttribName[] =
  12497.          {
  12498.            "read-only ",
  12499.            "hidden ",
  12500.            "system ",
  12501.            "volume ",
  12502.            "subdirectory ",
  12503.            "archive "
  12504.          };
  12505.  
  12506.  
  12507.          for( i=0; i<6; i++ )            /* test each attribute bit */
  12508.          {
  12509.            if( a & mask )
  12510.              printf( AttribName[i] );    /* display a message if bit is set */
  12511.            mask = mask << 1;
  12512.          }
  12513.  }
  12514.  
  12515.  \SAMPCODE\DOS_ENCY\8\DIRS.ASM
  12516.  
  12517.                  TITLE   'DIRS.ASM'
  12518.  
  12519.  ;
  12520.  ; Subroutines for DIRDUMP.C
  12521.  ;
  12522.  
  12523.  
  12524.  ARG1            EQU     [bp + 4]        ; stack frame addressing for C argume
  12525.  ARG2            EQU     [bp + 6]
  12526.  
  12527.  
  12528.  _TEXT           SEGMENT byte public 'CODE'
  12529.                  ASSUME  cs:_TEXT
  12530.  
  12531.  ;----------------------------------------------------------------------------
  12532.  ;
  12533.  ; void SetDTA( DTA );
  12534.  ;         char *DTA;
  12535.  ;
  12536.  ;----------------------------------------------------------------------------
  12537.  
  12538.                  PUBLIC  _SetDTA
  12539.  _SetDTA         PROC    near
  12540.  
  12541.                  push    bp
  12542.                  mov     bp,sp
  12543.  
  12544.                  mov     dx,ARG1         ; DS:DX -> DTA
  12545.                  mov     ah,1Ah          ; AH = INT 21H function number
  12546.                  int     21h             ; pass DTA to MS-DOS
  12547.  
  12548.                  pop     bp
  12549.                  ret
  12550.  
  12551.  _SetDTA         ENDP
  12552.  
  12553.  ;----------------------------------------------------------------------------
  12554.  ;
  12555.  ; int GetCurrentDir( *path );           /* returns error code */
  12556.  ;         char *path;                   /* pointer to buffer to contain path
  12557.  ;
  12558.  ;----------------------------------------------------------------------------
  12559.  
  12560.                  PUBLIC  _GetCurrentDir
  12561.  _GetCurrentDir  PROC    near
  12562.  
  12563.                  push    bp
  12564.                  mov     bp,sp
  12565.                  push    si
  12566.  
  12567.                  mov     si,ARG1         ; DS:SI -> buffer
  12568.                  xor     dl,dl           ; DL = 0 (default drive number)
  12569.                  mov     ah,47h          ; AH = INT 21H function number
  12570.                  int     21h             ; call MS-DOS; AX = error code
  12571.                  jc      L01             ; jump if error
  12572.  
  12573.                  xor     ax,ax           ; no error, return AX = 0
  12574.  
  12575.  L01:            pop     si
  12576.                  pop     bp
  12577.                  ret
  12578.  
  12579.  _GetCurrentDir  ENDP
  12580.  
  12581.  ;----------------------------------------------------------------------------
  12582.  ;
  12583.  ; int FindFirstFile( path, attribute ); /* returns error code */
  12584.  ;         char *path;
  12585.  ;         int  attribute;
  12586.  ;
  12587.  ;----------------------------------------------------------------------------
  12588.  
  12589.                  PUBLIC  _FindFirstFile
  12590.  _FindFirstFile  PROC    near
  12591.  
  12592.                  push    bp
  12593.                  mov     bp,sp
  12594.  
  12595.                  mov     dx,ARG1         ; DS:DX -> path
  12596.                  mov     cx,ARG2         ; CX = attribute
  12597.                  mov     ah,4Eh          ; AH = INT 21H function number
  12598.                  int     21h             ; call MS-DOS; AX = error code
  12599.                  jc      L02             ; jump if error
  12600.  
  12601.                  xor     ax,ax           ; no error, return AX = 0
  12602.  
  12603.  L02:            pop     bp
  12604.                  ret
  12605.  
  12606.  _FindFirstFile  ENDP
  12607.  
  12608.  ;----------------------------------------------------------------------------
  12609.  ;
  12610.  ; int FindNextFile();                   /* returns error code */
  12611.  ;
  12612.  ;----------------------------------------------------------------------------
  12613.  
  12614.                  PUBLIC  _FindNextFile
  12615.  _FindNextFile   PROC    near
  12616.  
  12617.                  push    bp
  12618.                  mov     bp,sp
  12619.  
  12620.                  mov     ah,4Fh          ; AH = INT 21H function number
  12621.                  int     21h             ; call MS-DOS; AX = error code
  12622.                  jc      L03             ; jump if error
  12623.  
  12624.                  xor     ax,ax           ; if no error, set AX = 0
  12625.  
  12626.  L03:            pop     bp
  12627.                  ret
  12628.  
  12629.  _FindNextFile   ENDP
  12630.  
  12631.  _TEXT           ENDS
  12632.  
  12633.  
  12634.  _DATA           SEGMENT word public 'DATA'
  12635.  
  12636.  CurrentDir      DB      64 dup(?)
  12637.  DTA             DB      64 dup(?)
  12638.  
  12639.  _DATA           ENDS
  12640.  
  12641.                  END
  12642.  
  12643.  \SAMPCODE\DOS_ENCY\8\VOLS.ASM
  12644.  
  12645.                  TITLE   'VOLS.ASM'
  12646.  
  12647.  ;----------------------------------------------------------------------------
  12648.  ;
  12649.  ; C-callable routines for manipulating MS-DOS volume labels
  12650.  ; Note: These routines modify the current DTA address.
  12651.  ;
  12652.  ;----------------------------------------------------------------------------
  12653.  
  12654.  ARG1            EQU     [bp + 4]        ; stack frame addressing
  12655.  
  12656.  DGROUP          GROUP   _DATA
  12657.  
  12658.  _TEXT           SEGMENT byte public 'CODE'
  12659.                  ASSUME  cs:_TEXT,ds:DGROUP
  12660.  
  12661.  ;----------------------------------------------------------------------------
  12662.  ;
  12663.  ; char *GetVolLabel();          /* returns pointer to volume label name */
  12664.  ;
  12665.  ;----------------------------------------------------------------------------
  12666.  
  12667.                  PUBLIC  _GetVolLabel
  12668.  _GetVolLabel    PROC    near
  12669.  
  12670.                  push    bp
  12671.                  mov     bp,sp
  12672.                  push    si
  12673.                  push    di
  12674.  
  12675.                  call    SetDTA          ; pass DTA address to MS-DOS
  12676.                  mov     dx,offset DGROUP:ExtendedFCB
  12677.                  mov     ah,11h          ; AH = INT 21H function number
  12678.                  int     21h             ; Search for First Entry
  12679.                  test    al,al
  12680.                  jnz     L01
  12681.                                          ; label found so make a copy
  12682.                  mov     si,offset DGROUP:DTA + 8
  12683.                  mov     di,offset DGROUP:VolLabel
  12684.                  call    CopyName
  12685.                  mov     ax,offset DGROUP:VolLabel ; return the copy's address
  12686.                  jmp     short L02
  12687.  
  12688.  L01:            xor     ax,ax           ; no label, return 0 (null pointer)
  12689.  
  12690.  L02:            pop     di
  12691.                  pop     si
  12692.                  pop     bp
  12693.                  ret
  12694.  
  12695.  _GetVolLabel    ENDP
  12696.  
  12697.  ;----------------------------------------------------------------------------
  12698.  ;
  12699.  ; int RenameVolLabel( label );          /* returns error code */
  12700.  ;         char *label;                  /* pointer to new volume label name *
  12701.  ;
  12702.  ;----------------------------------------------------------------------------
  12703.  
  12704.                  PUBLIC  _RenameVolLabel
  12705.  _RenameVolLabel PROC    near
  12706.  
  12707.                  push    bp
  12708.                  mov     bp,sp
  12709.                  push    si
  12710.                  push    di
  12711.  
  12712.                  mov     si,offset DGROUP:VolLabel  ; DS:SI -> old volume name
  12713.                  mov     di,offset DGROUP:Name1
  12714.                  call    CopyName        ; copy old name to FCB
  12715.  
  12716.                  mov     si,ARG1
  12717.                  mov     di,offset DGROUP:Name2
  12718.                  call    CopyName        ; copy new name into FCB
  12719.  
  12720.                  mov     dx,offset DGROUP:ExtendedFCB    ; DS:DX -> FCB
  12721.                  mov     ah,17h          ; AH = INT 21H function number
  12722.                  int     21h             ; rename
  12723.                  xor     ah,ah           ; AX = 00H (success) or 0FFH (failure
  12724.  
  12725.                  pop     di              ; restore registers and return
  12726.                  pop     si
  12727.                  pop     bp
  12728.                  ret
  12729.  
  12730.  _RenameVolLabel ENDP
  12731.  
  12732.  ;----------------------------------------------------------------------------
  12733.  ;
  12734.  ; int NewVolLabel( label );             /* returns error code */
  12735.  ;         char *label;                  /* pointer to new volume label name *
  12736.  ;
  12737.  ;----------------------------------------------------------------------------
  12738.  
  12739.                  PUBLIC  _NewVolLabel
  12740.  _NewVolLabel    PROC    near
  12741.  
  12742.                  push    bp
  12743.                  mov     bp,sp
  12744.                  push    si
  12745.                  push    di
  12746.  
  12747.                  mov     si,ARG1
  12748.                  mov     di,offset DGROUP:Name1
  12749.                  call    CopyName        ; copy new name to FCB
  12750.  
  12751.                  mov     dx,offset DGROUP:ExtendedFCB
  12752.                  mov     ah,16h          ; AH = INT 21H function number
  12753.                  int     21h             ; create directory entry
  12754.                  xor     ah,ah           ; AX = 00H (success) or 0FFH (failure
  12755.  
  12756.                  pop     di              ; restore registers and return
  12757.                  pop     si
  12758.                  pop     bp
  12759.                  ret
  12760.  
  12761.  _NewVolLabel    ENDP
  12762.  
  12763.  ;----------------------------------------------------------------------------
  12764.  ;
  12765.  ; int DeleteVolLabel();                 /* returns error code */
  12766.  ;
  12767.  ;----------------------------------------------------------------------------
  12768.  
  12769.                  PUBLIC  _DeleteVolLabel
  12770.  _DeleteVolLabel PROC    near
  12771.  
  12772.                  push    bp
  12773.                  mov     bp,sp
  12774.                  push    si
  12775.                  push    di
  12776.  
  12777.                  mov     si,offset DGROUP:VolLabel
  12778.                  mov     di,offset DGROUP:Name1
  12779.                  call    CopyName        ; copy current volume name to FCB
  12780.  
  12781.                  mov     dx,offset DGROUP:ExtendedFCB
  12782.                  mov     ah,13h          ; AH = INT 21H function number
  12783.                  int     21h             ; delete directory entry
  12784.                  xor     ah,ah           ; AX = 0 (success) or 0FFH (failure)
  12785.  
  12786.                  pop     di              ; restore registers and return
  12787.                  pop     si
  12788.                  pop     bp
  12789.                  ret
  12790.  
  12791.  _DeleteVolLabel ENDP
  12792.  
  12793.  ;----------------------------------------------------------------------------
  12794.  ;
  12795.  ; miscellaneous subroutines
  12796.  ;
  12797.  ;----------------------------------------------------------------------------
  12798.  
  12799.  SetDTA          PROC    near
  12800.  
  12801.                  push    ax              ; preserve registers used
  12802.                  push    dx
  12803.  
  12804.                  mov     dx,offset DGROUP:DTA    ; DS:DX -> DTA
  12805.                  mov     ah,1Ah          ; AH = INT 21H function number
  12806.                  int     21h             ; set DTA
  12807.  
  12808.                  pop     dx              ; restore registers and return
  12809.                  pop     ax
  12810.                  ret
  12811.  
  12812.  SetDTA          ENDP
  12813.  
  12814.  
  12815.  CopyName        PROC    near            ; Caller:  SI -> ASCIIZ source
  12816.                                          ;          DI -> destination
  12817.                  push    ds
  12818.                  pop     es              ; ES = DGROUP
  12819.                  mov     cx,11           ; length of name field
  12820.  
  12821.  L11:            lodsb                   ; copy new name into FCB ..
  12822.                  test    al,al
  12823.                  jz      L12             ; .. until null character is reached
  12824.                  stosb
  12825.                  loop    L11
  12826.  
  12827.  L12:            mov     al,' '          ; pad new name with blanks
  12828.                  rep     stosb
  12829.                  ret
  12830.  
  12831.  CopyName        ENDP
  12832.  
  12833.  _TEXT           ENDS
  12834.  
  12835.  
  12836.  _DATA           SEGMENT word public 'DATA'
  12837.  
  12838.  VolLabel        DB      11 dup(0),0
  12839.  
  12840.  ExtendedFCB     DB      0FFh            ; must be 0FFH for extended FCB
  12841.                  DB      5 dup(0)        ; (reserved)
  12842.                  DB      1000b           ; attribute byte (bit 3 = 1)
  12843.                  DB      0               ; default drive ID
  12844.  Name1           DB      11 dup('?')     ; global wildcard name
  12845.                  DB      5 dup(0)        ; (unused)
  12846.  Name2           DB      11 dup(0)       ; second name (for renaming entry)
  12847.                  DB      9 dup(0)        ; (unused)
  12848.  
  12849.  DTA             DB      64 dup(0)
  12850.  
  12851.  _DATA           ENDS
  12852.  
  12853.                  END
  12854.  
  12855.  \SAMPCODE\DOS_ENCY\9
  12856.  \SAMPCODE\DOS_ENCY\9\FIG9_2.ASM
  12857.  
  12858.          .
  12859.          .
  12860.          .
  12861.  _TEXT   segment para public 'CODE'
  12862.  
  12863.          org     100h
  12864.  
  12865.          assume  cs:_TEXT,ds:_TEXT,es:_TEXT,ss:_TEXT
  12866.  
  12867.  main    proc    near            ; entry point from MS-DOS
  12868.                                  ; CS = DS = ES = SS = PSP
  12869.  
  12870.                                  ; first move our stack
  12871.          mov     sp,offset stk   ; to a safe place...
  12872.  
  12873.                                  ; now release extra memory...
  12874.          mov     bx,offset stk   ; calculate paragraphs to keep
  12875.          mov     cl,4            ; (divide offset of end of
  12876.          shr     bx,cl           ; program by 16 and round up)
  12877.          inc     bx
  12878.          mov     ah,4ah          ; Fxn 4AH = resize mem block
  12879.          int     21h             ; transfer to MS-DOS
  12880.          jc      error           ; jump if resize failed
  12881.          .
  12882.          .                       ; otherwise go on with work...
  12883.          .
  12884.  
  12885.  main    endp
  12886.  
  12887.          .
  12888.          .
  12889.          .
  12890.  
  12891.          dw      64 dup (?)
  12892.  stk     equ     $               ; base of new stack area
  12893.  
  12894.  _TEXT   ends
  12895.  
  12896.          end     main            ; defines program entry point
  12897.  
  12898.  \SAMPCODE\DOS_ENCY\9\FIG9_3.ASM
  12899.  
  12900.          .
  12901.          .
  12902.          .
  12903.  
  12904.  _TEXT   segment word public 'CODE'      ; executable code segment
  12905.  
  12906.          assume  cs:_TEXT,ds:_DATA,ss:_STACK
  12907.  
  12908.  main    proc    far             ; entry point from MS-DOS
  12909.                                  ; CS = _TEXT segment,
  12910.                                  ; DS = ES = PSP
  12911.  
  12912.          mov     ax,_DATA        ; set DS = our data segment
  12913.          mov     ds,ax
  12914.  
  12915.                                  ; give back extra memory...
  12916.          mov     ax,es           ; let AX = segment of PSP base
  12917.          mov     bx,ss           ; and BX = segment of stack base
  12918.          sub     bx,ax           ; reserve seg stack - seg psp
  12919.          add     bx,stksize/16   ; plus paragraphs of stack
  12920.          inc     bx              ; round up
  12921.          mov     ah,4ah          ; Fxn 4AH = resize memory block
  12922.          int     21h
  12923.          jc      error
  12924.  
  12925.  main    endp
  12926.  
  12927.  _TEXT   ends
  12928.  
  12929.  
  12930.  _DATA   segment word public 'DATA'      ; static & variable data
  12931.  
  12932.          .
  12933.          .
  12934.          .
  12935.  
  12936.  _DATA   ends
  12937.  
  12938.  
  12939.  STACK   segment para stack 'STACK'
  12940.  
  12941.          db      stksize dup (?)
  12942.  
  12943.  STACK   ends
  12944.  
  12945.          end     main            ; defines program entry point
  12946.  
  12947.  \SAMPCODE\DOS_ENCY\9\FIG9_4.ASM
  12948.  
  12949.          .
  12950.          .
  12951.          .
  12952.          mov     bx,800h         ; 800H paragraphs = 32 KB
  12953.          mov     ah,48h          ; Fxn 48H = allocate block
  12954.          int     21h             ; transfer to MS-DOS
  12955.          jc      error           ; jump if allocation failed
  12956.          mov     bufseg,ax       ; save segment of block
  12957.  
  12958.                                  ; open working file...
  12959.          mov     dx,offset file1 ; DS:DX = filename address
  12960.          mov     ax,3d00h        ; Fxn 3DH = open, read only
  12961.          int     21h             ; transfer to MS-DOS
  12962.          jc      error           ; jump if open failed
  12963.          mov     handle1,ax      ; save handle for work file
  12964.  
  12965.                                  ; create backup file...
  12966.          mov     dx,offset file2 ; DS:DX = filename address
  12967.          mov     cx,0            ; CX = attribute (normal)
  12968.          mov     ah,3ch          ; Fxn 3CH = create file
  12969.          int     21h             ; transfer to MS-DOS
  12970.          jc      error           ; jump if create failed
  12971.          mov     handle2,ax      ; save handle for backup file
  12972.  
  12973.          push    ds              ; set ES = our data segment
  12974.          pop     es
  12975.          mov     ds,bufseg       ; set DS:DX = allocated block
  12976.          xor     dx,dx
  12977.  
  12978.          assume  ds:NOTHING,es:_DATA     ; tell assembler
  12979.  
  12980.  next:                           ; read working file...
  12981.          mov     bx,handle1      ; handle for work file
  12982.          mov     cx,8000h        ; try to read 32 KB
  12983.          mov     ah,3fh          ; Fxn 3FH = read
  12984.          int     21h             ; transfer to MS-DOS
  12985.          jc      error           ; jump if read failed
  12986.          or      ax,ax           ; was end of file reached?
  12987.          jz      done            ; yes, exit this loop
  12988.  
  12989.                                  ; now write backup file...
  12990.          mov     cx,ax           ; set write length = read length
  12991.          mov     bx,handle2      ; handle for backup file
  12992.          mov     ah,40h          ; Fxn 40H = write
  12993.          int     21h             ; transfer to MS-DOS
  12994.          jc      error           ; jump if write failed
  12995.          cmp     ax,cx           ; was write complete?
  12996.          jne     error           ; no, disk must be full
  12997.          jmp     next            ; transfer another record
  12998.  
  12999.  done:   push    es              ; restore DS = data segment
  13000.          pop     ds
  13001.  
  13002.          assume  ds:_DATA,es:NOTHING     ; tell assembler
  13003.  
  13004.                                  ; release allocated block...
  13005.          mov     es,bufseg       ; segment base of block
  13006.          mov     ah,49h          ; Fxn 49H = release block
  13007.          int     21h             ; transfer to MS-DOS
  13008.          jc      error           ; (should never fail)
  13009.  
  13010.                                  ; now close backup file...
  13011.          mov     bx,handle2      ; handle for backup file
  13012.          mov     ah,3eh          ; Fxn 3EH = close
  13013.          int     21h             ; transfer to MS-DOS
  13014.          jc      error           ; jump if close failed
  13015.          .
  13016.          .
  13017.          .
  13018.  
  13019.  file1   db      'MYFILE.DAT',0  ; name of working file
  13020.  file2   db      'MYFILE.BAK',0  ; name of backup file
  13021.  
  13022.  handle1 dw      ?               ; handle for working file
  13023.  handle2 dw      ?               ; handle for backup file
  13024.  bufseg  dw      ?               ; segment of allocated block
  13025.  
  13026.  \SAMPCODE\DOS_ENCY\9\FIG9_6.ASM
  13027.  
  13028.          .
  13029.          .
  13030.          .
  13031.                                  ; attempt to "open" EMM...
  13032.          mov     dx,seg emm_name ; DS:DX = address of name
  13033.          mov     ds,dx           ; of EMM
  13034.          mov     dx,offset emm_name
  13035.          mov     ax,3d00h        ; Fxn 3DH, Mode = 00H
  13036.                                  ; = open, read-only
  13037.          int     21h             ; transfer to MS-DOS
  13038.          jc      error           ; jump if open failed
  13039.  
  13040.                                  ; open succeeded, make sure
  13041.                                  ; it was not a file...
  13042.          mov     bx,ax           ; BX = handle from open
  13043.          mov     ax,4400h        ; Fxn 44H Subfxn 00H
  13044.                                  ; = IOCTL Get Device Information
  13045.          int     21h             ; transfer to MS-DOS
  13046.          jc      error           ; jump if IOCTL call failed
  13047.          and     dx,80h          ; Bit 7 = 1 if character device
  13048.          jz      error           ; jump if it was a file
  13049.  
  13050.                                  ; EMM is present, make sure
  13051.                                  ; it is available...
  13052.                                  ; (BX still contains handle)
  13053.          mov     ax,4407h        ; Fxn 44H Subfxn 07H
  13054.                                  ; = IOCTL Get Output Status
  13055.          int     21h             ; transfer to MS-DOS
  13056.          jc      error           ; jump if IOCTL call failed
  13057.          or      al,al           ; test device status
  13058.          jz      error           ; if AL = 0 EMM is not available
  13059.  
  13060.                                  ; now close handle ...
  13061.                                  ; (BX still contains handle)
  13062.          mov     ah,3eh          ; Fxn 3EH = Close
  13063.          int     21h             ; transfer to MS-DOS
  13064.          jc      error           ; jump if close failed
  13065.          .
  13066.          .
  13067.          .
  13068.  
  13069.  emm_name db     'EMMXXXX0',0    ; guaranteed device name for EMM
  13070.  
  13071.  \SAMPCODE\DOS_ENCY\9\FIG9_7.ASM
  13072.  
  13073.  emm_int equ     67h             ; EMM software interrupt
  13074.  
  13075.          .
  13076.          .
  13077.          .
  13078.                                  ; first fetch contents of
  13079.                                  ; EMM interrupt vector...
  13080.          mov     al,emm_int      ; AL = EMM int number
  13081.          mov     ah,35h          ; Fxn 35H = get vector
  13082.          int     21h             ; transfer to MS-DOS
  13083.                                  ; now ES:BX = handler address
  13084.  
  13085.                                  ; assume ES:0000 points
  13086.                                  ; to base of the EMM...
  13087.          mov     di,10           ; ES:DI = address of name
  13088.                                  ; field in device header
  13089.          mov     si,seg emm_name ; DS:SI = address of
  13090.          mov     ds,si           ; expected EMM driver name
  13091.          mov     si,offset emm_name
  13092.          mov     cx,8            ; length of name field
  13093.          cld
  13094.          repz cmpsb              ; compare names...
  13095.          jnz     error           ; jump if driver absent
  13096.          .
  13097.          .
  13098.          .
  13099.  
  13100.  
  13101.  emm_name db     'EMMXXXX0'      ; guaranteed device name for EMM
  13102.  
  13103.  \SAMPCODE\DOS_ENCY\9\FIG9_8.ASM
  13104.  
  13105.          .
  13106.          .
  13107.          .
  13108.          mov     ah,40h          ; test EMM status
  13109.          int     67h
  13110.          or      ah,ah
  13111.          jnz     error           ; jump if bad status from EMM
  13112.  
  13113.          mov     ah,46h          ; check EMM version
  13114.          int     67h
  13115.          or      ah,ah
  13116.          jnz     error           ; jump if couldn't get version
  13117.          cmp     al,30h          ; make sure at least ver. 3.0
  13118.          jb      error           ; jump if wrong EMM version
  13119.  
  13120.          mov     ah,41h          ; get page frame segment
  13121.          int     67h
  13122.          or      ah,ah
  13123.          jnz     error           ; jump if failed to get frame
  13124.          mov     page_frame,bx   ; save segment of page frame
  13125.  
  13126.          mov     ah,42h          ; get no. of available pages
  13127.          int     67h
  13128.          or      ah,ah
  13129.          jnz     error           ; jump if get pages error
  13130.          mov     total_pages,dx  ; save total EMM pages
  13131.          mov     avail_pages,bx  ; save available EMM pages
  13132.          or      bx,bx
  13133.          jz      error           ; abort if no pages available
  13134.  
  13135.          mov     ah,43h          ; try to allocate EMM pages
  13136.          mov     bx,needed_pages
  13137.          int     67h             ; if allocation is successful
  13138.          or      ah,ah
  13139.          jnz     error           ; jump if allocation failed
  13140.  
  13141.          mov     emm_handle,dx   ; save handle for allocated pages
  13142.  
  13143.          .
  13144.          .                       ; now we are ready for other
  13145.          .                       ; processing using EMM pages
  13146.          .
  13147.                                  ; map in EMM memory page...
  13148.          mov     bx,log_page     ; BX <- EMM logical page number
  13149.          mov     al,phys_page    ; AL <- EMM physical page (0-3)
  13150.          mov     dx,emm_handle   ; EMM handle for our pages
  13151.          mov     ah,44h          ; Fxn 44H = map EMM page
  13152.          int     67h
  13153.          or      ah,ah
  13154.          jnz     error           ; jump if mapping error
  13155.  
  13156.          .
  13157.          .
  13158.          .
  13159.                                  ; program ready to terminate,
  13160.                                  ; give up allocated EMM pages...
  13161.          mov     dx,emm_handle   ; handle for our pages
  13162.          mov     ah,45h          ; EMM Fxn 45H = release pages
  13163.          int     67h
  13164.          or      ah,ah
  13165.          jnz     error           ; jump if release failed
  13166.          .
  13167.          .
  13168.          .
  13169.  
  13170.  \SAMPCODE\DOS_ENCY\APP_A
  13171.  \SAMPCODE\DOS_ENCY\APP_A\6501_BUF.ASM
  13172.  
  13173.  buffer  db      1               ; Information ID code
  13174.          dw      38              ; Length of following buffer
  13175.          dw      1               ; Country ID (USA)
  13176.          dw      437             ; Code-page number
  13177.          dw      0               ; Date format
  13178.          db      '$',0,0,0,0     ; Currency symbol
  13179.          db      ',',0           ; Thousands separator
  13180.          db      '.',0           ; Decimal separator
  13181.          db      '-',0           ; Date separator
  13182.          db      ':',0           ; Time separator
  13183.          db      0               ; Currency format flags
  13184.          db      2               ; Digits in currency
  13185.          db      0               ; Time format
  13186.          dd      026ah:176ch     ; Monocase routine entry point
  13187.          db      ',',0           ; Data list separator
  13188.          db      10 dup (0)      ; Reserved
  13189.  
  13190.  \SAMPCODE\DOS_ENCY\APP_A\6502_BUF.ASM
  13191.  
  13192.  buffer  db      2               ; Information ID code
  13193.          dw      0204h           ; Offset of uppercase table
  13194.          dw      1140h           ; Segment of uppercase table
  13195.  
  13196.  \SAMPCODE\DOS_ENCY\APP_A\FXN6501H.ASM
  13197.  
  13198.  buffer  db      41 dup (0)      ; Receives country information.
  13199.          .
  13200.          .
  13201.          .
  13202.          mov     ax,6501h        ; Function = get extended info.
  13203.          mov     bx,437          ; Code page.
  13204.          mov     cx,41           ; Length of buffer.
  13205.          mov     dx,-1           ; Default country.
  13206.          mov     di,seg buffer   ; ES:DI = buffer address.
  13207.          mov     es,di
  13208.          mov     di,offset buffer
  13209.          int     21h             ; Transfer to MS-DOS.
  13210.          jc      error           ; Jump if function failed.
  13211.          .
  13212.          .
  13213.          .
  13214.  
  13215.  \SAMPCODE\DOS_ENCY\APP_A\FXN6502H.ASM
  13216.  
  13217.  buffer  db      5 dup (0)       ; Receives pointer information.
  13218.          .
  13219.          .
  13220.          .
  13221.          mov     ax,6502h        ; Function = get pointer to
  13222.                                  ; uppercase table.
  13223.          mov     bx,437          ; Code page.
  13224.          mov     cx,5            ; Length of buffer.
  13225.          mov     dx,-1           ; Default country.
  13226.          mov     di,seg buffer   ; ES:DI = buffer address.
  13227.          mov     es,di
  13228.          mov     di,offset buffer
  13229.          int     21h             ; Transfer to MS-DOS.
  13230.          jc      error           ; Jump if function failed.
  13231.          .
  13232.          .
  13233.          .
  13234.  
  13235.  \SAMPCODE\DOS_ENCY\APP_A\FXN67H.ASM
  13236.  
  13237.          .
  13238.          .
  13239.          .
  13240.          mov     ah,67h          ; Function 67H = set handle count.
  13241.          mov     bx,30           ; Maximum number of handles.
  13242.          int     21h             ; Transfer to MS-DOS.
  13243.          jc      error           ; Jump if function failed.
  13244.          .
  13245.          .
  13246.          .
  13247.  
  13248.  \SAMPCODE\DOS_ENCY\APP_A\FXN68H.ASM
  13249.  
  13250.  fname   db      'MYFILE.DAT',0  ; ASCIIZ filename.
  13251.  fhandle dw      ?               ; Handle from Open operation.
  13252.          .
  13253.          .
  13254.          .
  13255.          mov     ah,68h          ; Function 68H = commit file.
  13256.          mov     bx,fhandle      ; Handle from previous open.
  13257.          int     21h             ; Transfer to MS-DOS.
  13258.          jc      error           ; Jump if function failed.
  13259.          .
  13260.          .
  13261.          .
  13262.  
  13263.  \SAMPCODE\DOS_ENCY\APP_L
  13264.  \SAMPCODE\DOS_ENCY\APP_L\BIN2HEX.BAS
  13265.  
  13266.  'Binary-to-Hex file conversion utility.
  13267.  'Requires Microsoft QuickBASIC version 3.0 or later.
  13268.  
  13269.  DEFINT A-Z                                    ' All variables are integers
  13270.                                                ' unless otherwise declared.
  13271.  CONST FALSE = 0                               ' Value of logical FALSE.
  13272.  CONST TRUE = NOT FALSE                        ' Value of logical TRUE.
  13273.  
  13274.  DEF FNHXB$(X) = RIGHT$(HEX$(&H100 + X), 2)    ' Return 2-digit hex value for
  13275.  DEF FNHXW$(X!) = RIGHT$("000" + HEX$(X!), 4)  ' Return 4-digit hex value for
  13276.  DEF FNMOD(X, Y) = X! - INT(X!/Y) * Y          ' X! MOD Y (the MOD operation i
  13277.                                                ' only for integers).
  13278.  CONST SRCCNL = 1                              ' Source (.BIN) file channel.
  13279.  CONST TGTCNL = 2                              ' Target (.HEX) file channel.
  13280.  
  13281.  LINE INPUT "Enter full name of source .BIN file        :  ";SRCFIL$
  13282.  OPEN SCRCFIL$ FOR INPUT AS SRCCNL             ' Test for source (.BIN) file.
  13283.  SRCSIZ! = LOF(SRCCNL)                         ' Save file's size.
  13284.  CLOSE SRCCNL
  13285.  IF (SRCSIZ! > 65536) THEN                     ' Reject if file exceeds 64 KB.
  13286.      PRINT "Cannot convert file larger than 64 KB."
  13287.      END
  13288.  END IF
  13289.  
  13290.  LINE INPUT "Enter full name of target .HEX file        :  ";TGTFIL$
  13291.  OPEN TGTFIL$ FOR OUTPUT AS TGTCNL             ' Test target (.HEX) filename.
  13292.  CLOSE TGTCNL
  13293.  
  13294.  DO
  13295.      LINE INPUT "Enter starting address of .BIN file in HEX :  ";L$
  13296.      ADRBGN! = VAL("&H" + L$)                  ' Convert ASCII HEX address val
  13297.                                                ' to binary value.
  13298.      IF (ADRBGN! < 0) THEN                     ' HEX values 8000-FFFFH convert
  13299.       ADRBGN! = 65536 + ADRBGN!                ' to negative values.
  13300.      END IF
  13301.      ADREND! = ADRBGN! + SRCSIZ! - 1           ' Calculate resulting end addre
  13302.      IF (ADREND! > 65535) THEN                 ' Reject if address exceeds FFF
  13303.       PRINT "Entered start address causes end address to exceed FFFFH."
  13304.      END IF
  13305.  LOOP UNTIL (ADRFLD! >= 0) AND (ADRFLD! <= 65535) AND (ADREND! <= 65535)
  13306.  
  13307.  DO
  13308.      LINE INPUT "Enter byte count for each record in HEX    :  ";L$
  13309.      SRCRLN = VAL("&H" + L$)                   ' Convert ASCII HEX max record
  13310.                                                ' length value to binary value.
  13311.      IF (SRCRLN < 0) THEN                      ' HEX values 8000H-FFFFH conver
  13312.       SRCRLN = 65536 + SRCRLN                  ' to negative values.
  13313.      END IF
  13314.  LOOP UNTIL (SRCRLN > 0) AND (SRCRLN < 256)    ' Ask again if not 1-255.
  13315.  
  13316.  OPEN SRCFIL$ AS SRCCNL LEN = SRCRLN           ' Reopen source for block I/O.
  13317.  FIELD#SRCCNL,SRCRLN AS SRCBLK$
  13318.  OPEN TGTFIL$ FOR OUTPUT AS TGTCNL             ' Reopen target for text output
  13319.  SRCREC = 0                                    ' Starting source block # minus
  13320.  
  13321.  FOR ADRFLD! = ADRBGN! TO ADREND! STEP SRCRLN  ' Convert one block per loop.
  13322.      SRCREC = SRCREC + 1                       ' Next source block.
  13323.      GET SRCCNL,SRCREC                         ' Read the source block.
  13324.      IF (ADRFLD! + SRCRLN > ADREND!) THEN      ' If last block less than full
  13325.       BLK$=LEFT$(SRCBLK$,ADREND!-ADRFLD!+1)    ' size:  trim it.
  13326.      ELSE                                      ' Else:
  13327.          BLK$ = SRCBLK$                        ' Use full block.
  13328.      END IF
  13329.  
  13330.      PRINT#TGTCNL, ":";                        ' Write record mark.
  13331.  
  13332.      PRINT#TGTCNL, FNHXB$(LEN(BLK$));          ' Write data field size.
  13333.      CHKSUM = LEN(BLK$)                        ' Initialize checksum accumulat
  13334.                                                ' with first value.
  13335.      PRINT#TGTCNL,FNHXW$(ADRFLD!);             ' Write record's load address.
  13336.  
  13337.  ' The following "AND &HFF" operations limit CHKSUM to a byte value.
  13338.      CHKSUM = CHKSUM + INT(ADRFLD!/256) AND &HFF   ' Add hi byte of adrs to cs
  13339.      CHKSUM = CHKSUM + FNMOD(ADRFLD!,256) AND &HFF ' Add lo byte of adrs to cs
  13340.  
  13341.      PRINT#TGTCNL,FNHXB$(0);                   ' Write record type.
  13342.  
  13343.  ' Don't bother to add record type byte to checksum since it's 0.
  13344.      FOR IDX = 1 TO LEN(BLK$)                  ' Write all bytes.
  13345.       PRINT#TGTCNL,FNHXB$(ASC(MID$(BLK$,IDX,1)));      ' Write next byte.
  13346.       CHKSUM = CHKSUM + ASC(MID$(BLK$,IDX,1)) AND &HFF ' Incl byte in csum.
  13347.      NEXT IDX
  13348.  
  13349.      CHKSUM = 0 - CHKSUM AND &HFF              ' Negate checksum then limit
  13350.                                                ' to byte value.
  13351.      PRINT #TGTCNL,FNHXB$(CHKSUM)              ' End record with checksum.
  13352.  
  13353.  NEXT ADRFLD!
  13354.  
  13355.  PRINT#TGTCNL, ":00000001FF"                   ' Write end-of-file record.
  13356.  
  13357.  CLOSE TGTCNL                                  ' Close target file.
  13358.  CLOSE SRCCNL                                  ' Close source file.
  13359.  
  13360.  END
  13361.  
  13362.  \SAMPCODE\DOS_ENCY\APP_N
  13363.  \SAMPCODE\DOS_ENCY\APP_N\OBJDUMP.C
  13364.  
  13365.  /****************************************************************************
  13366.  *
  13367.  * OBJDUMP.C -- display contents of an object file
  13368.  *
  13369.  *
  13370.  *     Compile:  msc objdump;   (Microsoft C version 4.0 or later)
  13371.  *     Link:     link objdump;
  13372.  *     Execute:  objdump <filename>
  13373.  *
  13374.  *****************************************************************************
  13375.  
  13376.  #include        <fcntl.h>
  13377.  
  13378.  #define         TRUE    1
  13379.  #define         FALSE   0
  13380.  
  13381.  main( argc, argv )
  13382.  int        argc;
  13383.  char       **argv;
  13384.  {
  13385.          unsigned char        CurrentByte;
  13386.          int     ObjFileHandle;
  13387.          int     CurrentLineLength;                 /* length of output line *
  13388.          int     ObjRecordNumber = 0;
  13389.          int     ObjRecordLength;
  13390.          int     ObjRecordOffset = 0;   /* offset into current object record *
  13391.          char    ASCIIEquiv[17];
  13392.          char    FormatString[24];
  13393.          char    *ObjRecordName();
  13394.          char    *memset();
  13395.  
  13396.  
  13397.  /* open the object file */
  13398.  
  13399.          ObjFileHandle = open( argv[1],O_BINARY );
  13400.  
  13401.          if( ObjFileHandle == -1 )
  13402.          {
  13403.            printf( "\nCan't open object file\n" );
  13404.            exit( 1 );
  13405.          }
  13406.  
  13407.  /* process the object file character by character */
  13408.  
  13409.          while( read( ObjFileHandle, &CurrentByte, 1 ) )
  13410.          {
  13411.            switch( ObjRecordOffset ) /* action depends on offset into record *
  13412.            {
  13413.              case(0):                              /* start of object record *
  13414.                printf( "\n\nRecord %d:  %02Xh %s",
  13415.                  ++ObjRecordNumber, CurrentByte, ObjRecordName(CurrentByte) );
  13416.                printf( "\n%02X ", CurrentByte );
  13417.                ++ObjRecordOffset;
  13418.                break;
  13419.  
  13420.              case(1):                          /* first byte of length field *
  13421.                ObjRecordLength = CurrentByte;
  13422.                ++ObjRecordOffset;
  13423.                break;
  13424.  
  13425.              case(2):                         /* second byte of length field *
  13426.                ObjRecordLength += CurrentByte << 8; /* compute record length *
  13427.                printf( "%04Xh ", ObjRecordLength );           /* show length *
  13428.                CurrentLineLength = 0;
  13429.                memset( ASCIIEquiv,'\0', 17 );            /* zero this string *
  13430.                ++ObjRecordOffset;
  13431.                break;
  13432.  
  13433.              default:                    /* remaining bytes in object record *
  13434.                printf( "%02X ", CurrentByte );                        /* hex *
  13435.  
  13436.                if( CurrentByte < 0x20 || CurrentByte > 0x7F )       /* ASCII *
  13437.                  CurrentByte = '.';
  13438.                ASCIIEquiv[CurrentLineLength++] = CurrentByte;
  13439.  
  13440.                if( CurrentLineLength == 16 ||   /* if end of output line ... *
  13441.                   ObjRecordOffset == ObjRecordLength+2 )
  13442.                {                                           /* ... display it *
  13443.                  sprintf( FormatString, "%%%ds%%s\n         ",
  13444.                    3*(16-CurrentLineLength)+2 );
  13445.                  printf( FormatString, " ", ASCIIEquiv );
  13446.                  memset( ASCIIEquiv, '\0', 17 );
  13447.                  CurrentLineLength = 0;
  13448.                }
  13449.  
  13450.                if( ++ObjRecordOffset == ObjRecordLength+3 )  /* if done .. */
  13451.                  ObjRecordOffset = 0;          /* .. process another record */
  13452.                break;
  13453.            }
  13454.          }
  13455.  
  13456.          if( CurrentLineLength )    /* display remainder of last output line *
  13457.            printf( "  %s", ASCIIEquiv );
  13458.  
  13459.          close( ObjFileHandle );
  13460.  
  13461.          printf( "\n%d object records\n", ObjRecordNumber );
  13462.  
  13463.          return( 0 );
  13464.  }
  13465.  
  13466.  
  13467.  char *ObjRecordName( n )                       /* return object record name *
  13468.  int        n;                                            /* n = record type *
  13469.  {
  13470.          int        i;
  13471.  
  13472.          static     struct
  13473.          {
  13474.            int        RecordNumber;
  13475.            char       *RecordName;
  13476.          }                RecordStruct[] =
  13477.                           {
  13478.                            0x80,"THEADR",
  13479.                            0x88,"COMENT",
  13480.                            0x8A,"MODEND",
  13481.                            0x8C,"EXTDEF",
  13482.                            0x8E,"TYPDEF",
  13483.                            0x90,"PUBDEF",
  13484.                            0x94,"LINNUM",
  13485.                            0x96,"LNAMES",
  13486.                            0x98,"SEGDEF",
  13487.                            0x9A,"GRPDEF",
  13488.                            0x9C,"FIXUPP",
  13489.                            0xA0,"LEDATA",
  13490.                            0xA2,"LIDATA",
  13491.                            0xB0,"COMDEF",
  13492.                            0x00,"******"
  13493.                           };
  13494.  
  13495.          int      RecordTableSize = sizeof(RecordStruct)/sizeof(RecordStruct[0
  13496.  
  13497.  
  13498.          for( i=0; i<RecordTableSize-1; i++ )         /* scan table for name *
  13499.            if ( RecordStruct[i].RecordNumber == n )
  13500.              break;
  13501.  
  13502.          return( RecordStruct[i].RecordName );
  13503.  }
  13504.  
  13505.  \SAMPCODE\DOS_ENCY\SECTION5
  13506.  \SAMPCODE\DOS_ENCY\SECTION5\TESTCM.C
  13507.  
  13508.  main()
  13509.  {
  13510.          printf("The sum is %d",addnums(12,33));
  13511.  }
  13512.  
  13513.  \SAMPCODE\DOS_ENCY\SECTION5\FXN01H.ASM
  13514.  
  13515.          ;************************************************************;
  13516.          ;                                                            ;
  13517.          ;           Function 01H: Character Input with Echo          ;
  13518.          ;                                                            ;
  13519.          ;           int read_kbd_echo()                              ;
  13520.          ;                                                            ;
  13521.          ;           Returns a character from standard input          ;
  13522.          ;           after sending it to standard output.             ;
  13523.          ;                                                            ;
  13524.          ;************************************************************;
  13525.  
  13526.  cProc   read_kbd_echo,PUBLIC
  13527.  cBegin
  13528.          mov     ah,01h          ; Set function code.
  13529.          int     21h             ; Wait for character.
  13530.          mov     ah,0            ; Character is in AL, so clear high
  13531.                                  ; byte.
  13532.  cEnd
  13533.  
  13534.  \SAMPCODE\DOS_ENCY\SECTION5\FXN02H.ASM
  13535.  
  13536.          ;************************************************************;
  13537.          ;                                                            ;
  13538.          ;                Function 02H: Character Output              ;
  13539.          ;                                                            ;
  13540.          ;                int disp_ch(c)                              ;
  13541.          ;                    char c;                                 ;
  13542.          ;                                                            ;
  13543.          ;                Returns 0.                                  ;
  13544.          ;                                                            ;
  13545.          ;************************************************************;
  13546.  
  13547.  cProc   disp_ch,PUBLIC
  13548.  parmB   c
  13549.  cBegin
  13550.          mov     dl,c            ; Get character into DL.
  13551.          mov     ah,02h          ; Set function code.
  13552.          int     21h             ; Send character.
  13553.          xor     ax,ax           ; Return 0.
  13554.  cEnd
  13555.  
  13556.  \SAMPCODE\DOS_ENCY\SECTION5\FXN03H.ASM
  13557.  
  13558.          ;************************************************************;
  13559.          ;                                                            ;
  13560.          ;           Function 03H: Auxiliary Input                    ;
  13561.          ;                                                            ;
  13562.          ;           int aux_in()                                     ;
  13563.          ;                                                            ;
  13564.          ;           Returns next character from AUX device.          ;
  13565.          ;                                                            ;
  13566.          ;************************************************************;
  13567.  
  13568.  cProc   aux_in,PUBLIC
  13569.  cBegin
  13570.          mov     ah,03h          ; Set function code.
  13571.          int     21h             ; Wait for character from AUX.
  13572.          mov     ah,0            ; Character is in AL
  13573.                                  ; so clear high byte.
  13574.  cEnd
  13575.  
  13576.  \SAMPCODE\DOS_ENCY\SECTION5\FXN04H.ASM
  13577.  
  13578.          ;************************************************************;
  13579.          ;                                                            ;
  13580.          ;                Function 04H: Auxiliary Output              ;
  13581.          ;                                                            ;
  13582.          ;                int aux_out(c)                              ;
  13583.          ;                    char c;                                 ;
  13584.          ;                                                            ;
  13585.          ;                Returns 0.                                  ;
  13586.          ;                                                            ;
  13587.          ;************************************************************;
  13588.  
  13589.  cProc   aux_out,PUBLIC
  13590.  parmB   c
  13591.  cBegin
  13592.          mov     dl,c            ; Get character into DL.
  13593.          mov     ah,04h          ; Set function code.
  13594.          int     21h             ; Write character to AUX.
  13595.          xor     ax,ax           ; Return 0.
  13596.  cEnd
  13597.  
  13598.  \SAMPCODE\DOS_ENCY\SECTION5\FXN05H.ASM
  13599.  
  13600.          ;************************************************************;
  13601.          ;                                                            ;
  13602.          ;                Function 05H: Print Character               ;
  13603.          ;                                                            ;
  13604.          ;                int print_ch(c)                             ;
  13605.          ;                    char c;                                 ;
  13606.          ;                                                            ;
  13607.          ;                Returns 0.                                  ;
  13608.          ;                                                            ;
  13609.          ;************************************************************;
  13610.  
  13611.  cProc   print_ch,PUBLIC
  13612.  parmB   c
  13613.  cBegin
  13614.          mov     dl,c            ; Get character into DL.
  13615.          mov     ah,05h          ; Set function code.
  13616.          int     21h             ; Write character to standard printer.
  13617.          xor     ax,ax           ; Return 0.
  13618.  cEnd
  13619.  
  13620.  \SAMPCODE\DOS_ENCY\SECTION5\FXN06H.ASM
  13621.  
  13622.          ;************************************************************;
  13623.          ;                                                            ;
  13624.          ;          Function 06H: Direct Console I/O                  ;
  13625.          ;                                                            ;
  13626.          ;          int con_io(c)                                     ;
  13627.          ;              char c;                                       ;
  13628.          ;                                                            ;
  13629.          ;          Returns meaningless data if c is not 0FFH,        ;
  13630.          ;          otherwise returns next character from             ;
  13631.          ;          standard input.                                   ;
  13632.          ;                                                            ;
  13633.          ;************************************************************;
  13634.  
  13635.  cProc   con_io,PUBLIC
  13636.  parmB   c
  13637.  cBegin
  13638.          mov     dl,c            ; Get character into DL.
  13639.          mov     ah,06h          ; Set function code.
  13640.          int     21h             ; This function does NOT wait in
  13641.                                  ; input case (c = 0FFH)!
  13642.          mov     ah,0            ; Return the contents of AL.
  13643.  cEnd
  13644.  
  13645.  \SAMPCODE\DOS_ENCY\SECTION5\FXN07H.ASM
  13646.  
  13647.          ;************************************************************;
  13648.          ;                                                            ;
  13649.          ;         Function 07H: Unfiltered Character Input           ;
  13650.          ;                       Without Echo                         ;
  13651.          ;                                                            ;
  13652.          ;         int con_in()                                       ;
  13653.          ;                                                            ;
  13654.          ;         Returns next character from standard input.        ;
  13655.          ;                                                            ;
  13656.          ;************************************************************;
  13657.  
  13658.  cProc   con_in,PUBLIC
  13659.  cBegin
  13660.          mov     ah,07h          ; Set function code.
  13661.          int     21h             ; Wait for character, no echo.
  13662.          mov     ah,0            ; Clear high byte.
  13663.  cEnd
  13664.  
  13665.  \SAMPCODE\DOS_ENCY\SECTION5\FXN08H.ASM
  13666.  
  13667.          ;************************************************************;
  13668.          ;                                                            ;
  13669.          ;    Function 08H:  Unfiltered Character Input Without Echo  ;
  13670.          ;                                                            ;
  13671.          ;    int read_kbd()                                          ;
  13672.          ;                                                            ;
  13673.          ;    Returns next character from standard input.             ;
  13674.          ;                                                            ;
  13675.          ;************************************************************;
  13676.  
  13677.  cProc   read_kbd,PUBLIC
  13678.  cBegin
  13679.          mov     ah,08h          ; Set function code.
  13680.          int     21h             ; Wait for character, no echo.
  13681.          mov     ah,0            ; Clear high byte.
  13682.  cEnd
  13683.  
  13684.  \SAMPCODE\DOS_ENCY\SECTION5\FXN09H.ASM
  13685.  
  13686.          ;************************************************************;
  13687.          ;                                                            ;
  13688.          ;                 Function 09H: Display String               ;
  13689.          ;                                                            ;
  13690.          ;                 int disp_str(pstr)                         ;
  13691.          ;                     char *pstr;                            ;
  13692.          ;                                                            ;
  13693.          ;                 Returns 0.                                 ;
  13694.          ;                                                            ;
  13695.          ;************************************************************;
  13696.  
  13697.  cProc   disp_str,PUBLIC,<ds,di>
  13698.  parmDP  pstr
  13699.  cBegin
  13700.          loadDP  ds,dx,pstr      ; DS:DX = pointer to string.
  13701.          mov     ax,0900h        ; Prepare to write dollar-terminated
  13702.                                  ; string to standard output, but
  13703.                                  ; first replace the 0 at the end of
  13704.                                  ; the string with '$'.
  13705.          push    ds              ; Set ES equal to DS.
  13706.          pop     es              ; (MS-C does not require ES to be
  13707.                                  ; saved.)
  13708.          mov     di,dx           ; ES:DI points at string.
  13709.          mov     cx,0ffffh       ; Allow string to be 64KB long.
  13710.          repne   scasb           ; Look for 0 at end of string.
  13711.          dec     di              ; Scasb search always goes 1 byte too
  13712.                                  ; far.
  13713.          mov     byte ptr [di],'$' ; Replace 0 with dollar sign.
  13714.          int     21h             ; Have MS-DOS print string.
  13715.          mov     [di],al         ; Restore 0 terminator.
  13716.          xor     ax,ax           ; Return 0.
  13717.  cEnd
  13718.  
  13719.  \SAMPCODE\DOS_ENCY\SECTION5\FXN0AH.ASM
  13720.  
  13721.          ;************************************************************;
  13722.          ;                                                            ;
  13723.          ;        Function 0AH: Buffered Keyboard Input               ;
  13724.          ;                                                            ;
  13725.          ;        int read_str(pbuf,len)                              ;
  13726.          ;            char *pbuf;                                     ;
  13727.          ;            int len;                                        ;
  13728.          ;                                                            ;
  13729.          ;        Returns number of bytes read into buffer.           ;
  13730.          ;                                                            ;
  13731.          ;        Note: pbuf must be at least len+3 bytes long.       ;
  13732.          ;                                                            ;
  13733.          ;************************************************************;
  13734.  
  13735.  cProc   read_str,PUBLIC,<ds,di>
  13736.  parmDP  pbuf
  13737.  parmB   len
  13738.  cBegin
  13739.          loadDP  ds,dx,pbuf      ; DS:DX = pointer to buffer.
  13740.          mov     al,len          ; AL = len.
  13741.          inc     al              ; Add 1 to allow for CR in buf.
  13742.          mov     di,dx
  13743.          mov     [di],al         ; Store max length into buffer.
  13744.          mov     ah,0ah          ; Set function code.
  13745.          int     21h             ; Ask MS-DOS to read string.
  13746.          mov     al,[di+1]       ; Return number of characters read.
  13747.          mov     ah,0
  13748.          mov     bx,ax
  13749.          mov     [bx+di+2],ah    ; Store 0 at end of buffer.
  13750.  cEnd
  13751.  
  13752.  \SAMPCODE\DOS_ENCY\SECTION5\FXN0BH.ASM
  13753.  
  13754.          ;************************************************************;
  13755.          ;                                                            ;
  13756.          ;             Function 0BH: Check Keyboard Status            ;
  13757.          ;                                                            ;
  13758.          ;             int key_ready()                                ;
  13759.          ;                                                            ;
  13760.          ;             Returns 1 if key is ready, 0 if not.           ;
  13761.          ;                                                            ;
  13762.          ;************************************************************;
  13763.  
  13764.  cProc   key_ready,PUBLIC
  13765.  cBegin
  13766.          mov     ah,0bh          ; Set function code.
  13767.          int     21h             ; Ask MS-DOS if key is available.
  13768.          and     ax,0001h        ; Keep least significant bit only.
  13769.  cEnd
  13770.  
  13771.  \SAMPCODE\DOS_ENCY\SECTION5\FXN0CH.ASM
  13772.  
  13773.          ;************************************************************;
  13774.          ;                                                            ;
  13775.          ;          Function 0CH: Flush Buffer, Read Keyboard         ;
  13776.          ;                                                            ;
  13777.          ;          int flush_kbd()                                   ;
  13778.          ;                                                            ;
  13779.          ;          Returns 0.                                        ;
  13780.          ;                                                            ;
  13781.          ;************************************************************;
  13782.  
  13783.  cProc   flush_kbd,PUBLIC
  13784.  cBegin
  13785.          mov     ax,0c00h        ; Just flush type-ahead buffer.
  13786.          int     21h             ; Call MS-DOS.
  13787.          xor     ax,ax           ; Return 0.
  13788.  cEnd
  13789.  
  13790.  \SAMPCODE\DOS_ENCY\SECTION5\FXN0DH.ASM
  13791.  
  13792.          ;************************************************************;
  13793.          ;                                                            ;
  13794.          ;                   Function 0DH: Disk Reset                 ;
  13795.          ;                                                            ;
  13796.          ;                   int reset_disk()                         ;
  13797.          ;                                                            ;
  13798.          ;                   Returns 0.                               ;
  13799.          ;                                                            ;
  13800.          ;************************************************************;
  13801.  
  13802.  cProc   reset_disk,PUBLIC
  13803.  cBegin
  13804.          mov     ah,0dh          ; Set function code.
  13805.          int     21h             ; Ask MS-DOS to write all dirty file
  13806.                                  ; buffers to the disk.
  13807.          xor     ax,ax           ; Return 0.
  13808.  cEnd
  13809.  
  13810.  \SAMPCODE\DOS_ENCY\SECTION5\FXN0EH.ASM
  13811.  
  13812.          ;************************************************************;
  13813.          ;                                                            ;
  13814.          ;     Function 0EH: Select Disk                              ;
  13815.          ;                                                            ;
  13816.          ;     int select_drive(drive_ltr)                            ;
  13817.          ;         char drive_ltr;                                    ;
  13818.          ;                                                            ;
  13819.          ;     Returns number of logical drives present in system.    ;
  13820.          ;                                                            ;
  13821.          ;************************************************************;
  13822.  
  13823.  cProc   select_drive,PUBLIC
  13824.  parmB   disk_ltr
  13825.  cBegin
  13826.          mov     dl,disk_ltr     ; Get new drive letter.
  13827.          and     dl,not 20h      ; Make sure letter is uppercase.
  13828.          sub     dl,'A'          ; Convert drive letter to number,
  13829.                                  ; 'A' = 0, 'B' = 1, etc.
  13830.          mov     ah,0eh          ; Set function code.
  13831.          int     21h             ; Ask MS-DOS to set default drive.
  13832.          cbw                     ; Clear high byte of return value.
  13833.  cEnd
  13834.  
  13835.  \SAMPCODE\DOS_ENCY\SECTION5\FXN0FH.ASM
  13836.  
  13837.          ;************************************************************;
  13838.          ;                                                            ;
  13839.          ;        Function 0FH: Open File, FCB-based                  ;
  13840.          ;                                                            ;
  13841.          ;        int FCB_open(uXFCB,recsize)                         ;
  13842.          ;            char *uXFCB;                                    ;
  13843.          ;            int recsize;                                    ;
  13844.          ;                                                            ;
  13845.          ;        Returns 0 if file opened OK, otherwise returns -1.  ;
  13846.          ;                                                            ;
  13847.          ;        Note: uXFCB must have the drive and filename        ;
  13848.          ;        fields (bytes 07H through 12H) and the extension    ;
  13849.          ;        flag (byte 00H) set before the call to FCB_open     ;
  13850.          ;        (see Function 29H).                                 ;
  13851.          ;                                                            ;
  13852.          ;************************************************************;
  13853.  
  13854.  cProc   FCB_open,PUBLIC,ds
  13855.  parmDP  puXFCB
  13856.  parmW   recsize
  13857.  cBegin
  13858.          loadDP  ds,dx,puXFCB    ; Pointer to unopened extended FCB.
  13859.          mov     ah,0fh          ; Ask MS-DOS to open an existing file.
  13860.          int     21h
  13861.          add     dx,7            ; Advance pointer to start of regular
  13862.                                  ; FCB.
  13863.          mov     bx,dx           ; BX = FCB pointer.
  13864.          mov     dx,recsize      ; Get record size parameter.
  13865.          mov     [bx+0eh],dx     ; Store record size in FCB.
  13866.          xor     dx,dx
  13867.          mov     [bx+20h],dl     ; Set current-record
  13868.          mov     [bx+21h],dx     ; and relative-record
  13869.          mov     [bx+23h],dx     ; fields to 0.
  13870.          cbw                     ; Set return value to 0 or -1.
  13871.  cEnd
  13872.  
  13873.  \SAMPCODE\DOS_ENCY\SECTION5\FXN10H.ASM
  13874.  
  13875.          ;************************************************************;
  13876.          ;                                                            ;
  13877.          ;           Function 10H: Close file, FCB-based              ;
  13878.          ;                                                            ;
  13879.          ;           int FCB_close(oXFCB)                             ;
  13880.          ;               char *oXFCB;                                 ;
  13881.          ;                                                            ;
  13882.          ;           Returns 0 if file closed OK, otherwise           ;
  13883.          ;           returns -1.                                      ;
  13884.          ;                                                            ;
  13885.          ;************************************************************;
  13886.  
  13887.  cProc   FCB_close,PUBLIC,ds
  13888.  parmDP  poXFCB
  13889.  cBegin
  13890.          loadDP  ds,dx,poXFCB    ; Pointer to opened extended FCB.
  13891.          mov     ah,10h          ; Ask MS-DOS to close file.
  13892.          int     21h
  13893.          cbw                     ; Set return value to 0 or -1.
  13894.  cEnd
  13895.  
  13896.  \SAMPCODE\DOS_ENCY\SECTION5\FXN11H.ASM
  13897.  
  13898.          ;************************************************************;
  13899.          ;                                                            ;
  13900.          ;       Function 11H: Find First File, FCB-based             ;
  13901.          ;                                                            ;
  13902.          ;       int FCB_first(puXFCB,attrib)                         ;
  13903.          ;           char *puXFCB;                                    ;
  13904.          ;           char  attrib;                                    ;
  13905.          ;                                                            ;
  13906.          ;       Returns 0 if match found, otherwise returns -1.      ;
  13907.          ;                                                            ;
  13908.          ;       Note: The FCB must have the drive and                ;
  13909.          ;       filename fields (bytes 07H through 12H) and          ;
  13910.          ;       the extension flag (byte 00H) set before             ;
  13911.          ;       the call to FCB_first (see Function 29H).            ;
  13912.          ;                                                            ;
  13913.          ;************************************************************;
  13914.  
  13915.  cProc   FCB_first,PUBLIC,ds
  13916.  parmDP  puXFCB
  13917.  parmB   attrib
  13918.  cBegin
  13919.          loadDP  ds,dx,puXFCB    ; Pointer to unopened extended FCB.
  13920.          mov     bx,dx           ; BX points at FCB, too.
  13921.          mov     al,attrib       ; Get search attribute.
  13922.          mov     [bx+6],al       ; Put attribute into extended FCB
  13923.                                  ; area.
  13924.          mov     byte ptr [bx],0ffh ; Set flag for extended FCB.
  13925.          mov     ah,11h          ; Ask MS-DOS to find 1st matching
  13926.                                  ; file in current directory.
  13927.          int     21h             ; If match found, directory entry can
  13928.                                  ; be found at DTA address.
  13929.          cbw                     ; Set return value to 0 or -1.
  13930.  cEnd
  13931.  
  13932.  \SAMPCODE\DOS_ENCY\SECTION5\FXN12H.ASM
  13933.  
  13934.          ;************************************************************;
  13935.          ;                                                            ;
  13936.          ;       Function 12H: Find Next File, FCB-based              ;
  13937.          ;                                                            ;
  13938.          ;       int FCB_next(puXFCB)                                 ;
  13939.          ;           char *puXFCB;                                    ;
  13940.          ;                                                            ;
  13941.          ;       Returns 0 if match found, otherwise returns -1.      ;
  13942.          ;                                                            ;
  13943.          ;       Note: The FCB must have the drive and                ;
  13944.          ;       filename fields (bytes 07H through 12H) and          ;
  13945.          ;       the extension flag (byte 00H) set before             ;
  13946.          ;       the call to FCB_next (see Function 29H).             ;
  13947.          ;                                                            ;
  13948.          ;************************************************************;
  13949.  
  13950.  cProc   FCB_next,PUBLIC,ds
  13951.  parmDP  puXFCB
  13952.  cBegin
  13953.          loadDP  ds,dx,puXFCB    ; Pointer to unopened extended FCB.
  13954.          mov     ah,12h          ; Ask MS-DOS to find next matching
  13955.                                  ; file in current directory.
  13956.          int     21h             ; If match found, directory entry can
  13957.                                  ; be found at DTA address.
  13958.          cbw                     ; Set return value to 0 or -1.
  13959.  cEnd
  13960.  
  13961.  \SAMPCODE\DOS_ENCY\SECTION5\FXN13H.ASM
  13962.  
  13963.          ;************************************************************;
  13964.          ;                                                            ;
  13965.          ;       Function 13H: Delete File(s), FCB-based              ;
  13966.          ;                                                            ;
  13967.          ;       int FCB_delete(uXFCB)                                ;
  13968.          ;           char *uXFCB;                                     ;
  13969.          ;                                                            ;
  13970.          ;       Returns 0 if file(s) were deleted OK, otherwise      ;
  13971.          ;       returns -1.                                          ;
  13972.          ;                                                            ;
  13973.          ;       Note: uXFCB must have the drive and                  ;
  13974.          ;       filename fields (bytes 07H through 12H) and          ;
  13975.          ;       the extension flag (byte 00H) set before             ;
  13976.          ;       the call to FCB_delete (see Function 29H).           ;
  13977.          ;                                                            ;
  13978.          ;************************************************************;
  13979.  
  13980.  cProc   FCB_delete,PUBLIC,ds
  13981.  parmDP  puXFCB
  13982.  cBegin
  13983.          loadDP  ds,dx,puXFCB    ; Pointer to unopened extended FCB.
  13984.          mov     ah,13h          ; Ask MS-DOS to delete file(s).
  13985.          int     21h
  13986.          cbw                     ; Return value of 0 or -1.
  13987.  cEnd
  13988.  \SAMPCODE\DOS_ENCY\SECTION5\FXN14H.ASM
  13989.  
  13990.          ;************************************************************;
  13991.          ;                                                            ;
  13992.          ;           Function 14H: Sequential Read, FCB-based         ;
  13993.          ;                                                            ;
  13994.          ;           int FCB_sread(oXFCB)                             ;
  13995.          ;               char *oXFCB;                                 ;
  13996.          ;                                                            ;
  13997.          ;           Returns 0 if record read OK, otherwise           ;
  13998.          ;           returns error code 1, 2, or 3.                   ;
  13999.          ;                                                            ;
  14000.          ;************************************************************;
  14001.  
  14002.  cProc   FCB_sread,PUBLIC,ds
  14003.  parmDP  poXFCB
  14004.  cBegin
  14005.          loadDP  ds,dx,poXFCB    ; Pointer to opened extended FCB.
  14006.          mov     ah,14h          ; Ask MS-DOS to read next record,
  14007.                                  ; placing it at DTA.
  14008.          int     21h
  14009.          cbw                     ; Clear high byte for return value.
  14010.  cEnd
  14011.  
  14012.  \SAMPCODE\DOS_ENCY\SECTION5\FXN15H.ASM
  14013.  
  14014.          ;************************************************************;
  14015.          ;                                                            ;
  14016.          ;          Function 15H: Sequential Write, FCB-based         ;
  14017.          ;                                                            ;
  14018.          ;          int FCB_swrite(oXFCB)                             ;
  14019.          ;              char *oXFCB;                                  ;
  14020.          ;                                                            ;
  14021.          ;          Returns 0 if record read OK, otherwise            ;
  14022.          ;          returns error code 1 or 2.                        ;
  14023.          ;                                                            ;
  14024.          ;************************************************************;
  14025.  
  14026.  cProc   FCB_swrite,PUBLIC,ds
  14027.  parmDP  poXFCB
  14028.  cBegin
  14029.          loadDP  ds,dx,poXFCB    ; Pointer to opened extended FCB.
  14030.          mov     ah,15h          ; Ask MS-DOS to write next record
  14031.                                  ; from DTA to disk file.
  14032.          int     21h
  14033.          cbw                     ; Clear high byte for return value.
  14034.  cEnd
  14035.  
  14036.  \SAMPCODE\DOS_ENCY\SECTION5\FXN16H.ASM
  14037.  
  14038.          ;************************************************************;
  14039.          ;                                                            ;
  14040.          ;         Function 16H: Create File, FCB-based               ;
  14041.          ;                                                            ;
  14042.          ;         int FCB_create(uXFCB,recsize)                      ;
  14043.          ;             char *uXFCB;                                   ;
  14044.          ;             int recsize;                                   ;
  14045.          ;                                                            ;
  14046.          ;         Returns 0 if file created OK, otherwise            ;
  14047.          ;         returns -1.                                        ;
  14048.          ;                                                            ;
  14049.          ;         Note: uXFCB must have the drive and filename       ;
  14050.          ;         fields (bytes 07H through 12H) and the             ;
  14051.          ;         extension flag (byte 00H) set before the           ;
  14052.          ;         call to FCB_create (see Function 29H).             ;
  14053.          ;                                                            ;
  14054.          ;************************************************************;
  14055.  
  14056.  cProc   FCB_create,PUBLIC,ds
  14057.  parmDP  puXFCB
  14058.  parmW   recsize
  14059.  cBegin
  14060.          loadDP  ds,dx,puXFCB    ; Pointer to unopened extended FCB.
  14061.          mov     ah,16h          ; Ask MS-DOS to create file.
  14062.          int     21h
  14063.          add     dx,7            ; Advance pointer to start of regular
  14064.                                  ; FCB.
  14065.          mov     bx,dx           ; BX = FCB pointer.
  14066.          mov     dx,recsize      ; Get record size parameter.
  14067.          mov     [bx+0eh],dx     ; Store record size in FCB.
  14068.          xor     dx,dx
  14069.          mov     [bx+20h],dl     ; Set current-record
  14070.          mov     [bx+21h],dx     ; and relative-record
  14071.          mov     [bx+23h],dx     ; fields to 0.
  14072.          cbw                     ; Set return value to 0 or -1.
  14073.  cEnd
  14074.  
  14075.  \SAMPCODE\DOS_ENCY\SECTION5\FXN17H.ASM
  14076.  
  14077.          ;************************************************************;
  14078.          ;                                                            ;
  14079.          ;         Function 17H: Rename File(s), FCB-based            ;
  14080.          ;                                                            ;
  14081.          ;         int FCB_rename(uXFCBold,uXFCBnew)                  ;
  14082.          ;             char *uXFCBold,*uXFCBnew;                      ;
  14083.          ;                                                            ;
  14084.          ;         Returns 0 if file(s) renamed OK, otherwise         ;
  14085.          ;         returns -1.                                        ;
  14086.          ;                                                            ;
  14087.          ;         Note: Both uXFCB's must have the drive and         ;
  14088.          ;         filename fields (bytes 07H through 12H) and        ;
  14089.          ;         the extension flag (byte 00H) set before           ;
  14090.          ;         the call to FCB_rename (see Function 29H).         ;
  14091.          ;                                                            ;
  14092.          ;************************************************************;
  14093.  
  14094.  cProc   FCB_rename,PUBLIC,<ds,si,di>
  14095.  parmDP  puXFCBold
  14096.  parmDP  puXFCBnew
  14097.  cBegin
  14098.          loadDP  es,di,puXFCBold ; ES:DI = Pointer to uXFCBold.
  14099.          mov     dx,di           ; Save offset in DX.
  14100.          add     di,7            ; Advance pointer to start of regular
  14101.                                  ; FCBold.
  14102.          loadDP  ds,si,puXFCBnew ; DS:SI = Pointer to uXFCBnew.
  14103.          add     si,8            ; Advance pointer to filename field
  14104.                                  ; FCBnew.
  14105.                                  ; Copy name from FCBnew into FCBold
  14106.                                  ; at offset 11H:
  14107.          add     di,11h          ; DI points 11H bytes into old FCB.
  14108.          mov     cx,0bh          ; Copy 0BH bytes, moving new
  14109.          rep     movsb           ; name into old FCB.
  14110.          push    es              ; Set DS to segment of FCBold.
  14111.          pop     ds
  14112.          mov     ah,17h          ; Ask MS-DOS to rename old
  14113.          int     21h             ; file(s) to new name(s).
  14114.          cbw                     ; Set return flag to 0 or -1.
  14115.  cEnd
  14116.  
  14117.  \SAMPCODE\DOS_ENCY\SECTION5\FXN19H.ASM
  14118.  
  14119.          ;************************************************************;
  14120.          ;                                                            ;
  14121.          ;           Function 19H: Get Current Disk                   ;
  14122.          ;                                                            ;
  14123.          ;           int cur_drive()                                  ;
  14124.          ;                                                            ;
  14125.          ;           Returns letter of current "logged" disk.         ;
  14126.          ;                                                            ;
  14127.          ;************************************************************;
  14128.  
  14129.  cProc   cur_drive,PUBLIC
  14130.  cBegin
  14131.          mov     ah,19h          ; Set function code.
  14132.          int     21h             ; Get number of logged disk.
  14133.          add     al,'A'          ; Convert number to letter.
  14134.          cbw                     ; Clear the high byte of return value.
  14135.  cEnd
  14136.  
  14137.  \SAMPCODE\DOS_ENCY\SECTION5\FXN1AH.ASM
  14138.  
  14139.          ;************************************************************;
  14140.          ;                                                            ;
  14141.          ;                Function 1AH: Set DTA Address               ;
  14142.          ;                                                            ;
  14143.          ;                int set_DTA(pDTAbuffer)                     ;
  14144.          ;                    char far *pDTAbuffer;                   ;
  14145.          ;                                                            ;
  14146.          ;                Returns 0.                                  ;
  14147.          ;                                                            ;
  14148.          ;************************************************************;
  14149.  
  14150.  cProc   set_DTA,PUBLIC,ds
  14151.  parmD   pDTAbuffer
  14152.  cBegin
  14153.          lds     dx,pDTAbuffer   ; DS:DX = pointer to buffer.
  14154.          mov     ah,1ah          ; Set function code.
  14155.          int     21h             ; Ask MS-DOS to change DTA address.
  14156.          xor     ax,ax           ; Return 0.
  14157.  cEnd
  14158.  
  14159.  \SAMPCODE\DOS_ENCY\SECTION5\FXN1CH.ASM
  14160.  
  14161.          ;************************************************************;
  14162.          ;                                                            ;
  14163.          ;      Function 1CH: Get Drive Data                          ;
  14164.          ;                                                            ;
  14165.          ;      Get information about the disk in the specified       ;
  14166.          ;      drive.  Set drive_ltr to 0 for default drive info.    ;
  14167.          ;                                                            ;
  14168.          ;      int get_drive_data(drive_ltr,                         ;
  14169.          ;             pbytes_per_sector,                             ;
  14170.          ;             psectors_per_cluster,                          ;
  14171.          ;             pclusters_per_drive)                           ;
  14172.          ;           int  drive_ltr;                                  ;
  14173.          ;           int *pbytes_per_sector;                          ;
  14174.          ;           int *psectors_per_cluster;                       ;
  14175.          ;           int *pclusters_per_drive;                        ;
  14176.          ;                                                            ;
  14177.          ;      Returns -1 for invalid drive, otherwise returns       ;
  14178.          ;      the disk's type (from the 1st byte of the FAT).       ;
  14179.          ;                                                            ;
  14180.          ;************************************************************;
  14181.  
  14182.  cProc   get_drive_data,PUBLIC,<ds,si>
  14183.  parmB   drive_ltr
  14184.  parmDP  pbytes_per_sector
  14185.  parmDP  psectors_per_cluster
  14186.  parmDP  pclusters_per_drive
  14187.  cBegin
  14188.          mov     si,ds           ; Save DS in SI to use later.
  14189.          mov     dl,drive_ltr    ; Get drive letter.
  14190.          or      dl,dl           ; Leave 0 alone.
  14191.          jz      gdd
  14192.          and     dl,not 20h      ; Convert letter to uppercase.
  14193.          sub     dl,'A'-1        ; Convert to drive number: 'A' = 1,
  14194.                                  ; 'B' = 2, etc.
  14195.  gdd:
  14196.          mov     ah,1ch          ; Set function code.
  14197.          int     21h             ; Ask MS-DOS for data.
  14198.          cbw                     ; Extend AL into AH.
  14199.          cmp     al,0ffh         ; Bad drive letter?
  14200.          je      gddx            ; If so, exit with error code -1.
  14201.          mov     bl,[bx]         ; Get FAT ID byte from DS:BX.
  14202.          mov     ds,si           ; Get back original DS.
  14203.          loadDP  ds,si,pbytes_per_sector
  14204.          mov     [si],cx         ; Return bytes per sector.
  14205.          loadDP  ds,si,psectors_per_cluster
  14206.          mov     ah,0
  14207.          mov     [si],ax         ; Return sectors per cluster.
  14208.          loadDP  ds,si,pclusters_per_drive
  14209.          mov     [si],dx         ; Return clusters per drive.
  14210.          mov     al,bl           ; Return FAT ID byte.
  14211.  gddx:
  14212.  cEnd
  14213.  
  14214.  \SAMPCODE\DOS_ENCY\SECTION5\FXN21H.ASM
  14215.  
  14216.          ;************************************************************;
  14217.          ;                                                            ;
  14218.          ;          Function 21H: Random File Read, FCB-based         ;
  14219.          ;                                                            ;
  14220.          ;          int FCB_rread(oXFCB,recnum)                       ;
  14221.          ;              char *oXFCB;                                  ;
  14222.          ;              long recnum;                                  ;
  14223.          ;                                                            ;
  14224.          ;          Returns 0 if record read OK, otherwise            ;
  14225.          ;          returns error code 1, 2, or 3.                    ;
  14226.          ;                                                            ;
  14227.          ;************************************************************;
  14228.  
  14229.  cProc   FCB_rread,PUBLIC,ds
  14230.  parmDP  poXFCB
  14231.  parmD   recnum
  14232.  cBegin
  14233.          loadDP  ds,dx,poXFCB    ; Pointer to opened extended FCB.
  14234.          mov     bx,dx           ; BX points at FCB, too.
  14235.          mov     ax,word ptr (recnum)    ; Get low 16 bits of record
  14236.          mov     [bx+28h],ax             ; number and store in FCB.
  14237.          mov     ax,word ptr (recnum+2)  ; Get high 16 bits of record
  14238.          mov     [bx+2ah],ax             ; number and store in FCB.
  14239.          mov     ah,21h          ; Ask MS-DOS to read recnum'th
  14240.                                  ; record, placing it at DTA.
  14241.          int     21h
  14242.          cbw                     ; Clear high byte of return value.
  14243.  cEnd
  14244.  
  14245.  \SAMPCODE\DOS_ENCY\SECTION5\FXN22H.ASM
  14246.  
  14247.          ;************************************************************;
  14248.          ;                                                            ;
  14249.          ;          Function 22H: Random File Write, FCB-based        ;
  14250.          ;                                                            ;
  14251.          ;          int FCB_rwrite(oXFCB,recnum)                      ;
  14252.          ;              char *oXFCB;                                  ;
  14253.          ;              long recnum;                                  ;
  14254.          ;                                                            ;
  14255.          ;          Returns 0 if record read OK, otherwise            ;
  14256.          ;          returns error code 1 or 2.                        ;
  14257.          ;                                                            ;
  14258.          ;************************************************************;
  14259.  
  14260.  cProc   FCB_rwrite,PUBLIC,ds
  14261.  parmDP  poXFCB
  14262.  parmD   recnum
  14263.  cBegin
  14264.          loadDP  ds,dx,poXFCB    ; Pointer to opened extended FCB.
  14265.          mov     bx,dx           ; BX points at FCB, too.
  14266.          mov     ax,word ptr (recnum)    ; Get low 16 bits of record
  14267.          mov     [bx+28h],ax             ; number and store in FCB.
  14268.          mov     ax,word ptr (recnum+2)  ; Get high 16 bits of record
  14269.          mov     [bx+2ah],ax             ; number and store in FCB.
  14270.          mov     ah,22h          ; Ask MS-DOS to write DTA to
  14271.          int     21h             ; recnum'th record of file.
  14272.          cbw                     ; Clear high byte for return value.
  14273.  cEnd
  14274.  
  14275.  \SAMPCODE\DOS_ENCY\SECTION5\FXN23H.ASM
  14276.  
  14277.          ;************************************************************;
  14278.          ;                                                            ;
  14279.          ;      Function 23H: Get File Size, FCB-based                ;
  14280.          ;                                                            ;
  14281.          ;      long FCB_nrecs(uXFCB,recsize)                         ;
  14282.          ;           char *uXFCB;                                     ;
  14283.          ;           int recsize;                                     ;
  14284.          ;                                                            ;
  14285.          ;      Returns a long -1 if file not found, otherwise        ;
  14286.          ;      returns the number of records of size recsize.        ;
  14287.          ;                                                            ;
  14288.          ;      Note: uXFCB must have the drive and                   ;
  14289.          ;      filename fields (bytes 07H through 12H) and           ;
  14290.          ;      the extension flag (byte 00H) set before              ;
  14291.          ;      the call to FCB_nrecs (see Function 29H).             ;
  14292.          ;                                                            ;
  14293.          ;************************************************************;
  14294.  
  14295.  cProc   FCB_nrecs,PUBLIC,ds
  14296.  parmDP  puXFCB
  14297.  parmW   recsize
  14298.  cBegin
  14299.          loadDP  ds,dx,puXFCB    ; Pointer to unopened extended FCB.
  14300.          mov     bx,dx           ; Copy FCB pointer into BX.
  14301.          mov     ax,recsize      ; Get record size
  14302.          mov     [bx+15h],ax     ; and store it in FCB.
  14303.          mov     ah,23h          ; Ask MS-DOS for file size (in
  14304.                                  ; records).
  14305.          int     21h
  14306.          cbw                     ; If AL = 0FFH, set AX to -1.
  14307.          cwd                     ; Extend to long.
  14308.          or      dx,dx           ; Is DX negative?
  14309.          js      nr_exit         ; If so, exit with error flag.
  14310.          mov     [bx+2bh],al     ; Only low 24 bits of the relative-
  14311.                                  ; record field are used, so clear the
  14312.                                  ; top 8 bits.
  14313.          mov     ax,[bx+28h]     ; Return file length in DX:AX.
  14314.          mov     dx,[bx+2ah]
  14315.  nr_exit:
  14316.  cEnd
  14317.  
  14318.  \SAMPCODE\DOS_ENCY\SECTION5\FXN24H.ASM
  14319.  
  14320.          ;************************************************************;
  14321.          ;                                                            ;
  14322.          ;              Function 24H: Set Relative Record             ;
  14323.          ;                                                            ;
  14324.          ;              int FCB_set_rrec(oXFCB)                       ;
  14325.          ;                  char *oXFCB;                              ;
  14326.          ;                                                            ;
  14327.          ;              Returns 0.                                    ;
  14328.          ;                                                            ;
  14329.          ;************************************************************;
  14330.  
  14331.  cProc   FCB_set_rrec,PUBLIC,ds
  14332.  parmDP  poXFCB
  14333.  cBegin
  14334.          loadDP  ds,dx,poXFCB    ; Pointer to opened extended FCB.
  14335.          mov     bx,dx           ; BX points at FCB, too.
  14336.          mov     byte ptr [bx+2bh],0 ; Zero high byte of high word of
  14337.                                      ; relative-record field.
  14338.          mov     ah,24h          ; Ask MS-DOS to set relative record
  14339.                                  ; to current record.
  14340.          int     21h
  14341.          xor     ax,ax           ; Return 0.
  14342.  cEnd
  14343.  
  14344.  \SAMPCODE\DOS_ENCY\SECTION5\FXN25H.ASM
  14345.  
  14346.          ;************************************************************;
  14347.          ;                                                            ;
  14348.          ;              Function 25H: Set Interrupt Vector            ;
  14349.          ;                                                            ;
  14350.          ;              typedef void (far *FCP)();                    ;
  14351.          ;              int set_vector(intnum,vector)                 ;
  14352.          ;                  int intnum;                               ;
  14353.          ;                  FCP vector;                               ;
  14354.          ;                                                            ;
  14355.          ;              Returns 0.                                    ;
  14356.          ;                                                            ;
  14357.          ;************************************************************;
  14358.  
  14359.  cProc   set_vector,PUBLIC,ds
  14360.  parmB   intnum
  14361.  parmD   vector
  14362.  cBegin
  14363.          lds     dx,vector       ; Get vector segment:offset into
  14364.                                  ; DS:DX.
  14365.          mov     al,intnum       ; Get interrupt number into AL.
  14366.          mov     ah,25h          ; Select "set vector" function.
  14367.          int     21h             ; Ask MS-DOS to change vector.
  14368.          xor     ax,ax           ; Return 0.
  14369.  cEnd
  14370.  
  14371.  \SAMPCODE\DOS_ENCY\SECTION5\FXN26H.ASM
  14372.  
  14373.          ;************************************************************;
  14374.          ;                                                            ;
  14375.          ;       Function 26H: Create New Program Segment Prefix      ;
  14376.          ;                                                            ;
  14377.          ;       int create_psp(pspseg)                               ;
  14378.          ;           int  pspseg;                                     ;
  14379.          ;                                                            ;
  14380.          ;       Returns 0.                                           ;
  14381.          ;                                                            ;
  14382.          ;************************************************************;
  14383.  
  14384.  cProc   create_psp,PUBLIC
  14385.  parmW   pspseg
  14386.  cBegin
  14387.          mov     dx,pspseg       ; Get segment address of new PSP.
  14388.          mov     ah,26h          ; Set function code.
  14389.          int     21h             ; Ask MS-DOS to create new PSP.
  14390.          xor     ax,ax           ; Return 0.
  14391.  cEnd
  14392.  
  14393.  \SAMPCODE\DOS_ENCY\SECTION5\FXN27H.ASM
  14394.  
  14395.          ;************************************************************;
  14396.          ;                                                            ;
  14397.          ;      Function 27H: Random File Block Read, FCB-based       ;
  14398.          ;                                                            ;
  14399.          ;      int FCB_rblock(oXFCB,nrequest,nactual,start)          ;
  14400.          ;          char *oXFCB;                                      ;
  14401.          ;          int   nrequest;                                   ;
  14402.          ;          int  *nactual;                                    ;
  14403.          ;          long  start;                                      ;
  14404.          ;                                                            ;
  14405.          ;      Returns read status 0, 1, 2, or 3 and sets            ;
  14406.          ;      nactual to number of records actually read.           ;
  14407.          ;                                                            ;
  14408.          ;      If start is -1, the relative-record field is          ;
  14409.          ;      not changed, causing the block to be read starting    ;
  14410.          ;      at the current record.                                ;
  14411.          ;                                                            ;
  14412.          ;************************************************************;
  14413.  
  14414.  cProc   FCB_rblock,PUBLIC,<ds,di>
  14415.  parmDP  poXFCB
  14416.  parmW   nrequest
  14417.  parmDP  pnactual
  14418.  parmD   start
  14419.  cBegin
  14420.          loadDP  ds,dx,poXFCB    ; Pointer to opened extended FCB.
  14421.          mov     di,dx           ; DI points at FCB, too.
  14422.          mov     ax,word ptr (start) ; Get long value of start.
  14423.          mov     bx,word ptr (start+2)
  14424.          mov     cx,ax           ; Is start = -1?
  14425.          and     cx,bx
  14426.          inc     cx
  14427.          jcxz    rb_skip         ; If so, don't change relative-record
  14428.                                  ; field.
  14429.          mov     [di+28h],ax     ; Otherwise, seek to start record.
  14430.          mov     [di+2ah],bx
  14431.  rb_skip:
  14432.          mov     cx,nrequest     ; CX = number of records to read.
  14433.          mov     ah,27h          ; Get MS-DOS to read CX records,
  14434.          int     21h             ; placing them at DTA.
  14435.          loadDP  ds,bx,pnactual  ; DS:BX = address of nactual.
  14436.          mov     [bx],cx         ; Return number of records read.
  14437.          cbw                     ; Clear high byte.
  14438.  cEnd
  14439.  
  14440.  \SAMPCODE\DOS_ENCY\SECTION5\FXN28H.ASM
  14441.  
  14442.          ;************************************************************;
  14443.          ;                                                            ;
  14444.          ;       Function 28H: Random File Block Write, FCB-based     ;
  14445.          ;                                                            ;
  14446.          ;       int FCB_wblock(oXFCB,nrequest,nactual,start)         ;
  14447.          ;           char *oXFCB;                                     ;
  14448.          ;           int   nrequest;                                  ;
  14449.          ;           int  *nactual;                                   ;
  14450.          ;           long  start;                                     ;
  14451.          ;                                                            ;
  14452.          ;       Returns write status of 0, 1, or 2 and sets          ;
  14453.          ;       nactual to number of records actually written.       ;
  14454.          ;                                                            ;
  14455.          ;       If start is -1, the relative-record field is         ;
  14456.          ;       not changed, causing the block to be written         ;
  14457.          ;       starting at the current record.                      ;
  14458.          ;                                                            ;
  14459.          ;************************************************************;
  14460.  
  14461.  cProc   FCB_wblock,PUBLIC,<ds,di>
  14462.  parmDP  poXFCB
  14463.  parmW   nrequest
  14464.  parmDP  pnactual
  14465.  parmD   start
  14466.  cBegin
  14467.          loadDP  ds,dx,poXFCB    ; Pointer to opened extended FCB.
  14468.          mov     di,dx           ; DI points at FCB, too.
  14469.          mov     ax,word ptr (start) ; Get long value of start.
  14470.          mov     bx,word ptr (start+2)
  14471.          mov     cx,ax           ; Is start = -1?
  14472.          and     cx,bx
  14473.          inc     cx
  14474.          jcxz    wb_skip         ; If so, don't change relative-record
  14475.                                  ; field.
  14476.          mov     [di+28h],ax     ; Otherwise, seek to start record.
  14477.          mov     [di+2ah],bx
  14478.  wb_skip:
  14479.          mov     cx,nrequest     ; CX = number of records to write.
  14480.          mov     ah,28h          ; Get MS-DOS to write CX records
  14481.          int     21h             ; from DTA to file.
  14482.          loadDP  ds,bx,pnactual  ; DS:BX = address of nactual.
  14483.          mov     ds:[bx],cx      ; Return number of records written.
  14484.          cbw                     ; Clear high byte.
  14485.  cEnd
  14486.  
  14487.  \SAMPCODE\DOS_ENCY\SECTION5\FXN29H.ASM
  14488.  
  14489.          ;************************************************************;
  14490.          ;                                                            ;
  14491.          ;            Function 29H: Parse Filename into FCB           ;
  14492.          ;                                                            ;
  14493.          ;            int FCB_parse(uXFCB,name,ctrl)                  ;
  14494.          ;                char *uXFCB;                                ;
  14495.          ;                char *name;                                 ;
  14496.          ;                int ctrl;                                   ;
  14497.          ;                                                            ;
  14498.          ;            Returns -1 if error,                            ;
  14499.          ;                     0 if no wildcards found,               ;
  14500.          ;                     1 if wildcards found.                  ;
  14501.          ;                                                            ;
  14502.          ;************************************************************;
  14503.  
  14504.  cProc   FCB_parse,PUBLIC,<ds,si,di>
  14505.  parmDP  puXFCB
  14506.  parmDP  pname
  14507.  parmB   ctrl
  14508.  cBegin
  14509.          loadDP  es,di,puXFCB    ; Pointer to unopened extended FCB.
  14510.          push    di              ; Save DI.
  14511.          xor     ax,ax           ; Fill all 22 (decimal) words of the
  14512.                                  ; extended FCB with zeros.
  14513.          cld                     ; Make sure direction flag says UP.
  14514.          mov     cx,22d
  14515.          rep     stosw
  14516.          pop     di              ; Recover DI.
  14517.          mov     byte ptr [di],0ffh ; Set flag byte to mark this as an
  14518.                                     ; extended FCB.
  14519.          add     di,7            ; Advance pointer to start of regular
  14520.                                  ; FCB.
  14521.          loadDP  ds,si,pname     ; Get pointer to filename into DS:SI.
  14522.          mov     al,ctrl         ; Get parse control byte.
  14523.          mov     ah,29h          ; Parse filename, please.
  14524.          int     21h
  14525.          cbw                     ; Set return parameter.
  14526.  cEnd
  14527.  
  14528.  \SAMPCODE\DOS_ENCY\SECTION5\FXN2AH.ASM
  14529.  
  14530.          ;************************************************************;
  14531.          ;                                                            ;
  14532.          ;            Function 2AH: Get Date                          ;
  14533.          ;                                                            ;
  14534.          ;            long get_date(pdow,pmonth,pday,pyear)           ;
  14535.          ;                 char *pdow,*pmonth,*pday;                  ;
  14536.          ;                 int *pyear;                                ;
  14537.          ;                                                            ;
  14538.          ;            Returns the date packed into a long:            ;
  14539.          ;                 low byte  = day of month                   ;
  14540.          ;                 next byte = month                          ;
  14541.          ;                 next word = year.                          ;
  14542.          ;                                                            ;
  14543.          ;************************************************************;
  14544.  
  14545.  cProc   get_date,PUBLIC,ds
  14546.  parmDP  pdow
  14547.  parmDP  pmonth
  14548.  parmDP  pday
  14549.  parmDP  pyear
  14550.  cBegin
  14551.          mov     ah,2ah          ; Set function code.
  14552.          int     21h             ; Get date info from MS-DOS.
  14553.          loadDP  ds,bx,pdow      ; DS:BX = pointer to dow.
  14554.          mov     [bx],al         ; Return dow.
  14555.          loadDP  ds,bx,pmonth    ; DS:BX = pointer to month.
  14556.          mov     [bx],dh         ; Return month.
  14557.          loadDP  ds,bx,pday      ; DS:BX = pointer to day.
  14558.          mov     [bx],dl         ; Return day.
  14559.          loadDP  ds,bx,pyear     ; DS:BX = pointer to year.
  14560.          mov     [bx],cx         ; Return year.
  14561.          mov     ax,dx           ; Pack day, month, ...
  14562.          mov     dx,cx           ; ... and year into return value.
  14563.  cEnd
  14564.  
  14565.  \SAMPCODE\DOS_ENCY\SECTION5\FXN2BH.ASM
  14566.  
  14567.          ;************************************************************;
  14568.          ;                                                            ;
  14569.          ;             Function 2BH: Set Date                         ;
  14570.          ;                                                            ;
  14571.          ;             int set_date(month,day,year)                   ;
  14572.          ;                 char month,day;                            ;
  14573.          ;                 int year;                                  ;
  14574.          ;                                                            ;
  14575.          ;             Returns 0 if date was OK, -1 if not.           ;
  14576.          ;                                                            ;
  14577.          ;************************************************************;
  14578.  
  14579.  cProc   set_date,PUBLIC
  14580.  parmB   month
  14581.  parmB   day
  14582.  parmW   year
  14583.  cBegin
  14584.          mov     dh,month        ; Get new month.
  14585.          mov     dl,day          ; Get new day.
  14586.          mov     cx,year         ; Get new year.
  14587.          mov     ah,2bh          ; Set function code.
  14588.          int     21h             ; Ask MS-DOS to change date.
  14589.          cbw                     ; Return 0 or -1.
  14590.  cEnd
  14591.  
  14592.  \SAMPCODE\DOS_ENCY\SECTION5\FXN2CH.ASM
  14593.  
  14594.          ;************************************************************;
  14595.          ;                                                            ;
  14596.          ;             Function 2CH: Get Time                         ;
  14597.          ;                                                            ;
  14598.          ;             long get_time(phour,pmin,psec,phund)           ;
  14599.          ;                  char *phour,*pmin,*psec,*phund;           ;
  14600.          ;                                                            ;
  14601.          ;             Returns the time packed into a long:           ;
  14602.          ;                  low byte  = hundredths                    ;
  14603.          ;                  next byte = seconds                       ;
  14604.          ;                  next byte = minutes                       ;
  14605.          ;                  next byte = hours                         ;
  14606.          ;                                                            ;
  14607.          ;************************************************************;
  14608.  
  14609.  cProc   get_time,PUBLIC,ds
  14610.  parmDP  phour
  14611.  parmDP  pmin
  14612.  parmDP  psec
  14613.  parmDP  phund
  14614.  cBegin
  14615.          mov     ah,2ch          ; Set function code.
  14616.          int     21h             ; Get time from MS-DOS.
  14617.          loadDP  ds,bx,phour     ; DS:BX = pointer to hour.
  14618.          mov     [bx],ch         ; Return hour.
  14619.          loadDP  ds,bx,pmin      ; DS:BX = pointer to min.
  14620.          mov     [bx],cl         ; Return min.
  14621.          loadDP  ds,bx,psec      ; DS:BX = pointer to sec.
  14622.          mov     [bx],dh         ; Return sec.
  14623.          loadDP  ds,bx,phund     ; DS:BX = pointer to hund.
  14624.          mov     [bx],dl         ; Return hund.
  14625.          mov     ax,dx           ; Pack seconds, hundredths, ...
  14626.          mov     dx,cx           ; ... minutes, and hour into
  14627.                                  ; return value.
  14628.  cEnd
  14629.  
  14630.  \SAMPCODE\DOS_ENCY\SECTION5\FXN2DH.ASM
  14631.  
  14632.          ;************************************************************;
  14633.          ;                                                            ;
  14634.          ;             Function 2DH: Set Time                         ;
  14635.          ;                                                            ;
  14636.          ;             int set_time(hour,min,sec,hund)                ;
  14637.          ;                 char hour,min,sec,hund;                    ;
  14638.          ;                                                            ;
  14639.          ;             Returns 0 if time was OK, -1 if not.           ;
  14640.          ;                                                            ;
  14641.          ;************************************************************;
  14642.  
  14643.  cProc   set_time,PUBLIC
  14644.  parmB   hour
  14645.  parmB   min
  14646.  parmB   sec
  14647.  parmB   hund
  14648.  cBegin
  14649.          mov     ch,hour         ; Get new hour.
  14650.          mov     cl,min          ; Get new minutes.
  14651.          mov     dh,sec          ; Get new seconds.
  14652.          mov     dl,hund         ; Get new hundredths.
  14653.          mov     ah,2dh          ; Set function code.
  14654.          int     21h             ; Ask MS-DOS to change time.
  14655.          cbw                     ; Return 0 or -1.
  14656.  cEnd
  14657.  
  14658.  \SAMPCODE\DOS_ENCY\SECTION5\FXN2EH.ASM
  14659.  
  14660.          ;************************************************************;
  14661.          ;                                                            ;
  14662.          ;             Function 2EH: Set/Reset Verify Flag            ;
  14663.          ;                                                            ;
  14664.          ;             int set_verify(newvflag)                       ;
  14665.          ;                 char newvflag;                             ;
  14666.          ;                                                            ;
  14667.          ;             Returns 0.                                     ;
  14668.          ;                                                            ;
  14669.          ;************************************************************;
  14670.  
  14671.  cProc   set_verify,PUBLIC
  14672.  parmB   newvflag
  14673.  cBegin
  14674.          mov     al,newvflag     ; Get new value of verify flag.
  14675.          mov     ah,2eh          ; Set function code.
  14676.          int     21h             ; Ask MS-DOS to store flag.
  14677.          xor     ax,ax           ; Return 0.
  14678.  cEnd
  14679.  
  14680.  \SAMPCODE\DOS_ENCY\SECTION5\FXN2FH.ASM
  14681.  
  14682.          ;************************************************************;
  14683.          ;                                                            ;
  14684.          ;           Function 2FH: Get DTA Address                    ;
  14685.          ;                                                            ;
  14686.          ;           char far *get_DTA()                              ;
  14687.          ;                                                            ;
  14688.          ;           Returns a far pointer to the DTA buffer.         ;
  14689.          ;                                                            ;
  14690.          ;************************************************************;
  14691.  
  14692.  cProc   get_DTA,PUBLIC
  14693.  cBegin
  14694.          mov     ah,2fh          ; Set function code.
  14695.          int     21h             ; Ask MS-DOS for current DTA address.
  14696.          mov     ax,bx           ; Return offset in AX.
  14697.          mov     dx,es           ; Return segment in DX.
  14698.  cEnd
  14699.  
  14700.  \SAMPCODE\DOS_ENCY\SECTION5\FXN30H.ASM
  14701.  
  14702.          ;************************************************************;
  14703.          ;                                                            ;
  14704.          ;           Function 30H: Get MS-DOS Version Number          ;
  14705.          ;                                                            ;
  14706.          ;           int DOS_version()                                ;
  14707.          ;                                                            ;
  14708.          ;           Returns number of MS-DOS version, with           ;
  14709.          ;              major version in high byte,                   ;
  14710.          ;              minor version in low byte.                    ;
  14711.          ;                                                            ;
  14712.          ;************************************************************;
  14713.  
  14714.  cProc   DOS_version,PUBLIC
  14715.  cBegin
  14716.          mov     ax,3000H        ; Set function code and clear AL.
  14717.          int     21h             ; Ask MS-DOS for version number.
  14718.          xchg    al,ah           ; Swap major and minor numbers.
  14719.  cEnd
  14720.  
  14721.  \SAMPCODE\DOS_ENCY\SECTION5\FXN31H.ASM
  14722.  
  14723.          ;************************************************************;
  14724.          ;                                                            ;
  14725.          ;          Function 31H: Terminate and Stay Resident         ;
  14726.          ;                                                            ;
  14727.          ;          void keep_process(exit_code,nparas)               ;
  14728.          ;               int exit_code,nparas;                        ;
  14729.          ;                                                            ;
  14730.          ;          Does NOT return!                                  ;
  14731.          ;                                                            ;
  14732.          ;************************************************************;
  14733.  
  14734.  cProc   keep_process,PUBLIC
  14735.  parmB   exit_code
  14736.  parmW   nparas
  14737.  cBegin
  14738.          mov     al,exit_code    ; Get return code.
  14739.          mov     dx,nparas       ; Set DX to number of paragraphs the
  14740.                                  ; program wants to keep.
  14741.          mov     ah,31h          ; Set function code.
  14742.          int     21h             ; Ask MS-DOS to keep process.
  14743.  cEnd
  14744.  
  14745.  \SAMPCODE\DOS_ENCY\SECTION5\FXN33H.ASM
  14746.  
  14747.          ;************************************************************;
  14748.          ;                                                            ;
  14749.          ;          Function 33H: Get/Set Control-C Check Flag        ;
  14750.          ;                                                            ;
  14751.          ;          int controlC(func,state)                          ;
  14752.          ;              int func,state;                               ;
  14753.          ;                                                            ;
  14754.          ;          Returns current state of Ctrl-C flag.             ;
  14755.          ;                                                            ;
  14756.          ;************************************************************;
  14757.  
  14758.  cProc   controlC,PUBLIC
  14759.  parmB   func
  14760.  parmB   state
  14761.  cBegin
  14762.          mov     al,func         ; Get set/reset function.
  14763.          mov     dl,state        ; Get new value if present.
  14764.          mov     ah,33h          ; MS-DOS ^C check function.
  14765.          int     21h             ; Call MS-DOS.
  14766.          mov     al,dl           ; Return current state.
  14767.          cbw                     ; Clear high byte of return value.
  14768.  cEnd
  14769.  
  14770.  \SAMPCODE\DOS_ENCY\SECTION5\FXN34H.ASM
  14771.  
  14772.          ;************************************************************;
  14773.          ;                                                            ;
  14774.          ;       Function 34H: Get Return Address of InDOS Flag       ;
  14775.          ;                                                            ;
  14776.          ;       char far *inDOS_ptr()                                ;
  14777.          ;                                                            ;
  14778.          ;       Returns a far pointer to the MS-DOS inDOS flag.      ;
  14779.          ;                                                            ;
  14780.          ;************************************************************;
  14781.  
  14782.  cProc   inDOS_ptr,PUBLIC
  14783.  cBegin
  14784.          mov     ah,34h          ; InDOS flag function.
  14785.          int     21h             ; Call MS-DOS.
  14786.          mov     ax,bx           ; Return offset in AX.
  14787.          mov     dx,es           ; Return segment in DX.
  14788.  cEnd
  14789.  
  14790.  \SAMPCODE\DOS_ENCY\SECTION5\FXN35H.ASM
  14791.  
  14792.          ;************************************************************;
  14793.          ;                                                            ;
  14794.          ;           Function 35H: Get Interrupt Vector               ;
  14795.          ;                                                            ;
  14796.          ;           typedef void (far *FCP)();                       ;
  14797.          ;           FCP get_vector(intnum)                           ;
  14798.          ;               int intnum;                                  ;
  14799.          ;                                                            ;
  14800.          ;           Returns a far code pointer that is the           ;
  14801.          ;           segment:offset of the interrupt vector.          ;
  14802.          ;                                                            ;
  14803.          ;************************************************************;
  14804.  
  14805.  cProc   get_vector,PUBLIC
  14806.  parmB   intnum
  14807.  cBegin
  14808.          mov     al,intnum       ; Get interrupt number into AL.
  14809.          mov     ah,35h          ; Select "get vector" function.
  14810.          int     21h             ; Call MS-DOS.
  14811.          mov     ax,bx           ; Return vector offset.
  14812.          mov     dx,es           ; Return vector segment.
  14813.  cEnd
  14814.  
  14815.  \SAMPCODE\DOS_ENCY\SECTION5\FXN36H.ASM
  14816.  
  14817.          ;************************************************************;
  14818.          ;                                                            ;
  14819.          ;             Function 36H: Get Disk Free Space              ;
  14820.          ;                                                            ;
  14821.          ;             long free_space(drive_ltr)                     ;
  14822.          ;                 char drive_ltr;                            ;
  14823.          ;                                                            ;
  14824.          ;             Returns the number of bytes free as            ;
  14825.          ;             a long integer.                                ;
  14826.          ;                                                            ;
  14827.          ;************************************************************;
  14828.  
  14829.  cProc   free_space,PUBLIC
  14830.  parmB   drive_ltr
  14831.  cBegin
  14832.          mov     dl,drive_ltr    ; Get drive letter.
  14833.          or      dl,dl           ; Leave 0 alone.
  14834.          jz      fsp
  14835.          and     dl,not 20h      ; Convert letter to uppercase.
  14836.          sub     dl,'A'-1        ; Convert to drive number: 'A' = 1,
  14837.                                  ; 'B' = 2, etc.
  14838.  fsp:
  14839.          mov     ah,36h          ; Set function code.
  14840.          int     21h             ; Ask MS-DOS to get disk information.
  14841.          mul     cx              ; Bytes/sector * sectors/cluster
  14842.          mul     bx              ; * free clusters.
  14843.  cEnd
  14844.  
  14845.  \SAMPCODE\DOS_ENCY\SECTION5\FXN38H.ASM
  14846.  
  14847.          ;************************************************************;
  14848.          ;                                                            ;
  14849.          ;         Function 38H: Get/Set Current Country Data         ;
  14850.          ;                                                            ;
  14851.          ;         int country_info(country,pbuffer)                  ;
  14852.          ;             char country,*pbuffer;                         ;
  14853.          ;                                                            ;
  14854.          ;         Returns -1 if the "country" code is invalid.       ;
  14855.          ;                                                            ;
  14856.          ;************************************************************;
  14857.  
  14858.  cProc   country_info,PUBLIC,ds
  14859.  parmB   country
  14860.  parmDP  pbuffer
  14861.  cBegin
  14862.          mov     al,country      ; Get country code.
  14863.          loadDP  ds,dx,pbuffer   ; Get buffer pointer (or -1).
  14864.          mov     ah,38h          ; Set function code.
  14865.          int     21h             ; Ask MS-DOS to get country
  14866.                                  ; information.
  14867.          jnb     cc_ok           ; Branch if country code OK.
  14868.          mov     ax,-1           ; Else return -1.
  14869.  cc_ok:
  14870.  cEnd
  14871.  
  14872.  \SAMPCODE\DOS_ENCY\SECTION5\FXN39H.ASM
  14873.  
  14874.          ;************************************************************;
  14875.          ;                                                            ;
  14876.          ;              Function 39H: Create Directory                ;
  14877.          ;                                                            ;
  14878.          ;              int make_dir(pdirpath)                        ;
  14879.          ;                  char *pdirpath;                           ;
  14880.          ;                                                            ;
  14881.          ;              Returns 0 if directory created OK,            ;
  14882.          ;              otherwise returns error code.                 ;
  14883.          ;                                                            ;
  14884.          ;************************************************************;
  14885.  
  14886.  cProc   make_dir,PUBLIC,ds
  14887.  parmDP  pdirpath
  14888.  cBegin
  14889.          loadDP  ds,dx,pdirpath  ; Get pointer to pathname.
  14890.          mov     ah,39h          ; Set function code.
  14891.          int     21h             ; Ask MS-DOS to make new subdirectory.
  14892.          jb      md_err          ; Branch on error.
  14893.          xor     ax,ax           ; Else return 0.
  14894.  md_err:
  14895.  cEnd
  14896.  
  14897.  \SAMPCODE\DOS_ENCY\SECTION5\FXN40H.ASM
  14898.  
  14899.          ;************************************************************;
  14900.          ;                                                            ;
  14901.          ;          Function 40H: Write File or Device                ;
  14902.          ;                                                            ;
  14903.          ;          int write(handle,pbuffer,nbytes)                  ;
  14904.          ;              int handle,nbytes;                            ;
  14905.          ;              char *pbuffer;                                ;
  14906.          ;                                                            ;
  14907.          ;          Returns -1 if there was a write error,            ;
  14908.          ;          otherwise returns number of bytes written.        ;
  14909.          ;                                                            ;
  14910.          ;************************************************************;
  14911.  
  14912.  cProc   write,PUBLIC,ds
  14913.  parmW   handle
  14914.  parmDP  pbuffer
  14915.  parmW   nbytes
  14916.  cBegin
  14917.          mov     bx,handle       ; Get handle.
  14918.          loadDP  ds,dx,pbuffer   ; Get pointer to buffer.
  14919.          mov     cx,nbytes       ; Get number of bytes to write.
  14920.          mov     ah,40h          ; Set function code.
  14921.          int     21h             ; Ask MS-DOS to write CX bytes.
  14922.          jnb     wr_ok           ; Branch if write successful.
  14923.          mov     ax,-1           ; Else return -1.
  14924.  wr_ok:
  14925.  cEnd
  14926.  
  14927.  \SAMPCODE\DOS_ENCY\SECTION5\FXN41H.ASM
  14928.  
  14929.          ;************************************************************;
  14930.          ;                                                            ;
  14931.          ;                Function 41H: Delete File                   ;
  14932.          ;                                                            ;
  14933.          ;                int delete(pfilepath)                       ;
  14934.          ;                    char *pfilepath;                        ;
  14935.          ;                                                            ;
  14936.          ;                Returns 0 if file deleted,                  ;
  14937.          ;                otherwise returns error code.               ;
  14938.          ;                                                            ;
  14939.          ;************************************************************;
  14940.  
  14941.  cProc   delete,PUBLIC,ds
  14942.  parmDP  pfilepath
  14943.  cBegin
  14944.          loadDP  ds,dx,pfilepath ; Get pointer to pathname.
  14945.          mov     ah,41h          ; Set function code.
  14946.          int     21h             ; Ask MS-DOS to delete file.
  14947.          jb       dl_err         ; Branch if MS-DOS could not delete
  14948.                                  ; file.
  14949.          xor     ax,ax           ; Else return 0.
  14950.  dl_err:
  14951.  cEnd
  14952.  
  14953.  \SAMPCODE\DOS_ENCY\SECTION5\FXN42H.ASM
  14954.  
  14955.          ;************************************************************;
  14956.          ;                                                            ;
  14957.          ;           Function 42H: Move File Pointer                  ;
  14958.          ;                                                            ;
  14959.          ;           long seek(handle,distance,mode)                  ;
  14960.          ;                int handle,mode;                            ;
  14961.          ;                long distance;                              ;
  14962.          ;                                                            ;
  14963.          ;           Modes:                                           ;
  14964.          ;                   0: from beginning of file                ;
  14965.          ;                   1: from the current position             ;
  14966.          ;                   2: from the end of the file              ;
  14967.          ;                                                            ;
  14968.          ;           Returns -1 if there was a seek error,            ;
  14969.          ;           otherwise returns long pointer position.         ;
  14970.          ;                                                            ;
  14971.          ;************************************************************;
  14972.  
  14973.  cProc   seek,PUBLIC
  14974.  parmW   handle
  14975.  parmD   distance
  14976.  parmB   mode
  14977.  cBegin
  14978.          mov     bx,handle       ; Get handle.
  14979.          les     dx,distance     ; Get distance into ES:DX.
  14980.          mov     cx,es           ; Put high word of distance into CX.
  14981.          mov     al,mode         ; Get move method code.
  14982.          mov     ah,42h          ; Set function code.
  14983.          int     21h             ; Ask MS-DOS to move file pointer.
  14984.          jnb     sk_ok           ; Branch if seek successful.
  14985.          mov     ax,-1           ; Else return -1.
  14986.          cwd
  14987.  sk_ok:
  14988.  cEnd
  14989.  
  14990.  \SAMPCODE\DOS_ENCY\SECTION5\FXN43H.ASM
  14991.  
  14992.          ;************************************************************;
  14993.          ;                                                            ;
  14994.          ;            Function 43H: Get/Set File Attributes           ;
  14995.          ;                                                            ;
  14996.          ;            int file_attr(pfilepath,func,attr)              ;
  14997.          ;                char *pfilepath;                            ;
  14998.          ;                int func,attr;                              ;
  14999.          ;                                                            ;
  15000.          ;            Returns -1 for all errors,                      ;
  15001.          ;            otherwise returns file attribute.               ;
  15002.          ;                                                            ;
  15003.          ;************************************************************;
  15004.  
  15005.  cProc   file_attr,PUBLIC,ds
  15006.  parmDP  pfilepath
  15007.  parmB   func
  15008.  parmW   attr
  15009.  cBegin
  15010.          loadDP  ds,dx,pfilepath ; Get pointer to pathname.
  15011.          mov     al,func         ; Get/set flag into AL.
  15012.          mov     cx,attr         ; Get new attr (if present).
  15013.          mov     ah,43h          ; Set code function.
  15014.          int     21h             ; Call MS-DOS.
  15015.          jnb     fa_ok           ; Branch if no error.
  15016.          mov     cx,-1           ; Else return -1.
  15017.  fa_ok:
  15018.          mov     ax,cx           ; Return this value.
  15019.  
  15020.  cEnd
  15021.  
  15022.  \SAMPCODE\DOS_ENCY\SECTION5\FXN4400H.ASM
  15023.  
  15024.          ;************************************************************;
  15025.          ;                                                            ;
  15026.          ;        Function 44H, Subfunctions 00H,01H:                 ;
  15027.          ;                      Get/Set IOCTL Device Data             ;
  15028.          ;                                                            ;
  15029.          ;        int ioctl_char_flags(setflag,handle,newflags)       ;
  15030.          ;            int setflag;                                    ;
  15031.          ;            int handle;                                     ;
  15032.          ;            int newflags;                                   ;
  15033.          ;                                                            ;
  15034.          ;        Set setflag = 0 to get flags, 1 to set flags.       ;
  15035.          ;                                                            ;
  15036.          ;        Returns -1 for error, else returns flags.           ;
  15037.          ;                                                            ;
  15038.          ;************************************************************;
  15039.  
  15040.  cProc   ioctl_char_flags,PUBLIC
  15041.  parmB   setflag
  15042.  parmW   handle
  15043.  parmW   newflags
  15044.  cBegin
  15045.          mov     al,setflag      ; Get setflag.
  15046.          and     al,1            ; Save only lsb.
  15047.          mov     bx,handle       ; Get handle to character device.
  15048.          mov     dx,newflags     ; Get new flags (they are used only
  15049.                                  ; by "set" option).
  15050.          mov     ah,44h          ; Set function code.
  15051.          int     21h             ; Call MS-DOS.
  15052.          mov     ax,dx           ; Assume success - prepare to return
  15053.                                  ; flags.
  15054.          jnc     iocfx           ; Branch if no error.
  15055.          mov     ax,-1           ; Else return error flag.
  15056.  iocfx:
  15057.  cEnd
  15058.  
  15059.  \SAMPCODE\DOS_ENCY\SECTION5\FXN4401H.ASM
  15060.  
  15061.          ;************************************************************;
  15062.          ;                                                            ;
  15063.          ;        Function 44H, Subfunctions 00H,01H:                 ;
  15064.          ;                      Get/Set IOCTL Device Data             ;
  15065.          ;                                                            ;
  15066.          ;        int ioctl_char_flags(setflag,handle,newflags)       ;
  15067.          ;            int setflag;                                    ;
  15068.          ;            int handle;                                     ;
  15069.          ;            int newflags;                                   ;
  15070.          ;                                                            ;
  15071.          ;        Set setflag = 0 to get flags, 1 to set flags.       ;
  15072.          ;                                                            ;
  15073.          ;        Returns -1 for error, else returns flags.           ;
  15074.          ;                                                            ;
  15075.          ;************************************************************;
  15076.  
  15077.  cProc   ioctl_char_flags,PUBLIC
  15078.  parmB   setflag
  15079.  parmW   handle
  15080.  parmW   newflags
  15081.  cBegin
  15082.          mov     al,setflag      ; Get setflag.
  15083.          and     al,1            ; Save only lsb.
  15084.          mov     bx,handle       ; Get handle to character device.
  15085.          mov     dx,newflags     ; Get new flags (they are used only
  15086.                                  ; by "set" option).
  15087.          mov     ah,44h          ; Set function code.
  15088.          int     21h             ; Call MS-DOS.
  15089.          mov     ax,dx           ; Assume success - prepare to return
  15090.                                  ; flags.
  15091.          jnc     iocfx           ; Branch if no error.
  15092.          mov     ax,-1           ; Else return error flag.
  15093.  iocfx:
  15094.  cEnd
  15095.  
  15096.  \SAMPCODE\DOS_ENCY\SECTION5\FXN4402H.ASM
  15097.  
  15098.          ;************************************************************;
  15099.          ;                                                            ;
  15100.          ;     Function 44H, Subfunctions 02H,03H:                    ;
  15101.          ;                   IOCTL Character Device Control           ;
  15102.          ;                                                            ;
  15103.          ;     int ioctl_char_ctrl(recvflag,handle,pbuffer,nbytes)    ;
  15104.          ;         int   recvflag;                                    ;
  15105.          ;         int   handle;                                      ;
  15106.          ;         char *pbuffer;                                     ;
  15107.          ;         int   nbytes;                                      ;
  15108.          ;                                                            ;
  15109.          ;     Set recvflag = 0 to get flags, 1 to set flags.         ;
  15110.          ;                                                            ;
  15111.          ;     Returns -1 for error, otherwise returns number of      ;
  15112.          ;     bytes sent or received.                                ;
  15113.          ;                                                            ;
  15114.          ;************************************************************;
  15115.  
  15116.  cProc   ioctl_char_ctrl,PUBLIC,<ds>
  15117.  parmB   recvflag
  15118.  parmW   handle
  15119.  parmDP  pbuffer
  15120.  parmW   nbytes
  15121.  cBegin
  15122.          mov     al,recvflag     ; Get recvflag.
  15123.          and     al,1            ; Keep only lsb.
  15124.          add     al,2            ; AL = 02H for receive, 03H for send.
  15125.          mov     bx,handle       ; Get character-device handle.
  15126.          mov     cx,nbytes       ; Get number of bytes to receive/send.
  15127.          loadDP  ds,dx,pbuffer   ; Get pointer to buffer.
  15128.          mov     ah,44h          ; Set function code.
  15129.          int     21h             ; Call MS-DOS.
  15130.          jnc     iccx            ; Branch if no error.
  15131.          mov     ax,-1           ; Return -1 for all errors.
  15132.  iccx:
  15133.  cEnd
  15134.  
  15135.  \SAMPCODE\DOS_ENCY\SECTION5\FXN4403H.ASM
  15136.  
  15137.          ;************************************************************;
  15138.          ;                                                            ;
  15139.          ;     Function 44H, Subfunctions 02H,03H:                    ;
  15140.          ;                   IOCTL Character Device Control           ;
  15141.          ;                                                            ;
  15142.          ;     int ioctl_char_ctrl(recvflag,handle,pbuffer,nbytes)    ;
  15143.          ;         int   recvflag;                                    ;
  15144.          ;         int   handle;                                      ;
  15145.          ;         char *pbuffer;                                     ;
  15146.          ;         int   nbytes;                                      ;
  15147.          ;                                                            ;
  15148.          ;     Set recvflag = 0 to get flags, 1 to set flags.         ;
  15149.          ;                                                            ;
  15150.          ;     Returns -1 for error, otherwise returns number of      ;
  15151.          ;     bytes sent or received.                                ;
  15152.          ;                                                            ;
  15153.          ;************************************************************;
  15154.  
  15155.  cProc   ioctl_char_ctrl,PUBLIC,<ds>
  15156.  parmB   recvflag
  15157.  parmW   handle
  15158.  parmDP  pbuffer
  15159.  parmW   nbytes
  15160.  cBegin
  15161.          mov     al,recvflag     ; Get recvflag.
  15162.          and     al,1            ; Keep only lsb.
  15163.          add     al,3            ; AL = 02H for receive, 03H for send.
  15164.          mov     bx,handle       ; Get character-device handle.
  15165.          mov     cx,nbytes       ; Get number of bytes to receive/send.
  15166.          loadDP  ds,dx,pbuffer   ; Get pointer to buffer.
  15167.          mov     ah,44h          ; Set function code.
  15168.          int     21h             ; Call MS-DOS.
  15169.          jnc     iccx            ; Branch if no error.
  15170.          mov     ax,-1           ; Return -1 for all errors.
  15171.  iccx:
  15172.  cEnd
  15173.  
  15174.  \SAMPCODE\DOS_ENCY\SECTION5\FXN4404H.ASM
  15175.  
  15176.          ;************************************************************;
  15177.          ;                                                            ;
  15178.          ;   Function 44H, Subfunctions 04H,05H:                      ;
  15179.          ;                 IOCTL Block Device Control                 ;
  15180.          ;                                                            ;
  15181.          ;   int ioctl_block_ctrl(recvflag,drive_ltr,pbuffer,nbytes)  ;
  15182.          ;       int   recvflag;                                      ;
  15183.          ;       int   drive_ltr;                                     ;
  15184.          ;       char *pbuffer;                                       ;
  15185.          ;       int   nbytes;                                        ;
  15186.          ;                                                            ;
  15187.          ;   Set recvflag = 0 to receive info, 1 to send.             ;
  15188.          ;                                                            ;
  15189.          ;   Returns -1 for error, otherwise returns number of        ;
  15190.          ;   bytes sent or received.                                  ;
  15191.          ;                                                            ;
  15192.          ;************************************************************;
  15193.  
  15194.  cProc   ioctl_block_ctrl,PUBLIC,<ds>
  15195.  parmB   recvflag
  15196.  parmB   drive_ltr
  15197.  parmDP  pbuffer
  15198.  parmW   nbytes
  15199.  cBegin
  15200.          mov     al,recvflag     ; Get recvflag.
  15201.          and     al,1            ; Keep only lsb.
  15202.          add     al,4            ; AL = 04H for receive, 05H for send.
  15203.          mov     bl,drive_ltr    ; Get drive letter.
  15204.          or      bl,bl           ; Leave 0 alone.
  15205.          jz      ibc
  15206.          and     bl,not 20h      ; Convert letter to uppercase.
  15207.          sub     bl,'A'-1        ; Convert to drive number: 'A' = 1,
  15208.                                  ; 'B' = 2, etc.
  15209.  ibc:
  15210.          mov     cx,nbytes       ; Get number of bytes to recv/send.
  15211.          loadDP  ds,dx,pbuffer   ; Get pointer to buffer.
  15212.          mov     ah,44h          ; Set function code.
  15213.          int     21h             ; Call MS-DOS.
  15214.          jnc     ibcx            ; Branch if no error.
  15215.          mov     ax,-1           ; Return -1 for all errors.
  15216.  ibcx:
  15217.  cEnd
  15218.  
  15219.  \SAMPCODE\DOS_ENCY\SECTION5\FXN4405H.ASM
  15220.  
  15221.          ;************************************************************;
  15222.          ;                                                            ;
  15223.          ;   Function 44H, Subfunctions 04H,05H:                      ;
  15224.          ;                 IOCTL Block Device Control                 ;
  15225.          ;                                                            ;
  15226.          ;   int ioctl_block_ctrl(recvflag,drive_ltr,pbuffer,nbytes)  ;
  15227.          ;       int   recvflag;                                      ;
  15228.          ;       int   drive_ltr;                                     ;
  15229.          ;       char *pbuffer;                                       ;
  15230.          ;       int   nbytes;                                        ;
  15231.          ;                                                            ;
  15232.          ;   Set recvflag = 0 to receive info, 1 to send.             ;
  15233.          ;                                                            ;
  15234.          ;   Returns -1 for error, otherwise returns number of        ;
  15235.          ;   bytes sent or received.                                  ;
  15236.          ;                                                            ;
  15237.          ;************************************************************;
  15238.  
  15239.  cProc   ioctl_block_ctrl,PUBLIC,<ds>
  15240.  parmB   recvflag
  15241.  parmB   drive_ltr
  15242.  parmDP  pbuffer
  15243.  parmW   nbytes
  15244.  cBegin
  15245.          mov     al,recvflag     ; Get recvflag.
  15246.          and     al,1            ; Keep only lsb.
  15247.          add     al,5            ; AL = 04H for receive, 05H for send.
  15248.          mov     bl,drive_ltr    ; Get drive letter.
  15249.          or      bl,bl           ; Leave 0 alone.
  15250.          jz      ibc
  15251.          and     bl,not 20h      ; Convert letter to uppercase.
  15252.          sub     bl,'A'-1        ; Convert to drive number: 'A' = 1,
  15253.                                  ; 'B' = 2, etc.
  15254.  ibc:
  15255.          mov     cx,nbytes       ; Get number of bytes to recv/send.
  15256.          loadDP  ds,dx,pbuffer   ; Get pointer to buffer.
  15257.          mov     ah,44h          ; Set function code.
  15258.          int     21h             ; Call MS-DOS.
  15259.          jnc     ibcx            ; Branch if no error.
  15260.          mov     ax,-1           ; Return -1 for all errors.
  15261.  ibcx:
  15262.  cEnd
  15263.  
  15264.  \SAMPCODE\DOS_ENCY\SECTION5\FXN4406H.ASM
  15265.  
  15266.          ;************************************************************;
  15267.          ;                                                            ;
  15268.          ;   Function 44H, Subfunctions 06H,07H:                      ;
  15269.          ;                 IOCTL Input/Output Status                  ;
  15270.          ;                                                            ;
  15271.          ;   int ioctl_char_status(outputflag,handle)                 ;
  15272.          ;       int outputflag;                                      ;
  15273.          ;       int handle;                                          ;
  15274.          ;                                                            ;
  15275.          ;   Set outputflag = 0 for input status, 1 for output status.;
  15276.          ;                                                            ;
  15277.          ;   Returns -1 for all errors, 0 for not ready,              ;
  15278.          ;   and 1 for ready.                                         ;
  15279.          ;                                                            ;
  15280.          ;************************************************************;
  15281.  
  15282.  cProc   ioctl_char_status,PUBLIC
  15283.  parmB   outputflag
  15284.  parmW   handle
  15285.  cBegin
  15286.          mov     al,outputflag   ; Get outputflag.
  15287.          and     al,1            ; Keep only lsb.
  15288.          add     al,6            ; AL = 06H for input status, 07H for output
  15289.                                  ; status.
  15290.          mov     bx,handle       ; Get handle.
  15291.          mov     ah,44h          ; Set function code.
  15292.          int     21h             ; Call MS-DOS.
  15293.          jnc     isnoerr         ; Branch if no error.
  15294.          mov     ax,-1           ; Return error code.
  15295.          jmp     short isx
  15296.  isnoerr:
  15297.          and     ax,1            ; Keep only lsb for return value.
  15298.  isx:
  15299.  cEnd
  15300.  
  15301.  \SAMPCODE\DOS_ENCY\SECTION5\FXN4407H.ASM
  15302.  
  15303.          ;************************************************************;
  15304.          ;                                                            ;
  15305.          ;   Function 44H, Subfunctions 06H,07H:                      ;
  15306.          ;                 IOCTL Input/Output Status                  ;
  15307.          ;                                                            ;
  15308.          ;   int ioctl_char_status(outputflag,handle)                 ;
  15309.          ;       int outputflag;                                      ;
  15310.          ;       int handle;                                          ;
  15311.          ;                                                            ;
  15312.          ;   Set outputflag = 0 for input status, 1 for output status.;
  15313.          ;                                                            ;
  15314.          ;   Returns -1 for all errors, 0 for not ready,              ;
  15315.          ;   and 1 for ready.                                         ;
  15316.          ;                                                            ;
  15317.          ;************************************************************;
  15318.  
  15319.  cProc   ioctl_char_status,PUBLIC
  15320.  parmB   outputflag
  15321.  parmW   handle
  15322.  cBegin
  15323.          mov     al,outputflag   ; Get outputflag.
  15324.          and     al,1            ; Keep only lsb.
  15325.          add     al,7            ; AL = 06H for input status, 07H for output
  15326.                                  ; status.
  15327.          mov     bx,handle       ; Get handle.
  15328.          mov     ah,44h          ; Set function code.
  15329.          int     21h             ; Call MS-DOS.
  15330.          jnc     isnoerr         ; Branch if no error.
  15331.          mov     ax,-1           ; Return error code.
  15332.          jmp     short isx
  15333.  isnoerr:
  15334.          and     ax,1            ; Keep only lsb for return value.
  15335.  isx:
  15336.  cEnd
  15337.  
  15338.  \SAMPCODE\DOS_ENCY\SECTION5\FXN4408H.ASM
  15339.  
  15340.          ;************************************************************;
  15341.          ;                                                            ;
  15342.          ;      Function 44H, Subfunction 08H:                        ;
  15343.          ;                    IOCTL Removable Block Device Query      ;
  15344.          ;                                                            ;
  15345.          ;      int ioctl_block_fixed(drive_ltr)                      ;
  15346.          ;          int drive_ltr;                                    ;
  15347.          ;                                                            ;
  15348.          ;      Returns -1 for all errors, 1 if disk is fixed (not    ;
  15349.          ;      removable), 0 if disk is not fixed.                   ;
  15350.          ;                                                            ;
  15351.          ;************************************************************;
  15352.  
  15353.  cProc   ioctl_block_fixed,PUBLIC
  15354.  parmB   drive_ltr
  15355.  cBegin
  15356.          mov     bl,drive_ltr    ; Get drive letter.
  15357.          or      bl,bl           ; Leave 0 alone.
  15358.          jz      ibch
  15359.          and     bl,not 20h      ; Convert letter to uppercase.
  15360.          sub     bl,'A'-1        ; Convert to drive number: 'A' = 1,
  15361.                                  ; 'B' = 2, etc.
  15362.  ibch:
  15363.          mov     ax,4408h        ; Set function code, Subfunction 08H.
  15364.          int     21h             ; Call MS-DOS.
  15365.          jnc     ibchx           ; Branch if no error, AX = 0 or 1.
  15366.          cmp     ax,1            ; Treat error code of 1 as "disk is
  15367.                                  ; fixed."
  15368.          je      ibchx
  15369.          mov     ax,-1           ; Return -1 for other errors.
  15370.  ibchx:
  15371.  cEnd
  15372.  
  15373.  \SAMPCODE\DOS_ENCY\SECTION5\FXN4409H.ASM
  15374.  
  15375.          ;************************************************************;
  15376.          ;                                                            ;
  15377.          ;        Function 44H, Subfunction 09H:                      ;
  15378.          ;                      IOCTL Remote Block Device Query       ;
  15379.          ;                                                            ;
  15380.          ;        int ioctl_block_redir(drive_ltr)                    ;
  15381.          ;            int drive_ltr;                                  ;
  15382.          ;                                                            ;
  15383.          ;        Returns -1 for all errors, 1 if disk is remote      ;
  15384.          ;        (redirected), 0 if disk is local.                   ;
  15385.          ;                                                            ;
  15386.          ;************************************************************;
  15387.  
  15388.  cProc   ioctl_block_redir,PUBLIC
  15389.  parmB   drive_ltr
  15390.  cBegin
  15391.          mov     bl,drive_ltr    ; Get drive letter.
  15392.          or      bl,bl           ; Leave 0 alone.
  15393.          jz      ibr
  15394.          and     bl,not 20h      ; Convert letter to uppercase.
  15395.          sub     bl,'A'-1        ; Convert to drive number: 'A' = 1,
  15396.                                  ; 'B' = 2, etc.
  15397.  ibr:
  15398.          mov     ax,4409h        ; Set function code, Subfunction 09H.
  15399.          int     21h             ; Call MS-DOS.
  15400.          mov     ax,-1           ; Assume error.
  15401.          jc      ibrx            ; Branch if error, returning -1.
  15402.          inc     ax              ; Set AX = 0.
  15403.          test    dh,10h          ; Is bit 12 set?
  15404.          jz      ibrx            ; If not, disk is local: Return 0.
  15405.          inc     ax              ; Return 1 for remote disk.
  15406.  ibrx:
  15407.  cEnd
  15408.  
  15409.  \SAMPCODE\DOS_ENCY\SECTION5\FXN440AH.ASM
  15410.  
  15411.          ;************************************************************;
  15412.          ;                                                            ;
  15413.          ;    Function 44H, Subfunction 0AH:                          ;
  15414.          ;                  IOCTL Remote Handle Query                 ;
  15415.          ;                                                            ;
  15416.          ;    int ioctl_char_redir(handle)                            ;
  15417.          ;        int handle;                                         ;
  15418.          ;                                                            ;
  15419.          ;    Returns -1 for all errors, 1 if device/file is remote   ;
  15420.          ;    (redirected), 0 if it is local.                         ;
  15421.          ;                                                            ;
  15422.          ;************************************************************;
  15423.  
  15424.  cProc   ioctl_char_redir,PUBLIC
  15425.  parmW   handle
  15426.  cBegin
  15427.          mov     bx,handle       ; Get handle.
  15428.          mov     ax,440ah        ; Set function code, Subfunction 0AH.
  15429.          int     21h             ; Call MS-DOS.
  15430.          mov     ax,-1           ; Assume error.
  15431.          jc      icrx            ; Branch on error, returning -1.
  15432.          inc     ax              ; Set AX = 0.
  15433.          test    dh,80h          ; Is bit 15 set?
  15434.          jz      icrx            ; If not, device/file is local:
  15435.                                  ; Return 0.
  15436.          inc     ax              ; Return 1 for remote.
  15437.  icrx:
  15438.  cEnd
  15439.  
  15440.  \SAMPCODE\DOS_ENCY\SECTION5\FXN440BH.ASM
  15441.  
  15442.          ;************************************************************;
  15443.          ;                                                            ;
  15444.          ;     Function 44H, Subfunction 0BH:                         ;
  15445.          ;                   IOCTL Change Sharing Retry Count         ;
  15446.          ;                                                            ;
  15447.          ;     int ioctl_set_retry(num_retries,wait_time)             ;
  15448.          ;         int num_retries;                                   ;
  15449.          ;         int wait_time;                                     ;
  15450.          ;                                                            ;
  15451.          ;     Returns 0 for success, otherwise returns error code.   ;
  15452.          ;                                                            ;
  15453.          ;************************************************************;
  15454.  
  15455.  cProc   ioctl_set_retry,PUBLIC,<ds,si>
  15456.  parmW   num_retries
  15457.  parmW   wait_time
  15458.  cBegin
  15459.          mov     dx,num_retries  ; Get parameters.
  15460.          mov     cx,wait_time
  15461.          mov     ax,440bh        ; Set function code, Subfunction 0BH.
  15462.          int     21h             ; Call MS-DOS.
  15463.          jc      isrx            ; Branch on error.
  15464.          xor     ax,ax
  15465.  isrx:
  15466.  cEnd
  15467.  
  15468.  \SAMPCODE\DOS_ENCY\SECTION5\FXN440CH.ASM
  15469.  
  15470.          ;************************************************************;
  15471.          ;                                                            ;
  15472.          ;   Function 44H, Subfunction 0CH:                           ;
  15473.          ;                 Generic IOCTL for Handles                  ;
  15474.          ;                                                            ;
  15475.          ;   int ioctl_char_generic(handle,category,function,pbuffer) ;
  15476.          ;       int   handle;                                        ;
  15477.          ;       int   category;                                      ;
  15478.          ;       int   function;                                      ;
  15479.          ;       int  *pbuffer;                                       ;
  15480.          ;                                                            ;
  15481.          ;   Returns 0 for success, otherwise returns error code.     ;
  15482.          ;                                                            ;
  15483.          ;************************************************************;
  15484.  
  15485.  cProc   ioctl_char_generic,PUBLIC,<ds>
  15486.  parmW   handle
  15487.  parmB   category
  15488.  parmB   function
  15489.  parmDP  pbuffer
  15490.  cBegin
  15491.          mov     bx,handle       ; Get device handle.
  15492.          mov     ch,category     ; Get category
  15493.          mov     cl,function     ; and function.
  15494.          loadDP  ds,dx,pbuffer   ; Get pointer to data buffer.
  15495.          mov     ax,440ch        ; Set function code, Subfunction 0CH.
  15496.          int     21h             ; Call MS-DOS.
  15497.          jc      icgx            ; Branch on error.
  15498.          xor     ax,ax
  15499.  icgx:
  15500.  cEnd
  15501.  
  15502.  \SAMPCODE\DOS_ENCY\SECTION5\FXN440DH.ASM
  15503.  
  15504.          ;************************************************************;
  15505.          ;                                                            ;
  15506.          ;    Function 44H, Subfunction 0DH:                          ;
  15507.          ;                  Generic IOCTL for Block Devices           ;
  15508.          ;                                                            ;
  15509.          ;    int ioctl_block_generic(drv_ltr,category,func,pbuffer)  ;
  15510.          ;        int   drv_ltr;                                      ;
  15511.          ;        int   category;                                     ;
  15512.          ;        int   func;                                         ;
  15513.          ;        char *pbuffer;                                      ;
  15514.          ;                                                            ;
  15515.          ;    Returns 0 for success, otherwise returns error code.    ;
  15516.          ;                                                            ;
  15517.          ;************************************************************;
  15518.  
  15519.  cProc   ioctl_block_generic,PUBLIC,<ds>
  15520.  parmB   drv_ltr
  15521.  parmB   category
  15522.  parmB   func
  15523.  parmDP  pbuffer
  15524.  cBegin
  15525.          mov     bl,drv_ltr      ; Get drive letter.
  15526.          or      bl,bl           ; Leave 0 alone.
  15527.          jz      ibg
  15528.          and     bl,not 20h      ; Convert letter to uppercase.
  15529.          sub     bl,'A'-1        ; Convert to drive number: 'A' = 1,
  15530.                                  ; 'B' = 2, etc.
  15531.  ibg:
  15532.          mov     ch,category     ; Get category
  15533.          mov     cl,func         ; and function.
  15534.          loadDP  ds,dx,pbuffer   ; Get pointer to data buffer.
  15535.          mov     ax,440dh        ; Set function code, Subfunction 0DH.
  15536.          int     21h             ; Call MS-DOS.
  15537.          jc      ibgx            ; Branch on error.
  15538.          xor     ax,ax
  15539.  ibgx:
  15540.  cEnd
  15541.  
  15542.  \SAMPCODE\DOS_ENCY\SECTION5\FXN440EH.ASM
  15543.  
  15544.          ;************************************************************;
  15545.          ;                                                            ;
  15546.          ;       Function 44H, Subfunctions 0EH, 0FH:                 ;
  15547.          ;                     IOCTL Get/Set Logical Drive Map        ;
  15548.          ;                                                            ;
  15549.          ;       int ioctl_drive_owner(setflag, drv_ltr)              ;
  15550.          ;           int setflag;                                     ;
  15551.          ;           int drv_ltr;                                     ;
  15552.          ;                                                            ;
  15553.          ;       Set setflag = 1 to change drive's map, 0 to get      ;
  15554.          ;       current map.                                         ;
  15555.          ;                                                            ;
  15556.          ;       Returns -1 for all errors, otherwise returns         ;
  15557.          ;       the block device's current logical drive letter.     ;
  15558.          ;                                                            ;
  15559.          ;************************************************************;
  15560.  
  15561.  cProc   ioctl_drive_owner,PUBLIC
  15562.  parmB   setflag
  15563.  parmB   drv_ltr
  15564.  cBegin
  15565.          mov     al,setflag      ; Load setflag.
  15566.          and     al,1            ; Keep only lsb.
  15567.          add     al,0eh          ; AL = 0EH for get, 0FH for set.
  15568.          mov     bl,drv_ltr      ; Get drive letter.
  15569.          or      bl,bl           ; Leave 0 alone.
  15570.          jz      ido
  15571.          and     bl,not 20h      ; Convert letter to uppercase.
  15572.          sub     bl,'A'-1        ; Convert to drive number: 'A' = 1,
  15573.                                  ; 'B' = 2, etc.
  15574.  ido:
  15575.          mov     bh,0
  15576.          mov     ah,44h          ; Set function code.
  15577.          int     21h             ; Call MS-DOS.
  15578.          mov     ah,0            ; Clear high byte.
  15579.          jnc     idox            ; Branch if no error.
  15580.          mov     ax,-1-'A'       ; Return -1 for errors.
  15581.  idox:
  15582.          add     ax,'A'          ; Return drive letter.
  15583.  cEnd
  15584.  
  15585.  \SAMPCODE\DOS_ENCY\SECTION5\FXN440FH.ASM
  15586.  
  15587.          ;************************************************************;
  15588.          ;                                                            ;
  15589.          ;       Function 44H, Subfunctions 0EH, 0FH:                 ;
  15590.          ;                     IOCTL Get/Set Logical Drive Map        ;
  15591.          ;                                                            ;
  15592.          ;       int ioctl_drive_owner(setflag, drv_ ltr)             ;
  15593.          ;           int setflag;                                     ;
  15594.          ;           int drv_ltr;                                     ;
  15595.          ;                                                            ;
  15596.          ;       Set setflag = 1 to change drive's map, 0 to get      ;
  15597.          ;       current map.                                         ;
  15598.          ;                                                            ;
  15599.          ;       Returns -1 for all errors, otherwise returns         ;
  15600.          ;       the block device's current logical drive letter.     ;
  15601.          ;                                                            ;
  15602.          ;************************************************************;
  15603.  
  15604.  cProc   ioctl_drive_owner,PUBLIC
  15605.  parmB   setflag
  15606.  parmB   drv_ltr
  15607.  cBegin
  15608.          mov     al,setflag      ; Load setflag.
  15609.          and     al,1            ; Keep only lsb.
  15610.          add     al,0fh          ; AL = 0EH for get, 0FH for set.
  15611.          mov     bl,drv_ltr      ; Get drive letter.
  15612.          or      bl,bl           ; Leave 0 alone.
  15613.          jz      ido
  15614.          and     bl,not 20h      ; Convert letter to uppercase.
  15615.          sub     bl,'A'-1        ; Convert to drive number: 'A' = 1,
  15616.                                  ; 'B' = 2, etc.
  15617.  ido:
  15618.          mov     bh,0
  15619.          mov     ah,44h          ; Set function code.
  15620.          int     21h             ; Call MS-DOS.
  15621.          mov     ah,0            ; Clear high byte.
  15622.          jnc     idox            ; Branch if no error.
  15623.          mov     ax,-1-'A'       ; Return -1 for errors.
  15624.  idox:
  15625.          add     ax,'A'          ; Return drive letter.
  15626.  cEnd
  15627.  
  15628.  \SAMPCODE\DOS_ENCY\SECTION5\FXN45H.ASM
  15629.  
  15630.          ;************************************************************;
  15631.          ;                                                            ;
  15632.          ;             Function 45H: Duplicate File Handle            ;
  15633.          ;                                                            ;
  15634.          ;             int dup_handle(handle)                         ;
  15635.          ;                 int handle;                                ;
  15636.          ;                                                            ;
  15637.          ;             Returns -1 for errors,                         ;
  15638.          ;             otherwise returns new handle.                  ;
  15639.          ;                                                            ;
  15640.          ;************************************************************;
  15641.  
  15642.  cProc   dup_handle,PUBLIC
  15643.  parmW   handle
  15644.  cBegin
  15645.          mov     bx,handle       ; Get handle to copy.
  15646.          mov     ah,45h          ; Set function code.
  15647.          int     21h             ; Ask MS-DOS to duplicate handle.
  15648.          jnb     dup_ok          ; Branch if copy was successful.
  15649.          mov     ax,-1           ; Else return -1.
  15650.  dup_ok:
  15651.  cEnd
  15652.  
  15653.  \SAMPCODE\DOS_ENCY\SECTION5\FXN46H.ASM
  15654.  
  15655.          ;************************************************************;
  15656.          ;                                                            ;
  15657.          ;          Function 46H: Force Duplicate File Handle         ;
  15658.          ;                                                            ;
  15659.          ;          int dup_handle2(existhandle,newhandle)            ;
  15660.          ;              int existhandle,newhandle;                    ;
  15661.          ;                                                            ;
  15662.          ;          Returns -1 for errors,                            ;
  15663.          ;          otherwise returns newhandle unchanged.            ;
  15664.          ;                                                            ;
  15665.          ;************************************************************;
  15666.  
  15667.  cProc   dup_handle2,PUBLIC
  15668.  parmW   existhandle
  15669.  parmW   newhandle
  15670.  cBegin
  15671.          mov     bx,existhandle  ; Get handle of existing file.
  15672.          mov     cx,newhandle    ; Get handle to copy into.
  15673.          mov     ah,46h          ; Close handle CX and then
  15674.          int     21h             ; duplicate BX's handle into CX.
  15675.          mov     ax,newhandle    ; Prepare return value.
  15676.          jnb     dup2_ok         ; Branch if close/copy was successful.
  15677.          mov     ax,-1           ; Else return -1.
  15678.  dup2_ok:
  15679.  cEnd
  15680.  
  15681.  \SAMPCODE\DOS_ENCY\SECTION5\FXN47H.ASM
  15682.  
  15683.          ;************************************************************;
  15684.          ;                                                            ;
  15685.          ;            Function 47H: Get Current Directory             ;
  15686.          ;                                                            ;
  15687.          ;            int get_dir(drive_ltr,pbuffer)                  ;
  15688.          ;                int drive_ltr;                              ;
  15689.          ;                char *pbuffer;                              ;
  15690.          ;                                                            ;
  15691.          ;            Returns -1 for bad drive,                       ;
  15692.          ;            otherwise returns pointer to pbuffer.           ;
  15693.          ;                                                            ;
  15694.          ;************************************************************;
  15695.  
  15696.  cProc   get_dir,PUBLIC,<ds,si>
  15697.  parmB   drive_ltr
  15698.  parmDP  pbuffer
  15699.  cBegin
  15700.          loadDP  ds,si,pbuffer   ; Get pointer to buffer.
  15701.          mov     dl,drive_ltr    ; Get drive number.
  15702.          or      dl,dl           ; Leave 0 alone.
  15703.          jz      gdir
  15704.          and     dl,not 20h      ; Convert letter to uppercase
  15705.          sub     dl,'A'-1        ; Convert to drive number: 'A' = 1,
  15706.                                  ; 'B' = 2, etc.
  15707.  gdir:
  15708.          mov     ah,47h          ; Set function code.
  15709.          int     21h             ; Call MS-DOS.
  15710.          mov     ax,si           ; Return pointer to buffer ...
  15711.          jnb     gd_ok
  15712.          mov     ax,-1           ; ... unless an error occurred.
  15713.  gd_ok:
  15714.  cEnd
  15715.  
  15716.  \SAMPCODE\DOS_ENCY\SECTION5\FXN48H.ASM
  15717.  
  15718.          ;************************************************************;
  15719.          ;                                                            ;
  15720.          ;         Function 48H: Allocate Memory Block                ;
  15721.          ;                                                            ;
  15722.          ;         int get_block(nparas,pblocksegp,pmaxparas)         ;
  15723.          ;             int nparas,*pblockseg,*pmaxparas;              ;
  15724.          ;                                                            ;
  15725.          ;         Returns 0 if nparas are allocated OK and           ;
  15726.          ;         pblockseg has segment address of block,            ;
  15727.          ;         otherwise returns error code with pmaxparas        ;
  15728.          ;         set to maximum block size available.               ;
  15729.          ;                                                            ;
  15730.          ;************************************************************;
  15731.  
  15732.  cProc   get_block,PUBLIC,ds
  15733.  parmW   nparas
  15734.  parmDP  pblockseg
  15735.  parmDP  pmaxparas
  15736.  cBegin
  15737.          mov     bx,nparas       ; Get size request.
  15738.          mov     ah,48h          ; Set function code.
  15739.          int     21h             ; Ask MS-DOS for memory.
  15740.          mov     cx,bx           ; Save BX.
  15741.          loadDP  ds,bx,pmaxparas
  15742.          mov     [bx],cx         ; Return result, assuming failure.
  15743.          jb      gb_err          ; Exit if error, leaving error code
  15744.                                  ; in AX.
  15745.          loadDP  ds,bx,pblockseg
  15746.          mov     [bx],ax         ; No error, so store address of block.
  15747.          xor     ax,ax           ; Return 0.
  15748.  gb_err:
  15749.  cEnd
  15750.  
  15751.  \SAMPCODE\DOS_ENCY\SECTION5\FXN49H.ASM
  15752.  
  15753.          ;************************************************************;
  15754.          ;                                                            ;
  15755.          ;               Function 49H: Free Memory Block              ;
  15756.          ;                                                            ;
  15757.          ;               int free_block(blockseg)                     ;
  15758.          ;                   int blockseg;                            ;
  15759.          ;                                                            ;
  15760.          ;               Returns 0 if block freed OK,                 ;
  15761.          ;               otherwise returns error code.                ;
  15762.          ;                                                            ;
  15763.          ;************************************************************;
  15764.  
  15765.  cProc   free_block,PUBLIC
  15766.  parmW   blockseg
  15767.  cBegin
  15768.          mov     es,blockseg     ; Get block address.
  15769.          mov     ah,49h          ; Set function code.
  15770.          int     21h             ; Ask MS-DOS to free memory.
  15771.          jb      fb_err          ; Branch on error.
  15772.          xor     ax,ax           ; Return 0 if successful.
  15773.  fb_err:
  15774.  cEnd
  15775.  
  15776.  \SAMPCODE\DOS_ENCY\SECTION5\FXN4AH.ASM
  15777.  
  15778.          ;************************************************************;
  15779.          ;                                                            ;
  15780.          ;         Function 4AH: Resize Memory Block                  ;
  15781.          ;                                                            ;
  15782.          ;         int modify_block(nparas,blockseg,pmaxparas)        ;
  15783.          ;             int nparas,blockseg,*pmaxparas;                ;
  15784.          ;                                                            ;
  15785.          ;         Returns 0 if modification was a success,           ;
  15786.          ;         otherwise returns error code with pmaxparas        ;
  15787.          ;         set to max number of paragraphs available.         ;
  15788.          ;                                                            ;
  15789.          ;************************************************************;
  15790.  
  15791.  cProc   modify_block,PUBLIC,ds
  15792.  parmW   nparas
  15793.  parmW   blockseg
  15794.  parmDP  pmaxparas
  15795.  cBegin
  15796.          mov     es,blockseg     ; Get block address.
  15797.          mov     bx,nparas       ; Get nparas.
  15798.          mov     ah,4ah          ; Set function code.
  15799.          int     21h             ; Ask MS-DOS to change block size.
  15800.          mov     cx,bx           ; Save BX.
  15801.          loadDP  ds,bx,pmaxparas
  15802.          mov     [bx],cx         ; Set pmaxparas, assuming failure.
  15803.          jb      mb_exit         ; Branch if size change error.
  15804.          xor     ax,ax           ; Return 0 if successful.
  15805.  mb_exit:
  15806.  cEnd
  15807.  
  15808.  \SAMPCODE\DOS_ENCY\SECTION5\FXN4BH.ASM
  15809.  
  15810.          ;************************************************************;
  15811.          ;                                                            ;
  15812.          ;          Function 4BH: Load and Execute Program            ;
  15813.          ;                                                            ;
  15814.          ;          int execute(pprogname,pcmdtail)                   ;
  15815.          ;              char *pprogname,*pcmdtail;                    ;
  15816.          ;                                                            ;
  15817.          ;          Returns 0 if program loaded, ran, and             ;
  15818.          ;          terminated successfully, otherwise returns        ;
  15819.          ;          error code.                                       ;
  15820.          ;                                                            ;
  15821.          ;************************************************************;
  15822.  
  15823.  sBegin  data
  15824.  $cmdlen =       126
  15825.  $cmd    db      $cmdlen+2 dup (?) ; Make space for command line, plus
  15826.                                  ; 2 extra bytes for length and
  15827.                                  ; carriage return.
  15828.  
  15829.  $fcb    db      0               ; Make dummy FCB.
  15830.          db      'dummy   fcb'
  15831.          db      0,0,0,0
  15832.  
  15833.                                  ; Here's the EXEC parameter block:
  15834.  $epb    dw      0               ; 0 means inherit environment.
  15835.          dw      dataOFFSET $cmd ; Pointer to cmd line.
  15836.          dw      seg dgroup
  15837.          dw      dataOFFSET $fcb ; Pointer to FCB #1.
  15838.          dw      seg dgroup
  15839.          dw      dataOFFSET $fcb ; Pointer to FCB #2.
  15840.          dw      seg dgroup
  15841.  sEnd    data
  15842.  sBegin  code
  15843.  
  15844.  $sp     dw      ?               ; Allocate space in code seg
  15845.  $ss     dw      ?               ; for saving SS and SP.
  15846.  
  15847.  Assumes ES,dgroup
  15848.  
  15849.  cProc   execute,PUBLIC,<ds,si,di>
  15850.  parmDP  pprogname
  15851.  parmDP  pcmdtail
  15852.  cBegin
  15853.          mov     cx,$cmdlen      ; Allow command line this long.
  15854.          loadDP  ds,si,pcmdtail  ; DS:SI = pointer to cmdtail string.
  15855.          mov     ax,seg dgroup:$cmd    ; Set ES = data segment.
  15856.          mov     es,ax
  15857.          mov     di,dataOFFSET $cmd+1  ; ES:DI = pointer to 2nd byte of
  15858.                                        ; our command-line buffer.
  15859.  copycmd:
  15860.          lodsb                   ; Get next character.
  15861.          or      al,al           ; Found end of command tail?
  15862.          jz      endcopy         ; Exit loop if so.
  15863.          stosb                   ; Copy to command buffer.
  15864.          loop    copycmd
  15865.  endcopy:
  15866.          mov     al,13
  15867.          stosb                   ; Store carriage return at
  15868.                                  ; end of command.
  15869.          neg     cl
  15870.          add     cl,$cmdlen      ; CL = length of command tail.
  15871.          mov     es:$cmd,cl      ; Store length in command-tail buffer.
  15872.  
  15873.          loadDP  ds,dx,pprogname ; DS:DX = pointer to program name.
  15874.          mov     bx,dataOFFSET $epb ; ES:BX = pointer to parameter
  15875.                                     ; block.
  15876.  
  15877.          mov     cs:$ss,ss       ; Save current stack SS:SP (since
  15878.          mov     cs:$sp,sp       ; EXEC function destroys stack).
  15879.          mov     ax,4b00h        ; Set function code.
  15880.          int     21h             ; Ask MS-DOS to load and execute
  15881.                                  ; program.
  15882.          cli                     ; Disable interrupts.
  15883.          mov     ss,cs:$ss       ; Restore stack.
  15884.          mov     sp,cs:$sp
  15885.          sti                     ; Enable interrupts.
  15886.          jb      ex_err          ; Branch on error.
  15887.          xor     ax,ax           ; Return 0 if no error.
  15888.  ex_err:
  15889.  cEnd
  15890.  sEnd    code
  15891.  
  15892.  
  15893.  
  15894.          ;************************************************************;
  15895.          ;                                                            ;
  15896.          ;   Function 4BH: Load an Overlay Program                    ;
  15897.          ;                                                            ;
  15898.          ;   int load_overlay(pfilename,loadseg)                      ;
  15899.          ;       char *pfilename;                                     ;
  15900.          ;       int  loadseg;                                        ;
  15901.          ;                                                            ;
  15902.          ;   Returns 0 if program has been loaded OK,                 ;
  15903.          ;   otherwise returns error code.                            ;
  15904.          ;                                                            ;
  15905.          ;   To call an overlay function after it has been            ;
  15906.          ;   loaded by load_overlay(), you can use                    ;
  15907.          ;   a far indirect call:                                     ;
  15908.          ;                                                            ;
  15909.          ;   1. FTYPE (far *ovlptr)();                                ;
  15910.          ;   2. *((unsigned *)&ovlptr + 1) = loadseg;                 ;
  15911.          ;   3. *((unsigned *)&ovlptr) = offset;                      ;
  15912.          ;   4. (*ovlptr)(arg1,arg2,arg3,...);                        ;
  15913.          ;                                                            ;
  15914.          ;   Line 1 declares a far pointer to a                       ;
  15915.          ;   function with return type FTYPE.                         ;
  15916.          ;                                                            ;
  15917.          ;   Line 2 stores loadseg into the segment                   ;
  15918.          ;   portion (high word) of the far pointer.                  ;
  15919.          ;                                                            ;
  15920.          ;   Line 3 stores offset into the offset                     ;
  15921.          ;   portion (low word) of the far pointer.                   ;
  15922.          ;                                                            ;
  15923.          ;   Line 4 does a far call to offset                         ;
  15924.          ;   bytes into the segment loadseg                           ;
  15925.          ;   passing the arguments listed.                            ;
  15926.          ;                                                            ;
  15927.          ;   To return correctly, the overlay  must end with a far    ;
  15928.          ;   return instruction.  If the overlay is                   ;
  15929.          ;   written in Microsoft C, this can be done by              ;
  15930.          ;   declaring the overlay function with the                  ;
  15931.          ;   keyword "far".                                           ;
  15932.          ;                                                            ;
  15933.          ;************************************************************;
  15934.  
  15935.  sBegin  data
  15936.                                  ; The overlay parameter block:
  15937.  $lob    dw      ?               ; space for load segment;
  15938.          dw      ?               ; space for fixup segment.
  15939.  sEnd    data
  15940.  
  15941.  sBegin  code
  15942.  
  15943.  cProc   load_overlay,PUBLIC,<ds,si,di>
  15944.  parmDP  pfilename
  15945.  parmW   loadseg
  15946.  cBegin
  15947.          loadDP  ds,dx,pfilename ; DS:DX = pointer to program name.
  15948.          mov     ax,seg dgroup:$lob ; Set ES = data segment.
  15949.          mov     es,ax
  15950.          mov     bx,dataOFFSET $lob ; ES:BX = pointer to parameter
  15951.                                     ; block.
  15952.          mov     ax,loadseg      ; Get load segment parameter.
  15953.          mov     es:[bx],ax      ; Set both the load and fixup
  15954.          mov     es:[bx+2],ax    ; segments to that segment.
  15955.  
  15956.          mov     cs:$ss,ss       ; Save current stack SS:SP (because
  15957.          mov     cs:$sp,sp       ; EXEC function destroys stack).
  15958.          mov     ax,4b03h        ; Set function code.
  15959.          int     21h             ; Ask MS-DOS to load the overlay.
  15960.          cli                     ; Disable interrupts.
  15961.          mov     ss,cs:$ss       ; Restore stack.
  15962.          mov     sp,cs:$sp
  15963.          sti                     ; Enable interrupts.
  15964.          jb      lo_err          ; Branch on error.
  15965.          xor     ax,ax           ; Return 0 if no error.
  15966.  lo_err:
  15967.  cEnd
  15968.  sEnd    code
  15969.  
  15970.  \SAMPCODE\DOS_ENCY\SECTION5\FXN4CH.ASM
  15971.  
  15972.          ;************************************************************;
  15973.          ;                                                            ;
  15974.          ;       Function 4CH: Terminate Process with Return Code     ;
  15975.          ;                                                            ;
  15976.          ;       int terminate(returncode)                            ;
  15977.          ;           int returncode;                                  ;
  15978.          ;                                                            ;
  15979.          ;       Does NOT return at all!                              ;
  15980.          ;                                                            ;
  15981.          ;************************************************************;
  15982.  
  15983.  cProc   terminate,PUBLIC
  15984.  parmB   returncode
  15985.  cBegin
  15986.          mov     al,returncode   ; Set return code.
  15987.          mov     ah,4ch          ; Set function code.
  15988.          int     21h             ; Call MS-DOS to terminate process.
  15989.  cEnd
  15990.  
  15991.  \SAMPCODE\DOS_ENCY\SECTION5\FXN4DH.ASM
  15992.  
  15993.          ;************************************************************;
  15994.          ;                                                            ;
  15995.          ;        Function 4DH: Get Return Code of Child Process      ;
  15996.          ;                                                            ;
  15997.          ;        int child_ret_code()                                ;
  15998.          ;                                                            ;
  15999.          ;        Returns the return code of the last                 ;
  16000.          ;        child process.                                      ;
  16001.          ;                                                            ;
  16002.          ;************************************************************;
  16003.  
  16004.  cProc   child_ret_code,PUBLIC
  16005.  cBegin
  16006.          mov     ah,4dh          ; Set function code.
  16007.          int     21h             ; Ask MS-DOS to return code.
  16008.          cbw                     ; Convert AL to a word.
  16009.  cEnd
  16010.  
  16011.  \SAMPCODE\DOS_ENCY\SECTION5\FXN4EH.ASM
  16012.  
  16013.          ;************************************************************;
  16014.          ;                                                            ;
  16015.          ;               Function 4EH: Find First File                ;
  16016.          ;                                                            ;
  16017.          ;               int find_first(ppathname,attr)               ;
  16018.          ;                   char *ppathname;                         ;
  16019.          ;                   int  attr;                               ;
  16020.          ;                                                            ;
  16021.          ;               Returns 0 if a match was found,              ;
  16022.          ;               otherwise returns error code.                ;
  16023.          ;                                                            ;
  16024.          ;************************************************************;
  16025.  
  16026.  cProc   find_first,PUBLIC,ds
  16027.  parmDP  ppathname
  16028.  parmW   attr
  16029.  cBegin
  16030.          loadDP  ds,dx,ppathname ; Get pointer to pathname.
  16031.          mov     cx,attr         ; Get search attributes.
  16032.          mov     ah,4eh          ; Set function code.
  16033.          int     21h             ; Ask MS-DOS to look for a match.
  16034.          jb      ff_err          ; Branch on error.
  16035.          xor     ax,ax           ; Return 0 if no error.
  16036.  ff_err:
  16037.  cEnd
  16038.  
  16039.  \SAMPCODE\DOS_ENCY\SECTION5\FXN4FH.ASM
  16040.  
  16041.          ;************************************************************;
  16042.          ;                                                            ;
  16043.          ;               Function 4FH: Find Next File                 ;
  16044.          ;                                                            ;
  16045.          ;               int find_next()                              ;
  16046.          ;                                                            ;
  16047.          ;               Returns 0 if a match was found,              ;
  16048.          ;               otherwise returns error code.                ;
  16049.          ;                                                            ;
  16050.          ;************************************************************;
  16051.  
  16052.  cProc   find_next,PUBLIC
  16053.  cBegin
  16054.          mov     ah,4fh          ; Set function code.
  16055.          int     21h             ; Ask MS-DOS to look for the next
  16056.                                  ; matching file.
  16057.          jb      fn_err          ; Branch on error.
  16058.          xor     ax,ax           ; Return 0 if no error.
  16059.  fn_err:
  16060.  cEnd
  16061.  
  16062.  \SAMPCODE\DOS_ENCY\SECTION5\FXN54H.ASM
  16063.  
  16064.          ;************************************************************;
  16065.          ;                                                            ;
  16066.          ;            Function 54H: Get Verify Flag                   ;
  16067.          ;                                                            ;
  16068.          ;            int get_verify()                                ;
  16069.          ;                                                            ;
  16070.          ;            Returns current value of verify flag.           ;
  16071.          ;                                                            ;
  16072.          ;************************************************************;
  16073.  
  16074.  cProc   get_verify,PUBLIC
  16075.  cBegin
  16076.          mov     ah,54h          ; Set function code.
  16077.          int     21h             ; Read flag from MS-DOS.
  16078.          cbw                     ; Clear high byte of return value.
  16079.  
  16080.  cEnd
  16081.  
  16082.  \SAMPCODE\DOS_ENCY\SECTION5\FXN56H.ASM
  16083.  
  16084.          ;************************************************************;
  16085.          ;                                                            ;
  16086.          ;                Function 56H: Rename File                   ;
  16087.          ;                                                            ;
  16088.          ;                int rename(poldpath,pnewpath)               ;
  16089.          ;                    char *poldpath,*pnewpath;               ;
  16090.          ;                                                            ;
  16091.          ;                Returns 0 if file moved OK,                 ;
  16092.          ;                otherwise returns error code.               ;
  16093.          ;                                                            ;
  16094.          ;************************************************************;
  16095.  
  16096.  cProc   rename,PUBLIC,<ds,di>
  16097.  parmDP  poldpath
  16098.  parmDP  pnewpath
  16099.  cBegin
  16100.          loadDP  es,di,pnewpath  ; ES:DI = pointer to newpath.
  16101.          loadDP  ds,dx,poldpath  ; DS:DX = pointer to oldpath.
  16102.          mov     ah,56h          ; Set function code.
  16103.          int     21h             ; Ask MS-DOS to rename file.
  16104.          jb      rn_err          ; Branch on error.
  16105.          xor     ax,ax           ; Return 0 if no error.
  16106.  rn_err:
  16107.  cEnd
  16108.  
  16109.  \SAMPCODE\DOS_ENCY\SECTION5\FXN57H.ASM
  16110.  
  16111.          ;************************************************************;
  16112.          ;                                                            ;
  16113.          ;      Function 57H: Get/Set Date/Time of File               ;
  16114.          ;                                                            ;
  16115.          ;      long file_date_time(handle,func,packdate,packtime)    ;
  16116.          ;           int handle,func,packdate,packtime;               ;
  16117.          ;                                                            ;
  16118.          ;      Returns a long -1 for all errors, otherwise packs     ;
  16119.          ;      date and time into a long integer,                    ;
  16120.          ;      date in high word, time in low word.                  ;
  16121.          ;                                                            ;
  16122.          ;************************************************************;
  16123.  
  16124.  cProc   file_date_time,PUBLIC
  16125.  parmW   handle
  16126.  parmB   func
  16127.  parmW   packdate
  16128.  parmW   packtime
  16129.  cBegin
  16130.          mov     bx,handle       ; Get handle.
  16131.          mov     al,func         ; Get function: 0 = read, 1 = write.
  16132.          mov     dx,packdate     ; Get date (if present).
  16133.          mov     cx,packtime     ; Get time (if present).
  16134.          mov     ah,57h          ; Set function code.
  16135.          int     21h             ; Call MS-DOS.
  16136.          mov     ax,cx           ; Set DX:AX = date/time, assuming no
  16137.                                  ; error.
  16138.          jnb     dt_ok           ; Branch if no error.
  16139.          mov     ax,-1           ; Return -1 for errors.
  16140.          cwd                     ; Extend the -1 into DX.
  16141.  dt_ok:
  16142.  cEnd
  16143.  
  16144.  \SAMPCODE\DOS_ENCY\SECTION5\FXN58H.ASM
  16145.  
  16146.          ;************************************************************;
  16147.          ;                                                            ;
  16148.          ;          Function 58H: Get/Set Allocation Strategy         ;
  16149.          ;                                                            ;
  16150.          ;          int alloc_strategy(func,strategy)                 ;
  16151.          ;              int func,strategy;                            ;
  16152.          ;                                                            ;
  16153.          ;          Strategies:                                       ;
  16154.          ;                  0: First fit                              ;
  16155.          ;                  1: Best fit                               ;
  16156.          ;                  2: Last fit                               ;
  16157.          ;                                                            ;
  16158.          ;          Returns -1 for all errors, otherwise              ;
  16159.          ;          returns the current strategy.                     ;
  16160.          ;                                                            ;
  16161.          ;************************************************************;
  16162.  
  16163.  cProc   alloc_strategy,PUBLIC
  16164.  parmB   func
  16165.  parmW   strategy
  16166.  cBegin
  16167.          mov     al,func         ; AL = get/set selector.
  16168.          mov     bx,strategy     ; BX = new strategy (for AL = 01H).
  16169.          mov     ah,58h          ; Set function code.
  16170.          int     21h             ; Call MS-DOS.
  16171.          jnb     no_err          ; Branch if no error.
  16172.          mov     ax,-1           ; Return -1 for all errors.
  16173.  no_err:
  16174.  cEnd
  16175.  
  16176.  \SAMPCODE\DOS_ENCY\SECTION5\FXN59H.ASM
  16177.  
  16178.          ;************************************************************;
  16179.          ;                                                            ;
  16180.          ;         Function 59H: Get Extended Error Information       ;
  16181.          ;                                                            ;
  16182.          ;         int extended_error(err,class,action,locus)         ;
  16183.          ;             int *err;                                      ;
  16184.          ;             char *class,*action,*locus;                    ;
  16185.          ;                                                            ;
  16186.          ;         Return value is same as err.                       ;
  16187.          ;                                                            ;
  16188.          ;************************************************************;
  16189.  
  16190.  cProc   extended_error,PUBLIC,<ds,si,di>
  16191.  parmDP  perr
  16192.  parmDP  pclass
  16193.  parmDP  paction
  16194.  parmDP  plocus
  16195.  cBegin
  16196.          push    ds              ; Save DS.
  16197.          xor     bx,bx
  16198.          mov     ah,59h          ; Set function code.
  16199.          int     21h             ; Request error info from MS-DOS.
  16200.          pop     ds              ; Restore DS.
  16201.          loadDP  ds,si,perr      ; Get pointer to err.
  16202.          mov     [si],ax         ; Store err.
  16203.          loadDP  ds,si,pclass    ; Get pointer to class.
  16204.          mov     [si],bh         ; Store class.
  16205.          loadDP  ds,si,paction   ; Get pointer to action.
  16206.          mov     [si],bl         ; Store action.
  16207.          loadDP  ds,si,plocus    ; Get pointer to locus.
  16208.          mov     [si],ch         ; Store locus.
  16209.  cEnd
  16210.  
  16211.  \SAMPCODE\DOS_ENCY\SECTION5\FXN5AH.ASM
  16212.  
  16213.          ;************************************************************;
  16214.          ;                                                            ;
  16215.          ;             Function 5AH: Create Temporary File            ;
  16216.          ;                                                            ;
  16217.          ;             int create_temp(ppathname,attr)                ;
  16218.          ;                 char *ppathname;                           ;
  16219.          ;                 int attr;                                  ;
  16220.          ;                                                            ;
  16221.          ;             Returns -1 if file was not created,            ;
  16222.          ;             otherwise returns file handle.                 ;
  16223.          ;                                                            ;
  16224.          ;************************************************************;
  16225.  
  16226.  cProc   create_temp,PUBLIC,ds
  16227.  parmDP  ppathname
  16228.  parmW   attr
  16229.  cBegin
  16230.          loadDP  ds,dx,ppathname ; Get pointer to pathname.
  16231.          mov     cx,attr         ; Set function code.
  16232.          mov     ah,5ah          ; Ask MS-DOS to make a new file with
  16233.                                  ; a unique name.
  16234.          int     21h             ; Ask MS-DOS to make a tmp file.
  16235.          jnb     ct_ok           ; Branch if MS-DOS returned handle.
  16236.          mov     ax,-1           ; Else return -1.
  16237.  ct_ok:
  16238.  cEnd
  16239.  
  16240.  \SAMPCODE\DOS_ENCY\SECTION5\FXN5BH.ASM
  16241.  
  16242.          ;************************************************************;
  16243.          ;                                                            ;
  16244.          ;          Function 5BH: Create New File                     ;
  16245.          ;                                                            ;
  16246.          ;          int create_new(ppathname,attr)                    ;
  16247.          ;              char *ppathname;                              ;
  16248.          ;              int attr;                                     ;
  16249.          ;                                                            ;
  16250.          ;          Returns -2 if file already exists,                ;
  16251.          ;                  -1 for all other errors,                  ;
  16252.          ;                  otherwise returns file handle.            ;
  16253.          ;                                                            ;
  16254.          ;************************************************************;
  16255.  
  16256.  cProc   create_new,PUBLIC,ds
  16257.  parmDP  ppathname
  16258.  parmW   attr
  16259.  cBegin
  16260.          loadDP  ds,dx,ppathname ; Get pointer to pathname.
  16261.          mov     cx,attr         ; Get new file's attribute.
  16262.          mov     ah,5bh          ; Set function code.
  16263.          int     21h             ; Ask MS-DOS to make a new file.
  16264.          jnb     cn_ok           ; Branch if MS-DOS returned handle.
  16265.          mov     bx,-2
  16266.          cmp     al,80           ; Did file already exist?
  16267.          jz      ae_err          ; Branch if so.
  16268.          inc     bx              ; Change -2 to -1.
  16269.  ae_err:
  16270.          mov     ax,bx           ; Return error code.
  16271.  cn_ok:
  16272.  cEnd
  16273.  
  16274.  \SAMPCODE\DOS_ENCY\SECTION5\FXN5CH.ASM
  16275.  
  16276.          ;************************************************************;
  16277.          ;                                                            ;
  16278.          ;            Function 5CH: Lock/Unlock File Region           ;
  16279.          ;                                                            ;
  16280.          ;            int locks(handle,onoff,start,length)            ;
  16281.          ;                int handle,onoff;                           ;
  16282.          ;                long start,length;                          ;
  16283.          ;                                                            ;
  16284.          ;            Returns 0 if operation was successful,          ;
  16285.          ;            otherwise returns error code.                   ;
  16286.          ;                                                            ;
  16287.          ;************************************************************;
  16288.  
  16289.  cProc   locks,PUBLIC,<si,di>
  16290.  parmW   handle
  16291.  parmB   onoff
  16292.  parmD   start
  16293.  parmD   length
  16294.  cBegin
  16295.          mov     al,onoff        ; Get lock/unlock flag.
  16296.          mov     bx,handle       ; Get file handle.
  16297.          les     dx,start        ; Get low word of start.
  16298.          mov     cx,es           ; Get high word of start.
  16299.          les     di,length       ; Get low word of length.
  16300.          mov     si,es           ; Get high word of length.
  16301.          mov     ah,5ch          ; Set function code.
  16302.          int     21h             ; Make lock/unlock request.
  16303.          jb      lk_err          ; Branch on error.
  16304.          xor     ax,ax           ; Return 0 if no error.
  16305.  lk_err:
  16306.  cEnd
  16307.  
  16308.  \SAMPCODE\DOS_ENCY\SECTION5\FXN5E02H.ASM
  16309.  
  16310.          ;************************************************************;
  16311.          ;                                                            ;
  16312.          ;       Function 5EH Subfunction 02H:                        ;
  16313.          ;                     Set Printer Setup                      ;
  16314.          ;                                                            ;
  16315.          ;       int printer_setup(index,pstring,len)                 ;
  16316.          ;           int   index;                                     ;
  16317.          ;           char *pstring;                                   ;
  16318.          ;           int   len;                                       ;
  16319.          ;                                                            ;
  16320.          ;       Returns 0, otherwise returns -1 for all errors.      ;
  16321.          ;                                                            ;
  16322.          ;************************************************************;
  16323.  
  16324.  cProc   printer_setup,PUBLIC,<ds,si>
  16325.  parmW   index
  16326.  parmDP  pstring
  16327.  parmW   len
  16328.  cBegin
  16329.          mov     bx,index        ; BX = index of a net printer.
  16330.          loadDP  ds,si,pstring   ; DS:SI = pointer to string.
  16331.          mov     cx,len          ; CX = length of string.
  16332.          mov     ax,5e02h        ; Set function code.
  16333.          int     21h             ; Set printer prefix string.
  16334.          mov     al,0            ; Assume no error.
  16335.          jnb     ps_ok           ; Branch if no error,
  16336.          mov     al,-1           ; Else return -1.
  16337.  ps_ok:
  16338.          cbw
  16339.  cEnd
  16340.  
  16341.  \SAMPCODE\DOS_ENCY\SECTION5\FXN5F02H.ASM
  16342.  
  16343.          ;************************************************************;
  16344.          ;                                                            ;
  16345.          ;    Function 5FH Subfunction 02H:                           ;
  16346.          ;                  Get Assign-List Entry                     ;
  16347.          ;                                                            ;
  16348.          ;    int get_alist_entry(index,                              ;
  16349.          ;           plocalname,premotename,                          ;
  16350.          ;           puservalue,ptype)                                ;
  16351.          ;        int  index;                                         ;
  16352.          ;        char *plocalname;                                   ;
  16353.          ;        char *premotename;                                  ;
  16354.          ;        int  *puservalue;                                   ;
  16355.          ;        int  *ptype;                                        ;
  16356.          ;                                                            ;
  16357.          ;    Returns 0 if the requested assign-list entry is found,  ;
  16358.          ;    otherwise returns error code.                           ;
  16359.          ;                                                            ;
  16360.          ;************************************************************;
  16361.  
  16362.  cProc   get_alist_entry,PUBLIC,<ds,si,di>
  16363.  parmW   index
  16364.  parmDP  plocalname
  16365.  parmDP  premotename
  16366.  parmDP  puservalue
  16367.  parmDP  ptype
  16368.  cBegin
  16369.          mov     bx,index        ; Get list index.
  16370.          loadDP  ds,si,plocalname  ; DS:SI = pointer to local name
  16371.                                    ; buffer.
  16372.          loadDP  es,di,premotename ; ES:DI = pointer to remote name
  16373.                                    ; buffer.
  16374.          mov     ax,5f02h        ; Set function code.
  16375.          int     21h             ; Get assign-list entry.
  16376.          jb      ga_err          ; Exit on error.
  16377.          xor     ax,ax           ; Else return 0.
  16378.          loadDP  ds,si,puservalue ; Get address of uservalue.
  16379.          mov     [si],cx         ; Store user value.
  16380.          loadDP  ds,si,ptype     ; Get address of type.
  16381.          mov     bh,0
  16382.          mov     [si],bx         ; Store device type to type.
  16383.  ga_err:
  16384.  cEnd
  16385.  
  16386.  \SAMPCODE\DOS_ENCY\SECTION5\FXN5F03H.ASM
  16387.  
  16388.          ;************************************************************;
  16389.          ;                                                            ;
  16390.          ;    Function 5FH Subfunction 03H:                           ;
  16391.          ;                  Make Assign-List Entry                    ;
  16392.          ;    int add_alist_entry(psrcname,pdestname,uservalue,type)  ;
  16393.          ;        char *psrcname,*pdestname;                          ;
  16394.          ;        int  uservalue,type;                                ;
  16395.          ;                                                            ;
  16396.          ;    Returns 0 if new assign-list entry is made, otherwise   ;
  16397.          ;    returns error code.                                     ;
  16398.          ;                                                            ;
  16399.          ;************************************************************;
  16400.  
  16401.  cProc   add_alist_entry,PUBLIC,<ds,si,di>
  16402.  parmDP  psrcname
  16403.  parmDP  pdestname
  16404.  parmW   uservalue
  16405.  parmW   type
  16406.  cBegin
  16407.          mov     bx,type         ; Get device type.
  16408.          mov     cx,uservalue    ; Get uservalue.
  16409.          loadDP  ds,si,psrcname  ; DS:SI = pointer to source name.
  16410.          loadDP  es,di,pdestname ; ES:DI = pointer to destination name.
  16411.          mov     ax,5f03h        ; Set function code.
  16412.          int     21h             ; Make assign-list entry.
  16413.          jb      aa_err          ; Exit if there was some error.
  16414.          xor     ax,ax           ; Else return 0.
  16415.  aa_err:
  16416.  cEnd
  16417.  
  16418.  \SAMPCODE\DOS_ENCY\SECTION5\FXN5F04H.ASM
  16419.  
  16420.          ;************************************************************;
  16421.          ;                                                            ;
  16422.          ;    Function 5FH Subfunction 04H:                           ;
  16423.          ;                  Cancel Assign-List Entry                  ;
  16424.          ;                                                            ;
  16425.          ;    int cancel_alist_entry(psrcname)                        ;
  16426.          ;        char *psrcname;                                     ;
  16427.          ;                                                            ;
  16428.          ;    Returns 0 if assignment is canceled, otherwise returns  ;
  16429.          ;    error code.                                             ;
  16430.          ;                                                            ;
  16431.          ;************************************************************;
  16432.  
  16433.  cProc   cancel_alist_entry,PUBLIC,<ds,si>
  16434.  parmDP  psrcname
  16435.  cBegin
  16436.          loadDP  ds,si,psrcname  ; DS:SI = pointer to source name.
  16437.          mov     ax,5f04h        ; Set function code.
  16438.          int     21h             ; Cancel assign-list entry.
  16439.          jb      ca_err          ; Exit on error.
  16440.          xor     ax,ax           ; Else return 0.
  16441.  ca_err:
  16442.  cEnd
  16443.  
  16444.  \SAMPCODE\DOS_ENCY\SECTION5\FXN62H.ASM
  16445.  
  16446.          ;************************************************************;
  16447.          ;                                                            ;
  16448.          ;       Function 62H: Get Program Segment Prefix Address     ;
  16449.          ;                                                            ;
  16450.          ;       int get_psp()                                        ;
  16451.          ;                                                            ;
  16452.          ;       Returns PSP segment.                                 ;
  16453.          ;                                                            ;
  16454.          ;************************************************************;
  16455.  
  16456.  cProc   get_psp,PUBLIC
  16457.  cBegin
  16458.          mov     ah,62h          ; Set function code.
  16459.          int     21h             ; Get PSP address.
  16460.          mov     ax,bx           ; Return it in AX.
  16461.  cEnd
  16462.  
  16463.  \SAMPCODE\DOS_ENCY\SECTION5\FXN63H.ASM
  16464.  
  16465.          ;************************************************************;
  16466.          ;                                                            ;
  16467.          ;   Function 63H: Get Lead Byte Table                        ;
  16468.          ;                                                            ;
  16469.          ;   char far *get_lead_byte_table()                          ;
  16470.          ;                                                            ;
  16471.          ;   Returns far pointer to table of lead bytes for multibyte ;
  16472.          ;   characters.  Will work only in MS-DOS 2.25!              ;
  16473.          ;                                                            ;
  16474.          ;************************************************************;
  16475.  
  16476.  cProc   get_lead_byte_table,PUBLIC,<ds,si>
  16477.  cBegin
  16478.          mov     ax,6300h        ; Set function code.
  16479.          int     21h             ; Get lead byte table.
  16480.          mov     dx,ds           ; Return far pointer in DX:AX.
  16481.          mov     ax,si
  16482.  cEnd
  16483.  
  16484.  \SAMPCODE\DOS_ENCY\SECTION5\INT20H.ASM
  16485.  
  16486.  ;************************************************************;
  16487.  ;                                                            ;
  16488.  ;                     Perform a final exit.                  ;
  16489.  ;                                                            ;
  16490.  ;************************************************************;
  16491.          int     20H     ; Transfer to MS-DOS.
  16492.  
  16493.  \SAMPCODE\DOS_ENCY\SECTION5\INT25H.ASM
  16494.  
  16495.  ;***************************************************************;
  16496.  ;                                                               ;
  16497.  ;      Interrupt 25H: Absolute Disk Read                        ;
  16498.  ;                                                               ;
  16499.  ;      Read logical sector 1 of drive A into the memory area    ;
  16500.  ;      named buff. (On most MS-DOS floppy disks, this sector    ;
  16501.  ;      contains the beginning of the file allocation table.)    ;
  16502.  ;                                                               ;
  16503.  ;***************************************************************;
  16504.  
  16505.          mov     al,0            ; Drive A.
  16506.          mov     cx,1            ; Number of sectors.
  16507.          mov     dx,1            ; Beginning sector number.
  16508.          mov     bx,seg buff     ; Address of buffer.
  16509.          mov     ds,bx
  16510.          mov     bx,offset buff
  16511.          int     25h             ; Request disk read.
  16512.          jc      error           ; Jump if read failed.
  16513.          add     sp, 2           ; Clear stack.
  16514.          .
  16515.          .
  16516.          .
  16517.  error:                          ; Error routine goes here.
  16518.          .
  16519.          .
  16520.          .
  16521.  buff    db      512 dup (?)
  16522.  
  16523.  \SAMPCODE\DOS_ENCY\SECTION5\INT26H.ASM
  16524.  
  16525.  ;****************************************************************;
  16526.  ;                                                                ;
  16527.  ;       Interrupt 26H: Absolute Disk Write                       ;
  16528.  ;                                                                ;
  16529.  ;       Write the contents of the memory area named buff         ;
  16530.  ;       into logical sector 3 of drive C.                        ;
  16531.  ;                                                                ;
  16532.  ;       WARNING: Verbatim use of this code could damage          ;
  16533.  ;       the file structure of the fixed disk. It is meant        ;
  16534.  ;       only as a general guide. There is, unfortunately,        ;
  16535.  ;       no way to give a really safe example of this interrupt.  ;
  16536.  ;                                                                ;
  16537.  ;****************************************************************;
  16538.  
  16539.          mov     al,2            ; Drive C.
  16540.          mov     cx,1            ; Number of sectors.
  16541.          mov     dx,3            ; Beginning sector number.
  16542.          mov     bx,seg buff     ; Address of buffer.
  16543.          mov     ds,bx
  16544.          mov     bx,offset buff
  16545.          int     26h             ; Request disk write.
  16546.          jc      error           ; Jump if write failed.
  16547.          add     sp,2            ; Clear stack.
  16548.          .
  16549.          .
  16550.          .
  16551.  error:                          ; Error routine goes here.
  16552.          .
  16553.          .
  16554.          .
  16555.  buff    db      512 dup (?)     ; Data to be written to disk.
  16556.  
  16557.  \SAMPCODE\DOS_ENCY\SECTION5\INT27H.ASM
  16558.  
  16559.  ;***************************************************************;
  16560.  ;                                                               ;
  16561.  ;       Interrupt 27H: Terminate and Stay Resident              ;
  16562.  ;                                                               ;
  16563.  ;       Exit and stay resident, reserving enough memory         ;
  16564.  ;       to protect the program's code and data.                 ;
  16565.  ;                                                               ;
  16566.  ;***************************************************************;
  16567.  
  16568.  Start:  .
  16569.          .
  16570.          .
  16571.          mov     dx,offset pgm_end  ; DX = bytes to reserve.
  16572.          int     27h                ; Terminate, stay resident.
  16573.          .
  16574.          .
  16575.          .
  16576.  pgm_end equ     $
  16577.          end     start
  16578.  
  16579.  \SAMPCODE\DOS_ENCY\SECTION5\TEST.ASM
  16580.  
  16581.  memS    =       0                ;Small memory model
  16582.  ?PLM    =       0                ;C calling conventions
  16583.  ?WIN    =       0                ;Disable Windows support
  16584.  
  16585.  include cmacros.inc
  16586.  include cmacrosx.inc
  16587.  
  16588.  sBegin  CODE                     ;Start of code segment
  16589.  assumes CS,CODE                  ;Required by MASM
  16590.  
  16591.          ;Microsoft C function syntax:
  16592.          ;
  16593.          ;     int addnums(firstnum, secondnum)
  16594.          ;         int firstnum, secondnum;
  16595.          ;
  16596.          ;Returns firstnum + secondnum
  16597.  
  16598.  cProc   addnums,PUBLIC           ;Start of addnums functions
  16599.  parmW   firstnum                 ;Declare parameters
  16600.  parmW   secondnum
  16601.  cBegin
  16602.          mov     ax,firstnum
  16603.          add     ax,secondnum
  16604.  cEnd
  16605.  sEnd    CODE
  16606.          end
  16607.  
  16608.  \SAMPCODE\DOS_ENCY\SECTION5\CMACROSX.INC
  16609.  
  16610.  ;       CMACROSX.INC
  16611.  ;
  16612.  ;       This file includes supplemental macros for two macros included
  16613.  ;       in CMACROS.INC: parmCP and parmDP. When these macros are used,
  16614.  ;       CMACROS.INC allocates either 1 or 2 words to the variables
  16615.  ;       associated with these macros, depending on the memory model in
  16616.  ;       use. However, parmCP and parmDP provide no support for automatically
  16617.  ;       adjusting for different memory models--additional program code
  16618.  ;       needs to be written to compensate for this. The loadCP and loadDP
  16619.  ;       macros included in this file can be used to provide additional
  16620.  ;       flexibility for overcoming this limit.
  16621.  
  16622.  ;       For example, "parmDP pointer" will make space (1 word in small
  16623.  ;       and middle models and 2 words in compact, large, and huge models)
  16624.  ;       for the data pointer named "pointer". The statement
  16625.  ;       "loadDP ds,bx,pointer" can then be used to dynamically place the
  16626.  ;       value of "pointer" into DS:BX, depending on the memory model.
  16627.  ;       In small-model programs, this macro would generate the instruction
  16628.  ;       "mov dx,pointer" (it is assumed that DS already has the right
  16629.  ;       segment value); in large-model programs, this macro would generate
  16630.  ;       the statements "mov ds,SEG_pointer" and "mov dx,OFF_pointer".
  16631.  
  16632.  
  16633.  checkDS macro        segmt
  16634.             diffcount = 0
  16635.             irp d,<ds,DS,Ds,dS>                  ; Allow for all spellings
  16636.                ifdif <segmt>,<d>                 ; of "ds".
  16637.                   diffcount = diffcount+1
  16638.                endif
  16639.             endm
  16640.             if diffcount EQ 4
  16641.                it_is_DS = 0
  16642.             else
  16643.                it_is_DS = 1
  16644.             endif
  16645.          endm
  16646.  
  16647.  checkES macro        segmt
  16648.             diffcount = 0
  16649.             irp d,<es,ES,Es,eS>                  ; Allow for all spellings
  16650.                ifdif <segmt>,<d>                 ; of "es".
  16651.                   diffcount = diffcount+1
  16652.                endif
  16653.             endm
  16654.             if diffcount EQ 4
  16655.                it_is_ES = 0
  16656.             else
  16657.                it_is_ES = 1
  16658.             endif
  16659.          endm
  16660.  
  16661.  loadDP  macro        segmt,offst,dptr
  16662.             checkDS segmt
  16663.             if sizeD                             ; <-- Large data model
  16664.                if it_is_DS
  16665.                   lds  offst,dptr
  16666.                else
  16667.                   checkES segmt
  16668.                   if it_is_ES
  16669.                      les  offst,dptr
  16670.                   else
  16671.                      mov  offst,OFF_&dptr
  16672.                      mov  segmt,SEG_&dptr
  16673.                   endif
  16674.                endif
  16675.             else
  16676.                mov  offst,dptr                   ; <-- Small data model
  16677.                if it_is_DS EQ 0
  16678.                   push ds                        ; If "segmt" is not DS,
  16679.                   pop  segmt                     ; move ds to segmt.
  16680.                endif
  16681.             endif
  16682.          endm
  16683.  
  16684.  loadCP  macro        segmt,offst,cptr
  16685.             if sizeC                             ; <-- Large code model
  16686.                checkDS segmt
  16687.                if it_is_DS
  16688.                   lds offst,cptr
  16689.                else
  16690.                   checkES
  16691.                   if it_is_ES
  16692.                      les  offst,cptr
  16693.                   else
  16694.                      mov  segmt,SEG_&cptr
  16695.                      mov  offst,OFF_&cptr
  16696.                   endif
  16697.                endif
  16698.             else
  16699.                push cs                           ; <-- Small code model
  16700.                pop  segmt
  16701.                mov  offst,cptr
  16702.             endif
  16703.          endm
  16704.