Skip to content
string-escape.lisp 2.44 KiB
Newer Older
#+xcvb (module (:depends-on ("utilities")))
(defun escape-string-hashes (string &optional out)
  "Escapes only the hashes in a string.
This is required on the right side of a variable assignment in a Makefile. Go figure."
  (with-output (out)
    (loop :for c :across string :do
      (case c
        (#\# (write-string "\\#" out))
        (otherwise (write-char c out))))))

(defun escape-string-for-Makefile (string &optional out)
  "Takes a string and excapes all the characters that need to be put into a makefile.
The only such character right now is $.
Raises an error if the string contains a newline."
  (with-output (out)
    (loop :for c :across string :do
      (case c
        ;; Q: Instead of erroring, should this insert a "\\n" or something to escape the newline???
        ;; Q: Do we need to handle #\\ specially? Apparently, no. Make quoting is misdesigned.
        (#\newline (error "Makefile line cannot contain a newline"))
        (#\$ (write-string "$$" out))
        (otherwise (write-char c out))))))

Peter Keller's avatar
Peter Keller committed
(defun escape-sh-token-for-Makefile (string &optional out)
  "Takes a string and escapes it first for the shell, then for a makefile"
Peter Keller's avatar
Peter Keller committed
  (escape-string-for-Makefile (escape-sh-token string) out))

(defun shell-tokens-to-Makefile (tokens &optional out)
  "Transforms an list of tokens into something to print on a Makefile line
for the Makefile-invoked shell to execute the process specified by these tokens.
List elements can be either strings that will be escaped
or escapes of the form (:makefile string) that won't be escaped."
  (with-output (out)
Francois-Rene Rideau's avatar
Francois-Rene Rideau committed
    (loop :for (tok . rest) :on tokens :do
      (cond
        ((null tok))
        ((stringp tok)
         (escape-sh-token-for-Makefile tok out))
        ((and (consp tok) (eq :makefile (car tok)))
         (dolist (s (cdr tok))
           (write-string s out)))
        ((consp tok)
         (shell-tokens-to-Makefile tok out))
        (t
         (error "Invalid token member ~S" tok)))
      (when rest (write-char #\space out)))))
(defun shell-tokens-to-string (tokens &optional out)
  (with-output (out)
Francois-Rene Rideau's avatar
Francois-Rene Rideau committed
    (loop :for (tok . rest) :on tokens :do
      (cond
        ((null tok))
        ((stringp tok) (escape-sh-token tok out))
        (t (error "Invalid token ~S" tok)))
      (when rest (write-char #\space out)))))

(defun normalize-name-for-makefile (x)
  (map 'base-string (lambda (c) (if (find c "$`\\\" ()[]{};	") #\_ c)) x))