#!/bin/sh -u # interruptible parabolas, fast or slow, on any size terminal window # # $0 [ slow ] # # This script draws several parabolas. At any time, you can use # SIGINT (usually CTRL-C) to interrupt a loop and provide new loop # values for that parabola. An argument of "slow" slows down drawing. # # Integer Arithmetic Only! # Shell scripts only deal in integers. The order in which you do # arithmetic matters! let "x=1/80*160" is zero, because "1/80" is zero # in integer artithmetic. let "x=160*1/80" is the right answer "2". # Always do multiplication before division in integer math. # # Terminal Screen Coordinates are Zero-Based # The "tput cup" program positions the cursor based on coordinates that # range from (0,0) [top left] to (xlimit,ylimit) [bottom right], where # xlimit=cols-1 and ylimit=lines-1. (Using "tput $lines $cols" tries to # position the cursor too far off the bottom right corner of the # screen.) Make sure your display X,Y values lie in the range 0..cols-1 # and 0..lines-1. Trying to draw off the edge of the terminal screen # will result in a character at the edge of the screen. # # NOTE: This script fragment is incomplete - it does not follow all # the script guidelines set out in "script_style.txt". It also # contains many "Instructor-Style" comments that you must not use in # your own scripts. See script_style.txt for details. # # -IAN! idallen@idallen.ca PATH=/bin:/usr/bin ; export PATH LC_COLLATE=C ; export LC_COLLATE LANG=C ; export LANG umask 022 # Set speed based on optional command line argument. Default is fast. # if [ "${1-fast}" = 'slow' ] ; then sleepstart=3 else sleepstart=1 fi ########################################################################### # Function Definitions ########################################################################### # function: NewSleep time points # - time is the number of seconds to draw all the points # - points is the number of points to be drawn in the time # - calculates and echoes the floating-point value that will let all the # points be drawn in the given amount of time (usable by "sleep") # # The "dc" program is a floating-point, reverse-Polish calculator. # "2 k" sets the precison to 2 decimal places, enough for "sleep". # "p" prints the current calculation value ($1 divided by $2). # NewSleep () { # XXX should validate both integer arguments here echo 2 k "$1" "$2" / p | dc } # function: Prompt (no arguments - SIGINT handler) # # This Prompt function is used as the SIGINT trap handler. # Modifies global variables! # # A SIGINT (#2) interrupt lets us over-ride the number being used. # The number entered becomes the new parabola size and start value. # Prompt () { # Ignore SIGINT while prompting for user input. # Position the cursor at the top of the screen for prompting. # Clear the screen from cursor to the end of the line. # Make the cursor visible. # Read the user's input; quick-exit on EOF. # Make the cursor invisible. # Clear away the prompt and user's input. # Set the new program values. # XXX much necessary error checking of user input is missing here! # Restore the SIGINT trap handler. # trap '' 2 # ignore SIGINT tput cup 0 0 tput el # clear from cursor to end-of-line echo -n "Enter new num: " tput cnorm # make cursor visible read ans || exit 0 tput civis # make cursor invisible tput cup 0 0 tput el # clear from cursor to end-of-line let num=ans # XXX missing input validation here! let i=-num trap 'Prompt' 2 # reset SIGINT trap handler } # function: TerminalInit (no arguments) # # Initialize the terminal. Sets global variables! # TerminalInit () { # Fetch the current size of the terminal screen. # Create constants for the maximum X and Y terminal output values. # cols=$( tput cols ) lines=$( tput lines ) let xlimit=cols-1 let ylimit=lines-1 # Set the SIGINT trap (some shells allow INT instead of 2; 2 is portable) # trap 'Prompt' 2 # Clear the terminal screen. # Turn off the cursor. # tput clear tput civis # make cursor invisible } ########################################################################### # End of Function Definitions ########################################################################### # Initialize the terminal. Sets global variables! # TerminalInit # Output some debugging info just above the last line of the screen. # - Remember: tput is zero based and runs from 0..xlimit and 0..ylimit # let upone=ylimit-1 tput cup $upone 0 tput el # clear from cursor to end-of-line echo -n "cols $cols lines $lines, xlimit $xlimit ylimit $ylimit" #-------------------------------------------------------------------------- # First Parabola #-------------------------------------------------------------------------- # Run down the Y axis plotting X = Y*Y # - make sure display X and Y are positive and lie on terminal screen # - Remember: tput is zero based and runs from 0..xlimit and 0..ylimit # let num=lines/2-1 let i=-num sleep=$( NewSleep "$sleepstart" "$num" ) while [ "$i" -lt "$num" ] ; do let dispy=i+num let dispx=i*i*xlimit/num/num tput cup "$dispy" "$dispx" ; echo -n '*' let i=i+1 sleep "$sleep" done #-------------------------------------------------------------------------- # Second Parabola Pair #-------------------------------------------------------------------------- # Run across the X axis plotting both Y = X*X and Y = LINES - X*X # - make sure display X and Y are positive and lie on terminal screen # - Remember: tput is zero based and runs from 0..xlimit and 0..ylimit # let num=cols/2-1 let i=-num sleep=$( NewSleep "$sleepstart" "$num" ) while [ "$i" -lt "$num" ] ; do let dispx=i+num let dispy=i*i*ylimit/num/num # plot the main parabola (which comes out upside-down) tput cup "$dispy" "$dispx" ; echo -n '*' # plot a mirror-image parabola (right-side-up) let yinverse=ylimit-dispy tput cup "$yinverse" "$dispx" ; echo -n '+' let i=i+1 sleep "$sleep" done # Move cursor to two lines above last line on screen. # Switch to "bold" terminal font. # Say goodbye. # Switch to "normal" terminal font. # Move cursor to start of last line. # Make the cursor visible again. # Exit. # let uptwo=ylimit-2 tput cup $uptwo 0 tput bold echo -n "Done parabolas." tput sgr0 tput cup $ylimit 0 tput cnorm # make cursor visible