summaryrefslogtreecommitdiff
path: root/src/os_mac.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/os_mac.c')
-rw-r--r--src/os_mac.c1451
1 files changed, 1451 insertions, 0 deletions
diff --git a/src/os_mac.c b/src/os_mac.c
new file mode 100644
index 000000000..0f6a76ceb
--- /dev/null
+++ b/src/os_mac.c
@@ -0,0 +1,1451 @@
+/* vi:set ts=8 sts=4 sw=4:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ * See README.txt for an overview of the Vim source code.
+ */
+
+/*
+ * os_mac.c -- code for the MacOS
+ *
+ * This file is mainly based on os_unix.c.
+ */
+
+#include "vim.h"
+
+#if defined(__MRC__) || defined(__SC__) /* for Apple MPW Compilers */
+
+#include "StandardFile.h"
+
+/*
+ * Implements the corresponding unix function
+ */
+ int
+stat(
+ char *p,
+ struct stat *p_st)
+{
+ /*
+ TODO: Use functions which fill the FileParam struct (Files.h)
+ and copy these contents to our self-defined stat struct
+ */
+ return 0;
+}
+#endif
+
+/*
+ * change the current working directory
+ */
+ int
+mch_chdir(char *p_name)
+{
+#if defined(__MRC__) || defined(__SC__) /* for Apple MPW Compilers */
+ /* TODO */
+ return FAIL;
+#else
+ return chdir(p_name);
+#endif
+}
+
+
+/*
+ * Recursively build up a list of files in "gap" matching the first wildcard
+ * in `path'. Called by mch_expandpath().
+ * "path" has backslashes before chars that are not to be expanded.
+ */
+ int
+mac_expandpath(
+ garray_T *gap,
+ char_u *path,
+ int flags, /* EW_* flags */
+ short start_at,
+ short as_full)
+{
+ /*
+ * TODO:
+ * +Get Volumes (when looking for files in current dir)
+ * +Make it work when working dir not on select volume
+ * +Cleanup
+ */
+ short index = 1;
+ OSErr gErr;
+ char_u dirname[256];
+ char_u cfilename[256];
+ long dirID;
+ char_u *new_name;
+ CInfoPBRec gMyCPB;
+ HParamBlockRec gMyHPBlock;
+ FSSpec usedDir;
+
+ char_u *buf;
+ char_u *p, *s, *e, dany;
+ int start_len, c;
+ char_u *pat;
+ regmatch_T regmatch;
+
+ start_len = gap->ga_len;
+ buf = alloc(STRLEN(path) + BASENAMELEN + 5);/* make room for file name */
+ if (buf == NULL)
+ return 0;
+
+/*
+ * Find the first part in the path name that contains a wildcard.
+ * Copy it into buf, including the preceding characters.
+ */
+ p = buf;
+ s = buf;
+ e = NULL;
+#if 1
+ STRNCPY(buf, path, start_at);
+ p += start_at;
+ path += start_at;
+#endif
+
+ while (*path)
+ {
+ if (*path == ':')
+ {
+ if (e)
+ break;
+ else
+ s = p + 1;
+ }
+ /* should use WILCARDLIST but what about ` */
+ /* if (vim_strchr((char_u *)"*?[{~$", *path) != NULL)*/
+ else if (vim_strchr((char_u *)WILDCHAR_LIST, *path) != NULL)
+ e = p;
+#ifdef FEAT_MBYTE
+ if (has_mbyte)
+ {
+ int len = (*mb_ptr2len_check)(path);
+
+ STRNCPY(p, path, len);
+ p += len;
+ path += len;
+ }
+ else
+#endif
+ *p++ = *path++;
+ }
+ e = p;
+
+ /* now we have one wildcard component between s and e */
+ *e = NUL;
+
+#if 1
+ dany = *s;
+ *s = NUL;
+ backslash_halve(buf);
+ *s = dany;
+#endif
+
+ /* convert the file pattern to a regexp pattern */
+ pat = file_pat_to_reg_pat(s, e, NULL, FALSE);
+ if (pat == NULL)
+ {
+ vim_free(buf);
+ return 0;
+ }
+
+ /* compile the regexp into a program */
+ regmatch.rm_ic = FALSE; /* Don't ever ignore case */
+ regmatch.regprog = vim_regcomp(pat, RE_MAGIC);
+ vim_free(pat);
+
+ if (regmatch.regprog == NULL)
+ {
+ vim_free(buf);
+ return 0;
+ }
+
+ /* open the directory for scanning */
+ c = *s;
+ *s = NUL;
+
+ if (*buf == NUL)
+ {
+ as_full = TRUE;
+#if 0
+ (void) mch_dirname (&dirname[1], 254);
+ dirname[0] = STRLEN(&dirname[1]);
+#endif
+ }
+ else
+ {
+ if (*buf == ':') /* relative path */
+ {
+ (void)mch_dirname(&dirname[1], 254);
+ new_name = concat_fnames(&dirname[1], buf+1, TRUE);
+ STRCPY(&dirname[1], new_name);
+ dirname[0] = STRLEN(new_name);
+ vim_free(new_name);
+ }
+ else
+ {
+ STRCPY(&dirname[1], buf);
+ backslash_halve(&dirname[1]);
+ dirname[0] = STRLEN(buf);
+ }
+ }
+ *s = c;
+
+ FSMakeFSSpec (0, 0, dirname, &usedDir);
+
+ gMyCPB.dirInfo.ioNamePtr = dirname;
+ gMyCPB.dirInfo.ioVRefNum = usedDir.vRefNum;
+ gMyCPB.dirInfo.ioFDirIndex = 0;
+ gMyCPB.dirInfo.ioDrDirID = 0;
+
+ gErr = PBGetCatInfo(&gMyCPB, false);
+
+ gMyCPB.dirInfo.ioCompletion = NULL;
+ dirID = gMyCPB.dirInfo.ioDrDirID;
+ do
+ {
+ gMyCPB.hFileInfo.ioFDirIndex = index;
+ gMyCPB.hFileInfo.ioDirID = dirID;
+
+ gErr = PBGetCatInfo(&gMyCPB,false);
+
+ if (gErr == noErr)
+ {
+ STRNCPY (cfilename, &dirname[1], dirname[0]);
+ cfilename[dirname[0]] = 0;
+ if (vim_regexec(&regmatch, cfilename, (colnr_T)0))
+ {
+ if (s[-1] != ':')
+ {
+ /* TODO: need to copy with cleaned name */
+ STRCPY(s+1, cfilename);
+ s[0] = ':';
+ }
+ else
+ { /* TODO: need to copy with cleeaned name */
+ STRCPY(s, cfilename);
+ }
+ start_at = STRLEN(buf);
+ STRCAT(buf, path);
+ if (mch_has_exp_wildcard(path)) /* handle more wildcards */
+ (void)mac_expandpath(gap, buf, flags, start_at, FALSE);
+ else
+ {
+#ifdef DONT_ADD_PATHSEP_TO_DIR
+ if ((gMyCPB.hFileInfo.ioFlAttrib & ioDirMask) !=0 )
+ STRCAT(buf, PATHSEPSTR);
+#endif
+ addfile(gap, buf, flags);
+ }
+ }
+ if ((gMyCPB.hFileInfo.ioFlAttrib & ioDirMask) !=0 )
+ {
+ }
+ else
+ {
+ }
+ }
+ index++;
+ }
+ while (gErr == noErr);
+
+ if (as_full)
+ {
+ index = 1;
+ do
+ {
+ gMyHPBlock.volumeParam.ioNamePtr = (char_u *) dirname;
+ gMyHPBlock.volumeParam.ioVRefNum =0;
+ gMyHPBlock.volumeParam.ioVolIndex = index;
+
+ gErr = PBHGetVInfo (&gMyHPBlock,false);
+ if (gErr == noErr)
+ {
+ STRNCPY (cfilename, &dirname[1], dirname[0]);
+ cfilename[dirname[0]] = 0;
+ if (vim_regexec(&regmatch, cfilename, (colnr_T)0))
+ {
+ STRCPY(s, cfilename);
+ STRCAT(buf, path);
+ if (mch_has_exp_wildcard(path)) /* handle more wildcards */
+ (void)mac_expandpath(gap, s, flags, 0, FALSE);
+ else
+ {
+#ifdef DONT_ADD_PATHSEP_TO_DIR
+/* if ((gMyCPB.hFileInfo.ioFlAttrib & ioDirMask) !=0 )
+*/ STRCAT(buf, PATHSEPSTR);
+#endif
+ addfile(gap, s, flags);
+ }
+#if 0
+ STRCAT(cfilename, PATHSEPSTR);
+ addfile (gap, cfilename, flags);
+#endif
+ }
+ }
+ index++;
+ }
+ while (gErr == noErr);
+ }
+
+ vim_free(regmatch.regprog);
+
+ return gap->ga_len - start_len;
+}
+
+
+#ifdef USE_UNIXFILENAME
+ static int
+pstrcmp(a, b)
+ const void *a, *b;
+{
+ return (pathcmp(*(char **)a, *(char **)b));
+}
+
+ static int
+unix_expandpath(gap, path, wildoff, flags)
+ garray_T *gap;
+ char_u *path;
+ int wildoff;
+ int flags; /* EW_* flags */
+{
+ char_u *buf;
+ char_u *path_end;
+ char_u *p, *s, *e;
+ int start_len, c;
+ char_u *pat;
+ DIR *dirp;
+ regmatch_T regmatch;
+ struct dirent *dp;
+ int starts_with_dot;
+ int matches;
+ int len;
+
+ start_len = gap->ga_len;
+ buf = alloc(STRLEN(path) + BASENAMELEN + 5);/* make room for file name */
+ if (buf == NULL)
+ return 0;
+
+/*
+ * Find the first part in the path name that contains a wildcard.
+ * Copy it into buf, including the preceding characters.
+ */
+ p = buf;
+ s = buf;
+ e = NULL;
+ path_end = path;
+ while (*path_end)
+ {
+ /* May ignore a wildcard that has a backslash before it */
+ if (path_end >= path + wildoff && rem_backslash(path_end))
+ *p++ = *path_end++;
+ else if (*path_end == '/')
+ {
+ if (e != NULL)
+ break;
+ else
+ s = p + 1;
+ }
+ else if (vim_strchr((char_u *)"*?[{~$", *path_end) != NULL)
+ e = p;
+#ifdef FEAT_MBYTE
+ if (has_mbyte)
+ {
+ len = (*mb_ptr2len_check)(path_end);
+ STRNCPY(p, path_end, len);
+ p += len;
+ path_end += len;
+ }
+ else
+#endif
+ *p++ = *path_end++;
+ }
+ e = p;
+ *e = NUL;
+
+ /* now we have one wildcard component between s and e */
+ /* Remove backslashes between "wildoff" and the start of the wildcard
+ * component. */
+ for (p = buf + wildoff; p < s; ++p)
+ if (rem_backslash(p))
+ {
+ STRCPY(p, p + 1);
+ --e;
+ --s;
+ }
+
+ /* convert the file pattern to a regexp pattern */
+ starts_with_dot = (*s == '.');
+ pat = file_pat_to_reg_pat(s, e, NULL, FALSE);
+ if (pat == NULL)
+ {
+ vim_free(buf);
+ return 0;
+ }
+
+ /* compile the regexp into a program */
+#ifdef MACOS_X
+ /* We want to behave like Terminal.app */
+ regmatch.rm_ic = TRUE;
+#else
+ regmatch.rm_ic = FALSE; /* Don't ever ignore case */
+#endif
+ regmatch.regprog = vim_regcomp(pat, RE_MAGIC);
+ vim_free(pat);
+
+ if (regmatch.regprog == NULL)
+ {
+ vim_free(buf);
+ return 0;
+ }
+
+ /* open the directory for scanning */
+ c = *s;
+ *s = NUL;
+ dirp = opendir(*buf == NUL ? "." : (char *)buf);
+ *s = c;
+
+ /* Find all matching entries */
+ if (dirp != NULL)
+ {
+ for (;;)
+ {
+ dp = readdir(dirp);
+ if (dp == NULL)
+ break;
+ if ((dp->d_name[0] != '.' || starts_with_dot)
+ && vim_regexec(&regmatch, (char_u *)dp->d_name, (colnr_T)0))
+ {
+ STRCPY(s, dp->d_name);
+ len = STRLEN(buf);
+ STRCPY(buf + len, path_end);
+ if (mch_has_exp_wildcard(path_end)) /* handle more wildcards */
+ {
+ /* need to expand another component of the path */
+ /* remove backslashes for the remaining components only */
+ (void)unix_expandpath(gap, buf, len + 1, flags);
+ }
+ else
+ {
+ /* no more wildcards, check if there is a match */
+ /* remove backslashes for the remaining components only */
+ if (*path_end)
+ backslash_halve(buf + len + 1);
+ if (mch_getperm(buf) >= 0) /* add existing file */
+ addfile(gap, buf, flags);
+ }
+ }
+ }
+
+ closedir(dirp);
+ }
+
+ vim_free(buf);
+ vim_free(regmatch.regprog);
+
+ matches = gap->ga_len - start_len;
+ if (matches)
+ qsort(((char_u **)gap->ga_data) + start_len, matches,
+ sizeof(char_u *), pstrcmp);
+ return matches;
+}
+#endif
+
+/*
+ * Recursively build up a list of files in "gap" matching the first wildcard
+ * in `path'. Called by expand_wildcards().
+ * "pat" has backslashes before chars that are not to be expanded.
+ */
+ int
+mch_expandpath(
+ garray_T *gap,
+ char_u *path,
+ int flags) /* EW_* flags */
+{
+#ifdef USE_UNIXFILENAME
+ return unix_expandpath(gap, path, 0, flags);
+#else
+ char_u first = *path;
+ short scan_volume;
+
+ slash_n_colon_adjust(path);
+
+ scan_volume = (first != *path);
+
+ return mac_expandpath(gap, path, flags, 0, scan_volume);
+#endif
+}
+
+ void
+fname_case(name, len)
+ char_u *name;
+ int len; /* buffer size, ignored here */
+{
+ /*
+ * TODO: get the real casing for the file
+ * make it called
+ * with USE_FNAME_CASE & USE_LONG_FNAME
+ * CASE_INSENSITIVE_FILENAME
+ * within setfname, fix_fname, do_ecmd
+ */
+#ifdef USE_UNIXFILENAME
+ OSStatus status;
+ FSRef refFile;
+ UInt32 pathSize = STRLEN(name) + 1;
+ char_u *path;
+ Boolean isDirectory;
+
+ path = alloc(pathSize);
+ if (path == NULL)
+ return;
+
+ status = FSPathMakeRef((UInt8 *)name, &refFile, &isDirectory);
+ if (status)
+ return;
+
+ status = FSRefMakePath(&refFile, (UInt8 *)path, pathSize);
+ if (status)
+ return;
+
+ /* Paranoid: Update the name if only the casing differ.*/
+ if (STRICMP(name, path) == 0)
+ STRCPY(name, path);
+#endif
+}
+static char_u *oldtitle = (char_u *) "gVim";
+
+/*
+ * check for an "interrupt signal": CTRL-break or CTRL-C
+ */
+ void
+mch_breakcheck()
+{
+ /*
+ * TODO: Scan event for a CTRL-C or COMMAND-. and do: got_int=TRUE;
+ * or only go proccess event?
+ * or do nothing
+ */
+ EventRecord theEvent;
+
+ if (EventAvail (keyDownMask, &theEvent))
+ if ((theEvent.message & charCodeMask) == Ctrl_C && ctrl_c_interrupts)
+ got_int = TRUE;
+#if 0
+ short i = 0;
+ Boolean found = false;
+ EventRecord theEvent;
+
+ while ((i < 10) && (!found))
+ {
+ found = EventAvail (keyDownMask, &theEvent);
+ if (found)
+ {
+ if ((theEvent.modifiers & controlKey) != 0)
+ found = false;
+ if ((theEvent.what == keyDown))
+ found = false;
+ if ((theEvent.message & charCodeMask) == Ctrl_C)
+ {
+ found = false;
+ got_int = TRUE;
+ }
+ }
+ i++;
+ }
+#endif
+
+}
+
+/*
+ * Return amount of memory currently available.
+ */
+ long_u
+mch_avail_mem(special)
+ int special;
+{
+ /*
+ * TODO: Use MaxBlock, FreeMeM, PurgeSpace, MaxBlockSys FAQ-266
+ * figure out what the special is for
+ *
+ * FreeMem -> returns all avail memory is application heap
+ * MaxBlock -> returns the biggest contigeous block in application heap
+ * PurgeSpace ->
+ */
+ return MaxBlock();
+}
+
+ void
+mch_delay(msec, ignoreinput)
+ long msec;
+ int ignoreinput;
+{
+#if (defined(__MWERKS__) && __MWERKS__ >= 0x2000) \
+ || defined(__MRC__) || defined(__SC__)
+ unsigned
+#endif
+ long finalTick;
+
+ if (ignoreinput)
+ Delay (60*msec/1000, &finalTick);
+ else
+ /* even thougth we should call gui stuff from here
+ it the simplest way to be safe */
+ gui_mch_wait_for_chars(msec);
+}
+
+ void
+mch_init()
+{
+ /*
+ * TODO: Verify if needed, or override later.
+ */
+ Columns = 80;
+ Rows = 24;
+}
+
+/*
+ * Check_win checks whether we have an interactive stdout.
+ */
+ int
+mch_check_win(argc, argv)
+ int argc;
+ char **argv;
+{
+ /*
+ * TODO: Maybe to be remove through NO_CONSOLE
+ */
+ return OK;
+}
+
+/*
+ * Return TRUE if the input comes from a terminal, FALSE otherwise.
+ */
+ int
+mch_input_isatty()
+{
+ /*
+ * TODO: Maybe to be remove through NO_CONSOLE
+ */
+ return OK;
+}
+
+#ifdef FEAT_TITLE
+/*
+ * Set the window title and icon.
+ * (The icon is not taken care of).
+ */
+ void
+mch_settitle(title, icon)
+ char_u *title;
+ char_u *icon;
+{
+ gui_mch_settitle(title, icon);
+}
+
+/*
+ * Restore the window/icon title.
+ * which is one of:
+ * 1 Just restore title
+ * 2 Just restore icon
+ * 3 Restore title and icon
+ * but don't care about the icon.
+ */
+ void
+mch_restore_title(which)
+ int which;
+{
+ mch_settitle((which & 1) ? oldtitle : NULL, NULL);
+}
+#endif
+
+/*
+ * Insert user name in s[len].
+ * Return OK if a name found.
+ */
+ int
+mch_get_user_name(s, len)
+ char_u *s;
+ int len;
+{
+#if !(defined(__MRC__) || defined(__SC__)) /* No solution yet */
+ /*
+ * TODO: clean up and try getlogin ()
+ */
+#if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID)
+ struct passwd *pw;
+#endif
+ uid_t uid;
+
+ uid = getuid();
+#if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID)
+ if ((pw = getpwuid(uid)) != NULL
+ && pw->pw_name != NULL && *(pw->pw_name) != NUL)
+ {
+ STRNCPY(s, pw->pw_name, len);
+ return OK;
+ }
+#endif
+ sprintf((char *)s, "%d", (int)uid); /* assumes s is long enough */
+#endif
+ return FAIL; /* a number is not a name */
+}
+
+/*
+ * Copy host name into s[len].
+ */
+ void
+mch_get_host_name(s, len)
+ char_u *s;
+ int len;
+{
+#if defined(__MRC__) || defined(__SC__) || defined(__APPLE_CC__)
+ STRNCPY(s, "Mac", len); /* TODO: use Gestalt information */
+#else
+ struct utsname vutsname;
+
+ if (uname(&vutsname) < 0)
+ *s = NUL;
+ else
+ STRNCPY(s, vutsname.nodename, len);
+#endif
+ s[len - 1] = NUL; /* make sure it's terminated */
+}
+
+/*
+ * return process ID
+ */
+ long
+mch_get_pid()
+{
+ return (long)getpid();
+}
+
+/*
+ * Get name of current directory into buffer 'buf' of length 'len' bytes.
+ * Return OK for success, FAIL for failure.
+ */
+ int
+mch_dirname(buf, len)
+ char_u *buf;
+ int len;
+{
+#if defined(__MRC__) || defined(__SC__)
+ return FAIL; /* No solution yet */
+#else
+ /* The last : is already put by getcwd */
+ if (getcwd((char *)buf, len) == NULL)
+ {
+ STRCPY(buf, strerror(errno));
+ return FAIL;
+ }
+# ifndef USE_UNIXFILENAME
+ else if (*buf != NUL && buf[STRLEN(buf) - 1] == ':')
+ buf[STRLEN(buf) - 1] = NUL; /* remove trailing ':' */
+# endif
+ return OK;
+#endif
+}
+
+ void
+slash_to_colon(p)
+ char_u *p;
+{
+ for ( ; *p; ++p)
+ if (*p == '/')
+ *p = ':';
+}
+
+ char_u *
+slash_to_colon_save (p)
+ char_u *p;
+{
+ char_u *res;
+
+ res = vim_strsave(p);
+ if (res == NULL)
+ return p;
+ slash_to_colon(res);
+ return res;
+}
+
+ void
+slash_n_colon_adjust (buf)
+ char_u *buf;
+{
+ /*
+ * TODO: Make it faster
+ */
+#ifndef USE_UNIXFILENAME
+ char_u temp[MAXPATHL];
+ char_u *first_colon = vim_strchr(buf, ':');
+ char_u *first_slash = vim_strchr(buf, '/');
+ int full = TRUE;
+ char_u *scanning;
+ char_u *filling;
+ char_u last_copied = NUL;
+
+ if (*buf == NUL)
+ return ;
+
+ if ((first_colon == NULL) && (first_slash == NULL))
+ full = FALSE;
+ if ((first_slash == NULL) && (first_colon != NULL))
+ full = TRUE;
+ if ((first_colon == NULL) && (first_slash != NULL))
+ full = FALSE;
+ if ((first_slash < first_colon) && (first_slash != NULL))
+ full = FALSE;
+ if ((first_colon < first_slash) && (first_colon != NULL))
+ full = TRUE;
+ if (first_slash == buf)
+ full = TRUE;
+ if (first_colon == buf)
+ full = FALSE;
+
+ scanning = buf;
+ filling = temp;
+
+ while (*scanning != NUL)
+ {
+ if (*scanning == '/')
+ {
+ if ((scanning[1] != '/') && (scanning[-1] != ':'))
+ {
+ *filling++ = ':';
+ scanning++;
+ }
+ else
+ scanning++;
+ }
+ else if (*scanning == '.')
+ {
+ if ((scanning[1] == NUL) || scanning[1] == '/')
+ {
+ if (scanning[1] == NUL)
+ scanning += 1;
+ else
+ scanning += 2;
+ }
+ else if (scanning[1] == '.')
+ {
+ if ((scanning[2] == NUL) || scanning[2] == '/')
+ {
+ *filling++ = ':';
+ if (scanning[2] == NUL)
+ scanning +=2;
+ else
+ scanning += 3;
+ }
+ else
+ {
+ *filling++ = *scanning++;
+ }
+ }
+ else
+ {
+ *filling++ = *scanning++;
+ }
+
+ }
+ else
+ {
+ *filling++ = *scanning++;
+ }
+
+ }
+
+ *filling = 0;
+ filling = temp;
+
+ if (!full)
+ {
+ if (buf[0] != ':')
+ {
+ buf[0] = ':';
+ buf[1] = NUL;
+ }
+ else
+ buf[0] = NUL;
+ }
+ else
+ {
+ buf[0] = NUL;
+ if (filling[0] == ':')
+ filling++;
+ }
+
+ STRCAT (buf, filling);
+#endif
+}
+
+/*
+ * Get absolute filename into buffer 'buf' of length 'len' bytes.
+ *
+ * return FAIL for failure, OK for success
+ */
+ int
+mch_FullName(fname, buf, len, force)
+ char_u *fname, *buf;
+ int len;
+ int force; /* also expand when already absolute path name */
+{
+ /*
+ * TODO: Find what TODO
+ */
+ int l;
+ char_u olddir[MAXPATHL];
+ char_u newdir[MAXPATHL];
+ char_u *p;
+ char_u c;
+ int retval = OK;
+
+ if (force || !mch_isFullName(fname))
+ {
+ /*
+ * Forced or not an absolute path.
+ * If the file name has a path, change to that directory for a moment,
+ * and then do the getwd() (and get back to where we were).
+ * This will get the correct path name with "../" things.
+ */
+ if ((p = vim_strrchr(fname, ':')) != NULL)
+ {
+ p++;
+ if (mch_dirname(olddir, MAXPATHL) == FAIL)
+ {
+ p = NULL; /* can't get current dir: don't chdir */
+ retval = FAIL;
+ }
+ else
+ {
+ c = *p;
+ *p = NUL;
+ if (mch_chdir((char *)fname))
+ retval = FAIL;
+ else
+ fname = p; /* + 1;*/
+ *p = c;
+ }
+ }
+ if (mch_dirname(buf, len) == FAIL)
+ {
+ retval = FAIL;
+ *newdir = NUL;
+ }
+ l = STRLEN(buf);
+ if (STRCMP(fname, ".") != 0)
+ {
+#ifdef USE_UNIXFILENAME
+ if (l > 0 && buf[l - 1] != '/' && *fname != NUL)
+ STRCAT(buf, "/");
+#else
+ if (l > 0 && buf[l - 1] != ':' && *fname != NUL)
+ STRCAT(buf, ":");
+#endif
+ }
+ if (p != NULL)
+ mch_chdir((char *)olddir);
+ if (STRCMP(fname, ".") != 0)
+ STRCAT(buf, fname);
+ }
+ else
+ {
+ STRNCPY(buf, fname, len);
+ buf[len - 1] = NUL;
+ slash_n_colon_adjust(buf);
+ }
+
+ return retval;
+}
+
+/*
+ * Return TRUE if "fname" does not depend on the current directory.
+ */
+ int
+mch_isFullName(fname)
+ char_u *fname;
+{
+#ifdef USE_UNIXFILENAME
+ return ((fname[0] == '/') || (fname[0] == '~'));
+#else
+ /*
+ * TODO: Make sure fname is always of mac still
+ * i.e: passed throught slash_n_colon_adjust
+ */
+ char_u *first_colon = vim_strchr(fname, ':');
+ char_u *first_slash = vim_strchr(fname, '/');
+
+ if (first_colon == fname)
+ return FALSE;
+ if (first_slash == fname)
+ return TRUE;
+ if ((first_colon < first_slash) && (first_colon != NULL))
+ return TRUE;
+ if ((first_slash < first_colon) && (first_slash != NULL))
+ return FALSE;
+ if ((first_colon == NULL) && (first_slash != NULL))
+ return FALSE;
+ if ((first_slash == NULL) && (first_colon != NULL))
+ return TRUE;
+ if ((first_colon == NULL) && (first_slash == NULL))
+ return FALSE;
+ return TRUE;
+#endif
+}
+
+/*
+ * Replace all slashes by colons.
+ */
+ void
+slash_adjust(p)
+ char_u *p;
+{
+#ifndef USE_UNIXFILENAME
+ /*
+ * TODO: keep escaped '/'
+ */
+
+ while (*p)
+ {
+ if (*p == '/')
+ *p = ':';
+#ifdef FEAT_MBYTE
+ if (has_mbyte)
+ p += (*mb_ptr2len_check)(p);
+ else
+#endif
+ ++p;
+ }
+#endif
+}
+
+/*
+ * Get file permissions for 'name'.
+ * Returns -1 when it doesn't exist.
+ */
+ long
+mch_getperm(name)
+ char_u *name;
+{
+ /*
+ * TODO: Maybe use AppleShare info??
+ * Use locked for non writable
+ */
+
+ struct stat statb;
+
+ if (stat((char *)name, &statb))
+ return -1;
+ return statb.st_mode;
+}
+
+/*
+ * set file permission for 'name' to 'perm'
+ *
+ * return FAIL for failure, OK otherwise
+ */
+ int
+mch_setperm(name, perm)
+ char_u *name;
+ long perm;
+{
+ /*
+ * TODO: Maybe use AppleShare info??
+ * Use locked for non writable
+ */
+ return (OK);
+}
+
+/*
+ * Set hidden flag for "name".
+ */
+ void
+mch_hide(name)
+ char_u *name;
+{
+ /*
+ * TODO: Hide the file throught FileManager FAQ 8-34
+ *
+ * *name is mac style start with : for relative
+ */
+}
+
+
+/*
+ * return TRUE if "name" is a directory
+ * return FALSE if "name" is not a directory
+ * return FALSE for error
+ */
+ int
+mch_isdir(name)
+ char_u *name;
+{
+ /*
+ * TODO: Find out by FileManager calls ...
+ */
+ struct stat statb;
+
+#if defined(TARGET_API_MAC_CARBON) && TARGET_API_MAC_CARBON
+ /* For some reason the name is sometimes empty,
+ * (such as for a not yet named file). An empty
+ * filename is interpreted by the MacOS version
+ * of stat (at least under Codewarrior) as the
+ * current directory.
+ */
+ /* AK 20020413
+ * This is required for Carbon but breaks the
+ * explorer plugin in Classic
+ */
+ if (name[0] == NULL)
+ return FALSE;
+#endif
+
+ if (stat((char *)name, &statb))
+ return FALSE;
+#if defined(__MRC__) || defined(__SC__)
+ return FALSE; /* definitely TODO */
+#else
+ return ((statb.st_mode & S_IFMT) == S_IFDIR ? TRUE : FALSE);
+#endif
+}
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * Return 1 if "name" can be executed, 0 if not.
+ * Return -1 if unknown.
+ */
+ int
+mch_can_exe(name)
+ char_u *name;
+{
+ /* TODO */
+ return -1;
+}
+#endif
+
+/*
+ * Check what "name" is:
+ * NODE_NORMAL: file or directory (or doesn't exist)
+ * NODE_WRITABLE: writable device, socket, fifo, etc.
+ * NODE_OTHER: non-writable things
+ */
+ int
+mch_nodetype(name)
+ char_u *name;
+{
+ /* TODO */
+ return NODE_NORMAL;
+}
+
+ void
+mch_early_init()
+{
+}
+
+ void
+mch_exit(r)
+ int r;
+{
+ display_errors();
+
+ ml_close_all(TRUE); /* remove all memfiles */
+ exit(r);
+}
+
+
+ void
+mch_settmode(tmode)
+ int tmode;
+{
+ /*
+ * TODO: remove the needs of it.
+ */
+}
+
+#ifdef FEAT_MOUSE
+/*
+ * set mouse clicks on or off (only works for xterms)
+ */
+ void
+mch_setmouse(on)
+ int on;
+{
+ /*
+ * TODO: remove the needs of it.
+ */
+}
+#endif
+
+/*
+ * set screen mode, always fails.
+ */
+ int
+mch_screenmode(arg)
+ char_u *arg;
+{
+ EMSG(_(e_screenmode));
+ return FAIL;
+}
+
+ int
+mch_call_shell(cmd, options)
+ char_u *cmd;
+ int options; /* SHELL_*, see vim.h */
+{
+ /*
+ * TODO: find a shell or pseudo-shell to call
+ * for some simple useful command
+ */
+
+ return (-1);
+}
+
+/*
+ * Return TRUE if "p" contains a wildcard that can be expanded by
+ * mch_expandpath().
+ */
+ int
+mch_has_exp_wildcard(p)
+ char_u *p;
+{
+ for ( ; *p; ++p)
+ {
+ if (*p == '\\' && p[1] != NUL)
+ ++p;
+ else if (vim_strchr((char_u *)WILDCHAR_LIST, *p) != NULL)
+ return TRUE;
+#ifdef FEAT_MBYTE
+ if (has_mbyte)
+ p += (*mb_ptr2len_check)(p) - 1;
+#endif
+ }
+ return FALSE;
+}
+
+ int
+mch_has_wildcard(p)
+ char_u *p;
+{
+#ifdef USE_UNIXFILENAME
+ if (*p == '~' && p[1] != NUL)
+ return TRUE;
+#endif
+ return mch_has_exp_wildcard(p);
+}
+
+
+/*
+ * This procedure duplicate a file, it is used in order to keep
+ * the footprint of the previous file, when some info can be easily
+ * restored with set_perm().
+ *
+ * Return -1 for failure, 0 for success.
+ */
+ int
+mch_copy_file(from, to)
+ char_u *from;
+ char_u *to;
+{
+ char_u from_str[256];
+ char_u to_str[256];
+ char_u to_name[256];
+
+ HParamBlockRec paramBlock;
+ char_u *char_ptr;
+ int len;
+
+ /*
+ * Convert C string to Pascal string
+ */
+ char_ptr = from;
+ len = 1;
+ for (; (*char_ptr != 0) && (len < 255); len++, char_ptr++)
+ from_str[len] = *char_ptr;
+ from_str[0] = len-1;
+
+ char_ptr = to;
+ len = 1;
+ for (; (*char_ptr != 0) && (len < 255); len++, char_ptr++)
+ to_str[len] = *char_ptr;
+ to_str[0] = len-1;
+
+ paramBlock.copyParam.ioCompletion = NULL;
+ paramBlock.copyParam.ioNamePtr = from_str;
+ /* paramBlock.copyParam.ioVRefnum = overided by ioFilename; */
+ /* paramBlock.copyParam.ioDirI = overided by ioFilename; */
+
+ paramBlock.copyParam.ioNewName = to_str;
+ paramBlock.copyParam.ioCopyName = to_name; /* NIL */
+ /* paramBlock.copyParam.ioDstVRefNum = overided by ioNewName; */
+ /* paramBlock.copyParam.ioNewDirID = overided by ioNewName; */
+
+
+
+ /*
+ * First delete the "to" file, this is required on some systems to make
+ * the rename() work, on other systems it makes sure that we don't have
+ * two files when the rename() fails.
+ */
+ mch_remove(to);
+
+ /*
+ * First try a normal rename, return if it works.
+ */
+ (void) PBHCopyFile(&paramBlock, false);
+ return 0;
+
+}
+
+
+ int
+mch_copy_file_attribute(from, to)
+ char_u *from;
+ char_u *to;
+{
+ FSSpec frFSSpec;
+ FSSpec toFSSpec;
+ FInfo fndrInfo;
+ Str255 name;
+ ResType type;
+ ResType sink;
+ Handle resource;
+ short idxTypes;
+ short nbTypes;
+ short idxResources;
+ short nbResources;
+ short ID;
+ short frRFid;
+ short toRFid;
+ short attrs_orig;
+ short attrs_copy;
+ short temp;
+
+ /* TODO: Handle error */
+ (void) GetFSSpecFromPath (from, &frFSSpec);
+ (void) GetFSSpecFromPath (to , &toFSSpec);
+
+ /* Copy resource fork */
+ temp = 0;
+
+#if 1
+ frRFid = FSpOpenResFile (&frFSSpec, fsCurPerm);
+
+ if (frRFid != -1)
+ {
+ FSpCreateResFile(&toFSSpec, 'TEXT', UNKNOWN_CREATOR, 0);
+ toRFid = FSpOpenResFile (&toFSSpec, fsRdWrPerm);
+
+ UseResFile (frRFid);
+
+ nbTypes = Count1Types();
+
+ for (idxTypes = 1; idxTypes <= nbTypes; idxTypes++)
+ {
+ Get1IndType (&type, idxTypes);
+ nbResources = Count1Resources(type);
+
+ for (idxResources = 1; idxResources <= nbResources; idxResources++)
+ {
+ attrs_orig = 0; /* in case GetRes fails */
+ attrs_copy = 0; /* in case GetRes fails */
+ resource = Get1IndResource(type, idxResources);
+ GetResInfo (resource, &ID, &sink, name);
+ HLock (resource);
+ attrs_orig = GetResAttrs (resource);
+ DetachResource (resource);
+
+
+ UseResFile (toRFid);
+ AddResource (resource, type, ID, name);
+ attrs_copy = GetResAttrs (resource);
+ attrs_copy = (attrs_copy & 0x2) | (attrs_orig & 0xFD);
+ SetResAttrs (resource, attrs_copy);
+ WriteResource (resource);
+ UpdateResFile (toRFid);
+
+ temp = GetResAttrs (resource);
+
+ /*SetResAttrs (resource, 0);*/
+ HUnlock(resource);
+ ReleaseResource (resource);
+ UseResFile (frRFid);
+ }
+ }
+ CloseResFile (toRFid);
+ CloseResFile (frRFid);
+ }
+#endif
+ /* Copy Finder Info */
+ (void) FSpGetFInfo (&frFSSpec, &fndrInfo);
+ (void) FSpSetFInfo (&toFSSpec, &fndrInfo);
+
+ return (temp == attrs_copy);
+}
+
+ int
+mch_has_resource_fork (file)
+ char_u *file;
+{
+ FSSpec fileFSSpec;
+ short fileRFid;
+
+ /* TODO: Handle error */
+ (void) GetFSSpecFromPath (file, &fileFSSpec);
+ fileRFid = FSpOpenResFile (&fileFSSpec, fsCurPerm);
+ if (fileRFid != -1)
+ CloseResFile (fileRFid);
+
+ return (fileRFid != -1);
+}
+
+ int
+mch_get_shellsize(void)
+{
+ /* never used */
+ return OK;
+}
+
+ void
+mch_set_shellsize(void)
+{
+ /* never used */
+}
+
+/*
+ * Rows and/or Columns has changed.
+ */
+ void
+mch_new_shellsize(void)
+{
+ /* never used */
+}
+
+/*
+ * Those function were set as #define before, but in order
+ * to allow an easier us of os_unix.c for the MacOS X port,
+ * they are change to procedure. Thec ompile whould optimize
+ * them out.
+ */
+
+ int
+mch_can_restore_title()
+{
+ return TRUE;
+}
+
+ int
+mch_can_restore_icon()
+{
+ return TRUE;
+}
+
+/*
+ * If the machine has job control, use it to suspend the program,
+ * otherwise fake it by starting a new shell.
+ */
+ void
+mch_suspend()
+{
+ /* TODO: get calle in #ifndef NO_CONSOLE */
+ gui_mch_iconify();
+};
+