psl.red 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609
  1. module psl;
  2. % Redistribution and use in source and binary forms, with or without
  3. % modification, are permitted provided that the following conditions are met:
  4. %
  5. % * Redistributions of source code must retain the relevant copyright
  6. % notice, this list of conditions and the following disclaimer.
  7. % * Redistributions in binary form must reproduce the above copyright
  8. % notice, this list of conditions and the following disclaimer in the
  9. % documentation and/or other materials provided with the distribution.
  10. %
  11. % THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  12. % AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  13. % THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  14. % PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNERS OR
  15. % CONTRIBUTORS
  16. % BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  17. % CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  18. % SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  19. % INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  20. % CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  21. % ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  22. % POSSIBILITY OF SUCH DAMAGE.
  23. %
  24. % $Id$
  25. imports big2sys, bigp, floatloworder, floathighorder, gtneg, gtpos,
  26. i2bf!:, idifference, igetv, ilessp, iminus, inf, iplus, isub1,
  27. itimes, land, lshift, make!:ibf, neq, sys2int, trimbignum,
  28. vecinf, veclen, wand, wdifference, wminus, wor, wplus2, wputv,
  29. wquotient, wshift;
  30. exports ashift, msd!:, fl2bf, integerp!:, normbf, oddintp, preci!:;
  31. fluid '(bbits!* dirchar!* outputhandler!* !*gc!-hook!* lessspace!*);
  32. global '(bfz!* bitsperword tempdir!*);
  33. !#if (intersection '(dos os2 winnt alphant win32 win64 cygwin) lispsystem!*)
  34. dirchar!* := "\";
  35. tempdir!* := getenv "TMP" or getenv "TEMP";
  36. !#else
  37. dirchar!* := "/";
  38. tempdir!* := "/tmp";
  39. !#endif
  40. compiletime
  41. global '(!!fleps1exp !!plumaxexp !!pluminexp !!timmaxexp !!timminexp);
  42. remflag ('(ashift msd!: fl2bf ff0 ff1
  43. bf!-bits bf!-bits!-mask integerp!: normbf oddintp preci!:),
  44. 'lose);
  45. flag('(cond),'eval); % Enable conditional compilation.
  46. %-------------------------------------------------------------------
  47. !#if (member 'ieee lispsystem!*)
  48. % % The following routines support fast float operations by exploiting
  49. % % the IEEE number format explicitly.
  50. %
  51. % compiletime
  52. % if 'ieee member lispsystem!* then
  53. % remflag('(safe!-fp!-plus safe!-fp!-times safe!-fp!-quot),'lose)
  54. % else
  55. % flag('(safe!-fp!-plus safe!-fp!-times safe!-fp!-quot),'lose);
  56. % Currently 32 and 64 bit IEEE machines are supported.
  57. %
  58. % The following macros assume that on 64 bit machines floathighorder
  59. % and floatloworder both load the full 64 bit floating point number.
  60. % The version here has been adjusted by ACN who was simultaneously
  61. % working on the corresponding code within CSL - the aim is that the
  62. % two Lisp systems behave identically. And the adjusted code here
  63. % will be able to use machine floating point arithmetic in a number of cases
  64. % that the previous version of the code could not.
  65. compiletime
  66. <<
  67. define!-constant(ieeeshift,12 - bitsperword); % 32 bits:-20
  68. define!-constant(signshift,1 - bitsperword); % 32 bits:-31
  69. define!-constant(ieeebias,1023);
  70. define!-constant(ieeemask,2047);
  71. define!-constant(ieeemaxexp,1024);
  72. define!-constant(ieeeminexp,-1023);
  73. ds(floathiword,x(),floathighorder inf x);
  74. ds(floatloword,x(),floatloworder inf x);
  75. ds(ieeeexpt,u(),
  76. wdifference(wand(ieeemask,
  77. wshift(floathiword u,ieeeshift)),
  78. ieeebias));
  79. ds(ieeesign,u(),wshift(floathiword u,signshift));
  80. % ieeemant is the mantissa part of the upper 32 bit group.
  81. if bitsperword=32 then
  82. <<
  83. ds(ieeemant,f(),
  84. (lor(lshift(
  85. wor(wshift(wand (floathiword f, 1048575), % 16#FFFFF
  86. 6),
  87. wshift(lf,-26)),
  88. 26),
  89. wand(lshift(-1,-6), lf))
  90. where lf := floatloword f));
  91. % IEEE zero may have the sign bit set to indicate -0.0,
  92. % so shift the leftmost bit off the machine word before comparing with 0
  93. ds(ieeezerop,u(), weq(0,wshift(floathiword u,1)) and weq(0,floatloword u));
  94. ds(ieeeequal,u2(v),
  95. weq(floathiword u2,floathiword v)
  96. and weq(floatloword u2,floatloword v)
  97. and not(weq(ieeeexpt u2,ieeemaxexp,1024) and wneq(ieeemant u2,0))
  98. and not(weq(ieeeexpt v, ieeemaxexp,1024) and wneq(ieeemant v, 0)));
  99. >>
  100. else if bitsperword=64 then
  101. <<
  102. ds(ieeemant,f(), wand (floathiword f,
  103. 4503599627370495)); % 16#FFFFFFFFFFFFF
  104. ds(ieeezerop,u(), weq(0,wshift(floathiword u,1)));
  105. ds(ieeeequal,u2(v),
  106. weq(floathiword u2,floathiword v)
  107. and not(weq(ieeeexpt u2,ieeemaxexp,1024) and wneq(ieeemant u2,0))
  108. and not(weq(ieeeexpt v, ieeemaxexp,1024) and wneq(ieeemant v, 0)));
  109. >>
  110. else error(99,"#### unknown bit size");
  111. % define!-constant(!!plumaxexp,1018);
  112. % define!-constant(!!pluminexp,-979);
  113. % define!-constant(!!timmaxexp,509);
  114. % define!-constant(!!timminexp,-510);
  115. % define!-constant(!!fleps1exp,-40)
  116. >>;
  117. symbolic procedure float!-is!-finite x;
  118. floatp x and ieeeexpt x < ieeemaxexp;
  119. symbolic procedure float!-is!-nan x;
  120. floatp x and ieeeexpt x = ieeemaxexp and ieeemant x neq 0;
  121. symbolic procedure float!-is!-infinite x;
  122. floatp x and ieeeexpt x = ieeemaxexp and ieeemant x = 0;
  123. symbolic procedure float!-is!-subnormal x;
  124. floatp x and ieeeexpt x = 0;
  125. symbolic procedure float!-is!-negative x;
  126. floatp x and not(0 eq ieeesign x);
  127. !#else
  128. symbolic procedure float!-is!-finite x; t;
  129. symbolic procedure float!-is!-nan x; nil;
  130. symbolic procedure float!-is!-infinite x; nil;
  131. symbolic procedure float!-is!-subnormal x; nil;
  132. symbolic procedure float!-is!-negative x; floatp x and minusp x;
  133. !#endif
  134. remflag('(fp!-infinite fp!-nan fp!-finite fp!-subnorm fp!-signbit),'lose);
  135. symbolic inline procedure fp!-infinite x;
  136. float!-is!-infinite x;
  137. symbolic inline procedure fp!-nan x;
  138. float!-is!-nan x;
  139. symbolic inline procedure fp!-finite x;
  140. float!-is!-finite x;
  141. symbolic inline procedure fp!-subnorm x;
  142. float!-is!-subnormal x;
  143. symbolic inline procedure fp!-signbit x;
  144. float!-is!-negative x;
  145. flag('(fp!-infinite fp!-nan fp!-finite fp!-subnorm fp!-signbit),'lose);
  146. %---------------------------------------------------------------
  147. deflist('((iminus iminus)),'unary);
  148. symbolic inline procedure ashift (m,d);
  149. if and(numberp m, m < 0) then -lshift(-m,d) else lshift(m,d);
  150. symbolic inline procedure oddintp x;
  151. wand(if bigp x then wgetv(inf x,2)
  152. else if fixnp x then fixval inf x
  153. else x,1) eq 1;
  154. symbolic macro procedure bf!-bits (x); {'quote, bbits!*};
  155. %symbolic macro procedure bf!-bits!-mask (x);
  156. % {'quote, lshift(1, bf!-bits()) - 1};
  157. %symbolic procedure ff1 (w,n);
  158. % if n eq 0 then w else
  159. % if wshift (w, wminus n) eq 0 then
  160. % ff1 (w,wquotient(n,2))
  161. % else iplus2(ff1 (wshift (w, wminus n),wquotient(n,2)),n) ;
  162. symbolic inline procedure ff1 (ww,nn);
  163. <<while not (n eq 0) do <<
  164. x := wshift(w,wminus n);
  165. if not (x eq 0) then % left half
  166. << w := x; y := iplus2(y,n) >>; % Iplus2 etc. used for
  167. n := wquotient (n,2) % bootstrapping.
  168. >>;
  169. iplus2(y,w) >>
  170. where w=ww,n=nn,x=nil,y=0;
  171. %symbolic procedure ff0 (w,n);
  172. %% returns the number of 0 bits at the least significant end
  173. % if n eq 0 then w else
  174. % begin scalar lo;
  175. % lo := wand(w,isub1 wshift(1,n));
  176. % return if lo eq 0
  177. % then iplus2(n,ff0 (wshift(w,wminus n),wquotient(n,2)))
  178. % else ff0 (lo,wquotient(n,2)) ;
  179. % end;
  180. COMMENT ff0 determines the number of 0 bits at the least significant
  181. end of an integer, ie. the largest power of two by which the
  182. integer is divisible;
  183. compiletime put('hu_hu_hu,'opencode,'((!*move (reg 1) (reg 1))));
  184. symbolic inline procedure ff0 (ww,nn);
  185. <<while not (n eq 0) do <<
  186. lo := wand(w,isub1 wshift(1,n));
  187. if lo eq 0 then % left half
  188. << w := wshift(w,wminus n);
  189. y := iplus2(y,n) >>; % Iplus2 etc. used for
  190. n := wquotient (n,2) % bootstrapping.
  191. >>;
  192. if not eq(w,0) then << w := 17; hu_hu_hu (w); y >> else iadd1 y >>
  193. % we have to destroy w for gc !!
  194. where w=ww,n=nn,lo=nil,y=0;
  195. % use wshift(bitsperword,-1) rather than bitsperword/2 as the former
  196. % is open compiled
  197. COMMENT we split msd!: into two parts: one for bignums, one for
  198. machine words. That will greatly reduce the size of preci!:
  199. below;
  200. symbolic inline procedure word!-msd!: u;
  201. ff1(u,wshift(bitsperword,-1));
  202. symbolic inline procedure big!-msd!: u;
  203. iplus2(itimes2(bf!-bits(),isub1 s),word!-msd!: igetv(u,s))
  204. where s := veclen vecinf u;
  205. symbolic inline procedure msd!: u;
  206. if bigp u then big!-msd!: u
  207. else if fixnp u then word!-msd!: fixval inf u
  208. else word!-msd!: u;
  209. %symbolic inline procedure msd!: u;
  210. % % returns the most significant (binary) digit of a positive integer u
  211. % if bigp u
  212. % then iplus2(itimes2(bf!-bits(),isub1 s),
  213. % ff1(igetv(u,s),wshift(bitsperword,-1)))
  214. % where s := veclen vecinf u
  215. % else if fixnp u then ff1 (fixval inf u,wshift(bitsperword,-1))
  216. % else ff1 (u,wshift(bitsperword,-1));
  217. symbolic inline procedure mt!: u; cadr u;
  218. symbolic inline procedure ep!: u; cddr u;
  219. symbolic inline procedure preci!: nmbr;
  220. % This function counts the precision of a number "n". NMBR is a
  221. % binary bigfloat representation of "n".
  222. % msd!: abs mt!: nmbr
  223. (if bigp m then big!-msd!: m
  224. else if fixnp m
  225. then (word!-msd!:(if iminusp n then iminus n else n)
  226. where n = fixval inf m)
  227. else if iminusp m then word!-msd!:(iminus m)
  228. else word!-msd!: m)
  229. where m = mt!: nmbr;
  230. %symbolic inline procedure preci!: nmbr;
  231. % % This function counts the precision of a number "n". NMBR is a
  232. % % binary bigfloat representation of "n".
  233. % % msd!: abs mt!: nmbr
  234. % (if bigp m then msd!: m
  235. % else if fixnp m
  236. % then (ff1(if iminusp n then iminus n else n,
  237. % wshift(bitsperword,-1))
  238. % where n = fixval inf m)
  239. % else if iminusp m then ff1(iminus m,wshift(bitsperword,-1))
  240. % else ff1(m,wshift(bitsperword,-1)))
  241. % where m = mt!: nmbr;
  242. remflag('(make!:ibf), 'lose);
  243. symbolic inline procedure make!:ibf (mt, ep);
  244. '!:rd!: . (mt . ep);
  245. flag('(make!:ibf), 'lose);
  246. if not('ieee memq lispsystem!*) then
  247. flag('(fl2bf),'lose);
  248. % Use "!#if" not "#if" for bootstrapping reasons.
  249. !#if (eq bitsperword 64)
  250. symbolic procedure fl2bf f;
  251. % u is a floating point number
  252. % result is a binary bigfloat
  253. if fixp f then i2bf!: f
  254. else begin scalar m,e;
  255. m := ieeemant f;
  256. e := ieeeexpt f;
  257. % if exponent <> -1023 add 16#10000000000000, implicit highest bit
  258. if e neq -1023 then m := lor (m, lshift(1,52));
  259. return
  260. if izerop m then bfz!*
  261. else normbf make!:ibf (if ieeesign f eq 1 then -m else m,
  262. idifference(e,52))
  263. end;
  264. !#else
  265. symbolic procedure fl2bf f;
  266. % u is a floating point number
  267. % result is a binary bigfloat
  268. if fixp f then i2bf!: f
  269. else begin scalar m,e;
  270. m:=
  271. lor(lshift(
  272. wor(wshift(wand (floathiword f, 1048575), % 16#FFFFF
  273. 6),
  274. wshift(floatloword f,-26)),
  275. 26),
  276. wand(lshift(-1,-6), floatloword f));
  277. %% m := ieeemant f;
  278. e := ieeeexpt f;
  279. % if exponent <> -1023 add 16#10000000000000, implicit highest bit
  280. if e neq -1023 then m := lor (m, lshift(1,52));
  281. return
  282. if izerop m then bfz!*
  283. else normbf make!:ibf (if ieeesign f eq 1 then -m else m,
  284. idifference(e,52))
  285. end;
  286. !#endif
  287. symbolic procedure normbf x;
  288. begin scalar mt,s;integer ep,ep1;
  289. if (mt := mt!: x)=0 then go to ret;
  290. if mt<0 then <<mt := -mt; s := t>>;
  291. ep := ep!: x;
  292. % ep1 := remainder(ep,bf!-bits());
  293. % if ep1 < 0 then ep1 := ep1 + bf!-bits();
  294. % if ep1 neq 0 then <<ep := ep - ep1; mt := lshift(mt,ep1)>>;
  295. while bigp mt and wgetv(inf mt,2) eq 0 do <<
  296. mt := lshift(mt,-bf!-bits());
  297. ep := ep+bf!-bits() >>;
  298. ep1 := ff0(if bigp mt then wgetv(inf mt,2)
  299. else if fixnp mt then fixval inf mt
  300. else mt,wshift(bitsperword,-1));
  301. if not (ep1 eq 0) then <<mt := lshift(mt,wminus ep1);
  302. ep := ep + ep1>>;
  303. if s then mt := -mt;
  304. ret: return make!:ibf(mt,ep) end;
  305. symbolic procedure integerp!: x;
  306. % This function returns T if X is a BINARY BIG-FLOAT
  307. % representing an integer, else it returns NIL.
  308. % X is any LISP entity.
  309. bfp!: x and
  310. (ep!: x >= 0 or
  311. preci!: x > - ep!: x and
  312. land(abs mt!: x,lshift(2,-ep!: x) - 1) = 0);
  313. flag ('(ashift lshift msd!: fl2bf ff0 ff1
  314. bf!-bits bf!-bits!-mask integerp!: normbf oddintp preci!:),
  315. 'lose);
  316. if not('ieee memq lispsystem!*) then remflag('(fl2bf),'lose);
  317. % This belong in $pxu/nbig30a.
  318. symbolic(bigfloathi!* := (2 ** 53 - 1) * 2 ** 971);
  319. symbolic(bigfloatlow!* := - bigfloathi!*);
  320. remflag('(cond),'eval);
  321. % Put in some CSL compatibility here...
  322. symbolic inline procedure princ x; prin2 x;
  323. symbolic inline procedure prin x; prin1 x;
  324. symbolic inline procedure printc x; << prin2 x; terpri(); x >>;
  325. symbolic procedure ttab n;
  326. while posn() < n do prin2 " ";
  327. symbolic inline procedure list!-to!-vector a; list2vector a;
  328. symbolic procedure hexdig w;
  329. cdr assoc(w, '((0 . !0) (1 . !1) (2 . !2) (3 . !3)
  330. (4 . !4) (5 . !5) (6 . !6) (7 . !7)
  331. (8 . !8) (9 . !9) (10 . !a) (11 . !b)
  332. (12 . !c) (13 . !d) (14 . !e) (15 . !f)));
  333. symbolic procedure explodehex n;
  334. begin
  335. % Only for use with integers
  336. scalar r, s;
  337. if n = 0 then return "0";
  338. if n < 0 then << n := -n; s = t >>;
  339. while not zerop n do <<
  340. r := hexdig remainder(n, 16) . r;
  341. n := n / 16 >>;
  342. if s then r := '!- . r;
  343. return r
  344. end;
  345. symbolic procedure plist x;
  346. prop x;
  347. symbolic procedure symbol!-name x;
  348. id2string x;
  349. % A function to expand a filename glob (pattern) via a pipe
  350. % A couple of tricky issues here:
  351. % a) set *raise to nil so that upper case characters in strings are not changed to lower case
  352. % b) Unix Bourne shell returns the pattern string if no match, so check for this
  353. % [2021: note that !*raise is now fluid so can be rebount to nil and that
  354. % means that unwind-protect is no longer needed.]
  355. symbolic procedure glob!-filenames pat;
  356. if not stringp pat then rederr " glob!-filenames needs a string parameter"
  357. else begin scalar cmd,chan,oldchan,filelist,strbuf,chr,!*raise;
  358. !#if (or (memq 'win32 lispsystem!*) (memq 'win64 lispsystem!*) (memq 'cygwin lispsystem!*))
  359. cmd := "cmd /C FOR %%H IN (%w) DO @ECHO %%H";
  360. !#else
  361. cmd := "sh -c 'for h in %w ; do echo $h ;done'";
  362. !#endif
  363. cmd := bldmsg(cmd,pat);
  364. chan := pipe!-open(cmd,'input);
  365. if chan=0 then return rederr "error opening pipe";
  366. oldchan := rds chan;
  367. strbuf := nil;
  368. while (chr := readch()) neq !$eof!$ do <<
  369. if chr neq !$eol!$
  370. then strbuf := chr . strbuf % collect character for filename
  371. else << % eol - finish filename
  372. filelist := (list2string reversip strbuf) . filelist;
  373. strbuf := nil>> >>;
  374. close rds oldchan;
  375. !#if (not (or (memq 'win32 lispsystem!*) (memq 'win64 lispsystem!*) (memq 'cygwin lispsystem!*)))
  376. if null cdr filelist and car filelist = pat then return nil;
  377. !#endif
  378. return reversip filelist
  379. end;
  380. symbolic procedure delete!-file!-wildcard pat;
  381. if not stringp pat then nonstringerror(pat,'delete!-file!-wildcard)
  382. else for each fi in glob!-filenames pat do delete!-file fi;
  383. % emulate delete!-file via an external command if not defined in PSL
  384. symbolic procedure delete!-file!-slow fi;
  385. !#if (or (memq 'win32 lispsystem!*) (memq 'win64 lispsystem!*) (memq 'cygwin lispsystem!*))
  386. filep fi and system bldmsg("del ""%s""",fi);
  387. !#else
  388. system bldmsg("rm -f %s", fi);
  389. !#endif
  390. loadtime if not getd 'delete!-file then copyd('delete!-file,'delete!-file!-slow);
  391. % HP-Risc and IBM RS architectures need special handling of fltinf in
  392. % fastmath.red
  393. if 'hp!-risc member lispsystem!* then
  394. <<remflag('(fltinf),'lose);
  395. ds(fltinf,x(),mkitem(vector!-tag,x));
  396. flag('(fltinf),'lose)>>;
  397. if 'ibmrs member lispsystem!* then
  398. <<remflag('(fltinf),'lose);
  399. ds(fltinf,x(),mkstr x);
  400. flag('(fltinf),'lose)>>;
  401. % find path to gnuplot executable
  402. global '(!*gnuplot_name!*);
  403. !#if (intersection '(dos os2 winnt alphant win32 win64 cygwin) lispsystem!*)
  404. !*gnuplot_name!* := "gnuplot.exe";
  405. !#else
  406. !*gnuplot_name!* := "gnuplot";
  407. !#endif
  408. symbolic procedure find!-gnuplot;
  409. begin scalar path;
  410. % first check environment variable gnuplot
  411. path := find!-gnuplot!-aux getenv("GNUPLOT");
  412. if path then return find!-gnuplot!-quotify path;
  413. !#if (intersection '(winnt alphant win32 win64 cygwin) lispsystem!*)
  414. % if on windows, check registry
  415. path := get!-registry!-value("HKLM","Software\Microsoft\Windows\CurrentVersion\App Paths\gnuplot.exe",nil);
  416. if path and car path = 1 and filep cdr path
  417. then return find!-gnuplot!-quotify cdr path;
  418. !#endif
  419. % last resort: return the name without path
  420. return find!-gnuplot!-quotify !*gnuplot_name!*;
  421. end;
  422. symbolic procedure find!-gnuplot!-quotify path;
  423. %
  424. % for Windows, put double quotes around path
  425. %
  426. !#if (intersection '(winnt alphant win32 win64 cygwin) lispsystem!*)
  427. concat("""",concat(path,""""));
  428. !#else
  429. path;
  430. !#endif
  431. symbolic procedure find!-gnuplot!-aux path;
  432. %
  433. % check that dirpath path contains gnuplot executable
  434. %
  435. if null path then nil
  436. else <<
  437. if idp path then path := id2string path;
  438. % remove trailing directory separator if present
  439. if subseq(path,isub1 string!-length path, string!-length path) member '(!\ !/)
  440. then path := subseq(path,0,isub1 string!-length path);
  441. % build path
  442. path := bldmsg("%w%w%w",path,dirchar!*,!*gnuplot_name!*);
  443. % check existence
  444. (filep path and path)>>;
  445. !#if (intersection '(dos os2 winnt alphant win32 win64 cygwin) lispsystem!*)
  446. % When the Windows version of PSL is launched from a cygwin (mintty) shell
  447. % it can be that neither TEMP nor TMP is set. Under cygwin the directory
  448. % "/tmp" should be available but the path to it required by Reduce will
  449. % be something like "C:\cygwin\tmp" and the exact location that cygwin
  450. % had been installed in may vary from case to case. The code here tries
  451. % to sort this out!
  452. global '(cygwin_tmp!*);
  453. cygwin_tmp!* := nil;
  454. symbolic procedure tempdir_for_cygwin();
  455. begin
  456. scalar a, b, c;
  457. % I will only make the tests here once (if they succeed).
  458. if cygwin_tmp!* then return cygwin_tmp!*;
  459. % The next line will generate output like "sh: 1: cygpath: not found" if
  460. % cygpath is not available, and something like "c:\cygwin\tmp" if it is!
  461. a := errorset('(pipe!-open "cygpath -w /tmp 2>&1" 'input), nil, nil);
  462. if not errorp a then <<
  463. b := rds car a;
  464. c := readline();
  465. rds b;
  466. close car a >> where !*echo = nil;
  467. a := explode2 c;
  468. % I will assume that if the result ended up as "x:\..." for some x that it
  469. % was valid.
  470. if a and eqcar(cdr a, '!:) and eqcar(cddr a, '!\) then
  471. return (cygwin_tmp!* := c)
  472. else return nil
  473. end;
  474. !#endif
  475. symbolic procedure get!-tempdir();
  476. begin
  477. !#if (intersection '(dos os2 winnt alphant win32 win64 cygwin) lispsystem!*)
  478. tempdir!* := getenv "TMP" or getenv "TEMP";
  479. if null tempdir!* then tempdir!* := tempdir_for_cygwin();
  480. !#else
  481. !#if (member 'vms lispsystem!*)
  482. tempdir!* := "SYS$SCRATCH:";
  483. !#else
  484. tempdir!* := "/tmp";
  485. !#endif
  486. !#endif
  487. return tempdir!*;
  488. end;
  489. endmodule;
  490. end;