home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / amiga / utility / text / emacsdif.lha / emacs-18.58 / src / amiga_sysdep.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-05-16  |  16.9 KB  |  763 lines

  1. /* Interfaces to system-dependent kernel and library entries.
  2. Copyright (C) 1985, 1986, 1987, 1988 Free Software Foundation, Inc.
  3.  
  4. This file is part of GNU Emacs.
  5.  
  6. GNU Emacs is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY.  No author or distributor
  8. accepts responsibility to anyone for the consequences of using it
  9. or for whether it serves any particular purpose or works at all,
  10. unless he says so in writing.  Refer to the GNU Emacs General Public
  11. License for full details.
  12.  
  13. Everyone is granted permission to copy, modify and redistribute
  14. GNU Emacs, but only under the conditions described in the
  15. GNU Emacs General Public License.   A copy of this license is
  16. supposed to have been given to you along with GNU Emacs so you
  17. can know your rights and responsibilities.  It should be in a
  18. file named COPYING.  Among other things, the copyright notice
  19. and this notice must be preserved on all copies.  */
  20.  
  21. #include <exec/types.h>
  22. #include <dos/dos.h>
  23. #include <string.h>
  24. #include <ios1.h>
  25.  
  26. #include <proto/exec.h>
  27. #include <proto/dos.h>
  28.  
  29. #undef LONGBITS
  30. #undef NULL
  31. #include <signal.h>
  32. #include <setjmp.h>
  33.  
  34. #include "config.h"
  35. #undef NULL
  36. #include "lisp.h"
  37.  
  38. #define min(x,y) ((x) > (y) ? (y) : (x))
  39.  
  40. #include <stdio.h>
  41. #include <sys/types.h>
  42. #include <sys/stat.h>
  43. #include <errno.h>
  44. #include <dos/dos.h>
  45. #include <dos/dosextens.h>
  46. #include <dos/var.h>
  47. #include <proto/dos.h>
  48.  
  49. #include "termhooks.h"
  50. #include "termchar.h"
  51. #include "termopts.h"
  52. #include "dispextern.h"
  53. #include "amiga.h"
  54.  
  55. int term_initted;        /* 1 if outer tty status has been recorded */
  56. static char *empty_env = 0; /* A default empty environment */
  57. char **environ;            /* Unix style environment variable list */
  58.  
  59. extern short ospeed;
  60.  
  61. extern int errno;
  62. extern char *sys_errlist[];
  63.  
  64. #undef malloc
  65. #undef calloc
  66. #undef realloc
  67. #undef free
  68.  
  69. extern int *pure;
  70. long far DataSegBits;
  71. char *malloc_hunk;
  72. long malloc_hunk_size = MALLOC_HUNK_SIZE, far pre_alloc;
  73. extern int puresize;
  74. int malloc_bytes_used;
  75. static struct mem_header *current;
  76. struct mem_header *free_list;
  77.  
  78. int amiga_initialized;
  79.  
  80. #define ADDR_OK(x) (((long)x & ~VALMASK) == DataSegBits)
  81.  
  82. void free_hunk(char *p);
  83.  
  84. void amiga_early_init(int *_argc, char ***_argv)
  85. {
  86.     int argc = *_argc;
  87.     char **argv = *_argv;
  88.  
  89.     if (argc > 2 && !strcmp(argv[1], "-pure"))
  90.     {
  91.     puresize = atoi(argv[2]);
  92.     argc -= 2; argv += 2;
  93.     }
  94.     if (argc > 2 && !strcmp(argv[1], "-malloc"))
  95.     {
  96.     malloc_hunk_size = atoi(argv[2]);
  97.     argc -= 2; argv += 2;
  98.     }
  99.     if (argc > 2 && !strcmp(argv[1], "-prealloc"))
  100.     {
  101.     pre_alloc = atoi(argv[2]);
  102.     argc -= 2; argv += 2;
  103.     }
  104.     /* Patch real argc, argv to hide arguments we used */
  105.     argv[0] = (*_argv)[0];
  106.     *_argv = argv;
  107.     *_argc = argc;
  108.  
  109.     /* Find page containing Pure data. All data used by emacs must be
  110.        on the same page (As a page is 2^26 bytes, this shouldn't be too
  111.        unlikely). */
  112.     DataSegBits = (long)&first_data & ~VALMASK;
  113.     if (!(ADDR_OK(first_fn) && ADDR_OK(last_fn) &&
  114.       ADDR_OK(&first_data) && ADDR_OK(&last_data) &&
  115.       ADDR_OK(&first_bss) && ADDR_OK(&last_bss)))
  116.     {
  117.     printf("Emacs: I can't handle your memory configuration\n");
  118.     exit(20);
  119.     }
  120. }
  121.  
  122. void amiga_undump_reinit(void)
  123. {
  124.     struct mem_header *end_sentinel, *new_end, *new_block;
  125.  
  126.     /* Set up AmigaOS used memory list with just the malloc & pure hunks. */
  127.     new_end = (struct mem_header *)pure - 1;
  128.     current = (struct mem_header *)malloc_hunk - 1;
  129.     new_end->next = 0; new_end->prev = current;
  130.     current->prev = 0; current->next = new_end;
  131.  
  132.     /* Set up the memory allocation in the malloc hunk */
  133.     free_list = (struct mem_header *)malloc_hunk;
  134.     end_sentinel = (struct mem_header *)((char *)free_list + malloc_hunk_size
  135.                      - sizeof(struct mem_header));
  136.     if (!amiga_initialized)
  137.     {
  138.     /* Before dumping */
  139.     free_list->next = free_list + 1;
  140.     free_list->prev = 0;
  141.     free_list->size = 0; /* Prevents merges with this pseudo-block */
  142.     free_list[1].prev = free_list;
  143.     free_list[1].next = end_sentinel;
  144.     free_list[1].size =
  145.         malloc_hunk_size - 2 * sizeof(struct mem_header) - sizeof(long);
  146.     /* The - sizeof(long) prevents any merges with end_sentinel */
  147.  
  148.     end_sentinel->size = 0;
  149.     end_sentinel->prev = free_list + 1;
  150.     end_sentinel->next = 0;
  151.  
  152.     malloc_bytes_used = 0;
  153.     }
  154.     else if (pre_alloc)
  155.     {
  156.     /* After having undumped extend malloc block */
  157.     /* Move end_sentinel: */
  158.     new_end = (struct mem_header *)((char *)free_list + malloc_hunk_size +
  159.                     pre_alloc - sizeof(struct mem_header));
  160.     new_end->size = 0;
  161.     new_end->next = 0;
  162.     new_end->prev = end_sentinel->prev;
  163.     end_sentinel->prev->next = new_end;
  164.  
  165.     /* Add extra memory (pre_alloc bytes) */
  166.     new_block = (struct mem_header *)((char *)end_sentinel - sizeof(long));
  167.     new_block->size = pre_alloc;
  168.     free_hunk((char *)(new_block + 1));
  169.     }
  170.  
  171.     early_amiga_tty();
  172.     early_clipboard();
  173.  
  174.     if (!onexit(cleanup_amiga)) exit(20);
  175. }
  176.  
  177. int alloca_calling;
  178.  
  179. void *alloc_sys(long memsize)
  180. /* Effect: Allocate from AmigaOS (via AllocMem). */
  181. {
  182.     /* Allocation rounded up to multiple of 4 */
  183.     long size = ((memsize + 3) & ~3) + sizeof(struct mem_header);
  184.     struct mem_header *mem;
  185.  
  186.     mem = AllocMem(size, 0);
  187.     if (!mem) return 0;
  188.     /* All memory *must* be allocated on the same page ! */
  189.     if (!ADDR_OK(mem))
  190.     {
  191.     FreeMem(mem, size);
  192.     return 0;
  193.     }
  194.     if (current) current->prev = mem;
  195.     mem->next = current;
  196.     mem->prev = 0;
  197.     current = mem;
  198.     mem->size = size;
  199.  
  200.     return mem + 1;
  201. }
  202.  
  203. void free_sys(char *p)
  204. {
  205.     struct mem_header *old = (struct mem_header *)p - 1;
  206.  
  207.     if (old == current)
  208.     {
  209.     current = current->next;
  210.     if (current) current->prev = 0;
  211.     }
  212.     else
  213.     {
  214.     old->prev->next = old->next;
  215.     if (old->next) old->next->prev = old->prev;
  216.     }
  217.     FreeMem(old, old->size);
  218. }
  219.  
  220. static void free_sys_all(void)
  221. {
  222.     struct mem_header *next;
  223.  
  224.     while (current)
  225.     {
  226.     next = current->next;
  227.     FreeMem(current, current->size);
  228.     current = next;
  229.     }
  230. }
  231.  
  232. void *alloc_hunk(long memsize)
  233. /* Effect: Allocates from the malloc hunk (which is dumped to disk).
  234. */
  235. {
  236.     /* Allocation rounded up to multiple of 4 */
  237.     long size = ((memsize + 3) & ~3) + sizeof(struct mem_header);
  238.     /* Find a free block in the memory list */
  239.     struct mem_header *scan = free_list->next;
  240.  
  241.     while (scan->size > 0)
  242.     {
  243.     if (size < scan->size)    /* Found ! */
  244.     {
  245.         long end;
  246.  
  247.         /* Split block if big enough */
  248.         if (size + sizeof(struct mem_header) + 8 > scan->size)
  249.         {
  250.         /* Remove block from list */
  251.         scan->prev->next = scan->next;
  252.         scan->next->prev = scan->prev;
  253.         }
  254.         else
  255.         {
  256.         /* Split block */
  257.         struct mem_header *new = (struct mem_header *)((char *)scan + size);
  258.  
  259.         new->prev = scan->prev;
  260.         new->next = scan->next;
  261.         scan->prev->next = new;
  262.         scan->next->prev = new;
  263.         new->size = scan->size - size;
  264.         scan->size = size;
  265.         }
  266.         if (!amiga_initialized)
  267.         {
  268.         end = (char *)scan - (char *)free_list + scan->size +
  269.             sizeof(long) + sizeof(struct mem_header);
  270.         if (end > malloc_bytes_used) malloc_bytes_used = end;
  271.         }
  272.         return scan + 1;
  273.     }
  274.     scan = scan->next;
  275.     }
  276.     return 0;
  277. }
  278.  
  279. void free_hunk(char *p)
  280. {
  281.     struct mem_header *old = (struct mem_header *)p - 1, *scan = free_list;
  282.  
  283.     do scan = scan->next; while (scan < old);
  284.  
  285.     /* Check for merges (potentially with both sides) */
  286.     if ((char *)scan->prev + scan->prev->size == (char *)old)
  287.     if ((char *)old + old->size == (char *)scan)
  288.     {
  289.         /* Merge all 3 blocks together */
  290.         scan->prev->size += old->size + scan->size;
  291.         scan->next->prev = scan->prev;
  292.         scan->prev->next = scan->next;
  293.     }
  294.     else /* Merge with previous block */
  295.         scan->prev->size += old->size;
  296.     else if ((char *)old + old->size == (char *)scan)
  297.     {
  298.     /* Merge with next block */
  299.     old->size += scan->size;
  300.     scan->prev->next = old;
  301.     scan->next->prev = old;
  302.     old->prev = scan->prev;
  303.     old->next = scan->next;
  304.     }
  305.     else /* Add a new block */
  306.     {
  307.     old->next = scan;
  308.     old->prev = scan->prev;
  309.     scan->prev->next = old;
  310.     scan->prev = old;
  311.     }
  312. }
  313.  
  314. char *emacs_malloc(long size)
  315. {
  316.     if (!amiga_initialized)
  317.     if (alloca_calling)
  318.     {
  319.         alloca_calling = 0;
  320.         return alloc_sys(size);
  321.     }
  322.     else
  323.     {
  324.         void *mem = alloc_hunk(size);
  325.  
  326.         if (!mem)
  327.         {
  328.         printf("Emacs dump: ran out of memory for malloc. \n"
  329.                "See the -malloc option for more information.\n");
  330.         exit(20);
  331.         }
  332.         return mem;
  333.     }
  334.     else
  335.     {
  336.     alloca_calling = 0;
  337.     if (pre_alloc)
  338.     {
  339.         void *mem;
  340.  
  341.         if (mem = alloc_hunk(size)) return mem;
  342.     }
  343.     return alloc_sys(size);
  344.     }
  345. }
  346.  
  347. char *emacs_calloc(long n, long size)
  348. {
  349.     char *t;
  350.     long rsize = n * size;
  351.  
  352.     t = emacs_malloc(rsize);
  353.     if (t) memset (t, 0, rsize);
  354.  
  355.     return t;
  356. }
  357.  
  358. char *emacs_realloc(char *p, long size)
  359. {
  360.     char *new = emacs_malloc(size);
  361.     struct mem_header *old = (struct mem_header *)p - 1;
  362.  
  363.     if (new)
  364.     {
  365.     long minsize;
  366.     long oldsize = old->size - sizeof(struct mem_header);
  367.  
  368.     if (size < oldsize) minsize = size;
  369.     else minsize = oldsize;
  370.  
  371.     memcpy(new, p, minsize);
  372.     }
  373.     emacs_free(p);
  374.     return new;
  375. }
  376.  
  377. emacs_free(char *p)
  378. {
  379.     struct mem_header *old = (struct mem_header *)p - 1;
  380.  
  381.     if ((char *)p >= malloc_hunk &&
  382.     (char *)p <= malloc_hunk + malloc_hunk_size + pre_alloc)
  383.     {
  384.     if (!amiga_initialized || pre_alloc) free_hunk(p);
  385.     }
  386.     else free_sys(p);
  387. }
  388.  
  389. char *expand_path(char *path, char *buf, int len)
  390. {
  391.     BPTR dirlock;
  392.  
  393.     dirlock = Lock(path, ACCESS_READ);
  394.     if (dirlock) /* Expand lock name */
  395.     if (NameFromLock(dirlock, buf, len)) return buf;
  396.  
  397.     return 0;
  398. }
  399.  
  400. char *getwd (char *pathname)
  401. {
  402.     return getcwd(pathname, 1024);
  403. }
  404.  
  405. char *mktemp(char *name)
  406. {
  407.     int l;
  408.     char *change = name + strlen(name) - 6;
  409.     char letter = 'a';
  410.     struct Task *us = FindTask(0);
  411.     char id[9], *end_id;
  412.  
  413.     sprintf(id, "%p", us);
  414.     l = strlen(id);
  415.     end_id = l > 5 ? id + l - 5 : id;
  416.     sprintf(change, "a%s", end_id);
  417.  
  418.     while (letter <= 'z')
  419.     {
  420.     *change = letter;
  421.     if (access(name, 0)) return name;
  422.     letter++;
  423.     }
  424.     return 0;
  425. }
  426.  
  427. int pipe(int fd[2])
  428. {
  429.     char name[16];
  430.     char *change = name + 6;
  431.     char letter = 'a';
  432.     char id[9], *end_id;
  433.  
  434.     sprintf(name, "pipe:ea%lx", FindTask((STRPTR)0));
  435.  
  436.     while (letter <= 'z')
  437.     {
  438.     *change = letter;
  439.     fd[0] = open(name, O_RDONLY);
  440.     if (fd[0] != -1)
  441.     {
  442.         fd[1] = open(name, O_WRONLY | O_CREAT);
  443.         if (fd[1] == -1) /* Oops, we stole somebody's pipe ... */
  444.         {
  445.         close(fd[0]);
  446.         return -1;
  447.         }
  448.         return 0;
  449.     }
  450.     letter++;
  451.     }
  452.     return -1;
  453. }
  454.  
  455. int convert_oserr(int ioerr)
  456. {
  457.     switch (ioerr)
  458.     {
  459.     case 0: return 0;
  460.     case ERROR_NO_FREE_STORE: return ENOMEM;
  461.     case ERROR_TASK_TABLE_FULL: return EAGAIN;
  462.     case ERROR_BAD_TEMPLATE: case ERROR_REQUIRED_ARG_MISSING:
  463.     case ERROR_KEY_NEEDS_ARG: case ERROR_TOO_MANY_ARGS:
  464.     case ERROR_UNMATCHED_QUOTES: case ERROR_LINE_TOO_LONG: return EINVAL;
  465.     case ERROR_OBJECT_IN_USE: return EBUSY;
  466.     case ERROR_OBJECT_EXISTS: return EEXIST;
  467.     case ERROR_DIR_NOT_FOUND: return ENOENT;
  468.     case ERROR_OBJECT_NOT_FOUND: return ENOENT;
  469.     case ERROR_BAD_STREAM_NAME: return EINVAL;
  470.     case ERROR_OBJECT_TOO_LARGE: return E2BIG;
  471.     case ERROR_ACTION_NOT_KNOWN: return EINVAL;
  472.     case ERROR_INVALID_COMPONENT_NAME: return EINVAL;
  473.     case ERROR_INVALID_LOCK: return EINVAL;
  474.     case ERROR_OBJECT_WRONG_TYPE: return EINVAL;
  475.     case ERROR_DISK_WRITE_PROTECTED: return EACCES;
  476.     case ERROR_SEEK_ERROR: return EIO;
  477.     case ERROR_DISK_FULL: return ENOSPC;
  478.     case ERROR_DELETE_PROTECTED: return EACCES;
  479.     case ERROR_WRITE_PROTECTED: return EACCES;
  480.     case ERROR_READ_PROTECTED: return EACCES;
  481.     case ERROR_RENAME_ACROSS_DEVICES: return EXDEV;
  482.     default: return EOSERR;
  483.     }
  484. }
  485.  
  486. int link(char *from, char *to)
  487. {
  488.     BPTR from_lock = Lock(from, ACCESS_READ);
  489.  
  490.     if (from_lock)
  491.     {
  492.     int ok = MakeLink(to, from_lock, 0);
  493.  
  494.     UnLock(from_lock);
  495.     if (ok) return 0;
  496.     }
  497.     errno = convert_oserr(IoErr());
  498.     return -1;
  499. }
  500.  
  501. int rename(char *from, char *to)
  502. {
  503.     long err;
  504.  
  505.     if (Rename(from, to)) return 0;
  506.     err = IoErr();
  507.     if (err == ERROR_OBJECT_EXISTS)
  508.     {
  509.     if (DeleteFile(to) && Rename(from, to)) return 0;
  510.     err = IoErr();
  511.     }
  512.     errno = convert_oserr(err);
  513.     return -1;
  514. }
  515.  
  516. void make_environ(void)
  517. /* Effect: Builds a UNIX style environ variable from the AmigaDOS environment.
  518. */
  519. {
  520.     int env_count = 0;
  521.     long env_len = 0;
  522.     struct LocalVar *scan_env;
  523.     struct Process *us = (struct Process *)FindTask(0L);
  524.     char **new_environ, *env_text;
  525.  
  526.     for (scan_env = (struct LocalVar *)us->pr_LocalVars.mlh_Head;
  527.      scan_env->lv_Node.ln_Succ;
  528.      scan_env = (struct LocalVar *)scan_env->lv_Node.ln_Succ)
  529.     if (scan_env->lv_Node.ln_Type == LV_VAR &&
  530.         !(scan_env->lv_Flags & (GVF_GLOBAL_ONLY | GVF_BINARY_VAR)))
  531.     {
  532.         /* We only handle local text variables */
  533.         env_count++;
  534.         env_len += 2 + strlen(scan_env->lv_Node.ln_Name) + scan_env->lv_Len;
  535.     }
  536.  
  537.     new_environ = environ = (char **)xmalloc(sizeof(char *) * (1 + env_count) + env_len);
  538.     env_text = (char *)(environ + (1 + env_count));
  539.     if (!environ) environ = &empty_env;
  540.     else
  541.     {
  542.     for (scan_env = (struct LocalVar *)us->pr_LocalVars.mlh_Head;
  543.          scan_env->lv_Node.ln_Succ;
  544.          scan_env = (struct LocalVar *)scan_env->lv_Node.ln_Succ)
  545.         if (scan_env->lv_Node.ln_Type == LV_VAR &&
  546.         !(scan_env->lv_Flags & (GVF_GLOBAL_ONLY | GVF_BINARY_VAR)))
  547.         {
  548.         /* We only handle local text variables */
  549.         char *env_name = scan_env->lv_Node.ln_Name;
  550.         int env_len = scan_env->lv_Len;
  551.  
  552.         *new_environ++ = env_text;
  553.         while (*env_name) *env_text++ = *env_name++;
  554.         *env_text++ = '=';
  555.         env_name = scan_env->lv_Value;
  556.         while (env_len--) *env_text++ = *env_name++;
  557.         *env_text++ = '\0';
  558.         }
  559.     *new_environ = 0;
  560.     }
  561. }
  562.  
  563. set_exclusive_use (fd)
  564.      int fd;
  565. {
  566.   /* Ok to do nothing if this feature does not exist */
  567. }
  568.  
  569. setpgrp_of_tty (pid)
  570.      int pid;
  571. {
  572.   /* Just ignore this for now and hope for the best */
  573. }
  574.  
  575. /* Suspend the Emacs process; give terminal to its superior.  */
  576. sys_suspend ()
  577. {
  578. /* We'll let this slide for the time being... */
  579. }
  580.  
  581. init_sigio ()
  582. {
  583.   request_sigio ();
  584. }
  585.  
  586. reset_sigio ()
  587. {
  588.   unrequest_sigio ();
  589. }
  590.  
  591. request_sigio ()
  592. {
  593.   croak ("request sigio");
  594. }
  595.  
  596. unrequest_sigio ()
  597. {
  598.   croak ("unrequest sigio");
  599. }
  600.  
  601. init_sys_modes ()
  602. {
  603.  
  604.   if (noninteractive)
  605.     return;
  606.  
  607.   if (inhibit_window_system) clear_screen();
  608.  
  609.   term_initted = 1;
  610. }
  611.  
  612. /* Return nonzero if safe to use tabs in output.
  613.    At the time this is called, init_sys_modes has not been done yet.  */
  614.  
  615. tabs_safe_p ()
  616. {
  617.   if (noninteractive)
  618.     return 1;
  619.  
  620.   return 0;            /* Not safe on Amiga !? */
  621. }
  622.  
  623. /* get_screen_size is in amiga_tty.c */
  624.  
  625. reset_sys_modes ()
  626. {
  627.   if (noninteractive)
  628.     {
  629.       fflush (stdout);
  630.       return;
  631.     }
  632.   move_cursor (screen_height - 1, 0);
  633.   clear_end_of_line (screen_width);
  634.   /* clear_end_of_line may move the cursor */
  635.   move_cursor (screen_height - 1, 0);
  636. }
  637.  
  638. char *
  639. get_system_name ()
  640. {
  641.   return("an_amiga");
  642. }
  643.  
  644. select_alarm ()
  645. {
  646.     /* Not going to deal with this mess... */
  647. }
  648.  
  649. /* Only rfds are checked and timeout must point somewhere */
  650. int
  651. select (nfds, rfds, wfds, efds, timeout)
  652.      int nfds;
  653.      int *rfds, *wfds, *efds, *timeout;
  654. {
  655.     /* Not going to deal with this ... kludge! */
  656. }
  657.  
  658. /*
  659.  *    This function will go away as soon as all the stubs fixed. (fnf)
  660.  */
  661.  
  662. croak (badfunc)
  663.      char *badfunc;
  664. {
  665.   printf ("%s not yet implemented\r\n", badfunc);
  666.   reset_sys_modes ();
  667.   exit (1);
  668. }
  669.  
  670. /* This getenv removes trailing newlines & multiple calls don't
  671.    destroy results */
  672. char *getenv (char *varname)
  673. {
  674.     char *return_string;
  675.     char buf[64];
  676.  
  677.     if (varname && varname[0])
  678.     {
  679.     int len, size;
  680.  
  681.     len = GetVar(varname, buf, 64, LV_VAR);
  682.     if (len >= 0)
  683.     {
  684.         size = IoErr();
  685.         return_string = emacs_malloc(size + 1);
  686.         if (size != len)
  687.         {
  688.         if (GetVar(varname, return_string, size + 1, LV_VAR) > 0)
  689.             return return_string;
  690.         }
  691.         else return strcpy(return_string, buf);
  692.     }
  693.     }
  694.     return 0;
  695. }
  696.  
  697. int fstat(int fd, struct stat *sbuf)
  698. {
  699.     char name[256];
  700.     struct UFB *ufb = chkufb(fd);
  701.  
  702.     if (!ufb) return -1;
  703.     if (!NameFromFH(ufb->ufbfh, name, 256)) return -1;
  704.     return stat(name, sbuf);
  705. }
  706.  
  707. struct IORequest *device_open(char *name, ULONG unit, ULONG flags,
  708.                   APTR data, ULONG data_len, int req_size)
  709. {
  710.     struct MsgPort *port;
  711.     struct IORequest *ioreq;
  712.  
  713.     if ((port = CreateMsgPort()) && (ioreq = CreateIORequest(port, req_size)))
  714.     {
  715.     if (data)
  716.     {
  717.         struct IOStdReq *io2 = (struct IOStdReq *)ioreq;
  718.         io2->io_Data = data;
  719.         io2->io_Length = data_len;
  720.     }
  721.     if (OpenDevice(name, unit, ioreq, flags) == 0) return ioreq;
  722.     }
  723.     if (ioreq) DeleteIORequest(ioreq);
  724.     if (port) DeletePort(port);
  725.     return 0;
  726. }
  727.  
  728. void device_close(struct IORequest *ioreq)
  729. {
  730.     if (ioreq)
  731.     {
  732.     CloseDevice(ioreq);
  733.     DeletePort(ioreq->io_Message.mn_ReplyPort);
  734.     DeleteIORequest(ioreq);
  735.     }
  736. }
  737.  
  738. syms_of_amiga ()
  739. {
  740.     DEFVAR_BOOL("amiga-initialized", &amiga_initialized, "");
  741.     DEFVAR_INT("amiga-malloc-bytes-used", &malloc_bytes_used,
  742.            "Number of malloc bytes used when emacs was dumped");
  743.     syms_of_amiga_tty();
  744.     syms_of_amiga_menu();
  745.     syms_of_amiga_clipboard();
  746. }
  747.  
  748. void cleanup_amiga(void)
  749. {
  750.     cleanup_amiga_processes();
  751.     cleanup_clipboard();
  752.     cleanup_amiga_tty();
  753.     free_sys_all();
  754. }
  755.  
  756. void init_amiga(void)
  757. {
  758.     make_environ();
  759.  
  760.     if (!(init_amiga_tty() && init_clipboard() && init_amiga_processes()))
  761.     exit(20);
  762. }
  763.