home *** CD-ROM | disk | FTP | other *** search
- /* Interfaces to system-dependent kernel and library entries.
- Copyright (C) 1985, 1986, 1987, 1988 Free Software Foundation, Inc.
-
- This file is part of GNU Emacs.
-
- GNU Emacs is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY. No author or distributor
- accepts responsibility to anyone for the consequences of using it
- or for whether it serves any particular purpose or works at all,
- unless he says so in writing. Refer to the GNU Emacs General Public
- License for full details.
-
- Everyone is granted permission to copy, modify and redistribute
- GNU Emacs, but only under the conditions described in the
- GNU Emacs General Public License. A copy of this license is
- supposed to have been given to you along with GNU Emacs so you
- can know your rights and responsibilities. It should be in a
- file named COPYING. Among other things, the copyright notice
- and this notice must be preserved on all copies. */
-
- #include <exec/types.h>
- #include <dos/dos.h>
- #include <string.h>
- #include <ios1.h>
-
- #include <proto/exec.h>
- #include <proto/dos.h>
-
- #undef LONGBITS
- #undef NULL
- #include <signal.h>
- #include <setjmp.h>
-
- #include "config.h"
- #undef NULL
- #include "lisp.h"
-
- #define min(x,y) ((x) > (y) ? (y) : (x))
-
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <errno.h>
- #include <dos/dos.h>
- #include <dos/dosextens.h>
- #include <dos/var.h>
- #include <proto/dos.h>
-
- #include "termhooks.h"
- #include "termchar.h"
- #include "termopts.h"
- #include "dispextern.h"
- #include "amiga.h"
-
- int term_initted; /* 1 if outer tty status has been recorded */
- static char *empty_env = 0; /* A default empty environment */
- char **environ; /* Unix style environment variable list */
-
- extern short ospeed;
-
- extern int errno;
- extern char *sys_errlist[];
-
- #undef malloc
- #undef calloc
- #undef realloc
- #undef free
-
- extern int *pure;
- long far DataSegBits;
- char *malloc_hunk;
- long malloc_hunk_size = MALLOC_HUNK_SIZE, far pre_alloc;
- extern int puresize;
- int malloc_bytes_used;
- static struct mem_header *current;
- struct mem_header *free_list;
-
- int amiga_initialized;
-
- #define ADDR_OK(x) (((long)x & ~VALMASK) == DataSegBits)
-
- void free_hunk(char *p);
-
- void amiga_early_init(int *_argc, char ***_argv)
- {
- int argc = *_argc;
- char **argv = *_argv;
-
- if (argc > 2 && !strcmp(argv[1], "-pure"))
- {
- puresize = atoi(argv[2]);
- argc -= 2; argv += 2;
- }
- if (argc > 2 && !strcmp(argv[1], "-malloc"))
- {
- malloc_hunk_size = atoi(argv[2]);
- argc -= 2; argv += 2;
- }
- if (argc > 2 && !strcmp(argv[1], "-prealloc"))
- {
- pre_alloc = atoi(argv[2]);
- argc -= 2; argv += 2;
- }
- /* Patch real argc, argv to hide arguments we used */
- argv[0] = (*_argv)[0];
- *_argv = argv;
- *_argc = argc;
-
- /* Find page containing Pure data. All data used by emacs must be
- on the same page (As a page is 2^26 bytes, this shouldn't be too
- unlikely). */
- DataSegBits = (long)&first_data & ~VALMASK;
- if (!(ADDR_OK(first_fn) && ADDR_OK(last_fn) &&
- ADDR_OK(&first_data) && ADDR_OK(&last_data) &&
- ADDR_OK(&first_bss) && ADDR_OK(&last_bss)))
- {
- printf("Emacs: I can't handle your memory configuration\n");
- exit(20);
- }
- }
-
- void amiga_undump_reinit(void)
- {
- struct mem_header *end_sentinel, *new_end, *new_block;
-
- /* Set up AmigaOS used memory list with just the malloc & pure hunks. */
- new_end = (struct mem_header *)pure - 1;
- current = (struct mem_header *)malloc_hunk - 1;
- new_end->next = 0; new_end->prev = current;
- current->prev = 0; current->next = new_end;
-
- /* Set up the memory allocation in the malloc hunk */
- free_list = (struct mem_header *)malloc_hunk;
- end_sentinel = (struct mem_header *)((char *)free_list + malloc_hunk_size
- - sizeof(struct mem_header));
- if (!amiga_initialized)
- {
- /* Before dumping */
- free_list->next = free_list + 1;
- free_list->prev = 0;
- free_list->size = 0; /* Prevents merges with this pseudo-block */
- free_list[1].prev = free_list;
- free_list[1].next = end_sentinel;
- free_list[1].size =
- malloc_hunk_size - 2 * sizeof(struct mem_header) - sizeof(long);
- /* The - sizeof(long) prevents any merges with end_sentinel */
-
- end_sentinel->size = 0;
- end_sentinel->prev = free_list + 1;
- end_sentinel->next = 0;
-
- malloc_bytes_used = 0;
- }
- else if (pre_alloc)
- {
- /* After having undumped extend malloc block */
- /* Move end_sentinel: */
- new_end = (struct mem_header *)((char *)free_list + malloc_hunk_size +
- pre_alloc - sizeof(struct mem_header));
- new_end->size = 0;
- new_end->next = 0;
- new_end->prev = end_sentinel->prev;
- end_sentinel->prev->next = new_end;
-
- /* Add extra memory (pre_alloc bytes) */
- new_block = (struct mem_header *)((char *)end_sentinel - sizeof(long));
- new_block->size = pre_alloc;
- free_hunk((char *)(new_block + 1));
- }
-
- early_amiga_tty();
- early_clipboard();
-
- if (!onexit(cleanup_amiga)) exit(20);
- }
-
- int alloca_calling;
-
- void *alloc_sys(long memsize)
- /* Effect: Allocate from AmigaOS (via AllocMem). */
- {
- /* Allocation rounded up to multiple of 4 */
- long size = ((memsize + 3) & ~3) + sizeof(struct mem_header);
- struct mem_header *mem;
-
- mem = AllocMem(size, 0);
- if (!mem) return 0;
- /* All memory *must* be allocated on the same page ! */
- if (!ADDR_OK(mem))
- {
- FreeMem(mem, size);
- return 0;
- }
- if (current) current->prev = mem;
- mem->next = current;
- mem->prev = 0;
- current = mem;
- mem->size = size;
-
- return mem + 1;
- }
-
- void free_sys(char *p)
- {
- struct mem_header *old = (struct mem_header *)p - 1;
-
- if (old == current)
- {
- current = current->next;
- if (current) current->prev = 0;
- }
- else
- {
- old->prev->next = old->next;
- if (old->next) old->next->prev = old->prev;
- }
- FreeMem(old, old->size);
- }
-
- static void free_sys_all(void)
- {
- struct mem_header *next;
-
- while (current)
- {
- next = current->next;
- FreeMem(current, current->size);
- current = next;
- }
- }
-
- void *alloc_hunk(long memsize)
- /* Effect: Allocates from the malloc hunk (which is dumped to disk).
- */
- {
- /* Allocation rounded up to multiple of 4 */
- long size = ((memsize + 3) & ~3) + sizeof(struct mem_header);
- /* Find a free block in the memory list */
- struct mem_header *scan = free_list->next;
-
- while (scan->size > 0)
- {
- if (size < scan->size) /* Found ! */
- {
- long end;
-
- /* Split block if big enough */
- if (size + sizeof(struct mem_header) + 8 > scan->size)
- {
- /* Remove block from list */
- scan->prev->next = scan->next;
- scan->next->prev = scan->prev;
- }
- else
- {
- /* Split block */
- struct mem_header *new = (struct mem_header *)((char *)scan + size);
-
- new->prev = scan->prev;
- new->next = scan->next;
- scan->prev->next = new;
- scan->next->prev = new;
- new->size = scan->size - size;
- scan->size = size;
- }
- if (!amiga_initialized)
- {
- end = (char *)scan - (char *)free_list + scan->size +
- sizeof(long) + sizeof(struct mem_header);
- if (end > malloc_bytes_used) malloc_bytes_used = end;
- }
- return scan + 1;
- }
- scan = scan->next;
- }
- return 0;
- }
-
- void free_hunk(char *p)
- {
- struct mem_header *old = (struct mem_header *)p - 1, *scan = free_list;
-
- do scan = scan->next; while (scan < old);
-
- /* Check for merges (potentially with both sides) */
- if ((char *)scan->prev + scan->prev->size == (char *)old)
- if ((char *)old + old->size == (char *)scan)
- {
- /* Merge all 3 blocks together */
- scan->prev->size += old->size + scan->size;
- scan->next->prev = scan->prev;
- scan->prev->next = scan->next;
- }
- else /* Merge with previous block */
- scan->prev->size += old->size;
- else if ((char *)old + old->size == (char *)scan)
- {
- /* Merge with next block */
- old->size += scan->size;
- scan->prev->next = old;
- scan->next->prev = old;
- old->prev = scan->prev;
- old->next = scan->next;
- }
- else /* Add a new block */
- {
- old->next = scan;
- old->prev = scan->prev;
- scan->prev->next = old;
- scan->prev = old;
- }
- }
-
- char *emacs_malloc(long size)
- {
- if (!amiga_initialized)
- if (alloca_calling)
- {
- alloca_calling = 0;
- return alloc_sys(size);
- }
- else
- {
- void *mem = alloc_hunk(size);
-
- if (!mem)
- {
- printf("Emacs dump: ran out of memory for malloc. \n"
- "See the -malloc option for more information.\n");
- exit(20);
- }
- return mem;
- }
- else
- {
- alloca_calling = 0;
- if (pre_alloc)
- {
- void *mem;
-
- if (mem = alloc_hunk(size)) return mem;
- }
- return alloc_sys(size);
- }
- }
-
- char *emacs_calloc(long n, long size)
- {
- char *t;
- long rsize = n * size;
-
- t = emacs_malloc(rsize);
- if (t) memset (t, 0, rsize);
-
- return t;
- }
-
- char *emacs_realloc(char *p, long size)
- {
- char *new = emacs_malloc(size);
- struct mem_header *old = (struct mem_header *)p - 1;
-
- if (new)
- {
- long minsize;
- long oldsize = old->size - sizeof(struct mem_header);
-
- if (size < oldsize) minsize = size;
- else minsize = oldsize;
-
- memcpy(new, p, minsize);
- }
- emacs_free(p);
- return new;
- }
-
- emacs_free(char *p)
- {
- struct mem_header *old = (struct mem_header *)p - 1;
-
- if ((char *)p >= malloc_hunk &&
- (char *)p <= malloc_hunk + malloc_hunk_size + pre_alloc)
- {
- if (!amiga_initialized || pre_alloc) free_hunk(p);
- }
- else free_sys(p);
- }
-
- char *expand_path(char *path, char *buf, int len)
- {
- BPTR dirlock;
-
- dirlock = Lock(path, ACCESS_READ);
- if (dirlock) /* Expand lock name */
- if (NameFromLock(dirlock, buf, len)) return buf;
-
- return 0;
- }
-
- char *getwd (char *pathname)
- {
- return getcwd(pathname, 1024);
- }
-
- char *mktemp(char *name)
- {
- int l;
- char *change = name + strlen(name) - 6;
- char letter = 'a';
- struct Task *us = FindTask(0);
- char id[9], *end_id;
-
- sprintf(id, "%p", us);
- l = strlen(id);
- end_id = l > 5 ? id + l - 5 : id;
- sprintf(change, "a%s", end_id);
-
- while (letter <= 'z')
- {
- *change = letter;
- if (access(name, 0)) return name;
- letter++;
- }
- return 0;
- }
-
- int pipe(int fd[2])
- {
- char name[16];
- char *change = name + 6;
- char letter = 'a';
- char id[9], *end_id;
-
- sprintf(name, "pipe:ea%lx", FindTask((STRPTR)0));
-
- while (letter <= 'z')
- {
- *change = letter;
- fd[0] = open(name, O_RDONLY);
- if (fd[0] != -1)
- {
- fd[1] = open(name, O_WRONLY | O_CREAT);
- if (fd[1] == -1) /* Oops, we stole somebody's pipe ... */
- {
- close(fd[0]);
- return -1;
- }
- return 0;
- }
- letter++;
- }
- return -1;
- }
-
- int convert_oserr(int ioerr)
- {
- switch (ioerr)
- {
- case 0: return 0;
- case ERROR_NO_FREE_STORE: return ENOMEM;
- case ERROR_TASK_TABLE_FULL: return EAGAIN;
- case ERROR_BAD_TEMPLATE: case ERROR_REQUIRED_ARG_MISSING:
- case ERROR_KEY_NEEDS_ARG: case ERROR_TOO_MANY_ARGS:
- case ERROR_UNMATCHED_QUOTES: case ERROR_LINE_TOO_LONG: return EINVAL;
- case ERROR_OBJECT_IN_USE: return EBUSY;
- case ERROR_OBJECT_EXISTS: return EEXIST;
- case ERROR_DIR_NOT_FOUND: return ENOENT;
- case ERROR_OBJECT_NOT_FOUND: return ENOENT;
- case ERROR_BAD_STREAM_NAME: return EINVAL;
- case ERROR_OBJECT_TOO_LARGE: return E2BIG;
- case ERROR_ACTION_NOT_KNOWN: return EINVAL;
- case ERROR_INVALID_COMPONENT_NAME: return EINVAL;
- case ERROR_INVALID_LOCK: return EINVAL;
- case ERROR_OBJECT_WRONG_TYPE: return EINVAL;
- case ERROR_DISK_WRITE_PROTECTED: return EACCES;
- case ERROR_SEEK_ERROR: return EIO;
- case ERROR_DISK_FULL: return ENOSPC;
- case ERROR_DELETE_PROTECTED: return EACCES;
- case ERROR_WRITE_PROTECTED: return EACCES;
- case ERROR_READ_PROTECTED: return EACCES;
- case ERROR_RENAME_ACROSS_DEVICES: return EXDEV;
- default: return EOSERR;
- }
- }
-
- int link(char *from, char *to)
- {
- BPTR from_lock = Lock(from, ACCESS_READ);
-
- if (from_lock)
- {
- int ok = MakeLink(to, from_lock, 0);
-
- UnLock(from_lock);
- if (ok) return 0;
- }
- errno = convert_oserr(IoErr());
- return -1;
- }
-
- int rename(char *from, char *to)
- {
- long err;
-
- if (Rename(from, to)) return 0;
- err = IoErr();
- if (err == ERROR_OBJECT_EXISTS)
- {
- if (DeleteFile(to) && Rename(from, to)) return 0;
- err = IoErr();
- }
- errno = convert_oserr(err);
- return -1;
- }
-
- void make_environ(void)
- /* Effect: Builds a UNIX style environ variable from the AmigaDOS environment.
- */
- {
- int env_count = 0;
- long env_len = 0;
- struct LocalVar *scan_env;
- struct Process *us = (struct Process *)FindTask(0L);
- 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;
- }
- }
-
- set_exclusive_use (fd)
- int fd;
- {
- /* Ok to do nothing if this feature does not exist */
- }
-
- setpgrp_of_tty (pid)
- int pid;
- {
- /* Just ignore this for now and hope for the best */
- }
-
- /* Suspend the Emacs process; give terminal to its superior. */
- sys_suspend ()
- {
- /* We'll let this slide for the time being... */
- }
-
- init_sigio ()
- {
- request_sigio ();
- }
-
- reset_sigio ()
- {
- unrequest_sigio ();
- }
-
- request_sigio ()
- {
- croak ("request sigio");
- }
-
- unrequest_sigio ()
- {
- croak ("unrequest sigio");
- }
-
- init_sys_modes ()
- {
-
- if (noninteractive)
- return;
-
- if (inhibit_window_system) clear_screen();
-
- term_initted = 1;
- }
-
- /* Return nonzero if safe to use tabs in output.
- At the time this is called, init_sys_modes has not been done yet. */
-
- tabs_safe_p ()
- {
- if (noninteractive)
- return 1;
-
- return 0; /* Not safe on Amiga !? */
- }
-
- /* get_screen_size is in amiga_tty.c */
-
- reset_sys_modes ()
- {
- if (noninteractive)
- {
- fflush (stdout);
- return;
- }
- move_cursor (screen_height - 1, 0);
- clear_end_of_line (screen_width);
- /* clear_end_of_line may move the cursor */
- move_cursor (screen_height - 1, 0);
- }
-
- char *
- get_system_name ()
- {
- return("an_amiga");
- }
-
- select_alarm ()
- {
- /* Not going to deal with this mess... */
- }
-
- /* Only rfds are checked and timeout must point somewhere */
- int
- select (nfds, rfds, wfds, efds, timeout)
- int nfds;
- int *rfds, *wfds, *efds, *timeout;
- {
- /* Not going to deal with this ... kludge! */
- }
-
- /*
- * This function will go away as soon as all the stubs fixed. (fnf)
- */
-
- croak (badfunc)
- char *badfunc;
- {
- printf ("%s not yet implemented\r\n", badfunc);
- reset_sys_modes ();
- exit (1);
- }
-
- /* This getenv removes trailing newlines & multiple calls don't
- destroy results */
- char *getenv (char *varname)
- {
- char *return_string;
- char buf[64];
-
- if (varname && varname[0])
- {
- int len, size;
-
- len = GetVar(varname, buf, 64, LV_VAR);
- if (len >= 0)
- {
- size = IoErr();
- return_string = emacs_malloc(size + 1);
- if (size != len)
- {
- if (GetVar(varname, return_string, size + 1, LV_VAR) > 0)
- return return_string;
- }
- else return strcpy(return_string, buf);
- }
- }
- return 0;
- }
-
- int fstat(int fd, struct stat *sbuf)
- {
- char name[256];
- struct UFB *ufb = chkufb(fd);
-
- if (!ufb) return -1;
- if (!NameFromFH(ufb->ufbfh, name, 256)) return -1;
- return stat(name, sbuf);
- }
-
- struct IORequest *device_open(char *name, ULONG unit, ULONG flags,
- APTR data, ULONG data_len, int req_size)
- {
- struct MsgPort *port;
- struct IORequest *ioreq;
-
- if ((port = CreateMsgPort()) && (ioreq = CreateIORequest(port, req_size)))
- {
- if (data)
- {
- struct IOStdReq *io2 = (struct IOStdReq *)ioreq;
- io2->io_Data = data;
- io2->io_Length = data_len;
- }
- if (OpenDevice(name, unit, ioreq, flags) == 0) return ioreq;
- }
- if (ioreq) DeleteIORequest(ioreq);
- if (port) DeletePort(port);
- return 0;
- }
-
- void device_close(struct IORequest *ioreq)
- {
- if (ioreq)
- {
- CloseDevice(ioreq);
- DeletePort(ioreq->io_Message.mn_ReplyPort);
- DeleteIORequest(ioreq);
- }
- }
-
- syms_of_amiga ()
- {
- DEFVAR_BOOL("amiga-initialized", &amiga_initialized, "");
- DEFVAR_INT("amiga-malloc-bytes-used", &malloc_bytes_used,
- "Number of malloc bytes used when emacs was dumped");
- syms_of_amiga_tty();
- syms_of_amiga_menu();
- syms_of_amiga_clipboard();
- }
-
- void cleanup_amiga(void)
- {
- cleanup_amiga_processes();
- cleanup_clipboard();
- cleanup_amiga_tty();
- free_sys_all();
- }
-
- void init_amiga(void)
- {
- make_environ();
-
- if (!(init_amiga_tty() && init_clipboard() && init_amiga_processes()))
- exit(20);
- }
-