PageRenderTime 41ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/tools/error-code-snarf.scm

http://github.com/xatom/GPGME-Guile
Scheme | 345 lines | 250 code | 26 blank | 69 comment | 0 complexity | b207a6f57cd787205985cbc8ea928f0e MD5 | raw file
  1. #!/bin/sh
  2. exec guile -e main -s "$0" "$@"
  3. !#
  4. ;;; GPGME/G : GPGME with Guile
  5. ;;;
  6. ;;; A Guile binding to the GPGME library
  7. ;;; Error setup tools
  8. ;;;
  9. ;;; Copyright © 2011, 2013 Atom X Zane
  10. ;;;
  11. ;;; This library is free software: you can redistribute it and/or
  12. ;;; modify it under the terms of the GNU General Public License as
  13. ;;; published by the Free Software Foundation, either version 3 of the
  14. ;;; License, or (at your option) any later version.
  15. ;;;
  16. ;;; This library is distributed in the hope that it will be useful,
  17. ;;; but WITHOUT ANY WARRANTY; without even the implide warranty of
  18. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  19. ;;; General Public License for more details.
  20. ;;;
  21. ;;; You should have received a copy of the GNU General Public License
  22. ;;; along with this library. If not, see
  23. ;;; <http://www.gnu.org/licenses/>.
  24. ;;; Commentary:
  25. ;; The GPGME library deals with a @emph{lot} of error cases, some of
  26. ;; which are moving targets as far as creating bindings are concerned.
  27. ;; The procedures in this file are a simple set of tools that allow at
  28. ;; least some automation of the error binding process.
  29. ;;
  30. ;; The libgpg-error distribution includes several files where errors
  31. ;; and error sources are defined:
  32. ;;
  33. ;; @table @samp
  34. ;; @item err-codes.h.in
  35. ;; The GPG-specifice error codes and descriptions. The format is,
  36. ;; line-by-line,
  37. ;; @code{^[[:digits:]]+[\t]+[A-Z][A-Z_]+[A-Z][\t]+[[:alnum:] ]+$}
  38. ;;
  39. ;; @item err-sources.h.in
  40. ;; GPG error sources and descriptions. The format is the same as
  41. ;; for @samp{err-codes.h.in}
  42. ;;
  43. ;; @item errnos.in
  44. ;; The system-error translation table. The format is,
  45. ;; line-by-line:
  46. ;; @code{^[[:digit:]]+[\t]+[A-Z]+$}
  47. ;;
  48. ;; A special value, which shows up as
  49. ;; @code{#define GPG_ERR_SYSTEM_ERROR (1 << 15)}
  50. ;; in the resulting @samp{gpg-error.h} file is used as the basis
  51. ;; for the system error translation: the leading number of the
  52. ;; errors declared in @samp{errnos.in} are bitwise-or'ed with
  53. ;; @code{GPG_ERR_SYSTEM_ERROR} to get their final number. We will
  54. ;; put their actual values in to save on computation time.
  55. ;;
  56. ;; @end table
  57. ;;
  58. ;; At this time these tools are for GPGME/Guile developers' use only;
  59. ;; they require the libgpg-error sources to work properly, which users
  60. ;; cannot be expected to have on hand. As such, the files
  61. ;; @samp{error-sources.scm} and @samp{error-codes.scm} are to be
  62. ;; distributed complete with each release, or possibly even in the
  63. ;; archives themselves. *** FIXME ***
  64. ;;; Code:
  65. (use-modules (ice-9 popen)
  66. (ice-9 rdelim)
  67. (ice-9 regex)
  68. (ice-9 pretty-print)
  69. (ice-9 binary-ports)
  70. (rnrs bytevectors)
  71. (srfi srfi-1)
  72. (system foreign))
  73. (define libgpg-error (dynamic-link "libgpg-error"))
  74. (define *libgpg-error-prefix*
  75. (let* ((p (open-input-pipe "gpg-error-config --cflags"))
  76. (dir (substring (read-line p) 2)))
  77. (close-pipe p)
  78. dir))
  79. (define error-code->description
  80. (let ((gpg-strerror
  81. (pointer->procedure
  82. '*
  83. (dynamic-func "gpg_strerror" libgpg-error)
  84. (list unsigned-int))))
  85. (lambda (code)
  86. (pointer->string
  87. (gpg-strerror code)))))
  88. (define error-source->description
  89. (let ((gpg-strsource
  90. (pointer->procedure
  91. '*
  92. (dynamic-func "gpg_strsource" libgpg-error)
  93. (list unsigned-int)))
  94. (source-mask 127)
  95. (source-shift (1- (expt 2 7))))
  96. (lambda (code)
  97. (pointer->string
  98. (gpg-strsource (ash (logand code source-mask) 24))))))
  99. (define (error-code->number code)
  100. (let ((mask (ash 1 15))
  101. (num
  102. (string->number
  103. (string-delete (char-set-complement char-set:digit) code))))
  104. (if (string-prefix? "GPG_ERR_SYSTEM_ERROR" code)
  105. (logior mask num)
  106. num)))
  107. (define (error-string->pair str)
  108. (let ((err-pair
  109. (map
  110. (lambda (s)
  111. (string-trim-both
  112. s (char-set #\space #\,)))
  113. (string-split str #\=))))
  114. (cons
  115. (car err-pair)
  116. (error-code->number (cadr err-pair)))))
  117. (define (c-error-name->symbol cname)
  118. (define prefix-rx (make-regexp "(GPG_ERR(_SOURCE)?)[_-]"))
  119. (let ((prefix
  120. (or (and (string-prefix? "GPG_ERR_SOURCE_" cname)
  121. "error-source")
  122. (and (string-prefix? "GPG_ERR_" cname)
  123. "error-code")
  124. (error "Unknown error symbol" cname)))
  125. (name (string-join
  126. (string-split
  127. (string-downcase
  128. (match:suffix
  129. (regexp-exec prefix-rx cname)))
  130. #\_)
  131. "-")))
  132. (string->symbol
  133. (string-append prefix "/" name))))
  134. (define (extract-error-sources error-list)
  135. (map error-string->pair
  136. (filter (lambda (str)
  137. (and (string-prefix? "GPG_ERR_SOURCE" str)
  138. (string-index str #\=)))
  139. error-list)))
  140. (define (extract-error-codes error-list)
  141. (map error-string->pair
  142. (filter (lambda (str)
  143. (and (string-prefix? "GPG_ERR" str)
  144. (not (string-prefix? "GPG_ERR_SOURCE" str))
  145. (string-index str #\=)))
  146. error-list)))
  147. (define (output-error-code-define error-pair)
  148. (let ((name (c-error-name->symbol (car error-pair)))
  149. (value (cdr error-pair))
  150. (description (error-code->description
  151. (cdr error-pair))))
  152. `(define-public ,name (make-error-code ,value ,description))))
  153. (define (output-error-source-define error-pair)
  154. (let ((name (c-error-name->symbol (car error-pair)))
  155. (value (cdr error-pair))
  156. (description (error-source->description
  157. (cdr error-pair))))
  158. `(define-public ,name (make-error-source ,value ,description))))
  159. (define (extract-error-decls lines)
  160. (map
  161. (lambda (line)
  162. (string-trim-both line (char-set-adjoin char-set:whitespace #\,)))
  163. (filter (lambda (line)
  164. (string-match "^[[:space:]]*GPG_ERR_.*[[:digit:]],?" line))
  165. lines)))
  166. (define (output-error-code-dim input dim-value)
  167. (regexp-substitute
  168. #f (string-match "@@ERROR_CODE_DIM@@" input)
  169. 'pre dim-value 'post))
  170. (define (output-error-code-decls input decls)
  171. (regexp-substitute
  172. #f (string-match "@@ERROR_CODE_DECLS@@" input)
  173. 'pre decls 'post))
  174. (define (output-error-code-lookup input lookups)
  175. (let ((l (string-append
  176. " `"
  177. (substring
  178. (regexp-substitute/global
  179. #f
  180. "(error-code/)"
  181. (with-output-to-string
  182. (lambda ()
  183. (pretty-print
  184. (let loop ((rest lookups)
  185. (done '()))
  186. (if (null? rest)
  187. (reverse done)
  188. (loop (cdr rest)
  189. (if (string= (caar rest) "GPG_ERR_CODE_DIM")
  190. done
  191. (cons
  192. (cons (cdar rest)
  193. (c-error-name->symbol (caar rest)))
  194. done)))))
  195. #:per-line-prefix " ")))
  196. 'pre "," 1 'post)
  197. 4))))
  198. (regexp-substitute
  199. #f (string-match "@@ERROR_CODE_LOOKUP@@" input)
  200. 'pre l 'post)))
  201. (define (output-error-source-dim input dim-value)
  202. (regexp-substitute
  203. #f (string-match "@@ERROR_SOURCE_DIM@@" input)
  204. 'pre dim-value 'post))
  205. (define (output-error-source-decls input decls)
  206. (regexp-substitute
  207. #f (string-match "@@ERROR_SOURCE_DECLS@@" input)
  208. 'pre decls 'post))
  209. (define (output-error-source-lookup input lookups)
  210. (let ((l (string-append
  211. " `"
  212. (substring
  213. (regexp-substitute/global
  214. #f
  215. "(error-source/)"
  216. (with-output-to-string
  217. (lambda ()
  218. (pretty-print
  219. (let loop ((rest lookups)
  220. (done '()))
  221. (if (null? rest)
  222. (reverse done)
  223. (loop (cdr rest)
  224. (if (string= (caar rest) "GPG_ERR_SOURCE_DIM")
  225. done
  226. (cons
  227. (cons (cdar rest)
  228. (c-error-name->symbol (caar rest)))
  229. done)))))
  230. #:per-line-prefix " ")))
  231. 'pre "," 1 'post)
  232. 4))))
  233. (regexp-substitute
  234. #f (string-match "@@ERROR_SOURCE_LOOKUP@@" input)
  235. 'pre l 'post)))
  236. (define (main . args)
  237. (let* ((error-decls
  238. (extract-error-decls
  239. (let ((p (open-input-file (string-append
  240. *libgpg-error-prefix*
  241. "/gpg-error.h"))))
  242. (let loop ((line (read-line p))
  243. (lines '()))
  244. (if (eof-object? line)
  245. (begin
  246. (close-port p)
  247. (reverse lines))
  248. (loop (read-line p)
  249. (cons line lines)))))))
  250. ;; error codes
  251. (error-codes (extract-error-codes error-decls))
  252. (error-code-defines
  253. (with-output-to-string
  254. (lambda ()
  255. (for-each
  256. (lambda (defn)
  257. (if (not (string=
  258. (car defn)
  259. "GPG_ERR_CODE_DIM"))
  260. (pretty-print (output-error-code-define defn))
  261. (display "")))
  262. error-codes))))
  263. ;; error sources
  264. (error-sources (extract-error-sources error-decls))
  265. (error-source-defines
  266. (with-output-to-string
  267. (lambda ()
  268. (for-each
  269. (lambda (defn)
  270. (if (not (string=
  271. (car defn)
  272. "GPG_ERR_SOURCE_DIM"))
  273. (pretty-print (output-error-source-define defn))
  274. (display "")))
  275. error-sources))))
  276. ;; input files
  277. (error-codes.scm.in
  278. (let* ((p (open-input-file
  279. "../src/gpg/error-codes.scm.in" #:binary #t))
  280. (bv (get-bytevector-all p)))
  281. (close-port p)
  282. (utf8->string bv)))
  283. (error-sources.scm.in
  284. (let* ((p (open-input-file
  285. "../src/gpg/error-sources.scm.in" #:binary #t))
  286. (bv (get-bytevector-all p)))
  287. (close-port p)
  288. (utf8->string bv)))
  289. ;; output-files
  290. (error-codes.scm
  291. (open-output-file "../src/gpg/error-codes.scm" #:binary #t))
  292. (error-sources.scm
  293. (open-output-file "../src/gpg/error-sources.scm" #:binary #t)))
  294. (put-bytevector
  295. error-codes.scm
  296. (string->utf8
  297. (output-error-code-lookup
  298. (output-error-code-decls
  299. (output-error-code-dim
  300. error-codes.scm.in
  301. (number->string (assoc-ref error-codes "GPG_ERR_CODE_DIM")))
  302. error-code-defines)
  303. error-codes)))
  304. (close-port error-codes.scm)
  305. (put-bytevector
  306. error-sources.scm
  307. (string->utf8
  308. (output-error-source-lookup
  309. (output-error-source-decls
  310. (output-error-source-dim
  311. error-sources.scm.in
  312. (number->string (assoc-ref error-sources "GPG_ERR_SOURCE_DIM")))
  313. error-source-defines)
  314. error-sources)))
  315. (close-port error-sources.scm)))
  316. ;; Local Variables:
  317. ;; mode: scheme
  318. ;; End:
  319. ;;; err-setup.scm ends here