fileio.sl 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  1. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2. %
  3. % FileIO.SL
  4. %
  5. % Author: Alan Snyder
  6. % Hewlett-Packard/CRC
  7. % Date: 17 September 1982
  8. % Revised: 4 February 1983
  9. %
  10. % File I/O for NMODE.
  11. %
  12. % 4-Feb-83 Alan Snyder
  13. % Added functions for deleting/undeleting files and writing a message.
  14. % Find-file-in-buffer changed incompatibly to make it more useful.
  15. % Use nmode-error to report errors.
  16. % 1-Feb-83 Alan Snyder
  17. % Added separate default string for Insert File command.
  18. % 27-Dec-82 Alan Snyder
  19. % Removed runtime LOAD statements, for portability.
  20. %
  21. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  22. (CompileTime (load objects fast-strings pathnames))
  23. % External Variables:
  24. (fluid '(nmode-selectable-buffers nmode-current-buffer nmode-screen
  25. nmode-command-argument-given nmode-current-window Text-Mode
  26. ))
  27. % Internal static variables:
  28. (fluid '(text-io-default-fn insert-file-default-fn))
  29. (setf text-io-default-fn NIL)
  30. (setf insert-file-default-fn NIL)
  31. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  32. % File commands:
  33. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  34. (de visit-file-command ()
  35. % Ask for and read in a file.
  36. (let ((fn (prompt-for-defaulted-filename "Visit File: " NIL)))
  37. (visit-file nmode-current-buffer fn)
  38. ))
  39. (de insert-file-command ()
  40. % Ask for and read a file, inserting it into the current buffer.
  41. (setf insert-file-default-fn
  42. (prompt-for-file-name "Insert File: " insert-file-default-fn))
  43. (insert-file-into-buffer nmode-current-buffer insert-file-default-fn)
  44. )
  45. (de write-file-command ()
  46. % Ask for filename, write out the buffer to the file.
  47. (write-buffer-to-file
  48. nmode-current-buffer
  49. (prompt-for-defaulted-filename "Write File:" NIL)))
  50. (de save-file-command ()
  51. % Save current buffer on its associated file, ask for file if unknown.
  52. (cond
  53. ((not (=> nmode-current-buffer modified?))
  54. (write-prompt "(No changes need to be written)"))
  55. (t (save-file nmode-current-buffer))))
  56. (de save-file-version-command ()
  57. % Save current buffer on its associated file, ask for file if unknown.
  58. % The file is written using the current version number.
  59. (cond
  60. ((not (=> nmode-current-buffer modified?))
  61. (write-prompt "(No changes need to be written)"))
  62. (t (save-file-version nmode-current-buffer))))
  63. (de find-file-command ()
  64. % Ask for filename and then read it into a buffer created especially for that
  65. % file, or select already existing buffer containing the file.
  66. (find-file (prompt-for-defaulted-filename "Find file: " NIL))
  67. )
  68. (de write-screen-photo-command ()
  69. % Ask for filename, write out the screen to the file.
  70. (write-screen-photo (prompt-for-file-name "Write Photo to File: " NIL)))
  71. (de write-region-command ()
  72. % Ask for filename, write out the region to the file.
  73. (write-text-to-file
  74. (cdr (extract-region NIL (buffer-get-position) (current-mark)))
  75. (setf text-io-default-fn
  76. (prompt-for-file-name "Write Region to File:" text-io-default-fn))))
  77. (de prepend-to-file-command ()
  78. % Ask for filename, prepend the region to the file.
  79. (prepend-text-to-file
  80. (cdr (extract-region NIL (buffer-get-position) (current-mark)))
  81. (setf text-io-default-fn
  82. (prompt-for-file-name "Prepend Region to File:" text-io-default-fn))))
  83. (de append-to-file-command ()
  84. % Ask for filename, append the region to the file.
  85. (append-text-to-file
  86. (cdr (extract-region NIL (buffer-get-position) (current-mark)))
  87. (setf text-io-default-fn
  88. (prompt-for-file-name "Append Region to File:" text-io-default-fn))))
  89. (de delete-file-command ()
  90. (nmode-delete-file (prompt-for-defaulted-filename "Delete File:" NIL)))
  91. (de delete-and-expunge-file-command ()
  92. (nmode-delete-and-expunge-file
  93. (prompt-for-defaulted-filename "Delete and Expunge File:" NIL)))
  94. (de undelete-file-command ()
  95. (nmode-undelete-file (prompt-for-defaulted-filename "Undelete File:" NIL)))
  96. (de save-all-files-command ()
  97. % Save all files. Ask first, unless arg given.
  98. (for
  99. (in b nmode-selectable-buffers)
  100. (do
  101. (cond ((and (=> b file-name)
  102. (=> b modified?)
  103. (or nmode-command-argument-given
  104. (nmode-y-or-n?
  105. (bldmsg "Save %w in %w (Y or N)?"
  106. (=> b name) (=> b file-name)))
  107. ))
  108. (save-file b))
  109. ))))
  110. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  111. % File functions:
  112. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  113. (de prompt-for-defaulted-filename (prompt b)
  114. % The default name is the name associated with the specified buffer (without
  115. % Version number). Will throw 'ABORT if a bad file name is given.
  116. % If B is NIL, the "current" buffer is used.
  117. (let ((fn (=> (or b nmode-current-buffer) file-name)))
  118. (prompt-for-file-name prompt
  119. (and fn (namestring (pathname-without-version fn)))
  120. )))
  121. (de prompt-for-file-name (prompt default-name)
  122. % Default-Name may be NIL.
  123. % Will throw 'ABORT if a bad file name is given.
  124. (let ((pn (pathname (prompt-for-string prompt default-name))))
  125. (if default-name
  126. (setf pn
  127. (attempt-to-merge-pathname-defaults pn default-name
  128. (pathname-type default-name) NIL)))
  129. (namestring pn)
  130. ))
  131. (de attempt-to-merge-pathname-defaults (pn dn type version)
  132. (let ((result (errset (merge-pathname-defaults pn dn type version) NIL)))
  133. (cond
  134. ((listp result) (car result))
  135. (t (write-prompt EMSG*)
  136. (throw 'ABORT)))))
  137. (de read-file-into-buffer (b file-name)
  138. (=> b set-file-name file-name)
  139. (buffer-set-mode b (pathname-default-mode file-name))
  140. (let ((s (attempt-to-open-input file-name)))
  141. (if s
  142. (read-stream-into-buffer b s)
  143. % else
  144. (=> b reset)
  145. (=> b set-modified? NIL)
  146. (write-prompt "(New File)")
  147. )))
  148. (de read-stream-into-buffer (b s)
  149. (let ((fn (=> s file-name)))
  150. (write-prompt (bldmsg "Reading file: %w" fn))
  151. (=> b read-from-stream s)
  152. (=> s close)
  153. (write-prompt (bldmsg "File read: %w (%d lines)" fn (=> b visible-size)))
  154. ))
  155. (de insert-file-into-buffer (buf pn)
  156. (let ((b (buffer-create-unselectable "FOO" Text-Mode)))
  157. (read-file-into-buffer b pn)
  158. (insert-buffer-into-buffer b buf)
  159. ))
  160. (de insert-buffer-into-buffer (source destination)
  161. (let ((old-pos (=> destination position)))
  162. (=> destination insert-text (=> source contents))
  163. (=> destination set-mark-from-point)
  164. (=> destination set-position old-pos)
  165. ))
  166. (de save-file (b)
  167. % Save the specified buffer on its associated file, ask for file if unknown.
  168. (let ((fn (=> b file-name)))
  169. (cond
  170. ((not (=> b modified?)) nil)
  171. (fn (write-buffer-to-file b (pathname-without-version fn)))
  172. (T (write-file b)))))
  173. (de save-file-version (b)
  174. % Save the specified buffer on its associated file, ask for file if unknown.
  175. % The file is written to the current version number.
  176. (let ((fn (=> b file-name)))
  177. (cond
  178. ((not (=> b modified?)) nil)
  179. (fn (write-buffer-to-file b fn))
  180. (T (write-file b)))))
  181. (de write-file (b)
  182. % Ask for filename, write out the buffer to the file.
  183. (let ((msg (bldmsg "Write Buffer %w to File: " (=> b name))))
  184. (write-buffer-to-file b (prompt-for-defaulted-filename msg b))))
  185. (de write-buffer-to-file (b pn)
  186. % Write the specified buffer to a file.
  187. (write-prompt "")
  188. (let* ((file-name (namestring pn))
  189. (s (attempt-to-open-output file-name))
  190. )
  191. (if s
  192. (let ((fn (=> s file-name)))
  193. (write-prompt (bldmsg "Writing file: %w" fn))
  194. (=> b write-to-stream s)
  195. (=> s close)
  196. (write-prompt
  197. (bldmsg "File written: %w (%d lines)" fn (=> b visible-size)))
  198. (=> b set-modified? NIL)
  199. (=> b set-file-name fn)
  200. )
  201. (nmode-error (bldmsg "Unable to write file: %w" file-name))
  202. )))
  203. (de write-text-to-file (text pn)
  204. (let ((b (buffer-create-unselectable "FOO" Text-Mode)))
  205. (=> b insert-text text)
  206. (write-buffer-to-file b pn)
  207. ))
  208. (de prepend-text-to-file (text pn)
  209. (let ((b (buffer-create-unselectable "FOO" Text-Mode)))
  210. (read-file-into-buffer b pn)
  211. (=> b move-to-buffer-start)
  212. (=> b insert-text text)
  213. (write-buffer-to-file b pn)
  214. ))
  215. (de append-text-to-file (text pn)
  216. (let ((b (buffer-create-unselectable "FOO" Text-Mode)))
  217. (read-file-into-buffer b pn)
  218. (=> b move-to-buffer-end)
  219. (=> b insert-text text)
  220. (write-buffer-to-file b pn)
  221. ))
  222. (de visit-file (b file-name)
  223. % If the specified file exists, read it into the specified buffer.
  224. % Otherwise, clear the buffer for a new file.
  225. % If the buffer contains precious data, offer to save it first.
  226. (if (=> b modified?)
  227. (let* ((fn (=> b file-name))
  228. (msg (if fn (bldmsg "file %w" fn)
  229. (bldmsg "buffer %w" (=> b name))))
  230. )
  231. (if (nmode-yes-or-no? (bldmsg "Write out changes in %w?" msg))
  232. (save-file b)
  233. )))
  234. (let ((fn (actualize-file-name file-name)))
  235. (if fn
  236. (read-file-into-buffer b fn)
  237. (nmode-error (bldmsg "Unable to read or create file: %w" file-name))
  238. )))
  239. (de find-file (file-name)
  240. % Select a buffer containing the specified file. If the file exists in a
  241. % buffer already, then that buffer is selected. Otherwise, a new buffer is
  242. % created and the file read into it (if the file exists).
  243. (find-file-in-window nmode-current-window file-name))
  244. (de find-file-in-window (w file-name)
  245. % Attach a buffer to the specified window that contains the specified file.
  246. % If the file exists in a buffer already, then that buffer is used.
  247. % Otherwise, a new buffer is created and the file read into it (if the file
  248. % exists).
  249. (let ((b (find-file-in-buffer file-name nil)))
  250. (if b
  251. (window-select-buffer w b)
  252. % otherwise
  253. (nmode-error (bldmsg "Unable to read or create file: %w" file-name))
  254. )))
  255. (de find-file-in-buffer (file-name existing-file-only?)
  256. % Return a buffer containing the specified file. The buffer is not
  257. % selected. If the file exists in a buffer already, then that buffer is
  258. % returned. Otherwise, if the file exists and can be read, a new buffer is
  259. % created and the file read into it. Otherwise, if EXISTING-FILE-ONLY? is
  260. % NIL and the file is potentially creatable, a new buffer is created and
  261. % returned. Otherwise, NIL is returned.
  262. (setf file-name (actualize-file-name file-name))
  263. (if (and file-name (not (string-empty? file-name)))
  264. (or
  265. (find-file-in-existing-buffer file-name) % look for existing buffer
  266. (let ((s (attempt-to-open-input file-name)))
  267. (when (or s (not existing-file-only?)) % create a buffer
  268. (let ((b (buffer-create-default
  269. (buffer-make-unique-name
  270. (filename-to-buffername file-name)))))
  271. (=> b set-file-name file-name)
  272. (buffer-set-mode b (pathname-default-mode file-name))
  273. (if s
  274. (read-stream-into-buffer b s)
  275. (write-prompt "(New File)")
  276. )
  277. b
  278. ))))))
  279. (de find-file-in-existing-buffer (file-name)
  280. % Look for the specified file in an existing buffer. If found, return
  281. % that buffer, otherwise return NIL. The filename should be complete.
  282. (let ((pn (pathname file-name)))
  283. (for (in b nmode-selectable-buffers)
  284. (do (if (pathnames-match pn (=> b file-name)) (exit b)))
  285. (returns nil))
  286. ))
  287. (de nmode-delete-file (fn)
  288. (let ((del-fn (file-delete fn)))
  289. (if del-fn
  290. (write-prompt (bldmsg "File deleted: %w" del-fn))
  291. (nmode-error (bldmsg "Unable to delete file: %w" fn))
  292. )
  293. del-fn
  294. ))
  295. (de nmode-delete-and-expunge-file (fn)
  296. (let ((del-fn (file-delete-and-expunge fn)))
  297. (if del-fn
  298. (write-prompt (bldmsg "File deleted and expunged: %w" del-fn))
  299. (nmode-error (bldmsg "Unable to delete file: %w" fn))
  300. )
  301. del-fn
  302. ))
  303. (de nmode-undelete-file (fn)
  304. (let ((del-fn (file-undelete fn)))
  305. (if del-fn
  306. (write-prompt (bldmsg "File undeleted: %w" del-fn))
  307. (nmode-error (bldmsg "Unable to undelete file: %w" fn))
  308. )
  309. del-fn
  310. ))
  311. (de write-screen-photo (file-name)
  312. % Write the current screen to file.
  313. (let ((s (attempt-to-open-output file-name)))
  314. (cond (s
  315. (nmode-refresh)
  316. (=> nmode-screen write-to-stream s)
  317. (=> s close)
  318. (write-prompt (bldmsg "File written: %w" (=> s file-name)))
  319. )
  320. (t
  321. (nmode-error (bldmsg "Unable to write file: %w" file-name))
  322. ))))
  323. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  324. % Auxiliary functions
  325. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  326. (de actualize-file-name (file-name)
  327. % If the specified file exists, return its "true" (and complete) name.
  328. % Otherwise, return the "true" name of the file that would be created if one
  329. % were to do so. (Unfortunately, we have no way to do this except by actually
  330. % creating the file and then deleting it!) Return NIL if the file cannot be
  331. % read or created.
  332. (let ((s (attempt-to-open-input file-name)))
  333. (cond ((not s)
  334. (setf s (attempt-to-open-output file-name))
  335. (when s
  336. (setf file-name (=> s file-name))
  337. (=> s close)
  338. (file-delete-and-expunge file-name)
  339. file-name
  340. )
  341. )
  342. (t
  343. (setf file-name (=> s file-name))
  344. (=> s close)
  345. file-name
  346. ))))
  347. (de filename-to-buffername (pn)
  348. % Convert from a pathname to the "default" corresponding buffer name.
  349. (setf pn (pathname pn))
  350. (string-upcase (file-namestring (pathname-without-version pn)))
  351. )
  352. (de pathnames-match (pn1 pn2)
  353. (setf pn1 (pathname pn1))
  354. (setf pn2 (pathname pn2))
  355. (and (equal (pathname-device pn1) (pathname-device pn2))
  356. (equal (pathname-directory pn1) (pathname-directory pn2))
  357. (equal (pathname-name pn1) (pathname-name pn2))
  358. (equal (pathname-type pn1) (pathname-type pn2))
  359. (or (null (pathname-version pn1))
  360. (null (pathname-version pn2))
  361. (equal (pathname-version pn1) (pathname-version pn2)))
  362. ))
  363. (de pathname-without-version (pn)
  364. (setf pn (pathname pn))
  365. (make-pathname 'host (pathname-host pn)
  366. 'device (pathname-device pn)
  367. 'directory (pathname-directory pn)
  368. 'name (pathname-name pn)
  369. 'type (pathname-type pn)
  370. ))