xref: /vim-8.2.3635/src/os_amiga.c (revision 2bf24176)
1 /* vi:set ts=8 sts=4 sw=4:
2  *
3  * VIM - Vi IMproved	by Bram Moolenaar
4  *
5  * Do ":help uganda"  in Vim to read copying and usage conditions.
6  * Do ":help credits" in Vim to see a list of people who contributed.
7  * See README.txt for an overview of the Vim source code.
8  */
9 
10 /*
11  * os_amiga.c
12  *
13  * Amiga system-dependent routines.
14  */
15 
16 #include "vim.h"
17 
18 #ifdef Window
19 # undef Window	/* Amiga has its own Window definition */
20 #endif
21 
22 #undef TRUE		/* will be redefined by exec/types.h */
23 #undef FALSE
24 
25 /* cproto fails on missing include files, skip them */
26 #ifndef PROTO
27 
28 #ifndef LATTICE
29 # include <exec/types.h>
30 # include <exec/exec.h>
31 # include <libraries/dos.h>
32 # include <intuition/intuition.h>
33 #endif
34 
35 /* XXX These are included from os_amiga.h
36 #include <proto/exec.h>
37 #include <proto/dos.h>
38 #include <proto/intuition.h>
39 */
40 
41 #include <exec/memory.h>
42 #include <libraries/dosextens.h>
43 
44 #include <dos/dostags.h>	    /* for 2.0 functions */
45 #include <dos/dosasl.h>
46 
47 /* From version 4 of AmigaOS, several system structures must be allocated
48  * and freed using system functions. "struct AnchorPath" is one.
49  */
50 #ifdef __amigaos4__
51 # include <dos/anchorpath.h>
52 # define	free_fib(x) FreeDosObject(DOS_FIB, x)
53 #else
54 # define	free_fib(x) vim_free(fib)
55 #endif
56 
57 #if defined(LATTICE) && !defined(SASC) && defined(FEAT_ARP)
58 # include <libraries/arp_pragmas.h>
59 #endif
60 
61 #endif /* PROTO */
62 
63 /*
64  * At this point TRUE and FALSE are defined as 1L and 0L, but we want 1 and 0.
65  */
66 #undef	TRUE
67 #define TRUE (1)
68 #undef	FALSE
69 #define FALSE (0)
70 
71 #ifdef __amigaos4__
72 # define	dos_packet(a, b, c)   DoPkt(a, b, c, 0, 0, 0, 0)
73 #elif !defined(AZTEC_C) && !defined(__AROS__)
74 static long dos_packet __ARGS((struct MsgPort *, long, long));
75 #endif
76 static int lock2name __ARGS((BPTR lock, char_u *buf, long   len));
77 static void out_num __ARGS((long n));
78 static struct FileInfoBlock *get_fib __ARGS((char_u *));
79 static int sortcmp __ARGS((const void *a, const void *b));
80 
81 static BPTR		raw_in = (BPTR)NULL;
82 static BPTR		raw_out = (BPTR)NULL;
83 static int		close_win = FALSE;  /* set if Vim opened the window */
84 
85 #ifndef __amigaos4__	/* Use autoopen for AmigaOS4 */
86 struct IntuitionBase	*IntuitionBase = NULL;
87 #endif
88 #ifdef FEAT_ARP
89 struct ArpBase		*ArpBase = NULL;
90 #endif
91 
92 static struct Window	*wb_window;
93 static char_u		*oldwindowtitle = NULL;
94 
95 #ifdef FEAT_ARP
96 int			dos2 = FALSE;	    /* Amiga DOS 2.0x or higher */
97 #endif
98 int			size_set = FALSE;   /* set to TRUE if window size was set */
99 
100     void
101 win_resize_on()
102 {
103     OUT_STR_NF("\033[12{");
104 }
105 
106     void
107 win_resize_off()
108 {
109     OUT_STR_NF("\033[12}");
110 }
111 
112     void
113 mch_write(p, len)
114     char_u	*p;
115     int		len;
116 {
117     Write(raw_out, (char *)p, (long)len);
118 }
119 
120 /*
121  * mch_inchar(): low level input function.
122  * Get a characters from the keyboard.
123  * If time == 0 do not wait for characters.
124  * If time == n wait a short time for characters.
125  * If time == -1 wait forever for characters.
126  *
127  * Return number of characters read.
128  */
129     int
130 mch_inchar(buf, maxlen, time, tb_change_cnt)
131     char_u  *buf;
132     int	    maxlen;
133     long    time;		/* milli seconds */
134     int	    tb_change_cnt;
135 {
136     int	    len;
137     long    utime;
138 
139     if (time >= 0)
140     {
141 	if (time == 0)
142 	    utime = 100L;	    /* time = 0 causes problems in DOS 1.2 */
143 	else
144 	    utime = time * 1000L;   /* convert from milli to micro secs */
145 	if (WaitForChar(raw_in, utime) == 0)	/* no character available */
146 	    return 0;
147     }
148     else    /* time == -1 */
149     {
150 	/*
151 	 * If there is no character available within 2 seconds (default)
152 	 * write the autoscript file to disk.  Or cause the CursorHold event
153 	 * to be triggered.
154 	 */
155 	if (WaitForChar(raw_in, p_ut * 1000L) == 0)
156 	{
157 #ifdef FEAT_AUTOCMD
158 	    if (trigger_cursorhold() && maxlen >= 3)
159 	    {
160 		buf[0] = K_SPECIAL;
161 		buf[1] = KS_EXTRA;
162 		buf[2] = (int)KE_CURSORHOLD;
163 		return 3;
164 	    }
165 #endif
166 	    before_blocking();
167 	}
168     }
169 
170     for (;;)	    /* repeat until we got a character */
171     {
172 #  ifdef FEAT_MBYTE
173 	len = Read(raw_in, (char *)buf, (long)maxlen / input_conv.vc_factor);
174 #  else
175 	len = Read(raw_in, (char *)buf, (long)maxlen);
176 #  endif
177 	if (len > 0)
178 	{
179 #ifdef FEAT_MBYTE
180 	    /* Convert from 'termencoding' to 'encoding'. */
181 	    if (input_conv.vc_type != CONV_NONE)
182 		len = convert_input(buf, len, maxlen);
183 #endif
184 	    return len;
185 	}
186     }
187 }
188 
189 /*
190  * return non-zero if a character is available
191  */
192     int
193 mch_char_avail()
194 {
195     return (WaitForChar(raw_in, 100L) != 0);
196 }
197 
198 /*
199  * Return amount of memory still available in Kbyte.
200  */
201     long_u
202 mch_avail_mem(special)
203     int	    special;
204 {
205 #ifdef __amigaos4__
206     return (long_u)AvailMem(MEMF_ANY) >> 10;
207 #else
208     return (long_u)(AvailMem(special ? (long)MEMF_CHIP : (long)MEMF_ANY)) >> 10;
209 #endif
210 }
211 
212 /*
213  * Waits a specified amount of time, or until input arrives if
214  * ignoreinput is FALSE.
215  */
216     void
217 mch_delay(msec, ignoreinput)
218     long    msec;
219     int	    ignoreinput;
220 {
221 #ifndef LATTICE		/* SAS declares void Delay(ULONG) */
222     void	    Delay __ARGS((long));
223 #endif
224 
225     if (msec > 0)
226     {
227 	if (ignoreinput)
228 	    Delay(msec / 20L);	    /* Delay works with 20 msec intervals */
229 	else
230 	    WaitForChar(raw_in, msec * 1000L);
231     }
232 }
233 
234 /*
235  * We have no job control, fake it by starting a new shell.
236  */
237     void
238 mch_suspend()
239 {
240     suspend_shell();
241 }
242 
243 #ifndef DOS_LIBRARY
244 # define DOS_LIBRARY	((UBYTE *)"dos.library")
245 #endif
246 
247     void
248 mch_init()
249 {
250     static char	    intlibname[] = "intuition.library";
251 
252 #ifdef AZTEC_C
253     Enable_Abort = 0;		/* disallow vim to be aborted */
254 #endif
255     Columns = 80;
256     Rows = 24;
257 
258     /*
259      * Set input and output channels, unless we have opened our own window
260      */
261     if (raw_in == (BPTR)NULL)
262     {
263 	raw_in = Input();
264 	raw_out = Output();
265 	/*
266 	 * If Input() is not interactive, then Output() will be (because of
267 	 * check in mch_check_win()).  Used for "Vim -".
268 	 * Also check the other way around, for "Vim -h | more".
269 	 */
270 	if (!IsInteractive(raw_in))
271 	    raw_in = raw_out;
272 	else if (!IsInteractive(raw_out))
273 	    raw_out = raw_in;
274     }
275 
276     out_flush();
277 
278     wb_window = NULL;
279 #ifndef __amigaos4__
280     if ((IntuitionBase = (struct IntuitionBase *)
281 				OpenLibrary((UBYTE *)intlibname, 0L)) == NULL)
282     {
283 	mch_errmsg(_("cannot open "));
284 	mch_errmsg(intlibname);
285 	mch_errmsg("!?\n");
286 	mch_exit(3);
287     }
288 #endif
289 }
290 
291 #ifndef PROTO
292 # include <workbench/startup.h>
293 #endif
294 
295 /*
296  * Check_win checks whether we have an interactive window.
297  * If not, a new window is opened with the newcli command.
298  * If we would open a window ourselves, the :sh and :! commands would not
299  * work properly (Why? probably because we are then running in a background
300  * CLI). This also is the best way to assure proper working in a next
301  * Workbench release.
302  *
303  * For the -f option (foreground mode) we open our own window and disable :sh.
304  * Otherwise the calling program would never know when editing is finished.
305  */
306 #define BUF2SIZE 320	    /* length of buffer for argument with complete path */
307 
308     int
309 mch_check_win(argc, argv)
310     int argc;
311     char **argv;
312 {
313     int		    i;
314     BPTR	    nilfh, fh;
315     char_u	    buf1[24];
316     char_u	    buf2[BUF2SIZE];
317     static char_u   *(constrings[3]) = {(char_u *)"con:0/0/662/210/",
318 					(char_u *)"con:0/0/640/200/",
319 					(char_u *)"con:0/0/320/200/"};
320     static char_u   *winerr = (char_u *)N_("VIM: Can't open window!\n");
321     struct WBArg    *argp;
322     int		    ac;
323     char	    *av;
324     char_u	    *device = NULL;
325     int		    exitval = 4;
326 #ifndef __amigaos4__
327     struct Library  *DosBase;
328 #endif
329     int		    usewin = FALSE;
330 
331 /*
332  * check if we are running under DOS 2.0x or higher
333  */
334 #ifndef __amigaos4__
335     DosBase = OpenLibrary(DOS_LIBRARY, 37L);
336     if (DosBase != NULL)
337     /* if (((struct Library *)DOSBase)->lib_Version >= 37) */
338     {
339 	CloseLibrary(DosBase);
340 # ifdef FEAT_ARP
341 	dos2 = TRUE;
342 # endif
343     }
344     else	    /* without arp functions we NEED 2.0 */
345     {
346 # ifndef FEAT_ARP
347 	mch_errmsg(_("Need Amigados version 2.04 or later\n"));
348 	exit(3);
349 # else
350 		    /* need arp functions for dos 1.x */
351 	if (!(ArpBase = (struct ArpBase *) OpenLibrary((UBYTE *)ArpName, ArpVersion)))
352 	{
353 	    fprintf(stderr, _("Need %s version %ld\n"), ArpName, ArpVersion);
354 	    exit(3);
355 	}
356 # endif
357     }
358 #endif	/* __amigaos4__ */
359 
360     /*
361      * scan argv[] for the "-f" and "-d" arguments
362      */
363     for (i = 1; i < argc; ++i)
364 	if (argv[i][0] == '-')
365 	{
366 	    switch (argv[i][1])
367 	    {
368 	    case 'f':
369 		usewin = TRUE;
370 		break;
371 
372 	    case 'd':
373 		if (i < argc - 1
374 #ifdef FEAT_DIFF
375 			/* require using "-dev", "-d" means diff mode */
376 			&& argv[i][2] == 'e' && argv[i][3] == 'v'
377 #endif
378 		   )
379 		    device = (char_u *)argv[i + 1];
380 		break;
381 	    }
382 	}
383 
384 /*
385  * If we were not started from workbench, do not have a "-d" or "-dev"
386  * argument and we have been started with an interactive window, use that
387  * window.
388  */
389     if (argc != 0
390 	    && device == NULL
391 	    && (IsInteractive(Input()) || IsInteractive(Output())))
392 	return OK;
393 
394 /*
395  * When given the "-f" argument, we open our own window. We can't use the
396  * newcli trick below, because the calling program (mail, rn, etc.) would not
397  * know when we are finished.
398  */
399     if (usewin)
400     {
401 	/*
402 	 * Try to open a window. First try the specified device.
403 	 * Then try a 24 line 80 column window.
404 	 * If that fails, try two smaller ones.
405 	 */
406 	for (i = -1; i < 3; ++i)
407 	{
408 	    if (i >= 0)
409 		device = constrings[i];
410 	    if (device != NULL && (raw_in = Open((UBYTE *)device,
411 					   (long)MODE_NEWFILE)) != (BPTR)NULL)
412 		break;
413 	}
414 	if (raw_in == (BPTR)NULL)	/* all three failed */
415 	{
416 	    mch_errmsg(_(winerr));
417 	    goto exit;
418 	}
419 	raw_out = raw_in;
420 	close_win = TRUE;
421 	return OK;
422     }
423 
424     if ((nilfh = Open((UBYTE *)"NIL:", (long)MODE_NEWFILE)) == (BPTR)NULL)
425     {
426 	mch_errmsg(_("Cannot open NIL:\n"));
427 	goto exit;
428     }
429 
430     /*
431      * Make a unique name for the temp file (which we will not delete!).
432      * Use a pointer on the stack (nobody else will be using it).
433      * Under AmigaOS4, this assumption might change in the future, so
434      * we use a pointer to the current task instead. This should be a
435      * shared structure and thus globally unique.
436      */
437 #ifdef __amigaos4__
438     sprintf((char *)buf1, "t:nc%p", FindTask(0));
439 #else
440     sprintf((char *)buf1, "t:nc%ld", (long)buf1);
441 #endif
442     if ((fh = Open((UBYTE *)buf1, (long)MODE_NEWFILE)) == (BPTR)NULL)
443     {
444 	mch_errmsg(_("Cannot create "));
445 	mch_errmsg((char *)buf1);
446 	mch_errmsg("\n");
447 	goto exit;
448     }
449     /*
450      * Write the command into the file, put quotes around the arguments that
451      * have a space in them.
452      */
453     if (argc == 0)	/* run from workbench */
454 	ac = ((struct WBStartup *)argv)->sm_NumArgs;
455     else
456 	ac = argc;
457     for (i = 0; i < ac; ++i)
458     {
459 	if (argc == 0)
460 	{
461 	    *buf2 = NUL;
462 	    argp = &(((struct WBStartup *)argv)->sm_ArgList[i]);
463 	    if (argp->wa_Lock)
464 		(void)lock2name(argp->wa_Lock, buf2, (long)(BUF2SIZE - 1));
465 #ifdef FEAT_ARP
466 	    if (dos2)	    /* use 2.0 function */
467 #endif
468 		AddPart((UBYTE *)buf2, (UBYTE *)argp->wa_Name, (long)(BUF2SIZE - 1));
469 #ifdef FEAT_ARP
470 	    else	    /* use arp function */
471 		TackOn((char *)buf2, argp->wa_Name);
472 #endif
473 	    av = (char *)buf2;
474 	}
475 	else
476 	    av = argv[i];
477 
478 	/* skip '-d' or "-dev" option */
479 	if (av[0] == '-' && av[1] == 'd'
480 #ifdef FEAT_DIFF
481 		&& av[2] == 'e' && av[3] == 'v'
482 #endif
483 		)
484 	{
485 	    ++i;
486 	    continue;
487 	}
488 	if (vim_strchr((char_u *)av, ' '))
489 	    Write(fh, "\"", 1L);
490 	Write(fh, av, (long)strlen(av));
491 	if (vim_strchr((char_u *)av, ' '))
492 	    Write(fh, "\"", 1L);
493 	Write(fh, " ", 1L);
494     }
495     Write(fh, "\nendcli\n", 8L);
496     Close(fh);
497 
498 /*
499  * Try to open a new cli in a window. If "-d" or "-dev" argument was given try
500  * to open the specified device. Then try a 24 line 80 column window.  If that
501  * fails, try two smaller ones.
502  */
503     for (i = -1; i < 3; ++i)
504     {
505 	if (i >= 0)
506 	    device = constrings[i];
507 	else if (device == NULL)
508 	    continue;
509 	sprintf((char *)buf2, "newcli <nil: >nil: %s from %s", (char *)device, (char *)buf1);
510 #ifdef FEAT_ARP
511 	if (dos2)
512 	{
513 #endif
514 	    if (!SystemTags((UBYTE *)buf2, SYS_UserShell, TRUE, TAG_DONE))
515 		break;
516 #ifdef FEAT_ARP
517 	}
518 	else
519 	{
520 	    if (Execute((UBYTE *)buf2, nilfh, nilfh))
521 		break;
522 	}
523 #endif
524     }
525     if (i == 3)	    /* all three failed */
526     {
527 	DeleteFile((UBYTE *)buf1);
528 	mch_errmsg(_(winerr));
529 	goto exit;
530     }
531     exitval = 0;    /* The Execute succeeded: exit this program */
532 
533 exit:
534 #ifdef FEAT_ARP
535     if (ArpBase)
536 	CloseLibrary((struct Library *) ArpBase);
537 #endif
538     exit(exitval);
539     /* NOTREACHED */
540     return FAIL;
541 }
542 
543 /*
544  * Return TRUE if the input comes from a terminal, FALSE otherwise.
545  * We fake there is a window, because we can always open one!
546  */
547     int
548 mch_input_isatty()
549 {
550     return TRUE;
551 }
552 
553 /*
554  * fname_case(): Set the case of the file name, if it already exists.
555  *		 This will cause the file name to remain exactly the same
556  *		 if the file system ignores, but preserves case.
557  */
558 /*ARGSUSED*/
559     void
560 fname_case(name, len)
561     char_u	*name;
562     int		len;		/* buffer size, ignored here */
563 {
564     struct FileInfoBlock    *fib;
565     size_t		    flen;
566 
567     fib = get_fib(name);
568     if (fib != NULL)
569     {
570 	flen = STRLEN(name);
571 	/* TODO: Check if this fix applies to AmigaOS < 4 too.*/
572 #ifdef __amigaos4__
573 	if (fib->fib_DirEntryType == ST_ROOT)
574 	    strcat(fib->fib_FileName, ":");
575 #endif
576 	if (flen == strlen(fib->fib_FileName))	/* safety check */
577 	    mch_memmove(name, fib->fib_FileName, flen);
578 	free_fib(fib);
579     }
580 }
581 
582 /*
583  * Get the FileInfoBlock for file "fname"
584  * The returned structure has to be free()d.
585  * Returns NULL on error.
586  */
587     static struct FileInfoBlock *
588 get_fib(fname)
589     char_u *fname;
590 {
591     BPTR		    flock;
592     struct FileInfoBlock    *fib;
593 
594     if (fname == NULL)	    /* safety check */
595 	return NULL;
596 #ifdef __amigaos4__
597     fib = AllocDosObject(DOS_FIB,0);
598 #else
599     fib = (struct FileInfoBlock *)alloc(sizeof(struct FileInfoBlock));
600 #endif
601     if (fib != NULL)
602     {
603 	flock = Lock((UBYTE *)fname, (long)ACCESS_READ);
604 	if (flock == (BPTR)NULL || !Examine(flock, fib))
605 	{
606 	    free_fib(fib);  /* in case of an error the memory is freed here */
607 	    fib = NULL;
608 	}
609 	if (flock)
610 	    UnLock(flock);
611     }
612     return fib;
613 }
614 
615 #ifdef FEAT_TITLE
616 /*
617  * set the title of our window
618  * icon name is not set
619  */
620     void
621 mch_settitle(title, icon)
622     char_u  *title;
623     char_u  *icon;
624 {
625     if (wb_window != NULL && title != NULL)
626 	SetWindowTitles(wb_window, (UBYTE *)title, (UBYTE *)-1L);
627 }
628 
629 /*
630  * Restore the window/icon title.
631  * which is one of:
632  *  1  Just restore title
633  *  2  Just restore icon (which we don't have)
634  *  3  Restore title and icon (which we don't have)
635  */
636     void
637 mch_restore_title(which)
638     int which;
639 {
640     if (which & 1)
641 	mch_settitle(oldwindowtitle, NULL);
642 }
643 
644     int
645 mch_can_restore_title()
646 {
647     return (wb_window != NULL);
648 }
649 
650     int
651 mch_can_restore_icon()
652 {
653     return FALSE;
654 }
655 #endif
656 
657 /*
658  * Insert user name in s[len].
659  */
660     int
661 mch_get_user_name(s, len)
662     char_u  *s;
663     int	    len;
664 {
665     /* TODO: Implement this. */
666     *s = NUL;
667     return FAIL;
668 }
669 
670 /*
671  * Insert host name is s[len].
672  */
673     void
674 mch_get_host_name(s, len)
675     char_u  *s;
676     int	    len;
677 {
678 #if defined(__amigaos4__) && defined(__CLIB2__)
679     gethostname(s, len);
680 #else
681     vim_strncpy(s, "Amiga", len - 1);
682 #endif
683 }
684 
685 /*
686  * return process ID
687  */
688     long
689 mch_get_pid()
690 {
691 #ifdef __amigaos4__
692     /* This is as close to a pid as we can come. We could use CLI numbers also,
693      * but then we would have two different types of process identifiers.
694      */
695     return((long)FindTask(0));
696 #else
697     return (long)0;
698 #endif
699 }
700 
701 /*
702  * Get name of current directory into buffer 'buf' of length 'len' bytes.
703  * Return OK for success, FAIL for failure.
704  */
705     int
706 mch_dirname(buf, len)
707     char_u	*buf;
708     int		len;
709 {
710     return mch_FullName((char_u *)"", buf, len, FALSE);
711 }
712 
713 /*
714  * get absolute file name into buffer 'buf' of length 'len' bytes
715  *
716  * return FAIL for failure, OK otherwise
717  */
718     int
719 mch_FullName(fname, buf, len, force)
720     char_u	*fname, *buf;
721     int		len;
722     int		force;
723 {
724     BPTR	l;
725     int		retval = FAIL;
726     int		i;
727 
728     /* Lock the file.  If it exists, we can get the exact name. */
729     if ((l = Lock((UBYTE *)fname, (long)ACCESS_READ)) != (BPTR)0)
730     {
731 	retval = lock2name(l, buf, (long)len - 1);
732 	UnLock(l);
733     }
734     else if (force || !mch_isFullName(fname))	    /* not a full path yet */
735     {
736 	/*
737 	 * If the file cannot be locked (doesn't exist), try to lock the
738 	 * current directory and concatenate the file name.
739 	 */
740 	if ((l = Lock((UBYTE *)"", (long)ACCESS_READ)) != (BPTR)NULL)
741 	{
742 	    retval = lock2name(l, buf, (long)len);
743 	    UnLock(l);
744 	    if (retval == OK)
745 	    {
746 		i = STRLEN(buf);
747 		/* Concatenate the fname to the directory.  Don't add a slash
748 		 * if fname is empty, but do change "" to "/". */
749 		if (i == 0 || *fname != NUL)
750 		{
751 		    if (i < len - 1 && (i == 0 || buf[i - 1] != ':'))
752 			buf[i++] = '/';
753 		    vim_strncpy(buf + i, fname, len - i - 1);
754 		}
755 	    }
756 	}
757     }
758     if (*buf == 0 || *buf == ':')
759 	retval = FAIL;	/* something failed; use the file name */
760     return retval;
761 }
762 
763 /*
764  * Return TRUE if "fname" does not depend on the current directory.
765  */
766     int
767 mch_isFullName(fname)
768     char_u	*fname;
769 {
770     return (vim_strchr(fname, ':') != NULL && *fname != ':');
771 }
772 
773 /*
774  * Get the full file name from a lock. Use 2.0 function if possible, because
775  * the arp function has more restrictions on the path length.
776  *
777  * return FAIL for failure, OK otherwise
778  */
779     static int
780 lock2name(lock, buf, len)
781     BPTR    lock;
782     char_u  *buf;
783     long    len;
784 {
785 #ifdef FEAT_ARP
786     if (dos2)		    /* use 2.0 function */
787 #endif
788 	return ((int)NameFromLock(lock, (UBYTE *)buf, len) ? OK : FAIL);
789 #ifdef FEAT_ARP
790     else		/* use arp function */
791 	return ((int)PathName(lock, (char *)buf, (long)(len/32)) ? OK : FAIL);
792 #endif
793 }
794 
795 /*
796  * get file permissions for 'name'
797  * Returns -1 when it doesn't exist.
798  */
799     long
800 mch_getperm(name)
801     char_u	*name;
802 {
803     struct FileInfoBlock    *fib;
804     long		    retval = -1;
805 
806     fib = get_fib(name);
807     if (fib != NULL)
808     {
809 	retval = fib->fib_Protection;
810 	free_fib(fib);
811     }
812     return retval;
813 }
814 
815 /*
816  * set file permission for 'name' to 'perm'
817  *
818  * return FAIL for failure, OK otherwise
819  */
820     int
821 mch_setperm(name, perm)
822     char_u	*name;
823     long	perm;
824 {
825     perm &= ~FIBF_ARCHIVE;		/* reset archived bit */
826     return (SetProtection((UBYTE *)name, (long)perm) ? OK : FAIL);
827 }
828 
829 /*
830  * Set hidden flag for "name".
831  */
832     void
833 mch_hide(name)
834     char_u	*name;
835 {
836     /* can't hide a file */
837 }
838 
839 /*
840  * return FALSE if "name" is not a directory
841  * return TRUE if "name" is a directory.
842  * return FALSE for error.
843  */
844     int
845 mch_isdir(name)
846     char_u	*name;
847 {
848     struct FileInfoBlock    *fib;
849     int			    retval = FALSE;
850 
851     fib = get_fib(name);
852     if (fib != NULL)
853     {
854 #ifdef __amigaos4__
855 	retval = (FIB_IS_DRAWER(fib)) ? TRUE : FALSE;
856 #else
857 	retval = ((fib->fib_DirEntryType >= 0) ? TRUE : FALSE);
858 #endif
859 	free_fib(fib);
860     }
861     return retval;
862 }
863 
864 /*
865  * Create directory "name".
866  */
867     int
868 mch_mkdir(name)
869     char_u	*name;
870 {
871     BPTR	lock;
872 
873     lock = CreateDir(name);
874     if (lock != NULL)
875     {
876 	UnLock(lock);
877 	return 0;
878     }
879     return -1;
880 }
881 
882 /*
883  * Return 1 if "name" can be executed, 0 if not.
884  * If "use_path" is FALSE only check if "name" is executable.
885  * Return -1 if unknown.
886  */
887     int
888 mch_can_exe(name, path, use_path)
889     char_u	*name;
890     char_u	**path;
891     int		use_path;
892 {
893     /* TODO */
894     return -1;
895 }
896 
897 /*
898  * Check what "name" is:
899  * NODE_NORMAL: file or directory (or doesn't exist)
900  * NODE_WRITABLE: writable device, socket, fifo, etc.
901  * NODE_OTHER: non-writable things
902  */
903     int
904 mch_nodetype(name)
905     char_u	*name;
906 {
907     /* TODO */
908     return NODE_NORMAL;
909 }
910 
911     void
912 mch_early_init()
913 {
914 }
915 
916 /*
917  * Careful: mch_exit() may be called before mch_init()!
918  */
919     void
920 mch_exit(r)
921     int		    r;
922 {
923     if (raw_in)			    /* put terminal in 'normal' mode */
924     {
925 	settmode(TMODE_COOK);
926 	stoptermcap();
927     }
928     out_char('\n');
929     if (raw_out)
930     {
931 	if (term_console)
932 	{
933 	    win_resize_off();	    /* window resize events de-activated */
934 	    if (size_set)
935 		OUT_STR("\233t\233u");	/* reset window size (CSI t CSI u) */
936 	}
937 	out_flush();
938     }
939 
940 #ifdef FEAT_TITLE
941     mch_restore_title(3);	    /* restore window title */
942 #endif
943 
944     ml_close_all(TRUE);		    /* remove all memfiles */
945 
946 #ifdef FEAT_ARP
947     if (ArpBase)
948 	CloseLibrary((struct Library *) ArpBase);
949 #endif
950     if (close_win)
951 	Close(raw_in);
952     if (r)
953 	printf(_("Vim exiting with %d\n"), r); /* somehow this makes :cq work!? */
954     exit(r);
955 }
956 
957 /*
958  * This is a routine for setting a given stream to raw or cooked mode on the
959  * Amiga . This is useful when you are using Lattice C to produce programs
960  * that want to read single characters with the "getch()" or "fgetc" call.
961  *
962  * Written : 18-Jun-87 By Chuck McManis.
963  */
964 
965 #define MP(xx)	((struct MsgPort *)((struct FileHandle *) (BADDR(xx)))->fh_Type)
966 
967 /*
968  * Function mch_settmode() - Convert the specified file pointer to 'raw' or
969  * 'cooked' mode. This only works on TTY's.
970  *
971  * Raw: keeps DOS from translating keys for you, also (BIG WIN) it means
972  *	getch() will return immediately rather than wait for a return. You
973  *	lose editing features though.
974  *
975  * Cooked: This function returns the designate file pointer to it's normal,
976  *	wait for a <CR> mode. This is exactly like raw() except that
977  *	it sends a 0 to the console to make it back into a CON: from a RAW:
978  */
979     void
980 mch_settmode(tmode)
981     int		tmode;
982 {
983 #if defined(__AROS__) || defined(__amigaos4__)
984     if (!SetMode(raw_in, tmode == TMODE_RAW ? 1 : 0))
985 #else
986     if (dos_packet(MP(raw_in), (long)ACTION_SCREEN_MODE,
987 					  tmode == TMODE_RAW ? -1L : 0L) == 0)
988 #endif
989 	mch_errmsg(_("cannot change console mode ?!\n"));
990 }
991 
992 /*
993  * set screen mode, always fails.
994  */
995     int
996 mch_screenmode(arg)
997     char_u	*arg;
998 {
999     EMSG(_(e_screenmode));
1000     return FAIL;
1001 }
1002 
1003 /*
1004  * Code for this routine came from the following :
1005  *
1006  * ConPackets.c -  C. Scheppner, A. Finkel, P. Lindsay	CBM
1007  *   DOS packet example
1008  *   Requires 1.2
1009  *
1010  * Found on Fish Disk 56.
1011  *
1012  * Heavely modified by mool.
1013  */
1014 
1015 #ifndef PROTO
1016 # include <devices/conunit.h>
1017 #endif
1018 
1019 /*
1020  * try to get the real window size
1021  * return FAIL for failure, OK otherwise
1022  */
1023     int
1024 mch_get_shellsize()
1025 {
1026     struct ConUnit  *conUnit;
1027 #ifndef __amigaos4__
1028     char	    id_a[sizeof(struct InfoData) + 3];
1029 #endif
1030     struct InfoData *id=0;
1031 
1032     if (!term_console)	/* not an amiga window */
1033 	goto out;
1034 
1035     /* insure longword alignment */
1036 #ifdef __amigaos4__
1037     if (!(id = AllocDosObject(DOS_INFODATA, 0)))
1038 	goto out;
1039 #else
1040     id = (struct InfoData *)(((long)id_a + 3L) & ~3L);
1041 #endif
1042 
1043     /*
1044      * Should make console aware of real window size, not the one we set.
1045      * Unfortunately, under DOS 2.0x this redraws the window and it
1046      * is rarely needed, so we skip it now, unless we changed the size.
1047      */
1048     if (size_set)
1049 	OUT_STR("\233t\233u");	/* CSI t CSI u */
1050     out_flush();
1051 
1052 #ifdef __AROS__
1053     if (!Info(raw_out, id)
1054 		 || (wb_window = (struct Window *) id->id_VolumeNode) == NULL)
1055 #else
1056     if (dos_packet(MP(raw_out), (long)ACTION_DISK_INFO, ((ULONG) id) >> 2) == 0
1057 	    || (wb_window = (struct Window *)id->id_VolumeNode) == NULL)
1058 #endif
1059     {
1060 	/* it's not an amiga window, maybe aux device */
1061 	/* terminal type should be set */
1062 	term_console = FALSE;
1063 	goto out;
1064     }
1065     if (oldwindowtitle == NULL)
1066 	oldwindowtitle = (char_u *)wb_window->Title;
1067     if (id->id_InUse == (BPTR)NULL)
1068     {
1069 	mch_errmsg(_("mch_get_shellsize: not a console??\n"));
1070 	return FAIL;
1071     }
1072     conUnit = (struct ConUnit *) ((struct IOStdReq *) id->id_InUse)->io_Unit;
1073 
1074     /* get window size */
1075     Rows = conUnit->cu_YMax + 1;
1076     Columns = conUnit->cu_XMax + 1;
1077     if (Rows < 0 || Rows > 200)	    /* cannot be an amiga window */
1078     {
1079 	Columns = 80;
1080 	Rows = 24;
1081 	term_console = FALSE;
1082 	return FAIL;
1083     }
1084 
1085     return OK;
1086 out:
1087 #ifdef __amigaos4__
1088     FreeDosObject(DOS_INFODATA, id); /* Safe to pass NULL */
1089 #endif
1090 
1091     return FAIL;
1092 }
1093 
1094 /*
1095  * Try to set the real window size to Rows and Columns.
1096  */
1097     void
1098 mch_set_shellsize()
1099 {
1100     if (term_console)
1101     {
1102 	size_set = TRUE;
1103 	out_char(CSI);
1104 	out_num((long)Rows);
1105 	out_char('t');
1106 	out_char(CSI);
1107 	out_num((long)Columns);
1108 	out_char('u');
1109 	out_flush();
1110     }
1111 }
1112 
1113 /*
1114  * Rows and/or Columns has changed.
1115  */
1116     void
1117 mch_new_shellsize()
1118 {
1119     /* Nothing to do. */
1120 }
1121 
1122 /*
1123  * out_num - output a (big) number fast
1124  */
1125     static void
1126 out_num(n)
1127     long	n;
1128 {
1129     OUT_STR_NF(tltoa((unsigned long)n));
1130 }
1131 
1132 #if !defined(AZTEC_C) && !defined(__AROS__) && !defined(__amigaos4__)
1133 /*
1134  * Sendpacket.c
1135  *
1136  * An invaluable addition to your Amiga.lib file. This code sends a packet to
1137  * the given message port. This makes working around DOS lots easier.
1138  *
1139  * Note, I didn't write this, those wonderful folks at CBM did. I do suggest
1140  * however that you may wish to add it to Amiga.Lib, to do so, compile it and
1141  * say 'oml lib:amiga.lib -r sendpacket.o'
1142  */
1143 
1144 #ifndef PROTO
1145 /* #include <proto/exec.h> */
1146 /* #include <proto/dos.h> */
1147 # include <exec/memory.h>
1148 #endif
1149 
1150 /*
1151  * Function - dos_packet written by Phil Lindsay, Carolyn Scheppner, and Andy
1152  * Finkel. This function will send a packet of the given type to the Message
1153  * Port supplied.
1154  */
1155 
1156     static long
1157 dos_packet(pid, action, arg)
1158     struct MsgPort *pid;    /* process identifier ... (handlers message port) */
1159     long	    action, /* packet type ... (what you want handler to do)   */
1160 		    arg;    /* single argument */
1161 {
1162 # ifdef FEAT_ARP
1163     struct MsgPort	    *replyport;
1164     struct StandardPacket   *packet;
1165     long		    res1;
1166 
1167     if (dos2)
1168 # endif
1169 	return DoPkt(pid, action, arg, 0L, 0L, 0L, 0L);	/* use 2.0 function */
1170 # ifdef FEAT_ARP
1171 
1172     replyport = (struct MsgPort *) CreatePort(NULL, 0);	/* use arp function */
1173     if (!replyport)
1174 	return (0);
1175 
1176     /* Allocate space for a packet, make it public and clear it */
1177     packet = (struct StandardPacket *)
1178 	AllocMem((long) sizeof(struct StandardPacket), MEMF_PUBLIC | MEMF_CLEAR);
1179     if (!packet) {
1180 	DeletePort(replyport);
1181 	return (0);
1182     }
1183     packet->sp_Msg.mn_Node.ln_Name = (char *) &(packet->sp_Pkt);
1184     packet->sp_Pkt.dp_Link = &(packet->sp_Msg);
1185     packet->sp_Pkt.dp_Port = replyport;
1186     packet->sp_Pkt.dp_Type = action;
1187     packet->sp_Pkt.dp_Arg1 = arg;
1188 
1189     PutMsg(pid, (struct Message *)packet);	/* send packet */
1190 
1191     WaitPort(replyport);
1192     GetMsg(replyport);
1193 
1194     res1 = packet->sp_Pkt.dp_Res1;
1195 
1196     FreeMem(packet, (long) sizeof(struct StandardPacket));
1197     DeletePort(replyport);
1198 
1199     return (res1);
1200 # endif
1201 }
1202 #endif /* !defined(AZTEC_C) && !defined(__AROS__) */
1203 
1204 /*
1205  * Call shell.
1206  * Return error number for failure, 0 otherwise
1207  */
1208     int
1209 mch_call_shell(cmd, options)
1210     char_u	*cmd;
1211     int		options;	/* SHELL_*, see vim.h */
1212 {
1213     BPTR	mydir;
1214     int		x;
1215     int		tmode = cur_tmode;
1216 #ifdef AZTEC_C
1217     int		use_execute;
1218     char_u	*shellcmd = NULL;
1219     char_u	*shellarg;
1220 #endif
1221     int		retval = 0;
1222 
1223     if (close_win)
1224     {
1225 	/* if Vim opened a window: Executing a shell may cause crashes */
1226 	EMSG(_("E360: Cannot execute shell with -f option"));
1227 	return -1;
1228     }
1229 
1230     if (term_console)
1231 	win_resize_off();	    /* window resize events de-activated */
1232     out_flush();
1233 
1234     if (options & SHELL_COOKED)
1235 	settmode(TMODE_COOK);	    /* set to normal mode */
1236     mydir = Lock((UBYTE *)"", (long)ACCESS_READ);   /* remember current dir */
1237 
1238 #if !defined(AZTEC_C)		    /* not tested very much */
1239     if (cmd == NULL)
1240     {
1241 # ifdef FEAT_ARP
1242 	if (dos2)
1243 # endif
1244 	    x = SystemTags(p_sh, SYS_UserShell, TRUE, TAG_DONE);
1245 # ifdef FEAT_ARP
1246 	else
1247 	    x = Execute(p_sh, raw_in, raw_out);
1248 # endif
1249     }
1250     else
1251     {
1252 # ifdef FEAT_ARP
1253 	if (dos2)
1254 # endif
1255 	    x = SystemTags((char *)cmd, SYS_UserShell, TRUE, TAG_DONE);
1256 # ifdef FEAT_ARP
1257 	else
1258 	    x = Execute((char *)cmd, 0L, raw_out);
1259 # endif
1260     }
1261 # ifdef FEAT_ARP
1262     if ((dos2 && x < 0) || (!dos2 && !x))
1263 # else
1264     if (x < 0)
1265 # endif
1266     {
1267 	MSG_PUTS(_("Cannot execute "));
1268 	if (cmd == NULL)
1269 	{
1270 	    MSG_PUTS(_("shell "));
1271 	    msg_outtrans(p_sh);
1272 	}
1273 	else
1274 	    msg_outtrans(cmd);
1275 	msg_putchar('\n');
1276 	retval = -1;
1277     }
1278 # ifdef FEAT_ARP
1279     else if (!dos2 || x)
1280 # else
1281     else if (x)
1282 # endif
1283     {
1284 	if ((x = IoErr()) != 0)
1285 	{
1286 	    if (!(options & SHELL_SILENT))
1287 	    {
1288 		msg_putchar('\n');
1289 		msg_outnum((long)x);
1290 		MSG_PUTS(_(" returned\n"));
1291 	    }
1292 	    retval = x;
1293 	}
1294     }
1295 #else	/* else part is for AZTEC_C */
1296     if (p_st >= 4 || (p_st >= 2 && !(options & SHELL_FILTER)))
1297 	use_execute = 1;
1298     else
1299 	use_execute = 0;
1300     if (!use_execute)
1301     {
1302 	/*
1303 	 * separate shell name from argument
1304 	 */
1305 	shellcmd = vim_strsave(p_sh);
1306 	if (shellcmd == NULL)	    /* out of memory, use Execute */
1307 	    use_execute = 1;
1308 	else
1309 	{
1310 	    shellarg = skiptowhite(shellcmd);	/* find start of arguments */
1311 	    if (*shellarg != NUL)
1312 	    {
1313 		*shellarg++ = NUL;
1314 		shellarg = skipwhite(shellarg);
1315 	    }
1316 	}
1317     }
1318     if (cmd == NULL)
1319     {
1320 	if (use_execute)
1321 	{
1322 # ifdef FEAT_ARP
1323 	    if (dos2)
1324 # endif
1325 		x = SystemTags((UBYTE *)p_sh, SYS_UserShell, TRUE, TAG_DONE);
1326 # ifdef FEAT_ARP
1327 	    else
1328 		x = !Execute((UBYTE *)p_sh, raw_in, raw_out);
1329 # endif
1330 	}
1331 	else
1332 	    x = fexecl((char *)shellcmd, (char *)shellcmd, (char *)shellarg, NULL);
1333     }
1334     else if (use_execute)
1335     {
1336 # ifdef FEAT_ARP
1337 	if (dos2)
1338 # endif
1339 	    x = SystemTags((UBYTE *)cmd, SYS_UserShell, TRUE, TAG_DONE);
1340 # ifdef FEAT_ARP
1341 	else
1342 	    x = !Execute((UBYTE *)cmd, 0L, raw_out);
1343 # endif
1344     }
1345     else if (p_st & 1)
1346 	x = fexecl((char *)shellcmd, (char *)shellcmd, (char *)shellarg,
1347 							   (char *)cmd, NULL);
1348     else
1349 	x = fexecl((char *)shellcmd, (char *)shellcmd, (char *)shellarg,
1350 					   (char *)p_shcf, (char *)cmd, NULL);
1351 # ifdef FEAT_ARP
1352     if ((dos2 && x < 0) || (!dos2 && x))
1353 # else
1354     if (x < 0)
1355 # endif
1356     {
1357 	MSG_PUTS(_("Cannot execute "));
1358 	if (use_execute)
1359 	{
1360 	    if (cmd == NULL)
1361 		msg_outtrans(p_sh);
1362 	    else
1363 		msg_outtrans(cmd);
1364 	}
1365 	else
1366 	{
1367 	    MSG_PUTS(_("shell "));
1368 	    msg_outtrans(shellcmd);
1369 	}
1370 	msg_putchar('\n');
1371 	retval = -1;
1372     }
1373     else
1374     {
1375 	if (use_execute)
1376 	{
1377 # ifdef FEAT_ARP
1378 	    if (!dos2 || x)
1379 # else
1380 	    if (x)
1381 # endif
1382 		x = IoErr();
1383 	}
1384 	else
1385 	    x = wait();
1386 	if (x)
1387 	{
1388 	    if (!(options & SHELL_SILENT) && !emsg_silent)
1389 	    {
1390 		msg_putchar('\n');
1391 		msg_outnum((long)x);
1392 		MSG_PUTS(_(" returned\n"));
1393 	    }
1394 	    retval = x;
1395 	}
1396     }
1397     vim_free(shellcmd);
1398 #endif	/* AZTEC_C */
1399 
1400     if ((mydir = CurrentDir(mydir)) != 0) /* make sure we stay in the same directory */
1401 	UnLock(mydir);
1402     if (tmode == TMODE_RAW)
1403 	settmode(TMODE_RAW);		/* set to raw mode */
1404 #ifdef FEAT_TITLE
1405     resettitle();
1406 #endif
1407     if (term_console)
1408 	win_resize_on();		/* window resize events activated */
1409     return retval;
1410 }
1411 
1412 /*
1413  * check for an "interrupt signal"
1414  * We only react to a CTRL-C, but also clear the other break signals to avoid
1415  * trouble with lattice-c programs.
1416  */
1417     void
1418 mch_breakcheck()
1419 {
1420    if (SetSignal(0L, (long)(SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D|SIGBREAKF_CTRL_E|SIGBREAKF_CTRL_F)) & SIGBREAKF_CTRL_C)
1421 	got_int = TRUE;
1422 }
1423 
1424 /* this routine causes manx to use this Chk_Abort() rather than it's own */
1425 /* otherwise it resets our ^C when doing any I/O (even when Enable_Abort */
1426 /* is zero).  Since we want to check for our own ^C's			 */
1427 
1428 #ifdef _DCC
1429 #define Chk_Abort chkabort
1430 #endif
1431 
1432 #ifdef LATTICE
1433 void __regargs __chkabort(void);
1434 
1435 void __regargs __chkabort(void)
1436 {}
1437 
1438 #else
1439     long
1440 Chk_Abort(void)
1441 {
1442     return(0L);
1443 }
1444 #endif
1445 
1446 /*
1447  * mch_expandpath() - this code does wild-card pattern matching using the arp
1448  *		      routines.
1449  *
1450  * "pat" has backslashes before chars that are not to be expanded.
1451  * Returns the number of matches found.
1452  *
1453  * This is based on WildDemo2.c (found in arp1.1 distribution).
1454  * That code's copyright follows:
1455  *	Copyright (c) 1987, Scott Ballantyne
1456  *	Use and abuse as you please.
1457  */
1458 
1459 #ifdef __amigaos4__
1460 # define	ANCHOR_BUF_SIZE	1024
1461 #else
1462 # define ANCHOR_BUF_SIZE (512)
1463 # define ANCHOR_SIZE (sizeof(struct AnchorPath) + ANCHOR_BUF_SIZE)
1464 #endif
1465 
1466     int
1467 mch_expandpath(gap, pat, flags)
1468     garray_T	*gap;
1469     char_u	*pat;
1470     int		flags;		/* EW_* flags */
1471 {
1472     struct AnchorPath	*Anchor;
1473     LONG		Result;
1474     char_u		*starbuf, *sp, *dp;
1475     int			start_len;
1476     int			matches;
1477 #ifdef __amigaos4__
1478     struct TagItem	AnchorTags[] = {
1479 	{ADO_Strlen, ANCHOR_BUF_SIZE},
1480 	{ADO_Flags, APF_DODOT|APF_DOWILD|APF_MultiAssigns},
1481 	{TAG_DONE, 0L}
1482     };
1483 #endif
1484 
1485     start_len = gap->ga_len;
1486 
1487     /* Get our AnchorBase */
1488 #ifdef __amigaos4__
1489     Anchor = AllocDosObject(DOS_ANCHORPATH, AnchorTags);
1490 #else
1491     Anchor = (struct AnchorPath *)alloc_clear((unsigned)ANCHOR_SIZE);
1492 #endif
1493     if (Anchor == NULL)
1494 	return 0;
1495 
1496 #ifndef __amigaos4__
1497     Anchor->ap_Strlen = ANCHOR_BUF_SIZE;  /* ap_Length not supported anymore */
1498 # ifdef APF_DODOT
1499     Anchor->ap_Flags = APF_DODOT | APF_DOWILD;	/* allow '.' for current dir */
1500 # else
1501     Anchor->ap_Flags = APF_DoDot | APF_DoWild;	/* allow '.' for current dir */
1502 # endif
1503 #endif
1504 
1505 #ifdef FEAT_ARP
1506     if (dos2)
1507     {
1508 #endif
1509 	/* hack to replace '*' by '#?' */
1510 	starbuf = alloc((unsigned)(2 * STRLEN(pat) + 1));
1511 	if (starbuf == NULL)
1512 	    goto Return;
1513 	for (sp = pat, dp = starbuf; *sp; ++sp)
1514 	{
1515 	    if (*sp == '*')
1516 	    {
1517 		*dp++ = '#';
1518 		*dp++ = '?';
1519 	    }
1520 	    else
1521 		*dp++ = *sp;
1522 	}
1523 	*dp = NUL;
1524 	Result = MatchFirst((UBYTE *)starbuf, Anchor);
1525 	vim_free(starbuf);
1526 #ifdef FEAT_ARP
1527     }
1528     else
1529 	Result = FindFirst((char *)pat, Anchor);
1530 #endif
1531 
1532     /*
1533      * Loop to get all matches.
1534      */
1535     while (Result == 0)
1536     {
1537 #ifdef __amigaos4__
1538 	addfile(gap, (char_u *)Anchor->ap_Buffer, flags);
1539 #else
1540 	addfile(gap, (char_u *)Anchor->ap_Buf, flags);
1541 #endif
1542 #ifdef FEAT_ARP
1543 	if (dos2)
1544 #endif
1545 	    Result = MatchNext(Anchor);
1546 #ifdef FEAT_ARP
1547 	else
1548 	    Result = FindNext(Anchor);
1549 #endif
1550     }
1551     matches = gap->ga_len - start_len;
1552 
1553     if (Result == ERROR_BUFFER_OVERFLOW)
1554 	EMSG(_("ANCHOR_BUF_SIZE too small."));
1555     else if (matches == 0 && Result != ERROR_OBJECT_NOT_FOUND
1556 			  && Result != ERROR_DEVICE_NOT_MOUNTED
1557 			  && Result != ERROR_NO_MORE_ENTRIES)
1558 	EMSG(_("I/O ERROR"));
1559 
1560     /*
1561      * Sort the files for this pattern.
1562      */
1563     if (matches)
1564 	qsort((void *)(((char_u **)gap->ga_data) + start_len),
1565 				  (size_t)matches, sizeof(char_u *), sortcmp);
1566 
1567     /* Free the wildcard stuff */
1568 #ifdef FEAT_ARP
1569     if (dos2)
1570 #endif
1571 	MatchEnd(Anchor);
1572 #ifdef FEAT_ARP
1573     else
1574 	FreeAnchorChain(Anchor);
1575 #endif
1576 
1577 Return:
1578 #ifdef __amigaos4__
1579     FreeDosObject(DOS_ANCHORPATH, Anchor);
1580 #else
1581     vim_free(Anchor);
1582 #endif
1583 
1584     return matches;
1585 }
1586 
1587     static int
1588 sortcmp(a, b)
1589     const void *a, *b;
1590 {
1591     char *s = *(char **)a;
1592     char *t = *(char **)b;
1593 
1594     return pathcmp(s, t, -1);
1595 }
1596 
1597 /*
1598  * Return TRUE if "p" has wildcards that can be expanded by mch_expandpath().
1599  */
1600     int
1601 mch_has_exp_wildcard(p)
1602     char_u *p;
1603 {
1604     for ( ; *p; mb_ptr_adv(p))
1605     {
1606 	if (*p == '\\' && p[1] != NUL)
1607 	    ++p;
1608 	else if (vim_strchr((char_u *)"*?[(#", *p) != NULL)
1609 	    return TRUE;
1610     }
1611     return FALSE;
1612 }
1613 
1614     int
1615 mch_has_wildcard(p)
1616     char_u *p;
1617 {
1618     for ( ; *p; mb_ptr_adv(p))
1619     {
1620 	if (*p == '\\' && p[1] != NUL)
1621 	    ++p;
1622 	else
1623 	    if (vim_strchr((char_u *)
1624 #  ifdef VIM_BACKTICK
1625 				    "*?[(#$`"
1626 #  else
1627 				    "*?[(#$"
1628 #  endif
1629 						, *p) != NULL
1630 		    || (*p == '~' && p[1] != NUL))
1631 		return TRUE;
1632     }
1633     return FALSE;
1634 }
1635 
1636 /*
1637  * With AmigaDOS 2.0 support for reading local environment variables
1638  *
1639  * Two buffers are allocated:
1640  * - A big one to do the expansion into.  It is freed before returning.
1641  * - A small one to hold the return value.  It is kept until the next call.
1642  */
1643     char_u *
1644 mch_getenv(var)
1645     char_u *var;
1646 {
1647     int		    len;
1648     UBYTE	    *buf;		/* buffer to expand in */
1649     char_u	    *retval;		/* return value */
1650     static char_u   *alloced = NULL;	/* allocated memory */
1651 
1652 #ifdef FEAT_ARP
1653     if (!dos2)
1654 	retval = (char_u *)getenv((char *)var);
1655     else
1656 #endif
1657     {
1658 	vim_free(alloced);
1659 	alloced = NULL;
1660 	retval = NULL;
1661 
1662 	buf = alloc(IOSIZE);
1663 	if (buf == NULL)
1664 	    return NULL;
1665 
1666 	len = GetVar((UBYTE *)var, buf, (long)(IOSIZE - 1), (long)0);
1667 	if (len >= 0)
1668 	{
1669 	    retval = vim_strsave((char_u *)buf);
1670 	    alloced = retval;
1671 	}
1672 
1673 	vim_free(buf);
1674     }
1675 
1676     /* if $VIM is not defined, use "vim:" instead */
1677     if (retval == NULL && STRCMP(var, "VIM") == 0)
1678 	retval = (char_u *)"vim:";
1679 
1680     return retval;
1681 }
1682 
1683 /*
1684  * Amiga version of setenv() with AmigaDOS 2.0 support.
1685  */
1686 /* ARGSUSED */
1687     int
1688 mch_setenv(var, value, x)
1689     char *var;
1690     char *value;
1691     int	 x;
1692 {
1693 #ifdef FEAT_ARP
1694     if (!dos2)
1695 	return setenv(var, value);
1696 #endif
1697 
1698     if (SetVar((UBYTE *)var, (UBYTE *)value, (LONG)-1, (ULONG)GVF_LOCAL_ONLY))
1699 	return 0;   /* success */
1700     return -1;	    /* failure */
1701 }
1702