ftr.red 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  1. module ftr; % Various utilities for working with files and modules.
  2. % Author: Anthony C. Hearn.
  3. % NOTE: This module uses Standard Lisp global *RAISE as a fluid.
  4. % This module supports several applications of file-transform.
  5. % Currently we have:
  6. % make-dist-files:
  7. % module_file_split:
  8. % downcase_file:
  9. % trunc:
  10. create!-package('(ftr),'(util));
  11. fluid '(!*echo !*downcase !*upcase current!-char!* previous!-char!*
  12. member!-channel!* old!-channel!*);
  13. global '(!*raise charassoc!*);
  14. global '(dir!*); % output directory name.
  15. % global '(dirchar!*);
  16. switch downcase,upcase;
  17. dir!* := ""; % default.
  18. % dirchar!* := "/";
  19. % ***** utility functions *****.
  20. symbolic procedure s!-match(u,v);
  21. % Returns true if list of characters u begins with same characters
  22. % (regardless of case) as lower case string v.
  23. s!-match1(u,explode2 v);
  24. symbolic procedure s!-match1(u,v);
  25. null v
  26. or u and (car u eq car v
  27. or red!-uppercasep car u
  28. and red!-char!-downcase car u eq car v)
  29. and s!-match1(cdr u,cdr v);
  30. symbolic procedure reverse!-chars!-to!-string u;
  31. compress('!" . reversip('!" . u));
  32. symbolic procedure red!-lowercasep u;
  33. u memq '(!a !b !c !d !e !f !g !h !i !j !k !l !m !n !o !p !q !r !s
  34. !t !u !v !w !x !y !z);
  35. symbolic procedure red!-uppercasep u;
  36. u memq '(!A !B !C !D !E !F !G !H !I !J !K !L !M !N !O !P !Q !R !S !T
  37. !U !V !W !X !Y !Z);
  38. symbolic procedure red!-char!-downcase u;
  39. (if x then cdr x else u) where x = atsoc(u,charassoc!*);
  40. symbolic procedure string!-upcase u;
  41. begin scalar z;
  42. if not stringp u then u := '!" . append(explode2 u,'(!"))
  43. else u := explode u;
  44. for each x in u do z := red!-char!-upcase x . z;
  45. return compress reverse z
  46. end;
  47. symbolic procedure red!-char!-upcase u;
  48. (if x then car x else u) where x = rassoc(u,charassoc!*);
  49. % ***** functions for manipulating regular REDUCE module files *****.
  50. symbolic procedure module_file_split u;
  51. file!-transform(u,function module!-file!-split1);
  52. symbolic procedure module!-file!-split1;
  53. begin scalar x,!*raise;
  54. while not errorp (x := errorset!*('(uread),t))
  55. and (x := car x) neq !$eof!$
  56. and x neq 'END!; do
  57. if x neq 'MODULE then rerror(ftr,1,"Invalid module format")
  58. else begin scalar ochan,oldochan,y;
  59. y := xread t; % Should be module name.
  60. ochan:= open(concat(dir!*,concat(mkfil y,".red")),'output);
  61. oldochan := wrs ochan;
  62. prin2 "module "; prin2 y; prin2 ";";
  63. read!-module();
  64. wrs oldochan;
  65. close ochan
  66. end
  67. end;
  68. symbolic procedure uread;
  69. begin scalar !*raise; !*raise := t; return read() end;
  70. symbolic procedure read!-module;
  71. begin integer eolcount; scalar x,y;
  72. eolcount := 0;
  73. a: if errorp (x := errorset!*('(readch),t))
  74. or (x := car x) = !$eof!$
  75. or eolcount > 20
  76. then rerror(ftr,2,"Invalid module format")
  77. else if x = !$eol!$ then eolcount := eolcount+1
  78. else eolcount := 0;
  79. prin2 x;
  80. if x memq '(!e !E)
  81. then if y = '(L U D O M D N E)
  82. or y = '(!l !u !d !o !m !d !n !e)
  83. then <<prin2 readch();
  84. terpri();
  85. terpri();
  86. prin2t "end;";
  87. return nil>>
  88. else y := list x
  89. else if x memq '(N D M O U L !n !d !m !o !u !l)
  90. then y := x . y
  91. else y := nil;
  92. go to a
  93. end;
  94. symbolic procedure make!-dist!-files u;
  95. % Makes a set of distribution files from the list of packages u.
  96. % Setting u to packages* in $rsrc/build/packages.red makes complete
  97. % set.
  98. for each x in u do make_dist_file x;
  99. symbolic procedure make_dist_file x;
  100. begin scalar !*downcase,!*echo,!*int,!*lower,msg,!*raise,ochan,
  101. oldochan,v;
  102. !*downcase := t;
  103. v := concat(string!-downcase x,".red");
  104. prin2 "Creating ";
  105. prin2 v;
  106. prin2t " ...";
  107. ochan := open(mkfil v,'output);
  108. oldochan := wrs ochan;
  109. evload list x; % To get package list.
  110. v := get(x,'package);
  111. if null v then v := list x;
  112. for each j in v do
  113. file!-transform(module2file(j,x),function write_module);
  114. prin2t if !*downcase then "end;" else "END;";
  115. wrs oldochan;
  116. close ochan
  117. end;
  118. symbolic procedure module2file(u,v);
  119. % Converts the module u to a fully rooted file name with v the
  120. % package name, assuming files exist on $rsrc followed by path
  121. % defined by package given by associate of u in modules!*.
  122. begin scalar x;
  123. x := "$reduce/src/";
  124. for each j in get(v,'path) do
  125. % x := concat(x,concat(string!-downcase j,dirchar!*));
  126. x := concat(x,concat(string!-downcase j,"/"));
  127. return concat(x,concat(string!-downcase u,".red"))
  128. end;
  129. symbolic procedure write_module;
  130. begin scalar x; repeat (x := write!-line nil) until x eq 'done end;
  131. symbolic procedure write!-line bool;
  132. begin integer countr; scalar x,y;
  133. countr := 0;
  134. % EOF kludge.
  135. while (x := readline()) = "" and countr<10 do countr := countr+1;
  136. if countr=10 then return 'done
  137. else if countr>0 then for i:=1:countr do terpri();
  138. y := explode2 x;
  139. if null bool and s!-match(y,"endmodule;")
  140. % or bool and s!-match(x,"end;")
  141. then <<prin2t if !*upcase then string!-upcase x
  142. else if !*downcase then string!-downcase x
  143. else x;
  144. if null bool then <<terpri(); terpri()>>;
  145. return 'done>>;
  146. x := y;
  147. a: if null x then return terpri();
  148. y := car x;
  149. b: if y = '!% then return <<for each j in x do prin2 j; terpri()>>
  150. else if y = '!"
  151. then <<prin2 y;
  152. x := write!-until(cdr x,'(!"))>>
  153. else if y = '!!
  154. then <<prin2 y;
  155. x := cdr x;
  156. if null x then rerror(ftr,3,"Missing character after !");
  157. prin2 car x>>
  158. else if s!-match(x,"comment")
  159. then <<if !*upcase then prin2 "COMMENT" else prin2 "comment";
  160. for j := 1:7 do x := cdr x;
  161. x := write!-until(x,'(!; !$))>>
  162. else if y = '! then
  163. <<countr := 1;
  164. while (x := cdr x) and (y := car x) = '! do
  165. countr := countr + 1;
  166. if null x then return terpri(); % Trailing blanks.
  167. for i:=1:countr do prin2 " ";
  168. go to b>>
  169. else <<prin2 if !*upcase and red!-lowercasep y
  170. then red!-char!-upcase y
  171. else if !*downcase and red!-uppercasep y
  172. then red!-char!-downcase y
  173. else y>>;
  174. x := cdr x;
  175. go to a
  176. end;
  177. symbolic procedure write!-until(x,u);
  178. begin scalar y;
  179. a: if null x
  180. then <<terpri();
  181. x := explode2 readline(); go to a>>;
  182. y := car x;
  183. prin2 y;
  184. if y memq u then return x;
  185. x := cdr x;
  186. go to a
  187. end;
  188. % ***** Converting a file to lower case *****.
  189. symbolic procedure downcase_file u;
  190. % Convert file named u to lower case version.
  191. begin scalar ochan,oldochan,!*downcase,!*echo,!*int,!*raise;
  192. prin2t "*** Output is in file 'output'";
  193. !*downcase := t;
  194. ochan := open("output",'output);
  195. oldochan := wrs ochan;
  196. file!-transform(u,function write!-file);
  197. wrs oldochan;
  198. close ochan
  199. end;
  200. symbolic procedure write!-file;
  201. begin scalar x;
  202. repeat (x := write!-line t) until x eq 'done end;
  203. % ***** truncating a file to 80 characters *****.
  204. symbolic procedure trunc u;
  205. % Truncate a file to 80 characters.
  206. <<lprim "output is in file 'output'";
  207. file!-transform(u,function read!-trunc)>>;
  208. symbolic procedure read!-trunc;
  209. begin integer count;
  210. scalar !*echo,!*int,!*raise,bool,ochan,oldochan,x;
  211. oldochan := wrs (ochan := open("output",'output));
  212. while (x := readch()) neq !$eof!$ do
  213. if x eq !$eol!$ then <<bool := nil; count := 0; terpri()>>
  214. else if null bool
  215. then <<prin2 x; bool := (count := count+1)>79>>;
  216. write oldochan;
  217. close ochan
  218. end;
  219. endmodule;
  220. end;
  221. % The material in the rest of this file is obsolete.
  222. % ***** Functions for manipulating files on the HP 9836 *****.
  223. symbolic procedure merge!-9836!-files u;
  224. % merges a list of 9836 files into a Cambridge format file v
  225. % corresponding to a UNIX directory.
  226. % Files are separated by the string "./ ADD NAME= <file name>.
  227. % Last file is terminated by "./ ENDUP".
  228. begin scalar ochan,oldochan,!*echo,!*int,!*raise;
  229. ochan := open(mkfil u,'output);
  230. oldochan := wrs ochan;
  231. for each x in get(u,'file!-list) do
  232. begin scalar y;
  233. if null(y := get(u,'alias)) then y := u;
  234. y := mkfilename(x,y);
  235. prin2 "./ ADD NAME=";
  236. if atom x then prin2t string!-upcase x
  237. else <<prin2 string!-upcase car x;
  238. prin2 ".";
  239. prin2t string!-upcase cdr x>>;
  240. file!-transform(y,function writefile)
  241. end;
  242. prin2t "./ ENDUP";
  243. wrs oldochan;
  244. close ochan
  245. end;
  246. symbolic procedure mkfilename(u,v);
  247. begin
  248. if atom u then u := u . "red";
  249. return concat(string!-downcase v,
  250. concat(":",concat(string!-downcase car u,
  251. concat(".",
  252. string!-downcase cdr u))))
  253. end;
  254. symbolic procedure writefile;
  255. begin scalar countr,x;
  256. countr := 0;
  257. repeat
  258. <<x := readline();
  259. if x = "" then countr := countr+1
  260. else <<if countr>0
  261. then <<for i:=1:countr do terpri(); countr := 0>>;
  262. prin2t x>>>>
  263. until countr = 10;
  264. end;
  265. % ***** functions for manipulating Cambridge PDS files *****.
  266. % To use the first function, connect to the directory where you want the
  267. % modules written, and then say
  268. % file!-transform("<source file>",
  269. % function split!-cambridge!-format);
  270. symbolic smacro procedure read!-ch(); current!-char!* := readch();
  271. symbolic procedure split!-cambridge!-format;
  272. % splits a file in Cambridge PDS format with ./ ADD records preceding
  273. % each member into constituent components.
  274. begin scalar x,!*echo,!*raise;
  275. while not((x := read!-ch()) eq !$eof!$) do
  276. if not previous!-char!*
  277. then if x eq '!. and readch() eq '!/
  278. then begin!-new!-cambridge!-member()
  279. else rerror(ftr,4,
  280. "File has incorrect format in first line")
  281. else if previous!-char!* eq !$eol!$ and x eq '!.
  282. then if read!-ch() eq '!/
  283. then begin!-new!-cambridge!-member()
  284. else rerror(ftr,5,
  285. "File has unmatched period in first column")
  286. else <<prin2 x; previous!-char!* := x>>;
  287. close!-cambridge!-member()
  288. end;
  289. symbolic procedure begin!-new!-cambridge!-member;
  290. begin scalar x,y,z;
  291. if member!-channel!* then close!-cambridge!-member();
  292. z := readline();
  293. x := cdr explode z;
  294. previous!-char!* := !$eol!$;
  295. if not ( x := matched2(x,'(! A D D ! N A M E !=)))
  296. then <<terpri(); prin2 "Ignoring line ./"; prin2 z; terpri();
  297. return nil>>;
  298. x := car x;
  299. while cdr x do
  300. <<y := (if red!-uppercasep car x then red!-char!-downcase car x
  301. else if car x eq '!$ then '!@
  302. else car x) . y;
  303. x := cdr x>>;
  304. y := reverse!-chars!-to!-string y;
  305. terpri();
  306. prin2 "Processing module "; prin2 y; prin2t " ...";
  307. y := concat(y,".red");
  308. member!-channel!* := open(y,'output);
  309. old!-channel!* := wrs member!-channel!*
  310. end;
  311. symbolic procedure matched2(u,v);
  312. if null v then list u
  313. else if null u then nil
  314. else car u eq car v and matched2(cdr u,cdr v);
  315. symbolic procedure close!-cambridge!-member;
  316. if not member!-channel!* then nil
  317. else <<close member!-channel!*; wrs old!-channel!*;
  318. member!-channel!* := old!-channel!* := nil>>;
  319. symbolic procedure merge!-cambridge!-format(u,v);
  320. % merges a list of files u into Cambridge PDS format file v
  321. % with ./ ADD records preceding each member.
  322. begin scalar ochan,oldochan,!*echo,!*raise;
  323. ochan := open(mkfil v,'output);
  324. oldochan := wrs ochan;
  325. for each x in u do write!-cambridge!-member x;
  326. prin2t "./ ENDUP";
  327. wrs oldochan;
  328. close ochan
  329. end;
  330. symbolic procedure write!-cambridge!-member u;
  331. begin scalar y;
  332. u := explode2 u;
  333. for each x in u do y := red!-char!-downcase x . y;
  334. y := concat(reverse!-chars!-to!-string y,".red"); %file name.
  335. y := concat(dir!*,y);
  336. prin2 "./ ADD NAME=";
  337. if eqcar(u,'!@) then u := '!$ . cdr u;
  338. for each x in u do prin2 x;
  339. terpri();
  340. file!-transform(y,function print!-cambridge!-file)
  341. end;
  342. symbolic procedure print!-cambridge!-file;
  343. begin scalar x;
  344. while not((x := readch()) eq !$eof!$) do
  345. % if x eq '![ then prin2 string 0 % PSL dependent
  346. % else if x eq '!] then prin2 string 4 else % PSL dependent
  347. prin2 x
  348. end;
  349. % ***** and to manipulate a message from Cambridge *****.
  350. % Note this code is PSL dependent.
  351. symbolic procedure cambs!-msg u;
  352. <<lprim "output is in file 'output'";
  353. file!-transform(u,function read!-cambridge!-message)>>;
  354. symbolic procedure read!-cambridge!-message;
  355. begin scalar !*echo,!*int,!*raise,ochan,oldochan,x;
  356. oldochan := wrs (ochan := open("output",'output));
  357. while (x := readch()) neq !$eof!$ do
  358. if x eq intern string 13 % PSL dependent
  359. then if readch() neq intern string 11 % PSL dependent
  360. then rerror(ftr,8,"missing ^L after ^M")
  361. else terpri()
  362. else prin2 x;
  363. wrs oldochan;
  364. close ochan
  365. end;
  366. % ***** functions for manipulating mfe document files *****.
  367. symbolic procedure mfe!-6to8bit(u,v);
  368. % converts six-bit file u into eight-bit file v.
  369. begin scalar ochan,oldochan;
  370. oldochan := wrs (ochan := open(v,'output));
  371. file!-transform(u,function mfe!-6to8bit1);
  372. wrs oldochan;
  373. close ochan
  374. end;
  375. symbolic procedure mfe!-6to8bit1;
  376. begin scalar oll,x,y;
  377. oll := linelength 100;
  378. while (x := readch()) neq !$eof!$ do
  379. if x eq '!^
  380. then if red!-uppercasep(y := readch()) then prin2 y
  381. else if y eq '![ then '!{
  382. else if y eq '!] then '!}
  383. else <<prin2 x; prin2 y>>
  384. else if x eq '!&
  385. then if (y := readch()) eq '!& then prin2 y
  386. else if y eq 'e
  387. and readch() eq 'p and readch() eq 'x
  388. then prin2 '!!
  389. else if y eq 'v
  390. and (y := readch()) and readch() eq 'x
  391. then prin2 y
  392. else if y eq 'f
  393. and readch() eq 'u and readch() eq 'x
  394. then prin2 '!|
  395. else if y eq 'i then prin2 "\&i"
  396. else rerror(ftr,9,"Invalid character after &")
  397. else if x eq '!$ then prin2 "\$"
  398. else if x eq '!% then prin2 "\%"
  399. else if red!-uppercasep x then prin2 red!-char!-downcase x
  400. else prin2 x;
  401. linelength oll
  402. end;
  403. symbolic procedure mfe!-8to6bit(u,v);
  404. % converts eight-bit file u into six-bit file v.
  405. begin scalar ochan,oldochan;
  406. oldochan := wrs (ochan := open(v,'output));
  407. file!-transform(u,function mfe!-8to6bit1);
  408. wrs oldochan;
  409. close ochan
  410. end;
  411. symbolic procedure mfe!-8to6bit1;
  412. begin scalar !*raise,oll,x;
  413. oll := linelength 160;
  414. while (x := readch()) neq !$eof!$ do
  415. if x eq '!& then prin2 "&&"
  416. else if x eq '!\ then prin2 readch()
  417. else if x eq '!! then prin2 "&EPX"
  418. else if x eq '!$ then prin2 "&V$X"
  419. else if x eq '!% then prin2 "&V%X"
  420. else if x eq '!| then prin2 "$FUX"
  421. else if x eq '!{ then prin2 "^["
  422. else if x eq '!} then prin2 "^]"
  423. else if red!-uppercasep x then <<prin2 '!^; prin2 x>>
  424. else if red!-lowercasep x then prin2 red!-char!-upcase x
  425. else prin2 x;
  426. linelength oll
  427. end;