cadubi-1.3/0040755000175000017500000000000010015321626011246 5ustar bassbasscadubi-1.3/extras/0040755000175000017500000000000007372035411012562 5ustar bassbasscadubi-1.3/extras/ansi_term_codes.txt0100644000175000017500000001026707372035726016475 0ustar bassbassANSI TERMINAL CODES ------------------------------------------------------------------------ From the "Castle Perilous Manual" Original text Copyright (c) 1998 CircleWorld Converted to text & updated by Ian L. (1/23/00) ------------------------------------------------------------------------ ANSI is a standard for screen displays. Here is a listing of ANSI codes for color. Not available for game play, but is handy for coders. Wherever you see '#', that should be replaced by the appropriate number. The ESC char is usually hexidecimal 1B (ASCII 27, Octal 033) on most computers. To clarify this, in the example 'ESC[#B', to move the cursor down two lines you would print "\x1b[2B" in perl or in C. ESC code sequence Function ------------------------------------------------------------------------ >> Cursor Controls: Ê ESC[#;#H or ESC[#;#f Moves cusor to line #, column # ESC[#A Moves cursor up # lines ESC[#B Moves cursor down # lines ESC[#C Moves cursor forward # spaces ESC[#D Moves cursor back # spaces ESC[#;#R Reports current cursor line & column ESC[s Saves cursor position for recall later ESC[u Return to saved cursor position ------------------------------------------------------------------------ >> Erase Functions: Ê ESC[2J Clear screen and home cursor ESC[K Clear to end of line Ê Ê ------------------------------------------------------------------------ >> Set Graphics Rendition: ESC[#m Set single display attribute ESC[#;#;...;#m Set multiple display attributes where # is:Ê 0 for normal displayÊ 1 for bold onÊ 4 underline (mono only)Ê 5 blink onÊ 7 reverse video onÊ 8 nondisplayed (invisible)Ê 30 black foregroundÊ 31 red foregroundÊ 32 green foregroundÊ 33 yellow foregroundÊ 34 blue foregroundÊ 35 magenta foregroundÊ 36 cyan foregroundÊ 37 white foregroundÊ 40 black backgroundÊ 41 red backgroundÊ 42 green backgroundÊ 43 yellow backgroundÊ 44 blue backgroundÊ 45 magenta backgroundÊ 46 cyan backgroundÊ 47 white background ESC[=#;7h or.. ESC[=h or..Ê ESC[=0h or.. ESC[?7h Put screen in indicated mode where # is 0 for 40 x 25 black & whiteÊ 1 for 40 x 25 colorÊ 2 for 80 x 25 b&wÊ 3 for 80 x 25 colorÊ 4 for 320 x 200 color graphicsÊ 5 for 320 x 200 b & w graphicsÊ 6 for 640 x 200 b & w graphicsÊ 7 to wrap at end of line ESC[=#;7l or.. ESC[=l or.. ESC[=0l or.. ESC[?7l Resets mode # set with above command Ê Ê ------------------------------------------------------------------------ >> Keyboard Reassignments: Ê ESC[#;#;...p or.. ESC["string"p or.. ESC[#;"string";#; Using: #;"string";#p The first ASCII code defines which code is to be changed. The remaining codes define what it is to be changed to.Ê Example: Reassign the Q and q keys to the A and a keys (and vice versa).Ê ÊÊ ESC[65;81p --> A becomes QÊ ESC[97;113p --> a becomes qÊ ESC[81;65p --> Q becomes AÊ ESC[113;97p --> q becomes aÊ ÊÊ Example: Reassign the F10 key to a DIR command.Ê ESC [0;68;"dir";13p The 0;68 is the extended ASCII code for the F10 key and 13 is the ASCIIÊ code for a carriage return.Ê Other function key codes:Ê F1=59Ê F2=60Ê F3=61Ê F4=62Ê F5=63Ê F6=64Ê F7=65Ê F8=66Ê F9=67Ê F10=68 ------------------------------------------------------------------------ Eat snacky smores! cadubi-1.3/README0100644000175000017500000001671310015321455012133 0ustar bassbassCadubi - Creative ASCII Drawing Utility By Ian IMPORTANT -- Cadubi is no longer being maintained. 1.3 is a release for licensing and documentation fixes. See: http://langworth.com/CadubiProject --------------------------------------------------------------------- SYNOPSIS & AUTHOR --------------------------------------------------------------------- CADUBI is an application written in Perl that allows you to draw text-based images that are viewable on typical unix-based consoles. Usually the applications that emulate these consoles support various text modes, such as background and foreground colors, bold, and inverse. This text art, commonly called "ASCII art," is used in various places such as online BBSes, email and login prompts. --------------------------------------------------------------------- REQUIREMENTS --------------------------------------------------------------------- * Perl 5.002 or later --> http://www.perl.com/CPAN/src/latest.tar.gz * Term::ReadKey module --> http://www.perl.com/CPAN/CPAN.html --------------------------------------------------------------------- CONFIGURING CADUBI --------------------------------------------------------------------- Setting up CADUBI is quite easy. If you haven't already installed Term::ReadKey, do. The URL for Term::ReadKey is above under "REQUIREMENTS." To learn how to install a module, see Perl FAQ 8, under "How do I install a CPAN module?" Next, open up the 'cadubi' and 'CADUBI.pl' files. If you're perl executable is, for some reason, not located at /usr/bin/perl, change the first line of each file appropriately. Save your changes. Look in the file called 'cadubi' and examine the settings under "SETUP." Anything catch your eye? Save changes if you made any. Finally, make sure that the file called 'cadubi' is executable, and put a link to it in your /usr/bin, or wherever you keep your public executables. --------------------------------------------------------------------- USING CADUBI --------------------------------------------------------------------- CADUBI has a 'pen' which describes the current mode. Properties of the pen are the painting character, foreground color, background color, bold, inverse, and blink. Whenever you paint or use the text mode, the characters drawn on the screen will have the properties of the pen. The current mode of the pen is shown at the bottom of the console and is what will be drawn on screen when you paint. Move around the cursor with the 'i', 'j', 'k' and 'l' keys. Holding down shift and typing these keys will move the cursor five spaces instead of one. Pressing return/enter will move the cursor down one line and all the way to the left of the console. To paint the current pen on the screen, press the space bar. To delete a character, press the delete/backspace key. You'll notice that editing is much like common text editors, such as pico or joe. You can also delete with the '`' key, which makes moving & painting (right hand) and erasing (left hand) much easier. The pen character is the character that is drawn when you paint using the space bar. To change the character, press 'p' and then the character you would like it to be. To set the foreground or background colors for the cursor, press 'f' for foreground or 'b' for background, and then a corresponding color code. The color codes are case-insensitive and are listed below: 0 or N Normal (standard text) 1 or W White 2 or R Red 3 or G Green 4 or Y Yellow 5 or B Blue 6 or M Magenta 7 or C Cyan 8 or K Black If you can't remember the codes above, you can always hit control-'h' to view the Quick Help which will display a summary of all the keys, color codes and examples of how they look. Typically, foreground text colors are the same as background colors, unless the text is bold. If the text is bold, foreground colors are usually lighter than the background color, making text easier to read when the text has the same foreground and background color. Refer to the Quick Help (control-'h') to see what the colors look like on your console. Bold and inverse are two widely-supported modes. Bold is toggled with the 'g' key, and inverse is toggled with the 'v' key. Blink, though regarded as highly annoying, can be toggled with by pressing shift-'w'. Text mode is an extremely useful feature. Once in the text mode you can type as if you were using a normal text editor, and all the characters drawn onscreen will use the same mode as the pen. To enter text mode, press the 't' key. To exit, press escape. To exit the CADUBI application, press control-'x'. Quick help can be accessed by pressing control-'h'. In case it is needed, pressing control-'w' will refresh the entire screen by redrawing each character. --------------------------------------------------------------------- READING AND WRITING FILES --------------------------------------------------------------------- To read a file and use it with CADUBI, type control-'r'. To write a file, type control-'o'. You will be prompted for a filename. When CADUBI reads a file, it will only read as much that will fit in the workspace (the area of the console minus the bottom row [status bar]). To gain more workspace, see the '-s' operator in 'COMMAND LINE USAGE' below. CADUBI optimizes its output files to display properly and take up as little space as possible. All CADUBI output can be viewed with the 'cat' utility. --------------------------------------------------------------------- USAGE --------------------------------------------------------------------- Usage: cadubi [OPTIONS] [FILE] Available options: -h, --help what you're looking at now -m, --mute turn off beeping -s, --size [W] [H] sets the size of the console for use with CADUBI, where W is number of columns and H is number of rows. -v, --version show CADUBI version Example: Will make the cadubi workspace 160 columns wide, 48 rows high, disable beeping, and open the file 'bacon.txt': cadubi --mute --size 160 48 bacon.txt Will display the version of CADUBI, copyright and author: cadubi -v --------------------------------------------------------------------- NOTES --------------------------------------------------------------------- Whenever you are prompted to type in information, such as the name of a file to read/write to, you can hit escape to cancel. You can also hit escape to get out of text mode. When using the '-s' or '--size' command line option, make sure your console actually _is_ that size or the text won't wrap properly and CADUBI will look funny. The Quick Help actually displays the file 'CADUBI.help' that is in the same folder as 'CADUBI.pl'. That's all. Feel free to do something creative, just remember that when you redistribute CADUBI (that is, if you somehow feel compelled to do so), be sure to include all the original files. --------------------------------------------------------------------- AUTHOR --------------------------------------------------------------------- Ian Langworth - http://langworth.com/CadubiProject --------------------------------------------------------------------- LICENSE --------------------------------------------------------------------- Cadubi is copyright 1999-2004 Ian Langworth This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See: http://www.perl.com/perl/misc/Artistic.html cadubi-1.3/LICENSE0100644000175000017500000000031410015320040012233 0ustar bassbassCadubi is copyright 1999-2004 Ian Langworth This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See: http://www.perl.com/perl/misc/Artistic.html cadubi-1.3/logo.txt0100644000175000017500000000165507372035730012765 0ustar bassbass cccc rrrr yyy g g bbb m  c r r y y g g b b m  c rrrr y y g g bbb m  c r r y y g g b b m  cccc r r yyy gggg bbb m cadubi-1.3/cadubi0100755000175000017500000006044410015321626012430 0ustar bassbass#!/usr/bin/perl ## ## IMPORTANT -- Cadubi is no longer being maintained. 1.3 is a release ## for licensing and documentation fixes. See: ## ## http://langworth.com/CadubiProject ## eval 'exec /usr/local/stow/perl-5.8.x/bin/perl -w -S $0 ${1+"$@"}' if 0; # not running under some shell $VERSION = '1.3'; ######################################################################## # MAIN LOOP # kludge to make this easier (?) for package maintainers # (sorry guys, i wrote this years before i had the remotest clue as to # what the hell i was doing) use FindBin qw($Bin); $HELPFILE = "$Bin/help.txt"; # other stuff $DEBUG = 0; $CADUBI_VERSION = $VERSION; use Term::ReadKey; use lib "$Bin/../lib"; # global variables $ESC = "\x1b"; # our most important var $AUDIBLE = 1; # beep unless -m, --mute, or configured in 'cadubi' @pos = (1,1); # position of cursor (x,y) @totalspan = undef; # width & height of console (x,y) @workspan = undef; # same as $totalspace, but y-1 @charmap = undef; # a 3D array: # [col] [row] [(0 => char to paint with # 1 => bg color # 2 => fg color # 3 => bold # 4 => inverse # 5 => blink # 6 => special char command # )] @charmode = ('x',0,0,0,0,0,''); $status_changed = 1; # used with &status so we don't constantly redraw. $current_filename = undef; # name of file we're working with $cadubi_done = 0; # main loop var # runtime statements &initKeys(); # setup %controlkeys and %keymap &initANSI(); # setup %ansi_mode &setspan(); # setup span of terminal (default 24x80) &get_args; # read in command line parameters &clear; # clear screen &debug_open(); # open debug file ReadMode raw; # set terminal getchar mode if ($current_filename) { # file has been specified via command line, open it &user_readfile($current_filename); } else { # draw default status bar &status(); } do { &status if &HandleKeystroke(ReadKey(0)); # handle the key } until ($cadubi_done); &clear; # clear screen &cleanup; # cleanup code sub cleanup { ReadMode restore; # restore previous terminal getchar mode &debug_close(); # close debug file print $ESC.'[0m'; # return to normal ansi mode if anything has messed up } ######################################################################## # ANSI MODES sub initANSI { %ansi_mode = ( 'escape' => "\x1b", 'normal' => 0, 'bold' => 1, 'blink' => 5, 'inverse ' => 7, 'invisible' => 8, 'fg_black' => 30, 'fg_red' => 31, 'fg_green' => 32, 'fg_yellow' => 33, 'fg_blue' => 34, 'fg_magenta' => 35, 'fg_cyan' => 36, 'fg_white' => 37, 'bg_black' => 40, 'bg_red' => 41, 'bg_green' => 42, 'bg_yellow' => 43, 'bg_blue' => 44, 'bg_magenta' => 45, 'bg_cyan' => 46, 'bg_white' => 47 ); # color codes is used strictly for interface purposes %color_codes = qw( N normal 0 normal W white 1 white R red 2 red G green 3 green Y yellow 4 yellow B blue 5 blue M magenta 6 magenta C cyan 7 cyan K black 8 black ); } ######################################################################## # CONSOLE ROUTINES sub curs_move { # accepts coordinates ((x,y) or (column, row)) if (($_[0] >= 1) && ($_[0] <= $totalspan[0]) && ($_[1] >= 1) && ($_[1] <= $totalspan[1])) { print $ESC.'['.$_[1].';'.$_[0].'H'; @pos = ($_[0], $_[1]); } else { #&debug('&curs_move out of range: ('.$_[0].','.$_[1].')'); #&debug(' >> @totalspan = ('.$totalspan[0].','.$totalspan[1].')'); #&debug(' >> @workspan = ('.$workspan[0].','.$workspan[1].')'); #&debug(' >> @pos = ('.$pos[0].','.$pos[1].')'); return 0; } 1; } sub curs_move_up { if ($pos[1] > 1) { print $ESC.'[1A'; $pos[1]--; } else { &beep; return 0; } 1; } sub curs_move_dn { if ($pos[1] < $workspan[1]) { print $ESC.'[1B'; $pos[1]++; } else { &beep; return 0; } 1; } sub curs_move_rt { if ($pos[0] < $workspan[0]) { print $ESC.'[1C'; $pos[0]++; } else { &beep; return 0; } 1; } sub curs_move_lt { if ($pos[0] > 1) { print $ESC.'[1D'; $pos[0]--; } else { &beep; return 0; } 1; } sub clear { print $ESC.'[2J'; &curs_move(1,1); } # set the size of our workspace sub setspan { if (@_) { @totalspan = ($_[0],$_[1]); @workspan = ($_[0],$_[1]-1); &debug("\&setspan (specified): $_[0], $_[1]"); } elsif (GetTerminalSize) { #Term::ReadKey my ($w, $h, @x) = GetTerminalSize; #Term::ReadKey @totalspan = ($w,$h); @workspan = ($w,$h-1); &debug("\&setspan (using Term::ReadKey): $w, $h"); } else { # we must assume, even though it makes an ass of u and me @totalspan = (80,24); @workspan = (80,23); &debug("\&setspan (assumed): 80, 24"); } } # our status bar # if no parameters, erases if status has changed # if string is first argument, fills entire status bar with string # if string begins with '>', only replace 'CADUBI v1.x' in status bar with string # if second argument is true, leave the cursor at the end of the status text... # (good for prompts, see &user_writefile(). sub status { my $msg = shift; my $leave_cursor = shift; my $out = undef; if ($msg && (substr($msg,0,1) ne '>')) { $out = ''.$ESC.'[0m'.$ESC.'[7m '. pack('A'.($totalspan[0]-1), $msg).$ESC.'[0m'; $status_changed = 1; } else { if ($status_changed || $msg) { my $out_vers; if ($msg) { $out_vers = pack('A34',' '.substr($msg,1).' '); $status_changed = 1; } else { $out_vers = pack('A34',' cadubi '.$CADUBI_VERSION.' '); $status_changed = 0; } my $out_help = ' Type ^H for Help '; my $out_char = ' Pen: '.&printchar(@charmode).' '; $out = $ESC.'[0m'.$ESC.'[7m'.$out_vers. $ESC.'[0m'.$out_char.$ESC.'[7m'. (' ' x ($totalspan[0]- length($out_vers)- length($out_help)- 8) ). $out_help.$ESC.'[0m'; } } my @oldpos = @pos; &curs_move(1,$totalspan[1]); print $out; &curs_move(@oldpos) unless $leave_cursor; } # this promps the user with the first argument given, and waits for a string. # pass it a maximum string length for second argument. if no second argument, # user's allowed to fill the width between prompt & right edge with text. # a third argument is treated as a default answer, already filled in the field sub get_user_string { my $msg = shift; my $max = shift; my $out = shift; my @oldpos = @pos; my $char = undef; &curs_move(1,$totalspan[1]); # notice we don't print a normal mode sequence (\x1b[0m) because we # want to keep writing in inverse. we print a normal mode right before # we do a return. print $ESC.'[7m '.pack('A'.($workspan[0]-2),$msg)." "; $max = $workspan[0]-length($msg)-3 unless $max; &curs_move(length($msg)+3,$totalspan[1]); print $out; while (not $char =~ /[\n\x1b]/) { $char = ReadKey(0); # no chars < space if ($char =~ /[\x00-\x1f]/) { &beep; } # delete, but don't delete past starting x position elsif (ord($char) == $keymap{'del'}) { if ($out) { # print a backspace...the same as move left one char, print # a space (which moves the cursor right one char), then move # back one char again print $ESC.'[1D '.$ESC.'[1D'; $out = substr($out,0,-1); } else { &beep; } } else { if (length($out) >= $max) { &beep; } else { $out .= $char; print $char; } } } &curs_move(@oldpos); print $ESC.'[0m'; # refresh status bar $status_changed = 1; &status(); # user hit enter return $out if ($char eq "\n"); # user hit cancel return undef; } ######################################################################## # SUPPORT SUBROUTINES sub beep { print "\x07" if $AUDIBLE; } sub refresh { my @oldpos = @pos; &clear(); my ($x, $y); for ($y=1; $y<=$workspan[1]; $y++) { for ($x=1; $x<=$workspan[0]; $x++) { if (@{$charmap[$x][$y]}) { print &printchar(@{$charmap[$x][$y]}); } else { print ' '; } } &curs_move($x--,$y); } &curs_move(@oldpos); } sub printchar { # returns a string with the current ANSI mode and the character my $out = undef; my @desc = @_; my $char = shift(@desc); #key to draw pop(@desc); #remove special char command $out.= $ESC.'['; #print properties foreach (@desc) { $out.= $_.';' if ($_); } $out = substr($out,0,-1).'m'; $out = undef if ($out eq $ESC.'m'); if (defined($char)) { #print char or space if there's no char $out.= $char; } else { $out.= ' '; } $out.= $ESC.'[0m'; return $out; } sub paintchar { # prints the char on screen and saves it to @charmap @charmap->[$pos[0]][$pos[1]] = [@charmode]; print &printchar(@charmode); &curs_move(@pos); #print moves to the right on us, without asking. the nerve! } sub erasechar { # saves blank char to @charmap, prints @charmap->[$pos[0]][$pos[1]] = undef; print &printchar(@{@charmap->[$pos[0]][$pos[1]]}); &curs_move(@pos); #print moves to the right on us, without asking. the nerve! } sub usage { if ($_[0]) { print $_[0]."\n"; } print <> printed &usage'); &usage(); &cleanup; exit(1); } elsif (($option eq '-v') || ($option eq '--version')) { &debug('>> printed &version'); &version; &cleanup; exit(1); } elsif (($option eq '-m') || ($option eq '--mute')) { &debug('>> disabled audio'); $AUDIBLE = 0; } elsif (($option eq '-s') || ($option eq '--size')) { ($param1, $param2) = (shift(@ARGS), shift(@ARGS)); &debug('>> grabbing setspan variables, raw:'); &debug('>> $param1 = '.$param1); &debug('>> $param2 = '.$param2); $param1 = 80 unless $param1; $param2 = 24 unless $param2; &debug('>> processed setspan vars:'); &debug('>> $param1 = '.$param1); &debug('>> $param2 = '.$param2); &setspan($param1, $param2); } elsif ($option =~ /^-/) { &usage('Unknown option: '.$option); &cleanup; exit(1); } elsif (not $got_filename) { $got_filename = 1; $current_filename = $option; } else { &usage('Unknown argument: '.$option); &cleanup; exit(1); } } } ######################################################################## # DEBUGGING sub debug { print DEBUGFH $_[0]."\n" if ($DEBUG && DEBUGFH); } sub debug_open { open(DEBUGFH, '>cadubi_debug.txt') if $DEBUG; &debug('Debug file opened '.(localtime)); } sub debug_close { &debug('Debug file closed '.(localtime)); close(DEBUGFH) if DEBUGFH; } ######################################################################## # KEY HANDLING sub initKeys { %controlkeys = GetControlChars; #Term::ReadKey # DISCARD # DSUSPEND # EOF # EOL # EOL2 # ERASE # ERASEWORD # INTERRUPT # KILL # MIN # QUIT # QUOTENEXT # REPRINT # START # STATUS # STOP # SUSPEND # SWITCH # TIME %keymap = ( '^a' => 1, '^b' => 2, '^d' => 4, '^e' => 5, '^f' => 6, '^g' => 7, #bell '^h' => 8, '^i' => 9, '^k' => 11, '^o' => 15, '^p' => 16, '^r' => 18, '^t' => 20, '^u' => 21, '^v' => 22, '^w' => 23, '^x' => 24, '^y' => 25, 'esc' => 27, 'del' => 127, 'up' => 30, 'dn' => 31, 'lt' => 28, 'rt' => 29, 'space' => 32, 'cr' => 13, 'lf' => 10); } sub HandleKeystroke { my $key = shift; # ansi escape chars, like arrow keys if ($key eq $ESC) { if (ReadKey(0) eq '[') { my $newkey = ReadKey(0); if ($newkey eq 'A') {&curs_move_up; return 1;} elsif ($newkey eq 'B') {&curs_move_dn; return 1;} elsif ($newkey eq 'C') {&curs_move_rt; return 1;} elsif ($newkey eq 'D') {&curs_move_lt; return 1;} else { &status("Unknown escape sequence: '".$newkey."'"); return 0; } } else { &status("Unknown escape sequence."); return 0; } } # moving around keys (ijkl, IJKL, arrow keys) if ($key eq 'i') {&curs_move_up; return 1;} if ($key eq 'j') {&curs_move_lt; return 1;} if ($key eq 'k') {&curs_move_dn; return 1;} if ($key eq 'l') {&curs_move_rt; return 1;} if ($key eq 'I') {for (1 .. 5) {&curs_move_up}; return 1;} if ($key eq 'J') {for (1 .. 5) {&curs_move_lt}; return 1;} if ($key eq 'K') {for (1 .. 5) {&curs_move_dn}; return 1;} if ($key eq 'L') {for (1 .. 5) {&curs_move_rt}; return 1;} # exit if (ord($key) == $keymap{'^x'}) { $cadubi_done = 1; return 1; } # carrage return if ($key eq "\n") { # if we're at the bottom of the workspace, don't return if ($pos[1] >= $workspan[1]) { &curs_move(1, $pos[1]); } else { &curs_move(1, $pos[1]); &curs_move_dn; } return 1; } # paint if ($key eq ' ') { &paintchar; &curs_move_rt if ($pos[0] < $workspan[0]); return 1; } # erase if ((ord($key) == $keymap{'del'}) || ($key eq '`')) { &curs_move_lt; &erasechar; return 1; } # text mode if ($key eq 't') { my $char = undef; my $oldchar = $charmode[0]; my $startingx = $pos[0]; &status('Text mode (escape key exits)'); while ($char ne "\x1b") { $char = ReadKey(0); # if user hit return, move down a line to starting point if ($char eq "\n") { # if we're at the bottom of the workspace, don't return if ($pos[1] >= $workspan[1]) { &beep; } else { &curs_move($startingx, $pos[1]); &curs_move_dn; } } # no chars < space elsif ($char =~ /[\x00-\x1a\x1c-\x1f]/) { &beep; } # delete, but don't delete past starting x position elsif (ord($char) == $keymap{'del'}) { if ($pos[0] > $startingx) { &curs_move_lt; } else { &beep; } &erasechar; } elsif ($char ne $ESC) { $charmode[0] = $char; &paintchar(@charmode); &curs_move_rt; } } $charmode[0] = $oldchar; return 1; } # paint modes if ($key eq 'p') { # pen character &status('Set pen character:'); my $newkey = ReadKey(0); if ($newkey =~ /[\x00-\x1f\x7f]/) { &beep; &status('Unusable pen selection'); } else { $charmode[0] = $newkey; &status(">Pen char now: '".$newkey."'"); } return 0; } if ($key eq 'g') { # bold $charmode[3] = ($charmode[3]) ? 0 : 1; &status(">Bold enabled") if $charmode[3]; &status(">Bold disabled") unless $charmode[3]; return 0; } if ($key eq 'v') { # inverse $charmode[4] = ($charmode[4]) ? 0 : 7; &status(">Inverse enabled") if $charmode[4]; &status(">Inverse disabled") unless $charmode[4]; return 0; } if ($key eq 'W') { # blink (that's W for "why?") $charmode[5] = ($charmode[5]) ? 0 : 5; &status(">Blink enabled") if $charmode[5]; &status(">Blink disabled") unless $charmode[5]; return 0; } if ($key eq 'f') { &status('Set pen foreground color:'); my $newkey = ReadKey(0); if ($newkey =~ /[nN0]/) {$charmode[2] = $ansi_mode{'normal'}} elsif ($newkey =~ /[wW1]/) {$charmode[2] = $ansi_mode{'fg_white'}} elsif ($newkey =~ /[rR2]/) {$charmode[2] = $ansi_mode{'fg_red'}} elsif ($newkey =~ /[gG3]/) {$charmode[2] = $ansi_mode{'fg_green'}} elsif ($newkey =~ /[yY4]/) {$charmode[2] = $ansi_mode{'fg_yellow'}} elsif ($newkey =~ /[bB5]/) {$charmode[2] = $ansi_mode{'fg_blue'}} elsif ($newkey =~ /[mM6]/) {$charmode[2] = $ansi_mode{'fg_magenta'}} elsif ($newkey =~ /[cC7]/) {$charmode[2] = $ansi_mode{'fg_cyan'}} elsif ($newkey =~ /[kK8]/) {$charmode[2] = $ansi_mode{'fg_black'}} if ($newkey =~ /[NWRGYBMCK012345678]/i) { &status(">Foreground: ".$color_codes{uc($newkey)}); } else { &beep; &status("Unknown color selection: '".$newkey."'") } return 0; } if ($key eq 'b') { &status('Set pen background color:'); my $newkey = ReadKey(0); if ($newkey =~ /[nN0]/) {$charmode[1] = $ansi_mode{'normal'}} elsif ($newkey =~ /[wW1]/) {$charmode[1] = $ansi_mode{'bg_white'}} elsif ($newkey =~ /[rR2]/) {$charmode[1] = $ansi_mode{'bg_red'}} elsif ($newkey =~ /[gG3]/) {$charmode[1] = $ansi_mode{'bg_green'}} elsif ($newkey =~ /[yY4]/) {$charmode[1] = $ansi_mode{'bg_yellow'}} elsif ($newkey =~ /[bB5]/) {$charmode[1] = $ansi_mode{'bg_blue'}} elsif ($newkey =~ /[mM6]/) {$charmode[1] = $ansi_mode{'bg_magenta'}} elsif ($newkey =~ /[cC7]/) {$charmode[1] = $ansi_mode{'bg_cyan'}} elsif ($newkey =~ /[kK8]/) {$charmode[1] = $ansi_mode{'bg_black'}} if ($newkey =~ /[NWRGYBMCK012345678]/i) { &status(">Background: ".$color_codes{uc($newkey)}); } else { &beep; &status("Unknown color selection: '".$newkey."'") } return 0; } # file i/o if (ord($key) == $keymap{'^r'}) { return &user_readfile; } if (ord($key) == $keymap{'^o'}) { return &user_writefile; } # refresh if (ord($key) == $keymap{'^w'}) { #refresh &refresh(); &status('Workspace refreshed'); return 1; } # help if (ord($key) == $keymap{'^h'}) { #Help if (-e $HELPFILE) { my @oldmap = @charmap; my @oldpos = @pos; &readfile($HELPFILE); &status('Press a key to continue...', 1); my $temp = ReadKey(0); @charmap = @oldmap; $oldmap = undef; &curs_move(@oldpos); &refresh; &status; } else { &beep; &status("$HELPFILE not available"); } return 0; } # other if (ord($key) == $keymap{'^t'}) { # TEST &beep; return 0; } # no cigar! &beep; return 0; } ######################################################################## # FILE SUBROUTINES sub readfile { # pass it a filename as first argument, reads a file into # the @charmap array my $filepath = shift; my @oldpos = @pos; my @oldcharmode = @charmode; my ($char, $buf, $command, @nums); my $x = 1; my $y = 1; open(IN, '<'.$filepath); unless (IN) { return 0; } @charmap = undef; &debug('&readfile parsing:'); PARSE: while (not eof(IN)) { # MAGICAL ANSI ESCAPE SEQUENCE PARSER # This parses almost all the escape sequences I could get documentation on. # Even though, other than the mode change sequences, they will hardly ever # appear in an ascii art file, it's good to be prepared. # # I've parsed all EXCEPT this format: # ESC[#;"string";#p # $char = ReadKey(0, IN); &debug('>> "'.$char.'"'); # exit if we've found more lines than max if ($y > $workspan[1]) { &debug('>> '.$y.' is greater than '.$workspan[1]); last PARSE; } # if we've hit a newline in the file if ($char eq "\n") { &debug('>> newline'); $y++; $x = 1; } # if we've found more chars on the line than max elsif ($x > $workspan[0]) { &debug('>> maximum chars hit'); $y++; $x = 1; # read until newline do { $char = ReadKey(0, IN); } until ($char eq "\n"); } elsif ($char eq $ESC) { # escape sequence $char = ReadKey(0, IN); if ($char eq '[') { $char = ReadKey(0, IN); # These escape sequence types don't need support if ($char =~ /[usK]/) { # example: ESC[u } # Double-char unsupported escape sequences elsif ($char =~ /[2]/) { # example: ESC[2J $char = ReadKey(0, IN); } # Multi-numbered wierd with digits elsif ($char =~ /[\=\?]/) { # example: ESC[=21;29h do { $char = ReadKey(0, IN); } until (not ($char =~ /[\d\;]/)); } # Eeek! Keyboard reassignment! elsif ($char eq '"') { # example: ESC["string"p $char = ReadKey(0, IN); # get first " do { $char = ReadKey(0, IN); # get string" } until ($char eq '"'); $char = ReadKey(0, IN); # get final p } # Oh great. We've hit digits. elsif ($char =~ /\d/) { # example: ESC[31;7m $buf = $char; # read until we hit a non-digit or non-; char do { $char = ReadKey(0, IN); $buf .= $char; } until (not ($char =~ /[\d\;]/)); # $command is the letter following the number series $command = substr($buf,-1,1); # $buf ends up being a ; delimeted list of numbers $buf = substr($buf,0,-1); # @nums is a list the numbers @nums = split(/\;/, $buf); &debug(">> Sequence:"); &debug(">> -> \$command = $command"); &debug(">> -> \$buf = $bug"); &debug(">> -> \@nums = "); foreach (@nums) {&debug(">> -> !- $_")} # make sure these numbers are a mode change if ($command eq 'm') { # did we get a set-to-normal mode? (ESC[0m]) if (grep(/0/, @nums)) { @charmode = (' ',0,0,0,0,0,''); # no, we got a regular mode change } else { foreach (@nums) { $charmode[1] = $_ if (($_ >= 40) && ($_ <= 47)); $charmode[2] = $_ if (($_ >= 30) && ($_ <= 37)); $charmode[3] = $_ if ($_ == 1); $charmode[4] = $_ if ($_ == 7); $charmode[5] = $_ if ($_ == 5); } } } } } } else { $charmode[0] = $char; @charmap->[$x][$y] = [@charmode]; $x++; } } close(IN); &refresh; &curs_move(@oldpos); @charmode = @oldcharmode; return 1; } sub writefile { # pass it a filename, writes the entire @charmap to file, readable by # cat, more, less, whatever. my $filepath = shift; my $out = undef; my ($thisline, $thischar); my $inital_space = 1; my ($x, $y, $i, $d, $max, @newmode, @oldmode, @outlines); for ($y=1; $y<=$workspan[1]; $y++) { # fresh new line to work with @oldmode = qw(99 99 99 99 99 99); $thisline = undef; for ($x=1; $x<=$workspan[0]; $x++) { # set @newmode to the mode of the char we're about to write @newmode = @{$charmap[$x][$y]}; # is our new char mode different from our old one? $d = 0; $max = ($#oldmode > $#newmode) ? $#oldmode : $#newmode; for($i=1; $i<=$max; $i++) { # notice $i starts at one so we skip the character $d++ if ($oldmode[$i] != $newmode[$i]); } # if our new char mode is indeed different, add a normal # mode sequence and our new mode and char. else, just add # the char. if ($d) { $thisline .= $ESC.'[0m'.substr(&printchar(@{$charmap[$x][$y]}),0,-4); } else { # make sure it's not just a space if (defined(@{$charmap[$x][$y]})) { $thisline .= $newmode[0]; } else { $thisline .= ' '; } } # now make @newmode our @oldmode @oldmode = @newmode; } # kill trailing whitespace on single lines $thisline =~ s/(\s+)$//; # make sure each line ends with a normal mode sequence push(@outlines, $thisline.$ESC."[0m\n"); } open(OUT, ">$filepath") or return 0; # kill trailing lines $x = 0; for ($i=$#outlines; $i>=0; $i--) { unless (($outlines[$i] eq $ESC.'[0m'.$ESC."[0m\n") && (not $x)) { $out = $outlines[$i].$out; $x++; } } print OUT $out; close(OUT); if ($out) { return length($out); } else { # if no bytes were written, we'll return 'zero' return 'zero'; } } sub user_writefile { my ($filename, $reply, $bytes_written); my $file_exists = 1; my @oldpos = @pos; while ($file_exists) { $filename = &get_user_string('File name to write:', undef, $current_filename); # user canceled return 1 unless defined($filename); # check if file exists if (-e $filename) { &status('File already exists. Overwrite? (y/n)',1); $reply = uc(ReadKey(0)); $file_exists = 0 if ($reply eq 'Y'); return 1 if ($reply eq $ESC); &status(); } else { $file_exists = 0; } } $current_filename = $filename; $bytes_written = &writefile($filename); if ($bytes_written) { &status("Wrote '".$filename."' (".$bytes_written.' bytes)'); } else { &beep; &status("Couldn't write file '".$filename."': ".$!); } &curs_move(@oldpos); return 0; } sub user_readfile { my $filename; if ($_[0]) { $filename = $_[0]; } else { $filename = &get_user_string('File name to read:', undef, $current_filename); } # user canceled return 1 unless defined($filename); if (-e $filename) { if (&readfile($filename)) { &status("Read file '".$filename."'"); } else { &status("Couldn't read file '".$filename."': ".$!); } } else { &status("File '".$filename."' doesn't exist."); } return 0; } ######################################################################## # EOF 1; cadubi-1.3/help.txt0100644000175000017500000000731010015321361012731 0ustar bassbassoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo o cadubi Keys o Color Codes o o o o o ijkl Move o Key FG BG Bold All o o IJKL Move Quick o n / 0 X X XXX o o space Paint with Pen o w / 1 X   X XXX o o del Erase o r / 2 X   X XXX o o p Set Pen Character o g / 3 X   X XXX o o  g Toggle Pen Bold o y / 4 X   X XXX o o  v Toggle Pen Inverse o b / 5 X   X XXX o o  f Set Pen Foreground o m / 6 X   X XXX o o  b Set Pen Background o c / 7 X   X XXX o o  t Text Mode o k / 8 X   X XXX o o  W Toggle Pen Blink o o o ^r Read File In ooooooooooooooooooooooooooooooooooooooooooooooooo o ^o Write File Out o o o ^x Exit o Website: http://langworth.com/CadubiProject o o ^w Refresh Screen o o o  ` Erase (also) o   o o o o o o o o o o oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo