Batch file DOS systems programming via Peek.com

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
Aacini
Expert
Posts: 1914
Joined: 06 Dec 2011 22:15
Location: México City, México
Contact:

Batch file DOS systems programming via Peek.com

#1 Post by Aacini » 16 Mar 2015 18:02

After I wrote my Batch-Assembler, I reviewed some of my very old 16-bits assembly .COM programs. One of those programs is so special that I decided to "revive" it. PEEK.COM is a versatile program that can provide Batch files with a wide range of useful information, because it allows to have access to specific memory locations, or to execute a limited number of PC BIOS interrupts or MS-DOS functions.

PEEKdoc.bat Batch file below creates PEEK.COM and it is also an example program of its use. It show a description of PEEK.COM using the several video pages that the video card provides for that purpose.

EDIT 2015/04/08: I added the video scroll functions (INT:10:06 and INT:10:07) to PEEK.COM features. The code below generate the new PEEK.COM version.

Code: Select all

@echo off

rem PEEKdoc.bat: Create PEEK.COM program and show a menu-driven description of its use
rem Antonio Perez Ayala

setlocal EnableDelayedExpansion
if "%~1" equ ":getClickPos" goto %1

cd "%~P0"
if not exist PEEK.COM call :CreatePEEK.com

set LF=^
%empty line 1/2 don't remove%
%empty line 2/2 don't remove%
set "spaces="
for /L %%i in (1,1,80) do set "spaces= !spaces!"
set "menu=       1.PEEK   2.Video   3.Mouse    4.DOS     5.PSP    6.SYSVRS   7.MCB    exit"
set ESC_KEY=27
set HOME_KEY=71
set LEFT_ARROW=75     
set RIGHT_ARROW=77
set END_KEY=79

rem Load the descriptions into 7 video pages of 80x25 characters
title PEEK.COM Program Documentation
mode con: cols=80 lines=25
set /P "=Please wait, loading page: 1 " < NUL
for /F "delims=:" %%a in ('findstr /N /R /C:"^Page 1" "%~F0"') do set "skip=%%a"
set /A page=1, nextPage=page+1
rem Move cursor of page 1 to home
PEEK INT:10:02:1:0000 > NUL
for /F "skip=%skip% tokens=1* delims=:" %%a in ('findstr /N "^" "%~F0"') do (
   if "%%b" neq "Page !nextPage!" (
      set "line=%%b%spaces%"
      PEEK INT:10:09:!page!1F:"!line:~0,80!!LF!"
   ) else (
      rem This page ends: show the menu at bottom with this option selected
      set /A "this=page*10-5,rest=this+10"
      for /F "tokens=1-2" %%i in ("!this! !rest!") do (
         PEEK INT:10:09:!page!1F:"!menu:~0,%%i!":!page!0E:"!menu:~%%i,10!":!page!1F:"!menu:~%%j!"
      )
      rem Small adjustment in page 3's menu
      if !page! equ 3 (
         PEEK INT:10:02:03:184C > NUL
         PEEK INT:10:09:031F:"    "
      )
      rem Move the cursor at this menu option and leave it there
      call :DecToHex this
      PEEK INT:10:02:!page!:18!this:~-2! > NUL
      set /A page+=1, nextPage+=1
      if !page! equ 8 goto :@F
      rem Move cursor of next page to home
      PEEK INT:10:02:!page!:0000 > NUL
      set /P "=!page! " < NUL
   )
)
:@F
echo/

rem Change the display page via menu-driven input keys
set page=1
:nextPage
   PEEK INT:10:05:%page% > NUL
   if %page% neq 3 (
      PEEK INT:21:0C:07 > NUL
   ) else (
      call :MouseSelection
   )
   set key=%errorlevel%
   if %key% neq 0 (
      if 49 leq %key% if %key% leq 55 set /A page=key-48
   ) else (
      PEEK INT:21:07 > NUL
      set key=!errorlevel!
      if !key! equ %HOME_KEY% (
         set page=1
      ) else if !key! equ %LEFT_ARROW% (
         if %page% gtr 1 set /A page-=1
      ) else if !key! equ %RIGHT_ARROW% (
         if %page% lss 7 set /A page+=1
      ) else if !key! equ %END_KEY% (
         set page=7
      )
   )
if %key% neq %ESC_KEY% goto nextPage
PEEK INT:10:05:0 > NUL
cls
goto :EOF


rem Example of mouse use

:MouseSelection
setlocal
:getClick
for /F "tokens=1,2 delims=:" %%a in ('cmd /D /Q /C "%~F0" :getClickPos') do (
   set /A "col=%%a/8, row=%%b/8, colH=col, rowH=row"
)
rem Get the character at mouse click position
call :DecToHex colH
call :DecToHex rowH
PEEK INT:10:02:03:%rowH:~-2%%colH:~-2% > NUL
for /F "delims=" %%a in ('PEEK INT:10:08:03') do set "char=%%a"
rem Show position and character of mouse click
set "pos=%row%,%col%  "
PEEK INT:10:02:03:154A > NUL
PEEK INT:10:09:031F:"%pos:~0,5%"
PEEK INT:10:02:03:164B > NUL
PEEK INT:10:09:031F:"%char%"
if %row% neq 24 goto getClick
if %col% lss 5 goto getClick
if %col% gtr 74 goto getClick
set /A "selection=(col+5)/10+48"
exit /B %selection%


rem Wait for mouse button click and return its position

:getClickPos
PEEK INT:33:00 > NUL
for /L %%# in () do (
   ping -n 1 localhost > NUL
   PEEK INT:33:03 > NUL
   if errorlevel 1 PEEK INT:33:03 /D & exit
)


rem Convert a decimal number to a 4-digits (word) hexadecimal one

:DecToHex var
setlocal EnableDelayedExpansion
set "hexDigit=0123456789ABCDEF"
set "dec=!%1!"
set "hex="
for /L %%i in (1,1,4) do (
   set /A "nibble=dec&0x0F, dec>>=4"
   for %%h in (!nibble!) do set "hex=!hexDigit:~%%h,1!!hex!"
)
endlocal & set "%1=%hex%"
exit /B


rem Description of PEEK.COM program by pages

Page 1

                   1. Parameters and switches of PEEK.COM

PEEK seg:ofs  {/B|/W|/D}|[n [/L]]  [/H]

This program takes information from the memory address given by SEG:OFS params
and show it as a number of /Byte, /Word or /Doubleword size if anyone of these
switches are given; or as a character, or a string of length N, or until find a
zero delimiter if N is zero. If /L switch is also included, the length of the
string is displayed instead of its contents. A /Doubleword number is displayed
in two word parts this way: HIGH:LOW. /H switch show the result in hexadecimal.
The low byte of the result is also returned in ERRORLEVEL value.

