Outputting+text+with+word-wrap

//by Richard Russell, August 2009//

BBC BASIC (by default) automatically 'wraps' text that is output to the screen or the printer. If a character will not fit on the current line (or within the current text viewport) a 'new line' is generated and the character is displayed or printed at the beginning of the next line. The text viewport scrolls, or a new page is ejected from the printer, if necessary.

Although this ensures that all text output is visible, it does often result in a word being split between two lines. It would usually be more desirable to perform a **word wrap**, that is if a character will not fit the entire word containing that character is moved to the next line. This is the kind of behaviour that a word processor usually has.

The routines listed below implement word-wrap for text output to the screen or the printer. There are four procedures: **PROCww** outputs a string to the screen, **PROCvww** outputs a single character to the screen, **PROCwwp** outputs a string to the printer and **PROCvwwp** outputs a single character to the printer:

code format="bb4w" PROCww(A$)  : REM Equivalent to PRINT A$; PROCvww(C%) : REM Equivalent to VDU C%     PROCwwp(A$)  : REM Equivalent to OSCLI "OUTPUT 15" : PRINT A$; : OSCLI "OUTPUT 0" PROCvwwp(C%) : REM Equivalent to VDU 2,1,C%,3 code Note that **PROCww** and **PROCwwp** do not output a newline after the string; to do that you must concatenate **CHR$13+CHR$10** to the end of the string (or output them separately using **PROCvww** or **PROCvwwp**).

Here are the routines necessary to implement word-wrap:

code format="bb4w" DEF PROCww(A$) LOCAL I%     IF A$ = "" THEN ENDPROC FOR I% = 1 TO LEN(A$) PROCvww(ASCMID$(A$,I%)) NEXT ENDPROC DEF PROCvww(C%) PRIVATE X%, Y%, B$     VDU C%      IF C% > 32 B$ += CHR$C% ELSE B$ = "" : X% = @vdu.c.x% : Y% = @vdu.c.y%      IF X% > @vdu.c.x% IF B$ <> "" THEN LOCAL @vdu%!216 : @vdu%!216 = 1 IF Y% = @vdu.c.y% Y% -= @vdu%!220 REPEAT @vdu.c.x% = X% : @vdu.c.y% = Y%         VDU 32 : X% += 1 UNTIL X% > @vdu.tr% PRINT B$; X% = -1 ENDIF ENDPROC DEF PROCwwp(A$) LOCAL I%     IF A$ = "" THEN ENDPROC FOR I% = 1 TO LEN(A$) PROCvwwp(ASCMID$(A$,I%)) NEXT ENDPROC DEF PROCvwwp(C%) PRIVATE X%, B$     LOCAL M%, ?444 : ?444 = 64 M% = @vdu%!-12 VDU 2,1,C%,3 IF C% > 32 B$ += CHR$C% ELSE B$ = "" : X% = @vdu%!-12 IF @vdu%!-12 > @vdu%!236 IF B$ <> "" THEN IF X% < 0 X% = M% : B$ = RIGHT$(B$) SWAP @vdu%!-12, X%       SYS "SetBkMode", @prthdc%, 2 REPEAT VDU 2,1,32,3 UNTIL @vdu%!-12 > X%       SYS "SetBkMode", @prthdc%, 1 ?444 = 0       *OUTPUT 15 PRINT 'B$; *OUTPUT 0 X% = -1 ENDIF ENDPROC code Note that the usual restrictions caused by the use of **PRIVATE** apply. You must not attempt to resume execution if an error occurs (even an ESCape error) within the **PROCvww** or **PROCvwwp** routines. Ensure that any **ON ERROR** handler in your program aborts execution in such a case.