let /*************/ /* Constants */ var false := 0 var true := 1 var INDENT := " " var TIGER := "\ \\\ ^__^\n\ \ \\ (oo)\\_______\n\ \ (__)\\ )\\/\\\n\ \ ||----w |\n\ \ || ||" /*************/ /* Utilility */ function getinput () : string = let var l := "" /* Full output */ var c := "" /* Current char */ in while true do ( c := getchar() ; if c = "" then break /* Hit EOF */ ; l := concat(l, c) ) ; l end function concat3 (a:string, b:string, c:string) : string = concat(a, concat(b, c)) function concat4 (a:string, b:string, c:string, d:string) : string = concat(a, concat(b, concat(c, d))) function indentstring (text : string, before : string, after:string) : string = let var out := before var char := "" in for i := 0 to size(text) - 1 do ( char := substring (text, i, 1) ; out := concat(out, if char <> "\n" then char else concat3(after, char, before))); concat(out, after) end /* Linked Lists */ type stringll = { val: string, next: stringll } function ll_new () : stringll = stringll { val = "", next = nil } function ll_append (ll:stringll, str:string) = if ll.next = nil then ll.next := stringll { val = str, next = nil } else ll_append(ll.next, str) function ll_to_s (ll:stringll) : string = if ll <> nil then concat(ll.val, ll_to_s(ll.next)) else "" var MAXWIDTH := 40 function is_whitespace (char:string) : int = (char = "" | char = "\n" | char = " " | char = "\t") function substringabs (text:string, i1:int, i2:int) : string = substring(text, i1, i2 - i1 + 1) function split_words (text:string) : stringll = let var out := ll_new() var prev_word_start_i := -1 var char := "" in for i := 0 to size(text) - 1 do ( char := substring(text, i, 1) ; if is_whitespace(char) & prev_word_start_i <> -1 then ll_append(out, substringabs(text, prev_word_start_i, i - 1)) else if not(is_whitespace(char)) & prev_word_start_i = -1 then prev_word_start_i := i ; if is_whitespace(char) then prev_word_start_i := -1 ) ; out end function insert_whitespace_between_words (words : stringll, linewidth:int) : stringll = let function help (words:stringll, width:int) : stringll = if words = nil then nil else if width + size(words.val) > linewidth then stringll { val = "\n", next = stringll { val = words.val, next = help(words.next, size(words.val)) } } else stringll { val = " ", next = stringll { val = words.val, next = help(words.next, size(words.val) + width ) } } in help(words, 0) end function wrapstring (text:string, linewidth: int) : string = let var words := split_words(text) var splitstr := insert_whitespace_between_words(words, linewidth) in ll_to_s(splitstr.next.next.next) end function max (a:int, b:int) : int = if a > b then a else b function longest_line_length (text:string) : int = let var longest := 0 var current := 0 in for i := 0 to size(text) - 1 do if substring(text, i, 1) = "\n" then ( longest := max(longest, current) ; current := 0) else current := current + 1 ; max(longest, current) end function nr_char_in_str (text:string, char:string) : int = let var count := 0 var charwidth := size(char) in for i := 0 to size(text) - 1 do if substring(text, i, charwidth) = char then count := count + 1 ; count end function rep_string (str:string, rep:int) : string = let var out := "" in for i := 1 to rep do out := concat(out, str) ; out end function digit_to_s (n:int) :string = if 0 <= n & n <= 9 then chr(48 + n) else "?" function int_to_s (n:int) : string = concat(digit_to_s(n/10), digit_to_s(n - n/10*10)) /**************/ /* Draw stuff */ function drawtextbubble (text:string) = let var textwidth := longest_line_length(text) var textheight := nr_char_in_str(text, "\n") + 1 var bubblewidth := textwidth + 4 var after_text := concat3("\013\027[",int_to_s(bubblewidth-1),"C|") in print(concat(" ", concat(rep_string("_", bubblewidth - 2), " \n"))) ; print(concat(indentstring(text, "| ", after_text), "\n")) ; print(concat(" ", concat(rep_string("-", bubblewidth - 2), " \n"))) end function drawtiger () = print(indentstring(TIGER, INDENT, "")) var text := getinput() in drawtextbubble(wrapstring(text, MAXWIDTH)); drawtiger(); print("\n") end