1

Is there function/package that allows to make "wide string literals" as defined by C/C++ standards. That is, where one has to replace all non-ascii characters with escaped "\x.." sequences.

1
  • Note there were some old definitions in my code and I missed to require seq. Both problems are corrected now.
    – Tobias
    Commented Jul 3, 2017 at 15:51

1 Answer 1

1

The following function transforms unicode strings into literal c-strings. Note however that the transformation is encoding dependent.

For interactive use just write your c-string with multibyte characters place point in the string and call M-x string-to-cStr.

(require 'seq)
(require 'cl-lib)

(defun string-to-cStr (string)
  "Return STRING encoded as literal c-string.
For interactive use just write your string with multibyte characters place point in the string and call M-x `string-to-cStr'."
  (interactive (string-to-cStr-interactive-form))
  (let ((ret (seq-mapcat (lambda (ch) (if (<= ch 127) (format "%c" ch)
                                        (format "\\x%.2x" ch)))
                         (encode-coding-string string buffer-file-coding-system) 'string)))
    (when (called-interactively-p 'any)
      (string-to-cStr-interactive-form string ret))
    ret))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defun string-to-cStr-interactive-form (&optional string ret)
  "Handles all the bits for the interactive use of `string-to-cStr'."
  (if (stringp string)
      (save-excursion
        (kill-region (get-text-property 0 'start string)
                     (get-text-property 0 'end string))
        (insert ret))
    (let ((ppss (syntax-ppss)))
      (cl-assert (derived-mode-p 'c-mode 'c++-mode))
      (cl-assert (eq (syntax-ppss-context ppss) 'string))
      (let* ((start (nth 8 ppss))
             (end (save-excursion
                    (goto-char start)
                    (forward-sexp)
                    (point))))
        (list (propertize (buffer-substring-no-properties start end) 'start start 'end end))))))

A small demonstration in an utf8 buffer:

printf("Test unicode characters such as ⇒ and ∫.");

/* becomes */

printf("Test unicode characters such as \xe2\x87\x92 and \xe2\x88\xab.");
7
  • @npostavs I've corrected my answer according to your comments. Thanks.
    – Tobias
    Commented Jul 3, 2017 at 16:32
  • Now I wonder why you define string-to-unibyte* instead of just using the existing string-to-unibyte? :p
    – npostavs
    Commented Jul 3, 2017 at 18:23
  • @npostavs: Because of the following remark in the documentation of string-to-unibyte: "If STRING contains a non-ASCII, non-‘eight-bit’ character, an error is signaled." The original string contains multibyte characters. These are re-interpreted as a sequence of unibyte characters through (set-buffer-multibyte nil) in the starred variant string-to-unibyte*. The non-starred variant string-to-unibyte bails out in such a case.
    – Tobias
    Commented Jul 3, 2017 at 19:15
  • Ah, I think you really want encode-coding-string which will also let you choose the encoding (or use buffer-file-coding-system if you don't want to choose).
    – npostavs
    Commented Jul 3, 2017 at 20:12
  • @npostavs cl was just an old habit. It is corrected.
    – Tobias
    Commented Jul 4, 2017 at 4:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.