/* * Operating system library generic utilities. * */ #include "OSLib.h" #include #include #include #if __MWERKS__ && !__INTEL__ #include #else #include #endif #include #include #include char STSbuf[OS_PATHSIZE]; /* perform wildcard matching on a path; if path is non-NULL, start a search else continue searching; return NULL if no match found */ static OSSpec wildmatch; static OSDirRef wilddirref; static char wilddir[OS_MAXPATHLEN]; static char wildname[OS_MAXNAMELEN]; #if defined(OS_IS_CASE_INSENSITIVE) #define EQU(x,y) (tolower(x)==tolower(y)) #else #define EQU(x,y) ((x)==(y)) #endif /* Simple wildcard matcher. Fails if '*' is not followed by a character or EOS. */ static int WildCardMatch(const char *wild, const char *name) { if (*name == 0) return 0; while (*wild) { if (*wild == '*') { const char next = *++wild; const char *prev = NULL; while (*name) { if (EQU(*name, next)) prev = name; name++; } if (prev != NULL) name = prev; if (!EQU(*name, next)) /* allows matching next==0 */ return 0; } else if (*wild == '?' && *name) { ++wild; ++name; if (!*wild && *name) return 0; } else if (EQU(*wild, *name)) { ++wild; ++name; } else return 0; } return *name == 0 || (*name == OS_PATHSEP && *(name + 1) == 0); } /* This routine matches a patch with a wildcard at the end. It fails if the wildcard is in the directory part. Only matches files, not directories. */ OSSpec * OS_MatchPath(const char *path) { OSError err; char filename[OS_NAMESIZE]; bool isfile; if (path != NULL) { OSSpec spec; const char *nptr; /* Note: this fails in WinNT if the wildcard characters are present in path. We need to break the path at the wildcard and match from there on. */ nptr = strrchr(path, OS_PATHSEP); if (nptr == NULL) { nptr = path; strcpyn(wilddir, OS_CWDSTR, -1, OS_PATHSIZE); } else { nptr++; strcpyn(wilddir, path, nptr - path, OS_PATHSIZE); } err = OS_MakePathSpec(NULL, wilddir, &spec.path); if (err != OS_NOERR) return NULL; strcpyn(wildname, nptr, -1, OS_NAMESIZE); if ((err = OS_MakeNameSpec(wildname, &spec.name)) != OS_NOERR) return NULL; if ((err = OS_OpenDir(&spec.path, &wilddirref)) != OS_NOERR) return NULL; } while ((err = OS_ReadDir(&wilddirref, &wildmatch, filename, &isfile)) == OS_NOERR) { /* This inherently matches only filenames. */ if (isfile && WildCardMatch(wildname, filename)) return &wildmatch; } OS_CloseDir(&wilddirref); return NULL; } /* Return pointer to filename part of path */ const char * OS_GetFileNamePtr(const char *path) { const char *ptr = strrchr(path, OS_PATHSEP); if (ptr == NULL) ptr = path; else ptr++; return ptr; } /* make OSSpec from a path and filename */ OSError OS_MakeSpec2(const char *path, const char *filename, OSSpec * spec) { char bpath[OS_PATHSIZE], *eptr; int pthlen, fnlen; if (path == NULL) path = ""; if (filename == NULL) filename = ""; fnlen = strlen(filename); pthlen = strlen(path); if (fnlen + pthlen + 1 > OS_MAXPATHLEN) // 1 for OS_PATHSEP return OS_FNTLERR; strncpy(bpath, path, pthlen); eptr = bpath + pthlen; if (*(eptr - 1) != OS_PATHSEP) *eptr++ = OS_PATHSEP; strcpy(eptr, filename); return OS_MakeSpec(bpath, spec, NULL); } /* make OSSpec given an OSPathSpec (which may be NULL) and filename, relative path, or full path (which may be NULL); if 'noRelative' and filename is relative, or if filename is a full path, ignore 'path'. */ OSError OS_MakeSpecWithPath(const OSPathSpec * path, const char *filename, bool noRelative, OSSpec * spec) { if (filename == NULL) { if (path) spec->path = *path; else OS_GetCWD(&spec->path); return OS_MakeNameSpec("", &spec->name); } else if ((!noRelative || strpbrk(filename, "/\\:") == NULL) && !OS_IsFullPath(filename)) { char buf[OS_PATHSIZE]; char *mptr, *eptr; if (path) OS_PathSpecToString2(path, buf); else *buf = 0; #warning bugfix mptr = buf + OS_PATHSIZE - strlen(filename) - 1; eptr = buf + strlen(buf); if (eptr > mptr) strcpy(mptr, filename); else strcpy(eptr, filename); return OS_MakeSpec(buf, spec, NULL); } else return OS_MakeSpec(filename, spec, NULL); } /* change extension of a name */ OSError OS_NameSpecChangeExtension(OSNameSpec * spec, char *ext, bool append) { char tmp[OS_NAMESIZE]; char *per; OS_NameSpecToString2(spec, tmp); if (!append) { per = strrchr(tmp, '.'); if (per == NULL) per = tmp + strlen(tmp); } else per = tmp + strlen(tmp); if (strlen(tmp) + strlen(ext) > OS_NAMESIZE) per = tmp + OS_NAMESIZE - strlen(ext) - 1; strcpy(per, ext); return OS_MakeNameSpec(tmp, spec); } /* set the extension of a name; if ext begins with '.', append the extension, else replace it */ OSError OS_NameSpecSetExtension(OSNameSpec * spec, char *ext) { char tmp[OS_NAMESIZE]; char *per; OS_NameSpecToString2(spec, tmp); if (*ext != '.') { per = strrchr(tmp, '.'); if (per == NULL) per = tmp + strlen(tmp); if (*ext) // allow deleting extension if (strlen(tmp) + 1 >= OS_NAMESIZE) *(per - 1) = '.'; else *per++ = '.'; } else { per = tmp + strlen(tmp); } if (strlen(tmp) + strlen(ext) > OS_NAMESIZE) per = tmp + OS_NAMESIZE - strlen(ext) - 1; strcpy(per, ext); return OS_MakeNameSpec(tmp, spec); } /* This silly routine shortens an overlong concatenation by inserting "..." in the middle of the string. */ char * OS_CompactPaths(char *buf, const char *p, const char *n, int size) { int plen = p ? strlen(p) : 0; int nlen = n ? strlen(n) : 0; if (plen + nlen + 1 <= size) { sprintf(buf, "%s%s", p ? p : "", n ? n : ""); return buf; } else { char *ptr = buf; int bidx = 0; int pnidx = 0; int diff = (plen + nlen) - (size); while (plen > 0 && nlen > 0) { if (plen > 0) { *ptr++ = *p++; plen--; } else if (nlen > 0) { *ptr++ = *n++; nlen--; } bidx++; if (bidx == size / 2 - 2) { *ptr++ = '.'; *ptr++ = '.'; *ptr++ = '.'; bidx += 3; if (plen > 0) { plen -= diff / 2; if (plen < 0) { n -= plen; nlen += plen; plen = 0; } } else { n += diff / 2; nlen -= diff / 2; } } } *ptr = 0; return buf; } } char * OS_SpecToStringRelative(const OSSpec * spec, const OSPathSpec * cwdspec, char *path, int size) { char fullbuf[OS_PATHSIZE], *full = fullbuf; char cwdbuf[OS_PATHSIZE], *cwd = cwdbuf; OSPathSpec mycwdspec; OS_SpecToString(spec, fullbuf, OS_PATHSIZE); if (size == 0) size = OS_PATHSIZE; if (path == NULL && (path = (char *) malloc(size)) == NULL) return NULL; if (cwdspec == NULL) { OS_GetCWD(&mycwdspec); cwdspec = &mycwdspec; } if (OS_PathSpecToString(cwdspec, cwdbuf, OS_PATHSIZE) == NULL) { memcpy(path, fullbuf, size - 1); path[size - 1] = 0; return path; } /* find longest common prefix of full and cwd */ while (*cwd && EQU(*full, *cwd)) { full++; cwd++; } /* if prefix is less than a third the length of the fullpath, abort */ if (cwd - cwdbuf < strlen(fullbuf) / 2 && strlen(cwd) > strlen(fullbuf) / 2) { memcpy(path, fullbuf, size - 1); path[size - 1] = 0; return path; } /* backtrack, if necessary, up to previous OS_PATHSEP [don't match foo with fool] */ #if !defined(OS_REL_PATH_HAS_SEP) while (cwd > cwdbuf) { full--; cwd--; if (*cwd == OS_PATHSEP) break; } #else while (cwd > cwdbuf) { if (*(cwd - 1) == OS_PATHSEP) break; full--; cwd--; } #endif /* complete mismatch --> out */ if (cwd == cwdbuf) { strncpy(path, full, size - 1); path[size - 1] = 0; } else { #if !defined(OS_REL_PATH_HAS_SEP) /* skip OS_PATHSEP (relative dirs don't have 'em) */ cwd++; full++; #endif /* if cwd has more than full, need OS_PDSTR's and the rest of full... */ if (*cwd) { char *pptr = path; while (*cwd) { #if defined(OS_REL_PATH_HAS_SEP) cwd++; if (*cwd == OS_PATHSEP) pptr += sprintf(pptr, OS_PDSTR); #else if (*cwd == OS_PATHSEP) pptr += sprintf(pptr, OS_PDSTR); cwd++; #endif } strcpy(pptr, full); } /* if cwd has less, then use the part of full that doesn't match */ else { strncpy(path, full, size - 1); path[size - 1] = 0; } } return path; } /* Search for a file in a list; if not found, returns error and creates OSSpec in first directory in plist. */ OSError OS_FindFileInPath(const char *filename, const char *plist, OSSpec * spec) { const char *next; char path[OS_PATHSIZE]; OSError err; OSSpec first; bool madefirst = false; while (plist && *plist) { next = strchr(plist, OS_ENVSEP); if (next == NULL) next = strpbrk(plist, OS_ENVSEPLIST); if (next == NULL) next = plist + strlen(plist); strcpyn(path, plist, next - plist, OS_MAXPATHLEN); // printf("searching '%s' for '%s'\n",path,filename); if ((err = OS_MakeSpec2(path, filename, spec)) == OS_NOERR) { err = OS_FIDERR; if (*filename && (err = OS_Status(spec)) == OS_NOERR) return OS_NOERR; if (!madefirst) { // printf("%s\n", OS_SpecToString1(spec)); first = *spec; // use this if all else fails madefirst = true; } } plist = (*next) ? next + 1 : NULL; } if (madefirst) *spec = first; return err; } /* Search for a place to create file in a list; if not possible, returns error */ OSError OS_CreateFileInPath(const char *filename, const char *plist, OSSpec * spec, OSFileType *type) { const char *next; char path[OS_PATHSIZE]; OSError err; while (plist && *plist) { next = strchr(plist, OS_ENVSEP); if (next == NULL) next = strpbrk(plist, OS_ENVSEPLIST); if (next == NULL) next = plist + strlen(plist); strcpyn(path, plist, next - plist, OS_MAXPATHLEN); if ((err = OS_MakeSpec2(path, filename, spec)) == OS_NOERR) { if ((err = OS_Create(spec, type)) == OS_NOERR) return OS_NOERR; } plist = (*next) ? next + 1 : NULL; } return err; } /* Search for an executable using the OS standards; if relative path or not found, make spec in CWD */ //#define SRCH_DEBUG 1 OSError OS_FindProgram(const char *filename, OSSpec * spec) { char *plist; OSError err; char temp[OS_PATHSIZE]; strncpy(temp, filename, OS_PATHSIZE); temp[OS_PATHSIZE - 1] = 0; #if defined(WIN32_FS) if (strlen(temp) < 4 || strcasecmp(temp + strlen(temp) - 4, ".exe") != 0) strcatn(temp, ".exe", OS_PATHSIZE); #endif #if SRCH_DEBUG printf("Searching for '%s'\n", temp); #endif if (strchr(temp, OS_PATHSEP) == NULL) { /* Windows wants us to search its directories first. */ #if defined(WIN32_FS) { char path[OS_PATHSIZE]; int len; extern __declspec(dllimport) __stdcall int GetSystemDirectoryA(char *path, int size); extern __declspec(dllimport) __stdcall int GetWindowsDirectoryA(char *path, int size); len = GetSystemDirectoryA(path, OS_PATHSIZE); if (len != 0) { #if SRCH_DEBUG printf("Searching Windows system directory '%s' for '%s'\n", path, temp); #endif if ((err = OS_MakeSpec2(path, temp, spec)) == OS_NOERR) { err = OS_Status(spec); if (err != OS_NOERR) { #if SRCH_DEBUG printf("Not found at '%s', error '%s'\n", OS_SpecToString1(spec), OS_GetErrText(err)); #endif } else { #if SRCH_DEBUG printf("Found '%s' at '%s'\n", temp, OS_SpecToString1(spec)); #endif return err; } } } len = GetWindowsDirectoryA(path, OS_PATHSIZE); if (len != 0) { #if SRCH_DEBUG printf("Searching Windows directory '%s' for '%s'\n", path, temp); #endif if ((err = OS_MakeSpec2(path, temp, spec)) == OS_NOERR) { err = OS_Status(spec); if (err != OS_NOERR) { #if SRCH_DEBUG printf("Not found at '%s', error '%s'\n", OS_SpecToString1(spec), OS_GetErrText(err)); #endif } else { #if SRCH_DEBUG printf("Found '%s' at '%s'\n", temp, OS_SpecToString1(spec)); #endif return err; } } } } #endif #if defined(POSIX_FS) || defined(WIN32_FS) plist = getenv("PATH"); #elif defined(MAC_FS) plist = getenv("Commands"); #else #error #endif #if SRCH_DEBUG printf("Searching path '%s' for '%s'\n", plist, temp); #endif err = OS_FindFileInPath(temp, plist, spec); if (err == OS_NOERR) { #if SRCH_DEBUG printf("Found '%s' at '%s'\n", temp, OS_SpecToString1(spec)); #endif return OS_NOERR; } } /* Default to CWD */ #if SRCH_DEBUG printf("Using '%s'\n", temp); #endif if ((err = OS_MakeFileSpec(temp, spec)) == OS_NOERR) err = OS_Status(spec); #if SRCH_DEBUG if (err != OS_NOERR) { printf("Not found at '%s', error '%s'\n", temp, OS_GetErrText(err)); } #endif return err; } /****************************************/ /* Handle routines. */ /* Copy a handle. */ OSError OS_CopyHandle(OSHandle * hand, OSHandle * copy) { OSError err; OSSize sz; void *f, *t; if ((err = OS_GetHandleSize(hand, &sz)) == OS_NOERR && (err = OS_NewHandle(sz, copy)) == OS_NOERR) { f = OS_LockHandle(hand); t = OS_LockHandle(copy); memcpy(t, f, sz); OS_UnlockHandle(hand); OS_UnlockHandle(copy); return OS_NOERR; } else { OS_FreeHandle(copy); return err; } } /* Append data to a handle. */ OSError OS_AppendHandle(OSHandle * hand, void *data, OSSize len) { OSError err; OSSize sz; void *buffer; if ((err = OS_GetHandleSize(hand, &sz)) == OS_NOERR && (err = OS_ResizeHandle(hand, sz + len)) == OS_NOERR && (buffer = OS_LockHandle(hand)) != NULL) { memcpy((char *) buffer + sz, data, len); OS_UnlockHandle(hand); return OS_NOERR; } else return err; }