{
   USING THE PROGRAM SEGMENT PREFIX (PSP) AS
         A TURBO PASCAL RECORD

      GARRY J. VASS [72307,3311]

  The program segement prefix is created by DOS
  whenever a program is initiated.  It is 256 decimal
  bytes (100 hexidecimal bytes) long and contains a
  mixed-bag of information that can be used by a Turbo
  program.  Some of the information in the PSP has
  been made obsolete by:

           1.  New releases of DOS; and
           2.  New releases of Turbo Pascal.

  For example, location 80 hex (128 decimal) contains
  the length of the command tail.  Locations 81 hex
  and beyond contain the tail itself (the "command
  tail", by the way, are the parameters passed to
  a program.  In the case of "format" the tail con-
  tains a drive specification, system option, and
  label option, such as, "a:/s/v".).  The old days
  of de-coding the command tail are gone, however,
  replaced by Turbo's PARAMSTR(1), PARAMSTR(2), etc.
  functions.

  The File Control Blocks (FCB) went out with DOS 3,
  although it is still possible to use them.

  But several interesting items remain that can be
  found conveniently only in the PSP:

         1.  The address of the environment string; and
         2.  The amount of memory available.

  The segment address of the environment string is located
  at PSP address 2C hex (44 decimal).  This is equivalent
  to absolute address CSEG:002C.  (NOTE:  If you are using
  debug, pepores, corelook, etc to check this out, remember
  that it will appear in low-byte-followed-by-high-byte
  format.)

  Decoding the environment string works as follows:

         1.  Set Eseg to MEM[Cseg:2C], or PSP.ENVIRONMENT_SEGMENT.
             Start with offset address zero;
         2.  Concatenate the character value of
             the byte at Eseg:offset to a character string;
         3.  Increment the offset address and
             repeat step 2.
         4.  If the byte at Eseg:offset is equal to zero,
             then one string has been found.
         5.  If two consequtive bytes are equal to zero,
             then you have reached the end of the environment
             area.

  Normally, the environment strings are 10 hex paragraphs long
  (or 160 decimal bytes).  Some folks patch command.com and others
  use config.sys options to reset this value, and as Turbo programmers,
  we must accomodate them.  (The easiest way to give yourself more
  environment space is to use the SHELL statement in your config.sys
  file.  For example:  SHELL=C:\COMMAND.COM /P /E:20, will give you
  20 hex paragraphs.)  This, combined with Turbo's limitation of
  255 decimal bytes for a maximum string length, means that a REPEAT/
  UNTIL construct is necessary.

  Another item worth checking is the memory size DOS thinks it has.
  This is given in Cseg:0002, or PSP.MEMORY_SIZE_IN_PARAGRAPHS.

  The functions, ENVIRONMENT and MEMORY, provide at least one way
  of getting at these values.

}
PROGRAM PSP;
TYPE
    ANYSTRING = STRING[255];
    PSPAREA = RECORD
                    INT_20_INSTRUCTION         :INTEGER;
                    MEMORY_SIZE_IN_PARAGRAPHS  :INTEGER;
                    RESERVED_BYTE              :BYTE;
                    CALL_TO_DOS                :ARRAY[1..05] OF BYTE;
                    TERMINATE_VECTOR           :ARRAY[1..02] OF INTEGER;
                    BREAK_VECTOR               :ARRAY[1..02] OF INTEGER;
                    ERROR_VECTOR               :ARRAY[1..02] OF INTEGER;
                    USED_BY_DOS                :ARRAY[1..22] OF BYTE;
                    ENVIRONMENT_SEGMENT        :INTEGER;
                    DOS_WORK_AREA              :ARRAY[1..34] OF BYTE;
                    INT21_INSTRUCTIONS         :ARRAY[1..03] OF BYTE;
                    MORE_RESERVED              :INTEGER;
                    FCB_1_EXTENSION            :ARRAY[1..07] OF BYTE;
                    FCB_1                      :ARRAY[1..09] OF BYTE;
                    FCB_2_EXTENSION            :ARRAY[1..07] OF BYTE;
                    FCB_2                      :ARRAY[1..20] OF BYTE;
                    PARAMETER_LENGTH           :BYTE;
                    PARAMETERS                 :ARRAY[1..127] OF CHAR;
              END;
VAR
   PSP    :PSPAREA ABSOLUTE CSEG:$0000;
   I      :INTEGER;
   OFFSET :INTEGER;
   MORE   :BOOLEAN;

FUNCTION  REALNUMBER(R:INTEGER):REAL;
BEGIN
     IF R < 0 THEN REALNUMBER := 65536.0 + R
              ELSE REALNUMBER := R;
END;

FUNCTION ENVIRONMENT(SEGMENT:INTEGER;VAR OFF:INTEGER; VAR MORE:BOOLEAN):ANYSTRING;
{GET THE NEXT ASCIIZ STRING FROM THE ENVIRONMENT}
VAR
    T       : ANYSTRING;
    OFFSET  : INTEGER;
BEGIN
     T      := '';
     OFFSET := OFF;
     REPEAT
           T      := T + CHR(MEM[SEGMENT:OFFSET]);
           OFFSET :=     SUCC(OFFSET);
     UNTIL (MEM[SEGMENT:OFFSET] = 0);
    IF (MEM[SEGMENT:OFFSET + 0] = 0) AND
       (MEM[SEGMENT:OFFSET + 1] = 0) THEN MORE := FALSE
                                     ELSE MORE := TRUE;
    ENVIRONMENT := T;
    OFF := OFFSET;
END;

FUNCTION MEMORY(MEMORYSIZE:INTEGER):REAL;
BEGIN
     MEMORY := REALNUMBER(MEMORYSIZE) * 16;
END;

BEGIN
     OFFSET := 0;
     REPEAT
          WRITELN('ENVIRONMENT STRING = ',ENVIRONMENT(PSP.ENVIRONMENT_SEGMENT,OFFSET,MORE));
     UNTIL NOT MORE;
     WRITELN('DOS THINKS IT HAS ',MEMORY(PSP.MEMORY_SIZE_IN_PARAGRAPHS):10:0,' BYTES AVAILABLE');
END.

y:

           1.  New releases of DOS; and
           2.  New releases of Turbo Pascal.

  For examp