#!/usr/local/rexx/rxx /* * BOX * * A filter program to replace "-", "+", and "|" combinations with line * drawing characters. * * The program looks through a file and finds the typical usages of * "-", "+", and "|" to draw boxes, and replaces those characters with * the commonly used line drawing characters found in PC fonts. * * Here's a sample box... * * * 1abc2d3 * +---+-+ +---+-+ * | | | e| | |e * | | | f| 5 | |f xbbbbbbbbbbby * | | | g| \| |g ------------- * +---+-+ 4+---+-+6 * | | | h| | |h * +---+-+ +---+-+ * 7abc8d9 * * * The one on the right has each character marked with an alphanumeric * "case" indicator that relates to the state change table below. * * The state change table shows how a character ("current") is * translated ("changeto"), based on its four neighboring characters. * A blank value for a neighboring character means "anything other * than -+|". * * State change table: * * case a b c d e f g h 1 2 3 4 5 6 7 8 9 x y * current - - - - | | | | + + + + + + + + + - - * left + - - + - - - - - - - * right - - + + - - - - - - - * above + | | + | | | | | | * below | | + + | | | | | | * changeto c4 c4 c4 c4 b3 b3 b3 b3 da c2 bf c3 c5 b4 c0 c1 d9 c4 c4 * * This table is implemented via an associative array (stem) * that is indexed by current|left|right|above|below, and yields * changeto. "Don't care" cases are represented by blank characters. * * The program has a three line buffer, and the extra lines are null * at the start and end. * * Execute the program by typing * * box * * where is the name of the input file to be translated * and is one of the uni-REXX TRACE options (all, * error, etc.). The results of running the BOX program are * directed to standard output (the terminal screen) unless * redirected elsewhere. * * maintenance log: * * 06/18/91 ets added cases x and y, to support vertical lines. */ parse arg in traceopt trace value traceopt /* * Two associative arrays are set up. The first (s.) includes exactly * those keys seen in the table above (those in the arguments to si() * below). The second (ss.) is similar to the first, but includes * iterations that contain "-", "+" and "|" in place of blanks. This is * required for cases such as the figure below. * * +-+ * |-| * +-+ * * The "-" in the middle of the box does not match any of the state * diagrams (it should not change the way any surrounding character is * translated, since it doesn't "hook up" with any of them). It does * not get translated to blanks by the algorithm and would interfere * with a simple match on the s. stem. Therefore, if the s. stem does * not yield a translation, the ss. stem is searched for a translation * considering cases like the one shown here. */ s.=" " ss.=" " call si("-+- ","c4"x) call si("--- ","c4"x) call si("--+ ","c4"x) call si("-++ ","c4"x) call si("| +|","b3"x) call si("| ||","b3"x) call si("| |+","b3"x) call si("| ++","b3"x) call si("+ - |","da"x) call si("+-- |","c2"x) call si("+- |","bf"x) call si("+ -||","c3"x) call si("+--||","c5"x) call si("+- ||","b4"x) call si("+ -| ","c0"x) call si("+--| ","c1"x) call si("+- | ","d9"x) call si("- - ","c4"x) call si("-- ","c4"x) /* * Make a translation table that will be used to separate "-", "+", * and "|" from everything else. */ y=copies(" ",256) y=overlay("-",y,c2d("-")+1) y=overlay("+",y,c2d("+")+1) y=overlay("|",y,c2d("|")+1) /* * Begin the main loop, by initializing two of the three buffers. * When the loop is done, process the remaining buffer with a null line * for the "after" line. */ cl="" bl=linein(in) do while lines(in)>0 al=cl cl=bl bl=linein(in) call x end al=cl cl=bl bl="" call x exit /* * This routine goes through the current line building a lookup key * based on the neighboring data, and does the translate. It also * outputs the translated line. */ x: nl=cl do i=1 to length(cl) cc=extract(cl,i) if cc\==" " then do if i=1 then lc=" "; else lc=extract(cl,i-1) if i=length(cl) then rc=" "; else rc=extract(cl,i+1) ac=extract(al,i) bc=extract(bl,i) k=cc||lc||rc||ac||bc ct=s.k if ct==" " then ct=ss.k if ct\==" " then nl=overlay(ct,nl,i) end end say nl return 0 /* * The extract routine saves some typing above. */ extract: parse arg s,p return translate(substr(s,p,1),y) /* * The si routine initializes a decision table case. It puts the * exact case into the s. stem, including blanks. It then calls the * recursive routine expand() to build a string containing all the * combinations of the key, replacing blanks with "-", "+" and "|". * Note that expand has a convention regarding the use of "*" for * blanks in keys (explained below) requiring retranslation to * blanks here. */ si: parse arg k,v s.k=v if pos(" ",k)>0 then do k=expand(k) do while length(k)>0 parse var k kk 6 k do while pos("*",kk)>0 kk=overlay(" ",kk,pos("*",kk)) end ss.kk=v end end return 0 /* * The expand routine produces each iteration of the given key, * replacing blanks with "-", "+" and "|". In order to get "lower" * blanks substituted while "higher" blanks are retained, this routine * substitutes an "*" for the higher blank when it recurses. This is * to insure that lower routines do not substitute for the higher blank. * The caller then translates "*" back to blanks. */ expand: procedure parse arg k b=pos(" ",k) if b>0 then do kk= expand(overlay("-",k,b)) kk=kk||expand(overlay("+",k,b)) kk=kk||expand(overlay("|",k,b)) kk=kk||expand(overlay("*",k,b)) return kk end else return k