=====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:
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
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:
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
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, unless you execute a **RESTORE LOCAL** as part of your error handler. Ensure that any **ON ERROR** handler in your program aborts execution in such a case.