home *** CD-ROM | disk | FTP | other *** search
/ Crawly Crypt Collection 1 / crawlyvol1.bin / program / books / pexec / pexeccbk.txt
Text File  |  1992-03-16  |  38KB  |  902 lines

  1. From terminator!umich!samsung!uunet!mcsun!unido!laura!heike!klute Mon May 14 14:07:18 EDT 1990
  2. Article 23835 of comp.sys.atari.st:
  3. Path: terminator!umich!samsung!uunet!mcsun!unido!laura!heike!klute
  4. >From: klute@heike.informatik.uni-dortmund.de (Rainer Klute)
  5. Newsgroups: comp.sys.atari.st
  6. Subject: Pexec Cookbook: Here it is
  7. Message-ID: <2156@laura.UUCP>
  8. Date: 14 May 90 06:53:57 GMT
  9. References: <A1431442603@thelake.mn.org>
  10. Sender: news@laura.UUCP
  11. Reply-To: klute@heike.informatik.uni-dortmund.de (Rainer Klute)
  12. Organization: University of Dortmund, FRG
  13. Lines: 885
  14.  
  15.  
  16. Many people asked for the Pexec Cookbook or wondered what it was. What I
  17. have and post hereby is a "preliminary version of the long-awaited Pexec
  18. cookbook". It was posted already some time ago ("those good old days")
  19. by Allan Pratt (Atari) in this newsgroup. I do not know if a newer
  20. version exists. - Appended to the Pexec Cookbook you will find some more
  21. comp.sys.atari.st articles on the subject of program calling. Hopefully
  22. you will find some useful information there!
  23.  
  24.   Dipl.-Inform. Rainer Klute      klute@heike.informatik.uni-dortmund.de
  25.   Univ. Dortmund, IRB             klute@unido.uucp, klute@unido.bitnet
  26.   Postfach 500500         |)|/    ...uunet!mcvax!unido!klute
  27. D-4600 Dortmund 50        |\|\    Tel.: +49 231 755-4663
  28.  
  29.  
  30. =================================== snip, snip
  31. ===================================
  32.  
  33.  
  34. Allan Pratt (Atari) on the subject of Pexec:-
  35.  
  36. This is in response to a request from Christian Kaernbach which I got
  37. from  BITNET: I can't reply directly to BITNET, but I'm sure other people
  38. will find this interesting, too: it's a preliminary version of the
  39. long-awaited Pexec cookbook!
  40.  
  41. In broad terms, the things you have to know about Pexec are that it
  42. starts up a process, lets it execute, then returns to the caller
  43. when that process terminates.  The "caller" -- the process which used Pexec
  44. in the first place -- has some responsibilities: it has to make memory
  45. available to the OS for allocation to the child, and it has to build
  46. up the argument string for the child.
  47.  
  48. All GEMDOS programs are started with the largest block of OS memory 
  49. allocated to them.  Except in very rare circumstances, this block
  50. is the one stretching from the end of the accessories and resident
  51. utilities to the beginning of screen memory. The point is that your
  52. program has probably been allocated ALL of free memory.  In order to
  53. make memory available for a child process, you have to SHRINK the
  54. block you own, returning the top part of it to GEMDOS.  The time to
  55. do this is when you start up.
  56.  
  57. If you use Alcyon C (from the developer's kit), you know that you
  58. always link with a file called GEMSTART.  If you've been paying 
  59. attention, you should have gotten the *new* GEMSTART from Compuserve
  60. (or from somebody else who got it): I wrote that GEMSTART.  In
  61. GEMSTART.S, there is a lot of discussion about memory models, and then
  62. a variable you set telling how much memory you want to keep or give back
  63. to the OS.  Make your choice (when in doubt, use STACK=1), assemble
  64. GEMSTART.S, call the result GEMSEXEC.O (or something), and link the
  65. programs which Pexec with that file rather than the normal GEMSTART.
  66.  
  67. Now here's a discussion of what GEMSTART has to do with respect to
  68. keeping or returning memory:
  69.  
  70. Your program is invoked with the address of its own basepage as
  71. the argument to a function (that is, at 4(sp).l).  In this basepage
  72. is the structure you can find in your documentation.  The interesting
  73. fields are HITPA (the address of first byte NOT in your TPA),
  74. BSSBASE (the first address of your bss) and BSSLEN (the length of
  75. your BSS).
  76.  
  77. Your stack pointer starts at HITPA-8 (because 8 is the length of the
  78. basepage argument and the dummy return PC on the stack).  The space from
  79. BSSBASE+BSSLEN to your SP is the "stack+heap" space.  Library malloc()
  80. calls use this space, moving a pointer called the "break" (in the
  81. variable __break, or the C variable _break if you use Alcyon C) up as it
  82. uses memory.  Your stack pointer moves down from the top as it uses
  83. memory, and if the sp and _break ever meet, you're out of memory.  In
  84. fact, if they ever come close (within a "chicken factor" of about 512
  85. bytes or 1K), malloc() will fail because it doesn't want your stack to
  86. overwrite good data. 
  87.  
  88. When a process starts, it gets *all* of memory allocated to it: from the
  89. end of any accessories or resident utilities up to the default screen
  90. memory.  If you want to use Pexec, you have to give some memory back to
  91. the OS.  You do this with the Mshrink call.  Its arguments are the
  92. address of the memory block to shrink (your basepage address) and the
  93. new size to shrink it to.  You should be sure to leave enough room above
  94. your BSS for a reasonable stack (at least 2K) plus any malloc() calls
  95. you expect to make.  Let's say you're writing "make" and you want to
  96. leave about 32K for malloc() (for your dependency structures).  Also,
  97. since make is recursive, you should leave lots of space for the stack -
  98. maybe another 16K.  The new top of memory that your program needs is:
  99.  
  100.     newtop = your bss base address + your bss size + 16K stack + 32K heap
  101.  
  102. Since your stack pointer is at the top of your CURRENT TPA, and you're about
  103. to shrink that, you'd better move your stack:
  104.  
  105.     move.l      newtop,sp
  106.  
  107. Now you want to compute your new TPA size and call Mshrink:
  108.  
  109.     move.l      newtop,d0
  110.     sub.l       basepage,d0     ; newtop-basepage is desired TPA size
  111.     move.l      d0,-(sp)        ; set up Mshrink(basepage,d0)
  112.     move.l      basepage,-(sp)
  113.     move.w      #$4a            ; fn code for Mshrink
  114.     trap        #1
  115.     add.l       #10,sp          ; clean up args
  116.  
  117. Now that you've shrunk your TPA, the OS can allocate this new memory to
  118. your child.  It can also use this memory for Malloc(), which is used
  119. occasionally by GEM VDI for blt buffers, etc.  Note that you only
  120. have to do this once, when you start up: after that, you can do as much
  121. Pexec'ing as you want.
  122.  
  123. When you want to exec a child, you build its complete filespec into one
  124. string, and its arguments into another.  The argument string is a little
  125. strange: the first character of the argument string is the length of the
  126. rest of the string!
  127.  
  128. Here is a simple system call: pass it the name of the file to execute
  129. and the argument string to use.
  130.  
  131.         long system(cmd,args)
  132.         char *cmd, *args;
  133.         {
  134.             char buf[128];
  135.  
  136.             if (strlen(args) > 126) {
  137.                 printf("argument string too long\n");
  138.                 return -1;
  139.             }
  140.             strcpy(buf+1,args);                 /* copy args to buffer+1 */
  141.             buf[0] = strlen(args);              /* set buffer[0] to len */
  142.             return Pexec(0,cmd,buf,0L);
  143.         }
  144.  
  145. The first zero in the Pexec call is the Pexec function code: load and
  146. go.  The cmd argument is the full filespec, with the path, file name,
  147. and file type.  The third argument is the command-line argument string,
  148. and the fourth argument is the environment pointer.  A null environment
  149. pointer means "let the child inherit A COPY OF my environment."
  150.  
  151. This call will load the program, pass the arguments and environment to
  152. it, and execute it.  When the program terminates, the call returns the
  153. exit code from the program.  If the Pexec fails (not enough memory, file
  154. not found, etc.) a negative code is returned, and you should deal with
  155. it accordingly.  Note that error returns from Pexec are always negative
  156. LONGS, while return codes from the child will have zeros in the upper 16 bits.
  157.  
  158. EXIT CODES:
  159.  
  160. GEMDOS, like MS-DOS before it, allows programs to return a 16-bit exit
  161. code to their parents when they terminate.  This is done with the
  162. Pterm(errcode) call.  The value in errcode is passed to the parent
  163. as the return value of the Pexec system call.  The C library function
  164. exit(errcode) usually uses this call.
  165.  
  166. Unfortunately, the people who wrote the startup file for the Alcyon C
  167. compiler didn't use this.  The compiler calls exit() with an error code,
  168. and exit() calls _exit(), but _exit always uses Pterm0(), which returns
  169. zero as the exit code.  I fixed this by rewriting GEMSTART.S, the file
  170. you link with first when using Alcyon.
  171.  
  172. Even though new programs return the right exit code, the compiler
  173. itself still doesn't.  Well, I have patched the binaries of all the
  174. passes of the compiler so they DO.  It isn't hard, and I will post
  175. instructions at a later date for doing it.  IF YOU DO THIS, PLEASE
  176. DON'T BOTHER OUR CUSTOMER SUPPORT PEOPLE IF IT DOESN'T WORK.  THEY
  177. DON'T KNOW ANYTHING ABOUT IT.
  178.  
  179. I hope that this little cookbook makes Pexec less mysterious.  I haven't
  180. covered such topics as the critical-error and terminate vectors, even though
  181. they are intimately connected with the idea of exec'ing children.  A more
  182. complete cookbook should be forthcoming.
  183.  
  184. If there are any errors or gross omissions in the above text, please
  185. let me know BY MAIL so I can correct them coherently.  Landon isn't
  186. here to check my semantics, so I may have missed something.  [Landon
  187. is on vacation in France until early September.]
  188.  
  189. ********************************************************************
  190.  
  191. C. Kaernbach's question was why his accessory, which basically did
  192. a Pexec from a file selector, didn't always work.  The answer is that
  193. it works when used within a program which has returned enough memory to
  194. the OS for the child.  Why might it bomb?  Because if a program has
  195. returned a *little* memory to the OS (only about 2K), a bug in Pexec 
  196. shows up that breaks the memory manager.  Accessories are strange beasts
  197. anyway, so for the most part combining two strange beasts (Accessories
  198. and Pexec) is bad news.
  199.  
  200. /----------------------------------------------\
  201. | Opinions expressed above do not necessarily  |  -- Allan Pratt, Atari Corp.
  202. | reflect those of Atari Corp. or anyone else. |     ...lll-lcc!atari!apratt
  203. \----------------------------------------------/        (APRATT on GEnie)
  204.  
  205. in article <767@saturn.ucsc.edu>, koreth@ssyx.ucsc.edu (Steven Grimm) says:
  206. > #include <osbind.h>
  207. > main()
  208. > {
  209. >       long basepage;
  210. >       basepage = Pexec(3, "test.tos", "", 0L);
  211. >       printf("basepage = %08lx\n", basepage);
  212. >       Pexec(4, 0L, 0L, basepage);
  213. >       printf("done\n");
  214. > }
  215.  
  216. The correct call for Pexec type 4 is "Pexec(4,0L,basepage,0L);"
  217.  
  218. The combination of load/nogo plus just-go does not work reliably.
  219. There are bugs in Pexec relating to memory ownership which cause trouble.
  220.  
  221. You should be able to determine something about where the bombs are,
  222. though: is the PC in ROM, or less than "basepage" (i.e. in the parent),
  223. or greater than basepage (i.e. in the child)?
  224.  
  225. I have a trick which *does* work for fooling with a child before it has
  226. started executing, but it is ugly.  I use it in my debugger.  What are
  227. you trying to do?  Maybe the same trick would work for you.  Mail me more
  228. explanation.
  229.  
  230. /----------------------------------------------\
  231. | Opinions expressed above do not necessarily  |  -- Allan Pratt, Atari Corp.
  232. | reflect those of Atari Corp. or anyone else. |     ...lll-lcc!atari!apratt
  233. \----------------------------------------------/
  234.  
  235. in article <1322@dasys1.UUCP>, stevef@dasys1.UUCP (Steve A. Feinstein) says:
  236. > Does anyone know
  237. > if there is anyway to, say load a program into the top of the TPA
  238. > and execute it up there.  So that when it exits, there won't be any holes?
  239.  
  240. There is one way to do this with Pexec, but it requires knowing how much
  241. memory the program will need (lots of heuristics here).
  242.  
  243. long topPexec(cmd,args,env,size)
  244. char *cmd, *args, *env;
  245. unsigned long size;
  246. {
  247.         unsigned long blocksize;
  248.         char *addr;
  249.         long ret;
  250.  
  251.         blocksize = Malloc(-1L);        /* find out size of largest block */
  252.         if (block < size) {
  253.                 return ENSMEM;          /* largest block not big enough! */
  254.         }
  255.         addr = Malloc(blocksize);       /* allocate that block */
  256.         Mshrink(addr,blocksize-size);   /* shrink it by size TSR needs */
  257.         ret = Pexec(0,cmd,args,env);    /* exec the TSR */
  258.         Mfree(addr);                    /* free the padding */
  259.         return ret;                     /* return the exit code */
  260. }
  261.  
  262. This procedure takes a "size" argument which is the amount of memory
  263. the program in question will need for its text, data, bss, basepage,
  264. environment, and stack/heap.  This is not a computable number: you
  265. have to figure it out empirically.  text+data+bss+env+10K or so should
  266. work, but you will always leave a small hole at the top of memory,
  267. because TSR's always Mshrink a little bit.
  268.  
  269. ============================================
  270. Opinions expressed above do not necessarily     -- Allan Pratt, Atari Corp.
  271. reflect those of Atari Corp. or anyone else.      ...ames!atari!apratt
  272. ============================================
  273.  
  274.  
  275. Attention Mark Williams, Beckmeyer, and Gert Poltiek, and anybody
  276. else interested:
  277.  
  278. There is a trick that some shells and compiler libraries use that lets
  279. you pass argument strings to programs which are longer than the 127
  280. bytes which fit in the command line area of the basepage.  Their trick
  281. is to put the word ARGV= in the environment, and follow it with a
  282. null-separated list of argument strings.  The list is terminated with
  283. another null. 
  284.  
  285. This scheme works pretty well, but has two drawbacks, one major and one
  286. minor. 
  287.  
  288. The minor drawback is that it defies the definition of what is in the
  289. environment: the environment should consist of strings of the form
  290. NAME=value<NUL> terminated by a final <NUL>.  This is minor because
  291. shells using this convention usually put the ARGV information at the end
  292. of the environment anyway. 
  293.  
  294. The major drawback is that you can't tell if the ARGV string in your
  295. environment is really meant for you.  Imagine you have the Mark Williams
  296. shell (msh), an editor compiled with Alcyon, and another utility like
  297. "echo" compiled with MWC.  Imagine further that the editor has a
  298. "shell-escape" command that lets you execute another program from within
  299. the editor. 
  300.  
  301. Do this:
  302.  
  303.         From msh (the MWC shell): start up the editor with the
  304.         command line arguments "this is a test."
  305.  
  306.         Tell the editor to execute the command "echo hello world."
  307.  
  308.         The "echo" command will echo "this is a test," not
  309.         "hello world."
  310.  
  311. What happened is that msh put "this is a test" in the environment for
  312. the editor (as well as in the command tail in the basepage).  The
  313. editor, not knowing any better, didn't put "hello world" in the
  314. environment before executing "echo." When "echo" started, it found
  315. "ARGV=this is a test" in its environment and echoed that. 
  316.  
  317. What is needed is a way for a program to tell if the "ARGV=" string in
  318. its environment is really intended for it, or is just left over from an
  319. earlier program.  There is a way to do this that doesn't affect old
  320. programs compiled without this fix. 
  321.  
  322. The new convention could be to place another string in the environment
  323. with your own basepage address, before Pexec'ing your child.  The child
  324. could start up, and check to see if its parent's basepage address (in
  325. its basepage) matches the address in the environment.  If it does match,
  326. the child will know that the ARGV= string is for it.  If it doesn't
  327. match, the child will know it was started from a non-MWC program like
  328. the editor above, and will look in its basepage for the command line. 
  329.  
  330. Note that if the parent's basepage isn't in the environment at all, but
  331. the ARGV= string is, the child must assume that the ARGV string is
  332. intended for it, just as it does now.  Therefore, old-style programs
  333. could still Pexec new-style children, and vice-versa. 
  334.  
  335. This would all require a change in the startup code that calls main(),
  336. and the exec() code which Pexec's the child. 
  337.  
  338. How about it, guys? If we could all agree on the name and format of this
  339. new environment variable, we could get rid of a serious flaw in Mark
  340. Williams' otherwise clever scheme.  Other shells could adopt this, too,
  341. and ultimately everybody would be able to kiss the 127-character
  342. command-line limit goodbye. 
  343.  
  344. For now, I propose that the environment variable in question be called
  345. PBP, and that its value be the decimal string of digits making up the
  346. parent's basepage.  The reason for this is that almost all libraries
  347. have an atol() function, where not all have an atolx() function. 
  348.  
  349. A shell using this trick, with a basepage at 366494 (decimal), could
  350. Pexec a child called "test.prg" with these strings in the environment:
  351.  
  352. ...
  353. PBP=366494<NUL>
  354. ARGV=test.prg<NUL>first<NUL>second<NUL>third<NUL><NUL>
  355.  
  356. In the startup code of the child, you would do something like this:
  357.  
  358. If there's a PBP= in the environment
  359.         If atol(PBP) == my parent's basepage
  360.                 get args from environment
  361.         else
  362.                 get args from command line
  363.         endif
  364. else
  365.         if there's an ARGV= in the environment
  366.                 get args from environment
  367.         else
  368.                 get args from command line
  369.         endif
  370. endif
  371.  
  372.  
  373. Does this sound reasonable? I would like to see this kind of thing
  374. become a standard, but until a safeguard like this is in place, I can't
  375. condone using ARGV= in the environment for finding your arguments.  It's
  376. too chancy just to assume that you were started by a program savvy to
  377. this scheme. 
  378.  
  379. /----------------------------------------------\
  380. | Opinions expressed above do not necessarily  |  -- Allan Pratt, Atari Corp.
  381. | reflect those of Atari Corp. or anyone else. |     ...lll-lcc!atari!apratt
  382. \----------------------------------------------/
  383.  
  384.  
  385. ==================================== The End
  386. ====================================
  387.  
  388.  
  389. -- 
  390. Article 543 of comp.sys.atari.st:
  391. Path:
  392. unido!mcvax!uunet!seismo!sundc!pitstop!sun!amdcad!ames!rutgers!uwvax!umn
  393. n-d-ub!umn-cs!ems!nis!stag!daemon
  394. >From: syntel!dal@stag.UUCP (Dale Schumacher)
  395. Newsgroups: comp.sys.atari.st
  396. Subject: shell p usage
  397. Message-ID: <326@stag.UUCP>
  398. Date: 3 Feb 88 14:17:46 GMT
  399. Article-I.D.: stag.326
  400. Posted: Wed Feb  3 15:17:46 1988
  401. Sender: daemon@stag.UUCP
  402. Lines: 176
  403.  
  404.  
  405.   <dumas@sumex-aim.stanford.edu> writes...
  406. > Question #1 : How MWC's msh is discovering who called it ?
  407. >  (desktop, or other...) it is in the local shell variable 'calledfrom'.
  408. > An other shell is able to tell the list of all parents programs...
  409. > The base page does not contain any backward pointer, so what is it ?
  410.  
  411. I'm not sure that MSH does* detect being called from the desktop.  What
  412. difference would it make (or does it in MSH).  The basepage, however,
  413. DOES* contain a "backward pointer" to the parent processes basepage.
  414. Here is a struct to clarify...
  415.  
  416. typedef struct
  417.         {
  418.         char    *p_lowtpa;              /* pointer to self (bottom of TPA) */
  419.         char    *p_hitpa;               /* pointer to top of TPA + 1 */
  420.         char    *p_tbase;               /* base of text segment */
  421.         long    p_tlen;                 /* length of text segment */
  422.         char    *p_dbase;               /* base of data segment */
  423.         long    p_dlen;                 /* length of data segment */
  424.         char    *p_bbase;               /* base of BSS segment */
  425.         long    p_blen;                 /* length of BSS segment */
  426.         char    *p_dta;                 /* pointer to current DTA */
  427.         char    *p_parent;              /* pointer to parent's basepage */
  428.         char    *p_reserved;            /* reserved for future use */
  429.         char    *p_env;                 /* pointer to environment string */
  430.         long    p_undefined[20];        /* scratch area... don't touch */
  431.         char    p_cmdlin[128];          /* command line image */
  432.         }
  433.         BASEPAGE;
  434.  
  435. > Question #2 : I read again the dev kit doc on shell_p, the posting
  436. > by A.Pratt about it, and I still wonder : what is it ?
  437. > I would infer it is a pointer to a string telling the file name of a shell...
  438. > I am right ?
  439. > What would be the use otherwise ?
  440.  
  441. The shell_p variable, if it is valid, should point to a routine which
  442. will take a string argument and process it like the Un*x system() call.
  443. Here is an example implementation of system() which tries to use the
  444. shell_p variable, if possible.
  445.  
  446. /*----------------------------------------------------------------------*/
  447. #include <osbind.h>
  448. #include <stdio.h>
  449. #include <string.h>
  450. #include <basepage.h>
  451.  
  452. static parse_args(cmdln, argv)
  453.         char *cmdln;
  454.         register char *argv[];
  455.         {
  456.         register char *p;
  457.         static char delim[] = " \t\r\n";
  458.  
  459.         if(p = strtok(cmdln, delim))
  460.                 {
  461.                 do
  462.                         {
  463.                         *argv++ = p;
  464.                         } while(p = strtok(NULL, delim));
  465.                 }
  466.         }
  467.  
  468. int system(command)
  469.         register char *command;
  470. /*
  471.  *      Attempts to pass <command> to the shell program pointed to by
  472.  *      the system variable "_shell_p".  If a valid shell can't be found
  473.  *      there, the "SHELL" environment variable is searched for.  If it
  474.  *      exists and is not empty, it will be the name of the shell program
  475.  *      to execute the given command.  If "SHELL" is not valid, the
  476.  *      "PATH" variable is used as a list of directories to search for
  477.  *      the program name which is the first token of the command.  The
  478.  *      extensions tried (if none is specified) are ".TTP", ".TOS",
  479.  *      ".PRG" and ".APP".
  480.  */
  481. {
  482.         register char *p;
  483.         register int (*shell)();
  484.         char rv[2];
  485.         char cmdln[1024];
  486.         char *args[64];
  487.         char *getenv();
  488.  
  489.         if(!command)
  490.                 return(ERROR);
  491.  
  492.         /* get _shell_p value */
  493.         p = Super(0L);
  494.         shell = *((long *) 0x4F6L);
  495.         Super(p);
  496.  
  497.         /* validate _shell_p */
  498.         if((shell) &&                           /* Shell available. */
  499.            (((long) shell) < ((long) _base)) && /* Reasonable shell pointer. */
  500.            (strncmp(shell, "PATH", 4)))         /* Not corrupted */
  501.                 {
  502.                 /* execute the command */
  503.                 return((*shell)(command));
  504.                 }
  505.  
  506.         /* copy the command line for parsing */
  507.         strcpy(cmdln, command);
  508.  
  509.         /* SHELL= variable? */
  510.         if((p = getenv("SHELL")) && (*p))
  511.                 {
  512.                 args[0] = p;
  513.                 parse_args(cmdln, args+1);
  514.                 forkvpe(p, args, NULL);
  515.                 wait(&rv);
  516.                 return((rv[1] == 0) ? rv[0] : rv[1]);
  517.                 }
  518.  
  519.         /* attempt to find first token as a program on the path */
  520.         parse_args(cmdln, args);
  521.         if(p = pfindfile(args[0], ".ttp\0.tos\0.prg\0.app"))
  522.                 {
  523.                 forkvpe(p, args, NULL);
  524.                 wait(&rv);
  525.                 return((rv[1] == 0) ? rv[0] : rv[1]);
  526.                 }
  527.         return(ERROR);
  528. }
  529. /*----------------------------------------------------------------------*/
  530.  
  531. I hope this answers your question.  It's so easy for a shell to install
  532. itself on the shell_p vector and it's so convenient if other program
  533. which support shell escapes use a system() call like the one above.
  534. In case there is any question about installing and removing the shell_p
  535. vector, the following routines will handle it nicely.
  536.  
  537. /*----------------------------------------------------------------------*/
  538. long (*sh_save)();      /* previous value of _shell_p variable */
  539.  
  540. sh_install(new_shell)
  541.         int (*new_shell)();
  542. /*
  543.  * install _shell_p vector
  544.  */
  545.         {
  546.         register long *ssp;
  547.         register (**shell_p)() = 0x4F6L;
  548.  
  549.         ssp = Super(0L);
  550.         sh_save = *shell_p;
  551.         *shell_p = new_shell;
  552.         Super(ssp);
  553.         }
  554.  
  555. sh_restore()
  556. /*
  557.  * restore old _shell_p vector
  558.  */
  559.         {
  560.         register long *ssp;
  561.         register (**shell_p)() = 0x4F6L;
  562.  
  563.         ssp = Super(0L);
  564.         *shell_p = sh_save;
  565.         Super(ssp);
  566.         }
  567. /*----------------------------------------------------------------------*/
  568.  
  569. PS.  For those waiting for dLibs v1.1 and/or MicroEMACS 2.19, I have
  570. sent out disks for all the requests I had outstanding, you should either
  571. already have them, or should receive them soon.  Sorry for the delays.
  572. I hope you're happy with the results.  I'd like to hear from some of you
  573. after you've used dLibs a bit.  I'd be happy to receive bug reports,
  574. suggested enhancements or just experiences so that I know they're being
  575. put to good use.
  576.  
  577.                 Dale Schumacher
  578.                 ..ihnp4!meccts!stag!syntel!dal
  579.                 (alias: Dalnefre')
  580.  
  581. Article 616 of comp.sys.atari.st:
  582. Path:
  583. unido!mcvax!uunet!husc6!bloom-beacon!gatech!rutgers!uwvax!umn-d-ub!umn-c
  584. cs!mmm!ems!viper!john
  585. >From: john@viper.Lynx.MN.Org (John Stanley)
  586. Newsgroups: comp.sys.atari.st
  587. Subject: Re: Print redirection routine
  588. Message-ID: <595@viper.Lynx.MN.Org>
  589. Date: 8 Feb 88 09:49:38 GMT
  590. Article-I.D.: viper.595
  591. Posted: Mon Feb  8 10:49:38 1988
  592. References: <8801271313.AA10750@lasso.laas.fr> <15@obie.UUCP>
  593. Reply-To: john@viper.UUCP (John Stanley)
  594. Organization: DynaSoft Systems
  595. Lines: 54
  596.  
  597.  
  598.  >In article <8801271313.AA10750@lasso.laas.fr>, 
  599.  >ralph@lasso.UUCP (Ralph P. Sobek) writes:
  600.  >> To: inria!score.stanford.edu!info-atari16
  601.  >> Subject: Print redirection routine
  602.  >> 
  603.  >> what I'm looking for is an assembler or C program which would redirect
  604.  >> the output of one of these programs to an ascii file rather than the
  605. printer.
  606.  
  607.    The best program to accomplish this is called barrel written by
  608. Moshe Braner.  It has several functions to allow capturing text or
  609. screen dumps to a file.  It is TSR (terminate & stay resident) which
  610. may or may not be what you originaly wanted, but it is good and it
  611. works....
  612.  
  613.  
  614. In article <15@obie.UUCP> wes@obie.UUCP (Barnacle Wes) writes:
  615.  >You can redirect the output to printer in your program via the
  616.  >following:
  617.  >
  618. [part of sample deleted]
  619.  >      /* Now execute the program, the standard handles are inherited.  */
  620.  >      Pexec(0, "disk:/program/name/path.prg", NULL, tail);
  621.  >....
  622.  >
  623.  >      Hope this helps whoever it was!
  624.  
  625.   Not likely...  The example you gave will bomb miserably...  The
  626. parameters you gave for Pexec are in the wrong order and ignore an
  627. important pecularity in the Pexec call (the command tail is a Pascal
  628. style string, not a C style string).
  629.  
  630.   The correct order for Pexec parameters is:
  631.         Pexec mode:     zero is fine
  632.         Program name:   standard C string format
  633.         Command tail:   a pointer to a Pascal style string (a string 
  634.                         with the character count in the first byte!)
  635.         Environment:    A pointer to an environment block or NULL if
  636.                         you want to use the default environment.
  637.  
  638.   Thus, a corrected version would read:
  639.  
  640. static unsigned char tailbuf[255];
  641. ....
  642. tailbuf[0] = strlen(tail);
  643. strcpy(tailbuf+1,tail);
  644. Pexec(0, "A:\\folder1\\folder2\\program.ttp", tailbuf, (char*)NULL);
  645.  
  646.  
  647.  
  648. --- 
  649. John Stanley (john@viper.UUCP)
  650. Software Consultant - DynaSoft Systems
  651. UUCP: ...{amdahl,ihnp4,rutgers}!meccts!viper!john
  652.  
  653.  
  654. >From laura!unido!mcvax!philmds!leo Tue May  3 13:24:35 MET DST 1988
  655. Article 8601 of comp.sys.atari.st:
  656. Path: laura!unido!mcvax!philmds!leo
  657. >From: leo@philmds.UUCP (Leo de Wit)
  658. Newsgroups: comp.sys.atari.st
  659. Subject: Re: preloading programs
  660. Message-ID: <474@philmds.UUCP>
  661. Date: 2 May 88 11:25:04 GMT
  662. References: <8804141742.AA01455@decwrl.dec.com> <693@ast.cs.vu.nl>
  663. <390@uvicctr.UUCP> <188@obie.UUCP>
  664. Reply-To: leo@philmds.UUCP (L.J.M. de Wit)
  665. Organization: Philips I&E DTS Eindhoven
  666. Lines: 69
  667. Posted: Mon May  2 12:25:04 1988
  668.  
  669. In article <188@obie.UUCP> wes@obie.UUCP (Barnacle Wes) writes:
  670. >In article <390@uvicctr.UUCP>, collinge@uvicctr.UUCP (Doug Collinge) writes:
  671. >> Someone said that OS9 68k is capable of "preloading" commands; that is,
  672. >> loading some programs into memory and executing them there when invoked
  673. >> rather than loading them from disk.  This seems to be yet another
  674. >> excellent idea incorporated in OS9 that no-one else seems to have
  675. >> thought of.
  676. >
  677. >Yes, that is one of the many good features of OS9.  Another is
  678. >pre-loaded modules.  You can have "external" modules on OS9 - when
  679. > [...stuff deleted...]
  680. >itself.  You can, of course, pre-load modules.  Nice feature.
  681. >
  682. >> How difficult would it be to hack this into Gulaam?
  683. >
  684. >Probably VERY difficult.  TOS is not setup to handle pre-loaded programs;
  685. > [...stuff deleted...]
  686.  
  687. Never used gemdos call 0x4b (Exec) with a mode of 4?
  688. You can have preloaded programs on the Atari ST as well, and it works quite
  689. nicely. I used it in a find command and in a shell I programmed for the Atari 
  690. (yes, the Unix find command!), for example:
  691. find .. -type d ! -name . ! -name .. -exec ls -l {} \;
  692. (For those not familiar with find, this one finds all directories beneath 
  693. the current directory's parent (excluding . and .. names) and does a ls -l
  694. on each one of them).
  695.  
  696. Each time loading ls worked fine on the ramdisk I used to use, but once I
  697. started working on a hard disk, it becomes really slooooooooooowwww!
  698. Then I decided to preload the ls command (with gemdos(0x4b,3,"ls",0,0)).
  699. The gemdos function returns the basepage address of the loaded program.
  700. Now 'find', each time it has to 'ls', copies the argument string into the
  701. basepage; then it runs 'ls' by gemdos(0x4b,4,0,0,0) (I don't remember whether
  702. these are the correct values for the parameters). It is now (nearly) as fast 
  703. as a builtin function!
  704.  
  705. There are however a few problems (and I have not solved all of them):
  706. 1) When the parent program changes directories, the child stays in the
  707. directory
  708. it started in (the current directory and disk are saved somewhere on the 
  709. basepage, start+55?).
  710. 2) There is also a problem with the memory; the loaded child obtains, as usual
  711. the rest of the memory available (in addresses basepage+4 to basepage+7 the
  712. address of the 'next free location' or something like that is found: 0xF8000 on
  713. my 520 ST+). Thus there is a problem with multiple preloaded childs or childs
  714. requesting additional memory. I've overcome this (sort of) by using setblock
  715. (gemdos 0x4a) and adjusting the 'next_free_location' ptrs on the childs 
  716. basepages. It's better now, but still buggy (I don't know all about Gemdos
  717. memory management, I'm finding out now).
  718. 3) There could be problems as well with file descriptors (they're also on the
  719. basepage).
  720. 4) Initialized static and extern variables do not regain their initial value
  721. after a run. This is in consequence of the 'once-only' load. It could be
  722. overcome by a) always explicit initializing (by the child process), or 
  723. b) make a copy of the initialized data space (by the parent process) and use 
  724. this to re-initiate from the next time (more expensive, but not breaking 
  725. existing code).
  726.  
  727. If you manage to overcome these difficulties, it should not be very hard to
  728. code this preloading into a shell (I did it, having still these little problems
  729. ...). The shell maintains a list of preloaded programs, their pathname and
  730. their fat number and handles loading/executing depending on memory available,
  731. programs preloaded etc. Preloaded programs are almost as fast as functions
  732. built into the shell.
  733.  
  734. If anybody has suggestions about the memory management part, or questions 
  735. 'about the real code', or want examples, please RESPOND! A commented
  736. disassembly
  737. of the gemdos part of the O.S. would also be great ....
  738.  
  739.                 leo.
  740.  
  741.  
  742. >From laura!unido!mcvax!philmds!leo Tue May 17 13:00:13 MET DST 1988
  743. Article 8838 of comp.sys.atari.st:
  744. Path: laura!unido!mcvax!philmds!leo
  745. >From: leo@philmds.UUCP (Leo de Wit)
  746. Newsgroups: comp.sys.atari.st
  747. Subject: Re: preloading programs
  748. Keywords: Preload, Ramdisk, Pexec
  749. Message-ID: <482@philmds.UUCP>
  750. Date: 16 May 88 11:28:03 GMT
  751. References: <8804141742.AA01455@decwrl.dec.com> <693@ast.cs.vu.nl>
  752. <474@philmds.UUCP> <219@obie.UUCP>
  753. Reply-To: leo@philmds.UUCP (L.J.M. de Wit)
  754. Organization: Philips I&E DTS Eindhoven
  755. Lines: 139
  756. Posted: Mon May 16 12:28:03 1988
  757.  
  758. In article <219@obie.UUCP> wes@obie.UUCP (Barnacle Wes) writes:
  759. >In article <474@philmds.UUCP>, leo@philmds.UUCP (Leo de Wit) writes:
  760. >> ...[stuff deleted]...
  761. >
  762. >One of the problems is that GEMDOS will release all of the memory
  763. >allocated to program, including that gotten in the original
  764. >load/Mshrink process, when the program exits via Pterm or Pterm0.  I
  765. >don't know if the Pexec(,4,,,) call re-allocates that memory or not.
  766. >
  767. >> ...[stuff deleted]...
  768. >
  769.  
  770. I have had some time to figure things out (disassembled Pexec and several 
  771. others) and managed to get a reusable load image in core that can be run over 
  772. and over.
  773. A word of caution: the program should not depend on initialized data, unless
  774. this data will not change (is 'readonly'). An example:
  775.  
  776. #define INTERACTIVE 1
  777.  
  778. int option = 0;
  779.  
  780. main(argc,argv)
  781. int argc;
  782. char *argv[];
  783. {
  784.    if ((argc > 1) && (!strcmp(argv[1],"-i"))) {
  785.       option |= INTERACTIVE;
  786.    }
  787.    /* REST OF CODE ... */
  788. }
  789.  
  790. After one run with -i flag option 'has the INTERACTIVE bit set' and will have
  791. it too on the next run. So option must be explicitly initialized:
  792.  
  793. main(argc,argv)
  794. int argc;
  795. char *argv[];
  796. {
  797.    option = 0;
  798.    /* REST OF CODE ... */
  799.  
  800. Before I give the prescription I will give a more detailed explanation of the 
  801. Pexec call, Pexec(mode,path,tail,env); mainly because most books about GEMDOS 
  802. are much too terse about the subject (please correct me if I'm wrong, I had
  803. to find out things the hard way, like so many of us).
  804. Which functions will be performed within Pexec depends on the mode word; this
  805. can be either 0, 3, 4 or 5.
  806. The following actions are performed:
  807. 1) mode 0 and 3: searchfile. If the program file 'path' does not exist, Pexec
  808. returns error -32 (file not found).
  809. 2) mode 0, 3 and 5: 'basepage initializations':
  810.    a) create environment string. If 'env' is null a copy of the parent's
  811. environment string is made, else a copy of 'env' is made. 'env' is terminated
  812. by two '\0' 's. The new environment space is allocated and bp[11] is set to
  813. point to it (consider bp a (char **), it is the start of the basepage).
  814.    b) allocate program space. The maximum available space is claimed (that
  815. returned by Malloc(-1)).
  816.    c) If mode == 0, the environment and program spaces are owned by the child
  817. (in the memory parameter blocks the owner is the new basepage); if mode == 3 or
  818. mode == 5, the parent owns the memory blocks. This fact ensures that the
  819. program area is not automatically reclaimed when the child exits (but space
  820. Malloced by the child is).
  821.    d) bp[0] is set to the basepage, bp[1] is set to basepage + length of 
  822. program block (i.e. the first location above the program).
  823.    e) Initiate (redirected) file descriptors 0 - 5 (bytes 48 through 53 on the
  824. basepage).
  825.    f) Initiate current working directories: for each drive one (bytes 64 
  826. through 79 on the basepage). Note that e) and f) involves more than simply
  827. assigning a value.
  828.    g) Initiate current drive (byte 55 on the basepage). This is copied from the
  829. parent.
  830.    h) Copy tail to basepage + 128 (max. 0x7d bytes). bp[8] is set to point to
  831. this location.
  832. 3) mode 0 and 3: load program. This is a function on its own, and I will not
  833. explain all details. Generally speaking, the function performs some checks on
  834. the program format, it loads program and data, does relocation, null fills
  835. all above data and sets bp[2]: text start, bp[3]: text length, bp[4]: data 
  836. start, bp[5]: data length, bp[6]: bss start, bp[7]: bss length.
  837. 4) mode 0 and 4: final initializations and run.
  838.    a) bp[9] is set to the current basepage (parent).
  839.    b) A save area for registers is initialized at the last 50 locations of the
  840. program; bp[30] and bp[31] are set to point to this area; bp[26] through bp[30]
  841. are for saving other registers.
  842.    c) switch process: the new basepage is entered into the long at 0x602c and
  843. registers are loaded using the save area and bp[26]..bp[30] mentioned in b).
  844.  
  845. So far for the 'preliminary meditations'; here's the recipe:
  846.  
  847. A) First preload using mode 3:
  848. bp = (char **)Pexec(3,"program","",0);
  849. B) Return unused memory to the system:
  850. Calculate the memory needed, e.g.
  851. memneed = 0x100 + (int)bp[3] + (int)bp[5] + (int)bp[7] + 0x800 + 0x800;
  852.           basepage     text         data         bss     heap    stack.
  853. (the values needed for heap and stack depend on your program/your needs).
  854. Now:
  855. Mshrink(bp,mneed); /* return unused memory to the system */
  856. Mfree(bp[11]);     /* free the new environment space, we won't use it */
  857. bp[1] = (char *)bp + mneed; /* first free location is lower now */
  858. C) Prepare to run:
  859. bp2 = Pexec(5,0,"arguments",0);
  860. Mshrink(bp2,0x100); /* only keep a basepage */
  861. for (i = 1; i < 8; i++) bp2[i] = bp[i]; /* set pointers and lengths correctly*/
  862. D) Now run it:
  863. code = Pexec(4,0,bp2,0);
  864. Mfree(bp2[11]); /* frees the environment space */
  865. Mfree(bp2); /* frees the new basepage */
  866.  
  867. For each run, do C) and then D). Hey, it works!
  868. Some remarks:
  869. a) the environment is not used (0, so the parent's is used). You can use an
  870. environment string, in C): Pexec(5,0,"arguments","environment\0");
  871. note that the environment string must end on a double '\0', as in the example.
  872. b) Although the arguments string is simply copied, it is a convention that the
  873. first byte of the args string contains its byte count. This is probably due
  874. to the fact that the GEMDOS readline function (0xa) also returns the count in
  875. the string (and probably GEM uses this type of string for Pexec when starting
  876. TTP applications). So:
  877.  
  878. char newtail[128];
  879.  
  880. strncpy(newtail,tail,0x7d);
  881. newtail[0] = strlen(newtail + 1);
  882. Pexec(5,0,newtail,0);
  883.  
  884. c) The bp[..] and bp2[..] mentioned are longs (char *, to be precise).
  885. d) Preload could be used to provide more than 128 characters arguments string.
  886. The arguments can be placed on the child's stack; the child can find them using
  887. bp[8] (this will break existing code that uses simply (char *)bp + 128). I
  888. suggest that we use bp[8] as a char *[], as is argv; and use a startup module
  889. that uses this scheme if bp[8] != (char *)bp + 128 and the old one if it
  890. equals.
  891. e) A similar scheme can be used for the 'env', bp[11].
  892. f) I'm sure d) and e) start up new discussions!
  893.  
  894.     Hope this clarifies some things about Pexec and makes it better usable.
  895.     I'm waiting for your responses, questions, remarks, experiences...
  896.  
  897.     Leo (Swimming in the C..)
  898.  
  899.  
  900.