1
0
tigersay/tigersay.tig

226 lines
6.8 KiB
Plaintext

let
/*************/
/* Constants */
var false := 0
var true := 1
var INDENT := " "
var MAXWIDTH := 40
/* The cow is unused, and taken directly from the cowsay program. */
var COW := "\
\\\ ^__^ \n\
\ \\ (oo)\\_______ \n\
\ (__)\\ )\\/\\ \n\
\ ||----w | \n\
\ || ||"
/* The tiger is taken from http://www.ascii-art.de/ascii/t/tiger.txt */
var TIGER := "\
\\\ __,,,,_ \n\
\ \\ _ __..-;''`--/'/ /.',-`-. \n\
\ \\ (`/' ` | \\ \\ \\\\ / / / / .-'/`,_ \n\
\ /'`\\ \\ | \\ | \\| // // / -.,/_,'-, \n\
\ /<7' ; \\ \\ | ; ||/ /| | \\/ |`-/,/-.,_,/') \n\
\ / _.-, `,-\\,__| _-| / \\ \\/|_/ | '-/.;.\\' \n\
\ `-` f/ ; / __/ \\__ `/ |__/ | \n\
\ `-' | -| =|\\_ \\ |-' | \n\
\ __/ /_..-' ` ),' // \n\
\ ((__.-'((___..-'' \\__.' "
/***********/
/* Utility */
/* I/O */
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
/* Number / Maths */
function max (a:int, b:int) : int =
if a > b then a else b
function modulo (num : int, mod : int) : int =
( while num >= mod do
num := num - mod
; num )
function exp (exponee : int, exponent : int) : int =
if exponent = 0 then 1
else exponee * exp(exponee, exponent - 1)
function get_digit (num : int, digit : int) : int =
modulo(num / exp(10, digit-1), 10)
function log10 (num : int) : int =
let var log10 := 1
in while num > 9 do
( num := num/10
; log10 := log10 + 1 )
; log10
end
/* String manipulation */
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 indent_string (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
function is_whitespace (char:string) : int =
(char = "" | char = "\n" | char = " " | char = "\t")
function substring_absolute (text:string, i1:int, i2:int) : string =
/* Uses absolute coordinates to determine substring */
substring(text, i1, i2 - i1 + 1)
function count_substring_occurances (text:string, char:string) : int =
let var count := 0
var charwidth := size(char)
in for i := 0 to size(text) - charwidth do
if substring(text, i, charwidth) = char then
count := count + 1
; count
end
function repeat_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 (num : int) : string =
let var l := ""
in for i := 1 to log10(num) do
l := concat(digit_to_s(get_digit(num, i)), l)
; l
end
function length_of_longest_line (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
/* 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 ""
function ll_length (ll:stringll) : int =
if ll = nil
then 0
else 1 + ll_length(ll.next)
/**/
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, substring_absolute(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 wrap_string (text:string, linewidth: int) : string =
let var words := split_words(text)
var splitstr := insert_whitespace_between_words(words, linewidth)
in
ll_to_s( if ll_length(splitstr) > 2
then splitstr.next.next.next
else splitstr )
end
/**************/
/* Draw stuff */
function draw_textbubble (text:string) =
let
var textwidth := length_of_longest_line(text)
var textheight := count_substring_occurances(text, "\n") + 1
var bubblewidth := textwidth + 4
var after_text := concat3("\013\027[",int_to_s(bubblewidth-1),"C|")
in print(concat3(" ", repeat_string("_", bubblewidth - 2), " \n"))
; print(concat(indent_string(text, "| ", after_text), "\n"))
; print(concat3(" ", repeat_string("-", bubblewidth - 2), " \n"))
end
function draw_tiger () = print(indent_string(TIGER, INDENT, ""))
var text := getinput()
var wrappedtext := wrap_string(text, MAXWIDTH)
in
draw_textbubble(wrappedtext);
draw_tiger();
print("\n");
flush()
end