. Analysis and Design of the br Program for UNIX . WARNING -- old fashioned style, method, and notation .Open Introduction . Name br . Author R J Botting. 1988-1991 . Synopses br width --- break lines and word wrap input . Bugs This program fails if the expected width of a word wrapped line in characters exceeds the maximum integer stored on the machine. .Close Introduction .Open Requirements . Context DFD .As_is user .As_is |w .As_is V .As_is in->(br)->out The program reads text input and attempts to reformat it so that no line is longer than 'w' characters by breaking lines at the first block of whitespace after the last word that fits on the line. The break is done by removing all the whitespace characters after the last word that fits on the output line and replacing them by CR. Assume that there are no BS chars in the file. If w>250 or <10 then the program should do nothing and report an abnormal termination("error"). Default width is 79. If a single word is too long to fit on a line by itself then it will have to be broken up - Hyphenate words whose length is>w-1. . Data dictionary Input lines (ilines) must be broken up if they are too long. So each iline is split into a group of zero or more shorter output lines followed by part of a line that does not need breaking. The short lines end in the last word that can fit on that line. After the broken lines there is a last part of the iline which is less than 'w' in length, This is ok when each word is smaller than the output line width. Longer words are broken into hyphenated parts. in::=#$iline, iline::=#( #($word | $wsb ) $last_word $wsb |$pt_long_wd ) $ok_line, line::=#($word | $wsb ) $last_word $break |$pt_long_wd $hyphen $eoln, out::=#( # $line $ok_line), ok_line::= #non_eoln $eoln, user::=$w. w::10..250. The length of words, wsb and last word in each 'line' add up to less than w and HT (tab) equals HTWIDTH characters in width. wsb ::= #$ws, ws ::= HT|SP|non_print, Note. `Length of HT`=HTWIDTH, length of non_print=0. word ::= #non_ws, last_word ::= #last_non_ws, pt_long_word ::= #$pt_wd_char. Note. `w-1` non_ws chars. break ::= eoln, Alternative: break::=SP eoln, is used by Wordstar to signal a "soft_CR". break::=eoln HT, would look good. See the brt.c hack. hyphen ::= "-". .Close Requirements .Open Design . Note In this method the requirements are mapped, definition by definition into a program structure. Each component is named for the data that it consumes (C_) or produces(P_). The operations are extracted from the requirements in a separate process that works backwards from the outputs to the inputs. Then the operations are placed in the structure and an overall design or plan is produced. This is then mapped into the particular language that is needed. . Correspondences/Program Structure C_user_C_in_P_out::structure= CU_w; #C_iline, C_iline ::structure= #P_line; CP_ok_line, P_line ::structure= #( CP_word | CP_wsb ); CP_last_word; C_wsb_P_break | CP_pt_long_wd;P_hyphen;P_eoln, CP_ok_line ::structure= #CP_non_eoln; CP_eoln, CP_wsb ::structure= #(CP_HT|CP_non_HT_ws|CP_non_print), CP_last_word ::structure= #CP_last_non_ws, CP_word ::structure= #CP_non_ws, C_wsb_P_break ::structure= #C_ws, CP_pt_long_word ::structure= #CP_pt_wd_char, Note. `w-1` non_ws chars. . Operations List The notation is inspired by Tony Hoare's CSP and ":+" operator. .Table Symbol Function When .Row ch Character .Row !ch Output ch Each character output .Row !eoln Output end of line End of each output end of line .Row ?ch Input ch Each ch of input .Row n Number of charcters .Row n:+1 add 1 to n When character is output onto line. .Row n:+HTWIDTH add HTWIDTH to n each horizontal tab .Row n'=0 set n to 0 start of a line .Row w?:user get width from the user Start of program(or given) .Row !"-" Output a hyphen when word has to be broken .Close.Table . Program Design C_user_C_in_P_out ::design= w?:user; ?ch; #$C_iline, C_iline ::design= #$P_line; $CP_ok_line, P_line ::design= n'=0; #( $CP_word | $CP_wsb ); $CP_last_word; $C_wsb_P_break | $CP_pt_long_wd;$P_hyphen;$P_eoln, CP_ok_line ::design= #$CP_non_eoln; $CP_eoln, CP_wsb ::design= #($CP_HT|$CP_non_HT_ws|$CP_non_print), CP_last_word ::design= #$CP_last_non_ws, CP_word ::design= #$CP_non_ws, C_wsb_P_break ::design= #$C_ws; !eoln, CP_non_eoln ::design= !ch; ?ch, CP_eoln ::design= !eoln; ?ch, CP_HT ::design= n:+HTWIDTH; !ch;?ch, CP_non_HT_ws ::design= n:+1; !ch; ?ch, CP_non_print ::design= !ch; ?ch, CP_non_ws ::design= n:+1; !ch; ?ch, CP_last_non_ws ::design= !ch; ?ch, C_ws ::design= ?ch, CP_pt_long_wd ::design= #$CP_pt_wd_char, P_hyphen ::design= !"-", P_eoln ::design= !eoln, CP_pt_wd_char ::design= !ch; ?ch, . Temporal map of Program .As_is C_user_C_in_P_out .As_is ________________________________________________________________________ .As_is | w?:user; ?ch | .As_is |________________________________________________________________________| .As_is /| C_iline |\ .As_is | | ________________________________________________________________ | | .As_is | | /| P_line |\ | | .As_is | | | | ___________________________________________________________ | | | | .As_is | | | | | n'=0 | CP_pt_long_wd | | | | | .As_is | | | | |------------------------------------------| ---------- | | | | | .As_is | | | | | ______________________ | | /| CP_pt_wd|\ | | | | | .As_is | | | | | /|CP_word |\ | CP_wsb | | | -------| || | | | | .As_is | | | | | | | ________________ | | | | | | |!ch;?ch| || | | | | .As_is | | | | | | | /| CP_non_ws |\ | | | | | | -------| || | | | | .As_is | | | | | | || | -------------- | || | | | \|_________|/ | | | | | .As_is | | | | | | || ||n:+1;!ch; ?ch || || | | | | !"-" | | | | | | .As_is | | | | | | | \| -------------- |/ | | | | |---------| | | | | | .As_is | | | | | | | ---------------- | | | | | !eoln | | | | | | .As_is | | | | | \|______________________|/ | | |_________| | | | | | .As_is | | | | |-----------------------------------------------------------| | | | | .As_is | | | | | CP_last_word | | | | | .As_is | | | | | ----------------- | | | | | .As_is | | | | | /| CP_last_non_ws |\ | | | | | .As_is | | | | | | | --------- | | | | | | | .As_is | | | | | | | |!ch; ?ch | | | | | | | | .As_is | | | | | \| --------- |/ | | | | | .As_is | | | | | ----------------- | | | | | .As_is | | | | |-----------------------------------------------------------| | | | | .As_is | | | | | C_wsb_P_break | | | | | .As_is | | | | | ----------- | | | | | .As_is | | | | | /| C_ws |\ | | | | | .As_is | | | | | | | ------ | | | | | | | .As_is | | | | | | | | ?ch | | | | | | | | .As_is | | | | | | | ------ | | | | | | | .As_is | | | | | \|-----------|/ | | | | | .As_is | | | | | | !eoln | | | | | | .As_is | | | | | ----------- | | | | | .As_is | | | | |___________________________________________________________| | | | | .As_is | | \|________________________________________________________________|/ | | .As_is | | | CP_ok_line | | | .As_is | | | ---------------- | | | .As_is | | | /| CP_non_eoln |\ | | | .As_is | | || | _________ | | | | | .As_is | | || | |!ch; ?ch | | | | | | .As_is | | | \| |_________| |/ | | | .As_is | | | |----------------| | | | .As_is | | | | CP_eoln | | | | .As_is | | | | ---------- | | | | .As_is | | | | |!eoln; ?ch| | | | | .As_is | | | | ---------- | | | | .As_is | | | |________________| | | | .As_is | | |________________________________________________________________| | | .As_is \|________________________________________________________________________|/ .As_is .As_is CP_wsb .As_is ------------------------------- .As_is (|CP_HT|CP_non_HT_ws|CP_non_print |) .As_is ------------------------------- .As_is CP_HT ::design= n:+HTWIDTH; !ch;?ch CP_non_HT_ws ::design= n:+1; !ch; ?ch CP_non_print ::design= !ch; ?ch .Close Design .Open Implementation . DChart Schematic Logic wd and ws are buffers .As_is C_user_C_in_P_out .As_is \ .As_is | w?:user; ?ch .As_is | #C_iline .As_is | \ .As_is | | not end(in) .As_is | | #P_line(posit iline will be broken after word) .As_is | | \2_______________________________________1 .As_is | | |admit word not hyphenated |posit word hyphenated .As_is | | | push ch & wd back out; n'=0 |CP_pt_long_wd .As_is | | | # | \ .As_is | | | \ | |wd!new; n'=0 .As_is | | | | | |#CP_pt_wd .As_is | | | |posit room for next word or wsb | | \ .As_is | | | | | | |nw-1 .As_is | | | | | | | |ws!end; !ws .As_is | | | | |wd!end; !wd | .As_is | | | \| .As_is | | | .As_is | | |admit next did not fit (3) .As_is | | | CP_last_word | .As_is | | | \ | .As_is | | | side-effects | .As_is | | | | .As_is | | |push ch & wd back out (in!b) | .As_is | | | | .As_is | | | C_wsb_P_break | .As_is | | | \ | .As_is | | | | #C_ws | .As_is | | | | \ | .As_is | | | | beneficent side-effects | .As_is | | | | | .As_is | | | |!eoln | .As_is | | | \| | .As_is | | \|______________________________________| .As_is | | .As_is | |admit no more breaks needed .As_is | |CP_ok_line .As_is | | \ .As_is | | | #CP_non_eoln .As_is | | | \ .As_is | | | Beneficient side-effects .As_is | | | .As_is | | | .As_is | | | CP_eoln .As_is | | | \ .As_is | | | |!eoln; ?ch .As_is CP_HT ::schematic= n:+HTWIDTH; ws!ch;?ch CP_non_HT_ws ::schematic= n:+1; ws!ch; ?ch CP_non_print::schematic= ws!ch; ?ch .Close Implementation . Source Code .See http://www.csci.csusb.edu/dick/tools/br.c .See http://www.csci.csusb.edu/dick/tools/br.ANSI.c . UNIX Manual .See http://www.csci.csusb.edu/dick/tools/br.l