Do direct comparisons instead of using MEMBER over singleton lists
[maxima.git] / src / macsys.lisp
blob680a66a9eb9d9283266162d67ba150e7663c3a89
1 ;;; -*- Mode: Lisp; Package: Maxima; Syntax: Common-Lisp; Base: 10 -*- ;;;;
2 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3 ;;; The data in this file contains enhancments. ;;;;;
4 ;;; ;;;;;
5 ;;; Copyright (c) 1984,1987 by William Schelter,University of Texas ;;;;;
6 ;;; All rights reserved ;;;;;
7 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
8 ;;;
9 ;;; ** (c) Copyright 1981 Massachusetts Institute of Technology **
10 ;;;
11 ;;; SYSTEM: The ``New'' Macsyma System Stuff
13 (in-package :maxima)
15 (macsyma-module system)
17 (defmvar $showtime nil
18 "When T, the computation time is printed with each output expression.")
20 ;;; Standard Kinds of Input Prompts
22 (defmvar $prompt '_
23 "Prompt symbol of the demo function, playback, and the Maxima break loop.")
25 ;; A prefix and suffix that are wrapped around every prompt that Maxima
26 ;; emits. This is designed for use with text-based interfaces that drive Maxima
27 ;; through standard input and output and need to decorate prompts to make the
28 ;; output easier to parse. There are some more notes in
29 ;; doc/implementation/external-interface.txt.
30 (defvar *prompt-prefix* "")
31 (defvar *prompt-suffix* "")
32 (defvar *general-display-prefix* "")
33 (defvar $alt_format_prompt nil "If NIL, use DEFAULT-FORMAT-PROMPT to print input prompt; if a function, use it to print input prompt.")
35 (defun format-prompt (destination control-string &rest arguments)
36 "If $ALT_FORMAT_PROMPT is NIL, use DEFAULT-FORMAT-PROMPT to print
37 prompt; otherwise MFUNCALL $ALT_FORMAT_PROMPT to print prompt."
38 (funcall (if $alt_format_prompt #'alt-format-prompt #'default-format-prompt)
39 destination control-string arguments))
41 (defun alt-format-prompt (destination control-string arguments)
42 "MFUNCALL $ALT_FORMAT_PROMPT with a heavy coating of error protection."
43 (handler-bind ((error (lambda(msg) (setq $alt_format_prompt nil)
44 (format t (intl:gettext "Error in printing prompt; reverting to default.~%~a") msg)
45 (throw 'macsyma-quit 'maxima-error))))
46 (with-$error (let ((prompt (mfuncall $alt_format_prompt destination control-string arguments)))
47 (if (stringp prompt) prompt (merror "alt_format_prompt returned an object of type ~a, needed a string." (type-of prompt)))))))
49 (defun default-format-prompt (destination control-string arguments)
50 "Like AFORMAT, but add the prefix and suffix configured for a prompt. This
51 function deals correctly with the ~M control character, but only when
52 DESTINATION is an actual stream (rather than nil for a string)."
53 (let ((*print-circle* nil))
54 (if (null destination)
55 ;; return value string is important
56 (concatenate 'string
57 *prompt-prefix*
58 (apply #'aformat destination
59 control-string
60 arguments)
61 *prompt-suffix*)
62 (progn
63 (format destination "~A~A~A"
64 *prompt-prefix*
65 (apply #'aformat nil
66 control-string
67 arguments)
68 *prompt-suffix*)))))
71 (defvar $default_format_prompt (symbol-function 'default-format-prompt))
73 ;; "When time began" (or at least the start of version control history),
74 ;; the following comment was made at this point:
76 ;; instead of using this STRIPDOLLAR hackery, the
77 ;; MREAD function should call MFORMAT to print the prompt,
78 ;; and take a format string and format arguments.
79 ;; Even easier and more general is for MREAD to take
80 ;; a FUNARG as the prompt. -gjc
82 ;; I guess we're still failing miserably, but unfortunately MFORMAT/AFORMAT
83 ;; don't deal correctly with ~M plus a string output stream.
84 (defun main-prompt ()
85 (declare (special *display-labels-p*))
86 (if *display-labels-p*
87 (format-prompt nil "(~A~A) "
88 (print-invert-case (stripdollar $inchar))
89 $linenum)
90 ""))
92 (defun break-prompt ()
93 (format-prompt nil "~A"
94 (print-invert-case (stripdollar $prompt))))
96 (defun toplevel-macsyma-eval (x)
97 ;; Catch rat-err's here.
99 ;; The idea is that eventually there will be quite a few "maybe catch this"
100 ;; errors, which will be raised and might well get eaten before they get as far
101 ;; as here. However, we want to display them nicely like merror rather than
102 ;; letting a lisp error percolate to the debugger and, as such, we catch them
103 ;; here and replace them with an merror call.
105 ;; Other random errors get to the lisp debugger, which is normally set to print
106 ;; them and continue, via *debugger-hook*.
107 (rat-error-to-merror (meval* x)))
109 (defmvar $_ '$_ "last thing read in, corresponds to lisp +")
110 (defmvar $__ '$__ "thing read in which will be evaluated, corresponds to -")
112 (declare-top (special *mread-prompt* $file_search_demo))
114 (defvar accumulated-time 0.0)
116 #+(or cmu scl)
117 (defun used-area (&optional unused)
118 (declare (ignore unused))
119 (ext:get-bytes-consed))
121 #+sbcl
122 (defun used-area (&optional unused)
123 (declare (ignore unused))
124 (sb-ext:get-bytes-consed))
126 #+openmcl
127 (defun used-area (&optional unused)
128 (declare (ignore unused))
129 (ccl::total-bytes-allocated))
131 #+clisp
132 (defun used-area (&optional unused)
133 (declare (ignore unused))
134 (multiple-value-bind (real1 real2 run1 run2 gc1 gc2 space1 space2 gccount)
135 (sys::%%time)
136 (declare (ignore real1 real2 run1 run2 gc1 gc2 gccount))
137 (dpb space1 (byte 24 24) space2)))
140 #+allegro
141 (defun used-area (&optional unused)
142 (declare (ignore unused))
143 (declare (optimize (speed 3)))
144 (let ((.oldspace (make-array 4 :element-type
145 #-64bit '(unsigned-byte 32)
146 #+64bit '(unsigned-byte 64))))
147 (declare (type (simple-array #-64bit (unsigned-byte 32)
148 #+64bit (unsigned-byte 64) (*))
149 .oldspace))
151 (multiple-value-bind (.olduser .oldsystem .oldgcu .oldgcs)
152 (excl::get-internal-run-times)
153 (declare (ignore .olduser .oldsystem .oldgcs))
154 (sys::gsgc-totalloc .oldspace t)
155 (list (aref .oldspace 0) (aref .oldspace 2) .oldgcu)))) ;; report just two kinds of space,
156 ;; cons-cells and other bytes,
157 ;; also report gc-user time
159 #+lispworks
160 (defun used-area (&optional unused)
161 (declare (ignore unused))
162 (getf (system:room-values) :total-allocated))
164 #-(or cmu scl sbcl clisp allegro openmcl lispworks)
165 (defun used-area (&optional unused)
166 (declare (ignore unused))
169 (defun continue (&optional (input-stream *standard-input*)
170 batch-or-demo-flag)
171 (declare (special *socket-connection*))
172 (if (eql batch-or-demo-flag :demo)
173 (format t
174 (intl:gettext
175 "~%At the '~A' prompt, type ';' and <enter> to get next demonstration.~&")
176 (print-invert-case (stripdollar $prompt))))
177 (catch 'abort-demo
178 (do ((r)
179 (time-before)
180 (time-after)
181 (time-used)
182 (eof (list nil))
183 (etime-before)
184 (etime-after)
185 (area-before)
186 (area-after)
187 (etime-used)
188 (c-tag)
189 (d-tag))
190 (nil)
191 (declare (ignorable area-before area-after))
192 (catch 'return-from-debugger
193 (when (or (not (checklabel $inchar))
194 (not (checklabel $outchar)))
195 (incf $linenum))
196 (setq c-tag (makelabel $inchar))
197 (let ((*mread-prompt* (if batch-or-demo-flag nil (main-prompt)))
198 (eof-count 0))
199 (tagbody
201 (setq r (dbm-read input-stream nil eof))
202 ;; This is something of a hack. If we are running in a server mode
203 ;; (which we determine by checking *socket-connection*) and we get
204 ;; an eof on an input-stream that is not *standard-input*, switch
205 ;; the input stream to *standard-input*.
206 ;; There should probably be a better scheme for server mode.
207 ;; jfa 10/09/2002.
208 (if (and
209 (eq r eof)
210 (not (eq input-stream *standard-input*))
211 (boundp '*socket-connection*))
212 (progn
213 (setq input-stream *standard-input*)
214 (if batch-or-demo-flag
215 (return '$done)
216 (progn
217 (setq *mread-prompt* nil)
218 (setq r (dbm-read input-stream nil eof))))))
220 (cond ((and (eq r eof) (boundp '*socket-connection*)
221 (eq input-stream *socket-connection*))
222 (cond ((>= (setq eof-count (+ 1 eof-count)) 10)
223 (print "exiting on eof")
224 ($quit))
225 (t (go top)))))
226 (cond ((and (consp r) (keywordp (car r)))
227 (break-call (car r) (cdr r) 'break-command)
228 (go top)))))
229 (format t "~a" *general-display-prefix*)
230 (if (eq r eof) (return '$done))
231 (setq $__ (caddr r))
232 (unless $nolabels (setf (symbol-value c-tag) $__))
233 (cond (batch-or-demo-flag
234 (let (($display2d nil))
235 (displa `((mlabel) ,c-tag , $__)))))
236 (setq time-before (get-internal-run-time)
237 etime-before (get-internal-real-time))
238 (setq area-before (used-area))
239 (setq $% (toplevel-macsyma-eval $__))
240 (setq etime-after (get-internal-real-time)
241 time-after (get-internal-run-time))
242 (setq area-after (used-area))
243 (setq time-used (quotient
244 (float (- time-after time-before))
245 internal-time-units-per-second)
246 etime-used (quotient
247 (float (- etime-after etime-before))
248 internal-time-units-per-second))
249 (incf accumulated-time time-used)
250 (setq d-tag (makelabel $outchar))
251 (unless $nolabels (setf (symbol-value d-tag) $%))
252 (setq $_ $__)
253 (when $showtime ;; we don't distinguish showtime:all?? /RJF
254 (format t (intl:gettext "Evaluation took ~,4F seconds (~,4F elapsed)")
255 time-used etime-used )
256 #+(or gcl ecl)
257 (format t "~%")
258 #+(or cmu scl sbcl clisp openmcl)
259 (let ((total-bytes (- area-after area-before)))
260 (cond ((> total-bytes (* 1024 1024))
261 (format t (intl:gettext " using ~,3F MB.~%")
262 (/ total-bytes (* 1024.0 1024.0))))
263 ((> total-bytes 1024)
264 (format t (intl:gettext " using ~,3F KB.~%") (/ total-bytes 1024.0)))
266 (format t (intl:gettext " using ~:D bytes.~%") total-bytes))))
268 #+allegro
269 (let ((conses (- (car area-after) (car area-before)))
270 (other (- (cadr area-after) (cadr area-before)))
271 (gctime (- (caddr area-after) (caddr area-before))))
272 (if (= 0 gctime) nil (format t (intl:gettext " including GC time ~s s,") (* 0.001 gctime)))
273 (format t (intl:gettext " using ~s cons-cells and ~s other bytes.~%") conses other)))
274 (unless $nolabels
275 (putprop '$% (cons time-used 0) 'time)
276 (putprop d-tag (cons time-used 0) 'time))
277 (if (eq (caar r) 'displayinput)
278 (displa `((mlabel) ,d-tag ,$%)))
279 (when (eq batch-or-demo-flag ':demo)
280 (princ (break-prompt))
281 (force-output)
282 (let (quitting)
283 (loop
284 ;;those are common lisp characters you're reading here
285 (case (read-char *terminal-io*)
286 ((#\page)
287 (fresh-line)
288 (princ (break-prompt))
289 (force-output))
290 ((#\?)
291 (format t
292 (intl:gettext
293 " Pausing. Type a ';' and <enter> to continue demo.~%")))
294 ((#\space #\; #\n #\e #\x #\t))
295 ((#\newline )
296 (if quitting (throw 'abort-demo nil) (return nil)))
297 (t (setq quitting t))))))
298 ;; This is sort of a kludge -- eat newlines and blanks so that
299 ;; they don't echo
300 (and batch-or-demo-flag
301 (do ((char)) (())
302 (setq char (read-char input-stream nil nil))
303 (when (null char)
304 (throw 'macsyma-quit nil))
305 (unless (member char '(#\space #\newline #\return #\tab) :test #'equal)
306 (unread-char char input-stream)
307 (return nil))))))))
309 (defun $break (&rest arg-list)
310 (prog1 (apply #'$print arg-list)
311 (mbreak-loop)))
313 (defun mbreak-loop ()
314 (let ((*standard-input* *debug-io*)
315 (*standard-output* *debug-io*))
316 (catch 'break-exit
317 (format t (intl:gettext "~%Entering a Maxima break point. Type 'exit;' to resume."))
318 (do ((r)) (nil)
319 (fresh-line)
320 (setq r (caddr (let ((*mread-prompt* (break-prompt)))
321 (mread *standard-input*))))
322 (case r
323 (($exit) (throw 'break-exit t))
324 (t (errset (displa (meval r)) t)))))))
326 (defun merrbreak (&optional arg)
327 (format *debug-io* "~%Merrbreak:~A" arg)
328 (mbreak-loop))
330 (defun retrieve (msg flag &aux (print? nil))
331 (declare (special msg flag print?))
332 (or (eq flag 'noprint) (setq print? t))
333 (cond ((not print?)
334 (setq print? t)
335 (format-prompt t ""))
336 ((null msg)
337 (format-prompt t ""))
338 ((atom msg)
339 (format-prompt t "~A" msg)
340 (terpri))
341 ((eq flag t)
342 (format-prompt t "~{~A~}" (cdr msg))
343 (mterpri))
345 (format-prompt t "~M" msg)
346 (mterpri)))
347 (let ((res (mread-noprompt *query-io* nil)))
348 (princ *general-display-prefix*)
349 res))
351 (defmfun $read (&rest l)
352 (meval (apply #'$readonly l)))
354 (defmfun $readonly (&rest l)
355 (let ((*mread-prompt*
356 (if l
357 (string-right-trim '(#\n)
358 (with-output-to-string (*standard-output*) (apply #'$print l)))
359 "")))
360 (setf *mread-prompt* (format-prompt nil "~A" *mread-prompt*))
361 (third (mread *query-io*))))
363 ;; FUNCTION BATCH APPARENTLY NEVER CALLED. OMIT FROM GETTEXT SWEEP AND DELETE IT EVENTUALLY
364 (defun batch (filename &optional demo-p
365 &aux (orig filename) list
366 file-obj (accumulated-time 0.0) (abortp t))
367 (setq list (if demo-p '$file_search_demo '$file_search_maxima))
368 (setq filename ($file_search filename (symbol-value list)))
369 (or filename (merror "Could not find ~M in ~M: ~M"
370 orig list (symbol-value list)))
372 (unwind-protect
373 (progn (batch-internal (setq file-obj (open filename)) demo-p)
374 (setq abortp nil)
375 (when $showtime
376 (format t "~&Batch spent ~,4F seconds in evaluation.~%"
377 accumulated-time)))
378 (if file-obj (close file-obj))
379 (when abortp (format t "~&(Batch of ~A aborted.)~%" filename))))
382 (defun batch-internal (fileobj demo-p)
383 (continue (make-echo-stream fileobj *standard-output*)
384 (if demo-p ':demo ':batch)))
386 (defun $demo (&rest arg-list)
387 (let ((tem ($file_search (car arg-list) $file_search_demo)))
388 (or tem (merror (intl:gettext "demo: could not find ~M in ~M.")
389 (car arg-list) '$file_search_demo))
390 ($batch tem '$demo)))
392 (defmfun $bug_report ()
393 (format t (intl:gettext "~%Please report bugs to:~%"))
394 (format t " https://sourceforge.net/p/maxima/bugs~%")
395 (format t (intl:gettext "To report a bug, you must have a Sourceforge account.~%"))
396 (format t (intl:gettext "Please include the following information with your bug report:~%"))
397 (format t "-------------------------------------------------------------~%")
398 ; Display the 2D-formatted build information
399 (let (($display2d t))
400 (displa ($build_info)))
401 (format t "-------------------------------------------------------------~%")
402 (format t (intl:gettext "The above information is also reported by the function 'build_info()'.~%~%"))
405 ;; Declare a build_info structure, then remove it from the list of user-defined structures.
406 (defstruct1 '((%build_info) $version $timestamp $host $lisp_name $lisp_version))
407 (let nil (declare (special $structures))
408 (setq $structures (cons '(mlist) (remove-if #'(lambda (x) (eq (caar x) '%build_info)) (cdr $structures)))))
410 (defvar *maxima-build-info* nil)
412 (defmfun $build_info ()
414 *maxima-build-info*
415 (setq
416 *maxima-build-info*
417 (let
418 ((year (sixth cl-user:*maxima-build-time*))
419 (month (fifth cl-user:*maxima-build-time*))
420 (day (fourth cl-user:*maxima-build-time*))
421 (hour (third cl-user:*maxima-build-time*))
422 (minute (second cl-user:*maxima-build-time*))
423 (seconds (first cl-user:*maxima-build-time*)))
424 (mfuncall
425 '$new
426 `((%build_info)
427 ,*autoconf-version*
428 ,(format nil "~4,'0d-~2,'0d-~2,'0d ~2,'0d:~2,'0d:~2,'0d" year month day hour minute seconds)
429 ,*autoconf-host*
430 ,#+sbcl (ensure-readably-printable-string (lisp-implementation-type)) #-sbcl (lisp-implementation-type)
431 ,#+sbcl (ensure-readably-printable-string (lisp-implementation-version)) #-sbcl (lisp-implementation-version)))))))
433 ;; SBCL base strings aren't readably printable.
434 ;; Attempt a work-around. Yes, this is terribly ugly.
435 #+sbcl (defun ensure-readably-printable-string (x)
436 (coerce x `(simple-array character (,(length x)))))
438 (defun dimension-build-info (form result)
439 (declare (special bkptht bkptdp lines break))
440 ;; Usually the result of (MFUNCALL '$@ ...) is a string,
441 ;; but ensure that output makes sense even if it is not.
442 (let
443 ((version-string (format nil (intl:gettext "Maxima version: ~a")
444 (coerce (mstring (mfuncall '$@ form '$version)) 'string)))
445 (timestamp-string (format nil (intl:gettext "Maxima build date: ~a")
446 (coerce (mstring (mfuncall '$@ form '$timestamp)) 'string)))
447 (host-string (format nil (intl:gettext "Host type: ~a")
448 (coerce (mstring (mfuncall '$@ form '$host)) 'string)))
449 (lisp-name-string (format nil (intl:gettext "Lisp implementation type: ~a")
450 (coerce (mstring (mfuncall '$@ form '$lisp_name)) 'string)))
451 (lisp-version-string (format nil (intl:gettext "Lisp implementation version: ~a")
452 (coerce (mstring (mfuncall '$@ form '$lisp_version)) 'string)))
453 (bkptht 1)
454 (bkptdp 1)
455 (lines 0)
456 (break 0))
457 (forcebreak result 0)
458 (forcebreak (reverse (coerce version-string 'list)) 0)
459 (forcebreak (reverse (coerce timestamp-string 'list)) 0)
460 (forcebreak (reverse (coerce host-string 'list)) 0)
461 (forcebreak (reverse (coerce lisp-name-string 'list)) 0)
462 (forcebreak (reverse (coerce lisp-version-string 'list)) 0))
463 nil)
465 (setf (get '%build_info 'dimension) 'dimension-build-info)
467 (defvar *maxima-started* nil)
469 (defvar *maxima-prolog* "")
470 (defvar *maxima-epilog* "")
472 (declare-top (special *maxima-initmac* *maxima-initlisp*))
474 (defvar *maxima-quiet* nil)
476 (defun macsyma-top-level (&optional (input-stream *standard-input*) batch-flag)
477 (let ((*package* (find-package :maxima)))
478 (if *maxima-started*
479 (format t (intl:gettext "Maxima restarted.~%"))
480 (progn
481 (if (not *maxima-quiet*) (maxima-banner))
482 (setq *maxima-started* t)))
484 (if ($file_search *maxima-initlisp*) ($load ($file_search *maxima-initlisp*)))
485 (if ($file_search *maxima-initmac*) ($batchload ($file_search *maxima-initmac*)))
487 (catch 'quit-to-lisp
488 (in-package :maxima)
489 (loop
491 (catch #+kcl si::*quit-tag*
492 #+(or cmu scl sbcl openmcl lispworks) 'continue
493 #-(or kcl cmu scl sbcl openmcl lispworks) nil
494 (catch 'macsyma-quit
495 (continue input-stream batch-flag)
496 (format t *maxima-epilog*)
497 (bye)))))))
499 (defun maxima-banner ()
500 (format t *maxima-prolog*)
501 (format t "~&Maxima ~a http://maxima.sourceforge.net~%"
502 *autoconf-version*)
503 (format t (intl:gettext "using Lisp ~a ~a") (lisp-implementation-type)
504 #-clisp (lisp-implementation-version)
505 #+clisp (subseq (lisp-implementation-version)
506 0 (1+ (search ")" (lisp-implementation-version)))))
507 (format t (intl:gettext "~%Distributed under the GNU Public License. See the file COPYING.~%"))
508 (format t (intl:gettext "Dedicated to the memory of William Schelter.~%"))
509 (format t (intl:gettext "The function bug_report() provides bug reporting information.~%")))
511 #+kcl
512 (si::putprop :t 'throw-macsyma-top 'si::break-command)
514 (defun throw-macsyma-top ()
515 (throw 'macsyma-quit t))
517 (defmfun $writefile (x)
518 (let ((msg (dribble (maxima-string x))))
519 (format t "~&~A~&" msg)
520 '$done))
522 (defvar $appendfile nil )
523 (defvar *appendfile-data*)
525 (defmfun $appendfile (name)
526 (if (and (symbolp name)
527 (char= (char (symbol-name name) 0) #\$))
528 (setq name (maxima-string name)))
529 (if $appendfile (merror (intl:gettext "appendfile: already in appendfile, you must call closefile first.")))
530 (let ((stream (open name :direction :output
531 :if-exists :append
532 :if-does-not-exist :create)))
533 (setq *appendfile-data* (list stream *terminal-io* name))
535 (setq $appendfile (make-two-way-stream
536 (make-echo-stream *terminal-io* stream)
537 (make-broadcast-stream *terminal-io* stream))
538 *terminal-io* $appendfile)
539 (multiple-value-bind (sec min hour day month year)
540 (get-decoded-time)
541 (format t (intl:gettext "~&/* Starts dribbling to ~A (~d/~d/~d, ~2,'0d:~2,'0d:~2,'0d).*/~&")
542 name year month day hour min sec))
543 '$done))
545 (defmfun $closefile ()
546 (cond ($appendfile
547 (cond ((eq $appendfile *terminal-io*)
548 (format t (intl:gettext "~&/*Finished dribbling to ~A.*/~&")
549 (nth 2 *appendfile-data*))
550 (setq *terminal-io* (nth 1 *appendfile-data*)))
551 (t (warn "*TERMINAL-IO* was rebound while APPENDFILE is on.~%~
552 You may miss some dribble output.")))
553 (close (nth 0 *appendfile-data*))
554 (setq *appendfile-data* nil $appendfile nil))
555 (t (let ((msg (dribble)))
556 (format t "~&~A~&" msg))))
557 '$done)
559 (defmfun $ed (x)
560 (ed (maxima-string x)))
562 (defun nsubstring (x y)
563 (subseq x y))
565 (defun filestrip (x)
566 (subseq (print-invert-case (car x)) 1))
568 (defmspec $with_stdout (arg)
569 (declare (special $file_output_append))
570 (setq arg (cdr arg))
571 (let ((output (meval (car arg))))
572 (if (streamp output)
573 (let
574 ((*standard-output* output)
575 (body (cdr arg))
576 result)
577 (dolist (v body)
578 (setq result (meval* v)))
579 result)
580 (let*
581 ((fname (namestring (maxima-string output)))
582 (filespec
583 (if (or (eq $file_output_append '$true)
584 (eq $file_output_append t))
585 `(*standard-output* ,fname :direction :output :if-exists :append :if-does-not-exist :create)
586 `(*standard-output* ,fname :direction :output :if-exists :supersede :if-does-not-exist :create))))
587 (eval
588 `(with-open-file ,filespec
589 (let ((body ',(cdr arg)) result)
590 (dolist (v body)
591 (setq result (meval* v)))
592 result)))))))
594 (defun $sconcat (&rest x)
595 (let ((ans "") )
596 (dolist (v x)
597 (setq ans (concatenate 'string ans
598 (cond
599 ((stringp v) v)
601 (coerce (mstring v) 'string))))))
602 ans))
604 (defun $system (&rest args)
605 ;; If XMaxima is running, direct output from command into *SOCKET-CONNECTION*.
606 ;; From what I can tell, GCL, ECL, and Clisp cannot redirect the output into an existing stream. Oh well.
607 (let ((s (and (boundp '*socket-connection*) *socket-connection*))
608 shell shell-opt)
609 #+(or gcl ecl lispworks)
610 (declare (ignore s))
611 (declare (ignorable shell shell-opt))
613 (cond ((string= *autoconf-windows* "true")
614 (setf shell "cmd") (setf shell-opt "/c"))
615 (t (setf shell "/bin/sh") (setf shell-opt "-c")))
617 #+gcl (system::system (apply '$sconcat args))
618 #+ecl (si:system (apply '$concat args))
619 #+clisp (let ((output (ext:run-shell-command (apply '$sconcat args)
620 :wait t :output :stream)))
621 (loop for line = (read-line output nil)
622 while line do
623 (format (or s t) "~a~%" line)))
624 #+(or cmu scl) (ext:run-program shell (list shell-opt (apply '$sconcat args)) :output (or s t))
625 #+allegro (excl:run-shell-command (apply '$sconcat args) :wait t :output (or s nil))
626 #+sbcl (sb-ext:run-program shell
627 #+(or win32 win64) (cons shell-opt (mapcar '$sconcat args))
628 #-(or win32 win64) (list shell-opt (apply '$sconcat args))
629 :search t :output (or s t))
630 #+openmcl (ccl::run-program shell
631 #+windows (cons shell-opt (mapcar '$sconcat args))
632 #-windows (list shell-opt (apply '$sconcat args))
633 :output (or s t))
634 #+abcl (extensions::run-shell-command (apply '$sconcat args) :output (or s *standard-output*))
635 #+lispworks (system:run-shell-command (apply '$sconcat args) :wait t)))
637 (defun $room (&optional (arg nil arg-p))
638 (if (and arg-p (member arg '(t nil) :test #'eq))
639 (room arg)
640 (room)))
642 (defun maxima-lisp-debugger (condition me-or-my-encapsulation)
643 (declare (ignore me-or-my-encapsulation))
644 (format t (intl:gettext "~&Maxima encountered a Lisp error:~%~% ~A") condition)
645 (format t (intl:gettext "~&~%Automatically continuing.~%To enable the Lisp debugger set *debugger-hook* to nil.~%"))
646 (throw 'return-from-debugger t))
648 (let ((t0-real 0) (t0-run 0)
649 (float-units (float internal-time-units-per-second)))
651 (defun initialize-real-and-run-time ()
652 (setq t0-real (get-internal-real-time))
653 (setq t0-run (get-internal-run-time)))
655 (defun $absolute_real_time () (get-universal-time))
657 (defun $elapsed_real_time ()
658 (let ((elapsed-real-time (- (get-internal-real-time) t0-real)))
659 (/ elapsed-real-time float-units)))
661 (defun $elapsed_run_time ()
662 (let ((elapsed-run-time (- (get-internal-run-time) t0-run)))
663 (/ elapsed-run-time float-units))))