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