dos-w32.el 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. ;; dos-w32.el --- Functions shared among MS-DOS and W32 (NT/95) platforms
  2. ;; Copyright (C) 1996, 2001-2012 Free Software Foundation, Inc.
  3. ;; Maintainer: Geoff Voelker <voelker@cs.washington.edu>
  4. ;; Keywords: internal
  5. ;; Package: emacs
  6. ;; This file is part of GNU Emacs.
  7. ;; GNU Emacs is free software: you can redistribute it and/or modify
  8. ;; it under the terms of the GNU General Public License as published by
  9. ;; the Free Software Foundation, either version 3 of the License, or
  10. ;; (at your option) any later version.
  11. ;; GNU Emacs is distributed in the hope that it will be useful,
  12. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. ;; GNU General Public License for more details.
  15. ;; You should have received a copy of the GNU General Public License
  16. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  17. ;;; Commentary:
  18. ;; Parts of this code are duplicated functions taken from dos-fns.el
  19. ;; and winnt.el.
  20. ;;; Code:
  21. ;; Use ";" instead of ":" as a path separator (from files.el).
  22. (setq path-separator ";")
  23. (setq minibuffer-history-case-insensitive-variables
  24. (cons 'file-name-history minibuffer-history-case-insensitive-variables))
  25. ;; Set the null device (for compile.el).
  26. (setq null-device "NUL")
  27. ;; For distinguishing file types based upon suffixes.
  28. (defvar file-name-buffer-file-type-alist
  29. '(
  30. ("[:/].*config.sys$" . nil) ; config.sys text
  31. ("\\.\\(obj\\|exe\\|com\\|lib\\|sys\\|bin\\|ico\\|pif\\|class\\)$" . t)
  32. ; MS-Dos stuff
  33. ("\\.\\(dll\\|drv\\|386\\|vxd\\|fon\\|fnt\\|fot\\|ttf\\|grp\\)$" . t)
  34. ; Windows stuff
  35. ("\\.\\(bmp\\|wav\\|avi\\|mpg\\|jpg\\|tif\\|mov\\|au\\)$" . t)
  36. ; known binary data files
  37. ("\\.\\(arc\\|zip\\|pak\\|lzh\\|zoo\\)$" . t)
  38. ; Packers
  39. ("\\.\\(a\\|o\\|tar\\|z\\|gz\\|taz\\|jar\\)$" . t)
  40. ; Unix stuff
  41. ("\\.sx[dmicw]$" . t) ; OpenOffice.org
  42. ("\\.tp[ulpw]$" . t) ; borland Pascal stuff
  43. ("[:/]tags$" . nil) ; emacs TAGS file
  44. )
  45. "*Alist for distinguishing text files from binary files.
  46. Each element has the form (REGEXP . TYPE), where REGEXP is matched
  47. against the file name, and TYPE is nil for text, t for binary.")
  48. ;; Return the pair matching filename on file-name-buffer-file-type-alist,
  49. ;; or nil otherwise.
  50. (defun find-buffer-file-type-match (filename)
  51. (let ((alist file-name-buffer-file-type-alist)
  52. (found nil))
  53. (let ((case-fold-search t))
  54. (setq filename (file-name-sans-versions filename))
  55. (while (and (not found) alist)
  56. (if (string-match (car (car alist)) filename)
  57. (setq found (car alist)))
  58. (setq alist (cdr alist)))
  59. found)))
  60. ;; Don't check for untranslated file systems here.
  61. (defun find-buffer-file-type (filename)
  62. (let ((match (find-buffer-file-type-match filename))
  63. (code))
  64. (if (not match)
  65. (default-value 'buffer-file-type)
  66. (setq code (cdr match))
  67. (cond ((memq code '(nil t)) code)
  68. ((and (symbolp code) (fboundp code))
  69. (funcall code filename))))))
  70. (setq-default buffer-file-coding-system 'undecided-dos)
  71. (defun find-buffer-file-type-coding-system (command)
  72. "Choose a coding system for a file operation in COMMAND.
  73. COMMAND is a list that specifies the operation, an I/O primitive, as its
  74. CAR, and the arguments that might be given to that operation as its CDR.
  75. If operation is `insert-file-contents', the coding system is chosen based
  76. upon the filename (the CAR of the arguments beyond the operation), the contents
  77. of `untranslated-filesystem-list' and `file-name-buffer-file-type-alist',
  78. and whether the file exists:
  79. If it matches in `untranslated-filesystem-list':
  80. If the file exists: `undecided'
  81. If the file does not exist: `undecided-unix'
  82. If it matches in `file-name-buffer-file-type-alist':
  83. If the match is t (for binary): `no-conversion'
  84. If the match is nil (for dos-text): `undecided-dos'
  85. Otherwise:
  86. If the file exists: `undecided'
  87. If the file does not exist default value of `buffer-file-coding-system'
  88. Note that the CAR of arguments to `insert-file-contents' operation could
  89. be a cons cell of the form \(FILENAME . BUFFER\), where BUFFER is a buffer
  90. into which the file's contents were already read, but not yet decoded.
  91. If operation is `write-region', the coding system is chosen based upon
  92. the value of `buffer-file-coding-system' and `buffer-file-type'. If
  93. `buffer-file-coding-system' is non-nil, its value is used. If it is
  94. nil and `buffer-file-type' is t, the coding system is `no-conversion'.
  95. Otherwise, it is `undecided-dos'.
  96. The two most common situations are when DOS and Unix files are read
  97. and written, and their names do not match in
  98. `untranslated-filesystem-list' and `file-name-buffer-file-type-alist'.
  99. In these cases, the coding system initially will be `undecided'. As
  100. the file is read in the DOS case, the coding system will be changed to
  101. `undecided-dos' as CR/LFs are detected. As the file is read in the
  102. Unix case, the coding system will be changed to `undecided-unix' as
  103. LFs are detected. In both cases, `buffer-file-coding-system' will be
  104. set to the appropriate coding system, and the value of
  105. `buffer-file-coding-system' will be used when writing the file."
  106. (let ((op (nth 0 command))
  107. (binary nil) (text nil)
  108. (undecided nil) (undecided-unix nil)
  109. target target-buf)
  110. (cond ((eq op 'insert-file-contents)
  111. (setq target (nth 1 command))
  112. ;; If TARGET is a cons cell, it has the form (FILENAME . BUFFER),
  113. ;; where BUFFER is a buffer into which the file was already read,
  114. ;; but its contents were not yet decoded. (This form of the
  115. ;; arguments is used, e.g., in arc-mode.el.) This function
  116. ;; doesn't care about the contents, it only looks at the file's
  117. ;; name, which is the CAR of the cons cell.
  118. (when (consp target)
  119. (setq target-buf
  120. (and (bufferp (cdr target))
  121. (buffer-name (cdr target))))
  122. (setq target (car target)))
  123. ;; First check for a file name that indicates
  124. ;; it is truly binary.
  125. (setq binary (find-buffer-file-type target))
  126. (cond (binary)
  127. ;; Next check for files that MUST use DOS eol conversion.
  128. ((find-buffer-file-type-match target)
  129. (setq text t))
  130. ;; For any other existing file, decide based on contents.
  131. ((or
  132. (file-exists-p target)
  133. ;; If TARGET does not exist as a file, replace its
  134. ;; base name with TARGET-BUF and try again. This
  135. ;; is for jka-compr's sake, which strips the
  136. ;; compression (.gz etc.) extension from the
  137. ;; FILENAME, but leaves it in the BUFFER's name.
  138. (and (stringp target-buf)
  139. (file-exists-p
  140. (expand-file-name target-buf
  141. (file-name-directory target)))))
  142. (setq undecided t))
  143. ;; Next check for a non-DOS file system.
  144. ((untranslated-file-p target)
  145. (setq undecided-unix t)))
  146. (cond (binary '(no-conversion . no-conversion))
  147. (text '(undecided-dos . undecided-dos))
  148. (undecided-unix '(undecided-unix . undecided-unix))
  149. (undecided '(undecided . undecided))
  150. (t (cons (default-value 'buffer-file-coding-system)
  151. (default-value 'buffer-file-coding-system)))))
  152. ((eq op 'write-region)
  153. (if buffer-file-coding-system
  154. (cons buffer-file-coding-system
  155. buffer-file-coding-system)
  156. ;; Normally this is used only in a non-file-visiting
  157. ;; buffer, because normally buffer-file-coding-system is non-nil
  158. ;; in a file-visiting buffer.
  159. (if buffer-file-type
  160. '(no-conversion . no-conversion)
  161. '(undecided-dos . undecided-dos)))))))
  162. (modify-coding-system-alist 'file "" 'find-buffer-file-type-coding-system)
  163. (defun find-file-binary (filename)
  164. "Visit file FILENAME and treat it as binary."
  165. (interactive "FFind file binary: ")
  166. (let ((file-name-buffer-file-type-alist '(("" . t))))
  167. (find-file filename)))
  168. (defun find-file-text (filename)
  169. "Visit file FILENAME and treat it as a text file."
  170. (interactive "FFind file text: ")
  171. (let ((file-name-buffer-file-type-alist '(("" . nil))))
  172. (find-file filename)))
  173. (defun find-file-not-found-set-buffer-file-coding-system ()
  174. (with-current-buffer (current-buffer)
  175. (let ((coding buffer-file-coding-system))
  176. ;; buffer-file-coding-system is already set by
  177. ;; find-operation-coding-system, which was called from
  178. ;; insert-file-contents. All that's left is to change
  179. ;; the EOL conversion, if required by the user.
  180. (when (and (null coding-system-for-read)
  181. (or inhibit-eol-conversion
  182. (untranslated-file-p (buffer-file-name))))
  183. (setq coding (coding-system-change-eol-conversion coding 0))
  184. (setq buffer-file-coding-system coding))
  185. (setq buffer-file-type (eq buffer-file-coding-system 'no-conversion)))))
  186. ;;; To set the default coding system on new files.
  187. (add-hook 'find-file-not-found-functions
  188. 'find-file-not-found-set-buffer-file-coding-system)
  189. ;;; To accommodate filesystems that do not require CR/LF translation.
  190. (defvar untranslated-filesystem-list nil
  191. "List of filesystems that require no CR/LF translation when reading
  192. and writing files. Each filesystem in the list is a string naming
  193. the directory prefix corresponding to the filesystem.")
  194. (defun untranslated-canonical-name (filename)
  195. "Return FILENAME in a canonicalized form for use with the functions
  196. dealing with untranslated filesystems."
  197. (if (memq system-type '(ms-dos windows-nt cygwin))
  198. ;; The canonical form for DOS/W32 is with A-Z downcased and all
  199. ;; directory separators changed to directory-sep-char.
  200. (let ((name nil))
  201. (setq name (mapconcat
  202. (lambda (char)
  203. (if (and (<= ?A char) (<= char ?Z))
  204. (char-to-string (+ (- char ?A) ?a))
  205. (char-to-string char)))
  206. filename nil))
  207. ;; Use expand-file-name to canonicalize directory separators, except
  208. ;; with bare drive letters (which would have the cwd appended).
  209. ;; Avoid expanding names that could trigger ange-ftp to prompt
  210. ;; for passwords, though.
  211. (if (or (string-match "^.:$" name)
  212. (string-match "^/[^/:]+:" name))
  213. name
  214. (expand-file-name name)))
  215. filename))
  216. (defun untranslated-file-p (filename)
  217. "Return t if FILENAME is on a filesystem that does not require
  218. CR/LF translation, and nil otherwise."
  219. (let ((fs (untranslated-canonical-name filename))
  220. (ufs-list untranslated-filesystem-list)
  221. (found nil))
  222. (while (and (not found) ufs-list)
  223. (if (string-match (concat "^" (car ufs-list)) fs)
  224. (setq found t)
  225. (setq ufs-list (cdr ufs-list))))
  226. found))
  227. (defun add-untranslated-filesystem (filesystem)
  228. "Add FILESYSTEM to the list of filesystems that do not require
  229. CR/LF translation. FILESYSTEM is a string containing the directory
  230. prefix corresponding to the filesystem. For example, for a Unix
  231. filesystem mounted on drive Z:, FILESYSTEM could be \"Z:\"."
  232. ;; We use "D", not "f", to avoid confusing the user: "f" prompts
  233. ;; with a directory, but RET returns the current buffer's file, not
  234. ;; its directory.
  235. (interactive "DUntranslated file system: ")
  236. (let ((fs (untranslated-canonical-name filesystem)))
  237. (if (member fs untranslated-filesystem-list)
  238. untranslated-filesystem-list
  239. (setq untranslated-filesystem-list
  240. (cons fs untranslated-filesystem-list)))))
  241. (defun remove-untranslated-filesystem (filesystem)
  242. "Remove FILESYSTEM from the list of filesystems that do not require
  243. CR/LF translation. FILESYSTEM is a string containing the directory
  244. prefix corresponding to the filesystem. For example, for a Unix
  245. filesystem mounted on drive Z:, FILESYSTEM could be \"Z:\"."
  246. (interactive "fUntranslated file system: ")
  247. (setq untranslated-filesystem-list
  248. (delete (untranslated-canonical-name filesystem)
  249. untranslated-filesystem-list)))
  250. ;;; Support for printing under DOS/Windows, see lpr.el and ps-print.el.
  251. (defvar direct-print-region-use-command-dot-com t
  252. "*Control whether command.com is used to print on Windows 9x.")
  253. ;; Function to actually send data to the printer port.
  254. ;; Supports writing directly, and using various programs.
  255. (defun direct-print-region-helper (printer
  256. start end
  257. lpr-prog
  258. _delete-text _buf _display
  259. rest)
  260. (let* (;; Ignore case when matching known external program names.
  261. (case-fold-search t)
  262. ;; Convert / to \ in printer name, for sake of external programs.
  263. (printer
  264. (if (stringp printer)
  265. (subst-char-in-string ?/ ?\\ printer)
  266. printer))
  267. ;; Find a directory that is local, to work-around Windows bug.
  268. (safe-dir
  269. (let ((safe-dirs (list "c:/" (getenv "windir") (getenv "TMPDIR"))))
  270. (while (not (file-attributes (car safe-dirs)))
  271. (setq safe-dirs (cdr safe-dirs)))
  272. (car safe-dirs)))
  273. (tempfile
  274. (subst-char-in-string
  275. ?/ ?\\
  276. (make-temp-name
  277. (expand-file-name "EP" temporary-file-directory))))
  278. ;; capture output for diagnosis
  279. (errbuf (list (get-buffer-create " *print-region-helper*") t)))
  280. ;; It seems that we must be careful about the directory name that
  281. ;; gets added to the printer port name by write-region when using
  282. ;; the standard "PRN" or "LPTx" ports, because the write can fail if
  283. ;; the directory is on a network drive. The same is true when
  284. ;; asking command.com to copy the file.
  285. ;; No action is needed for UNC printer names, which is just as well
  286. ;; because `expand-file-name' doesn't support UNC names on MS-DOS.
  287. (if (and (stringp printer) (not (string-match "^\\\\" printer)))
  288. (setq printer
  289. (subst-char-in-string ?/ ?\\ (expand-file-name printer safe-dir))))
  290. ;; Handle known programs specially where necessary.
  291. (unwind-protect
  292. (cond
  293. ;; nprint.exe is the standard print command on Netware
  294. ((string-match "^nprint\\(\\.exe\\)?$" (file-name-nondirectory lpr-prog))
  295. (write-region start end tempfile nil 0)
  296. (call-process lpr-prog nil errbuf nil
  297. tempfile (concat "P=" printer)))
  298. ;; print.exe is a standard command on NT
  299. ((string-match "^print\\(\\.exe\\)?$" (file-name-nondirectory lpr-prog))
  300. ;; Be careful not to invoke print.exe on MS-DOS or Windows 9x
  301. ;; though, because it is a TSR program there (hangs Emacs).
  302. (or (and (eq system-type 'windows-nt)
  303. (null (getenv "winbootdir")))
  304. (error "Printing via print.exe is not supported on MS-DOS or Windows 9x"))
  305. ;; It seems that print.exe always appends a form-feed so we
  306. ;; should make sure to omit the last FF in the data.
  307. (if (and (> end start)
  308. (char-equal (char-before end) ?\C-l))
  309. (setq end (1- end)))
  310. ;; cancel out annotate function for non-PS case
  311. (let ((write-region-annotate-functions nil))
  312. (write-region start end tempfile nil 0))
  313. (call-process lpr-prog nil errbuf nil
  314. (concat "/D:" printer) tempfile))
  315. ;; support lpr and similar programs for convenience, but
  316. ;; supply an explicit filename because the NT version of lpr
  317. ;; can't read from stdin.
  318. ((> (length lpr-prog) 0)
  319. (write-region start end tempfile nil 0)
  320. (setq rest (append rest (list tempfile)))
  321. (apply 'call-process lpr-prog nil errbuf nil rest))
  322. ;; Run command.com to access printer port on Windows 9x, unless
  323. ;; we are supposed to append to an existing (non-empty) file,
  324. ;; to work around a bug in Windows 9x that prevents Win32
  325. ;; programs from accessing LPT ports reliably.
  326. ((and (eq system-type 'windows-nt)
  327. (getenv "winbootdir")
  328. ;; Allow cop-out so command.com isn't invoked
  329. direct-print-region-use-command-dot-com
  330. ;; file-attributes fails on LPT ports on Windows 9x but
  331. ;; not on NT, so handle both cases for safety.
  332. (eq (or (nth 7 (file-attributes printer)) 0) 0))
  333. (write-region start end tempfile nil 0)
  334. (let ((w32-quote-process-args nil))
  335. (call-process "command.com" nil errbuf nil "/c"
  336. (format "copy /b %s %s" tempfile printer))))
  337. ;; write directly to the printer port
  338. (t
  339. (write-region start end printer t 0)))
  340. ;; ensure we remove the tempfile if created
  341. (if (file-exists-p tempfile)
  342. (delete-file tempfile)))))
  343. (defvar printer-name)
  344. (declare-function default-printer-name "w32fns.c")
  345. (defun direct-print-region-function (start end
  346. &optional lpr-prog
  347. delete-text buf display
  348. &rest rest)
  349. "DOS/Windows-specific function to print the region on a printer.
  350. Writes the region to the device or file which is a value of
  351. `printer-name' \(which see\), unless the value of `lpr-command'
  352. indicates a specific program should be invoked."
  353. ;; DOS printers need the lines to end with CR-LF pairs, so make
  354. ;; sure it always happens that way, unless the buffer is binary.
  355. (let* ((coding coding-system-for-write)
  356. (coding-base
  357. (if (null coding) 'undecided (coding-system-base coding)))
  358. (eol-type (coding-system-eol-type coding-base))
  359. ;; Make each print-out eject the final page, but don't waste
  360. ;; paper if the file ends with a form-feed already.
  361. (write-region-annotate-functions
  362. (cons
  363. (lambda (_start end)
  364. (if (not (char-equal (char-before end) ?\C-l))
  365. `((,end . "\f"))))
  366. write-region-annotate-functions))
  367. (printer (or (and (boundp 'dos-printer)
  368. (stringp (symbol-value 'dos-printer))
  369. (symbol-value 'dos-printer))
  370. printer-name
  371. (default-printer-name))))
  372. (or (eq coding-system-for-write 'no-conversion)
  373. (setq coding-system-for-write
  374. (aref eol-type 1))) ; force conversion to DOS EOLs
  375. (direct-print-region-helper printer start end lpr-prog
  376. delete-text buf display rest)))
  377. (defvar print-region-function)
  378. (defvar lpr-headers-switches)
  379. (setq print-region-function 'direct-print-region-function)
  380. ;; Set this to nil if you have a port of the `pr' program
  381. ;; (e.g., from GNU Textutils), or if you have an `lpr'
  382. ;; program (see above) that can print page headers.
  383. ;; If `lpr-headers-switches' is non-nil (the default) and
  384. ;; `print-region-function' is set to `dos-print-region-function',
  385. ;; then requests to print page headers will be silently
  386. ;; ignored, and `print-buffer' and `print-region' produce
  387. ;; the same output as `lpr-buffer' and `lpr-region', accordingly.
  388. (setq lpr-headers-switches "(page headers are not supported)")
  389. (defvar ps-printer-name)
  390. (defun direct-ps-print-region-function (start end
  391. &optional lpr-prog
  392. delete-text buf display
  393. &rest rest)
  394. "DOS/Windows-specific function to print the region on a PostScript printer.
  395. Writes the region to the device or file which is a value of
  396. `ps-printer-name' \(which see\), unless the value of `ps-lpr-command'
  397. indicates a specific program should be invoked."
  398. (let ((printer (or (and (boundp 'dos-ps-printer)
  399. (stringp (symbol-value 'dos-ps-printer))
  400. (symbol-value 'dos-ps-printer))
  401. ps-printer-name
  402. (default-printer-name))))
  403. (direct-print-region-helper printer start end lpr-prog
  404. delete-text buf display rest)))
  405. (defvar ps-print-region-function)
  406. (setq ps-print-region-function 'direct-ps-print-region-function)
  407. ;(setq ps-lpr-command "gs")
  408. ;(setq ps-lpr-switches '("-q" "-dNOPAUSE" "-sDEVICE=epson" "-r240x60"
  409. ; "-sOutputFile=LPT1"))
  410. (provide 'dos-w32)
  411. ;;; dos-w32.el ends here