SEG parameter may be `BIOS` word. This is a list of some useful BIOS values:

BIOS:4A /W         Number of columns in the text screen.
BIOS:62 /B         Current active display page (see INT:10:05:p in 2.Video).
BIOS:84 /B         Number of rows in the text screen minus one.
BIOS:85 /W         Height of the current text font characters in pixels.

If SEG parameter is `INT`, execute an Int this way: PEEK INT:int:fun:sub:data
as described below. Note that all parameters must be given in hexadecimal base.

Press: Home            <--           digit           -->             End    Esc
Page 2

                    2. Screen management via INT:10

INT:10:02:p:rrcc    Set cursor position of page P at row RR column CC (base 16).
INT:10:03:p /W      Read cursor position of video page P (/H = RRCC).
INT:10:05:p         Change active display page (max=3 or 7, see: BIOS:62 /B).
INT:10:06:ttll:bbrr Scroll the window delimited by TTop, LLeft, BBottom, RRight
INT:10:07:ttll:bbrr (base 16) up in function 06, or down in function 07.
INT:10:08:p /W      Read character and attribute from video page P (/H = AACC).
INT:10:09:ppaa:`s`  Show string `S` with attribute AA in video page PP (base 16)
                    several ppaa:`text` may be included: 10:09:1E:`One`:3C:`Two`

In functions 06/07 the number of lines may be given after last coordinate; the
attribute for new lines is taken from BBRR (function 06) or TTLL (function 07).

In the string of function 09, back-quote characters (Ascii 96) will be changed
by quotes, and an embedded LF (Ascii 10) will advance the cursor to new line.

Each video page store a complete text screen. The number of available pages
depends on the number of lines in the screen: 25 lines = 8 pages (0-7), 43/50
lines = 4 pages (0-3). A non-visible video page may be filled with text via
INT:10:09 and then displayed via INT:10:05. Don't use video page 0 this way.

Press: Home            <--           digit           -->             End    Esc
Page 3

                   3. Mouse management via INT:33

INT:33:00 /W       Initialize mouse, return number of buttons (2 or 3);
                   the mouse must be initialized before used.
INT:33:03 /W       Button pressed status: 1=left, 2=right, 4=center.
INT:33:03 /D       Mouse pointer position in X:Y order in pixels (divide by 8).

   REM INITIALIZE MOUSE
   PEEK INT:33:00 > NUL
   REM WAIT FOR A MOUSE BUTTON PRESSED
   :WAIT_FOR_CLICK
      PEEK INT:33:03 > NUL
   IF %ERRORLEVEL% EQU 0 GOTO WAIT_FOR_CLICK
   REM GET THE MOUSE POSITION AND SHOW IT
   FOR /F `TOKENS=1,2 DELIMS=:` %%A IN ('PEEK INT:33:03 /D') DO (
      SET /A `COL=%%A/8, LINE=%%B/8`
   )
   ECHO Mouse button pressed at line,col: %LINE%,%COL%

For a further example, see the code of this program.           Button click:
                                                               line,col =
                                                               character =
Select the desired option via a left-button mouse click:
Page 4

                   4. Values returned by DOS via INT:21

INT:21:01 [/B]     Keyboard input with echo (0 = first byte of extended key).
INT:21:07 [/B]     Direct keyboard input with no echo (0 = same as above).
INT:21:0B /B       Keyboard status: 255 = key ready, else = no key or EOF.
INT:21:0C:fun [/B] Flush input buffer, execute function FUN (must be 1 or 7).
INT:21:2A /D       Current date in system clock (/H = YYYY:MMDD).
INT:21:2C /D       Current time in system clock (/H = HHMM:SSCC).
INT:21:30 /W       MS-DOS version (/H = RRVV).
INT:21:44:09:d /W  Test disk unit D (1=A,2=B,...): 0 = not valid, else = valid.
INT:21:44:60:d /W  Type of disk in unit D. /H = MUDD:
                   M-  Media type: 0 = removable, 1 = fixed.
                   U-  Unit type:  0&1 = 5 1/4, 2,7&8 = 3 1/2, 5 = Hard disk.
                   DD- Disk type:  FD=360K, F9=1.2M/720K, F8=fixed, F0=1.44M.
INT:21:51 /W /H    Segment address of PEEK.COM's PSP program.
INT:21:52 /D /H    SEG:OFS address of SYSVARS data structure.

INT:21:07 is used in this documentation program to read cursor control keys.

The PSP is described in next page.
SYSVARS is described in page 6.

Press: Home            <--           digit           -->             End    Esc
Page 5

                   5. The Program Segment Prefix (PSP)

The PSP is a 256-byte area placed at beginning of the memory block of all
running programs. It contains several data about the program, like these items:

psp:16 /W /H       Segment address of parent's PSP (i.e. COMMAND.COM).
psp:2C /W /H       Segment address of the Environment block of this program.
psp:80 /B          Length of the parameters given to run this program.
psp:81 len         Parameters (command-line) given to run this program.

The Environment block is a memory area that store variables in this format:

   var1=value1_
   var2=value2_
   ...
   varN=valueN__
   Word count of how many strings follows (always 1)
   Path where the running program was loaded from_

The underscore indicate a byte with binary zero. MySet.bat file is an example
program that show the environment values of PEEK.COM running program.

Press: Home            <--           digit           -->             End    Esc
Page 6

                   6. The SYSVARS DOS data structure

Function 52H of Int 21H returns the address of SYSVARS (see page 4.DOS). This
is an area used by DOS to store several data, like the address-1 of the first
allocated memory block, that is stored at SYSVARS base address minus 2:


   FOR /F `TOKENS=1,2 DELIMS=:` %%A IN ('PEEK INT:21:52 /D /H') DO (
      SET SYSVARS_SEG=%%A
      SET SYSVARS_OFS=%%B
   )
   SET /A SYSVARS_OFS_MINUS2=0x%SYSVARS_OFS% - 2
   CALL :DECTOHEX SYSVARS_OFS_MINUS2
   FOR /F %%A IN ('PEEK %SYSVARS_SEG%:%SYSVARS_OFS_MINUS2% /W /H') DO (
      SET /A FIRST_BLOCK=0x%%A + 1
   )
   CALL :DECTOHEX FIRST_BLOCK


The address of the first allocated block is used to traverse the MCB chain, as
described in next page.

Press: Home            <--           digit           -->             End    Esc
Page 7

                   7. The Memory Control Block (MCB)

In the 16 bytes previous to all memory blocks there is a Memory Control Block
(MCB or `arena header`) that contain information about the block.

All MCB's in the system form a chain that starts at the first allocated block,
previously described. The data in the MCB of any block may be accessed via its
segment and `MCB` word in OFS parameter, plus an additional MCB offset.

seg:MCB:0          Identifier of each block in the chain: `M`=valid, `Z`=last.
seg:MCB:1 /W /H    PSP segment of the program owner of this block.
seg:MCB:3 /W       Size of this block in paragraphs (16 bytes).
seg:MCB:8 8        Name of program owner of this block (only in PSP segments).

Free memory blocks have 0 as owner, and blocks that belongs to DOS have an 8.

The first block allocated for DOS is further divided in sub-blocks with the
same MCB structure that store the additional data loaded when CONFIG.SYS file
is processed, like device drivers or the area required for FILES=. For further
information see MCB-Chain.bat file, that is an example program that walks
through the MCB chain and display diverse data about the blocks.

Press: Home            <--           digit           -->             End    Esc
Page 8


:CreatePEEK.COM

echo Please wait, creating PEEK.COM program

rem Create PutBytes.com auxiliary program, if not exists
if exist PutBytes.com goto :@F
setlocal DisableDelayedExpansion
set LF=^
%empty line 1/2 don't remove%
%empty line 2/2 don't remove%
< NUL (
   set /P "=ë0¬<"tZ^<'tV^<0rG^<9wC,0Šàë,Í!€þ,tâë4ŠðŠÔŠç€úÿ"
   setlocal EnableDelayedExpansion
   set /P "=tì€ìüëç³q€ëd·f€ïd2ä°‚‹ðü뽬<0rØ<9wÔ,0Õ!LF!"
   endlocal
   set /P "=Šàëï3ÀÍ!¬<,t£ëõŠð¬:Ætò:ÃtêŠÐŠçÍ!ëï"
) > PutBytes.com
endlocal
:@F

for /F "delims=:" %%a in ('findstr /N /R /C:"^PEEK.COM" "%~F0"') do set "skip=%%a"
(for /F "skip=%skip%" %%a in ('findstr "^" "%~F0"') do (
   set "lineHex=%%a"
   set "lineDec="
   for /L %%i in (1,1,32) do if defined lineHex (
      set /A "byte=0x!lineHex:~0,2!"
      set "lineDec=!lineDec!,!byte!"
      set "lineHex=!lineHex:~2!"
   )
   PutBytes !lineDec:~1!
   set /P "=." < NUL > CON
)) > PEEK.com

exit /B


PEEK.COM Object code in hexadecimal

e9f50053796e7461783a205045454b207365673a6f6673205b6e205b2f4c5d5d
20207c20207b2f427c2f577c2f447d20205b2f485d0d0a202020202020202050
45454b20494e543a696e743a66756e3a7375623a6461746124496e76616c6964
205345473a4f465320616464726573730d0a24496e76616c696420494e542070
6172616d65746572730d0a24496e76616c696420706172616d65746572287329
0d0a2400000000000000000100ffff42494f53494e543a4d43423a0000000000
0000000000000000000000000000000000000210031005100610071008100910
00330333012107210b210c212a212c2130214421512152218a0e800032ede30b
8d3e8100b020fcf3ae750d528d160301b409cd215ae97304817dff2f3f74ec4f
418bf78bd732e4ac3c227505f6d4eb0f900ae4750a3c6172063c7a77022c20aa
e2e50ae47403e956018bf28d3eaf01b90400f3a67506acba4000eb318bf28d3e
b301b90400f3a67507800ebb0101eb028bf2e81d0474168d165901f606bb0101
74048d167301b409cd21e9fe038916a5013c3a75e2f606bb010175158bd68d3e
b701b90400f3a67506ff0ea501eb028bf2e8de0375c18916a301f606bb010174
403c3a753ce8ca0375b88916a7013c3a752f803c227514468936be0133c9ac41
3c2275fa49890ebc01eb4ee8a40375928916a9013c3a7509e8970375858916ab
013c0d74343c207403e96bffac3c2074fb3c0d74243c2f7522acb4103c42740c
b4203c577406b4403c4475610826bb01ac3c2074fb3c0d754feb713c3072603c
39775c2c308ad0ac3c30720e3c39770a2c308ae2d50a8ad0ebed32f68916ad01
3c0d74483c207537ac3c2074fb3c0d743b3c2f752aac3c4c7513800ebb0102ac
3c2074fb3c0d74243c2f7513ac3c48750e800ebb0180ac3c2074fb3c0d740d52
8d168c01b409cd215ae9df02f606bb01017418f606bb0170750e833ead01ff75
def606bb010275d7e9e800c43ea301f606bb01707450268b05a3bc01268b4502
a3be018cc0f6c4f0750fb104d3e003c73d710475042680257f8ad0f606bb0170
7439f606bb0140740ca1be01e8a802b23ab402cd21a1bc01f606bb0110740232
e4e89302eb27800ebb01108b0ead0183f9ff751b268a158816bc01f606bb0180
7506b402cd21eb5e8ac2e88502eb570bc97501498bd9f606bb0102741932c0f2
ae7501412bd9891ebc018026bb01ef800ebb0120eb83268a15470ad2741cf606
bb01807506b402cd21eb0d518ac2e84102b220b402cd2159e2dc2bd90aff7402
b3ff881ebc01528d16a001b409cd215ae9d8018a26a501a0a3018d3ed201b913
00f2af75eba3ad013d061074053d07107541b40fcd10b403cd10528b16a90180
3ea3010674048b16a701b402cd10b408cd108adc5ab402cd10b410a0a3018afb
8b0ea7018b16ab018916a7018b16a901e9c6003d091075668b1ea701b403cd10
b901008b36be01833ebc01007421ac3c0a750632d2fec6eb0c3c607502b022b4
09cd10fec2b402cd10ff0ebc0175df46ac3c3a7526e83a0175218916a7013c3a
7519803c227514468936be0133c9ac413c2275fa49890ebc01eb9de90d013d02
10750b8a3ea7018b16a901eb4c903d031075078a3ea701eb40903d081075078a
3ea701eb349080fc337507a3a70132c0eb273d442175228b1ea901833ea70109
7417833ea701607403e9bf00c706a7010d00b960088d16c0018826e3058ae0a0
a701cd007316803eae0121750f803ead0144720833c033c933d2eb78803eae01
10750b803ead010375048bc2eb66803eae0133750f803ead010075040bc07454
8bc3eb50813ead0144217530833ea7010975068bc20c01eb3ba1c2012401b10c
d3e00a26c10150c606c00101b96008b80d44cd2158721da0d101eb18813ead01
512175048bc3eb0c813ead01522175048cc18bd3f606bb01407505a3bc01eb08
890ebe018916bc01e96efda0bc01b44ccd21b9040133d2ac3c3072183c39760a
3c4172103c46770c2c072c30d3e20ad032edebe30aedc3f606bb0180751433c9
bb0a0033d2f7f380c23052410bc075f3eb2cb90010f606bb01107402d0ed8bd0
d3ea80e20f80c23080fa39760380c2075280c1043acd75e6d0e9d0e932ed5ab4
02cd21e2f9c3

