home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / emacs-19.28-src.tgz / tar.out / fsf / emacs / unixlib / src / _main.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  12KB  |  472 lines

  1. #include "amiga.h"
  2. #include "signals.h"
  3. #include "fifofd.h"
  4. #include "timers.h"
  5. #include "amigaos.h"
  6. #include <exec/execbase.h>
  7. #include <dos/var.h>
  8. #include <workbench/startup.h>
  9. #include <proto/timer.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include <ctype.h>
  13. #include <sys/time.h>
  14. #include <pwd.h>
  15.  
  16. struct Process *_us;
  17. struct timeinfo *_odd_timer;
  18. ULONG _odd_sig;
  19. long _startup_time;
  20. long _stack_size;
  21. struct Library *TimerBase;
  22.  
  23. static char *empty_env = 0;    /* A default empty environment */
  24. char **environ;            /* Unix style environment variable list */
  25. char *_system_name;
  26.  
  27. extern struct ExecBase *SysBase;
  28. extern struct passwd _amiga_user;
  29. extern main(int argc, char **argv, char **envp);
  30.  
  31. static void nomem(void)
  32. {
  33.   _fail("No memory");
  34. }
  35.  
  36. static void *_xmalloc(unsigned n)
  37. {
  38.     void *p = malloc(n);
  39.  
  40.     if (!p) nomem();
  41.  
  42.     return p;
  43. }
  44.  
  45. static void *_xrealloc(void *p, unsigned n)
  46. {
  47.     void *p2 = realloc(p, n);
  48.  
  49.     if (!p2) nomem();
  50.  
  51.     return p2;
  52. }
  53.  
  54. static char *safe_copystr(char *str)
  55. {
  56.     char *new;
  57.  
  58.     if (!str) str = "";
  59.     new = malloc(strlen(str) + 1);
  60.     if (!new) return 0;
  61.     return strcpy(new, str);
  62. }
  63.  
  64. static char *copystr(char *str)
  65. {
  66.     char *new = safe_copystr(str);
  67.  
  68.     if (!new) nomem();
  69.  
  70.     return new;
  71. }
  72.  
  73. void make_environ(void)
  74. /* Effect: Builds a UNIX style environ variable from the AmigaOS environment.
  75. */
  76. {
  77.     int env_count = 0;
  78.     long env_len = 0;
  79.     struct LocalVar *scan_env;
  80.     char **new_environ, *env_text;
  81.  
  82.     for (scan_env = (struct LocalVar *)_us->pr_LocalVars.mlh_Head;
  83.      scan_env->lv_Node.ln_Succ;
  84.      scan_env = (struct LocalVar *)scan_env->lv_Node.ln_Succ)
  85.     if (scan_env->lv_Node.ln_Type == LV_VAR &&
  86.         !(scan_env->lv_Flags & (GVF_GLOBAL_ONLY | GVF_BINARY_VAR)))
  87.     {
  88.         /* We only handle local text variables */
  89.         env_count++;
  90.         env_len += 2 + strlen(scan_env->lv_Node.ln_Name) + scan_env->lv_Len;
  91.     }
  92.  
  93.     new_environ = environ = (char **)_xmalloc(sizeof(char *) * (1 + env_count) +
  94.                           env_len);
  95.     env_text = (char *)(environ + (1 + env_count));
  96.     if (!environ) environ = &empty_env;
  97.     else
  98.     {
  99.     for (scan_env = (struct LocalVar *)_us->pr_LocalVars.mlh_Head;
  100.          scan_env->lv_Node.ln_Succ;
  101.          scan_env = (struct LocalVar *)scan_env->lv_Node.ln_Succ)
  102.         if (scan_env->lv_Node.ln_Type == LV_VAR &&
  103.         !(scan_env->lv_Flags & (GVF_GLOBAL_ONLY | GVF_BINARY_VAR)))
  104.         {
  105.         /* We only handle local text variables */
  106.         char *env_name = scan_env->lv_Node.ln_Name;
  107.         int env_len = scan_env->lv_Len;
  108.  
  109.         *new_environ++ = env_text;
  110.         while (*env_name) *env_text++ = *env_name++;
  111.         *env_text++ = '=';
  112.         env_name = scan_env->lv_Value;
  113.         while (env_len--) *env_text++ = *env_name++;
  114.         *env_text++ = '\0';
  115.         }
  116.     *new_environ = 0;
  117.     }
  118. }
  119.  
  120. /* _main routine.
  121.    Hides the differences between wb & cli.
  122.    Provides a unix-like environment (including coomand-line parsing &
  123.    wildcard expansion)
  124. */
  125.  
  126. #define DEFPATLEN 256
  127. #define NAMELEN 1024
  128.  
  129. struct args
  130. {
  131.     int size;
  132.     int argc;
  133.     char **argv;
  134. };
  135.  
  136. static void make_argv(struct args *args, int argc)
  137. {
  138.     args->size = argc;
  139.     args->argc = 0;
  140.     args->argv = _xmalloc(sizeof(char *) * argc);
  141. }
  142.  
  143. static int safe_add_arg(struct args *args, char *argument, int copy)
  144. {
  145.     char *arg_copy;
  146.  
  147.     if (copy) arg_copy = safe_copystr(argument);
  148.     else arg_copy = argument;
  149.     if (!arg_copy) return 0;
  150.  
  151.     if (args->argc >= args->size)
  152.     {
  153.     /* Make argv bigger */
  154.     if (args->size * 2 < args->size + 16) args->size += 16;
  155.     else args->size *= 2;
  156.     args->argv = realloc(args->argv, sizeof(char *) * args->size);
  157.     if (!args->argv) return 0;
  158.     }
  159.     args->argv[args->argc++] = arg_copy;
  160.     return 1;
  161. }
  162.  
  163. static void add_arg(struct args *args, char *argument, int copy)
  164. {
  165.     if (!safe_add_arg(args, argument, copy)) nomem();
  166. }
  167.  
  168. static void concat_args(struct args *args, struct args *add)
  169. {
  170.     if (args->argc + add->argc > args->size)
  171.     {
  172.     args->size = (args->argc + add->argc) * 2;
  173.     args->argv = _xrealloc(args->argv, sizeof(char *) * args->size);
  174.     }
  175.     memcpy(args->argv + args->argc, add->argv, add->argc * sizeof(char *));
  176.     args->argc += add->argc;
  177.     free(add->argv);
  178. }
  179.  
  180. typedef enum { quote_none, quote_single, quote_double } quote_type;
  181. typedef enum { extract_normal, extract_test, extract_pattern } extract_type;
  182.  
  183. static void extract(char *buf, char *start, char *end,
  184.             quote_type type, extract_type extract)
  185. {
  186.   char *res = buf;
  187.  
  188.   switch (type)
  189.     {
  190.     case quote_single:
  191.       if (extract != extract_test)
  192.     {
  193.       buf[end - start] = '\0';
  194.       memcpy(buf, start, end - start);
  195.     }
  196.       else strcpy(buf, "a");    /* Things in quotes are never patterns */
  197.       break;
  198.  
  199.     case quote_none:
  200.       while (start < end)
  201.     {
  202.       if (start[0] == '\\' && start[1])
  203.         {
  204.           start += 2;
  205.           /* Wildcard are escaped */
  206.           if (extract == extract_test) *res++ = 'a';
  207.           else if (extract == extract_pattern)
  208.         switch (start[-1])
  209.           {
  210.           case '?': case '#': case '(': case ')': case '|': case '[':
  211.           case ']': case '~': case '%': case '*': case '\'':
  212.             *res++ = '\'';
  213.           default:
  214.             *res++ = start[-1];
  215.             break;
  216.           }
  217.           else *res++ = start[-1];
  218.         }
  219.       else *res++ = *start++;
  220.     }
  221.       *res++ = '\0';
  222.       break;
  223.  
  224.     case quote_double:
  225.       while (start < end)
  226.     {
  227.       if (start[0] == '*' && start[1])
  228.         {
  229.           start += 2;
  230.           switch (start[-1])
  231.         {
  232.         case 'n': *res++ = '\n'; break;
  233.         case 'e': *res++ = '\x1b'; break;
  234.         default: *res++ = start[-1]; break;
  235.         }
  236.         }
  237.       else *res++ = *start++;
  238.     }
  239.       *res++ = '\0';
  240.       break;
  241.     }
  242. }
  243.  
  244. void __stdargs _main(char *line)
  245. /* Effect: Call unix_main with wildcards in argc & argv expanded (like unix)
  246.      Also, do some early amiga initialisation for emacs.
  247. */
  248. {
  249.   struct args args, wildargs;
  250.   char *pattern, *arg_start, *arg_end, *arg;
  251.   quote_type arg_quoted;
  252.   long patlen = DEFPATLEN;
  253.   struct AnchorPath *anchor;
  254.   struct timeval now;
  255.  
  256.   if (SysBase->LibNode.lib_Version < 37) XCEXIT(20);
  257.  
  258.   stdin->_file = 0;
  259.   stdin->_flag = _IOREAD;
  260.   stdout->_file = 1;
  261.   stdout->_flag = _IOWRT;
  262.   stderr->_file = 2;
  263.   stderr->_flag = _IORW | _IONBF;
  264.  
  265.   _us = (struct Process *)FindTask(0);
  266.   _odd_timer = _alloc_timer();
  267.   if (!_odd_timer) _fail("Failed to create timer");
  268.   _odd_sig = _timer_sig(_odd_timer);
  269.   TimerBase = _odd_timer->io->tr_node.io_Device;
  270.   GetSysTime(&now);
  271.   _startup_time = now.tv_secs;
  272.  
  273.   /* These use _startup_time, so must be here */
  274.   _init_fifo();
  275.   _init_signals();
  276.  
  277.   if (_us->pr_CLI) _stack_size = ((struct CommandLineInterface *)BADDR(_us->pr_CLI))->cli_DefaultStack << 2;
  278.   else _stack_size = _us->pr_StackSize;
  279.  
  280.   /* Make unix-like argc, argv (expand wildcards) */
  281.   if (!line[0])            /* Workbench, create argc & argv from files passed */
  282.     {
  283.       extern struct WBStartup *_WBenchMsg;
  284.       int i;
  285.       BPTR nilin = Open("NIL:",MODE_NEWFILE);
  286.       BPTR nilout = Open("NIL:",MODE_NEWFILE);
  287.       BPTR nilerr = Open("NIL:",MODE_NEWFILE);
  288.  
  289.       /* Initialise I/O. Nothing is available */
  290.       if (!nilin || !nilout || !nilerr)
  291.     {
  292.       if (nilin) Close(nilin);
  293.       if (nilout) Close(nilout);
  294.       if (nilerr) Close(nilerr);
  295.       nomem();
  296.     }
  297.       _init_unixio(nilin, TRUE, nilout, TRUE, nilerr, TRUE);
  298.  
  299.       /* Make argc, argv from Workbench parameters */
  300.       make_argv(&args, _WBenchMsg->sm_NumArgs);
  301.  
  302.       for (i = 0; i < _WBenchMsg->sm_NumArgs; i++)
  303.     {
  304.       char filename[256];
  305.  
  306.       if (_WBenchMsg->sm_ArgList[i].wa_Lock &&
  307.           NameFromLock(_WBenchMsg->sm_ArgList[i].wa_Lock, filename, 256))
  308.         {
  309.           if (_WBenchMsg->sm_ArgList[i].wa_Name)
  310.         AddPart(filename, _WBenchMsg->sm_ArgList[i].wa_Name, 256);
  311.           add_arg(&args, filename, TRUE);
  312.         }
  313.       /* else A parameter was lost, cry, cry, cry */
  314.     }
  315.     }
  316.   else                /* From CLI expand wildcards (with unix-like command line parsing) */
  317.     {
  318.       int close_error;
  319.       BPTR in, out, error;
  320.  
  321.       /* Initialise I/O. Copy CLI info */
  322.       in = Input();
  323.       out = Output();
  324.       close_error = FALSE;
  325.       if ((error = _us->pr_CES) == 0)
  326.     {
  327.       close_error = TRUE;
  328.       if ((error = Open("*", MODE_OLDFILE)) == 0)
  329.         if ((error = Open("NIL:", MODE_OLDFILE)) == 0) nomem();
  330.     }
  331.       _init_unixio(in, FALSE, out, FALSE, error, close_error);
  332.  
  333.       make_argv(&args, 1);
  334.  
  335.       anchor = _xmalloc(sizeof(struct AnchorPath) + NAMELEN);
  336.       anchor->ap_Strlen = NAMELEN;
  337.       pattern = _xmalloc(DEFPATLEN);
  338.       while (1)
  339.     {
  340.       long new_patlen;
  341.       int wild;
  342.  
  343.       /* Skip white space */
  344.       while (isspace(*line)) line++;
  345.       if (!*line) break;    /* End of command line */
  346.  
  347.       /* Extract next word */
  348.       /* Words in double quotes are handled AmigaOS style
  349.          (+ filename expansion) */
  350.       if (*line == '"')
  351.         {
  352.           line++;
  353.           arg_start = line;
  354.           /* Find end of word */
  355.           while (*line && *line != '"')
  356.         {
  357.           /* * is an escape character inside double quotes
  358.              (AmigaOS compatibility) */
  359.           if ((*line == '*') && line[1]) line++;
  360.           line++;
  361.         }
  362.           arg_end = line;
  363.           if (*line == '"') line++;
  364.           arg_quoted = quote_double;
  365.         }
  366.       /* Words in single quotes are handled unix style */
  367.       else if (*line == '\'')
  368.         {
  369.           line++;
  370.           arg_start = line;
  371.           /* Find end of word */
  372.           while (*line && *line != '\'') line++;
  373.           arg_end = line;
  374.           if (*line == '\'') line++;
  375.           arg_quoted = quote_single;
  376.         }
  377.       /* Unquoted words are handled unix style */
  378.       else            /* Plain word */
  379.         {
  380.           arg_start = line;
  381.           /* Find end of word */
  382.           while (*line && *line != ' ' && *line != '\n' && *line != '\t')
  383.         {
  384.           if (*line == '\\' && line[1]) line++;
  385.           line++;
  386.         }
  387.           arg_end = line;
  388.           arg_quoted = quote_none;
  389.         }
  390.       arg = _xmalloc(arg_end - arg_start + 1);
  391.       if (args.argc == 0)    /* Command name is left untouched */
  392.         {
  393.           strncpy(arg, arg_start, arg_end - arg_start);
  394.           arg[arg_end - arg_start] = 0;
  395.           add_arg(&args, arg, FALSE);
  396.         }
  397.       else
  398.         {
  399.           new_patlen = (arg_end - arg_start) * 2 + 16;
  400.           if (new_patlen > patlen)
  401.         {
  402.           free(pattern);
  403.           pattern = _xmalloc(new_patlen);
  404.           patlen = new_patlen;
  405.         }
  406.           extract(arg, arg_start, arg_end, arg_quoted, extract_test);
  407.           wild = ParsePattern(arg, pattern, patlen);
  408.           if (wild < 0)
  409.         {
  410.           *arg_end = 0;
  411.           _fail("Invalid wildcard %s", arg_start);
  412.         }
  413.           if (!wild)
  414.         {
  415.           extract(arg, arg_start, arg_end, arg_quoted, extract_normal);
  416.           add_arg(&args, arg, FALSE);
  417.         }
  418.           else
  419.         {
  420.           int none = TRUE;
  421.           long error;
  422.  
  423.           anchor->ap_Flags = anchor->ap_Reserved = anchor->ap_BreakBits = 0;
  424.           extract(arg, arg_start, arg_end, arg_quoted, extract_pattern);
  425.           make_argv(&wildargs, 16);
  426.           if (!(error = MatchFirst(arg, anchor)))
  427.             {
  428.               while (!error)
  429.             {
  430.               none = FALSE;
  431.               if (!safe_add_arg(&wildargs, anchor->ap_Buf, TRUE))
  432.                 {
  433.                   error = ERROR_NO_FREE_STORE;
  434.                   break;
  435.                 }
  436.               error = MatchNext(anchor);
  437.             }
  438.               MatchEnd(anchor);
  439.             }
  440.           if (error != ERROR_NO_MORE_ENTRIES)
  441.               _fail("Error expanding arguments");
  442.           if (none)
  443.             {
  444.               extract(arg, arg_start, arg_end, arg_quoted, extract_normal);
  445.               add_arg(&args, arg, FALSE);
  446.             }
  447.           else
  448.             {
  449.               tqsort(wildargs.argv, wildargs.argc);
  450.               concat_args(&args, &wildargs);
  451.               free(arg);
  452.             }
  453.         }
  454.         }
  455.     }
  456.       free(pattern);
  457.       free(anchor);
  458.     }
  459.  
  460.   make_environ();
  461.  
  462.   if (!(_amiga_user.pw_name = getenv("USER"))) _amiga_user.pw_name = "user";
  463.   if (!(_amiga_user.pw_gecos = getenv("USERNAME")))
  464.     _amiga_user.pw_gecos = _amiga_user.pw_name;
  465.   if (!(_amiga_user.pw_dir = getenv("HOME"))) _amiga_user.pw_dir = "s:";
  466.   if (!(_amiga_user.pw_shell = getenv("SHELL"))) _amiga_user.pw_shell = "bin:sh";
  467.   if (!(_system_name = getenv("HOSTNAME"))) _system_name = "amiga";
  468.     
  469.   main(args.argc, args.argv, environ);
  470.   exit(0);
  471. }
  472.