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 >
Wrap
C/C++ Source or Header
|
1996-09-28
|
12KB
|
472 lines
#include "amiga.h"
#include "signals.h"
#include "fifofd.h"
#include "timers.h"
#include "amigaos.h"
#include <exec/execbase.h>
#include <dos/var.h>
#include <workbench/startup.h>
#include <proto/timer.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/time.h>
#include <pwd.h>
struct Process *_us;
struct timeinfo *_odd_timer;
ULONG _odd_sig;
long _startup_time;
long _stack_size;
struct Library *TimerBase;
static char *empty_env = 0; /* A default empty environment */
char **environ; /* Unix style environment variable list */
char *_system_name;
extern struct ExecBase *SysBase;
extern struct passwd _amiga_user;
extern main(int argc, char **argv, char **envp);
static void nomem(void)
{
_fail("No memory");
}
static void *_xmalloc(unsigned n)
{
void *p = malloc(n);
if (!p) nomem();
return p;
}
static void *_xrealloc(void *p, unsigned n)
{
void *p2 = realloc(p, n);
if (!p2) nomem();
return p2;
}
static char *safe_copystr(char *str)
{
char *new;
if (!str) str = "";
new = malloc(strlen(str) + 1);
if (!new) return 0;
return strcpy(new, str);
}
static char *copystr(char *str)
{
char *new = safe_copystr(str);
if (!new) nomem();
return new;
}
void make_environ(void)
/* Effect: Builds a UNIX style environ variable from the AmigaOS environment.
*/
{
int env_count = 0;
long env_len = 0;
struct LocalVar *scan_env;
char **new_environ, *env_text;
for (scan_env = (struct LocalVar *)_us->pr_LocalVars.mlh_Head;
scan_env->lv_Node.ln_Succ;
scan_env = (struct LocalVar *)scan_env->lv_Node.ln_Succ)
if (scan_env->lv_Node.ln_Type == LV_VAR &&
!(scan_env->lv_Flags & (GVF_GLOBAL_ONLY | GVF_BINARY_VAR)))
{
/* We only handle local text variables */
env_count++;
env_len += 2 + strlen(scan_env->lv_Node.ln_Name) + scan_env->lv_Len;
}
new_environ = environ = (char **)_xmalloc(sizeof(char *) * (1 + env_count) +
env_len);
env_text = (char *)(environ + (1 + env_count));
if (!environ) environ = &empty_env;
else
{
for (scan_env = (struct LocalVar *)_us->pr_LocalVars.mlh_Head;
scan_env->lv_Node.ln_Succ;
scan_env = (struct LocalVar *)scan_env->lv_Node.ln_Succ)
if (scan_env->lv_Node.ln_Type == LV_VAR &&
!(scan_env->lv_Flags & (GVF_GLOBAL_ONLY | GVF_BINARY_VAR)))
{
/* We only handle local text variables */
char *env_name = scan_env->lv_Node.ln_Name;
int env_len = scan_env->lv_Len;
*new_environ++ = env_text;
while (*env_name) *env_text++ = *env_name++;
*env_text++ = '=';
env_name = scan_env->lv_Value;
while (env_len--) *env_text++ = *env_name++;
*env_text++ = '\0';
}
*new_environ = 0;
}
}
/* _main routine.
Hides the differences between wb & cli.
Provides a unix-like environment (including coomand-line parsing &
wildcard expansion)
*/
#define DEFPATLEN 256
#define NAMELEN 1024
struct args
{
int size;
int argc;
char **argv;
};
static void make_argv(struct args *args, int argc)
{
args->size = argc;
args->argc = 0;
args->argv = _xmalloc(sizeof(char *) * argc);
}
static int safe_add_arg(struct args *args, char *argument, int copy)
{
char *arg_copy;
if (copy) arg_copy = safe_copystr(argument);
else arg_copy = argument;
if (!arg_copy) return 0;
if (args->argc >= args->size)
{
/* Make argv bigger */
if (args->size * 2 < args->size + 16) args->size += 16;
else args->size *= 2;
args->argv = realloc(args->argv, sizeof(char *) * args->size);
if (!args->argv) return 0;
}
args->argv[args->argc++] = arg_copy;
return 1;
}
static void add_arg(struct args *args, char *argument, int copy)
{
if (!safe_add_arg(args, argument, copy)) nomem();
}
static void concat_args(struct args *args, struct args *add)
{
if (args->argc + add->argc > args->size)
{
args->size = (args->argc + add->argc) * 2;
args->argv = _xrealloc(args->argv, sizeof(char *) * args->size);
}
memcpy(args->argv + args->argc, add->argv, add->argc * sizeof(char *));
args->argc += add->argc;
free(add->argv);
}
typedef enum { quote_none, quote_single, quote_double } quote_type;
typedef enum { extract_normal, extract_test, extract_pattern } extract_type;
static void extract(char *buf, char *start, char *end,
quote_type type, extract_type extract)
{
char *res = buf;
switch (type)
{
case quote_single:
if (extract != extract_test)
{
buf[end - start] = '\0';
memcpy(buf, start, end - start);
}
else strcpy(buf, "a"); /* Things in quotes are never patterns */
break;
case quote_none:
while (start < end)
{
if (start[0] == '\\' && start[1])
{
start += 2;
/* Wildcard are escaped */
if (extract == extract_test) *res++ = 'a';
else if (extract == extract_pattern)
switch (start[-1])
{
case '?': case '#': case '(': case ')': case '|': case '[':
case ']': case '~': case '%': case '*': case '\'':
*res++ = '\'';
default:
*res++ = start[-1];
break;
}
else *res++ = start[-1];
}
else *res++ = *start++;
}
*res++ = '\0';
break;
case quote_double:
while (start < end)
{
if (start[0] == '*' && start[1])
{
start += 2;
switch (start[-1])
{
case 'n': *res++ = '\n'; break;
case 'e': *res++ = '\x1b'; break;
default: *res++ = start[-1]; break;
}
}
else *res++ = *start++;
}
*res++ = '\0';
break;
}
}
void __stdargs _main(char *line)
/* Effect: Call unix_main with wildcards in argc & argv expanded (like unix)
Also, do some early amiga initialisation for emacs.
*/
{
struct args args, wildargs;
char *pattern, *arg_start, *arg_end, *arg;
quote_type arg_quoted;
long patlen = DEFPATLEN;
struct AnchorPath *anchor;
struct timeval now;
if (SysBase->LibNode.lib_Version < 37) XCEXIT(20);
stdin->_file = 0;
stdin->_flag = _IOREAD;
stdout->_file = 1;
stdout->_flag = _IOWRT;
stderr->_file = 2;
stderr->_flag = _IORW | _IONBF;
_us = (struct Process *)FindTask(0);
_odd_timer = _alloc_timer();
if (!_odd_timer) _fail("Failed to create timer");
_odd_sig = _timer_sig(_odd_timer);
TimerBase = _odd_timer->io->tr_node.io_Device;
GetSysTime(&now);
_startup_time = now.tv_secs;
/* These use _startup_time, so must be here */
_init_fifo();
_init_signals();
if (_us->pr_CLI) _stack_size = ((struct CommandLineInterface *)BADDR(_us->pr_CLI))->cli_DefaultStack << 2;
else _stack_size = _us->pr_StackSize;
/* Make unix-like argc, argv (expand wildcards) */
if (!line[0]) /* Workbench, create argc & argv from files passed */
{
extern struct WBStartup *_WBenchMsg;
int i;
BPTR nilin = Open("NIL:",MODE_NEWFILE);
BPTR nilout = Open("NIL:",MODE_NEWFILE);
BPTR nilerr = Open("NIL:",MODE_NEWFILE);
/* Initialise I/O. Nothing is available */
if (!nilin || !nilout || !nilerr)
{
if (nilin) Close(nilin);
if (nilout) Close(nilout);
if (nilerr) Close(nilerr);
nomem();
}
_init_unixio(nilin, TRUE, nilout, TRUE, nilerr, TRUE);
/* Make argc, argv from Workbench parameters */
make_argv(&args, _WBenchMsg->sm_NumArgs);
for (i = 0; i < _WBenchMsg->sm_NumArgs; i++)
{
char filename[256];
if (_WBenchMsg->sm_ArgList[i].wa_Lock &&
NameFromLock(_WBenchMsg->sm_ArgList[i].wa_Lock, filename, 256))
{
if (_WBenchMsg->sm_ArgList[i].wa_Name)
AddPart(filename, _WBenchMsg->sm_ArgList[i].wa_Name, 256);
add_arg(&args, filename, TRUE);
}
/* else A parameter was lost, cry, cry, cry */
}
}
else /* From CLI expand wildcards (with unix-like command line parsing) */
{
int close_error;
BPTR in, out, error;
/* Initialise I/O. Copy CLI info */
in = Input();
out = Output();
close_error = FALSE;
if ((error = _us->pr_CES) == 0)
{
close_error = TRUE;
if ((error = Open("*", MODE_OLDFILE)) == 0)
if ((error = Open("NIL:", MODE_OLDFILE)) == 0) nomem();
}
_init_unixio(in, FALSE, out, FALSE, error, close_error);
make_argv(&args, 1);
anchor = _xmalloc(sizeof(struct AnchorPath) + NAMELEN);
anchor->ap_Strlen = NAMELEN;
pattern = _xmalloc(DEFPATLEN);
while (1)
{
long new_patlen;
int wild;
/* Skip white space */
while (isspace(*line)) line++;
if (!*line) break; /* End of command line */
/* Extract next word */
/* Words in double quotes are handled AmigaOS style
(+ filename expansion) */
if (*line == '"')
{
line++;
arg_start = line;
/* Find end of word */
while (*line && *line != '"')
{
/* * is an escape character inside double quotes
(AmigaOS compatibility) */
if ((*line == '*') && line[1]) line++;
line++;
}
arg_end = line;
if (*line == '"') line++;
arg_quoted = quote_double;
}
/* Words in single quotes are handled unix style */
else if (*line == '\'')
{
line++;
arg_start = line;
/* Find end of word */
while (*line && *line != '\'') line++;
arg_end = line;
if (*line == '\'') line++;
arg_quoted = quote_single;
}
/* Unquoted words are handled unix style */
else /* Plain word */
{
arg_start = line;
/* Find end of word */
while (*line && *line != ' ' && *line != '\n' && *line != '\t')
{
if (*line == '\\' && line[1]) line++;
line++;
}
arg_end = line;
arg_quoted = quote_none;
}
arg = _xmalloc(arg_end - arg_start + 1);
if (args.argc == 0) /* Command name is left untouched */
{
strncpy(arg, arg_start, arg_end - arg_start);
arg[arg_end - arg_start] = 0;
add_arg(&args, arg, FALSE);
}
else
{
new_patlen = (arg_end - arg_start) * 2 + 16;
if (new_patlen > patlen)
{
free(pattern);
pattern = _xmalloc(new_patlen);
patlen = new_patlen;
}
extract(arg, arg_start, arg_end, arg_quoted, extract_test);
wild = ParsePattern(arg, pattern, patlen);
if (wild < 0)
{
*arg_end = 0;
_fail("Invalid wildcard %s", arg_start);
}
if (!wild)
{
extract(arg, arg_start, arg_end, arg_quoted, extract_normal);
add_arg(&args, arg, FALSE);
}
else
{
int none = TRUE;
long error;
anchor->ap_Flags = anchor->ap_Reserved = anchor->ap_BreakBits = 0;
extract(arg, arg_start, arg_end, arg_quoted, extract_pattern);
make_argv(&wildargs, 16);
if (!(error = MatchFirst(arg, anchor)))
{
while (!error)
{
none = FALSE;
if (!safe_add_arg(&wildargs, anchor->ap_Buf, TRUE))
{
error = ERROR_NO_FREE_STORE;
break;
}
error = MatchNext(anchor);
}
MatchEnd(anchor);
}
if (error != ERROR_NO_MORE_ENTRIES)
_fail("Error expanding arguments");
if (none)
{
extract(arg, arg_start, arg_end, arg_quoted, extract_normal);
add_arg(&args, arg, FALSE);
}
else
{
tqsort(wildargs.argv, wildargs.argc);
concat_args(&args, &wildargs);
free(arg);
}
}
}
}
free(pattern);
free(anchor);
}
make_environ();
if (!(_amiga_user.pw_name = getenv("USER"))) _amiga_user.pw_name = "user";
if (!(_amiga_user.pw_gecos = getenv("USERNAME")))
_amiga_user.pw_gecos = _amiga_user.pw_name;
if (!(_amiga_user.pw_dir = getenv("HOME"))) _amiga_user.pw_dir = "s:";
if (!(_amiga_user.pw_shell = getenv("SHELL"))) _amiga_user.pw_shell = "bin:sh";
if (!(_system_name = getenv("HOSTNAME"))) _system_name = "amiga";
main(args.argc, args.argv, environ);
exit(0);
}