This is MySet.bat:

Code: Select all

@echo off
setlocal

rem MySet.bat: Show the values in the environment of PEEK.COM program
rem Antonio Perez Ayala

rem Define local variables with same sizes, so the environment don't change
set PSP=1234
set ENV=1234
set OFS=0000

rem Get the segment of PEEK.COM's PSP
for /F %%a in ('PEEK INT:21:51 /W /H') do set PSP=%%a

rem Get the segment of PEEK.COM's environment
for /F %%a in ('PEEK %PSP%:2C /W /H') do set ENV=%%a

:showVar

   rem Show this variable
   PEEK %ENV%:%OFS% 0

   rem Advance offset to next variable
   for /F %%a in ('PEEK %ENV%:%OFS% 0 /L') do set /A OFS=0x%OFS%+%%a+1
   call :DecToHex OFS

rem If there is another variable, go back for it
for /F %%a in ('PEEK %ENV%:%OFS% /B') do if %%a neq 0 goto showVar

rem Advance offset to PEEK.COM's path and show it
set /A OFS=0x%OFS%+3
call :DecToHex OFS
echo/
echo PEEK.COM's path:
PEEK %ENV%:%OFS% 0

goto :EOF


rem Convert a decimal number to a 4-digits (word) hexadecimal one

:DecToHex var
setlocal EnableDelayedExpansion
set "hexDigit=0123456789ABCDEF"
set "dec=!%1!"
set "hex="
for /L %%i in (1,1,4) do (
   set /A "nibble=dec&0x0F, dec>>=4"
   for %%h in (!nibble!) do set "hex=!hexDigit:~%%h,1!!hex!"
)
endlocal & set "%1=%hex%"
exit /B

This is MCB-Chain.bat:

Code: Select all

@echo off
setlocal EnableDelayedExpansion

rem MCB-Chain.bat: Walk through the DOS Memory Control Blocks chain and show data about the blocks
rem Antonio Perez Ayala

rem Initialize the array of sub-block types in DOS Data Segment
set type[B]=BUFFERS
set type[C]=BUFFERS /X
set type[D]=DEVICE
set type[E]=DEVICE Additional
set type[F]=FILES
set type[I]=IFS-Device
set type[L]=LASTDRIVE
set type[Q]=DEVICE (Q type)
set type[S]=STACKS
set type[T]=Temporary Area
set type[X]=FCBS

rem The name of block owner is valid only in sub-blocks type "D" or "I" (or "Q")
set valid_Types=DIQ

rem Initialize/Define all variables with their maximum lengths so several
rem executions of PEEK.COM preserve the Environment in the same place
set SYS_SEG=1234
set SYS_OFS=1234
set Segment=1234
set owner=1234
set owner_Name=12345678
set size=1234
set size_B=12345
set size_K=123
set first=FALSE
set MCB_ID=X
set PSP_ID=20CD
set HAVE_ENV=FALSE
set ENV_SEG=1234
set par_Len=126
set UMB=FALSE
set UMB_ID=SC
set region=0
set dec=65535
set hex=1234
set d=1
set hexDigit=0123456789ABCDEF

rem Get address of SYSVARS-2
for /F "tokens=1,2 delims=:" %%a in ('PEEK INT:21:52 /D /H') do (
   set SYS_SEG=%%a
   set /A SYS_OFS=0x%%b - 2
   call :DecToHex SYS_OFS
)

rem Get segment of first allocated memory block
for /F %%a in ('PEEK %SYS_SEG%:%SYS_OFS% /W /H') do (
   set /A Segment=0x%%a + 1
   call :DecToHex Segment
)

title DOS Memory Control Blocks chain
cls

:SHOW-HEADER
echo/
echo Seg.     Block size   Owner   Name       Type, Environment and Parameters
echo ----   -------------   ----   --------   --------------------------------
echo/
set first= TRUE

:PROC-MCB
rem Take data from this MCB and show they
for /F %%a in ('PEEK %Segment%:MCB:1 /W /H') do set owner=%%a
for /F %%a in ('PEEK %Segment%:MCB:3 /W /H') do set size=%%a
set /A size_B=0x%size%*16, size_K=(0x%size%+32)/64
set "size_B=     %size_B%"
set "size_K=   (%size_K%)"
for /F "delims=" %%a in ('PEEK %owner%:MCB:8 8') do set "owner_Name=%%a        "
rem If the owner is 0 or 8, the block belongs to MS-DOS
if %owner% equ 0000 set "owner_Name=MS-DOS  "
if %owner% equ 0008 set "owner_Name=MS-DOS  "
set /P "=%Segment%   %size_B:~-6% %size_K:~-6%   %owner%   %owner_Name:~0,8%   " < NUL

if %owner_Name% neq MS-DOS goto PROC-PSP


   rem Process blocks that belongs to MS-DOS

   rem If the owner is 0: the block is free
   if %owner% equ 0000 (
      echo -- Free Memory --
      goto NEXT-MCB
   )

   rem If is the first block of DOS: is the DOS Data Segment
   if %first% neq TRUE goto DOS-CODE

      echo DOS Data Segment:
      set first=FALSE

      :DOS-SUB-BLOCK

      rem Get the type of this sub-block
      for /F %%a in ('PEEK %Segment%:0') do set MCB_ID=%%a

      rem If the type is "M": DOS Data Segment ends (start a normal MCB)
      if %MCB_ID% equ M (
         set /A Segment=0x%Segment% + 1
         call :DecToHex Segment
         goto PROC-MCB
      )

      rem Take data from this DOS sub-block and show they
      for /F %%a in ('PEEK %Segment%:3 /W /H') do set size=%%a
      set /A size_B=0x%size%*16, size_K=(0x%size%+32)/64
      set "size_B=     %size_B%"
      set "size_K=   (%size_K%)"
      for /F "delims=" %%a in ('PEEK %Segment%:8 8') do set "owner_Name=%%a        "
      rem Owner name is valid only in sub-blocks type "D" or "I" (or "Q")
      if "!valid_Types:%MCB_ID%=!" equ "%valid_Types%" set "owner_Name=        "
      echo        %size_B:~-6% %size_K:~-6%          %owner_Name:~0,8%      !TYPE[%MCB_ID%]!

      rem Pass to next sub-block and go back to process it
      set /A Segment=0x%Segment% + 0x%size% + 1
      call :DecToHex Segment
      goto DOS-SUB-BLOCK

   :DOS-CODE
   rem The next DOS blocks are internal programs
   echo System Program
   goto NEXT-MCB


