Contributor: MARK OUELLET ------------------------------------------------------------------------ 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)