YAP 7.1.0
absf.c
Go to the documentation of this file.
1/*************************************************************************
2 * *
3 * YAP Prolog *
4 * *
5 * Yap Prolog was developed at NCCUP - Universidade do Porto *
6 * *
7 * Copyright L.Damas, V.S.Costa and Universidade do Porto 1985-1997 *
8 * *
9 **************************************************************************
10 * *
11 * File: iopreds.c *
12 * Last rev: 5/2/88 *
13 * mods: *
14 * comments: Input/Output C implemented predicates *
15 * *
16 *************************************************************************/
17#ifdef SCCS
18static char SccsId[] = "%W% %G%";
19#endif
20
21#include "Yap.h"
22#include "YapFlags.h"
23#include "yapio.h"
24#include "sysbits.h"
25
26#include <cwalk.h>
27
37static Term do_glob(const char *spec, bool glob_vs_wordexp);
38static const char *PlExpandVars(const char *source, const char *root);
39
40static Term gethdir(Term t) {
41 CACHE_REGS
42
43 Atom aref = AtomOfTerm(t);
44 char *s = RepAtom(aref)->StrOfAE;
45 size_t nsz;
46 char buf[PATH_MAX];
47
48 s = strncpy(buf, RepAtom(aref)->StrOfAE, PATH_MAX - 1);
49 if (!s) {
50 return false;
51 }
52 if (TermDot == t) {
53 return
54 MkAtomTerm(Yap_LookupAtom(Yap_getcwd(buf,
55PATH_MAX - 1)));
56 }
57 nsz = strlen(s);
58 if (!Yap_dir_separator(s[nsz - 1])) {
59#if _WIN32
60 s[nsz] = '\\';
61#else
62 s[nsz] = '/';
63#endif
64 s[nsz + 1] = '\0';
65 }
66 return MkAtomTerm(Yap_LookupAtom(s));
67}
68
69static Term issolutions(Term t) {
70 if (t == TermFirst || t == TermAll)
71 return t;
72
73 if (IsVarTerm(t)) {
74 Yap_Error(INSTANTIATION_ERROR, t, "solutions in {first, all}.");
75 return TermZERO;
76 }
77 if (IsAtomTerm(t)) {
78 Yap_Error(DOMAIN_ERROR_SOLUTIONS, t, "solutions in {first, all}");
79 return TermZERO;
80 }
81 Yap_Error(TYPE_ERROR_ATOM, t, "solutions in {first, all}}");
82 return TermZERO;
83}
84
85static Term is_file_errors(Term t) {
86 if (t == TermFail || t == TermError)
87 return t;
88
89 if (IsVarTerm(t)) {
90 Yap_Error(INSTANTIATION_ERROR, t, "file_error in {fail,error}.");
91 return TermZERO;
92 }
93 if (IsAtomTerm(t)) {
94 Yap_Error(DOMAIN_ERROR_FILE_ERRORS, t, "file_error in {fail,error}.");
95 return TermZERO;
96 }
97 Yap_Error(TYPE_ERROR_ATOM, t, "file_error in {fail,error}.");
98 return TermZERO;
99}
100
101
102static Term is_file_type(Term t) {
103 if (t == TermTxt || t == TermProlog || t == TermSource ||
104 t == TermExecutable || t == TermQly || t == TermDirectory)
105 return t;
106
107 if (IsVarTerm(t)) {
108 Yap_Error(INSTANTIATION_ERROR, t,
109 "file_type in {txt,prolog,exe,directory...}");
110 return TermZERO;
111 }
112 if (IsAtomTerm(t)) {
113 Yap_Error(DOMAIN_ERROR_FILE_TYPE, t,
114 "file_type in {txt,prolog,exe,directory...}");
115 return TermZERO;
116 }
117 Yap_Error(TYPE_ERROR_ATOM, t, "file_type in {txt,prolog,exe,directory...}");
118 return TermZERO;
119}
120
121
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(
127 cwd, path,
128 o,
129 FILENAME_MAX
130 );
131 if (sz <0)
132 return NULL;
133return pop_output_text_stack(lvl,o);
134}
135
136
145const char *Yap_AbsoluteFile(const char *spec, bool ok) {
146 const char *rc;
147 const char *spec1;
148 const char *spec2;
149 int lvl = push_text_stack();
150char s[257];
151 if (spec == NULL || spec[0]=='\0') spec = Yap_getcwd(s,256);
157
158#if _WIN32
159 char rc2[MAX_PATH];
160 if ((rc = unix2win(spec, rc2, MAX_PATH)) == NULL) {
161 pop_text_stack();
162 return NULL;
163 }
164 spec1 = rc;
165#else
166 spec1 = spec;
167#endif
170 if (ok) {
171 const char *q = PlExpandVars(spec1, NULL);
172 if (!q)
173 spec2 = spec1;
174 else
175 spec2 = q;
176 } else {
177 spec2 = spec1;
178 }
179 rc = myrealpath(spec2 PASS_REGS);
180 return pop_output_text_stack(lvl, rc);
181}
182
183static Term
184/* Expand the string for the program to run. */
185do_glob(const char *spec, bool glob_vs_wordexp) {
186 CACHE_REGS
187 if (spec == NULL) {
188 return TermNil;
189 }
190#if _WIN32
191 char u[MAX_PATH + 1];
192 {
193 WIN32_FIND_DATA find;
194 HANDLE hFind;
195 CELL *dest;
196 Term tf;
197 char drive[_MAX_DRIVE];
198 char dir[_MAX_DIR];
199 char fname[_MAX_FNAME];
200 char ext[_MAX_EXT];
201
202 _splitpath(spec, drive, dir, fname, ext);
203 _makepath(u, drive, dir, fname, ext);
204
205 // first pass, remove Unix style stuff
206 hFind = FindFirstFile(u, &find);
207 if (hFind == INVALID_HANDLE_VALUE) {
208 return TermNil;
209 } else {
210 tf = AbsPair(HR);
211 _makepath(u, drive, dir, find.cFileName, NULL);
212 HR[0] = MkAtomTerm(Yap_LookupAtom(u));
213 HR[1] = TermNil;
214 dest = HR + 1;
215 HR += 2;
216 while (FindNextFile(hFind, &find)) {
217 *dest = AbsPair(HR);
218 _makepath(u, drive, dir, find.cFileName, NULL);
219 HR[0] = MkAtomTerm(Yap_LookupAtom(u));
220 HR[1] = TermNil;
221 dest = HR + 1;
222 HR += 2;
223 }
224 FindClose(hFind);
225 }
226 return tf;
227 }
228#elif __ANDROID__
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));
234 /* Expand the string for the program to run. */
235 size_t pathcount;
236#if HAVE_GLOB
237 glob_t gresult;
238#endif
239#if HAVE_WORDEXP
240 wordexp_t wresult;
241#endif
242#if HAVE_GLOB || HAVE_WORDEXP
243 char **ss = NULL;
244 int flags = 0, j;
245#endif
246 if (glob_vs_wordexp) {
247#if HAVE_GLOB
248#ifdef GLOB_NOCHECK
249 flags = GLOB_NOCHECK;
250#else
251 flags = 0;
252#endif
253#ifdef GLOB_BRACE
254 flags |= GLOB_BRACE | GLOB_TILDE;
255#endif
256 switch (glob(espec, flags, NULL, &gresult)) {
257 case 0: /* Successful. */
258 ss = gresult.gl_pathv;
259 pathcount = gresult.gl_pathc;
260 if (pathcount) {
261 break;
262 }
263 case GLOB_NOMATCH:
264 globfree(&gresult);
265 { return TermNil; }
266 case GLOB_ABORTED:
267 PlIOError(SYSTEM_ERROR_OPERATING_SYSTEM, ARG1, "glob aborted: %sn",
268 strerror(errno));
269 globfree(&gresult);
270 return TermNil;
271 case GLOB_NOSPACE:
272 Yap_Error(RESOURCE_ERROR_HEAP, ARG1, "glob ran out of space: %sn",
273 strerror(errno));
274 globfree(&gresult);
275 return TermNil;
276 /* If the error was WRDE_NOSPACE,
277 then perhaps part of the result was allocated. */
278 default: /* Some other error. */
279 return TermNil;
280 }
281#endif
282 } else {
283#if HAVE_WORDEXP
284 int rc;
285 memset(&wresult, 0, sizeof(wresult));
286 switch ((rc = wordexp(espec, &wresult, flags))) {
287 case 0: /* Successful. */
288 ss = wresult.we_wordv;
289 pathcount = wresult.we_wordc;
290 if (pathcount) {
291 break;
292 } else {
293 Term t;
294 t = MkAtomTerm(Yap_LookupAtom(espec));
295 wordfree(&wresult);
296 return MkPairTerm(t, TermNil);
297 }
298 case WRDE_NOSPACE:
299 /* If the error was WRDE_NOSPACE,
300 then perhaps part of the result was allocated. */
301 Yap_Error(RESOURCE_ERROR_HEAP, ARG1, "wordexp ran out of space: %s",
302 strerror(errno));
303 wordfree(&wresult);
304 return TermNil;
305 default: /* Some other error. */
306 PlIOError(SYSTEM_ERROR_OPERATING_SYSTEM, ARG1, "wordexp failed: %s",
307 strerror(errno));
308 wordfree(&wresult);
309 return TermNil;
310 }
311#endif
312 }
313 const char *tmp;
314 Term tf = TermNil;
315 for (j = 0; j < pathcount; j++) {
316 const char *s = ss[pathcount - (j + 1)];
317 tmp = s;
318 // if (!exists(s))
319 // continue;
320 Atom a = Yap_LookupAtom(tmp);
321 tf = MkPairTerm(MkAtomTerm(a), tf);
322 }
323#if HAVE_GLOB
324 if (glob_vs_wordexp)
325 globfree(&gresult);
326#endif
327#if HAVE_WORDEXP
328 if (!glob_vs_wordexp)
329 wordfree(&wresult);
330#endif
331 return tf;
332#else
333 // just use basic
334 return MkPairTerm(MkAtomTerm(Yap_LookupAtom(spec)), TermNil);
335#endif
336}
337
338// this is necessary because
339// support for ~expansion at the beginning
340// systems like Android do not do this.
341static const char *PlExpandVars(const char *source, const char *root) {
342 CACHE_REGS
343 int lvl = push_text_stack();
344 const char *src = source;
345 char *result = Malloc(MAX_PATH + 1);
346
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)",
350 source, strlen(source));
351 }
352 /* step 1: eating home information */
353 if (source[0] == '~') {
354 if (Yap_dir_separator(source[1]) || source[1] == '\0') {
355 char *s;
356 src++;
357#if defined(_WIN32)
358 s = getenv("HOMEDRIVE");
359 if (s != NULL)
360 strncpy(result, getenv("HOMEDRIVE"), MAX_PATH);
361// s = getenv("HOMEPATH");
362#else
363 s = getenv("HOME");
364#endif
365 if (s != NULL)
366 strncpy(result, s, MAX_PATH);
367 strcat(result, src);
368 result = pop_output_text_stack(lvl, result);
369 return result;
370 } else {
371#if HAVE_GETPWNAM
372 struct passwd *user_passwd;
373 char *res = result;
374
375 src++;
376 while (!Yap_dir_separator((*res = *src)) && *res != '\0')
377 res++, src++;
378 res[0] = '\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);
383 pop_text_stack(lvl);
384 return NULL;
385 }
386 strncpy(result, user_passwd->pw_dir, MAX_PATH);
387 strcat(result, src);
388#else
389 FileError(
390 SYSTEM_ERROR_OPERATING_SYSTEM, MkAtomTerm(Yap_LookupAtom(source)),
391 "User %s cannot be found in %s, missing getpwnam", result, source);
392 return NULL;
393#endif
394 }
395 result = pop_output_text_stack(lvl, result);
396 return result;
397 }
398 // do VARIABLE expansion
399 else if (source[0] == '$') {
400 /* follow SICStus expansion rules */
401 char v[MAX_PATH + 1];
402 int ch;
403 char *s, *res;
404 src = source + 1;
405 if (src[0] == '{') {
406 res = v;
407 src++;
408 while ((*res = (ch = *src++)) && isValidEnvChar(ch) && ch != '}') {
409 res++;
410 }
411 if (ch == '}') {
412 // {...}
413 // done
414 res[0] = '\0';
415 }
416 } else {
417 res = v;
418 while ((*res = (ch = *src++)) && isValidEnvChar(ch) && ch != '}') {
419 res++;
420 }
421 src--;
422 res[0] = '\0';
423 }
424 if ((s = (char *)getenv(v))) {
425 strcpy(result, s);
426 strcat(result, src);
427 } else
428 strcpy(result, src);
429 } else {
430 size_t tocp = strlen(src);
431 if (root) {
432 tocp = strlen(root) + 1;
433 }
434 if (tocp > MAX_PATH) {
435 Yap_Error(SYSTEM_ERROR_OPERATING_SYSTEM, MkStringTerm(src),
436 "path too long");
437 pop_text_stack(lvl);
438 return NULL;
439 }
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);
445 } else {
446 strncpy(result, source, strlen(src) + 1);
447 }
448 }
449 result = pop_output_text_stack(lvl, result);
450 return result;
451}
452
458static Int real_path(USES_REGS1) {
459 Term t1 = Deref(ARG1);
460 const char *cmd, *rc0;
461
462 if (IsAtomTerm(t1)) {
463 cmd = RepAtom(AtomOfTerm(t1))->StrOfAE;
464 } else if (IsStringTerm(t1)) {
465 cmd = StringOfTerm(t1);
466 } else {
467 return false;
468 }
469#if _WIN32
470 char cmd2[MAX_PATH + 1];
471 char *rc;
472
473 if ((rc = unix2win(cmd, cmd2, MAX_PATH)) == NULL) {
474 return false;
475 }
476 cmd = rc;
477#endif
478 int lvl = push_text_stack();
479 const char *p = PlExpandVars(cmd, NULL);
480 rc0 = myrealpath(p PASS_REGS);
481 if (!rc0) {
482 pop_text_stack(lvl);
483 PlIOError(SYSTEM_ERROR_OPERATING_SYSTEM, ARG1, NULL);
484 }
485 bool out = Yap_unify(MkAtomTerm(Yap_LookupAtom(rc0)), ARG2);
486 pop_text_stack(lvl);
487 return out;
488}
489
490#if undefined
491static char *close_path(char *b0, char *o0, char *o) {
492 if (b0[0] == '\0') {
493 return o;
494 } else if (!strcmp(b0, "..")) {
495 while (o-- > o0) {
496 if (Yap_dir_separator(*o)) {
497 break;
498 }
499 }
500
501 } else if (strcmp(b0, ".") != 0) {
502 *o++ = '/';
503 strcpy(o, b0);
504 o += strlen(b0);
505 }
506 return o;
507 }
508#endif
509
510
511
512bool Yap_IsAbsolutePath(const char *p0, bool expand) {
513 // verify first if expansion is needed: ~/ or $HOME/
514 const char *p = p0;
515 bool nrc;
516 if (expand) {
517 p = PlExpandVars(p0, NULL);
518 }
519#if _WIN32 || __MINGW32__
520 nrc = !PathIsRelative(p);
521#else
522 nrc = (p[0] == '/');
523#endif
524 return nrc;
525}
526
527
528
529
530static Int true_file_name(USES_REGS1) {
531 Term t = Deref(ARG1);
532 const char *s;
533
534 if (IsVarTerm(t)) {
535 Yap_ThrowError(INSTANTIATION_ERROR, t, "argument to true_file_name unbound");
536 return FALSE;
537 }
538 if (IsAtomTerm(t)) {
539 s = RepAtom(AtomOfTerm(t))->StrOfAE;
540 } else if (IsStringTerm(t)) {
541 s = StringOfTerm(t);
542 } else {
543 Yap_ThrowError(TYPE_ERROR_ATOM, t, "argument to true_file_name");
544 return FALSE;
545 }
546 int l = push_text_stack();
547 if (!(s = Yap_AbsoluteFile(s, true))){
548 pop_text_stack(l);
549 return false;
550 }
551 bool rc = Yap_unify(ARG2, MkAtomTerm(Yap_LookupAtom(s)));
552 pop_text_stack(l);
553 return rc;
554}
555
556
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);
561 const char *fp;
562 bool rc;
563
564 if (text == NULL) {
565 pop_text_stack(l);
566 return false;
567 }
568 if (!(fp = Yap_AbsoluteFile(text, true))) {
569 pop_text_stack(l);
570 return false;
571 }
572 rc = Yap_unify(Yap_MkTextTerm(fp, Yap_TextType(t)), ARG2);
573 pop_text_stack(l);
574 return rc;
575}
576
577static Int prolog_to_os_filename(USES_REGS1) {
578 Term t = Deref(ARG1), t2 = Deref(ARG2);
579 char *fp;
580 char out[PATH_MAX + 1];
581
582 if (IsVarTerm(t)) {
583
584 if (IsVarTerm(t2)) {
585 Yap_Error(INSTANTIATION_ERROR, t, "prolog_to_os_filename");
586 return false;
587 } else if (IsAtomTerm(t2)) {
588 if (!(fp = PrologPath(RepAtom(AtomOfTerm(t2))->StrOfAE, out)))
589 return false;
590 return Yap_unify(ARG1, MkAtomTerm(Yap_LookupAtom(fp)));
591 } else {
592 Yap_Error(TYPE_ERROR_ATOM, t2, "prolog_to_os_filename");
593 return false;
594 }
595 } else if (!IsAtomTerm(t)) {
596 Yap_Error(TYPE_ERROR_ATOM, t, "prolog_to_os_filename");
597 return false;
598 }
599
600 if (!(fp = OsPath(RepAtom(AtomOfTerm(t))->StrOfAE, out)))
601 return false;
602 return Yap_unify(MkAtomTerm(Yap_LookupAtom(fp)), ARG2);
603}
604
605
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)));
611 }
612 if (IsAtomTerm(t)) {
613 return RepAtom(AtomOfTerm(t))->StrOfAE;
614 }
615 if (IsStringTerm(t)) {
616 return StringOfTerm(t);
617 }
618 return Yap_TextTermToText(t PASS_REGS);
619}
620
640static Int file_name_extension(USES_REGS1) {
641 Term t1;
642 Term t2;
643 Term t3 = Deref(ARG3);
644 int l = push_text_stack();
645 if (!IsVarTerm(t3)) {
646 // full path is given.
647 const char *f = Yap_GetFileName(t3);
648 const char *ext;
649 char *base;
650 bool rc = true;
651 seq_type_t typ = Yap_TextType(t3);
652 if (!f) {
653 pop_text_stack(l);
654 return false;
655 }
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;
661 ext = candidate + 1;
662 } else {
663 lenb_b = len_b;
664 ext = "";
665 }
666 base = Malloc(lenb_b + 1);
667 memmove(base, f, lenb_b);
668 base[lenb_b] = '\0';
669 if (IsVarTerm(t1 = Deref(ARG1))) {
670 // should always succeed
671 rc = Yap_unify(t1, Yap_MkTextTerm(base, typ));
672 } else {
673 char *f_a = (char *)Yap_GetFileName(t1 PASS_REGS);
674#if __APPLE__ || _WIN32
675 rc = strcasecmp(f_a, base) == 0;
676#else
677 rc = strcmp(f_a, base) == 0;
678#endif
679 }
680 if (rc) {
681 if (IsVarTerm(t2 = Deref(ARG2))) {
682 // should always succeed
683 rc = Yap_unify(t2, Yap_MkTextTerm(ext, typ));
684 } else {
685 char *f_a = (char *)Yap_TextTermToText(t2 PASS_REGS);
686 if (f_a[0] == '.') {
687 f_a += 1;
688 }
689#if __APPLE__ || _WIN32
690 rc = strcasecmp(f_a, ext) == 0;
691#else
692 rc = strcmp(f_a, ext) == 0;
693#endif
694 }
695 }
696 pop_text_stack(l);
697 return rc;
698 } else {
699 const char *f;
700 char *f2;
701 seq_type_t typ, typ1 = Yap_TextType((t1 = Deref(ARG1))),
702 typ2 = Yap_TextType((t2 = Deref(ARG2)));
703 if (typ1 == typ2) {
704 typ = typ1;
705 } else if (typ1 == YAP_STRING_ATOM || typ2 == YAP_STRING_ATOM) {
706 typ = YAP_STRING_ATOM;
707 } else {
708 typ = YAP_STRING_STRING;
709 }
710 if (!(f = Yap_TextTermToText(t1 PASS_REGS))) {
711 pop_text_stack(l);
712 return false;
713 }
714 if (!(f2 = (char *)Yap_TextTermToText(t2 PASS_REGS))) {
715 pop_text_stack(l);
716 return false;
717 }
718 if (f2[0] == '.') {
719 f2++;
720 }
721
722 size_t lenb_b = strlen(f);
723 char *o = Realloc((void *)f, lenb_b + strlen(f2) + 2);
724 o[lenb_b] = '.';
725 o += lenb_b + 1;
726 pop_text_stack(l);
727 return strcpy(o, f2) && (t3 = Yap_MkTextTerm(o, typ)) &&
728 Yap_unify(t3, ARG3);
729 }
730}
731#if 0
732static Int access_path(USES_REGS1) {
733 Term tname = Deref(ARG1);
734
735 if (IsVarTerm(tname)) {
736 Yap_Error(INSTANTIATION_ERROR, tname, "access");
737 return false;
738 } else if (!IsAtomTerm(tname)) {
739 Yap_Error(TYPE_ERROR_ATOM, tname, "access");
740 return false;
741 } else {
742 VFS_t *vfs;
743 char *s = RepAtom(AtomOfTerm(tname))->StrOfAE;
744 if (!s) return false;
745 if ((vfs = vfs_owner(s))) {
746 vfs_stat st;
747 bool rc = vfs->stat(vfs, s, &st);
748 UNLOCK(GLOBAL_Stream[sno].streamlock);
749 return rc;
750 }
751#if HAVE_STAT
752 struct SYSTEM_STAT ss;
753 char *file_name;
754
755 file_name = RepAtom(AtomOfTerm(tname))->StrOfAE;
756 if (SYSTEM_STAT(file_name, &ss) != 0) {
757 /* ignore errors while checking a file */
758 return true;
759 }
760 return true;
761#else
762 return false;
763#endif
764 }
765}
766
767static char *clean_path(const char *path) {
768 const char *p, *p0;
769 int lvl = push_text_stack();
770
771 //__android_log_print(ANDROID_LOG_INFO, "YAPDroid ", " looking at %s", path);
772 char *o0 = Malloc(FILENAME_MAX + 1), *o = o0;
773 int ch;
774 char *b0 = Malloc(FILENAME_MAX + 1), *b = b0;
775 p = p0 = path;
776 while ((ch = *p++)) {
777 if (Yap_dir_separator(ch)) {
778 if (b == b0) {
779 o = o0;
780 } else {
781 b[0] = '\0';
782 o = close_path(b0, o0, o);
783 b = b0;
784 }
785 } else {
786 *b++ = ch;
787 }
788 }
789 if (!Yap_dir_separator(p[-1])) {
790 b[0] = '\0';
791 o = close_path(b0, o0, o);
792 }
793 if (o == o0)
794 *o++ = '/';
795 *o = '\0';
796// __android_log_print(ANDROID_LOG_INFO, "YAPDroid ", " %s at %s, %p-%p", p0, o0,
797// o, o0);
798 return pop_output_text_stack(lvl, o0);
799}
800#endif
801
802static Int p_expand_file_name(USES_REGS1) {
803 Term t = Deref(ARG1);
804 const char *text, *text2;
805
806 if (IsVarTerm(t)) {
807 Yap_Error(INSTANTIATION_ERROR, t, "argument to true_file_name unbound");
808 return FALSE;
809 }
810 int l = push_text_stack();
811 text = Yap_TextTermToText(t);
812 if (!text) {
813 pop_text_stack(l);
814 return false;
815 }
816 if (!(text2 = PlExpandVars(text, NULL))) {
817 pop_text_stack(l);
818 return false;
819 }
820 bool rc = Yap_unify(ARG2, do_glob(text2, true) );
821 pop_text_stack(l);
822 return rc;
823}
824
825static Int true_file_name3(USES_REGS1) {
826 Term t = Deref(ARG1), t2 = Deref(ARG2);
827
828 if (IsVarTerm(t)) {
829 Yap_Error(INSTANTIATION_ERROR, t, "argument to true_file_name unbound");
830 return FALSE;
831 }
832 if (!IsAtomTerm(t)) {
833 Yap_Error(TYPE_ERROR_ATOM, t, "argument to true_file_name");
834 return FALSE;
835 }
836 if (!IsVarTerm(t2)) {
837 if (!IsAtomTerm(t)) {
838 Yap_Error(TYPE_ERROR_ATOM, t2, "argument to true_file_name");
839 return FALSE;
840 }
841 // root = RepAtom(AtomOfTerm(t2))->StrOfAE;
842 }
843 int lvl = push_text_stack();
844 const char *tmp = Yap_AbsoluteFile(RepAtom(AtomOfTerm(t))->StrOfAE, true);
845 Atom at = NULL;
846 bool rc = (tmp != NULL && (at = Yap_LookupAtom(tmp)) != NULL);
847 pop_text_stack(lvl);
848 return rc && Yap_unify(ARG3, MkAtomTerm(at));
849}
850
851static Int path_concat(USES_REGS1) {
852 int l = push_text_stack();
853 size_t len;
854 Term t = Deref(ARG1);
855 Term *tailp;
856 int n = Yap_SkipList(&t, &tailp);
857 if (*tailp != TermNil) {
858 Yap_ThrowError(TYPE_ERROR_LIST, t, "while concatenating sub-paths");
859 }
860 const char **inp = Malloc( (n+1)*sizeof(const char *) );
861 int i=0;
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);
868 }
869 t = TailOfTerm(t);
870 }
871 inp[i] = NULL;
872 len = PATH_MAX;
873 size_t sz;
874 char *buf = Malloc(len);
875 do {
876
877 sz = cwk_path_join_multiple(inp,buf,len-1);
878 if (sz >= len) {
879 len = sz+1;
880 buf = Realloc (buf, len);
881 } else {
882 bool rc= Yap_unify(MkAtomTerm(Yap_LookupAtom(buf)),ARG2);
883 pop_text_stack(l);
884 return rc;
885 }
886 } while (true);
887 }
888
889
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)
901
902#define PAR(x, y, z) z
903
904typedef enum ABSOLUTE_FILE_NAME_enum_ {
905 ABSOLUTE_FILE_NAME_DEFS()
906} absolute_file_name_choices_t;
907
908#undef PAR
909
910#define PAR(x, y, z) \
911 { x, y, z }
912
913static const param_t absolute_file_name_search_defs[] = {
914 ABSOLUTE_FILE_NAME_DEFS()};
915#undef PAR
916
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();
921 /* get options */
922 xarg *args = Malloc(ABSOLUTE_FILE_NAME_END*sizeof(xarg));
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);
927 if (args == NULL) {
928 if (LOCAL_Error_TYPE != YAP_NO_ERROR) {
929 Yap_Error(LOCAL_Error_TYPE, tlist, NULL);
930 }
931 pop_text_stack(lvl);
932 return false;
933 }
934 /* done */
935 if (args[ABSOLUTE_FILE_NAME_EXTENSIONS].used) {
936 t[ABSOLUTE_FILE_NAME_EXTENSIONS] =
937 args[ABSOLUTE_FILE_NAME_EXTENSIONS].tvalue;
938 } else {
939 t[ABSOLUTE_FILE_NAME_EXTENSIONS] = TermNil;
940 }
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);
944 } else {
945 t[ABSOLUTE_FILE_NAME_RELATIVE_TO] = gethdir(TermDot);
946 }
947 if (args[ABSOLUTE_FILE_NAME_FILE_TYPE].used)
948 t[ABSOLUTE_FILE_NAME_FILE_TYPE] = args[ABSOLUTE_FILE_NAME_FILE_TYPE].tvalue;
949 else
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;
953 else
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 );
959 else
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;
963 else
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;
967 else
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;
972 } else
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;
977 else
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));
983}
984
985static Int get_abs_file_parameter(USES_REGS1) {
986 Term t = Deref(ARG1), topts = Deref(ARG2);
987 /* get options */
988 /* done */
989 int i = Yap_ArgKey(AtomOfTerm(t), absolute_file_name_search_defs,
990 ABSOLUTE_FILE_NAME_END);
991 if (i >= 0)
992 return Yap_unify(ARG3, ArgOfTerm(i + 1, topts));
993 Yap_Error(DOMAIN_ERROR_ABSOLUTE_FILE_NAME_OPTION, ARG1, NULL);
994 return false;
995}
996
997
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,
1002 SyncPredFlag);
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);
1011}
Main definitions.
const char * Yap_AbsoluteFile(const char *spec, bool ok)
generate absolute path, if ok first expand SICStus Prolog style
Definition: absf.c:145
int Yap_ArgKey(Atom key, const param_t *def, int n)
Returns the index of an argument key, or -1 if not found.
Definition: args.c:42
void * Malloc(size_t sz USES_REGS)
allocate a temporary text block
Definition: alloc.c:1759
@ source
If true maintain the source for all clauses.
Definition: YapGFlagInfo.h:601
Definition: VFS.h:36
Definition: VFS.h:74
bool(* stat)(struct vfs *, const char *s, vfs_stat *)
close access a directory object
Definition: VFS.h:102
Definition: YapFlags.h:152
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
Definition: text.c:1133