wisp
 
(Arne Babenhauserheide)
2016-04-08: merge

merge

diff --git a/examples/safepassword.w b/examples/safepassword.w
new file mode 100755
--- /dev/null
+++ b/examples/safepassword.w
@@ -0,0 +1,104 @@
+#!/usr/bin/env sh
+# -*- wisp -*-
+exec guile -L $(dirname $(dirname $(realpath "$0"))) --language=wisp -e '(@@ (examples safepassword) main)' -s "$0" "$@"
+; !#
+
+;; Create safe passwords, usable on US and German keyboards without problems
+
+define-module : examples safepassword
+              . #:export : password
+
+import
+    only (srfi srfi-27) random-source-make-integers
+      . make-random-source random-source-randomize!
+    only (srfi srfi-1) second third iota
+    srfi srfi-42
+
+
+;; newbase60 without yz_: 57 letters, each 5.78 bits of entropy.
+define qwertysafeletters "0123456789ABCDEFGHJKLMNPQRSTUVWXabcdefghijkmnopqrstuvwx"
+;; delimiters: 2.32 bits of entropy per delimiter.
+define delimiters ",.!?-"
+
+define random-source : make-random-source
+random-source-randomize! random-source
+
+
+define random-integer 
+       random-source-make-integers random-source
+
+
+define : randomletter letters
+      string-ref letters
+        random-integer
+          string-length letters
+
+
+define : flatten e
+    cond 
+       : pair? e
+         ` 
+           ,@ flatten : car e 
+           ,@ flatten : cdr e
+       : null? e
+         list
+       else 
+         list e
+
+
+define : password/srfi-42 length
+       list->string
+         append-ec (: i (iota length 1))
+           cons : randomletter qwertysafeletters
+             if : and (not (= i length)) : zero? : modulo i 4
+                cons : randomletter delimiters
+                  list
+                list
+
+
+define : password/map length
+       list->string
+         flatten
+           map
+             lambda : i
+               let
+                 : letter : randomletter qwertysafeletters
+                 if : and (not (= i length)) : zero? : modulo i 4
+                    list letter 
+                      randomletter delimiters
+                    list letter
+             iota length 1
+
+
+define : password length
+       let fill
+         : letters '()
+           remaining length
+         if : zero? remaining
+            reverse-list->string letters
+            fill
+              cons : randomletter qwertysafeletters
+                if : and (not (= length remaining)) : zero? : modulo remaining 4
+                   cons : randomletter delimiters
+                        . letters
+                   . letters
+              - remaining 1
+
+
+define : main args
+      let
+       :
+         len
+           if : <= 2 : length args
+              string->number : second args
+              . 16
+       let 
+         : idx (if (> 3 (length args)) 1 (string->number (third args)))
+         cond
+           : = idx 1
+             display : password len
+           : = idx 2
+             display : password/map len
+           : = idx 3
+             display : password/srfi-42 len
+         newline