18static char SccsId[] =
"%W% %G%";
37static Term do_glob(
const char *spec,
bool glob_vs_wordexp);
38static const char *PlExpandVars(
const char *
source,
const char *root);
40static Term gethdir(Term t) {
43 Atom aref = AtomOfTerm(t);
44 char *s = RepAtom(aref)->StrOfAE;
48 s = strncpy(buf, RepAtom(aref)->StrOfAE, PATH_MAX - 1);
54 MkAtomTerm(Yap_LookupAtom(Yap_getcwd(buf,
58 if (!Yap_dir_separator(s[nsz - 1])) {
66 return MkAtomTerm(Yap_LookupAtom(s));
69static Term issolutions(Term t) {
70 if (t == TermFirst || t == TermAll)
74 Yap_Error(INSTANTIATION_ERROR, t,
"solutions in {first, all}.");
78 Yap_Error(DOMAIN_ERROR_SOLUTIONS, t,
"solutions in {first, all}");
81 Yap_Error(TYPE_ERROR_ATOM, t,
"solutions in {first, all}}");
85static Term is_file_errors(Term t) {
86 if (t == TermFail || t == TermError)
90 Yap_Error(INSTANTIATION_ERROR, t,
"file_error in {fail,error}.");
94 Yap_Error(DOMAIN_ERROR_FILE_ERRORS, t,
"file_error in {fail,error}.");
97 Yap_Error(TYPE_ERROR_ATOM, t,
"file_error in {fail,error}.");
102static Term is_file_type(Term t) {
103 if (t == TermTxt || t == TermProlog || t == TermSource ||
104 t == TermExecutable || t == TermQly || t == TermDirectory)
108 Yap_Error(INSTANTIATION_ERROR, t,
109 "file_type in {txt,prolog,exe,directory...}");
113 Yap_Error(DOMAIN_ERROR_FILE_TYPE, t,
114 "file_type in {txt,prolog,exe,directory...}");
117 Yap_Error(TYPE_ERROR_ATOM, t,
"file_type in {txt,prolog,exe,directory...}");
122 static const char *myrealpath(
const char *path USES_REGS) {
123 int lvl = push_text_stack();
124 char *o =
Malloc(FILENAME_MAX+1), *wd =
Malloc(FILENAME_MAX+1);
125 const char *cwd = Yap_getcwd(wd, FILENAME_MAX);
126 size_t sz = cwk_path_get_absolute(
133return pop_output_text_stack(lvl,o);
149 int lvl = push_text_stack();
151 if (spec == NULL || spec[0]==
'\0') spec = Yap_getcwd(s,256);
160 if ((rc = unix2win(spec, rc2, MAX_PATH)) == NULL) {
171 const char *q = PlExpandVars(spec1, NULL);
179 rc = myrealpath(spec2 PASS_REGS);
180 return pop_output_text_stack(lvl, rc);
185do_glob(
const char *spec,
bool glob_vs_wordexp) {
191 char u[MAX_PATH + 1];
193 WIN32_FIND_DATA find;
197 char drive[_MAX_DRIVE];
199 char fname[_MAX_FNAME];
202 _splitpath(spec, drive, dir, fname, ext);
203 _makepath(u, drive, dir, fname, ext);
206 hFind = FindFirstFile(u, &find);
207 if (hFind == INVALID_HANDLE_VALUE) {
211 _makepath(u, drive, dir, find.cFileName, NULL);
212 HR[0] = MkAtomTerm(Yap_LookupAtom(u));
216 while (FindNextFile(hFind, &find)) {
218 _makepath(u, drive, dir, find.cFileName, NULL);
219 HR[0] = MkAtomTerm(Yap_LookupAtom(u));
229 return MkPairTerm(MkAtomTerm(Yap_LookupAtom(spec)), TermNil);
230#elif HAVE_WORDEXP || HAVE_GLOB
231 char u[MAX_PATH + 1];
232 const char *espec = u;
233 strncpy(u, spec,
sizeof(u));
242#if HAVE_GLOB || HAVE_WORDEXP
246 if (glob_vs_wordexp) {
249 flags = GLOB_NOCHECK;
254 flags |= GLOB_BRACE | GLOB_TILDE;
256 switch (glob(espec, flags, NULL, &gresult)) {
258 ss = gresult.gl_pathv;
259 pathcount = gresult.gl_pathc;
267 PlIOError(SYSTEM_ERROR_OPERATING_SYSTEM, ARG1,
"glob aborted: %sn",
272 Yap_Error(RESOURCE_ERROR_HEAP, ARG1,
"glob ran out of space: %sn",
285 memset(&wresult, 0,
sizeof(wresult));
286 switch ((rc = wordexp(espec, &wresult, flags))) {
288 ss = wresult.we_wordv;
289 pathcount = wresult.we_wordc;
294 t = MkAtomTerm(Yap_LookupAtom(espec));
296 return MkPairTerm(t, TermNil);
301 Yap_Error(RESOURCE_ERROR_HEAP, ARG1,
"wordexp ran out of space: %s",
306 PlIOError(SYSTEM_ERROR_OPERATING_SYSTEM, ARG1,
"wordexp failed: %s",
315 for (j = 0; j < pathcount; j++) {
316 const char *s = ss[pathcount - (j + 1)];
320 Atom a = Yap_LookupAtom(tmp);
321 tf = MkPairTerm(MkAtomTerm(a), tf);
328 if (!glob_vs_wordexp)
334 return MkPairTerm(MkAtomTerm(Yap_LookupAtom(spec)), TermNil);
341static const char *PlExpandVars(
const char *
source,
const char *root) {
343 int lvl = push_text_stack();
345 char *result =
Malloc(MAX_PATH + 1);
347 if (strlen(
source) >= MAX_PATH) {
348 Yap_Error(SYSTEM_ERROR_OPERATING_SYSTEM, TermNil,
349 "%s in true_file-name is larger than the buffer size (%d bytes)",
354 if (Yap_dir_separator(
source[1]) ||
source[1] ==
'\0') {
358 s = getenv(
"HOMEDRIVE");
360 strncpy(result, getenv(
"HOMEDRIVE"), MAX_PATH);
366 strncpy(result, s, MAX_PATH);
368 result = pop_output_text_stack(lvl, result);
372 struct passwd *user_passwd;
376 while (!Yap_dir_separator((*res = *src)) && *res !=
'\0')
379 if ((user_passwd = getpwnam(result)) == NULL) {
380 FileError(SYSTEM_ERROR_OPERATING_SYSTEM,
381 MkAtomTerm(Yap_LookupAtom(
source)),
382 "User %s does not exist in %s", result,
source);
386 strncpy(result, user_passwd->pw_dir, MAX_PATH);
390 SYSTEM_ERROR_OPERATING_SYSTEM, MkAtomTerm(Yap_LookupAtom(
source)),
391 "User %s cannot be found in %s, missing getpwnam", result,
source);
395 result = pop_output_text_stack(lvl, result);
399 else if (
source[0] ==
'$') {
401 char v[MAX_PATH + 1];
408 while ((*res = (ch = *src++)) && isValidEnvChar(ch) && ch !=
'}') {
418 while ((*res = (ch = *src++)) && isValidEnvChar(ch) && ch !=
'}') {
424 if ((s = (
char *)getenv(v))) {
430 size_t tocp = strlen(src);
432 tocp = strlen(root) + 1;
434 if (tocp > MAX_PATH) {
435 Yap_Error(SYSTEM_ERROR_OPERATING_SYSTEM, MkStringTerm(src),
440 if (root && !Yap_IsAbsolutePath(
source,
false)) {
441 strncpy(result, root, MAX_PATH);
442 if (root[strlen(root) - 1] !=
'/')
443 strncat(result,
"/", MAX_PATH);
444 strncat(result,
source, MAX_PATH);
446 strncpy(result,
source, strlen(src) + 1);
449 result = pop_output_text_stack(lvl, result);
458static Int real_path(USES_REGS1) {
459 Term t1 = Deref(ARG1);
460 const char *cmd, *rc0;
462 if (IsAtomTerm(t1)) {
463 cmd = RepAtom(AtomOfTerm(t1))->StrOfAE;
464 }
else if (IsStringTerm(t1)) {
465 cmd = StringOfTerm(t1);
470 char cmd2[MAX_PATH + 1];
473 if ((rc = unix2win(cmd, cmd2, MAX_PATH)) == NULL) {
478 int lvl = push_text_stack();
479 const char *p = PlExpandVars(cmd, NULL);
480 rc0 = myrealpath(p PASS_REGS);
483 PlIOError(SYSTEM_ERROR_OPERATING_SYSTEM, ARG1, NULL);
485 bool out = Yap_unify(MkAtomTerm(Yap_LookupAtom(rc0)), ARG2);
491static char *close_path(
char *b0,
char *o0,
char *o) {
494 }
else if (!strcmp(b0,
"..")) {
496 if (Yap_dir_separator(*o)) {
501 }
else if (strcmp(b0,
".") != 0) {
512bool Yap_IsAbsolutePath(
const char *p0,
bool expand) {
517 p = PlExpandVars(p0, NULL);
519#if _WIN32 || __MINGW32__
520 nrc = !PathIsRelative(p);
530static Int true_file_name(USES_REGS1) {
531 Term t = Deref(ARG1);
535 Yap_ThrowError(INSTANTIATION_ERROR, t,
"argument to true_file_name unbound");
539 s = RepAtom(AtomOfTerm(t))->StrOfAE;
540 }
else if (IsStringTerm(t)) {
543 Yap_ThrowError(TYPE_ERROR_ATOM, t,
"argument to true_file_name");
546 int l = push_text_stack();
551 bool rc = Yap_unify(ARG2, MkAtomTerm(Yap_LookupAtom(s)));
557static Int absolute_file_system_path(USES_REGS1) {
558 Term t = Deref(ARG1);
559 int l = push_text_stack();
560 const char *text = Yap_TextTermToText(t);
577static Int prolog_to_os_filename(USES_REGS1) {
578 Term t = Deref(ARG1), t2 = Deref(ARG2);
580 char out[PATH_MAX + 1];
585 Yap_Error(INSTANTIATION_ERROR, t,
"prolog_to_os_filename");
587 }
else if (IsAtomTerm(t2)) {
588 if (!(fp = PrologPath(RepAtom(AtomOfTerm(t2))->StrOfAE, out)))
590 return Yap_unify(ARG1, MkAtomTerm(Yap_LookupAtom(fp)));
592 Yap_Error(TYPE_ERROR_ATOM, t2,
"prolog_to_os_filename");
595 }
else if (!IsAtomTerm(t)) {
596 Yap_Error(TYPE_ERROR_ATOM, t,
"prolog_to_os_filename");
600 if (!(fp = OsPath(RepAtom(AtomOfTerm(t))->StrOfAE, out)))
602 return Yap_unify(MkAtomTerm(Yap_LookupAtom(fp)), ARG2);
606const char *Yap_GetFileName(Term t USES_REGS) {
607 char *buf =
Malloc(MAX_PATH + 1);
608 if (IsApplTerm(t) && FunctorOfTerm(t) == FunctorSlash) {
609 snprintf(buf, MAX_PATH,
"%s/%s", Yap_GetFileName(ArgOfTerm(1, t)),
610 Yap_GetFileName(ArgOfTerm(2, t)));
613 return RepAtom(AtomOfTerm(t))->StrOfAE;
615 if (IsStringTerm(t)) {
616 return StringOfTerm(t);
618 return Yap_TextTermToText(t PASS_REGS);
640static Int file_name_extension(USES_REGS1) {
643 Term t3 = Deref(ARG3);
644 int l = push_text_stack();
645 if (!IsVarTerm(t3)) {
647 const char *f = Yap_GetFileName(t3);
651 seq_type_t typ = Yap_TextType(t3);
656 size_t len_b = strlen(f), lenb_b;
657 char *candidate = strrchr(f,
'.');
658 char *file = strrchr(f,
'/');
659 if (candidate && candidate > file) {
660 lenb_b = candidate - f;
666 base =
Malloc(lenb_b + 1);
667 memmove(base, f, lenb_b);
669 if (IsVarTerm(t1 = Deref(ARG1))) {
673 char *f_a = (
char *)Yap_GetFileName(t1 PASS_REGS);
674#if __APPLE__ || _WIN32
675 rc = strcasecmp(f_a, base) == 0;
677 rc = strcmp(f_a, base) == 0;
681 if (IsVarTerm(t2 = Deref(ARG2))) {
685 char *f_a = (
char *)Yap_TextTermToText(t2 PASS_REGS);
689#if __APPLE__ || _WIN32
690 rc = strcasecmp(f_a, ext) == 0;
692 rc = strcmp(f_a, ext) == 0;
701 seq_type_t typ, typ1 = Yap_TextType((t1 = Deref(ARG1))),
702 typ2 = Yap_TextType((t2 = Deref(ARG2)));
705 }
else if (typ1 == YAP_STRING_ATOM || typ2 == YAP_STRING_ATOM) {
706 typ = YAP_STRING_ATOM;
708 typ = YAP_STRING_STRING;
710 if (!(f = Yap_TextTermToText(t1 PASS_REGS))) {
714 if (!(f2 = (
char *)Yap_TextTermToText(t2 PASS_REGS))) {
722 size_t lenb_b = strlen(f);
723 char *o = Realloc((
void *)f, lenb_b + strlen(f2) + 2);
732static Int access_path(USES_REGS1) {
733 Term tname = Deref(ARG1);
735 if (IsVarTerm(tname)) {
736 Yap_Error(INSTANTIATION_ERROR, tname,
"access");
738 }
else if (!IsAtomTerm(tname)) {
739 Yap_Error(TYPE_ERROR_ATOM, tname,
"access");
743 char *s = RepAtom(AtomOfTerm(tname))->StrOfAE;
744 if (!s)
return false;
745 if ((
vfs = vfs_owner(s))) {
748 UNLOCK(GLOBAL_Stream[sno].streamlock);
752 struct SYSTEM_STAT ss;
755 file_name = RepAtom(AtomOfTerm(tname))->StrOfAE;
756 if (SYSTEM_STAT(file_name, &ss) != 0) {
767static char *clean_path(
const char *path) {
769 int lvl = push_text_stack();
772 char *o0 =
Malloc(FILENAME_MAX + 1), *o = o0;
774 char *b0 =
Malloc(FILENAME_MAX + 1), *b = b0;
776 while ((ch = *p++)) {
777 if (Yap_dir_separator(ch)) {
782 o = close_path(b0, o0, o);
789 if (!Yap_dir_separator(p[-1])) {
791 o = close_path(b0, o0, o);
798 return pop_output_text_stack(lvl, o0);
802static Int p_expand_file_name(USES_REGS1) {
803 Term t = Deref(ARG1);
804 const char *text, *text2;
807 Yap_Error(INSTANTIATION_ERROR, t,
"argument to true_file_name unbound");
810 int l = push_text_stack();
811 text = Yap_TextTermToText(t);
816 if (!(text2 = PlExpandVars(text, NULL))) {
820 bool rc = Yap_unify(ARG2, do_glob(text2,
true) );
825static Int true_file_name3(USES_REGS1) {
826 Term t = Deref(ARG1), t2 = Deref(ARG2);
829 Yap_Error(INSTANTIATION_ERROR, t,
"argument to true_file_name unbound");
832 if (!IsAtomTerm(t)) {
833 Yap_Error(TYPE_ERROR_ATOM, t,
"argument to true_file_name");
836 if (!IsVarTerm(t2)) {
837 if (!IsAtomTerm(t)) {
838 Yap_Error(TYPE_ERROR_ATOM, t2,
"argument to true_file_name");
843 int lvl = push_text_stack();
846 bool rc = (tmp != NULL && (at = Yap_LookupAtom(tmp)) != NULL);
848 return rc && Yap_unify(ARG3, MkAtomTerm(at));
851static Int path_concat(USES_REGS1) {
852 int l = push_text_stack();
854 Term t = Deref(ARG1);
856 int n = Yap_SkipList(&t, &tailp);
857 if (*tailp != TermNil) {
858 Yap_ThrowError(TYPE_ERROR_LIST, t,
"while concatenating sub-paths");
860 const char **inp =
Malloc( (n+1)*
sizeof(
const char *) );
862 while (IsPairTerm(t)) {
863 Term th = HeadOfTerm(t);
864 if (IsAtomTerm(th)) {
865 inp[i++] = RepAtom(AtomOfTerm(th))->StrOfAE;
866 }
else if (IsStringTerm(th)) {
867 inp[i++] = StringOfTerm(th);
877 sz = cwk_path_join_multiple(inp,buf,len-1);
880 buf = Realloc (buf, len);
882 bool rc= Yap_unify(MkAtomTerm(Yap_LookupAtom(buf)),ARG2);
890#define ABSOLUTE_FILE_NAME_DEFS() \
891 PAR("access", isatom, ABSOLUTE_FILE_NAME_ACCESS) , \
892 PAR("expand", booleanFlag, ABSOLUTE_FILE_NAME_EXPAND), \
893 PAR("extensions", ok, ABSOLUTE_FILE_NAME_EXTENSIONS) , \
894 PAR("file_errors", is_file_errors, ABSOLUTE_FILE_NAME_FILE_ERRORS), \
895 PAR("file_type", is_file_type, ABSOLUTE_FILE_NAME_FILE_TYPE) , \
896 PAR("glob", ok, ABSOLUTE_FILE_NAME_GLOB) , \
897 PAR("relative_to", isatom, ABSOLUTE_FILE_NAME_RELATIVE_TO), \
898 PAR("solutions", issolutions, ABSOLUTE_FILE_NAME_SOLUTIONS) , \
899 PAR("verbose_file_search", booleanFlag, ABSOLUTE_FILE_NAME_VERBOSE_FILE_SEARCH), \
900 PAR(NULL, ok, ABSOLUTE_FILE_NAME_END)
902#define PAR(x, y, z) z
904typedef enum ABSOLUTE_FILE_NAME_enum_ {
905 ABSOLUTE_FILE_NAME_DEFS()
906} absolute_file_name_choices_t;
910#define PAR(x, y, z) \
913static const param_t absolute_file_name_search_defs[] = {
914 ABSOLUTE_FILE_NAME_DEFS()};
917static Int abs_file_parameters(USES_REGS1) {
918 Term t[ABSOLUTE_FILE_NAME_END];
919 Term tlist = Deref(ARG1), tf;
920 int lvl = push_text_stack();
923 memset(args,0,ABSOLUTE_FILE_NAME_END*
sizeof(
xarg));
924 Yap_ArgListToVector(tlist, absolute_file_name_search_defs,
925 ABSOLUTE_FILE_NAME_END, args,
926 DOMAIN_ERROR_ABSOLUTE_FILE_NAME_OPTION);
928 if (LOCAL_Error_TYPE != YAP_NO_ERROR) {
929 Yap_Error(LOCAL_Error_TYPE, tlist, NULL);
935 if (args[ABSOLUTE_FILE_NAME_EXTENSIONS].used) {
936 t[ABSOLUTE_FILE_NAME_EXTENSIONS] =
937 args[ABSOLUTE_FILE_NAME_EXTENSIONS].tvalue;
939 t[ABSOLUTE_FILE_NAME_EXTENSIONS] = TermNil;
941 if (args[ABSOLUTE_FILE_NAME_RELATIVE_TO].used) {
942 t[ABSOLUTE_FILE_NAME_RELATIVE_TO] =
943 gethdir(args[ABSOLUTE_FILE_NAME_RELATIVE_TO].tvalue);
945 t[ABSOLUTE_FILE_NAME_RELATIVE_TO] = gethdir(TermDot);
947 if (args[ABSOLUTE_FILE_NAME_FILE_TYPE].used)
948 t[ABSOLUTE_FILE_NAME_FILE_TYPE] = args[ABSOLUTE_FILE_NAME_FILE_TYPE].tvalue;
950 t[ABSOLUTE_FILE_NAME_FILE_TYPE] = TermTxt;
951 if (args[ABSOLUTE_FILE_NAME_ACCESS].used)
952 t[ABSOLUTE_FILE_NAME_ACCESS] = args[ABSOLUTE_FILE_NAME_ACCESS].tvalue;
954 t[ABSOLUTE_FILE_NAME_ACCESS] = TermNone;
955 if (args[ABSOLUTE_FILE_NAME_FILE_ERRORS].used)
956 t[ABSOLUTE_FILE_NAME_FILE_ERRORS] =
957 ( args[ABSOLUTE_FILE_NAME_FILE_ERRORS].tvalue == TermFail ?
958 TermFalse : TermTrue );
960 t[ABSOLUTE_FILE_NAME_FILE_ERRORS] = getAtomicLocalPrologFlag(FILE_ERRORS_FLAG) ;;
961 if (args[ABSOLUTE_FILE_NAME_SOLUTIONS].used)
962 t[ABSOLUTE_FILE_NAME_SOLUTIONS] = args[ABSOLUTE_FILE_NAME_SOLUTIONS].tvalue;
964 t[ABSOLUTE_FILE_NAME_SOLUTIONS] = TermFirst;
965 if (args[ABSOLUTE_FILE_NAME_EXPAND].used)
966 t[ABSOLUTE_FILE_NAME_EXPAND] = args[ABSOLUTE_FILE_NAME_EXPAND].tvalue;
968 t[ABSOLUTE_FILE_NAME_EXPAND] =getAtomicLocalPrologFlag(EXPAND_FILE_NAME_FLAG) ;
969 if (args[ABSOLUTE_FILE_NAME_GLOB].used) {
970 t[ABSOLUTE_FILE_NAME_GLOB] = args[ABSOLUTE_FILE_NAME_GLOB].tvalue;
971 t[ABSOLUTE_FILE_NAME_EXPAND] = TermTrue;
973 t[ABSOLUTE_FILE_NAME_GLOB] = MkVarTerm();
974 if (args[ABSOLUTE_FILE_NAME_VERBOSE_FILE_SEARCH].used)
975 t[ABSOLUTE_FILE_NAME_VERBOSE_FILE_SEARCH] =
976 args[ABSOLUTE_FILE_NAME_VERBOSE_FILE_SEARCH].tvalue;
978 t[ABSOLUTE_FILE_NAME_VERBOSE_FILE_SEARCH] =
979 (trueLocalPrologFlag(VERBOSE_FILE_SEARCH_FLAG) ? TermTrue : TermFalse);
980 tf = Yap_MkApplTerm(Yap_MkFunctor(AtomOpt, ABSOLUTE_FILE_NAME_END),
981 ABSOLUTE_FILE_NAME_END, t);
982 pop_text_stack(lvl);
return (Yap_unify(ARG2, tf));
985static Int get_abs_file_parameter(USES_REGS1) {
986 Term t = Deref(ARG1), topts = Deref(ARG2);
989 int i =
Yap_ArgKey(AtomOfTerm(t), absolute_file_name_search_defs,
990 ABSOLUTE_FILE_NAME_END);
992 return Yap_unify(ARG3, ArgOfTerm(i + 1, topts));
993 Yap_Error(DOMAIN_ERROR_ABSOLUTE_FILE_NAME_OPTION, ARG1, NULL);
998void Yap_InitAbsfPreds(
void) {
999 Yap_InitCPred(
"path_concat", 2, path_concat,0);
1000 Yap_InitCPred(
"expand_file_name", 2, p_expand_file_name, SyncPredFlag);
1001 Yap_InitCPred(
"prolog_to_os_filename", 2, prolog_to_os_filename,
1003 Yap_InitCPred(
"absolute_file_system_path", 2, absolute_file_system_path, 0);
1004 Yap_InitCPred(
"absolute_file_system_path", 2, absolute_file_system_path, 0);
1005 Yap_InitCPred(
"absolute_file_name", 2, real_path, 0);
1006 Yap_InitCPred(
"true_file_name", 2, true_file_name, SyncPredFlag);
1007 Yap_InitCPred(
"true_file_name", 3, true_file_name3, SyncPredFlag);
1008 Yap_InitCPred(
"abs_file_parameters", 2, abs_file_parameters, HiddenPredFlag);
1009 Yap_InitCPred(
"get_abs_file_parameter", 3, get_abs_file_parameter, HiddenPredFlag);
1010 Yap_InitCPred(
"file_name_extension", 3, file_name_extension, 0);
const char * Yap_AbsoluteFile(const char *spec, bool ok)
generate absolute path, if ok first expand SICStus Prolog style
int Yap_ArgKey(Atom key, const param_t *def, int n)
Returns the index of an argument key, or -1 if not found.
void * Malloc(size_t sz USES_REGS)
allocate a temporary text block
@ source
If true maintain the source for all clauses.
bool(* stat)(struct vfs *, const char *s, vfs_stat *)
close access a directory object
Term Yap_MkTextTerm(const char *s, int guide USES_REGS)
Convert from a text buffer (8-bit) to a term that has the same type as Tguide