blob: 4a3014ba5c327ab53130bd857d56171da1591e89 [file] [log] [blame]
Bram Moolenaar071d4272004-06-13 20:20:40 +00001/* 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_mac.c -- code for the MacOS
12 *
13 * This file is mainly based on os_unix.c.
14 */
15
16#include "vim.h"
17
18#if defined(__MRC__) || defined(__SC__) /* for Apple MPW Compilers */
19
20#include "StandardFile.h"
21
22/*
23 * Implements the corresponding unix function
24 */
25 int
26stat(
27 char *p,
28 struct stat *p_st)
29{
30 /*
31 TODO: Use functions which fill the FileParam struct (Files.h)
32 and copy these contents to our self-defined stat struct
33 */
34 return 0;
35}
36#endif
37
38/*
39 * change the current working directory
40 */
41 int
42mch_chdir(char *p_name)
43{
44#if defined(__MRC__) || defined(__SC__) /* for Apple MPW Compilers */
45 /* TODO */
46 return FAIL;
47#else
48 return chdir(p_name);
49#endif
50}
51
52
53/*
54 * Recursively build up a list of files in "gap" matching the first wildcard
55 * in `path'. Called by mch_expandpath().
56 * "path" has backslashes before chars that are not to be expanded.
57 */
58 int
59mac_expandpath(
60 garray_T *gap,
61 char_u *path,
62 int flags, /* EW_* flags */
63 short start_at,
64 short as_full)
65{
66 /*
67 * TODO:
68 * +Get Volumes (when looking for files in current dir)
69 * +Make it work when working dir not on select volume
70 * +Cleanup
71 */
72 short index = 1;
73 OSErr gErr;
74 char_u dirname[256];
75 char_u cfilename[256];
76 long dirID;
77 char_u *new_name;
78 CInfoPBRec gMyCPB;
79 HParamBlockRec gMyHPBlock;
80 FSSpec usedDir;
81
82 char_u *buf;
83 char_u *p, *s, *e, dany;
84 int start_len, c;
85 char_u *pat;
86 regmatch_T regmatch;
87
88 start_len = gap->ga_len;
89 buf = alloc(STRLEN(path) + BASENAMELEN + 5);/* make room for file name */
90 if (buf == NULL)
91 return 0;
92
93/*
94 * Find the first part in the path name that contains a wildcard.
95 * Copy it into buf, including the preceding characters.
96 */
97 p = buf;
98 s = buf;
99 e = NULL;
100#if 1
101 STRNCPY(buf, path, start_at);
102 p += start_at;
103 path += start_at;
104#endif
105
106 while (*path)
107 {
108 if (*path == ':')
109 {
110 if (e)
111 break;
112 else
113 s = p + 1;
114 }
115 /* should use WILCARDLIST but what about ` */
116 /* if (vim_strchr((char_u *)"*?[{~$", *path) != NULL)*/
117 else if (vim_strchr((char_u *)WILDCHAR_LIST, *path) != NULL)
118 e = p;
119#ifdef FEAT_MBYTE
120 if (has_mbyte)
121 {
122 int len = (*mb_ptr2len_check)(path);
123
124 STRNCPY(p, path, len);
125 p += len;
126 path += len;
127 }
128 else
129#endif
130 *p++ = *path++;
131 }
132 e = p;
133
134 /* now we have one wildcard component between s and e */
135 *e = NUL;
136
137#if 1
138 dany = *s;
139 *s = NUL;
140 backslash_halve(buf);
141 *s = dany;
142#endif
143
144 /* convert the file pattern to a regexp pattern */
145 pat = file_pat_to_reg_pat(s, e, NULL, FALSE);
146 if (pat == NULL)
147 {
148 vim_free(buf);
149 return 0;
150 }
151
152 /* compile the regexp into a program */
153 regmatch.rm_ic = FALSE; /* Don't ever ignore case */
154 regmatch.regprog = vim_regcomp(pat, RE_MAGIC);
155 vim_free(pat);
156
157 if (regmatch.regprog == NULL)
158 {
159 vim_free(buf);
160 return 0;
161 }
162
163 /* open the directory for scanning */
164 c = *s;
165 *s = NUL;
166
167 if (*buf == NUL)
168 {
169 as_full = TRUE;
170#if 0
171 (void) mch_dirname (&dirname[1], 254);
172 dirname[0] = STRLEN(&dirname[1]);
173#endif
174 }
175 else
176 {
177 if (*buf == ':') /* relative path */
178 {
179 (void)mch_dirname(&dirname[1], 254);
180 new_name = concat_fnames(&dirname[1], buf+1, TRUE);
181 STRCPY(&dirname[1], new_name);
182 dirname[0] = STRLEN(new_name);
183 vim_free(new_name);
184 }
185 else
186 {
187 STRCPY(&dirname[1], buf);
188 backslash_halve(&dirname[1]);
189 dirname[0] = STRLEN(buf);
190 }
191 }
192 *s = c;
193
194 FSMakeFSSpec (0, 0, dirname, &usedDir);
195
196 gMyCPB.dirInfo.ioNamePtr = dirname;
197 gMyCPB.dirInfo.ioVRefNum = usedDir.vRefNum;
198 gMyCPB.dirInfo.ioFDirIndex = 0;
199 gMyCPB.dirInfo.ioDrDirID = 0;
200
201 gErr = PBGetCatInfo(&gMyCPB, false);
202
203 gMyCPB.dirInfo.ioCompletion = NULL;
204 dirID = gMyCPB.dirInfo.ioDrDirID;
205 do
206 {
207 gMyCPB.hFileInfo.ioFDirIndex = index;
208 gMyCPB.hFileInfo.ioDirID = dirID;
209
210 gErr = PBGetCatInfo(&gMyCPB,false);
211
212 if (gErr == noErr)
213 {
Bram Moolenaarb6356332005-07-18 21:40:44 +0000214 vim_strncpy(cfilename, &dirname[1], dirname[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000215 if (vim_regexec(&regmatch, cfilename, (colnr_T)0))
216 {
217 if (s[-1] != ':')
218 {
219 /* TODO: need to copy with cleaned name */
220 STRCPY(s+1, cfilename);
221 s[0] = ':';
222 }
223 else
224 { /* TODO: need to copy with cleeaned name */
225 STRCPY(s, cfilename);
226 }
227 start_at = STRLEN(buf);
228 STRCAT(buf, path);
229 if (mch_has_exp_wildcard(path)) /* handle more wildcards */
230 (void)mac_expandpath(gap, buf, flags, start_at, FALSE);
231 else
232 {
233#ifdef DONT_ADD_PATHSEP_TO_DIR
234 if ((gMyCPB.hFileInfo.ioFlAttrib & ioDirMask) !=0 )
235 STRCAT(buf, PATHSEPSTR);
236#endif
237 addfile(gap, buf, flags);
238 }
239 }
240 if ((gMyCPB.hFileInfo.ioFlAttrib & ioDirMask) !=0 )
241 {
242 }
243 else
244 {
245 }
246 }
247 index++;
248 }
249 while (gErr == noErr);
250
251 if (as_full)
252 {
253 index = 1;
254 do
255 {
256 gMyHPBlock.volumeParam.ioNamePtr = (char_u *) dirname;
257 gMyHPBlock.volumeParam.ioVRefNum =0;
258 gMyHPBlock.volumeParam.ioVolIndex = index;
259
260 gErr = PBHGetVInfo (&gMyHPBlock,false);
261 if (gErr == noErr)
262 {
Bram Moolenaarb6356332005-07-18 21:40:44 +0000263 vim_strncpy(cfilename, &dirname[1], dirname[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000264 if (vim_regexec(&regmatch, cfilename, (colnr_T)0))
265 {
266 STRCPY(s, cfilename);
267 STRCAT(buf, path);
268 if (mch_has_exp_wildcard(path)) /* handle more wildcards */
269 (void)mac_expandpath(gap, s, flags, 0, FALSE);
270 else
271 {
272#ifdef DONT_ADD_PATHSEP_TO_DIR
273/* if ((gMyCPB.hFileInfo.ioFlAttrib & ioDirMask) !=0 )
274*/ STRCAT(buf, PATHSEPSTR);
275#endif
276 addfile(gap, s, flags);
277 }
278#if 0
279 STRCAT(cfilename, PATHSEPSTR);
280 addfile (gap, cfilename, flags);
281#endif
282 }
283 }
284 index++;
285 }
286 while (gErr == noErr);
287 }
288
289 vim_free(regmatch.regprog);
290
291 return gap->ga_len - start_len;
292}
293
294
295#ifdef USE_UNIXFILENAME
296 static int
297pstrcmp(a, b)
298 const void *a, *b;
299{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000300 return (pathcmp(*(char **)a, *(char **)b, -1));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000301}
302
303 static int
304unix_expandpath(gap, path, wildoff, flags)
305 garray_T *gap;
306 char_u *path;
307 int wildoff;
308 int flags; /* EW_* flags */
309{
310 char_u *buf;
311 char_u *path_end;
312 char_u *p, *s, *e;
313 int start_len, c;
314 char_u *pat;
315 DIR *dirp;
316 regmatch_T regmatch;
317 struct dirent *dp;
318 int starts_with_dot;
319 int matches;
320 int len;
321
322 start_len = gap->ga_len;
323 buf = alloc(STRLEN(path) + BASENAMELEN + 5);/* make room for file name */
324 if (buf == NULL)
325 return 0;
326
327/*
328 * Find the first part in the path name that contains a wildcard.
329 * Copy it into buf, including the preceding characters.
330 */
331 p = buf;
332 s = buf;
333 e = NULL;
334 path_end = path;
335 while (*path_end)
336 {
337 /* May ignore a wildcard that has a backslash before it */
338 if (path_end >= path + wildoff && rem_backslash(path_end))
339 *p++ = *path_end++;
340 else if (*path_end == '/')
341 {
342 if (e != NULL)
343 break;
344 else
345 s = p + 1;
346 }
347 else if (vim_strchr((char_u *)"*?[{~$", *path_end) != NULL)
348 e = p;
349#ifdef FEAT_MBYTE
350 if (has_mbyte)
351 {
352 len = (*mb_ptr2len_check)(path_end);
353 STRNCPY(p, path_end, len);
354 p += len;
355 path_end += len;
356 }
357 else
358#endif
359 *p++ = *path_end++;
360 }
361 e = p;
362 *e = NUL;
363
364 /* now we have one wildcard component between s and e */
365 /* Remove backslashes between "wildoff" and the start of the wildcard
366 * component. */
367 for (p = buf + wildoff; p < s; ++p)
368 if (rem_backslash(p))
369 {
370 STRCPY(p, p + 1);
371 --e;
372 --s;
373 }
374
375 /* convert the file pattern to a regexp pattern */
376 starts_with_dot = (*s == '.');
377 pat = file_pat_to_reg_pat(s, e, NULL, FALSE);
378 if (pat == NULL)
379 {
380 vim_free(buf);
381 return 0;
382 }
383
384 /* compile the regexp into a program */
385#ifdef MACOS_X
386 /* We want to behave like Terminal.app */
387 regmatch.rm_ic = TRUE;
388#else
389 regmatch.rm_ic = FALSE; /* Don't ever ignore case */
390#endif
391 regmatch.regprog = vim_regcomp(pat, RE_MAGIC);
392 vim_free(pat);
393
394 if (regmatch.regprog == NULL)
395 {
396 vim_free(buf);
397 return 0;
398 }
399
400 /* open the directory for scanning */
401 c = *s;
402 *s = NUL;
403 dirp = opendir(*buf == NUL ? "." : (char *)buf);
404 *s = c;
405
406 /* Find all matching entries */
407 if (dirp != NULL)
408 {
409 for (;;)
410 {
411 dp = readdir(dirp);
412 if (dp == NULL)
413 break;
414 if ((dp->d_name[0] != '.' || starts_with_dot)
415 && vim_regexec(&regmatch, (char_u *)dp->d_name, (colnr_T)0))
416 {
417 STRCPY(s, dp->d_name);
418 len = STRLEN(buf);
419 STRCPY(buf + len, path_end);
420 if (mch_has_exp_wildcard(path_end)) /* handle more wildcards */
421 {
422 /* need to expand another component of the path */
423 /* remove backslashes for the remaining components only */
424 (void)unix_expandpath(gap, buf, len + 1, flags);
425 }
426 else
427 {
428 /* no more wildcards, check if there is a match */
429 /* remove backslashes for the remaining components only */
430 if (*path_end)
431 backslash_halve(buf + len + 1);
432 if (mch_getperm(buf) >= 0) /* add existing file */
433 addfile(gap, buf, flags);
434 }
435 }
436 }
437
438 closedir(dirp);
439 }
440
441 vim_free(buf);
442 vim_free(regmatch.regprog);
443
444 matches = gap->ga_len - start_len;
445 if (matches)
446 qsort(((char_u **)gap->ga_data) + start_len, matches,
447 sizeof(char_u *), pstrcmp);
448 return matches;
449}
450#endif
451
452/*
453 * Recursively build up a list of files in "gap" matching the first wildcard
454 * in `path'. Called by expand_wildcards().
455 * "pat" has backslashes before chars that are not to be expanded.
456 */
457 int
458mch_expandpath(
459 garray_T *gap,
460 char_u *path,
461 int flags) /* EW_* flags */
462{
463#ifdef USE_UNIXFILENAME
464 return unix_expandpath(gap, path, 0, flags);
465#else
466 char_u first = *path;
467 short scan_volume;
468
469 slash_n_colon_adjust(path);
470
471 scan_volume = (first != *path);
472
473 return mac_expandpath(gap, path, flags, 0, scan_volume);
474#endif
475}
476
477 void
478fname_case(name, len)
479 char_u *name;
480 int len; /* buffer size, ignored here */
481{
482 /*
483 * TODO: get the real casing for the file
484 * make it called
485 * with USE_FNAME_CASE & USE_LONG_FNAME
486 * CASE_INSENSITIVE_FILENAME
487 * within setfname, fix_fname, do_ecmd
488 */
489#ifdef USE_UNIXFILENAME
490 OSStatus status;
491 FSRef refFile;
492 UInt32 pathSize = STRLEN(name) + 1;
493 char_u *path;
494 Boolean isDirectory;
495
496 path = alloc(pathSize);
497 if (path == NULL)
498 return;
499
500 status = FSPathMakeRef((UInt8 *)name, &refFile, &isDirectory);
501 if (status)
502 return;
503
504 status = FSRefMakePath(&refFile, (UInt8 *)path, pathSize);
505 if (status)
506 return;
507
508 /* Paranoid: Update the name if only the casing differ.*/
509 if (STRICMP(name, path) == 0)
510 STRCPY(name, path);
511#endif
512}
513static char_u *oldtitle = (char_u *) "gVim";
514
515/*
516 * check for an "interrupt signal": CTRL-break or CTRL-C
517 */
518 void
519mch_breakcheck()
520{
521 /*
522 * TODO: Scan event for a CTRL-C or COMMAND-. and do: got_int=TRUE;
523 * or only go proccess event?
524 * or do nothing
525 */
526 EventRecord theEvent;
527
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000528 if (EventAvail(keyDownMask, &theEvent))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000529 if ((theEvent.message & charCodeMask) == Ctrl_C && ctrl_c_interrupts)
530 got_int = TRUE;
531#if 0
532 short i = 0;
533 Boolean found = false;
534 EventRecord theEvent;
535
536 while ((i < 10) && (!found))
537 {
538 found = EventAvail (keyDownMask, &theEvent);
539 if (found)
540 {
541 if ((theEvent.modifiers & controlKey) != 0)
542 found = false;
543 if ((theEvent.what == keyDown))
544 found = false;
545 if ((theEvent.message & charCodeMask) == Ctrl_C)
546 {
547 found = false;
548 got_int = TRUE;
549 }
550 }
551 i++;
552 }
553#endif
554
555}
556
557/*
558 * Return amount of memory currently available.
559 */
560 long_u
561mch_avail_mem(special)
562 int special;
563{
564 /*
565 * TODO: Use MaxBlock, FreeMeM, PurgeSpace, MaxBlockSys FAQ-266
566 * figure out what the special is for
567 *
568 * FreeMem -> returns all avail memory is application heap
569 * MaxBlock -> returns the biggest contigeous block in application heap
570 * PurgeSpace ->
571 */
572 return MaxBlock();
573}
574
575 void
576mch_delay(msec, ignoreinput)
577 long msec;
578 int ignoreinput;
579{
580#if (defined(__MWERKS__) && __MWERKS__ >= 0x2000) \
581 || defined(__MRC__) || defined(__SC__)
582 unsigned
583#endif
584 long finalTick;
585
586 if (ignoreinput)
587 Delay (60*msec/1000, &finalTick);
588 else
589 /* even thougth we should call gui stuff from here
590 it the simplest way to be safe */
591 gui_mch_wait_for_chars(msec);
592}
593
594 void
595mch_init()
596{
597 /*
598 * TODO: Verify if needed, or override later.
599 */
600 Columns = 80;
601 Rows = 24;
602}
603
604/*
605 * Check_win checks whether we have an interactive stdout.
606 */
607 int
608mch_check_win(argc, argv)
609 int argc;
610 char **argv;
611{
612 /*
613 * TODO: Maybe to be remove through NO_CONSOLE
614 */
615 return OK;
616}
617
618/*
619 * Return TRUE if the input comes from a terminal, FALSE otherwise.
620 */
621 int
622mch_input_isatty()
623{
624 /*
625 * TODO: Maybe to be remove through NO_CONSOLE
626 */
627 return OK;
628}
629
630#ifdef FEAT_TITLE
631/*
632 * Set the window title and icon.
633 * (The icon is not taken care of).
634 */
635 void
636mch_settitle(title, icon)
637 char_u *title;
638 char_u *icon;
639{
640 gui_mch_settitle(title, icon);
641}
642
643/*
644 * Restore the window/icon title.
645 * which is one of:
646 * 1 Just restore title
647 * 2 Just restore icon
648 * 3 Restore title and icon
649 * but don't care about the icon.
650 */
651 void
652mch_restore_title(which)
653 int which;
654{
655 mch_settitle((which & 1) ? oldtitle : NULL, NULL);
656}
657#endif
658
659/*
660 * Insert user name in s[len].
661 * Return OK if a name found.
662 */
663 int
664mch_get_user_name(s, len)
665 char_u *s;
666 int len;
667{
668#if !(defined(__MRC__) || defined(__SC__)) /* No solution yet */
669 /*
670 * TODO: clean up and try getlogin ()
671 */
672#if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID)
673 struct passwd *pw;
674#endif
675 uid_t uid;
676
677 uid = getuid();
678#if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID)
679 if ((pw = getpwuid(uid)) != NULL
680 && pw->pw_name != NULL && *(pw->pw_name) != NUL)
681 {
Bram Moolenaarb6356332005-07-18 21:40:44 +0000682 vim_strncpy(s, pw->pw_name, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000683 return OK;
684 }
685#endif
686 sprintf((char *)s, "%d", (int)uid); /* assumes s is long enough */
687#endif
688 return FAIL; /* a number is not a name */
689}
690
691/*
692 * Copy host name into s[len].
693 */
694 void
695mch_get_host_name(s, len)
696 char_u *s;
697 int len;
698{
699#if defined(__MRC__) || defined(__SC__) || defined(__APPLE_CC__)
Bram Moolenaarb6356332005-07-18 21:40:44 +0000700 vim_strncpy(s, "Mac", len - 1); /* TODO: use Gestalt information */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000701#else
702 struct utsname vutsname;
703
704 if (uname(&vutsname) < 0)
705 *s = NUL;
706 else
Bram Moolenaarb6356332005-07-18 21:40:44 +0000707 vim_strncpy(s, vutsname.nodename, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000708#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000709}
710
711/*
712 * return process ID
713 */
714 long
715mch_get_pid()
716{
717 return (long)getpid();
718}
719
720/*
721 * Get name of current directory into buffer 'buf' of length 'len' bytes.
722 * Return OK for success, FAIL for failure.
723 */
724 int
725mch_dirname(buf, len)
726 char_u *buf;
727 int len;
728{
729#if defined(__MRC__) || defined(__SC__)
730 return FAIL; /* No solution yet */
731#else
732 /* The last : is already put by getcwd */
733 if (getcwd((char *)buf, len) == NULL)
734 {
735 STRCPY(buf, strerror(errno));
736 return FAIL;
737 }
738# ifndef USE_UNIXFILENAME
739 else if (*buf != NUL && buf[STRLEN(buf) - 1] == ':')
740 buf[STRLEN(buf) - 1] = NUL; /* remove trailing ':' */
741# endif
742 return OK;
743#endif
744}
745
746 void
747slash_to_colon(p)
748 char_u *p;
749{
750 for ( ; *p; ++p)
751 if (*p == '/')
752 *p = ':';
753}
754
755 char_u *
756slash_to_colon_save (p)
757 char_u *p;
758{
759 char_u *res;
760
761 res = vim_strsave(p);
762 if (res == NULL)
763 return p;
764 slash_to_colon(res);
765 return res;
766}
767
768 void
769slash_n_colon_adjust (buf)
770 char_u *buf;
771{
772 /*
773 * TODO: Make it faster
774 */
775#ifndef USE_UNIXFILENAME
776 char_u temp[MAXPATHL];
777 char_u *first_colon = vim_strchr(buf, ':');
778 char_u *first_slash = vim_strchr(buf, '/');
779 int full = TRUE;
780 char_u *scanning;
781 char_u *filling;
782 char_u last_copied = NUL;
783
784 if (*buf == NUL)
785 return ;
786
787 if ((first_colon == NULL) && (first_slash == NULL))
788 full = FALSE;
789 if ((first_slash == NULL) && (first_colon != NULL))
790 full = TRUE;
791 if ((first_colon == NULL) && (first_slash != NULL))
792 full = FALSE;
793 if ((first_slash < first_colon) && (first_slash != NULL))
794 full = FALSE;
795 if ((first_colon < first_slash) && (first_colon != NULL))
796 full = TRUE;
797 if (first_slash == buf)
798 full = TRUE;
799 if (first_colon == buf)
800 full = FALSE;
801
802 scanning = buf;
803 filling = temp;
804
805 while (*scanning != NUL)
806 {
807 if (*scanning == '/')
808 {
809 if ((scanning[1] != '/') && (scanning[-1] != ':'))
810 {
811 *filling++ = ':';
812 scanning++;
813 }
814 else
815 scanning++;
816 }
817 else if (*scanning == '.')
818 {
819 if ((scanning[1] == NUL) || scanning[1] == '/')
820 {
821 if (scanning[1] == NUL)
822 scanning += 1;
823 else
824 scanning += 2;
825 }
826 else if (scanning[1] == '.')
827 {
828 if ((scanning[2] == NUL) || scanning[2] == '/')
829 {
830 *filling++ = ':';
831 if (scanning[2] == NUL)
832 scanning +=2;
833 else
834 scanning += 3;
835 }
836 else
837 {
838 *filling++ = *scanning++;
839 }
840 }
841 else
842 {
843 *filling++ = *scanning++;
844 }
845
846 }
847 else
848 {
849 *filling++ = *scanning++;
850 }
851
852 }
853
854 *filling = 0;
855 filling = temp;
856
857 if (!full)
858 {
859 if (buf[0] != ':')
860 {
861 buf[0] = ':';
862 buf[1] = NUL;
863 }
864 else
865 buf[0] = NUL;
866 }
867 else
868 {
869 buf[0] = NUL;
870 if (filling[0] == ':')
871 filling++;
872 }
873
874 STRCAT (buf, filling);
875#endif
876}
877
878/*
879 * Get absolute filename into buffer 'buf' of length 'len' bytes.
880 *
881 * return FAIL for failure, OK for success
882 */
883 int
884mch_FullName(fname, buf, len, force)
885 char_u *fname, *buf;
886 int len;
887 int force; /* also expand when already absolute path name */
888{
889 /*
890 * TODO: Find what TODO
891 */
892 int l;
893 char_u olddir[MAXPATHL];
894 char_u newdir[MAXPATHL];
895 char_u *p;
896 char_u c;
897 int retval = OK;
898
899 if (force || !mch_isFullName(fname))
900 {
901 /*
902 * Forced or not an absolute path.
903 * If the file name has a path, change to that directory for a moment,
904 * and then do the getwd() (and get back to where we were).
905 * This will get the correct path name with "../" things.
906 */
907 if ((p = vim_strrchr(fname, ':')) != NULL)
908 {
909 p++;
910 if (mch_dirname(olddir, MAXPATHL) == FAIL)
911 {
912 p = NULL; /* can't get current dir: don't chdir */
913 retval = FAIL;
914 }
915 else
916 {
917 c = *p;
918 *p = NUL;
919 if (mch_chdir((char *)fname))
920 retval = FAIL;
921 else
922 fname = p; /* + 1;*/
923 *p = c;
924 }
925 }
926 if (mch_dirname(buf, len) == FAIL)
927 {
928 retval = FAIL;
929 *newdir = NUL;
930 }
931 l = STRLEN(buf);
932 if (STRCMP(fname, ".") != 0)
933 {
934#ifdef USE_UNIXFILENAME
935 if (l > 0 && buf[l - 1] != '/' && *fname != NUL)
936 STRCAT(buf, "/");
937#else
938 if (l > 0 && buf[l - 1] != ':' && *fname != NUL)
939 STRCAT(buf, ":");
940#endif
941 }
942 if (p != NULL)
943 mch_chdir((char *)olddir);
944 if (STRCMP(fname, ".") != 0)
945 STRCAT(buf, fname);
946 }
947 else
948 {
Bram Moolenaarb6356332005-07-18 21:40:44 +0000949 vim_strncpy(buf, fname, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000950 slash_n_colon_adjust(buf);
951 }
952
953 return retval;
954}
955
956/*
957 * Return TRUE if "fname" does not depend on the current directory.
958 */
959 int
960mch_isFullName(fname)
961 char_u *fname;
962{
963#ifdef USE_UNIXFILENAME
964 return ((fname[0] == '/') || (fname[0] == '~'));
965#else
966 /*
967 * TODO: Make sure fname is always of mac still
968 * i.e: passed throught slash_n_colon_adjust
969 */
970 char_u *first_colon = vim_strchr(fname, ':');
971 char_u *first_slash = vim_strchr(fname, '/');
972
973 if (first_colon == fname)
974 return FALSE;
975 if (first_slash == fname)
976 return TRUE;
977 if ((first_colon < first_slash) && (first_colon != NULL))
978 return TRUE;
979 if ((first_slash < first_colon) && (first_slash != NULL))
980 return FALSE;
981 if ((first_colon == NULL) && (first_slash != NULL))
982 return FALSE;
983 if ((first_slash == NULL) && (first_colon != NULL))
984 return TRUE;
985 if ((first_colon == NULL) && (first_slash == NULL))
986 return FALSE;
987 return TRUE;
988#endif
989}
990
991/*
992 * Replace all slashes by colons.
993 */
994 void
995slash_adjust(p)
996 char_u *p;
997{
998#ifndef USE_UNIXFILENAME
999 /*
1000 * TODO: keep escaped '/'
1001 */
1002
1003 while (*p)
1004 {
1005 if (*p == '/')
1006 *p = ':';
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001007 mb_ptr_adv(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001008 }
1009#endif
1010}
1011
1012/*
1013 * Get file permissions for 'name'.
1014 * Returns -1 when it doesn't exist.
1015 */
1016 long
1017mch_getperm(name)
1018 char_u *name;
1019{
1020 /*
1021 * TODO: Maybe use AppleShare info??
1022 * Use locked for non writable
1023 */
1024
1025 struct stat statb;
1026
1027 if (stat((char *)name, &statb))
1028 return -1;
1029 return statb.st_mode;
1030}
1031
1032/*
1033 * set file permission for 'name' to 'perm'
1034 *
1035 * return FAIL for failure, OK otherwise
1036 */
1037 int
1038mch_setperm(name, perm)
1039 char_u *name;
1040 long perm;
1041{
1042 /*
1043 * TODO: Maybe use AppleShare info??
1044 * Use locked for non writable
1045 */
1046 return (OK);
1047}
1048
1049/*
1050 * Set hidden flag for "name".
1051 */
1052 void
1053mch_hide(name)
1054 char_u *name;
1055{
1056 /*
1057 * TODO: Hide the file throught FileManager FAQ 8-34
1058 *
1059 * *name is mac style start with : for relative
1060 */
1061}
1062
1063
1064/*
1065 * return TRUE if "name" is a directory
1066 * return FALSE if "name" is not a directory
1067 * return FALSE for error
1068 */
1069 int
1070mch_isdir(name)
1071 char_u *name;
1072{
1073 /*
1074 * TODO: Find out by FileManager calls ...
1075 */
1076 struct stat statb;
1077
1078#if defined(TARGET_API_MAC_CARBON) && TARGET_API_MAC_CARBON
1079 /* For some reason the name is sometimes empty,
1080 * (such as for a not yet named file). An empty
1081 * filename is interpreted by the MacOS version
1082 * of stat (at least under Codewarrior) as the
1083 * current directory.
1084 */
1085 /* AK 20020413
1086 * This is required for Carbon but breaks the
1087 * explorer plugin in Classic
1088 */
1089 if (name[0] == NULL)
1090 return FALSE;
1091#endif
1092
1093 if (stat((char *)name, &statb))
1094 return FALSE;
1095#if defined(__MRC__) || defined(__SC__)
1096 return FALSE; /* definitely TODO */
1097#else
1098 return ((statb.st_mode & S_IFMT) == S_IFDIR ? TRUE : FALSE);
1099#endif
1100}
1101
1102#if defined(FEAT_EVAL) || defined(PROTO)
1103/*
1104 * Return 1 if "name" can be executed, 0 if not.
1105 * Return -1 if unknown.
1106 */
1107 int
1108mch_can_exe(name)
1109 char_u *name;
1110{
1111 /* TODO */
1112 return -1;
1113}
1114#endif
1115
1116/*
1117 * Check what "name" is:
1118 * NODE_NORMAL: file or directory (or doesn't exist)
1119 * NODE_WRITABLE: writable device, socket, fifo, etc.
1120 * NODE_OTHER: non-writable things
1121 */
1122 int
1123mch_nodetype(name)
1124 char_u *name;
1125{
1126 /* TODO */
1127 return NODE_NORMAL;
1128}
1129
1130 void
1131mch_early_init()
1132{
1133}
1134
1135 void
1136mch_exit(r)
1137 int r;
1138{
1139 display_errors();
1140
1141 ml_close_all(TRUE); /* remove all memfiles */
1142 exit(r);
1143}
1144
1145
1146 void
1147mch_settmode(tmode)
1148 int tmode;
1149{
1150 /*
1151 * TODO: remove the needs of it.
1152 */
1153}
1154
1155#ifdef FEAT_MOUSE
1156/*
1157 * set mouse clicks on or off (only works for xterms)
1158 */
1159 void
1160mch_setmouse(on)
1161 int on;
1162{
1163 /*
1164 * TODO: remove the needs of it.
1165 */
1166}
1167#endif
1168
1169/*
1170 * set screen mode, always fails.
1171 */
1172 int
1173mch_screenmode(arg)
1174 char_u *arg;
1175{
1176 EMSG(_(e_screenmode));
1177 return FAIL;
1178}
1179
1180 int
1181mch_call_shell(cmd, options)
1182 char_u *cmd;
1183 int options; /* SHELL_*, see vim.h */
1184{
1185 /*
1186 * TODO: find a shell or pseudo-shell to call
1187 * for some simple useful command
1188 */
1189
1190 return (-1);
1191}
1192
1193/*
1194 * Return TRUE if "p" contains a wildcard that can be expanded by
1195 * mch_expandpath().
1196 */
1197 int
1198mch_has_exp_wildcard(p)
1199 char_u *p;
1200{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001201 for ( ; *p; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001202 {
1203 if (*p == '\\' && p[1] != NUL)
1204 ++p;
1205 else if (vim_strchr((char_u *)WILDCHAR_LIST, *p) != NULL)
1206 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001207 }
1208 return FALSE;
1209}
1210
1211 int
1212mch_has_wildcard(p)
1213 char_u *p;
1214{
1215#ifdef USE_UNIXFILENAME
1216 if (*p == '~' && p[1] != NUL)
1217 return TRUE;
1218#endif
1219 return mch_has_exp_wildcard(p);
1220}
1221
1222
1223/*
1224 * This procedure duplicate a file, it is used in order to keep
1225 * the footprint of the previous file, when some info can be easily
1226 * restored with set_perm().
1227 *
1228 * Return -1 for failure, 0 for success.
1229 */
1230 int
1231mch_copy_file(from, to)
1232 char_u *from;
1233 char_u *to;
1234{
1235 char_u from_str[256];
1236 char_u to_str[256];
1237 char_u to_name[256];
1238
1239 HParamBlockRec paramBlock;
1240 char_u *char_ptr;
1241 int len;
1242
1243 /*
1244 * Convert C string to Pascal string
1245 */
1246 char_ptr = from;
1247 len = 1;
1248 for (; (*char_ptr != 0) && (len < 255); len++, char_ptr++)
1249 from_str[len] = *char_ptr;
1250 from_str[0] = len-1;
1251
1252 char_ptr = to;
1253 len = 1;
1254 for (; (*char_ptr != 0) && (len < 255); len++, char_ptr++)
1255 to_str[len] = *char_ptr;
1256 to_str[0] = len-1;
1257
1258 paramBlock.copyParam.ioCompletion = NULL;
1259 paramBlock.copyParam.ioNamePtr = from_str;
1260 /* paramBlock.copyParam.ioVRefnum = overided by ioFilename; */
1261 /* paramBlock.copyParam.ioDirI = overided by ioFilename; */
1262
1263 paramBlock.copyParam.ioNewName = to_str;
1264 paramBlock.copyParam.ioCopyName = to_name; /* NIL */
1265 /* paramBlock.copyParam.ioDstVRefNum = overided by ioNewName; */
1266 /* paramBlock.copyParam.ioNewDirID = overided by ioNewName; */
1267
1268
1269
1270 /*
1271 * First delete the "to" file, this is required on some systems to make
1272 * the rename() work, on other systems it makes sure that we don't have
1273 * two files when the rename() fails.
1274 */
1275 mch_remove(to);
1276
1277 /*
1278 * First try a normal rename, return if it works.
1279 */
1280 (void) PBHCopyFile(&paramBlock, false);
1281 return 0;
1282
1283}
1284
1285
1286 int
1287mch_copy_file_attribute(from, to)
1288 char_u *from;
1289 char_u *to;
1290{
Bram Moolenaar8299df92004-07-10 09:47:34 +00001291 FSSpec frFSSpec;
1292 FSSpec toFSSpec;
1293 FInfo fndrInfo;
1294 Str255 name;
1295 ResType type;
1296 ResType sink;
1297 Handle resource;
1298 short idxTypes;
1299 short nbTypes;
1300 short idxResources;
1301 short nbResources;
1302 short ID;
1303 short frRFid;
1304 short toRFid;
1305 short attrs_orig;
1306 short attrs_copy;
1307 short temp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001308
1309 /* TODO: Handle error */
Bram Moolenaar8299df92004-07-10 09:47:34 +00001310 (void)GetFSSpecFromPath(from, &frFSSpec);
1311 (void)GetFSSpecFromPath(to , &toFSSpec);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001312
1313 /* Copy resource fork */
1314 temp = 0;
1315
1316#if 1
1317 frRFid = FSpOpenResFile (&frFSSpec, fsCurPerm);
1318
1319 if (frRFid != -1)
1320 {
1321 FSpCreateResFile(&toFSSpec, 'TEXT', UNKNOWN_CREATOR, 0);
Bram Moolenaar8299df92004-07-10 09:47:34 +00001322 toRFid = FSpOpenResFile(&toFSSpec, fsRdWrPerm);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001323
Bram Moolenaar8299df92004-07-10 09:47:34 +00001324 UseResFile(frRFid);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001325
1326 nbTypes = Count1Types();
1327
1328 for (idxTypes = 1; idxTypes <= nbTypes; idxTypes++)
1329 {
Bram Moolenaar8299df92004-07-10 09:47:34 +00001330 Get1IndType(&type, idxTypes);
1331 nbResources = Count1Resources(type);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001332
Bram Moolenaar8299df92004-07-10 09:47:34 +00001333 for (idxResources = 1; idxResources <= nbResources; idxResources++)
1334 {
1335 attrs_orig = 0; /* in case GetRes fails */
1336 attrs_copy = 0; /* in case GetRes fails */
1337 resource = Get1IndResource(type, idxResources);
1338 GetResInfo(resource, &ID, &sink, name);
1339 HLock(resource);
1340 attrs_orig = GetResAttrs(resource);
1341 DetachResource(resource);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001342
1343
Bram Moolenaar8299df92004-07-10 09:47:34 +00001344 UseResFile(toRFid);
1345 AddResource(resource, type, ID, name);
1346 attrs_copy = GetResAttrs(resource);
1347 attrs_copy = (attrs_copy & 0x2) | (attrs_orig & 0xFD);
1348 SetResAttrs(resource, attrs_copy);
1349 WriteResource(resource);
1350 UpdateResFile(toRFid);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001351
Bram Moolenaar8299df92004-07-10 09:47:34 +00001352 temp = GetResAttrs(resource);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001353
Bram Moolenaar8299df92004-07-10 09:47:34 +00001354 /*SetResAttrs (resource, 0);*/
1355 HUnlock(resource);
1356 ReleaseResource(resource);
1357 UseResFile(frRFid);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001358 }
1359 }
Bram Moolenaar8299df92004-07-10 09:47:34 +00001360 CloseResFile(toRFid);
1361 CloseResFile(frRFid);
1362 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001363#endif
1364 /* Copy Finder Info */
Bram Moolenaar8299df92004-07-10 09:47:34 +00001365 (void)FSpGetFInfo(&frFSSpec, &fndrInfo);
1366 (void)FSpSetFInfo(&toFSSpec, &fndrInfo);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001367
1368 return (temp == attrs_copy);
1369}
1370
1371 int
1372mch_has_resource_fork (file)
1373 char_u *file;
1374{
1375 FSSpec fileFSSpec;
Bram Moolenaar8299df92004-07-10 09:47:34 +00001376 short fileRFid;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001377
1378 /* TODO: Handle error */
Bram Moolenaar8299df92004-07-10 09:47:34 +00001379 (void)GetFSSpecFromPath(file, &fileFSSpec);
1380 fileRFid = FSpOpenResFile(&fileFSSpec, fsCurPerm);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001381 if (fileRFid != -1)
Bram Moolenaar8299df92004-07-10 09:47:34 +00001382 CloseResFile(fileRFid);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001383
1384 return (fileRFid != -1);
1385}
1386
1387 int
1388mch_get_shellsize(void)
1389{
1390 /* never used */
1391 return OK;
1392}
1393
1394 void
1395mch_set_shellsize(void)
1396{
1397 /* never used */
1398}
1399
1400/*
1401 * Rows and/or Columns has changed.
1402 */
1403 void
1404mch_new_shellsize(void)
1405{
1406 /* never used */
1407}
1408
1409/*
1410 * Those function were set as #define before, but in order
1411 * to allow an easier us of os_unix.c for the MacOS X port,
1412 * they are change to procedure. Thec ompile whould optimize
1413 * them out.
1414 */
1415
1416 int
1417mch_can_restore_title()
1418{
1419 return TRUE;
1420}
1421
1422 int
1423mch_can_restore_icon()
1424{
1425 return TRUE;
1426}
1427
1428/*
1429 * If the machine has job control, use it to suspend the program,
1430 * otherwise fake it by starting a new shell.
1431 */
1432 void
1433mch_suspend()
1434{
1435 /* TODO: get calle in #ifndef NO_CONSOLE */
1436 gui_mch_iconify();
1437};
1438