home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast2.iso / asmutil / usoftpd.zip / WHAT.ASM < prev   
Assembly Source File  |  1987-07-31  |  23KB  |  794 lines

  1.       TITLE      WHAT
  2.  
  3. ; Program WHAT.ASM
  4. ; Purpose Batch    file enhancer
  5. ; Input      Command line consisting of:
  6. ;         Command letter (with optional E for extended)
  7. ;         Optional prompt enclosed in double    quotes
  8. ;         Optional argument
  9. ; Output  Number in DOS    ERRORLEVEL and string in WHAT environment variable
  10.  
  11.       DOSSEG
  12.       .MODEL  small
  13.       PAGE      60,120
  14.       INCLUDE DOS.INC
  15.  
  16.       .STACK  100h
  17.  
  18.       .DATA
  19. help1      LABEL      BYTE
  20. DB 13,10,"            WHAT - Batch file enhancer",13,10,13,10
  21. DB "Command            Purpose        Argument   Environ       Exit           Extended",13,10
  22. DB "---------        -------        --------   -------       ----           ------",13,10
  23. DB "C[E] [""prompt""]    [chars]    Get        Allowable  Character   Character   Echo",13,10
  24. DB "            character   characters",13,10,13,10
  25. DB "S[E] [""prompt""]        Get string  None       String       Length      Echo",13,10,13,10
  26. DB "D[E]            Check DOS   None       Major       (Major*10)  Minor",13,10
  27. DB "                           version       +Minor      version",13,10,13,10
  28. DB "E[E]            Get environ None       Bytes       Bytes/10    10 bytes",13,10
  29. DB "            bytes left               bytes       in exit",13,10,13,10
  30. DB "F[E] filespec        Get file    Filespec   Kilobytes   Ks/10Ks     10Ks in",13,10
  31. DB "            size             (255=directory)       exit",13,10,13,10
  32. DB "K[E] [driveletter]    Get disk    Drive      Kilobytes   Ks/10Ks     10Ks in",13,10
  33. DB "            space                           exit",13,10,13,10
  34. DB "Press a key to continue . . .$"
  35. help2      LABEL      BYTE
  36. DB 13,"M[E]            Check        None       Kilobytes   Ks/10Ks     10Ks in",13,10
  37. DB "            memory                           exit",13,10,13,10
  38. DB "P            Check for   None       1=yes,0=no  1=yes,0=no  None",13,10
  39. DB "            printer",13,10,13,10
  40. DB "V [number]        Get/Set        New mode   Current or  Current or  None",13,10
  41. DB "            video mode           last mode   last mode",13,10,13,10
  42. DB "7            Check for   None       1=yes,0=no  1=yes,0=no  None",13,10
  43. DB "            coprocessor",13,10,13,10
  44. DB "A            Check for   None       1=yes,0=no  1=yes,0=no  None",13,10
  45. DB "            ANSI driver",13,10,13,10
  46. DB "Y[E]            Get current None       Directory   Level/Drive Drive",13,10
  47. DB "            directory",13,10,"$"
  48.  
  49. guess      DB      80         ; Prompt for string
  50. actual      DB      ?
  51. string      DB      80 DUP (0)
  52.  
  53. extend      DB      0         ; Flag    for extended command
  54. vid      DB      3         ; Video mode
  55. ans      DB      27,"[6n$"     ; ANSI    string to get current position
  56. overwrt      DB      8,8,8,8,"    $"; Overwrite ANSI characters
  57. delete      DB      8,8,8,"$"     ; Delete ANSI characters
  58.  
  59. what      DB      "WHAT="     ; Variable name
  60. lwhat      EQU      $-what
  61.  
  62. prompt      DW      0         ; Pointer to prompt
  63. lprompt      DW      0         ; Length of prompt
  64. arg      DW      0         ; Pointer to argument
  65. larg      DW      0         ; Length of argument
  66.  
  67. ; Command table
  68.  
  69. cmds      DB      "CSVDMEKFP7AY" ; Command character list
  70. lcmds      EQU      $-cmds     ;   and length    of list
  71.       EVEN
  72. table      DW      GetChar     ; Command procedure table
  73.       DW      GetStr
  74.       DW      DoVid
  75.       DW      GetDOS
  76.       DW      GetMem
  77.       DW      GetEnvSz
  78.       DW      GetDskSz
  79.       DW      GetFilSz
  80.       DW      VeriPrint
  81.       DW      VeriCop
  82.       DW      VerAnsi
  83.       DW      GetDir
  84.       DW      NoCmd
  85.  
  86. err1      DB      "Invalid command",7,13,10,"$"
  87. err2      DB      "Out of environment space",7,13,10,"$"
  88. err3      DB      "Must have DOS Version 2.0 or higher",7,13,10,"$"
  89.  
  90.       .CODE
  91. start:      mov      ax,@DATA        ; Starting execution address
  92.       mov      ds,ax            ; Initialize data segment
  93.  
  94.       @GetVer            ; Get DOS version
  95.       or      al,al            ; Is it    0?
  96.       jne      DOSOK            ; No? Continue
  97.       @DispStr err3            ; Yes? Quit for    1.x
  98.       int      20h
  99.  
  100. DOSOK:      mov      si,83h        ; Starting point in PSP
  101.       mov      ax,WORD PTR es:[5Dh]    ; Load command characters
  102.       cmp      al,' '        ; Is it    space?
  103.       jne      isarg            ; If no    argument, show help
  104.       call      Help
  105.  
  106. isarg:      cmp      ah,'E'        ; Extend flag?
  107.       jne      noextend        ; No? Continue
  108.       inc      extend        ; Yes? Turn on flag and    adjust pointer
  109.       inc      si
  110.  
  111. noextend: call      GetArg        ; Get argument from command line
  112.  
  113.       push      es            ; Save and load    DS into    ES
  114.       mov      bx,ds
  115.       mov      es,bx
  116.       mov      di,OFFSET cmds    ; Load pointer to command table
  117.       mov      cx,lcmds+1        ; Load length
  118.       repne      scasb            ; Find position    of command character
  119.       pop      es
  120.       sub      di,(OFFSET cmds)+1    ; Point    to procedure
  121.       shl      di,1            ; Adjust for word addresses
  122.       call      table[di]        ; Call the selected procedure
  123.  
  124.       push      ax            ; Save
  125.       push      es
  126.       call      DoEnviron        ; Put result in    environment string
  127.       or      ax,ax            ; Test for 0 before
  128.       pop      es            ;   restore
  129.       pop      ax
  130.       jz      done
  131.  
  132.       cmp      BYTE PTR es:[5Dh],'E'    ; Is it    Environment command
  133.       je      done            ; Yes? Skip message
  134.  
  135. error2:      @DispStr err2            ; Error    message
  136.  
  137. done:      @Exit                ; Quit with AL as return code
  138.  
  139. ; End of program - Start of procedures
  140.  
  141. ; Procedure GetChar
  142. ; Purpose   Get    a character from user
  143. ; Input        Allowable characters pointed to by "arg" (optional)
  144. ;        Prompt pointed to by "prompt" (optional)
  145. ; Output    Character in AX and    in "string"
  146.  
  147. GetChar      PROC
  148.  
  149.       call      ShowPrmpt        ; Display prompt if there is one
  150.  
  151. readkey:  @GetKey 0,1            ; Get a    key
  152.       cmp      al,13            ; Is it    carriage return?
  153.       jne      notcr            ; Yes? Continue
  154.       mov      al,"~"        ; Call it tilde
  155.                     ;   (use tilde in character list
  156.                     ;    if    you want to accept CR)
  157. notcr:      or      al,al            ; Is it    0 for extended key?
  158.       je      exkey            ; Special case
  159.  
  160.       mov      bl,al            ; Save a copy and swap
  161.       xchg      ah,al
  162.  
  163.       call      UpCase        ; Uppercase it
  164.  
  165.       xchg      ah,al            ; Swap back
  166.       mov      si,arg        ; Load pointer and length of argument
  167.       mov      cx,larg
  168.       jcxz      gotchar        ; If no    argument, quit early
  169.  
  170. ; Compare character to argument    to see if it's valid
  171.  
  172. argcheck: mov      ah,BYTE PTR es:[si]    ; Get character
  173.       inc      si            ; Increment index
  174.  
  175.       call      UpCase        ; Convert to uppercase
  176.  
  177.       cmp      ah,al            ; Is it    in argument?
  178.       je      gotchar        ; Yes? We're done
  179.       loop      argcheck        ;   else check another
  180.       @DispCh 7            ; Checked all, so ring bell
  181.       jmp      SHORT    readkey        ;   and    get another character
  182.  
  183. gotchar:  push      ax
  184.       cmp      extend,0        ; Is extend flag set?
  185.       jne      noecho        ; Yes? Don't echo
  186.       cmp      bl,"~"        ; Don't echo ~ (alias for CR)
  187.       je      noecho
  188.       @DispCh bl            ; Display valid    character
  189. noecho:      pop      ax
  190.       mov      string,al        ; Put the character in string
  191.       inc      actual        ; Length is one
  192.       ret
  193.  
  194. exkey:      @GetKey 0,1            ; Get second key in AL
  195.       mov      si,arg        ; Load pointer to argument
  196.       cmp      BYTE PTR es:[si],"`"    ; Is argument grave accent?
  197.                     ;   (use grave in character list if
  198.                     ;    you want to accept    extended keys)
  199.       je      gotext        ; Yes? Extended    character
  200.       @DispCh 7            ; No? Illegal, so ring bell
  201.       jmp      SHORT    readkey        ;   and    get another
  202. gotext:      mov      string[0],'0'        ; Extended flag    value is "0<char>"
  203.       mov      string[1],al
  204.       mov      actual,2        ; Length is 2
  205.  
  206.       ret
  207. GetChar      ENDP
  208.  
  209. ; Procedure GetStr
  210. ; Purpose   Get    a string
  211. ; Input        Prompt pointed to by prompt    (optional)
  212. ; Output    String in "string";    length to AX
  213.  
  214. GetStr      PROC
  215.  
  216.       call      ShowPrmpt        ; Display prompt if there is one
  217.  
  218.       cmp      extend,1        ; Extend flag true?
  219.       je      password        ; Yes? Then don't echo
  220.  
  221.       @GetStr guess,0        ; Get string (null-terminated)
  222.       jmp      SHORT    gotstr        ; Done
  223.  
  224. password: mov      bx,OFFSET string    ; Load offset of string    buffer
  225.       mov      cx,80            ; Maximum count
  226. nextkey:  @GetKey 0,1            ; Get key, no echo
  227.       cmp      al,13            ; Is it    carriage return
  228.       je      gotpass        ; Yes? Done
  229.       mov      [bx],al        ; No? Put key in buffer
  230.       inc      bx            ; Point    to next
  231.       loop      nextkey
  232.  
  233. gotpass:  sub      bx,OFFSET string    ; Adjust pointer to get    count
  234.       mov      actual,bl        ; Save count
  235.  
  236. gotstr:      @DispCh 13,10
  237.       mov      ax,bx            ; Save string length
  238.       ret
  239. GetStr      ENDP
  240.  
  241. ; Procedure GetDOS
  242. ; Purpose   Get    DOS version
  243. ; Input        None
  244. ; Output    Major or minor version in "string";    (major *10)+minor in AX
  245.  
  246. GetDOS      PROC
  247.       @GetVer            ; Get DOS version
  248.       mov      string,al        ; Put major in string
  249.       mov      bh,al            ; Save copy
  250.       mov      al,ah            ; Divide minor to get one digit
  251.       sub      ah,ah            ; Clear    top
  252.       mov      cl,10            ; Divide by 10
  253.       div      cl
  254.       xchg      al,bh            ; Exchange major and minor
  255.       mul      cl            ; Multiply major by 10
  256.       add      al,bh            ; (Major*10)+Minor - 3.2 is now    32
  257.       cmp      extend,1        ; Extend?
  258.       jne      gotver        ; No? Already got it
  259.       mov      string,bh        ; Save number
  260. gotver:      mov      actual,1        ; Save length 1
  261.       add      string,30h        ; Convert to ASCII
  262.       ret
  263. GetDOS      ENDP
  264.  
  265. ; Procedure GetEnvSz
  266. ; Purpose   Get    environment bytes available
  267. ; Input        None
  268. ; Output    Environment    bytes available
  269.  
  270. GetEnvSz  PROC
  271.       push      es            ; Save ES
  272.       call      GetEnv        ; Get the environment size
  273.       pop      es            ; Restore
  274.       sub      ax,cx            ; Subtract length used from total
  275.                     ;   length to get length remaining
  276.       call      BinToDec        ; Convert to string
  277.       call      Byticize        ; Handle values    too large for byte
  278.       ret
  279. GetEnvSz  ENDP
  280.  
  281. ; Procedure GetFilSz
  282. ; Purpose   Get    the size of a specified    file
  283. ; Input        Filespec pointed to    by "arg"
  284. ; Output    File size
  285.  
  286. GetFilSz  PROC
  287.       cmp      arg,0            ; File name argument?
  288.       jne      isfile
  289.       call      NoCmd
  290. isfile:      mov      di,arg        ; Point    to start and end of arg
  291.       mov      bx,larg
  292.       mov      BYTE PTR es:[bx+di],0    ; Make null-terminated
  293.  
  294.       push      ds
  295.       @OpenFil arg,0,es        ; Open file for    reading
  296.       pop      ds
  297.       jc      ferror        ; Error    if carry
  298.  
  299. notdir:      @GetFilSz ax
  300.       jc      ferror        ; Error    if carry
  301.       mov      cx,1000        ; Convert to thousands
  302.       div      cx
  303.       inc      ax            ; Round    up
  304.       jmp      SHORT    gotsize
  305.  
  306. ferror:      cmp      ax,5            ; Access denied? Probably a directory
  307.       jne      nofile        ; No file or some other    error
  308.       mov      ax,0FFh        ; Call directory size 255
  309.       jmp      SHORT    gotsize
  310. nofile:      sub      ax,ax            ; Size of nothing is 0
  311.  
  312. gotsize:  call      BinToDec        ; Convert to string
  313.       call      Byticize        ; Handle large values
  314.       ret
  315. GetFilSz  ENDP
  316.  
  317. ; Procedure GetDskSz
  318. ; Purpose   Get    K remaining on specified disk
  319. ; Input        Drive letter pointed to by "arg"
  320. ; Output    Disk space remaining
  321.  
  322. GetDskSz  PROC
  323.       sub      ax,ax            ; Assume default drive
  324.       cmp      arg,0            ; Was there an argument?
  325.       je      defdrive        ; No? Got drive
  326.       mov      al,BYTE PTR es:6Dh    ; Yes? Get drive letter
  327.       sub      al,'A'-1        ; Convert to binary
  328. defdrive: @ChkDrv al            ; Get disk space
  329.       cmp      ax,0FFFFh        ; Is drive valid?
  330.       jne      valid
  331.       call      NoCmd
  332. valid:      mul      bx            ; Sectors = sectors/cluster * clusters
  333.       mul      cx            ; Bytes    = bytes/sector * sectors
  334.       mov      cx,1000        ; Convert to thousand
  335.       div      cx
  336.       inc      ax            ; Round    up
  337.       call      BinToDec        ; Convert to string
  338.       call      Byticize        ; Handle large values
  339.  
  340.       ret
  341. GetDskSz  ENDP
  342.  
  343. ; Procedure GetMem
  344. ; Purpose   Get    memory available
  345. ; Input        None
  346. ; Output    Available memory
  347.  
  348. GetMem      PROC
  349.       int      12h            ; Get memory available in K
  350.       mov      bx,es            ; Get memory used
  351.       mov      cx,6            ; Convert to K
  352.       shr      bx,cl
  353.       sub      ax,bx            ; Calculate how    much is    left
  354.       sub      dx,dx            ; Clear    DX
  355.       mov      cx,1024        ; Multiply to get bytes
  356.       mul      cx
  357.       mov      cx,1000        ; Divide to get    thousands (not K)
  358.       div      cx
  359.       call      BinToDec        ; Convert to string
  360.       call      Byticize        ; Handle large values
  361.       ret
  362. GetMem      ENDP
  363.  
  364. ; Procedure VeriPrint
  365. ; Purpose   See    if LPT1    (PRN) is available
  366. ; Input        None
  367. ; Output    1 for yes or 0 for no
  368.  
  369. VeriPrint PROC
  370.       mov      ax,200h        ; Check    printer    status
  371.       sub      dx,dx            ;   for    main parallel printer (port 0)
  372.       int      17h
  373.       xchg      dx,ax            ; Put 0    (for error) in AX
  374.       test      dh,00101001b        ; Are any error    bits on?
  375.       jne      printerr        ; Yes? Leave 0
  376.       test      dh,10010000b        ; Are both operation bits on?
  377.       jz      printerr        ; No? Leave 0
  378.       inc      ax            ; Yes? Return 1
  379. printerr: call      BinToDec        ; Convert to string
  380.       ret
  381. VeriPrint ENDP
  382.  
  383. ; Procedure DoVid
  384. ; Purpose   Get    current    video mode and optionally set a    new mode
  385. ; Input        New    video mode pointed to by "arg" (optional)
  386. ; Output    Current video mode (before change)
  387.  
  388. DoVid      PROC
  389.       mov      ah,0Fh        ; Get video mode
  390.       int      10h
  391.  
  392.       cmp      larg,1        ; How many digits in mode?
  393.       jl      gotmode        ; None?    Get out
  394.       push      ax            ; Some?    Save mode
  395.       mov      bx,arg        ; Load address of argument string
  396.       mov      ax,es:WORD PTR [bx]    ; Get address of mode string
  397.       je      one            ; One digit - skip the reverse
  398.       xchg      ah,al            ; Reverse for two digits
  399.       sub      ax,'00'        ; Adjust from ASCII to numeric
  400.       aad                ; Convert to binary
  401.       jmp      SHORT    setmode
  402. one:      sub      al,'0'        ; Convert to numeric
  403. setmode:  sub      ah,ah            ; Set mode
  404.       int      10h
  405.       pop      ax            ; Restore
  406. gotmode:  cbw                ; Extend to AX
  407.       call      BinToDec        ; Convert to string
  408.       ret
  409. DoVid      ENDP
  410.  
  411. ; Procedure VeriCop
  412. ; Purpose   Check for coprocessor
  413. ; Input        None
  414. ; Output    1 for yes or 0 for no
  415.  
  416. VeriCop      PROC
  417.       int      11h            ; Check    peripherals
  418.       test      al,10b        ; Coprocessor
  419.       mov      ax,0            ; Assume no (don't change flags)
  420.       jz      no87            ; No? Done
  421.       inc      ax            ; Yes? Set to 1
  422. no87:      call      BinToDec        ; Convert to string
  423.       ret
  424. VeriCop      ENDP
  425.  
  426. ; Procedure VerAnsi
  427. ; Purpose   Check for ANSI driver
  428. ; Input        None
  429. ; Output    1 for yes or 0 for no
  430.  
  431. VerAnsi      PROC
  432.  
  433.       @DispStr ans            ; Print    ANSI string to get
  434.                     ;   cursor position
  435.       mov      ah,6            ; Check    for key
  436.       mov      dl,0FFh        ;   in buffer
  437.       int      21h
  438.       jnz      ansi            ; Done if ANSI
  439.       @DispStr overwrt        ; Overwrite ANSI string
  440.       sub      ax,ax            ; 0 if not ANSI
  441.       jmp      SHORT    gotansi
  442. ansi:      mov      ax,0C06h        ; Clear    returned ANSI keys
  443.       mov      dl,0FFh        ;   out    of buffer
  444.       int      21h
  445.       @DispStr delete        ; Delete ANSI string
  446.       mov      ax,1            ; Set 1    for true
  447. gotansi:  call      BinToDec        ; Convert to string
  448.       ret
  449. VerAnsi      ENDP
  450.  
  451. ; Procedure GetDir
  452. ; Purpose   Get    the current directory or drive
  453. ; Input        None
  454. ; Output    Current directory or drive in "string"; level or drive number in AX
  455.  
  456. GetDir      PROC      NEAR
  457.       cmp      extend,1        ; Extend flag true?
  458.       jne      directry        ; No? Get directory
  459.  
  460.       @GetDrv            ; Yes? Get drive
  461.       mov      ah,al            ; Copy
  462.       add      ah,'A'        ; Convert to drive letter
  463.       mov      string,ah        ; Put character    in string
  464.       inc      actual        ; Length 1
  465.       cbw
  466.       ret
  467.  
  468. directry: mov      si,OFFSET string    ; Load address for string
  469.       mov      BYTE PTR [si],"\"    ; Insert backslash (DOS    doesn't)
  470.       inc      si            ; Point    to next
  471.       @GetDir si
  472.       sub      cx,cx            ; Count    is zero
  473.       dec      si            ; Move pointer back to start
  474. findback: lodsb                ; Load
  475.       cmp      al,"\"        ; Is it    backslash?
  476.       jne      notslash        ; No? Continue
  477.       inc      dx            ; Yes? Increment level counter
  478. notslash: or      al,al            ; Is it    0?
  479.       loopne  findback        ; No? Repeat
  480.  
  481.       neg      cx            ; Negate to get    positive count
  482.       mov      actual,cl        ; Put level in variable
  483.       xchg      ax,dx
  484.       ret
  485. GetDir      ENDP
  486.  
  487. ; Procedure NoCmd
  488. ; Purpose   Return error for invalid command
  489. ; Input        None
  490. ; Output    None
  491.  
  492. NoCmd      PROC
  493.       @DispStr err1            ; Display error    and quit
  494.       @Exit      0
  495. NoCmd      ENDP
  496.  
  497. ; Procedure Byticize
  498. ; Purpose   Adjust word    values to fit in a byte
  499. ; Input        Value in AX
  500. ; Output    255    for word values, else value (no    extend)    or value*10 (extend)
  501.  
  502. Byticize  PROC
  503.       cmp      extend,0        ; Is extend flag set?
  504.       je      sizechk        ; No? Check size
  505.       sub      dx,dx            ; Yes? Clear DX
  506.       mov      bx,10            ; Divide by 10 to get 10-unit chunks
  507.       div      bx
  508.  
  509. sizechk:  or      ah,ah            ; Is it    255 or less?
  510.       je      byteOK
  511.       mov      al,0FFh        ; No? Call it 255
  512. byteok:      ret
  513. Byticize  ENDP
  514.  
  515. ; Procedure GetArg
  516. ; Purpose   Parse command line for argument and    prompt strings
  517. ; Input        Command line
  518. ; Output    Pointer to argument    in "arg"; length (or 0 if none)    in "larg"
  519. ;        Pointer to prompt in "prompt"; length (or 0    if none) in "lprompt"
  520.  
  521. GetArg      PROC
  522.       push      ax
  523.       push      es            ; Swap ES and DS
  524.       push      ds
  525.       pop      es
  526.       pop      ds
  527.  
  528. white:      lodsb                ; Load while white space
  529.       cmp      al,' '        ; Is it    space?
  530.       je      white            ; Throw    away
  531.       cmp      al,9            ; Is it    tab?
  532.       je      white            ; Throw    away
  533.       cmp      al,'"'                ; Is it quote?
  534.       je      promptit        ; Process
  535.       cmp      al,13            ; Is it    carriage return?
  536.       je      gotarg        ; Done
  537.  
  538.       sub      cx,cx
  539. qdone:      dec      si            ; Adjust
  540.       mov      es:arg,si        ; Save pointer to argument start
  541.  
  542. chars:      lodsb                ; Load while not white
  543.       cmp      al,' '        ; Is it    space?
  544.       je      nomore        ; Done
  545.       cmp      al,9            ; Is it    tab?
  546.       je      nomore        ; Done
  547.       cmp      al,13            ; Is it    carriage return?
  548.       loopne  chars            ; Throw    away
  549. nomore:      not      cx            ; Adjust count
  550.       mov      es:larg,cx        ; Save length
  551.       jmp      SHORT    gotarg
  552.  
  553. promptit: mov      di,si            ; Save pointer to start
  554.       sub      cx,cx            ; Clear    count
  555. inprompt: lodsb                ; Another
  556.       cmp      al,13            ; Is it    carriage return?
  557.       je      oneq            ; Yes? Treat one quote like character
  558.       cmp      al,'"'                ; Is it quote?
  559.       loopne  inprompt        ; No? Throw away
  560.       mov      es:prompt,di        ; Save prompt pointer
  561.       not      cx
  562.       mov      es:lprompt,cx        ;   and    length
  563.       jmp      SHORT    white        ; Get the argument
  564.  
  565. oneq:      mov      si,di            ; Restore
  566.       mov      cx,-1            ; Set count to -1
  567.       jmp      SHORT    qdone
  568.  
  569. gotarg:      push      es            ; Swap ES and DS back
  570.       push      ds
  571.       pop      es
  572.       pop      ds
  573.  
  574.       pop      ax
  575.       ret
  576. GetArg      ENDP
  577.  
  578. ; Procedure ShowPrmpt
  579. ; Purpose   If prompt, display it
  580. ; Input        Pointer to prompt
  581. ; Output    Prompt to screen
  582.  
  583. ShowPrmpt PROC
  584.       cmp      prompt,0        ; Is there a prompt?
  585.       je      noshow        ; If not, continue
  586.       push      ds            ; Save and restore DS
  587.       @Write  prompt,lprompt,,es    ; DOS Write function
  588.       pop      ds
  589.  
  590. noshow:      ret
  591. ShowPrmpt ENDP
  592.  
  593. ; Procedure DoEnviron
  594. ; Purpose   Convert a string to    an environment variable
  595. ; Input        String in "string"
  596. ; Output    String in "WHAT" environment variable;
  597. ;          AX has 0 for success, nonzero for    failure
  598.  
  599. DoEnviron PROC
  600.       call      GetEnv        ; Get environment size,    length,    address
  601.       mov      dx,ax            ; Save size and    length
  602.       mov      bx,cx
  603.  
  604. ; Find "WHAT="
  605.  
  606.       sub      di,di            ; Point    to start
  607.       sub      al,al            ; Search for zero
  608.       mov      si, OFFSET what    ; Point    source at "WHAT="
  609. findwh:      repne      scasb            ; Search
  610.       cmp      BYTE PTR es:[di],0    ; If double null, end of environment
  611.       je      gotend
  612.       jcxz      noroom        ; Error    if not found
  613.       push      di            ; Save
  614.       push      cx
  615.       mov      si,OFFSET what    ; Load address and length of "what"
  616.       mov      cx,lwhat        ;   for    comparison
  617.       repe      cmpsb            ; Compare
  618.       mov      si,di            ; Make copy
  619.       pop      cx            ; Restore
  620.       pop      di
  621.       jnz      findwh
  622.  
  623. ; Find end of "WHAT" variable
  624.  
  625.       xchg      di,si
  626.       repne      scasb            ; Find end of environment variable
  627.       xchg      si,di            ; Point    source to next variable
  628.  
  629. ; Calculate characters left to write
  630.  
  631.       mov      cx,bx            ; Load total characters
  632.       sub      cx,si            ; Subtract finished to get left
  633.  
  634. ; Move everything back to overwrite "WHAT="
  635.  
  636. movenv:      push      ds            ; Save DS
  637.       mov      ax,es            ; Copy to ES
  638.       mov      ds,ax
  639.       rep      movsb            ; Copy
  640.       mov      BYTE PTR es:[di],0    ; Put null at end in case of error
  641.       pop      ds            ; Restore
  642.  
  643. ; Check    environment space
  644.  
  645. gotend:      mov      al,actual        ; Load length of string
  646.       sub      ah,ah            ; Clear    top
  647.       add      ax,lwhat        ; Add length of    name
  648.       add      ax,di            ; Add position to get final length
  649.       cmp      ax,dx            ; Is it    longer than environment?
  650.       jge      noroom        ; Yes? Quit
  651.  
  652. ; Put WHAT= at end
  653.  
  654.       mov      si,OFFSET what    ; Load address and length of what
  655.       mov      cx,lwhat
  656.       rep      movsb
  657.  
  658. ; Put new string at end
  659.  
  660.       mov      si,OFFSET string    ; Load address and length of string
  661.       mov      cl,actual
  662.       rep      movsb
  663.       mov      WORD PTR es:[di],0    ; Put double null at end
  664.       sub      ax,ax            ; Return 0 for success
  665.       ret
  666.  
  667. noroom:      inc      ax            ; Return nonzero for fail
  668.       ret
  669. DoEnviron ENDP
  670.  
  671. ; Procedure GetEnv
  672. ; Purpose   Find and measure the environment
  673. ; Input        None
  674. ; Output    Segment of environment in ES, size in AX, length in    CX
  675.  
  676. GetEnv      PROC
  677.       mov      dx,es:10h        ; Load segment of COMMAND.COM
  678.       mov      es,dx            ;   into ES
  679.       mov      ax,es:2Ch        ; Load COMMAND.COM's environment
  680.       or      ax,ax            ; Is it    0?
  681.       jnz      secondry        ; No? This is a    secondary command
  682.                     ;   and    we have    its environment    in AX
  683.       dec      dx            ; Yes? This is original    COMMAND.COM
  684.       mov      es,dx            ;   so point ES    to paragraph before PSP
  685.       add      dx,es:03        ; Offset of environment    is 3 bytes in
  686.       add      dx,2            ; Adjust it back to PSP
  687.       mov      ax,dx            ; Put it in AX
  688. secondry:
  689.  
  690. ; Note:
  691. ; CodeView cannot debug    the previous section of    code, because the PSP
  692. ; addresses checked by the code    are those passed from DOS to CodeView,
  693. ; not addresses    passed from DOS    to the program.    To debug with CodeView,
  694. ; find the actual address of the environment:
  695.  
  696. ;     S    500:0 L    FFFF "COMSPEC="
  697.  
  698. ; When you find    the actual address, hard code it into your program:
  699.  
  700. ;      mov      ax,110Ch        ; Debug    line
  701.  
  702. ; Comment the line out for final assembly after    debugging.
  703.  
  704.       mov      si,ax            ; Save a copy
  705.       sub      dx,dx            ; Clear    DX for multiply
  706.       dec      ax            ; Get paragaraph before    environment
  707.       mov      es,ax            ; Load into DS
  708.       mov      ax,es:03        ; Size in paragraphs is    at byte    4
  709.       mov      cx,16            ; Multiply by 16
  710.       mul      cx
  711.       mov      es,si            ; Restore environment address
  712.       sub      di,di            ; Point    to start
  713.       mov      cx,ax            ; Load maximum count (size of
  714.       mov      bx,ax            ;   environment) and save a copy
  715.       sub      ax,ax            ; Search for double null
  716. null2:      repne      scasb            ; Look for null
  717.       jz      noerr            ; If not out of    space, continue
  718.       sub      ax,ax            ;   else error (return 0)
  719.       jmp      error2
  720. noerr:      cmp      BYTE PTR es:[di],0    ; Is it    double null?
  721.       jne      null2            ; No? Look again
  722.       mov      cx,di            ; Yes? Save length in CX
  723.       mov      ax,bx            ; Reload size to AX
  724.  
  725.       ret
  726. GetEnv      ENDP
  727.  
  728. ; Procedure BinToDec
  729. ; Purpose   Convert binary number in AX    to string
  730. ; Input        Value in AX
  731. ; Output    Value string in "string"; length of    string in "actual"
  732.  
  733. ; AL contains number to    be converted
  734.  
  735. BinToDec  PROC
  736.       push      ax
  737.       push      es
  738.       sub      cx,cx            ; Clear    counter
  739.       mov      bx,10            ; Get ready to divide by 10
  740.  
  741. getdigit: sub      dx,dx            ; Clear    top
  742.       div      bx            ; Remainder is last digit
  743.       add      dl,'0'        ; Convert to ASCII
  744.       push      dx            ; Put on stack
  745.       inc      cx            ; Count    character
  746.       or      ax,ax            ; Is quotient 0?
  747.       jnz      getdigit        ; No? Get another
  748.  
  749.       mov      actual,cl        ; Save number of digits
  750.       mov      ax,ds            ; Load DS to ES
  751.       mov      es,ax
  752.       mov      di,OFFSET string    ; Load source
  753.  
  754. putdigit: pop      ax            ; Get a    digit off stack
  755.       stosb                ; Store    it to string
  756.       loop      putdigit
  757.  
  758.       pop      es
  759.       pop      ax
  760.       ret
  761. BinToDec  ENDP
  762.  
  763. ; Procedure UpCase
  764. ; Purpose   Convert a character    to uppercase
  765. ; Input        Character in AH
  766. ; Output    Converted character    in AH
  767.  
  768. UpCase      PROC
  769.  
  770.       cmp      ah,"a"        ; Is character below lowercase?
  771.       jl      ok            ; If so, continue
  772.                     ;   else
  773.       cmp      ah,"z"        ; Is character above lowercase?
  774.       jg      ok            ; If so, continue
  775.                     ;   else
  776.       sub      ah,20h        ; Make it lowercase
  777. ok:      ret
  778. UpCase      ENDP
  779.  
  780. ; Procedure Help
  781. ; Purpose   Display syntax screens
  782. ; Input        None
  783. ; Output    Help to screen
  784.  
  785. Help      PROC
  786.       @DispStr help1        ; First    screen
  787.       @GetKey            ; Pause
  788.       @DispStr help2        ; Second screen
  789.       @Exit      0
  790. Help      ENDP
  791.  
  792.       END     start            ; End assembly
  793.  
  794.