home *** CD-ROM | disk | FTP | other *** search
/ The CDPD Public Domain Collection for CDTV 3 / CDPDIII.bin / pd / programming / gnuc / library / rcs / __load_seg.c,v < prev    next >
Encoding:
Text File  |  1992-09-14  |  14.2 KB  |  668 lines

  1. head    1.5;
  2. access;
  3. symbols
  4.     version39-41:1.3;
  5. locks;
  6. comment    @ *  @;
  7.  
  8.  
  9. 1.5
  10. date    92.09.14.01.38.35;    author mwild;    state Exp;
  11. branches;
  12. next    1.4;
  13.  
  14. 1.4
  15. date    92.08.09.20.37.07;    author amiga;    state Exp;
  16. branches;
  17. next    1.3;
  18.  
  19. 1.3
  20. date    92.07.04.19.02.39;    author mwild;    state Exp;
  21. branches;
  22. next    1.2;
  23.  
  24. 1.2
  25. date    92.05.22.01.45.00;    author mwild;    state Exp;
  26. branches;
  27. next    1.1;
  28.  
  29. 1.1
  30. date    92.05.14.19.55.40;    author mwild;    state Exp;
  31. branches;
  32. next    ;
  33.  
  34.  
  35. desc
  36. @load segment, consider resident list, do interpreter expansion
  37. @
  38.  
  39.  
  40. 1.5
  41. log
  42. @fix a bug with #! expansion (forgot separating /)
  43. @
  44. text
  45. @/*
  46.  *  This file is part of ixemul.library for the Amiga.
  47.  *  Copyright (C) 1991, 1992  Markus M. Wild
  48.  *
  49.  *  This library is free software; you can redistribute it and/or
  50.  *  modify it under the terms of the GNU Library General Public
  51.  *  License as published by the Free Software Foundation; either
  52.  *  version 2 of the License, or (at your option) any later version.
  53.  *
  54.  *  This library is distributed in the hope that it will be useful,
  55.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  56.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  57.  *  Library General Public License for more details.
  58.  *
  59.  *  You should have received a copy of the GNU Library General Public
  60.  *  License along with this library; if not, write to the Free
  61.  *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  62.  *
  63.  *  $Id: __load_seg.c,v 1.4 1992/08/09 20:37:07 amiga Exp $
  64.  *
  65.  *  $Log: __load_seg.c,v $
  66.  *  Revision 1.4  1992/08/09  20:37:07  amiga
  67.  *  change to use 2.x header files by default
  68.  *
  69.  *  Revision 1.3  1992/07/04  19:02:39  mwild
  70.  *  fix typo, the buffer for interpreter-expansion was ways too small...
  71.  *
  72.  * Revision 1.2  1992/05/22  01:45:00  mwild
  73.  * rewrote interpreter expansion, `should' now work as expected
  74.  *
  75.  * Revision 1.1  1992/05/14  19:55:40  mwild
  76.  * Initial revision
  77.  *
  78.  */
  79.  
  80. #define KERNEL
  81. #include "ixemul.h"
  82. #include <ctype.h>
  83. #include <string.h>
  84.  
  85. #ifdef DEBUG
  86. #define DP(a) kprintf a
  87. #else
  88. #define DP(a)
  89. #endif
  90.  
  91. #if __GNUC__ != 2
  92. #define alloca __builtin_alloca
  93. #endif
  94.  
  95. /* until sksh is fixed... */
  96. #define BIG_KLUDGE
  97.  
  98. extern int _dos20;
  99.  
  100. /* 2.0 support */
  101. #include <utility/tagitem.h>
  102. #include <dos/dostags.h>
  103.  
  104. extern void *kmalloc (size_t size);
  105.  
  106. struct my_seg {
  107.   BPTR    segment;    /* the thing our clients can use */
  108.   enum { LOADSEG, RESSEG } type;
  109.   u_int    priv;        /* information depending on type */
  110. };
  111.  
  112.  
  113. static struct my_seg *try_load_seg (BPTR lock, char *name, char **args);
  114.  
  115.  
  116. static inline struct my_seg *
  117. check_resident (char *tmp)
  118. {
  119.   struct my_seg *res = 0;
  120.   struct Segment *seg = 0;
  121.  
  122.   if (_dos20)
  123.     {
  124.       /* big problem: Commo only stores the bare names in the resident
  125.          list. So we have to truncate to the filename part, and so lose
  126.          the ability to explicitly load the disk version even if a 
  127.          resident version is installed */
  128.  
  129.       char *cp = rindex (tmp, '/');
  130.       if (cp)
  131.     tmp = cp + 1;
  132.       else if (cp = index (tmp, ':'))
  133.     tmp = cp + 1;
  134.  
  135.       Forbid ();
  136.       seg = FindSegment (tmp, 0, 0);
  137.       if (seg)
  138.         {
  139.           /* strange they didn't provide a function for this... */
  140.           if (seg->seg_UC >= 0) 
  141.         seg->seg_UC++;
  142.     }
  143.       Permit ();
  144.     }
  145.  
  146.   if (seg && (res = (struct my_seg *) kmalloc (sizeof (*res))))
  147.     {
  148.       res->segment = seg->seg_Seg;
  149.       res->type    = RESSEG;
  150.       res->priv    = (u_int) seg;
  151.     }
  152.   else if (seg)
  153.     {
  154.       Forbid ();
  155.       if (seg->seg_UC > 0)
  156.     seg->seg_UC--;
  157.       Permit ();
  158.     }
  159.  
  160.   return res;
  161. }
  162.  
  163.  
  164. static inline struct my_seg *
  165. check_loadseg (char *tmp)
  166. {
  167.   struct my_seg *res = 0;
  168.   BPTR seg;
  169.   
  170.   seg = LoadSeg (tmp);
  171.   if (seg && (res = kmalloc (sizeof (*res))))
  172.     {
  173.       res->segment = seg;
  174.       res->type       = LOADSEG;
  175.       res->priv    = seg;
  176.     }
  177.   else if (seg)
  178.     UnLoadSeg (seg);
  179.     
  180.   return res;
  181. }
  182.  
  183.  
  184. void
  185. __free_seg (BPTR *seg)
  186. {
  187.   struct my_seg *ms;
  188.   
  189.   ms = (struct my_seg *) seg;
  190.   
  191.   if (ms->type == RESSEG)
  192.     {
  193.       struct Segment *s = (struct Segment *) ms->priv;
  194.  
  195.       Forbid ();
  196.       if (s->seg_UC > 0)
  197.     s->seg_UC--;
  198.       Permit ();
  199.     }
  200.   else
  201.     UnLoadSeg (ms->priv);
  202.  
  203.   kfree (ms);
  204. }
  205.  
  206.  
  207. /*
  208.  * This function does what LoadSeg() does, and a little bit more ;-)
  209.  * Besides walking the PATH of the user, we try to do interpreter expansion as
  210.  * well. But, well, we do it a little bit different then a usual Amiga-shell.
  211.  * We check the magic cookies `#!' and `;!', and if found, run the interpreter
  212.  * specified on this first line of text. This does *not* depend on any script
  213.  * bit set!
  214.  * If this check is negative, the script bit is tested. If set, the special
  215.  * BPTR (-2) is returned, this is the hint to ssystem() to go and invoke
  216.  * system() with the command line. In this case *NO* interpreter expansion
  217.  * takes place, as the expansion must have already failed before.
  218.  */
  219.  
  220. /*
  221.  * IMPORTANT: only call this function with all signals masked!!! 
  222.  */
  223.  
  224. /*
  225.  * name:        the name of the command to load. Can be relative to installed PATH
  226.  * args:        if set, a string to the first part of an expanded command is stored
  227.  */
  228.  
  229. BPTR *
  230. __load_seg (char *name, char **args)
  231. {
  232.   BPTR lock, parent_lock;
  233.   struct my_seg *seg;
  234.   char *base_name;
  235.   
  236.   /* perhaps the name is vanilla enough, so that even LoadSeg() groks it? */
  237.   if (args) *args = 0;
  238.  
  239.   seg = check_resident (name);
  240.  
  241.   if (! seg)
  242.     seg = check_loadseg (name);
  243.  
  244.   if (seg)
  245.     return &seg->segment;
  246.  
  247.   /* try to lock the file (using __lock() provides full path-parsing ;-)) */
  248.  
  249.   lock = __lock (name, ACCESS_READ);
  250.   if (lock)
  251.     {
  252.       /* this is tricky.. it is legal to CurrentDir() to a file. This is what
  253.        * we do here, we try to LoadSeg("") afterwards ;-)) */
  254.       seg = try_load_seg (lock, "", args);
  255.  
  256.       __unlock (lock);
  257.     }
  258.  
  259.   /* now we may have a valid segment */
  260.   if (seg)
  261.     return &seg->segment;
  262.  
  263.   /* if the command was specified with some kind of path, for example with a
  264.    * device or a directory in it, we don't run it thru the PATH expander
  265.    */
  266.   if (strpbrk (name, ":/"))
  267.     return 0;
  268.  
  269.   /* so the command is not directly addressable, but perhaps it's in our PATH? */
  270.   {
  271.     struct Process *me = (struct Process *)((*(struct ExecBase **)4)->ThisTask);
  272.     struct CommandLineInterface *cli;
  273.  
  274.     /* but we need a valid CLI then */
  275.     if (cli = BTOCPTR (me->pr_CLI))
  276.       {
  277.     struct path_element {
  278.       BPTR    next;
  279.       BPTR     lock;
  280.     } *lock_list;
  281.  
  282.     for (lock_list = BTOCPTR (cli->cli_CommandDir);
  283.          lock_list;
  284.          lock_list = BTOCPTR (lock_list->next))
  285.       {
  286. #if 0
  287.             DP(("__load_seg: trying PATH component: next = $%lx, lock = $%lx\n",
  288.                 lock_list->next, lock_list->lock));
  289. #endif
  290.  
  291.         if (seg = try_load_seg (lock_list->lock, name, args))
  292.           break;
  293.       }
  294.       }
  295.   }
  296.   
  297.   if (seg)
  298.     return &seg->segment;
  299.  
  300.   errno = ENOENT;
  301.   return 0;
  302. }
  303.  
  304. static struct my_seg *
  305. try_load_seg (BPTR lock, char *name, char **args)
  306. {
  307.   BPTR ocd;
  308.   struct my_seg *seg;
  309.  
  310.   if (args) *args = 0;
  311.   
  312.   ocd = CurrentDir (lock);
  313.   
  314.   seg = check_loadseg (name);
  315.  
  316.   /* try to do interpreter - expansion, but only if args is non-zero */
  317.   if (! seg && args)
  318.     {
  319.       int fd;
  320.       char magic[2];
  321.       struct stat stb;
  322.       
  323.       if (syscall (SYS_stat, name, &stb) == 0 && S_ISREG (stb.st_mode))
  324.     {
  325.       if ((fd = syscall (SYS_open, name, 0)) >= 0)
  326.             {
  327.           if (syscall (SYS_read, fd, magic, 2) == 2 && 
  328.               (((magic[0] == '#' || magic[0] == ';') && magic[1] == '!')
  329. #ifdef BIG_KLUDGE
  330.           /* I can't currently use #! expansion with sksh, since the shell
  331.            * does the same expansion again, and then doesn't seem to get
  332.            * it right anymore... this is the so far unused hidden bit,
  333.            * set it with PROTECT +h
  334.            */
  335.           || (stb.st_amode & (1 << 7))
  336. #endif
  337.                                         ))
  338.             {
  339.               char interp[MAXPATHLEN + 1];
  340.               int n;
  341.           
  342.               if ((n = syscall (SYS_read, fd, interp, MAXINTERP)) > 0)
  343.             {
  344.               char *cp, *colon, ch;
  345.               char *interp_path;
  346.  
  347. #ifdef BIG_KLUDGE
  348.               if (stb.st_amode & (1<<7))
  349.                 {
  350.               strcpy (interp, "sksh -c");
  351.               n = strlen (interp);
  352.             }
  353. #endif
  354.  
  355.               /* oky.. got one.. terminate with 0 and try to find end of it */
  356.               interp[n] = 0;
  357.               for (cp = interp; cp < interp + n; cp++)
  358.                 if (*cp == 0 || isspace (*cp)) break;
  359.               ch = *cp;
  360.               *cp = 0;
  361.  
  362.               /* okay, lets try to load this instead. Call us recursively,
  363.                * but leave out the argument-argument, so we can't get
  364.                * into infinite recursion. Interpreter-Expansion is only
  365.                * done the first time __load_seg() is called from
  366.                * ssystem()
  367.                */
  368.               seg = (struct my_seg *) __load_seg (interp, 0);
  369.               *cp = ch;
  370.               if (! seg)
  371.                 goto ret;
  372.           
  373.               /* in this case, set the argument as well. 
  374.                */
  375.  
  376.               /* first skip intergap whitespace */
  377.               for (;cp < interp + n; cp++)
  378.             if (!*cp || ! isspace (*cp) || *cp == '\n')
  379.               break;
  380.  
  381.               if (*cp && *cp != '\n')
  382.                 {
  383.               /* we read a certain amount of bytes, but we 
  384.                * unconditionally stop when we hit newline
  385.                */
  386.               interp_path = cp;
  387.  
  388.                   /* crop any further arguments, only ONE argument
  389.                    * is supported
  390.                */
  391.                   for (;cp < interp + n; cp++) 
  392.                 if (isspace (*cp)) 
  393.                   break;
  394.                   if (cp < interp + n)
  395.                 *cp = 0;
  396.  
  397.               *cp++ = ' ';
  398.             }
  399.               else
  400.             cp = interp_path = interp;
  401. #ifdef BIG_KLUDGE
  402.               if (stb.st_amode & (1<<7))
  403.                 {
  404.                   *cp++ = '\"';
  405.                 }
  406. #endif
  407.               if (ix.ix_translate_slash && name[0] != '/')
  408.             *cp++ = '/';
  409.  
  410.               if (name[0] != '/' && !index (name, ':'))
  411.             {
  412.               if (NameFromLock (lock, cp, 
  413.                         MAXPATHLEN-(cp-interp)) == -1)
  414.                 strcat (strcat (cp, "/"), name);
  415.               else
  416.                 strcpy (cp, name);
  417.             }
  418.               else
  419.             strcpy (cp, name);
  420.  
  421.               if (ix.ix_translate_slash && (colon = index (cp, ':')))
  422.             *colon = '/';
  423.  
  424.               *args = syscall (SYS_strdup, interp_path);
  425. #ifdef BIG_KLUDGE
  426.               if (stb.st_amode & (1<<7))
  427.                 {
  428.               /* tell ssystem() that it should add the closing
  429.                * quote... shudder.. I want a newer sksh !
  430.                */
  431.                   *args = (char *)(-(int)*args);
  432.                 }
  433. #endif
  434.             }
  435.             }
  436.           syscall (SYS_close, fd);
  437.         }
  438.  
  439. ret:  
  440.       /* check to see if script bit is set, no matter whether we could
  441.        * actually open the file or not. If set, set seg to magic BPTR */
  442.       if (! seg && (stb.st_amode & FIBF_SCRIPT))
  443.         seg = (struct my_seg *) -2;
  444.         }
  445.     }
  446.  
  447.   CurrentDir (ocd);
  448.   
  449.   return seg;
  450. }
  451. @
  452.  
  453.  
  454. 1.4
  455. log
  456. @change to use 2.x header files by default
  457. @
  458. text
  459. @d19 1
  460. a19 1
  461.  *  $Id: __load_seg.c,v 1.3 1992/07/04 19:02:39 mwild Exp $
  462. d22 3
  463. d370 1
  464. a370 1
  465.                 strcat (cp, name);
  466. @
  467.  
  468.  
  469. 1.3
  470. log
  471. @fix typo, the buffer for interpreter-expansion was ways too small...
  472. @
  473. text
  474. @d19 1
  475. a19 1
  476.  *  $Id: __load_seg.c,v 1.2 1992/05/22 01:45:00 mwild Exp $
  477. d22 3
  478. d54 2
  479. a55 58
  480. #include "gcc:include20/utility/tagitem.h"
  481. #include "gcc:include20/dos/dostags.h"
  482. #define BASE_EXT_DECL
  483. #define BASE_PAR_DECL    
  484. #define BASE_PAR_DECL0    
  485. #define BASE_NAME    ix.ix_dos_base
  486. __inline static LONG NameFromLock(BASE_PAR_DECL BPTR lock, UBYTE* buffer, long int len)
  487. {
  488.     BASE_EXT_DECL
  489.     register LONG res __asm("d0");
  490.     register void *a6 __asm ("a6");
  491.     register BPTR d1 __asm("d1");
  492.     register UBYTE* d2 __asm("d2");
  493.     register long int d3 __asm("d3");
  494.  
  495.     a6 = BASE_NAME;
  496.     d1 = lock;
  497.     d2 = buffer;
  498.     d3 = len;
  499.     __asm volatile ("
  500.     jsr a6@@(-0x192)"
  501.     : "=r" (res)
  502.     : "r" (a6), "r" (d1), "r" (d2), "r" (d3)
  503.     : "d0", "d1", "a0", "a1", "d2", "d3");
  504.     *(u_char *)d2=*(u_char *)d2;
  505.     return res;
  506. }
  507. #ifndef CMD_SYSTEM
  508. #define CMD_SYSTEM    -1
  509. #define CMD_INTERNAL    -2
  510.  
  511. struct Segment {
  512.     BPTR seg_Next;
  513.     LONG seg_UC;
  514.     BPTR seg_Seg;
  515.     UBYTE seg_Name[4];    /* actually the first 4 chars of BSTR name */
  516. };
  517. #endif
  518. __inline static struct Segment* FindSegment(BASE_PAR_DECL UBYTE* name, struct Segment* seg, long int system)
  519. {
  520.     BASE_EXT_DECL
  521.     register struct Segment* res __asm("d0");
  522.     register void *a6 __asm ("a6");
  523.     register UBYTE* d1 __asm("d1");
  524.     register struct Segment* d2 __asm("d2");
  525.     register long int d3 __asm("d3");
  526.  
  527.     a6 = BASE_NAME;
  528.     d1 = name;
  529.     d2 = seg;
  530.     d3 = system;
  531.     __asm volatile ("
  532.     jsr a6@@(-0x30c)"
  533.     : "=r" (res)
  534.     : "r" (a6), "r" (d1), "r" (d2), "r" (d3)
  535.     : "d0", "d1", "a0", "a1", "d2", "d3");
  536.     return res;
  537. }
  538. @
  539.  
  540.  
  541. 1.2
  542. log
  543. @rewrote interpreter expansion, `should' now work as expected
  544. @
  545. text
  546. @d19 1
  547. a19 1
  548.  *  $Id: __load_seg.c,v 1.1 1992/05/14 19:55:40 mwild Exp $
  549. d22 3
  550. d345 1
  551. a345 1
  552.               char interp[MAXINTERP + 1];
  553. @
  554.  
  555.  
  556. 1.1
  557. log
  558. @Initial revision
  559. @
  560. text
  561. @d19 1
  562. a19 1
  563.  *  $Id$
  564. d21 4
  565. a24 1
  566.  *  $Log$
  567. d300 5
  568. a304 1
  569.   return &seg->segment;
  570. d347 2
  571. a348 1
  572.               char *cp;
  573. d360 1
  574. a360 1
  575.               for (cp = interp; cp < interp+n; cp++)
  576. d362 2
  577. a363 1
  578.               *cp++ = 0;
  579. d372 3
  580. d376 2
  581. a377 4
  582.               if (seg)
  583.                 {
  584.               char *interp_path;
  585.               int len;
  586. d379 4
  587. a382 4
  588.                   /* in this case, set the argument as well. 
  589.                    */
  590.                   for (;cp < interp+n; cp++) 
  591.                 if (! isspace (*cp) || *cp == '\n') break;
  592. d384 2
  593. d389 1
  594. a389 2
  595.               if (*cp == '\n')
  596.                 n = cp - interp;
  597. a390 3
  598.                   if (cp < interp+n) 
  599.                 *args = cp;
  600.  
  601. d394 1
  602. a394 1
  603.                   for (;cp < interp+n; cp++) 
  604. d397 1
  605. a397 1
  606.                   if (cp < interp+n) 
  607. d400 4
  608. a403 26
  609.               /* okay, now get a reasonably long buffer for the
  610.                * system to convert our lock into a path-name
  611.                */
  612.               if (! strpbrk (name, ":/"))
  613.                 {
  614.                   interp_path = alloca (MAXPATHLEN);
  615.                   if (NameFromLock (lock, interp_path, MAXPATHLEN) == -1)
  616.                 len = strlen (interp_path);
  617.                   else
  618.                 len = 0;
  619.                 }
  620.               else
  621.                 len = 0;
  622.  
  623.               /* now build the argument string */
  624.               if (! *args) *args = "";
  625.               cp = (char *)syscall (SYS_malloc, len + 1 + 
  626.                             strlen (name) + 1 
  627.                         + strlen (*args) + 2);
  628.               *cp = 0;
  629.               if (**args)
  630.                 {
  631.                   strcat (cp, *args);
  632.                   strcat (cp, " ");
  633.                 }
  634.  
  635. d405 4
  636. a408 2
  637.                   if (stb.st_amode & (1<<7))
  638.                 strcat (cp, "\"");
  639. d410 13
  640. d424 2
  641. a425 7
  642.               if (len)
  643.                 {
  644.                   strcat (cp, interp_path);
  645.                   if (! index (":/", cp[strlen (cp) - 1]) && *name)
  646.                 strcat (cp, "/");
  647.                 }
  648.               strcat (cp, name);
  649. d427 1
  650. a427 1
  651.               *args = cp;
  652. d429 7
  653. a435 7
  654.                   if (stb.st_amode & (1<<7))
  655.                     {
  656.                   /* tell ssystem() that it should add the closing
  657.                    * quote... shudder.. I want a newer sksh !
  658.                    */
  659.                       *args = (char *)(-(int)cp);
  660.                     }
  661. a436 1
  662.                 }
  663. d442 1
  664. d449 1
  665. a449 1
  666.   
  667. @
  668.