ciphermytext-cli.scm 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. #!/usr/bin/env scheme-r7rs
  2. (import (scheme base)
  3. (scheme load)
  4. (scheme write)
  5. (scheme process-context)
  6. (scheme cxr)
  7. (scheme file)
  8. (macduffie cipher)
  9. (srfi 1))
  10. (define (usage)
  11. (display "Usage: ciphermytext [options] [-e] <algorithm> <plaintext/[-f=?]> <key>
  12. ciphermytext [options] -d <algorithm> <ciphertext/[-f=?]> <key>
  13. Algorithms:
  14. autokey
  15. caesar
  16. mono
  17. reptkey
  18. Options:
  19. -f=? Read from a file instead of an inline string.
  20. -h Display this help text.
  21. -i=? Set the number of iterations.
  22. -p Preserve the punctuation of the original message.
  23. -v Display the version of the software.\n")
  24. (exit))
  25. (define (version)
  26. (display "Version: 0.0.1\n")
  27. (exit))
  28. (define (extract-parameterized-arg args param-char default)
  29. (let loop ((list-out '())
  30. (list-in args))
  31. (if (null? list-in)
  32. (values args default)
  33. (let ((value (car list-in)))
  34. (if (and (char=? (string-ref value 0) #\-)
  35. (char=? (string-ref value 1) param-char))
  36. (if (not (char=? (string-ref value 2) #\=))
  37. (usage)
  38. (values (append (reverse list-out)
  39. (cdr list-in))
  40. (substring value 3 (string-length value))))
  41. (loop (cons value list-out) (cdr list-in)))))))
  42. (define (extract-iterations args)
  43. (define-values (a b) (extract-parameterized-arg args #\i "1"))
  44. (values a (string->number b)))
  45. (define (extract-file-type args)
  46. (extract-parameterized-arg args #\f #f))
  47. (define (extract-mode args)
  48. (if (member "-d" args)
  49. (values (delete "-d" args)
  50. 'decipher)
  51. (values (if (member "-e" args)
  52. (delete "-e" args)
  53. args)
  54. 'encipher)))
  55. (define (extract-punct args)
  56. (if (member "-p" args)
  57. (values (delete "-p" args)
  58. #t)
  59. (values args #f)))
  60. (define (check-algorithm algo)
  61. (if (not (member (string->symbol algo) (map car algos)))
  62. (usage)))
  63. (define (check-undetected args file-type)
  64. (for-each (lambda (x)
  65. (if (char=? (string-ref x 0) #\-)
  66. (usage)))
  67. args)
  68. (if (not (or (and (not file-type)
  69. (= (length args) 3))
  70. (and file-type
  71. (= (length args) 2))))
  72. (usage)))
  73. (define algos
  74. `((autokey ,autokey-encipher ,autokey-decipher)
  75. (caesar ,caesar-encipher ,caesar-decipher)
  76. (mono ,mono-encipher ,mono-decipher)
  77. (reptkey ,reptkey-encipher ,reptkey-decipher)))
  78. (define (get-cipher-type algo mode)
  79. (if (eq? mode 'encipher)
  80. (cadr (assq (string->symbol algo) algos))
  81. (caddr (assq (string->symbol algo) algos))))
  82. (define (read-entire-file file-name)
  83. (define port-in
  84. ;; A single dash means read from stdin
  85. (if (string=? file-name "-")
  86. (current-input-port)
  87. (open-input-file file-name)))
  88. (let loop ((result '())
  89. (next-line (read-line port-in)))
  90. (if (string? next-line)
  91. (loop (cons "\n" (cons next-line result))
  92. (read-line port-in))
  93. (begin
  94. (close-port port-in)
  95. (apply string-append (reverse result))))))
  96. (define (xcipher algo text key mode iters punct)
  97. (define key-cast (if (equal? algo "caesar") (string->number key) key))
  98. (define (cipher-once current-text)
  99. (apply-cipher (get-cipher-type algo mode) punct current-text key-cast))
  100. (let loop ((i 0)
  101. (current-text text))
  102. (if (< i iters)
  103. (let ((a (cipher-once current-text)))
  104. (loop (+ i 1) a))
  105. current-text)))
  106. (define (main-prog args)
  107. (define-values (arg-iter iters)
  108. (extract-iterations args))
  109. (define-values (arg-file-type file-type)
  110. (extract-file-type arg-iter))
  111. (define-values (arg-mode cipher-mode)
  112. (extract-mode arg-file-type))
  113. (define-values (new-args punctuate)
  114. (extract-punct arg-mode))
  115. (if (< iters 1)
  116. (error "ciphermytext-cli" "Iterations must be at least 1."))
  117. (if (or (member "--help" new-args)
  118. (member "-h" new-args))
  119. (usage))
  120. (if (or (member "--version" new-args)
  121. (member "-v" new-args))
  122. (version))
  123. (check-undetected new-args file-type)
  124. (check-algorithm (car new-args))
  125. (let ((result (if file-type
  126. (xcipher (car new-args) (read-entire-file file-type) (cadr new-args) cipher-mode iters punctuate)
  127. (xcipher (car new-args) (cadr new-args) (caddr new-args) cipher-mode iters punctuate))))
  128. (display result)
  129. (unless (and punctuate file-type) (newline))))
  130. (main-prog (cdr (command-line)))