:PROC-PSP
rem If the block belongs to itself...
if %owner% neq %Segment% goto NOT-PSP
rem And have the "20CD" mark id (INT 20H) at beginning...
for /F %%a in ('PEEK %Segment%:0 /W /H') do set PSP_ID=%%a
if %PSP_ID% neq 20CD goto NOT-PSP

   rem Then it is a PSP

   rem Check if the PSP have an Environment block:
   set HAVE_ENV= TRUE
   rem - Get Environment block address from PSP:2C
   for /F %%a in ('PEEK %Segment%:2C /W /H') do set ENV_SEG=%%a
   rem - Check that the address points to a valid block (MCB id "M" or "Z")
   for /F %%a in ('PEEK %ENV_SEG%:MCB:0') do set MCB_ID=%%a
   if "%MCB_ID%" neq "M" if "%MCB_ID%" neq "Z" set HAVE_ENV=FALSE
   rem - Check that the Env block belongs to the PSP
   for /F %%a in ('PEEK %ENV_SEG%:MCB:1 /W /H') do set owner=%%a
   if %owner% neq %Segment% set HAVE_ENV=FALSE
   if %HAVE_ENV% equ TRUE (
      echo Program, Environment at Seg. %ENV_SEG%
   ) else (
      echo Program, don't have Environment
   )

   rem Check if the PSP have command-line parameters
   for /F %%a in ('PEEK %Segment%:80 /B') do set par_Len=%%a
   if %par_Len% geq 127 goto NEXT-MCB
   if %par_Len% equ 0 goto NEXT-MCB
   rem Show the first 38 chars. of command-line parameters
   if %par_Len% gtr 38 set par_Len=38
   for /F "delims=" %%a in ('PEEK %Segment%:81 %par_Len%') do set PARAM=%%a
   echo                               param:    %PARAM%
   set "PARAM="
   goto NEXT-MCB


:NOT-PSP
rem Check if this block is the Environment of its owner segment
for /F %%a in ('PEEK %owner%:2C /W /H') do set ENV_SEG=%%a
if %ENV_SEG% equ %Segment% (
   echo Environment of Seg. %owner%
   goto NEXT-MCB
)

rem Otherwise: this block is just PSP's data
echo Data of Seg. %owner%


:NEXT-MCB
rem Check if is there another MCB in the chain
if %size% equ 0 goto END

rem If is the last MCB in the chain (id = "Z"),
rem then an additional MCB chain may start in Upper Memory Blocks
for /F %%a in ('PEEK %Segment%:MCB:0') do set MCB_ID=%%a
if %MCB_ID% equ Z set UMB= TRUE

rem Pass to the next MCB in the chain
set /A Segment=0x%Segment% + 0x%size% + 1
call :DecToHex Segment

rem Check that the next MCB be valid (id = "M" or "Z")
for /F %%a in ('PEEK %Segment%:MCB:0') do set MCB_ID=%%a
if "%MCB_ID%" neq "M" if "%MCB_ID%" neq "Z" (
   if %UMB% neq TRUE echo Memory control blocks destroyed
   goto END
)

rem If the owner is 8 and the name is "SC" (after the last MCB in the chain),
rem then this MCB specify a "hole" before a new MCB chain in Upper Memory Blocks
for /F %%a in ('PEEK %Segment%:MCB:1 /W /H') do set owner=%%a
for /F %%a in ('PEEK %Segment%:MCB:8 2') do set "UMB_ID=%%a"
if %UMB% equ TRUE  if %owner% equ 0008  if "%UMB_ID%" equ "SC"  goto UMB-Region

rem Else: go back to process this MCB normally
goto PROC-MCB


:UMB-Region
rem Pass over the "hole" to reach the start of the new MCB chain in UMB
for /F %%a in ('PEEK %Segment%:MCB:3 /W /H') do set size=%%a
set /A Segment=0x%Segment% + 0x%size% + 1
call :DecToHex Segment
rem Show the header of the new MCB chain in UMB
echo/
echo/
set /A region+=1
echo Region # %region% in Upper Memory Blocks:
rem And go back to process it
goto SHOW-HEADER


:END
echo/
goto :EOF


rem Convert a decimal number to a 4-digits (word) hexadecimal one

:DecToHex var
set "dec=!%1!"
set "hex="
for /L %%i in (1,1,4) do (
   set /A "d=dec&0x0F, dec>>=4"
   for %%d in (!d!) do set "hex=!hexDigit:~%%d,1!!hex!"
)
set "%1=%hex%"
exit /B

PEEK.COM program is useful to explore some MS-DOS systems programmings concepts in a very simple way with Batch files, instead of using C or assembly language. For example, this is the output of previous MCB-Chain.bat file:

Image

Below there is a list of some web sites that provide further information about all this stuff:

Code: Select all

http://stanislavs.org/helppc
http://www.ctyme.com/rbrown.htm
http://collaboration.cmc.ec.gc.ca/science/rpn/biblio/ddj/Website/articles/DDJ/1988/8811/8811e/8811e.htm

I suggest you to review the "Batch Control Block" in Tables and Formats of the first link listed above. It represents a whole new research world that is directly related to Batch files! I think that the BCB is the 128-bytes data block of DOSX program that appears at segment D52E in previous MCB-Chain.bat output.

I tested these programs in an old Windows-XP computer and also in a modern Windows 8.1 one. I erroneously thought that old MS-DOS .COM programs will not run in modern Windows versions, but the .COM file format is still supported in any Windows computer that have a 32-bits CPU don't matters how modern it is, and there are a lot of them nowadays. This means that it is not time to abandon MS-DOS .COM programs yet!

Antonio

NOTE: PEEK.COM does not check the values provided to the INT's, so the program may fail if the values are outside of the valid ranges; for example, if you use INT:10 and try to move the cursor or show text outside of the screen limits.
Last edited by Aacini on 08 Apr 2015 22:03, edited 1 time in total.

miskox
Posts: 630
Joined: 28 Jun 2010 03:46

Re: Batch file DOS systems programming via Peek.com

