+;;;; hacking the Unix environment
+;;;;
+;;;; In the original CMU CL code that LOAD-FOREIGN is derived from, the
+;;;; Unix environment (as in "man environ") was represented as an
+;;;; alist from keywords to strings, so that e.g. the Unix environment
+;;;; "SHELL=/bin/bash" "HOME=/root" "PAGER=less"
+;;;; was represented as
+;;;; ((:SHELL . "/bin/bash") (:HOME . "/root") (:PAGER "less"))
+;;;; This had a few problems in principle: the mapping into
+;;;; keyword symbols smashed the case of environment
+;;;; variables, and the whole mapping depended on the presence of
+;;;; #\= characters in the environment strings. In practice these
+;;;; problems weren't hugely important, since conventionally environment
+;;;; variables are uppercase strings followed by #\= followed by
+;;;; arbitrary data. However, since it's so manifestly not The Right
+;;;; Thing to make code which breaks unnecessarily on input which
+;;;; doesn't follow what is, after all, only a tradition, we've switched
+;;;; formats in SBCL, so that the fundamental environment list
+;;;; is just a list of strings, with a one-to-one-correspondence
+;;;; to the C-level representation. I.e., in the example above,
+;;;; the SBCL representation is
+;;;; '("SHELL=/bin/bash" "HOME=/root" "PAGER=less")
+;;;; CMU CL's implementation is currently supported to help with porting.
+;;;;
+;;;; It's not obvious that this code belongs here (instead of e.g. in
+;;;; unix.lisp), since it has only a weak logical connection with
+;;;; RUN-PROGRAM. However, physically it's convenient to put it here.
+;;;; It's not needed at cold init, so we *can* put it in this
+;;;; warm-loaded file. And by putting it in this warm-loaded file, we
+;;;; make it easy for it to get to the C-level 'environ' variable.
+;;;; which (at least in sbcl-0.6.10 on Red Hat Linux 6.2) is not
+;;;; visible at GENESIS time.
+
+(define-alien-routine wrapped-environ (* c-string))
+(defun posix-environ ()
+ "Return the Unix environment (\"man environ\") as a list of SIMPLE-STRINGs."
+ (c-strings->string-list (wrapped-environ)))
+
+;;; Convert as best we can from an SBCL representation of a Unix
+;;; environment to a CMU CL representation.
+;;;
+;;; * (UNIX-ENVIRONMENT-CMUCL-FROM-SBCL '("Bletch=fub" "Noggin" "YES=No!"))
+;;; WARNING:
+;;; smashing case of "Bletch=fub" in conversion to CMU-CL-style
+;;; environment alist
+;;; WARNING:
+;;; no #\= in "Noggin", eliding it in CMU-CL-style environment alist
+;;; ((:BLETCH . "fub") (:YES . "No!"))
+(defun unix-environment-cmucl-from-sbcl (sbcl)
+ (mapcan
+ (lambda (string)
+ (declare (type simple-base-string string))
+ (let ((=-pos (position #\= string :test #'equal)))
+ (if =-pos
+ (list
+ (let* ((key-as-string (subseq string 0 =-pos))
+ (key-as-upcase-string (string-upcase key-as-string))
+ (key (keywordicate key-as-upcase-string))
+ (val (subseq string (1+ =-pos))))
+ (unless (string= key-as-string key-as-upcase-string)
+ (warn "smashing case of ~S in conversion to CMU-CL-style ~
+ environment alist"
+ string))
+ (cons key val)))
+ (warn "no #\\= in ~S, eliding it in CMU-CL-style environment alist"
+ string))))
+ sbcl))