37.body.scm 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. ;;; args-fold.scm - a program argument processor
  2. ;;;
  3. ;;; Copyright (c) 2002 Anthony Carrico
  4. ;;; Copyright (c) 2014 Taylan Ulrich Bayırlı/Kammer
  5. ;;;
  6. ;;; All rights reserved.
  7. ;;;
  8. ;;; Redistribution and use in source and binary forms, with or without
  9. ;;; modification, are permitted provided that the following conditions
  10. ;;; are met:
  11. ;;; 1. Redistributions of source code must retain the above copyright
  12. ;;; notice, this list of conditions and the following disclaimer.
  13. ;;; 2. Redistributions in binary form must reproduce the above copyright
  14. ;;; notice, this list of conditions and the following disclaimer in the
  15. ;;; documentation and/or other materials provided with the distribution.
  16. ;;; 3. The name of the authors may not be used to endorse or promote products
  17. ;;; derived from this software without specific prior written permission.
  18. ;;;
  19. ;;; THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
  20. ;;; IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  21. ;;; OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  22. ;;; IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  23. ;;; INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  24. ;;; NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25. ;;; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26. ;;; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. ;;; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  28. ;;; THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. (define-record-type <option>
  30. (option names required-arg? optional-arg? processor)
  31. option?
  32. (names option-names)
  33. (required-arg? option-required-arg?)
  34. (optional-arg? option-optional-arg?)
  35. (processor option-processor))
  36. (define (args-fold args options unrecognized-option-proc operand-proc . seeds)
  37. (define (find-option name)
  38. ;; ISSUE: This is a brute force search. Could use a table.
  39. (find (lambda (option)
  40. (find (lambda (test-name)
  41. (equal? name test-name))
  42. (option-names option)))
  43. options))
  44. (define (scan-short-options index shorts args seeds)
  45. (if (= index (string-length shorts))
  46. (scan-args args seeds)
  47. (let* ((name (string-ref shorts index))
  48. (option (or (find-option name)
  49. (option (list name)
  50. #f
  51. #f
  52. unrecognized-option-proc))))
  53. (cond
  54. ((and (< (+ index 1) (string-length shorts))
  55. (or (option-required-arg? option)
  56. (option-optional-arg? option)))
  57. (let-values
  58. ((seeds (apply (option-processor option)
  59. option
  60. name
  61. (substring
  62. shorts
  63. (+ index 1)
  64. (string-length shorts))
  65. seeds)))
  66. (scan-args args seeds)))
  67. ((and (option-required-arg? option)
  68. (pair? args))
  69. (let-values
  70. ((seeds (apply (option-processor option)
  71. option
  72. name
  73. (car args)
  74. seeds)))
  75. (scan-args (cdr args) seeds)))
  76. (else
  77. (let-values
  78. ((seeds (apply (option-processor option)
  79. option
  80. name
  81. #f
  82. seeds)))
  83. (scan-short-options
  84. (+ index 1)
  85. shorts
  86. args
  87. seeds)))))))
  88. (define (scan-operands operands seeds)
  89. (if (null? operands)
  90. (apply values seeds)
  91. (let-values ((seeds (apply operand-proc
  92. (car operands)
  93. seeds)))
  94. (scan-operands (cdr operands) seeds))))
  95. (define (scan-args args seeds)
  96. (if (null? args)
  97. (apply values seeds)
  98. (let ((arg (car args))
  99. (args (cdr args)))
  100. ;; NOTE: This string matching code would be simpler
  101. ;; using a regular expression matcher.
  102. (cond
  103. ((string=? "--" arg)
  104. ;; End option scanning:
  105. (scan-operands args seeds))
  106. ((and (> (string-length arg) 4)
  107. (char=? #\- (string-ref arg 0))
  108. (char=? #\- (string-ref arg 1))
  109. (not (char=? #\= (string-ref arg 2)))
  110. (let loop ((index 3))
  111. (cond ((= index (string-length arg))
  112. #f)
  113. ((char=? #\= (string-ref arg index))
  114. index)
  115. (else
  116. (loop (+ 1 index))))))
  117. ;; Found long option with arg:
  118. => (lambda (=-index)
  119. (let*-values
  120. (((name)
  121. (substring arg 2 =-index))
  122. ((option-arg)
  123. (substring arg
  124. (+ =-index 1)
  125. (string-length arg)))
  126. ((option)
  127. (or (find-option name)
  128. (option (list name)
  129. #t
  130. #f
  131. unrecognized-option-proc)))
  132. (seeds
  133. (apply (option-processor option)
  134. option
  135. name
  136. option-arg
  137. seeds)))
  138. (scan-args args seeds))))
  139. ((and (> (string-length arg) 3)
  140. (char=? #\- (string-ref arg 0))
  141. (char=? #\- (string-ref arg 1)))
  142. ;; Found long option:
  143. (let* ((name (substring arg 2 (string-length arg)))
  144. (option (or (find-option name)
  145. (option
  146. (list name)
  147. #f
  148. #f
  149. unrecognized-option-proc))))
  150. (if (and (option-required-arg? option)
  151. (pair? args))
  152. (let-values
  153. ((seeds (apply (option-processor option)
  154. option
  155. name
  156. (car args)
  157. seeds)))
  158. (scan-args (cdr args) seeds))
  159. (let-values
  160. ((seeds (apply (option-processor option)
  161. option
  162. name
  163. #f
  164. seeds)))
  165. (scan-args args seeds)))))
  166. ((and (> (string-length arg) 1)
  167. (char=? #\- (string-ref arg 0)))
  168. ;; Found short options
  169. (let ((shorts (substring arg 1 (string-length arg))))
  170. (scan-short-options 0 shorts args seeds)))
  171. (else
  172. (let-values ((seeds (apply operand-proc arg seeds)))
  173. (scan-args args seeds)))))))
  174. (scan-args args seeds))