#2 Post by miskox » 17 Mar 2015 00:57

Aacini wrote:snip


Wow. More work to do. I have to find some time to study these assembler codes. I really want to do that!

Tutorials usualy start with a Hello World! program but your example is a good start.

Thanks!

Saso

Aacini
Expert
Posts: 1914
Joined: 06 Dec 2011 22:15
Location: México City, México
Contact:

Re: Batch file DOS systems programming via Peek.com

#3 Post by Aacini » 08 Apr 2015 22:28

I added the video scroll functions (INT:10:6 and INT:10:7) to PEEK.COM program. Although I don't like large programs that have multiple functions and cryptic names, it is very easy to add more functions of the same type to an already working code. If you want to use the new scroll functions, just delete your PEEK.COM file, copy the new PEEKdoc.bat that is located at the first post of this thread as usual, and run it.

The new PEEK.COM's video scroll functions, besides all its original features, finally allowed me to complete a program I designed some time ago. It is a File Manager application that allows to perform basic file operations using a directory/file browser that resemble the GUI of Windows Explorer in some aspects. The result is pretty good!

Image


This is "Aacini's File Manager.bat":

Code: Select all

@if (@CodeSection == @Batch) @then


@echo off
goto begin


"Aacini's File Manager.bat": Basic file management via a text-mode browser
Antonio Perez Ayala

2015/04/08 - Version 0.1 (preliminary):
             - Directory browser
             - File browser ordered by date, size, name or extension
             - Execute file via Enter key

To do:
- Browse directory/file via its first letter
- Select individual files via Space key
- Select range of files via Shift-Space key
- Select several files via a wild-card or a range of dates/sizes
- File operations: Delete, Copy, Move

This Batch file requires PEEK.COM auxiliary program. Download it from:
http://www.dostips.com/forum/viewtopic.php?f=3&t=6342


:begin
setlocal EnableDelayedExpansion

rem Set in next variable the total number of lines in the cmd.exe window screen
set lines=43


mode con cols=80 lines=%lines%
title Aacini's  File  Manager
color 07

set /A firstRow=3, lastRow=lines-3, pageSize=lastRow-firstRow+1, dig1=0
set firstRowH=03
set hex=0123456789ABCDEF
for /L %%r in (%firstRow%,1,%lastRow%) do (
   set /A dig2=%%r %% 16
   if !dig2! equ 0 set /A dig1+=1
   for %%d in (!dig2!) do set lastRowH=!dig1!!hex:~%%d,1!
   set rowH[%%r]=!lastRowH!
)

set "spaces= "
for /L %%i in (1,1,6) do set "spaces=!spaces!!spaces!"

set /A HomeKey=-71, PageUp=-73, Ctrl_UpArrow=-141, UpArrow=-72
set /A DownArrow=-80, Ctrl_DownArrow=-145, PageDown=-81, EndKey=-79
set /A LeftArrow=-75, RightArrow=-77, EnterKey=13, EscKey=27

set "upKeys=/%HomeKey%/%PageUp%/%Ctrl_UpArrow%/%UpArrow%/"
set "downKeys=/%DownArrow%/%Ctrl_DownArrow%/%PageDown%/%EndKey%/"

set "myself=%~F0"
set "Path=%~DP0;%Path%"

setlocal DisableDelayedExpansion

:updateDirectory

cls
echo Loading directory data, please wait...

rem Get the list of existent directories
set "dir[1]=..%spaces:~0,33%"
set lastDir=1
for /D %%a in (*) do (
   set "name=%%a"
   set /A lastDir+=1
   setlocal EnableDelayedExpansion
   if "!name:~34,1!" equ "" (
      set "name=!name!%spaces%"
      set "name=!name:~0,35!"
   )
   for /F "tokens=1*" %%b in ("!lastDir! !name!") do endlocal & set "dir[%%b]=%%c"
)
for /L %%i in (1,1,%lastDir%) do set "n[%%i]=%%i"

rem Get the list of existent files
set lastFile=0
for %%a in (*.*) do (
   set "name=%%a"
   set /A lastFile+=1
   setlocal EnableDelayedExpansion
   if "!name:~34,1!" equ "" (
      set len=0
      for /L %%i in (5,-1,0) do (
         set /A "newLen=len+(1<<%%i)"
         for %%j in (!newLen!) do if "!name:~%%j,1!" neq "" set len=%%j
      )
      set /A len=33-len
      for %%i in (!len!) do set "name=!spaces:~0,%%i!ÿ!name!ÿ!spaces:~0,%%i!"
   )
   for /F "tokens=1* delims=:" %%b in ("!lastFile!:!name!") do endlocal & set "file[%%b]=%%c"
)

setlocal EnableDelayedExpansion

:showDirectory

rem Show the first page of directory browser

cls
echo/
echo %cd:~-79%
set "i=  %lastDir%"
set "j=  %lastFile%"
echo %i:~-3% Folders ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂ%j:~-3% Files ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
for /L %%i in (1,1,%pageSize%) do (
   set "i=  %%i"
   if %%i leq %lastFile% (
      if %%i leq %lastDir% (
         echo !i:~-3! !dir[%%i]:~-35!³!i:~-3! !file[%%i]:~-35!
      ) else (
         echo !spaces:~0,39!³!i:~-3! !file[%%i]:~-35!
      )
   ) else if %%i leq %lastDir% (
      echo !i:~-3! !dir[%%i]:~-35!³
   ) else (
      echo %spaces:~0,39%³
   )
)
echo  ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄ
PEEK INT:10:09:07:"   Cursor keys=Browse ³ Enter=Open ³":08:" [Shift-]Space=[Range] Select ":07:"³ Esc=Exit"

rem Directory selection

set "order=n"
set   "normalItem=^!dir[%%j]:~-35^!"
set "selectedItem=^!dir[%%j]:~0,35^!"
set "exitKeys=/%LeftArrow%/%EnterKey%/%EscKey%/%RightArrow%/"
call :select 26 %lastDir%
set key=%errorlevel%
if %key% equ %LeftArrow% set "key=%EnterKey%" & set "item=1"
if %key% equ %EnterKey% (
   for %%a in ("!dir[%item%]!") do endlocal & cd %%a
   goto updateDirectory
)
if %key% equ %EscKey% cls & goto :EOF

rem Else %key% equ %RightArrow%: Pass to file browser

