[Back to DOS SWAG index] [Back to Main SWAG index] [Original]

    ------------------------------------------------------------------------

    Echo Flag :         Permanent: N       Export: N      Personal Read: N

     BBS: IN-TECH         Conference: PASCAL          Imported: 11/14/1991
      To: DAVID HICKEY                    Num: 1442       Date: 10/31/1991
    From: MARK OUELLET                     Re: 0          Time: 10:51 pm
    Subj: >NUL REDIRECTION               Prvt: N          Read: N

        On 27 Oct 91, you, David Hickey, of 1:261/1108.0 wrote...

     DH> From the DOS prompt, I can redirect things easily.  But when I try it in
     DH> my program, it doesn't work at all.  Here's what I'm doing:
     DH>
     DH> EXEC ('C:\Pkzip.Exe', '-o c:\ra\ra.zip c:\ra\ralogs\ra.log >nul');
     DH>
     DH> The problem is that the information from Pkzip is not being redirected
     DH> to NUL
     DH> like I want it to.  It's obviously got to be something I'm not doing
     DH> right. Anyone know what it is?  I've tried everything I can think of.

    David,
            This might help you,

    Msg#:20994 *> PASCAL  Echo <*
    03/17/89 03:15:00
    From: ROSS WENTWORTH
      To: NORBERT LANGE
    Subj: REPLY TO MSG# 20986 (RE: REDIRECTING STDERR)
     > I'd appreciate seeing some code.  I've tried this before,
     > using a couple different methods, and couldn't seem to get
     > DOS to like redirecting StdErr.  I tried the $45 (Duplicate
     > File Handle) function as well with no success.

    Ok, here's a routine that can be easily modified to do the job. It replaces
    EXEC from the DOS unit and checks the "command line" for the redirection
    symbols ('>' and '<').  One minor change and it will redirect STDERR to the
    file (see comment below).
    {=============================================================}
    Unit Execute;

    Interface

    Procedure Exec(Path,CmdLine : String);

    Implementation

    Uses
      Dos;

    Function ExtractFileName(Var Line : String;Index : Integer) : String;

    Var
      Temp : String;

    Begin
      Delete(Line,Index,1);
      While (Index <= Length(Line)) AND (Line[Index] = ' ')
        Do Delete(Line,Index,1);
      Temp := '';
      While (Index <= Length(Line)) AND (Line[Index] <> ' ') Do
      Begin
        Temp := Temp + Line[Index];
        Delete(Line,Index,1);
      End;
      ExtractFileName := Temp;
    End;

    Procedure CloseHandle(Handle : Word);

    Var
      Regs : Registers;

    Begin
      With Regs Do
      Begin
        AH := $3E;
        BX := Handle;
        MsDos(Regs);
      End;
    End;

    Procedure Duplicate(SourceHandle : Word;Var TargetHandle : Word);

    Var
      Regs : Registers;

    Begin
      With Regs Do
      Begin
        AH := $45;
        BX := SourceHandle;
        MsDos(Regs);
        TargetHandle := AX;
      End;
    End;

    Procedure ForceDuplicate(SourceHandle : Word;Var TargetHandle : Word);

    Var
      Regs : Registers;

    Begin
      With Regs Do
      Begin
        AH := $46;
        BX := SourceHandle;
        CX := TargetHandle;
        MsDos(Regs);
        TargetHandle := AX;
      End;
    End;

    Procedure Exec(Path,CmdLine : String);

    Var
      StdIn   : Word;
      Stdout  : Word;
      Index   : Integer;
      FName   : String[80];
      InFile  : Text;
      OutFile : Text;

      InHandle  : Word;
      OutHandle : Word;
             { ===============>>>> }   { change below for STDERR }
    Begin
      StdIn := 0;
      StdOut := 1;                    { change to 2 for StdErr       }
      Duplicate(StdIn,InHandle);      { duplicate standard input     }
      Duplicate(StdOut,OutHandle);    { duplicate standard output    }
      Index := Pos('>',CmdLine);
      If Index > 0 Then               { check for output redirection }
      Begin
        FName := ExtractFileName(CmdLine,Index);  { get output file name }
        Assign(OutFile,FName);                    { open a text file      }
        Rewrite(OutFile);                         { .. for output         }
        ForceDuplicate(TextRec(OutFile).Handle,StdOut);{ make output same }
      End;
      Index := Pos('<',CmdLine);
      If Index > 0 Then               { check for input redirection }
      Begin
        FName := ExtractFileName(CmdLine,Index);  { get input file name }
        Assign(InFile,FName);                     { open a text file    }
        Reset(InFile);                            { for input           }
        ForceDuplicate(TextRec(InFile).Handle,StdIn);  { make input same }
      End;
      DOS.Exec(Path,CmdLine);           { run EXEC }
      ForceDuplicate(InHandle,StdIn);   { put standard input back to keyboard }
      ForceDuplicate(OutHandle,StdOut); { put standard output back to screen  }
      CloseHandle(InHandle);            { close the redirected input file     }
      CloseHandle(OutHandle);           { close the redirected output file    }
    End;

    End.

    {===============================================================}

    Use it exactly as you would the normal EXEC procedure:

      Exec('MASM.EXE','mystuff.asm');

    To activate redirection simply add the redirection symbols, etc:

      Exec('MASM.EXE',mystuff.asm >err.lst');

    One note of caution.  This routine temporarily uses extra handles.  It'
    s either
    two or four more.  The various books I have are not clear as two whether
    duplicated handles 'count' or not. My guess is yes.  If you don't plan on
    redirecting STDIN then remove all the code for duplicating it to cut your
    handle overhead in half.

                                        Ross Wentworth

    +++ FD 2.00
     Origin: St Dymphna's Retreat via Torrance BBS 213-370-9027 (1:102/345.1)

            Best regards,
            Mark Ouellet.

    --- ME2
     * Origin: The Doctor's Tardis, A point in time!! (Fidonet 1:240/1.4)
    ==============================================================================
     BBS: ®® The Information and Technology Exchan
      To: BUTCH ADAMS                  Date: 12-10Ä91 (18:00)
    From: RUSS PARKS                 Number: 3982   [101] PASCAL
    Subj: EXEC()                     Status: Public
    ------------------------------------------------------------------------------
    * In a bleating, agonizing plea to All, Butch Adams groaned:

    BA>       I'm wondering if I can get some insight as to how to
    BA>use the Exec() command in TP6. What I'm trying to do is this:
    BA> Exec('Type Filename|sort > newfilename', '');
    BA>I've even tried this:
    BA> Exec('Type', 'filename|sort > newfilename');

     Close, but no cigar :-) Try something like this:
            Exec('command.com', '/c type filename | sort > newfilename');

     The first parameter is the path to the program to be run. In this
    case, 'TYPE' is an internal DOS command so you need to run
    COMMAND.COM. The second parameter is a string with the command
    line arguments you want to pass to the program.
      P.S.: The '/c' part of the parameters tells COMMAND.COM to execute
    the command, then exit back to the program that originally
    called the COMMAND.COM. It's like loading COMMAND.COM, running
    a program, then typing 'EXIT'.
    Besta'Luck,
    Russ

    ---
     * Origin: Objectively.Speak('Turbo Pascal 6.0, YEAH!'); (1:170/212)
    ==============================================================================
     BBS: ®® The Information and Technology Exchan
      To: BUTCH ADAMS                  Date: 12-10Ä91 (21:07)
    From: MIKE COPELAND              Number: 4000   [101] PASCAL
    Subj: EXEC()                     Status: Public
    ------------------------------------------------------------------------------
     BA>       I'm wondering if I can get some insight as to how to use the
     BA>Exec() command in TP6. What I'm trying to do is this:

     BA> Exec('Type Filename|sort > newfilename', '');

     BA>I've even tried this:

     BA> Exec('Type', 'filename|sort > newfilename');

     BA>But still no result. Are we able to execute internal commands from
     BA>within a TP program? I've tried loading Command.Com first but all I get
     BA>is the shell to come up and sit there with a C> staring back at me. I
     BA>would appreciate any help with this.

       The process to execute any DOS-callable program/command is more than
    you're doing/showing here. Try the following:

    {$M 4096,0,0}  { allocate space for the child process }

      SwapVectors;
      Exec (GetEnv('COMSPEC'),'/C Type filename|sort > newfile');
      SwapVectors;
      if DosError > 0 then  { check the result of Exec }
        You_Have_A_Problem;
      if DosExitCode <> 0 then
        You_Have_A_Different_Problem;
      { If you get here, everything's okay... }

       Read the manual about SwapVectors, DosError, DosExitCode, GetEnv,
    Exec, the $M parameter, and all the stuff you don't understand here...

    --- msged 2.07
     * Origin: Hello, Keyboard, my old friend... (1:114/18.10)
    ==============================================================================
     BBS: ®® The Information and Technology Exchan
      To: ANDREW PARK                  Date: 12-10Ä91 (21:15)
    From: MIKE COPELAND              Number: 4001   [101] PASCAL
    Subj: PASCAL                     Status: Public
    ------------------------------------------------------------------------------
     AP>It's quite simple.
     AP>Here's an example
     AP>{$M,1025,0,0}  <-- I don't know what this means but you need anyways

       Well, it's very important: it states how much Stack, Heap_Min, and
    Heap_Max space you're reserving for the program to use (and how
    much space you're leaving for the child process to execute in).
    The last (2nd 0) is the most important, since failing to reduce
    this from the default of ALL memory will PREVENT the Exec from
    having any memory to do its work within. So, setting it to 0
    will say "reserve ALL of available memory (except for what's
    used by my program itself) for the DOS call I'm going to make
    from within my program".
       If you don't do this, it defaults to 640K - meaning "reserve NO
    memory for the exec".

     AP>Program Copying;
     AP>Uses dos;
     AP>begin
     AP>  exec ('Command.com','copy a:*.* b:');
          Exec (GetEnv('COMSPEC'),'/C copy a:* b:*');
     AP>end.
     AP>Something like that.  See the manual for Exec section.

       You should also wrap that Exec call within a pair of SwapVectors
    statements...before and after. Furthermore, it's a good idea to
    check DosError and DosExitCode after the action, so see if any
    problems occurred.
       Exec is very useful, but it carries a lot of "baggage" when used...

    --- msged 2.07
     * Origin: Hello, Keyboard, my old friend... (1:114/18.10)
    ==============================================================================
     BBS: ®® The Information and Technology Exchan
      To: KEVIN HIGGINS                Date: 01-04Ä92 (09:58)
    From: MARK OUELLET               Number: 4088   [101] PASCAL
    Subj: RE: HEAP KNOWLEDGE         Status: Public
    ------------------------------------------------------------------------------
        On 29 Dec 91, you, Kevin Higgins, of 1:128/74.0 wrote...

     KH> I still don't understand full use of the {$M} compiler directive.
     KH> The Pascal tome I have says nothing other than if you don't use New() or
     KH> GetMem() to set the HeapMin and HeapMax to 0. But it never says what to
     KH> set it to if you DO you New or GetMem. Nor could I find any reference on
     KH> ideal settings for a small program which Exec's another fairly small
     KH> program....

    Kevin,
            New() and GetMem() are used to allocate space
    (memory) off the heap (That which is left of the 640 K of
    dos memory after your program is loaded and DOS and your
    TSRs ect...) for variables that are created AT RUNTIME.
    Variables you declare in the usual way ie: Var X : Integer;
    allready have space allocated to them.

            The heap is used to allocate memory to dynamic
    variables ie: variables accessed through the use of
    pointers. These need to have memory allocated to them
    (Unless you are using the pointer to access a region of
    memory that allready contains information such as the
    keyboard buffer etc... those allready have memory allocated
    to them so you need NO MORE MEMORY TO USE THEM.) Those that
    *YOU* create such as linked lists need memory. Your program
    when compiled will only allocate 4 bytes for each pointer
    (Pointers need 2 words, one for the segment, one for the
    offset in that segment) thus the 4 bytes.

    As a rule of thumb, if you don't create dynamic variables
    then you can set the $M to: {$M 16384, 0, 0} which is the
    minimum.

    {$MStack space, minimum heap required to run, Max heap needed}

    Stack space is the memory needed to hold the stack of your
    program, each time you call a function or procedure from
    another one, the old adress is pushed onto the stack, it
    will pulled off when the called procedure finishes to find
    out where to go back and continue executing. Local
    variables, parameters are also saved on the stack so they
    are not lost or modified while the other procedure is
    running.

    So if you have recursive procedures (procedures that call
    themselfes) or use lots of parameters you could set a large
    stack. you will find this out through trial and error. If it
    doesn't run properly and halts with a *STACK OVERFLOW* error
    (TP runtime error 202) then you know you need to increase
    the stack space allocated to your program.

    The second parameter is use IF you create dynamic variables,
    it tells TP you need at least this much heap memory free to
    run correctly and that it should return to DOS with an error
    if at least that much is not free when you try to load your
    program.

    The last paramater is the Maximum heap memory you expect to
    use, it can be calculated if you know how much you are going
    to use like a big array. If you are using linked lists,
    which can not allways be evaluated as to how many items the
    list will contain, then you might decide to use it all.
    Setting the 3rd parameter to 655360. This won't leave any
    room to EXEC another program though.

    So if you intend to run another program from yours, say
    running PKUNZIP from a TP program of yours, then you should
    set Maximum Heap to a value lower than 655360. If you know
    PKUNZIP needs 55k to run without problems then you could
    simply say:

            655360 - (55 * 1024) = 599040

    and set $M to

    {$M 16384, 0, 599040} this will ensure you have at least 55k
    free for PKUNZIP yet giving you the maximum heap space at
    the same time.

    As allways if you don't use dynamic variables at all don't
    bother with it simply use

    {$M 16384, 0, 0} and you will allways have enough memory to
    run other programs from your TP programs (Unless you don't
    have enough memory to run them from DOS to begin with ;-) )

            Best regards,
            and a very Happy New Year
            Mark Ouellet.

    --- ME2
     * Origin: BaseBall for Windows, use the disks as bases ;-) (Fidonet 1:240/1.4)
    ==============================================================================
     BBS: ®® The Info-Tech BBS ¯¯
      To: SHANE RUSSO                  Date: 01-24Ä92 (15:00)
    From: MIKE COPELAND              Number: 5922   [101] $_PASCAL
    Subj: TP 6.0 -- MEMORY ALLOCATI  Status: Public
    ------------------------------------------------------------------------------
     SR>    Could anyone inform me how to use the $M directive correctly, and
     SR>    what it does exactly?

     SR>    Also, what the stack size, heap min and heap max are? (How do you
     SR>    calculate the stack size, heap min and heap max)

       There is no absolute, exact answer to this question, since every TP
    program has different characteristics and requirements.
    However, I will try to give you (and others) some basics, from
    which you can probably adjust and use as you learn what's right
    for _you_ (every programmer has different styles, which also
    affect the way the $M is used):

      {$M Stack,Heap_Min,Heap_Max}

       The Stack is used within your program for calls to subprograms
    (functions and procedures). Its size is dependent on (1) how
    deep your calls go (or recurse) and (2) how much parameter and
    local data is referenced during these calls. The worst case
    I've encountered is a recursive sort of strings, where each
    level of call requires all the resident data of the routine and
    the parameters passed (string data being so big) are saved on
    the Stack - too many levels of such action will exceed the max.
    available Stack value, 64K.
       So, if you're not making heavily-nested (or recursive) calls in your
    program, you won't need much Stack space - 8192 is probably plenty.

       Heap is data _you_ explicitly ask for (unlike the implicit data used
    by subprogram calls) - by New, GetMem (in TP), or by calling
    library routines which do (therefore, you're not always in
    control of this if you're using subroutine libraries you didn't
    create). The two parameters stated in the $M are for (1) the
    minimum value you want to reserve and (2) the maximum you want to allow.
       I don't know a good reason to ever use any value > 0 for the
    Heap_Min parameter, since the runtime will allocate what's
    needed (providing the Heap_Max still has something left) -
    perhaps performance. So, it's the Heap_Max that's critical for
    your consideration.
       I see 2 distinct things here, which are in conflict (and thus
    require management of this parameter): dynamic memory use in
    your program, and use of the Exec procedure to spawn a child
    process. If you don't ever do one of these things, then you have
    maximum use of the other; it's that simple 8<}}.
       However (!), doing this is not simple, if you're doing anything
    sophistocated with TP. For instance, if you must use data >64K,
    you've _got_ to use pointers - which implies dynamic memory
    allocation (and consumes the Heap. If, OTOH, you Exec to DOS to
    run other programs or DOS calls from within your program, you
    must leave sufficient memory for DOS to load that other
    program, etc. This, of course, depends on what you're Exec-ing.
       In either case, your program logic and application must determine
    how much Heap_Max to reserve. The default is 640K (all of
    conventional memory), which prevents _any_ child process
    Exec-ing. This default will allow maximum possible use of
    dynamic memory (New, GetMem); any need to Exec will require a
    reduced value for Heap_Max.
       I often do a bit of both in my programs, and I typically use the
    following $M parameter:

       {$M 8192,0,128000}

    and I change either Stack or Heap_Max as I encounter runtime errors
    during development. Everyone must do the same, for the reasons
    I stated above.
       Note that you _won't_ be able to play with this during development
    in the IDE, since that's a program already consuming a LOT of
    available memory.
       Hope I made some sense/cleared up some confusion/helped.

    --- msged 2.07
     * Origin: Hello, Keyboard, my old friend... (1:114/18.10)

    ------------------------------------------------------------------------

    Echo Flag :         Permanent: N       Export: N      Personal Read: N

     BBS: IN-TECH         Conference: PASCAL          Imported: 11/11/1991
      To: ZAK SMITH                       Num: 1295       Date: 11/03/1991
    From: TREVOR CARLSEN                   Re: 0          Time:  1:58 am
    Subj: >NUL REDIRECTION               Prvt: N          Read: N

     ZS> Change that to
     ZS> EXEC ('C:\COMMAND.COM','c:\pkzip.exe -o ..... >nul');

    I'd reckon that will not work on a majority of systems.  Better is ...

      exec(GetEnv('COMSPEC'),'c:\pkzip...etc');

    That way it is not command.com specific.

    TeeCee

    --- TC-ED   v2.01
     * Origin: The Pilbara's Pascal Centre (+61 91 732569) (3:690/644)

[Back to DOS SWAG index] [Back to Main SWAG index] [Original]