(* TEXTBUF.PAS -- buffer for output of texts ** Copyright (c) 1995,1996 Jochen Metzinger ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *) UNIT TextBuf; INTERFACE USES errors; CONST DEFAULT_LINE = 78; MAX_TABS = 8; PROCEDURE buf_open(filename: STRING); (* open 'filename' for output *) PROCEDURE buf_close; (* close file *) PROCEDURE buf_margin(left, indent, right, style: BYTE); (* set margin, indent and text style (like Ruler) *) PROCEDURE buf_set_tab(pos: WORD); (* set a tab *) PROCEDURE buf_line_space(skip: BYTE); (* set line spacing *) PROCEDURE buf_add(txt: STRING); (* add 'txt' to current line *) PROCEDURE buf_indent; (* add indent to line *) PROCEDURE buf_tab; (* add tabulator to line *) PROCEDURE buf_nl; (* make a new line *) PROCEDURE buf_break(txt: STRING); (* break line and write special text 'txt' *) IMPLEMENTATION VAR output_file: TEXT; (* output file *) left_margin, indent_space, max_line: WORD; (* left margin and line size *) ragged, line_skip: BYTE; (* text form and line space *) nr_tabs: WORD; tab_pos: ARRAY [1..MAX_TABS] OF WORD; (* tabulators *) state: (S_TEXT, S_BROKEN); (* working state *) line: STRING; (* line buffer *) PROCEDURE buf_open(filename: STRING); BEGIN (*$I-*) Assign(output_file, filename); ReWrite(output_file); IF IOResult <> 0 THEN FATAL('unable to create file '+filename); (*$I+*) buf_margin(0,0,DEFAULT_LINE,0); line := ''; state := S_TEXT; END; (* buf_open *) PROCEDURE buf_close; BEGIN buf_break(''); Close(output_file); END; (* buf_close *) PROCEDURE buf_margin(left, indent, right, style: BYTE); BEGIN IF left < right THEN BEGIN left_margin := left; max_line := right-left; END ELSE BEGIN left_margin := 0; max_line := DEFAULT_LINE; END; (* else *) IF indent >= max_line THEN indent := 0; indent_space := indent; IF style <= 3 THEN style := 0; ragged := style; line_skip := 1; nr_tabs := 0; END; (* buf_margin *) PROCEDURE buf_set_tab(pos: WORD); VAR i: INTEGER; BEGIN IF nr_tabs = MAX_TABS THEN EXIT; IF pos <= left_margin THEN EXIT; Dec(pos, left_margin); IF pos >= max_line THEN EXIT; INC(nr_tabs); tab_pos[nr_tabs] := pos; FOR i := nr_tabs DOWNTO 2 DO IF tab_pos[i] < tab_pos[i-1] THEN BEGIN pos := tab_pos[i]; tab_pos[i] := tab_pos[i-1]; tab_pos[i-1] := pos; END; (* if *) END; (* buf_set_tab *) PROCEDURE buf_line_space(skip: BYTE); BEGIN IF skip <= 0 THEN skip := 1; line_skip := skip; END; (* buf_line_space *) PROCEDURE break_line; VAR i: BYTE; rest: STRING; BEGIN (* find space to break *) FOR i := max_line DOWNTO (max_line DIV 2) DO IF line[i] = ' ' THEN BEGIN rest := Copy(line, i+1, $FF); line := Copy(line, 1, i-1); buf_nl; state := S_BROKEN; line := rest; EXIT; END; (* if *) (* no space found *) buf_break(''); END; (* break_line *) PROCEDURE buf_add(txt: STRING); VAR i: BYTE; BEGIN line := line + txt; IF Length(line) > max_line THEN break_line; END; (* buf_add *) FUNCTION space(nr: BYTE): STRING; VAR s: STRING; BEGIN FillChar(s, SizeOf(s), ' '); s[0] := CHAR(nr); space := s; END; (* space *) PROCEDURE CenterLine; BEGIN IF Length(line) < max_line THEN line := space((max_line - Length(line)) DIV 2) + line; END; (* CenterLine *) PROCEDURE FlushRightLine; VAR i: INTEGER; BEGIN IF Length(line) < max_line THEN line := space(max_line - Length(line)) + line; END; (* FlushRightLine *) PROCEDURE BlockLine; VAR i: BYTE; s, a, b: WORD; new_line: STRING; BEGIN IF Length(line) > max_line THEN EXIT; (* reduce space *) i := 1; WHILE i < Length(line) DO IF Copy(line, i, 2) = ' ' THEN Delete(line, i, 1) ELSE Inc(i); (* remove space at begin and end *) IF Copy(line,1,1) = ' ' THEN Delete(line,1,1); IF Copy(line,Length(line),1) = ' ' THEN Delete(line,Length(line),1); IF line = '' THEN EXIT; (* count space *) s := 0; FOR i := 1 TO Length(line) DO IF line[i] = ' ' THEN Inc(s); IF s = 0 THEN BEGIN CenterLine; EXIT; END; (* if *) (* calculate stretch faktor a/b *) a := s + (max_line - Length(line)); b := s; (* insert space *) new_line := ''; s := 0; FOR i := 1 TO Length(line) DO IF line[i] <> ' ' THEN new_line := new_line + line[i] ELSE BEGIN s := s + a; new_line := new_line + space(s DIV b); s := s MOD b; END; (* else *) line := new_line; END; (* BlockLine *) PROCEDURE buf_nl; VAR i: INTEGER; BEGIN IF (line <> '') OR (state = S_TEXT) THEN BEGIN CASE ragged OF 1: CenterLine; 2: FlushRightLine; 3: BlockLine; ELSE (* FlushLeftLine *); END; (* case *) WriteLn(output_file, space(left_margin), line); line := ''; FOR i := 2 TO line_skip DO WriteLn(output_file); state := S_TEXT; END; (* if *) END; (* buf_nl *) PROCEDURE buf_break(txt: STRING); VAR i: INTEGER; BEGIN IF line <> '' THEN BEGIN CASE ragged OF 1: CenterLine; 2: FlushRightLine; 3: BlockLine; ELSE (* FlushLeftLine *); END; (* case *) WriteLn(output_file, space(left_margin), line, '|'); line := ''; FOR i := 2 TO line_skip DO WriteLn(output_file); state := S_BROKEN; END; (* if *) IF txt <> '' THEN WriteLn(output_file, txt); END; (* buf_break *) PROCEDURE buf_tab; VAR i: INTEGER; BEGIN IF nr_tabs = 0 THEN buf_add(' ') ELSE BEGIN IF Length(line) > tab_pos[nr_tabs] THEN buf_nl; FOR i := 1 TO nr_tabs DO IF tab_pos[i] > Length(line) THEN BEGIN WHILE Length(line) < tab_pos[i] DO line := line + ' '; EXIT; END; (* if *) FATAL('INTERN [buf_tab without tab]'); END; END; (* buf_tab *) PROCEDURE buf_indent; BEGIN line := line + space(indent_space); END; (* buf_indent *) BEGIN left_margin := 0; indent_space := 0; max_line := DEFAULT_LINE; ragged := 0; line_skip := 1; nr_tabs := 0; state := S_TEXT; line := ''; END. (* TextBuf *)