rem Get file's data from JScript code
cls
echo Loading files data, please wait...
set "order="
for /F "tokens=1-8 delims=," %%i in ('CScript //nologo //E:JScript "%myself%"') do (
   if not defined order (
      if %%i neq 0 (
         set "cd[%%i]=%%j %%k"
         set "wd[%%i]=%%l %%m"
         set "ad[%%i]=%%n %%o"
         set "sz[%%i]=%%p"
      ) else (
         set "order=n"
      )
   ) else (
      set "n[%%i]=%%i"
      set "c[%%i]=%%j"
      set "w[%%i]=%%k"
      set "a[%%i]=%%l"
      set "s[%%i]=%%m"
      set "e[%%i]=%%n"
   )
)

set /A dAttr=sAttr=eAttr=07
set "nAttr=0F"
set "dName=Written"
set "dData=wd"
set "normal=-35"
set "selected=0,35"

:showFiles

rem Show the first page of file browser
cls
echo/
set "i=   %lastFile%"
echo %i:~-4% Files / 0 Selected     %cd:~-50%
PEEK INT:10:09:07:"ÄÄ#     ÄÄÄ":%dAttr%:"%dName%":07:":days     ÄÄÄÄÄÄ":%sAttr%:"Size     "
PEEK INT:10:09:%nAttr%:"Name":07:"ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ":%eAttr%:"Ext"
echo/
set   "normalItem=    ^!%dData%[%%j]^!     ^!sz[%%j]^!     ^!file[%%j]:~%normal%^!"
set "selectedItem=    ^!%dData%[%%j]^!     ^!sz[%%j]^!     ^!file[%%j]:~%selected%^!"
call :updateColumn 1 %lastFile%
PEEK INT:10:02:0:%lastRowH%00 > NUL
echo/
echo  ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄ
PEEK INT:10:09:07:"   Cursor keys=Browse ³ Enter=Open ³":08:" [Shift-]Space=[Range] Select ":07:"³ Esc=Menu"

set "exitKeys=/%LeftArrow%/%EnterKey%/%EscKey%/"
set "item="
:updateFile
if not defined item (
   call :select 4F %lastFile%
) else (
   call :updateItem 4F
)
set key=%errorlevel%
if %key% equ %LeftArrow% goto showDirectory
if %key% equ %EnterKey% (
   for %%j in (!%order%[%item%]!) do (
      for /F "tokens=1,2 delims=ÿ" %%a in ("!file[%%j]!") do (
         if "%%b" equ "" (set "aux=%%a") else set "aux=%%b"
      )
   )
   cls
   call "!aux!"
   pause
   goto showFiles
)

rem Else %key% equ %EscKey%: Open file menu

set /A letterO=79,letterS=83,letterD=68,letterM=77,letterC=67
set "dateOrders=CWA"
set "orders=%dateOrders%SNE"
set "dateName[C]=Created"
set "dateName[W]=Written"
set "dateName[A]=Accessd"

PEEK INT:10:06:0000:014F:2 > NUL
PEEK INT:10:02:0:0000 > NUL
PEEK INT:10:09:0F:"O":07:"rder":08:"   Select   Delete    Move   Copy     ":0F:"Esc":07:"=exit"
echo/
for /F %%a in ('PEEK INT:21:07 /B') do set "key=%%a"
if %key% equ %EscKey% cls & goto :EOF
if %key% gtr 90 set /A key-=32
if %key% neq %letterO% goto endif

   rem Order option
   PEEK INT:10:09:07:"Select order: date":0F:"C":07:"reated, date":0F:"W":07:"ritten, date":0F:"A"
   PEEK INT:10:09:07:"ccessed, ":0F:"S":07:"ize, ":0F:"N":07:"ame, ":0F:"E":07:"xtension " < NUL
   :getOrder
   for /F %%a in ('PEEK INT:21:07') do set "key=%%a"
   if "!orders:%key%=!" equ "%orders%" goto getOrder
   set "order="
   if "!dateOrders:%key%=!" neq "%dateOrders%" (
      set "dName=!dateName[%key%]!"
      set "dData=%key%d"
      set "order=%key%"
      set "key=d"
   )
   set /A dAttr=sAttr=nAttr=eAttr=07
   set "%key%Attr=0F"
   if /I %key% neq E (
      set "normal=-35"
      set "selected=0,35"
   ) else (
      set "normal=0,35"
      set "selected=-35"
   )
   if not defined order set "order=%key%"
   goto showFiles

:endif
if %key% equ 0 PEEK INT:21:07 /B > NUL
PEEK INT:10:06:0000:014F > NUL
set "i=   %lastFile%"
echo %i:~-4% Files/0 Selected       %cd:~-50%
goto updateFile



rem Subroutine that browse directories/files and exit with one of them selected

:select rightColH lastItem
set /A item=1, lastItem=%2, row=firstRow

:updateItem
PEEK INT:10:02:0:!rowH[%row%]!00 > NUL
set "i=  %item%"
for %%i in (%item%) do for %%j in (!%order%[%%i]!) do PEEK INT:10:09:70:"%i:~-3% %selectedItem%"
PEEK INT:10:02:0:!rowH[%row%]!00 > NUL
:getKey
for /F %%a in ('PEEK INT:21:07 /B') do set "key=%%a"
if "!exitKeys:/%key%/=!" neq "%exitKeys%" exit /B %key%
if %key% neq 0 goto getKey
for /F %%a in ('PEEK INT:21:07 /B') do set "key=-%%a"
if "!exitKeys:/%key%/=!" neq "%exitKeys%" (
   if %key% equ %RightArrow% if %lastFile% equ 0 goto getKey
   exit /B %key%
)

set "topItem="

if "!upKeys:/%key%/=!" neq "%upKeys%" (

   rem Key is anyone of HomeKey, PageUp, Ctrl_PageUp or UpArrow
   if %item% equ 1 goto getKey

   if %key% equ %HomeKey% (
      rem Skip/Jump to first item
      set /A rowItem=item+firstRow-1, item=1, row=firstRow
      if !rowItem! neq %row% set topItem=1
   ) else if %key% equ %PageUp% (
      rem Skip to top row, or jump to previous page
      if %row% gtr %firstRow% (
         set /A item-=row-firstRow, row=firstRow
      ) else (
         set /A item-=pageSize, row=firstRow
         if !item! lss 1 set item=1
         set /A topItem=item
      )
   ) else if %key% equ %Ctrl_UpArrow% (
      rem Skip/Jump to 10 items up
      set /A item-=10, row-=10
      if !item! lss 1 set /A row+=1-item, item=1
      if !row! lss %firstRow% set /A row=firstRow, topItem=item
   ) else ( rem %key% equ %UpArrow%
      rem Skip/Scroll to previous item
      if %row% gtr %firstRow% (
         set /A item-=1, row-=1
      ) else (
         for %%i in (%item%) do for %%j in (!%order%[%%i]!) do echo %i:~-3% %normalItem%
         PEEK INT:10:07:%firstRowH%00:%lastRowH%%1 > NUL
         PEEK INT:10:02:0:%firstRowH%00 > NUL
         set /A item-=1
      )
   )

   if not defined topItem (
      for %%i in (%item%) do for %%j in (!%order%[%%i]!) do echo %i:~-3% %normalItem%
   ) else (
      call :updateColumn !topItem! %lastItem%
   )

   goto updateItem

)

if "!downKeys:/%key%/=!" neq "%downKeys%" (

   rem Key is anyone of EndKey, PageDown, Ctrl_DownArrow or DownArrow
   if %item% equ %lastItem% goto getKey

   if %key% equ %EndKey% (
      rem Skip/Jump to last item
      set /A "item=lastItem, topItem=lastItem-(lastRow-firstRow), row=lastRow"
      if !topItem! lss 1 set /A topItem=1, row=lastItem+firstRow-1
   ) else if %key% equ %PageDown% (
      rem Skip to bottom row, or jump to next page
      if %row% lss %lastRow% (
         set /A item+=lastRow-row, row=lastRow
         if !item! gtr %lastItem% set /A item=lastItem, row=lastItem+firstRow-1
      ) else (
         set /A item+=pageSize, row=lastRow
         if !item! gtr %lastItem% set item=%lastItem%
         set /A "topItem=item-(lastRow-firstRow)"
      )
   ) else if %key% equ %Ctrl_DownArrow% (
      rem Skip/Jump to 10 items down
      set /A item+=10, row+=10
      if !item! gtr %lastItem% set /A row-=item-lastItem, item=lastItem
      if !row! gtr %lastRow% set /A "row=lastRow, topItem=item-(lastRow-firstRow)"
   ) else ( rem %key% equ %DownArrow%
      rem Skip/Scroll to next item
      if %row% lss %lastRow% (
         set /A item+=1, row+=1
      ) else (
         for %%i in (%item%) do for %%j in (!%order%[%%i]!) do echo %i:~-3% %normalItem%
         PEEK INT:10:06:%firstRowH%00:%lastRowH%%1 > NUL
         PEEK INT:10:02:0:%lastRowH%00 > NUL
         set /A item+=1
      )
   )

   if not defined topItem (
      for %%i in (%item%) do for %%j in (!%order%[%%i]!) do echo %i:~-3% %normalItem%
   ) else (
      call :updateColumn !topItem! %lastItem%
   )

   goto updateItem

)

goto getKey


:updateColumn topItem lastItem
set /A topItem=%1, lastItem=%2
PEEK INT:10:02:0:%firstRowH%00 > NUL
set /A botItem=topItem+pageSize-1
if %botItem% gtr %lastItem% set botItem=%lastItem%
for /L %%i in (%topItem%,1,%botItem%) do (
   set "i=  %%i"
   for %%j in (!%order%[%%i]!) do echo !i:~-3! %normalItem%
)
exit /B



@end



// JScript section

d1 = new Date();
d2 = new Date();

function date2str(d,dArr,i) {
   d2.setTime(d);
   var days = Math.floor((d1-d2)/86400000);
   dArr[i-1] = ("000"+days).slice(-4)+("000"+i).slice(-4);
   return ( d2.getFullYear()+"/"+
            (101+d2.getMonth()).toString().substr(1)+"/"+
            (100+d2.getDate()).toString().substr(1)+","+
            ("   "+days).slice(-4)+","
   );
}

var memvar = WScript.CreateObject("WScript.Shell").Environment("Process"),
    lastFile = parseInt(memvar("lastFile")), sep = String.fromCharCode(160),
    fso = new ActiveXObject("Scripting.FileSystemObject"),
    cd = new Array(), md = new Array(), ad = new Array(), sz = new Array(), ex = new Array();

for ( var i = 1; i <= lastFile; ++i ) {
   var name = memvar("file["+i+"]").split(sep);
   name = name[name.length<3?0:1];
   var file = fso.GetFile(name), size = file.Size;
   WScript.Stdout.WriteLine(
      i+","+
      date2str(file.DateCreated,cd,i)+
      date2str(file.DateLastModified,md,i)+
      date2str(file.DateLastAccessed,ad,i)+
      ("         "+size).slice(-10)
   );
   sz[i-1] = ("000000000"+size).slice(-10)+("000"+i).slice(-4);
   ex[i-1] = fso.GetExtensionName(name).toLowerCase()+("000"+i).slice(-4);
}

WScript.Stdout.WriteLine("0,as separator");

cd.sort();
md.sort();
ad.sort();
sz.sort();
ex.sort();
for ( i = 0; i < lastFile; ++i ) {
   var c = parseInt("1"+cd[i].slice(-4))-10000,
       m = parseInt("1"+md[i].slice(-4))-10000,
       a = parseInt("1"+ad[i].slice(-4))-10000,
       s = parseInt("1"+sz[i].slice(-4))-10000;
       e = parseInt("1"+ex[i].slice(-4))-10000;
   WScript.Stdout.WriteLine((i+1)+","+c+","+m+","+a+","+s+","+e);
}


Antonio

taripo
Posts: 228
Joined: 01 Aug 2011 13:48

Re: Batch file DOS systems programming via Peek.com

#4 Post by taripo » 10 Apr 2015 06:35

I have heard about peek and poke, the context was QBASIC

e.g.

http://www.petesqbsite.com/sections/tut ... memory.htm

Code: Select all

Test$ = "This is a test." 'Set the string Test$.
Address = SADD(Test$) 'Store the string's address in Address.
CLS
PRINT PEEK(Address) 'Get and show the value at the memory address 
                    'stored in Address,this value should be 84
                    '(ASCII character 84 is "T").
POKE Address, 65 'Writes value 65 to the memory location of the
                 'string's first letter, changing the
                 'letter into an "A". ASCII character 64 is "A".
PRINT Test$ 'Display what is stored in Test$
            'it should be: "Ahis is a test."


Though I am on Win7 64bit and haven't got QB running on it.

foxidrive
Expert
Posts: 6031
Joined: 10 Feb 2012 02:20

Re: Batch file DOS systems programming via Peek.com

#5 Post by foxidrive » 10 Apr 2015 06:51

peek.com was also a commonly used tool back in the MSDOS days to show you strings in any executable, not just in basic.

Antonio, your tool will work in 32 bit systems though it seems to me that the latest preference for new computers and reinstalls is for 64 bit systems...

That's not to say your work is not useful in any way, it's just that so many newbies will never have 32 bit systems.

Post Reply