/* @(#)txdisplay.c 17.1.1.1 (ES0-DMD) 01/25/02 17:48:06 */ /*=========================================================================== Copyright (C) 1995 European Southern Observatory (ESO) 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 of the License, 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 Massachusetss Ave, Cambridge, MA 02139, USA. Corresponding concerning ESO-MIDAS should be addressed as follows: Internet e-mail: midas@eso.org Postal address: European Southern Observatory Data Management Division Karl-Schwarzschild-Strasse 2 D 85748 Garching bei Muenchen GERMANY ===========================================================================*/ /*+++++++++++++++++++++++++++ .TYPE Module .IDENTIFICATION txdisplay.c .AUTHOR Francois Ochsenbein [ESO-IPG] .LANGUAGE C .KEYWORDS Display ``TeX-like'' text .ENVIRONMENT TermWindows .VERSION 1.0 24-Sep-1986: Creation .VERSION 1.1 30-Jan-1987: Redefinition of internal functions as static .VERSION 1.2 01-Jun-1987: Added \ul macro (underline) .VERSION 2.0 02-Jul-1987: Version '2' of TermWindows. Removed LastRule. Added CentreColumns, LeftColumns, RightColumns. .VERSION 2.1 28-Sep-1987: For Forms, added Macros \Field{name}{text} \Hspace{len} .VERSION 3.0 29-Apr-1988: Version '3', with complete macro processing. .VERSION 3.1 08-Dec-1988: \tab action does not indent if the cursor is at a line beginning. Added environment {Ccode}, which accumulates the text into the Ccode buffer, and which can be retrieved via tx_ccode. .VERSION 3.2 31-Jan-1989: \columns{}{} to redefine columns of a table .VERSION 3.3 01-Mar-1989: Replaced Ccode by {more}{Ccode}. Added tx_symbol() to translate a symbol. .VERSION 3.31 14-Mar-1989: Removed bug in tx_action, at tx_item call, and tx_item (Syndrome: item tag disappeared at top of page) .VERSION 3.32 26-May-1989: Added tx_def to define a symbol. .VERSION 3.4 29-Jun-1989: Redesigned table editions. .VERSION 3.5 24-Jul-1989: Removed bug in tx_rule / nltab .VERSION 3.51 16-Aug-1989: Added close_table as a separate routine. .VERSION 3.6 19-Mar-1990: Removed bug in tx_action. .VERSION 3.7 21-Nov-1990: Added obeylines / obeyspaces + begin{group}/end{group} .VERSION 3.8 04-Dec-1990: Removed bug in tabright, alignment was not correct when linesize not a multiple of MARGIN.. Also allow negative Hspace .VERSION 3.9 10-Jun-1991: Modified tx_more to allow several `more' environments .COMMENTS This module contains routines to output a ``TeX-like'' text on a window. A complete macro substitution is performed (cf tex.c module). \begin{TeX} The text to process follows some of the \LaTeX\footnote{Leslie Lamport, Addison-Wesley Publishing Company} conventions: it includes both the text and ``macros'' that specify processing options. The available macros are listed in the table. \begin{table}[htbp] $$\begin{tabular}{|lp{30em}|} \hline Name & Explanation \\ \hline {\tt\b b} & Issue a single backslash (\b) \\ {\tt\b$x$} & Issue symbol $x$, with possibilities \{ \} \% \$ \& \_ \^{ } \# space \\ \hline \hline \multicolumn{2}{|c|}{{\em Blanks and Line Position}} \\ \hline \hline {\tt\b\b} & Break the current line \\ {\tt\b quad} {\tt\b qquad} & Issue 2 or 4 blanks \\ {\tt \~{ }} & Issue a single non-breakable blank \\ {\tt\b Hspace\{$n$\}} & Issue $n$ non-breakable blanks \\ {\tt\b tab} & Align to next ``tab'' \\ {\tt\b SkipLine} & Issue a single blank line \\ {\tt\b indent} & Indentation \\ {\tt\b hfill} & Horizontal Stretchable space \\ {\tt\b vfill} & Vertical Stretchable space \\ {\tt\b tabright\{{\em text}\} & Align rightmost letter of {\em text} to next ``tab'' \\ % \hline \hline \multicolumn{2}{|c|}{{\em Line Justifications}} \\ \hline \hline {\tt\b centerline\{{\em text}\}} & Issue a line with {\em text} centered. (see also {\tt center} environment)\\ {\tt\b leftline\{{\em text}\}} & Issue a line with {\em text} adjusted to the left (see also {\tt left} environment)\\ {\tt\b rightline\{{\em text}\}} & Issue a line with {\em text} adjusted to the right (see also {\tt right} environment)\\ \hline \hline \multicolumn{2}{|c|}{{\em Video Attributes}} \\ \hline \hline {\tt\b VB} or {\tt\b bf} & use {\bf Boldface} attribute \\ {\tt\b Vu} or {\tt\b sl} & use {\sl Underscore} attribute \\ {\tt\b Vr} or {\tt\b em} or{ \tt\b it} & use {\em Reverse} attribute \\ {\tt\b Vb} & use {\tt Blink} attribute \\ {\tt\b fbox\{{\em text}\}} & use \fbox{Bold+Reverse+Blink} attribute \\ % \hline \hline \multicolumn{2}{|c|}{{\em Environments}} \\ \hline \hline {\tt\{verbatim\}} & Display text as it is \\ {\tt\{center\}} & Centering text \\ {\tt\{left\}} \quad{\tt\{right\}} & Left-aligned / Right-adjusted text, also called raggedright / raggedleft\\ {\tt\{indent\}} & Push left margin \\ {\tt\{quote\}} & Push left and right margins \\ {\tt\{itemize\}} & Itemized list; {\tt\b item} starts each item \\ {\tt\{enumerate\}} & Start an enumerated list; {\tt\b item} starts each item \\ {\tt \{alphaenumerate\}} & Enumerated list using lowercase letters\\ {\tt \{Alphaenumerate\}} & Enumerated list using uppercase letters\\ {\tt \{more\}}\{{\em name}\} & Text which can be retrieved, but not displayed \\ {\tt \{table\}\{{\em pos}\}\{{\em w}\}} & Table environment. See explanations in the text. \\ \hline \hline \multicolumn{2}{|c|}{{\em Environment-specific macros}} \\ \hline \hline % {\tt\b item} & Specifies a new element in the itemize / enumerate list\\ {\tt\b crule\{$c_1$--$c_2$\}} {\tt\b Rule} &Issue a horizontal line over one columns $c_1$ to $c_2$ and whole table \\ {\tt\b len\{{\em text}\}} & Computes length of {\em text} \\ {\tt\b multicolumn\{$n$\}\{{\em j}\}\{{\em text}\}} & define a column spreading over $n$ columns with {\em j} justification.\\ {\tt\b columns\{{\em pos}\}\{{\em w}\}} & redefine columns in Table environment\\ \hline \hline \multicolumn{2}{|c|}{{\em Miscellaneous}} \\ \hline \hline % {\tt\b bell} & Ring the terminal bell \\ {\tt\b input\{{\em filename}\}} & Get text to process from {\em filename} \\ {\tt\b def\b{\em name\#}\dots\{{\em equivalence}\}} & Macro definition \\ {\tt\b today}\quad {\tt\b time}\quad {\tt\b now} & Date, time, date+time editions\\ {\tt\b EOF} & End of text indicator (stops when found) \\ {\tt\b iftrue} {\tt\b iffalse} {\tt\b else} {\tt\b fi} & Conditional tests \\ {\tt\b CheckLines\{$n$\}} & Terminate if less than $n$ lines remain on the current window \\ {\tt\b FormField\{{\em name}\}\{{\em type}\}\{{\em pic}\}\{{\em text}\}}& Define a named field which can be retrieved in the calling program \via {\em GetMarkedFields}\\ \hline\end{tabular}$$ \caption{\label{macro:tex}TermDisplay macros}\end{table} \medskip {\bf Table Environment} \label{env:table} The 2 parameters of the {\tt\b begin\{table\}} or {\tt\b columns} macros specify: \begin{enumerate} \item The {\em pos} parameter, similar to the \LaTeX: possibilities of \quad l \quad r \quad c \quad p \quad for left, right, centered or justified text, $|$ for a vertical line separating columns, and blanks before / after the $|$ . \item The {\em w} parameter specifies the {\em width} of each column, as number of characters separated by commas or blanks; if the last column width is not specified, it is assumed to use the {\em remaining space}. \end{enumerate} Examples: \begin{itemize} \item {\tt\b begin\{table\}\{|r |p|\}\{5,50\}} will create a table with 2 columns: a right-adjusted column (with a blank at the left of the second $|$) of 5 characters, and a justified column with 50 characters; the complete width of the table is 59 characters (don't forget the space required by the vertical lines and blanks!) \item {\tt\b begin\{table\}\{rcp\}\{5,10\}} will create a table with 3 columns: a right-adjusted column of 5 characters, a centered column of 10 characters, and a justified column of 65 characters if the width of the window is 80 characters. \end{itemize} \medskip {\bf more environment} \label{env:Ccode} The text between {\tt\b begin\{more\}\{Ccode\}} and {\tt\b end\{more\}} contains C instructions (cf {\bf cc} module) which can be retrieved with the {\em tx\_more{Ccode}} function, then compiled (see {\em cc\_compile}) and executed. The text between {\tt\b begin\{more\}\{Ccode\}} and {\tt\b end\{more\}} will never be displayed on a window. \medskip The program uses a {\em tex\_action} routine; the characters passed to this routine have the following meaning: $$\begin{tabular}{|ll||ll|} \hline \multicolumn{2}{|c||}{\em Single character actions} & \multicolumn{2}{|c|}{\em Two character actions} \\ \hline \ &single stretchable blank & & \\ \b r &new line & & \\ \b n &new paragraph & & \\ 0 &begin / end environments & F &Field definitions\\ \{ &open a new environment & f &fill horizontal / vertical\\ \} &return to previous environment & J &justification specifications\\ / &issue a blank line & M &Move margins operations\\ \& &start next column of a table & m &multicolumn definitions\\ t &start at next `tab' & V &Video attributes specifications\\ b &ring terminal bell & & \\ r &rule over one column & & \\ R &rule all over table & & \\ \hline \end{tabular}$$ \end{TeX} ----------------------------------------------------------------------------*/ #define DEBUG 0 /* For debugging only */ #define PM_LEVEL LEVEL_TX #include #include #include #include #include #define HSIZE 300 /* Size of h-table */ static char item_ed[3]; static char zero = EOS; typedef struct { short int col_lim[2]; short int line_lim[2]; /* [0] = Top next & / [1] = Next \\ */ unsigned char smart; /* Smart (justify) attribute */ unsigned char attr; /* Attribute for this depth */ unsigned char cols; /* Number of columns this depth */ unsigned char col_no; /* Current column number */ unsigned char col_i; /* Increment column number */ unsigned char flags; #define ForceJustification 0x01 #define NoJustification 0x02 #define JustificationDone 0x04 #define AnchoredPosition 0x08 #define InField 0x10 char tex_mode; char env; short count; /* For enumerate */ } DEPTH; static DEPTH *pd, *pd0; /* Pointer to current environment */ static DEPTH column; #define _JUSTIFY_ (_LEFT_+_RIGHT_) #define _LEFT_BAR_ 0x10 #define _RIGHT_BAR_ 0x20 #define _LEFT_BLANK_ 0x40 #define _RIGHT_BLANK_ 0x80 #define _MARKER1_ 0x8000 /* 2 markers are used to allow */ static short marked; #define Lines() (ws->dim[0]) #define Columns() (ws->dim[1]) #define Position(i,j) ((i)*(ws->dim[1]) + j) #define CurrentLine() (ws->pos / ws->dim[1]) #define CurrentColumn() (ws->pos % ws->dim[1]) #define BottomReached() (ws->pos >= ws->marker[1]) /* Static variables used for communication between routines */ static TeX htex = { /* The TeX header */ NULL_PTR(H_TABLE), NULL_FCT(int), NULL_FCT(int), NULL_PTR(char), 0,0,0}; static BUFFER *depth_buf = NULL_PTR(BUFFER); static BUFFER line_buf = BUF_Init(char, 80); /* This buffer contains the `blank' line */ static BUFFER field_names = BUF_Init(char, 128); /* This buffer contains the Marked Field Names */ static BUFFER field_def = BUF_Init(short int, 48); /* This buffer contains the Column Ranges of each field */ static BUFFER More = BUF_Init(char, 128); /* This buffer contains the C Code in the Ccode env. */ static BUFFER aux = BUF_Init(char, 24); /* This buffer contains the temporary output */ static BUFFER oMore = BUF_Init(int, 4); /* This buffer contains the offsets in More env. */ static BUFFER *inaux = NULL_PTR(BUFFER); /* When output redirected */ static short MARGIN; /* Margin Size, computed as 1/10 of window width */ static char WindowIsActive = 0; static char blank_lines = 0; static char rule_lines = 0; static char do_init_line = 0; static char last_issued_char = EOS; static char table_depth = 0; #define MAX_MARKED 6 static int vfill_no = 0; static int hfill_no = 0; static short vfill[MAX_MARKED]; static short hfill[MAX_MARKED]; static char blanks[32]; static int (*external_action)() = NULL_FCT(int); /* User-defined function for math symbols */ static WINDOW *ws = NULL_WINDOW; /* Used Window */ static ACHAR current_blank = ' '; /* Blank attr of begin of line */ static int txopt = 1; /* Centering Option */ int tx_out(), tx_action(); MONITOR(TXDISPLAY); /*========================================================================== * tx_set *==========================================================================*/ static int tx_set() /*+++ .PURPOSE Positions in the current environment. .RETURNS OK .REMARKS Not traced ---*/ { pd0 = BUF_ItemPosition(depth_buf, DEPTH), pd = pd0; if (pd0->cols) pd += (1 + pd->col_no); return(OK); } /*========================================================================== * init_line *==========================================================================*/ static int init_line() /*+++ .PURPOSE Write Rules .RETURNS OK .REMARKS ---*/ { int i, j; i = CurrentLine(); if (CurrentColumn() > 0) i++; i = Position(i, 0); if (BottomReached()) FINISH; for (j = 0; j < line_buf.used; j++) { if (line_buf.buf[j] == 1) ws->pos = i + j, tw_rule(ws, _DOWN_, ws->dim[0]); } FIN: ws->pos = i; do_init_line = 0; /* Performed... */ return(OK); } /*========================================================================== * tx_tex *==========================================================================*/ TeX *tx_tex() /*+++ .PURPOSE Retrieve the TeX structure (macro table, etc); initilize if not done. .RETURNS Pointer to the TeX structure used by TermDisplay. .REMARKS The macros H-table is created if necessary ---*/ { MID_STATIC char definitions[] = "\ \\def\\indent{\03MI\04}\ \\def\\vfill{\03fv\04}\ \\def\\hfill{\03fh\04}\ \\def\\Hspace#1{\\action{Mh}}\ \\def\\CheckLines#1{\\action{MV}}\ \\def\\CheckCols#1{\\action{MH}}\ \\def\\quad{\\ \\ }\ \\def\\qquad{\\ \\ \\ \\ }\ \\def\\SkipLine{\03/\04}\ \\def\\bell{\03b\04}\ \\def\\VB{\03VB\04}\ \\def\\Vr{\03Vr\04}\ \\def\\VR{\03VR\04}\ \\def\\Vu{\03Vu\04}\ \\def\\Vn{\03Vn\04}\ \\def\\Vb{\03Vb\04}\ \\def\\Jl{\03Jl\04}\ \\def\\Jr{\03Jr\04}\ \\def\\Jc{\03Jc\04}\ \\def\\Jf{\03Jf\04}\ \\def\\Jj{\03Jj\04}\ \\def\\bf{\\VB}\ \\def\\em{\\VR}\ \\def\\rm{\\Vn}\ \\def\\it{\\Vr}\ \\def\\sl{\\Vu}\ \\def\\fbox#1{{\\action{VrVBVb}#1}}\ \\def\\item{\\action{Mi}}\ \\def\\crule#1{\\action{r}}\ \\def\\Rule{\\action{R}}\ \\def\\tab{\\action{t}}"; MID_STATIC char def_env[] = "\ \\def\\tabright#1{\\action{Jt}#1\\action{J0}}\ \\def\\centerline#1{\\\\{\\Jc\\Jf#1}\\\\}\ \\def\\leftline#1{\\\\{\\Jl\\Jf#1}\\\\}\ \\def\\rightline#1{\\\\{\\Jr\\Jf#1}\\\\}\ \\defenv\\left{\\0\\action{JlJf}}{\\0}\ \\defenv\\right{\\0\\action{JrJf}}{\\0}\ \\defenv\\center{\\0\\action{JcJf}}{\\0}\ \\defenv\\quote{\\0\\action{MlMr}}{\\0}\ \\defenv\\itemize{\\0\\action{Ml}}{\\0}\ \\defenv\\indent{\\0\\action{Ml}}{\\0}\ \\defenv\\enumerate{\\0\\action{Ml}}{\\0}\ \\defenv\\alphaenumerate{\\0\\action{Ml}}{\\0}\ \\defenv\\Alphaenumerate{\\0\\action{Ml}}{\\0}\ \\defenv\\group{\\0}{\\0}\ \\defenv\\more#1{\\0}{\\0}\ \\defenv\\table#1#2{\\0}{\\0}"; MID_STATIC char def_ff[] = "\ \\def\\columns#1#2{\\action{Ft}}\ \\def\\multicolumn#1#2#3{\\action{m#2}#3\\action{m0}}\ \\def\\FormField#4{\\action{Fs}#4\\action{Fe}}\ \\def\\Field#2{\\FormField{#1}{}{}{#2}}\ "; htex.output = tx_out, htex.action = tx_action; if_not(htex.macros) { htex.macros = h_create (HSIZE); TeX_Execute(&htex, definitions, sizeof(definitions)-1); TeX_Execute(&htex, def_env, sizeof(def_env)-1); TeX_Execute(&htex, def_ff , sizeof(def_ff )-1); } return(&htex); } /*========================================================================== * tx_init *==========================================================================*/ static int tx_init(str, clear_option) /*+++ .PURPOSE Initialisation: TeX, buffers, etc .RETURNS OK / NOK .REMARKS Important actions as \03action\04 ---*/ char *str; /* IN: String to display */ int clear_option; /* IN: Option to clear Window before display */ { int status, i; int old_offset, old_used; ENTER("tx_init"); status = NOK; if_not(depth_buf) /* Not yet initialized */ { oscfill(blanks, sizeof(blanks), ' '); if_not(depth_buf = BUF_Open(DEPTH, 24, 24)) FINISH; if_not(htex.macros) tx_tex(); /* Initialise TeX macros */ } /* Do all initialisations */ MARGIN = (Columns()+4)/10; vfill_no = 0; hfill_no = 0; inaux = NULL_PTR(BUFFER); last_issued_char = ' '; BUF_Clear(&field_def); BUF_Clear(&field_names); BUF_Clear(&More); BUF_Clear(&aux); BUF_Clear(&oMore); if (Fields(ws)) BUF_Clear(Fields(ws)); /* Be sure that window is not Active. It is useless to output * data on the screen immediately --- moreover, justifications * etc must be performed before presenting the nice result ... */ WindowIsActive = (ws->flags & Echo); DeactiveWindow(ws); if (clear_option) ClearWindow(ws); blank_lines = (CurrentColumn() == 0 ? 1 : 0); tw_uflag(ws, 1); /* Window completely modified */ /* Initialise: set flags, and if the text is starting (non-null str) * initialize depth to zero, default justification, etc ... */ if (str) /* A new string to display */ { BUF_Clear(depth_buf); column.col_lim[0] = 0, column.col_lim[1] = Columns(); column.line_lim[0] = 0, column.line_lim[1] = 0; column.smart = 0; column.attr = 0; column.cols = 0; column.col_no = 0; column.col_i = 1; column.env = 0; column.count = 0; BUF_StackItem(depth_buf, DEPTH, &column); BUF_Clear(&line_buf); table_depth = 0; rule_lines = 0; } /* Reset All Line Limits */ tx_set(); pd0->line_lim[1] = CurrentLine(); pd0->line_lim[0] = pd0->line_lim[1]; old_used = depth_buf->used; old_offset = depth_buf->offset; for ( pd = pd0; pd; pd = BUF_UnstackItem(depth_buf, DEPTH)) { for (i = pd->cols; i-- >= 0; pd++) { pd->line_lim[0] = pd0->line_lim[0]; pd->line_lim[1] = pd0->line_lim[1]; } } depth_buf->used = old_used; depth_buf->offset = old_offset ; tx_set(); SetAttr(ws, pd0->attr); current_blank = ws->attr; /* In the case of a continuation in the Tab environment, * initialize the first line. This is done with init_line */ if (table_depth) init_line(); FIN: EXIT(status); } /*========================================================================== * new_col *==========================================================================*/ static int new_col() /*+++ .PURPOSE Create a new column .RETURNS OK .REMARKS ---*/ { unsigned char j; j = column.smart&7; if ( (j == _RIGHT_) || (j == _CENTER_)) column.flags |= ForceJustification; BUF_AppendItem(depth_buf, DEPTH, &column); tx_set(); pd0->cols += 1; column.smart = 0; column.flags = 0; return(OK); } /*========================================================================== * Mark *==========================================================================*/ static int Mark(pos, len) /*+++ .PURPOSE Mark characters from pos, length len .RETURNS OK / NOK .REMARKS ---*/ int pos; /* IN: Position for marker */ int len; /* IN: Number of characters to mark */ { ACHAR *pa; if (marked == 0) { pa = Aij(ws, pos/Columns(), pos%Columns()); *pa |= _MARKER1_; } marked += len; return((pos + len < ws->marker[1] ? OK : NOK)); } /*========================================================================== * tx_smart *==========================================================================*/ static int tx_smart() /*+++ .PURPOSE Justify the text in column, accordings to pd->smart. .RETURNS OK .REMARKS No justification if left adjustement, or line is empty. The flag NoJustification or JustificationDone are taken into account. ---*/ { register ACHAR *pa; int i, len, j, justify; if (pd->flags & NoJustification) FINISH; if (pd->flags & JustificationDone) { pd->flags &= ~JustificationDone; FINISH; } if (blank_lines) FINISH; if (htex.mode == _TeX_VERBATIM_) FINISH; if (htex.mode & _TeX_OBEY_) FINISH; switch( justify = (pd->smart & 7) ) { default: justify = _JUSTIFY_; break; case _LEFT_ : case _RIGHT_ : case _CENTER_: break; } i = CurrentLine(); pa = Aij(ws, i, pd->col_lim[0]); len = pd->col_lim[1] - pd->col_lim[0]; if ((current_blank != ws->attr_init) && (current_blank == ws->attr) && (justify != _JUSTIFY_)) { for (j = len; --j >=0; pa++) if (*pa == ws->attr_init) *pa = current_blank; pa = Aij(ws, i, pd->col_lim[0]); } else current_blank = ws->attr_init; switch( justify ) { case _LEFT_ : /* tx_jl(pa, len, current_blank); */ break; case _RIGHT_ : tx_jr(pa, len, current_blank); break; case _CENTER_: tx_jc(pa, len, current_blank); break; case _JUSTIFY_: tx_justify(pa, len, current_blank); break; } current_blank = ws->attr; ws->pos = Position(i, pd->col_lim[1]); /* Correct position */ if (CurrentColumn() == 0) blank_lines = 1; else blank_lines = 0; FIN: return(OK); } /*========================================================================== * tx_blank *==========================================================================*/ static int tx_blank() /*+++ .PURPOSE Output a stretchable blank on a window: don't output blanks on margins, don't repeat spaces. .RETURNS --- OK if blank not needed or correctly output --- NOK if there is no more room to issue the character. .REMARKS The blank uses the current attribute --- but Blinking or Bold blanks are made normal ! ---*/ { register int j; tx_set(); j = CurrentColumn(); if ((j <= pd->col_lim[0]) && (!(pd->flags & AnchoredPosition))) FINISH; if (j >= pd->col_lim[1]) FINISH; if (last_issued_char == ' ') FINISH; /* Don't issue 2 blanks */ last_issued_char = ' ', j++; if (j == pd->col_lim[1]) /* Must justify, no blank */ tx_smart(); else /* Insert blank */ { Write(ws, &last_issued_char, 1); rule_lines = 0; if (pd->flags & InField) Mark(ws->pos - 1, 1); } FIN: return(OK); } /*========================================================================== * tx_hfil *==========================================================================*/ static int tx_hfil() /*+++ .PURPOSE Insert blanks according to hfill_no. .RETURNS OK .REMARKS Not traced ---*/ { int j, right_lim, remaining_blanks; ACHAR *pa; pa = Aij(ws, CurrentLine(), 0); /* Line beginning */ remaining_blanks = pd->col_lim[1] - CurrentColumn(); for (right_lim = pd->col_lim[1]; hfill_no > 0; right_lim=hfill[--hfill_no]+j) { j = hfill[hfill_no - 1]; tx_jr(pa + j, right_lim - j, ws->attr_init); j = remaining_blanks / hfill_no; remaining_blanks -= j; } pd->flags |= NoJustification; /* Already justified */ return(OK); } /*========================================================================== * tx_nl *==========================================================================*/ static int tx_nl() /*+++ .PURPOSE Issue a new line. .RETURNS OK .REMARKS Newline may imply some skips... ---*/ { register int i; tx_set(); pd->flags &= ~AnchoredPosition; if (BottomReached()) FINISH; if (hfill_no) tx_hfil(); /* Horizontal Fill */ if (pd->flags & ForceJustification) tx_smart(); i = CurrentLine(); if (i < pd->line_lim[0]) i = pd->line_lim[0]; pd->line_lim[1] = i; i = pd->line_lim[1] + 1; ws->pos = Position(i, 0); /* New position */ blank_lines += 1; pd->flags &= ~(NoJustification | JustificationDone); last_issued_char = ' '; /* In the Tab Environment, the new line is initialized * when the position is at column 0. */ if (do_init_line) init_line(); FIN: return(OK); } /*========================================================================== * tx_vfil *==========================================================================*/ static int tx_vfil() /*+++ .PURPOSE Insert lines according to vfill_no. .RETURNS OK .REMARKS Not traced ---*/ { int old_pos, i, remaining_lines; if(blank_lines == 0) tx_nl() ; old_pos = ws->pos; i = CurrentLine(); remaining_lines = Lines() - i; if (remaining_lines <= 0) FINISH; for ( ; vfill_no > 0; vfill_no--) { tw_goto(ws, vfill[vfill_no - 1], 0); i = remaining_lines / vfill_no; tw_il(ws, i); old_pos += i*ws->dim[1]; remaining_lines -= i; } ws->pos = old_pos; FIN: return(OK); } /*========================================================================== * tabright *==========================================================================*/ static int tabright(text, len) /*+++ .PURPOSE Justify the text at right of next `tab' .RETURNS Written Length .REMARKS ---*/ char *text; /* IN : text to issue */ int len; /* IN : Len of text */ { int i, j, nb; if (inaux == &aux) inaux = NULL_PTR(BUFFER); i = CurrentLine(), j = CurrentColumn(); if (j < pd->col_lim[0]) j = pd->col_lim[0]; if ((j+len) > pd->col_lim[1]) j = pd->col_lim[0], i++; nb = (j+len-pd->col_lim[0])%MARGIN; if (nb) nb = (MARGIN - nb); j += nb; if ((j+len) > pd->col_lim[1]) { /* Try to remove blanks */ j = pd->col_lim[1] - len; if (j < pd->col_lim[0]) j = pd->col_lim[0]; } ws->pos = Position(i, j); pd->flags |= JustificationDone; if (len > 0) i = tx_out(text, len); else i = 0; return(i); } /*========================================================================== * nltab *==========================================================================*/ static int nltab() /*+++ .PURPOSE Issue a new line in Table Environment .RETURNS OK .REMARKS Newline may imply some skips... ---*/ { int i, j; i = CurrentLine(); pd0->line_lim[0] = MAX(i, pd0->line_lim[1]); pd0->col_no = 0, pd0->col_i = 1; pd0->line_lim[1] = pd0->line_lim[0]; ws->pos = Position(pd0->line_lim[0], 0); for (j = pd0->cols, pd = pd0+1; --j >= 0; pd++) pd->line_lim[0] = pd0->line_lim[0], pd->line_lim[1] = pd0->line_lim[1]; if (do_init_line) init_line(); blank_lines = 1; last_issued_char = ' '; return(OK); } /*========================================================================== * clear_down *==========================================================================*/ static int clear_down(pd) /*+++ .PURPOSE Clear the bottom of the table .RETURNS OK .REMARKS ---*/ DEPTH *pd; /* IN: Column concerned */ { ACHAR *pa; int i, j, len, old_pos; old_pos = ws->pos; len = pd->col_lim[1] - pd->col_lim[0]; i = CurrentLine(); if (CurrentColumn() > pd->col_lim[0]) i++; i = MAX(i , pd->line_lim[1]); j = i-1; /* Where to start tx_mrule */ if (j < 0) j = 0; ws->pos = Position(j, pd->col_lim[0]); for (; i < ws->dim[0]; i++) { pa = Aij(ws, i, pd->col_lim[0]); for (j = len; --j >= 0; pa++) *pa = ws->attr_init; } tw_mrule(ws, len); ws->pos = old_pos; return(OK); } /*========================================================================== * open_depth *==========================================================================*/ static int open_depth() /*+++ .PURPOSE Do operations for opening a depth .RETURNS OK .REMARKS ---*/ { BUF_StackItem(depth_buf, DEPTH, pd); /* Copy this depth */ tx_set(); pd->env = 0; pd->tex_mode = htex.mode; pd->flags &= ~ForceJustification; return(OK); } /*========================================================================== * close_depth *==========================================================================*/ static int close_depth() /*+++ .PURPOSE Do operations for closing a depth .RETURNS OK .REMARKS ---*/ { unsigned char old_attr; short old_lim[2]; old_attr = pd->attr; old_lim[0] = pd0->line_lim[1]; old_lim[1] = pd->line_lim[1]; if (depth_buf->offset <= sizeof(int)) ERROR("Too many }"); else { if (pd->flags & ForceJustification) tx_smart(); BUF_Unstack(depth_buf); tx_set(); htex.mode = pd->tex_mode; if (old_attr != pd->attr) SetAttr(ws, pd->attr); /* pd->line_lim[0] = old_lim[0], */ pd0->line_lim[1] = MAX(pd0->line_lim[1], old_lim[0]); pd->line_lim[1] = MAX( pd->line_lim[1], old_lim[1]); } return(OK); } /*========================================================================== * full_width *==========================================================================*/ static int full_width(pd, width) /*+++ .PURPOSE Compute the full width of a column .RETURNS The width. .REMARKS Adds the bars ---*/ DEPTH *pd; /* IN: Column concerned */ short width[2]; /* OUT: Column Limits (right limit excluded)*/ { width[0] = pd->col_lim[0]; width[1] = pd->col_lim[1]; if (pd->smart & _LEFT_BLANK_) width[0]--; if (pd->smart & _LEFT_BAR_) width[0]--; if (pd->smart & _RIGHT_BLANK_) width[1]++; if (pd->smart & _RIGHT_BAR_) width[1]++; return(width[1] - width[0]); } /*========================================================================== * tr_line *==========================================================================*/ static int tr_line(pd, old, new) /*+++ .PURPOSE Modify the line buffer. .RETURNS Number of modifications. .REMARKS Adds the bars ---*/ DEPTH *pd; /* IN: Column concerned */ int old; /* IN: Values to change */ int new; /* IN: Replacement */ { char *p; int i, count; count = 0; for (p = line_buf.buf + pd->col_lim[0], i = pd->col_lim[1] - pd->col_lim[0]; --i >= 0; p++) { if (*p == old) count++, *p = new; } return(count); } /*========================================================================== * tx_tab0 *==========================================================================*/ static int tx_tab0(opt) /*+++ .PURPOSE Write / Wipe Vertical Rules (until End of Window) .RETURNS OK .REMARKS Starting at current line... ---*/ int opt; /* IN: Option 1 to add, 0 to remove vertical bars */ { DEPTH *pc; int ic, i, j, old_pos; short lim[2]; if (line_buf.used == 0) { ic = Columns(); BUF_AllocateItems(&line_buf, char, ic); oscfill(line_buf.buf, ic, 0); /* Clear Vertical Rules */ } if (opt == 0) { tr_line(pd0, 1, 0); /* Suppress */ return(OK); } old_pos = ws->pos; i = old_pos / Columns(); /* Current Line */ for (ic = pd0->cols, pc = pd0+1; --ic >= 0; pc++) { full_width(pc, lim); if (pc->smart & _LEFT_BAR_) j = lim[0], ws->pos = Position(i, j), line_buf.buf[j] = 1, tw_rule(ws, _DOWN_, ws->dim[0]); if (pc->smart & _RIGHT_BAR_) j = lim[1]-1, ws->pos = Position(i, j), line_buf.buf[j] = 1, tw_rule(ws, _DOWN_, ws->dim[0]); } ws->pos = old_pos; return(OK); } /*========================================================================== * tx_tab1 *==========================================================================*/ static int tx_tab1() /*+++ .PURPOSE Interpret the first field of a tabular environment, made of | l r c p{} (column definitions) .RETURNS Number of defined columns .REMARKS ---*/ { char *p; unsigned char j; pd0->cols = 0, pd0->smart = 0; column = *pd0; for (p = htex.ap; *p ; p++) { switch(*p) { case '|': if (column.smart&7) column.smart |= _RIGHT_BAR_, new_col(); else column.smart |= _LEFT_BAR_; continue; case ' ': column.smart |= (column.smart&7 ? _RIGHT_BLANK_ : _LEFT_BLANK_); default: continue; case '{': p += 1 + tex_unit(p+1, 1024); /* Length arbitrary */ continue; case 'l': j = _LEFT_; goto NEW_COL; case 'r': j = _RIGHT_; goto NEW_COL; case 'c': j = _CENTER_; goto NEW_COL; case 'p': j = _JUSTIFY_; NEW_COL: if (column.smart&7) new_col(); column.smart |= j; break; } } if (column.smart&7) new_col(); return ((int)pd0->cols); } /*========================================================================== * tx_tab2 *==========================================================================*/ static int tx_tab2() /*+++ .PURPOSE Interpret the second field of a tabular environment, indicating the column width. .RETURNS OK / NOK (table cannot fit) .REMARKS The last column width is computed, or the table is centered on the window. ---*/ { char *p; int i, left_position, status; DEPTH *pc; status = OK; pd0->col_no = 0; left_position = pd0->col_lim[0]; for (p = htex.ap, pc = pd0+1; pd0->col_no < pd0->cols; pc++, (pd0->col_no)++) { i = 0; while (isTeX(*p,_TeX_SPACE_)) p++; while (isTeX(*p,_TeX_DIGIT_)) i = i*10 + (*(p++) - '0'); if (pc->smart & _LEFT_BAR_) left_position++; if (pc->smart & _LEFT_BLANK_) left_position++; pc->col_lim[0] = left_position; if (i == 0) { i = pd0->col_lim[1] - left_position; if (pc->smart & _RIGHT_BAR_) i--; if (pc->smart & _RIGHT_BLANK_) i--; } left_position += i; if (left_position > pd0->col_lim[1]) /* Too large text ... */ status = NOK, left_position = pd0->col_lim[1]; pc->col_lim[1] = left_position; if (pc->smart & _RIGHT_BAR_) left_position++; if (pc->smart & _RIGHT_BLANK_) left_position++; if (pc->col_lim[1] <= pc->col_lim[0]) /* Too large text ... */ status = NOK, pc->col_lim[0] = pc->col_lim[1] - 1; if (isTeX(*p,_TeX_PUNCT_)) p++; } pd0->col_no = 0; /* If spaces remain, center table */ i = pd0->col_lim[1] - left_position; if (i < 0) status = NOK; if_not(status) ERR_ED_STRING("The table cannot fit on window: ", htex.ap); else /* Remaining blanks */ { pd0->col_lim[1] = left_position; left_position = ( txopt & 1 ? i/2 : 0); for (pc = pd0, i = pd0->cols; i-- >= 0; pc++) pc->col_lim[0] += left_position, pc->col_lim[1] += left_position; } return(status); } /*========================================================================== * open_env *==========================================================================*/ static int open_table() /*+++ .PURPOSE Do operations for opening a table .RETURNS OK .REMARKS ---*/ { pd->env = 't'; tex_getparm(1); tx_tab1(); tex_getparm(2); tx_tab2(); tx_tab0(1); table_depth++; return(OK); } /*==========================================================================*/ static int open_more() /*+++ .PURPOSE Do operations for opening a {more}{...} environment .RETURNS OK .REMARKS ---*/ { int i, l; char *p; pd->env = 'm'; tex_getparm(1); /* More name */ l = strlen(htex.ap); i = More.used; BUF_AppendItem(&oMore, int, &(More.used)); BUF_AppendItems(&More, char, htex.ap, l+1); /* Copy Name */ p = More.buf + i; /* Name address */ strred(p); /* Suppress blanks in name */ More.used = i + strlen(p) + 1; return(OK); } /*==========================================================================*/ static int open_env() /*+++ .PURPOSE Do operations for opening a new environment .RETURNS OK / NOK (not possible) .REMARKS ---*/ { int i; char env; int min_lines; i = CurrentLine(); /* Current position */ env = *(htex.ap+1); /* Environment to open */ /* Some lines at least must exist before starting */ if (env == 'm') min_lines = -1; else if (env == 't') min_lines = (table_depth ? 1:3); else min_lines = 2; if (i >= Lines() - min_lines) return(NOK); if(blank_lines == 0) tx_nl(); open_depth(); /* Copy this depth */ pd->env = env; pd->count = 0; pd->line_lim[0] = CurrentLine(); pd->line_lim[1] = pd->line_lim[0]; if (env == 'm') /* more */ inaux = &More, open_more(); if (env == 't') /* Tabular Environment */ open_table(); return(OK); } /*========================================================================== * close_env *==========================================================================*/ static int close_table() /*+++ .PURPOSE Do operations for closing a table .RETURNS OK .REMARKS ---*/ { do_init_line = 0; clear_down(pd0); /* Clear the bottom of Columns */ tx_tab0(0); table_depth--; return(OK); } /*==========================================================================*/ static int close_env() /*+++ .PURPOSE Do operations for closing an environment .RETURNS OK .REMARKS ---*/ { char *p; p = htex.ap + 1; if (pd->env != *p) ERR_ED_STRING("Mismatching begin/end env.: ", p); if (pd0->env == 'm') /* More */ inaux = NULL_PTR(BUFFER), BUF_AppendItem(&More, char, &zero); if (pd0->env == 't') /* Ending Table Env */ close_table(); if(blank_lines == 0) tx_nl() ; return(close_depth()); } /*========================================================================== * tx_item *==========================================================================*/ static int tx_item() /*+++ .PURPOSE Write an `item' .RETURNS OK / NOK (line full) .REMARKS Item issued in Bold ---*/ { int i, old_attr; if(blank_lines == 0) tx_nl() ; if (BottomReached()) return(NOK); pd->count += 1; /* Item number */ pd->col_lim[0] -= sizeof(item_ed); if (pd->col_lim[0] < 0) pd->col_lim[0] = 0; ws->pos = Position(CurrentLine(), pd->col_lim[0]); item_ed[0] = pd->count, item_ed[1] = '>', item_ed[2] = ' '; switch(pd->env) { case 'e': item_ed[0] += '0'; break; case 'a': item_ed[0] += 'a'-1; break; case 'A': item_ed[0] += 'A'-1; break; default: item_ed[0] = '='; } old_attr = SetAttr(ws, _BOLD_); i = tx_out(item_ed, 2); SetAttr(ws, old_attr); if (i == 0) pd->count -= 1, i = NOK; else tx_out(item_ed+2, sizeof(item_ed)-2), pd->col_lim[0] += sizeof(item_ed), i = OK; return(i); } /*========================================================================== * multicol *==========================================================================*/ static int multicol(str) /*+++ .PURPOSE Interprets the `multicolumn' environment .RETURNS Length of string taken into account .REMARKS ---*/ char *str; /* IN: multicolumn specification (starting with `m') */ { int i, nc, status; DEPTH *pm; char *p; ACHAR *pa; for (p = str; *++p == '\0'; ) ; if (*p == '0') /* Close Multicol Env */ { do_init_line = tr_line(pd, 2, 1); close_depth(); return(1); } status = depth_buf->offset; open_depth(); /* Create a new depth */ pm = pd; pd0 = (DEPTH *)(depth_buf->buf + status); /* In case of expansion */ pd = pd0 + 1 + pd0->col_no; pd->flags |= JustificationDone; /* Don't justify old columns */ tex_getparm(1); /* Number of columns */ nc = atoi(htex.ap); pm->flags |= ForceJustification; pm->smart = 0; status = OK; if ((int)(pd0->col_no + nc) > (int)pd0->cols) status = NOK, nc = pd0->cols - pd0->col_no; if (nc < 1) status = NOK, nc = 1; pd0->col_i = nc; /* Increment for next column */ pm->col_lim[0] = pd->col_lim[0]; pm->col_lim[1] = (pd + nc - 1)->col_lim[1]; /* Modify the current line sketch */ if (tr_line(pm, 1, 2)) clear_down(pm); /* Chose smart attr */ ChoseSmart: switch(*(p++)) { case '|': case ' ': if_not(iscntrl(*p)) goto ChoseSmart; /* If |c| */ default : pm->smart = _JUSTIFY_, pm->flags &= ~ForceJustification; break; case 'l': pm->smart = _LEFT_; break; case 'r': pm->smart = _RIGHT_; break; case 'c': pm->smart = _CENTER_; break; } while ( (*p == '|') || (*p == ' ')) p++; --p; /* Position at correct position */ /* ws->pos = Position(i, pm->col_lim[0]); */ if_not(status) ERR_ED_STRING("Bad \\multicolumn ", htex.ap); return(p-str); } /*========================================================================== * tx_crule *==========================================================================*/ static int tx_crule() /*+++ .PURPOSE Draw a horizontal rule some columns (\crule). .RETURNS OK / NOK (Bad column) .REMARKS Argument normally contains 2 parameters separated by a dash. ---*/ { int i, j, len, status; short lim[2], alim[2]; char *p; DEPTH *pd; status = NOK; /* Default status */ pd0->col_no = 0; i = CurrentLine(); if (rule_lines) i--, ws->pos -= ws->dim[1]; if (BottomReached()) FINISH; len = 0; tex_getparm(1); p = htex.ap; alim[0] = pd0->col_no + 1; /* Column Number */ alim[1] = alim[0]; if (*p) /* There are parameters */ { p += strloc(p, '-'); if (*p == '-') alim[0] = atoi(htex.ap), alim[1] = atoi(++p); /* Two Parameters */ else alim[1] = alim[0] + atoi(htex.ap); } if ( (alim[0] < 1) || (alim[1] < alim[0]) || (alim[1] > (int)pd0->cols)) { ERR_ED_STRING("Bad \\crule ", htex.ap); FINISH; } full_width(pd0 + alim[0], lim); /* lim[0] = Left */ if (alim[0] > 1) /* Check if preceding column has a Right Bar */ { pd = pd0 + (alim[0] - 1); if (pd->smart & _RIGHT_BAR_) lim[0] -= 1; } full_width(pd0 + alim[1], alim); /* alim[1] = Right */ len = alim[1] - lim[0]; i = CurrentLine(); if (len > 0) ws->pos = Position(i, lim[0]), tw_rule(ws, _RIGHT_, len); ++i; ws->pos = Position(i, 0); nltab(); rule_lines = 1; status = OK; FIN: return(status); } /*========================================================================== * tx_rule *==========================================================================*/ static int tx_rule() /*+++ .PURPOSE Draw a horizontal rule over the complete window / table. .RETURNS OK / NOK (Window full) .REMARKS ---*/ { int i, j; if (BottomReached()) return(NOK); if (blank_lines == 0) tx_nl(); if (do_init_line) init_line(); pd0->col_no = 0; i = CurrentLine(); /* Now replace blanks by horizontal bars */ ws->pos = Position(i, pd0->col_lim[0]); tw_rule(ws, _RIGHT_, pd0->col_lim[1] - pd0->col_lim[0]) ; ++i; ws->pos = Position(i, 0); nltab(); rule_lines = 1; return(OK); } /*========================================================================== * tx_mark *==========================================================================*/ static int tx_mark() /*+++ .PURPOSE Mark the starting point of a field. .RETURNS OK / NOK (Window full) .REMARKS ---*/ { int i, l; /* Save Field name, Field Type, Field Picture */ for (i = 1; i <= 3; i++) { tex_getparm(i); /* Get Param */ l = strlen(htex.ap); /* Param Length */ BUF_AppendItems(&field_names, char, htex.ap, l+1); } /* Save current column position */ BUF_AppendItems(&field_def, short int, &pd->col_lim[0], 2); pd->flags |= InField; /* Next output will be flagged */ marked = 0; /* Count of marked bytes */ return(OK); } /*========================================================================== * get_marked *==========================================================================*/ static int get_marked(st) /*+++ .PURPOSE Retrieve marked fields. .RETURNS Number of fields .REMARKS If a field lies over several lines, complete lines are assumed. ---*/ int st; /* IN: Completion Status of Field */ { char *fname; /* Field Name */ TWFIELD *fdef; /* Field Definition */ short *f, *fe; /* Current Column */ ACHAR *pa; short i, j; char **stored_address; BUFFER *b; MID_STATIC TWFIELD twfield0 = {(char *)0}; /* Issue Error Message if Bad Status */ if (st == NOK) { ERROR("The Form doesn't fit on the Window..."); return(0); } /* Allocate first the Field Buffer connected with window */ if_not(Fields(ws)) { Fields(ws) = BUF_Open(char, field_names.used + sizeof(TWFIELD)*(1 + field_def.used / (3*sizeof(short int))), 8*sizeof(TWFIELD)); } b = Fields(ws); BUF_Clear(b); /* ... and retrieve fields successively */ f = (short int *)(field_def.buf); /* First column range */ fe = (short int *)(field_def.buf + field_def.used); for (; f < fe; f += 3) { fdef = BUF_AllocateItem(b, TWFIELD); fdef->dim[1] = f[1] - f[0]; /* Field Width */ fdef->dim[1] = MIN(fdef->dim[1], f[2]); i = 0, j = f[0], pa = Aij(ws, 0, j); while (!(*pa & _MARKER1_)) /* Find Start of Marked Text */ { if (++j >= f[1]) { j = f[0], i++, pa = Aij(ws, i, j); if (i >= Lines()) break; /* Bottom of Window */ } else pa++; } if (i >= Lines()) { b->used -= sizeof(TWFIELD); break; /* Bottom of Window */ } *pa &= ~_MARKER1_; fdef->home[0] = i, fdef->home[1] = j; fdef->dim[0] = (f[2] + fdef->dim[1] -1)/fdef->dim[1]; } i = b->used / sizeof(TWFIELD); /* Number of Fields */ BUF_AppendItem(b, TWFIELD, &twfield0); /* End indicator */ /* Copy now the Names into the Buffer associated to Window */ b->offset = b->used; /* Mark beginning of names */ BUF_AppendItems(b, char, field_names.buf, field_names.used); /* Indicate positions of names */ fdef = (TWFIELD *)(b->buf); fname= b->buf + b->offset; /* First name address */ for (j = i; --j >= 0; fdef++) { for (stored_address = &(fdef->name); stored_address <= (&fdef->pic); stored_address++) *stored_address = fname, fname += 1 + strlen(fname); } return(i); } /*========================================================================== * tx_finish *==========================================================================*/ static int tx_finish(st) /*+++ .PURPOSE Terminate Display: actions of \vfill's, non-terminated tables, retrieve marked fields. .RETURNS st .REMARKS ---*/ int st; /* IN: Status as OK / NOK / EOF */ { ENTER("tx_finish"); if (hfill_no) tx_hfil(); /* Insert supplementary blank lines */ if(vfill_no > 0) tx_vfil(), vfill_no = 0; /* Get the Marked Lines */ if (field_def.used) get_marked(st); if ( (st == OK) && (depth_buf->offset > sizeof(int))) ERROR("Missing } or \\end"); if (WindowIsActive) ActiveWindow(ws); EXIT(st); } /*========================================================================== * tx_option *==========================================================================*/ int tx_option(opt) /*+++ .PURPOSE Change options. .RETURNS Old options. .REMARKS ---*/ int opt; /* IN: New option 0 = Don't Center */ { int old_opt; old_opt = txopt; txopt = opt; return(old_opt); } /*========================================================================== * tx_symbol *==========================================================================*/ char *tx_symbol(str) /*+++ .PURPOSE Retrieve the translation of a definition .RETURNS Pointer to the translated definition .REMARKS ---*/ char *str; /* IN: String to translate */ { return(tex_symbol(str)); } int tx_def(symbol, synonym) /*+++ .PURPOSE Set a symbol in the TeX definitions. .RETURNS 1 .REMARKS ---*/ char *symbol; /* IN: Symbol to define */ char *synonym; /* IN: Equivalence */ { char *def, *p; tx_tex(); /* Install the TeX structure */ def = MEM_GET(char, 12 + strlen(symbol) + strlen(synonym)); p = def + strcopy(def, "\\def"); if (*symbol != '\\') *(p++) = '\\'; p += strcopy(p, symbol); p += strcopy(p, "{"); p += strcopy(p, synonym); p += strcopy(p, "}"); #if DEBUG LOG_ED_STRING("Added: ", def); #endif status = TeX_Execute(&htex, def, strlen(def)); MEM_FREE(def); return(1); } /*========================================================================== * tx_display *==========================================================================*/ int tx_display(w, str, len, clear_option) /*+++ .PURPOSE Display a text on the window. .RETURNS --- OK (no remaining text) --- NOK (text did not fit on the window) --- EOF: the \EOF macro was fond in the text. .REMARKS ---*/ WINDOW *w; /* IN: Window to echo the processed text */ char *str; /* IN: text to display, or NULL (continuation )*/ int len; /* IN: Length of text */ int clear_option; /* IN: Option 1 to clear window \ before display */ { register int status; ENTER("tx_display"); #if DEBUG TRACE_ED_STR2("String to display:", str, len); #endif ws = w; tx_init(str, clear_option); /* Execute TeX. The routines tx_out collects the words * for output, while tx_action is triggered for each action. */ status = TeX_Execute(&htex, str, len); /* Terminate: vfill adjustments, non-terminated tables, * and retrieve marked fields */ tx_finish(status); EXIT(status); } /*========================================================================== * tx_mdisplay *==========================================================================*/ int tx_mdisplay(w, str, nstrings, clear_option) /*+++ .PURPOSE Display a text on the window made of several pieces of text. The pieces are provided by the array of strings str made of (2*nstrings) pointers, specifying nstrings times (start, end). (a pointer to the end of a string is the byte just following the last byte of the string, i.e. the address of the null character for a standard string) .RETURNS --- OK (no remaining text) --- NOK (text did not fit on the window) --- EOF: the \EOF macro was fond in the text. .REMARKS ---*/ WINDOW *w; /* IN: Window to echo the processed text */ char **str; /* IN: Array of strings to display, \ as n* (start, end) */ int nstrings; /* IN: Number of strings */ int clear_option; /* IN: Option 1 to clear window \ before display */ { register int status; ENTER("tx_mdisplay"); #if DEBUG TRACE_ED_I("Number of string to display:", nstrings); #endif ws = w; tx_init(str, clear_option); /* Execute TeX. The routines tx_out collects the words * for output, while tx_action is triggered for each action. */ status = TeX_ExecuteArray(&htex, str, nstrings); /* Terminate: vfill adjustments, non-terminated tables, * and retrieve marked fields */ tx_finish(status); EXIT(status); } /*========================================================================== * tx_fdisplay *==========================================================================*/ int tx_fdisplay(w, fid, len, clear_option) /*+++ .PURPOSE Display a file extract on the window. .RETURNS --- OK (no remaining text) --- NOK (text did not fit on the window) --- EOF the \EOF macro was found in the text. .REMARKS ---*/ WINDOW *w; /* IN: Window to echo the processed text */ int fid; /* IN: File number (opened by fi_open) */ int len; /* IN: Maximal number of bytes to read */ int clear_option; /* IN: Option 1 to clear window \ before display */ { register int status; ENTER("tx_fdisplay"); ws = w; tx_init(blanks, clear_option); /* Non-null char pointer */ /* Load text to process */ TeX_Load(&htex, fid, len); /* Execute TeX. The routines tx_out collects the words * for output, while tx_action is triggered for each action. */ status = TeX_Continue(&htex); /* Terminate: vfill adjustments, non-terminated tables, * and retrieve marked fields */ tx_finish(status); EXIT(status); } /*========================================================================== * tx_file *==========================================================================*/ int tx_file(w, fname, clear_option) /*+++ .PURPOSE Display a complete file extract on the window. .RETURNS --- OK (no remaining text) --- NOK (text did not fit on the window) --- EOF the \EOF macro was found in the text. .REMARKS ---*/ WINDOW *w; /* IN: Window to echo the processed text */ char *fname; /* IN: File name */ int clear_option; /* IN: Option 1 to clear window \ before display */ { register int status; ENTER("tx_file"); ws = w; tx_init(fname, clear_option); /* Non-null char pointer */ /* Load text to process */ TeX_Include(&htex, fname); /* Execute TeX. The routines tx_out collects the words * for output, while tx_action is triggered for each action. */ status = TeX_Continue(&htex); /* Terminate: vfill adjustments, non-terminated tables, * and retrieve marked fields */ tx_finish(status); EXIT(status); } /*========================================================================== * tx_fields *==========================================================================*/ TWFIELD *tx_fields(w) /*+++ .PURPOSE Retrieve the marked fields in a window. .RETURNS Address of first TWFIELD / null pointer if no field was defined. .REMARKS The last valid field is followed by a null name, i.e. (char *)0. ---*/ WINDOW *w; /* IN: Window concerned */ { TWFIELD *f; BUFFER *b; ENTER("*tx_fields"); f = NULL_PTR(TWFIELD); b = Fields(w); if (b) if (b->used) f = (TWFIELD *)b->buf; EXIT_PTR(TWFIELD, f); } /*========================================================================== * tx_more *==========================================================================*/ char *tx_more(name) /*+++ .PURPOSE Retrieve the `more' (between \begin{more}{name} and \end{more}) .RETURNS Address of code / NULL if none .REMARKS When `name' is NULL, return the NEXT more value as the two strings concatenated. ---*/ char *name; /* IN: `more' name to find */ { char *p; int i, *pi; ENTER("*tx_more"); if (!name) { /* Get the Next one */ if (oMore.offset >= oMore.used) { oMore.offset = 0; EXIT_PTR(char, 0); /* Indicates End */ } pi = (int *)(oMore.buf + oMore.offset); oMore.offset += sizeof(int); p = More.buf + *pi; EXIT_PTR(char, p); } for (i=SET_Items(&oMore, int), pi=SET_FirstItem(&oMore, int); --i >= 0; pi++) { p = More.buf + *pi; if (strcomp(name, p) == 0) break; /* Topic Found */ } if (i < 0) p = NULL_PTR(char); else p += 1 + strlen(name); EXIT_PTR(char, p); } /*========================================================================== * tx_math *==========================================================================*/ int tx_math(f) /*+++ .PURPOSE Define an action routine in case of mathematical symbols ($ ^ _) .RETURNS OK .REMARKS Use NULL_FCT to take standard action (ignore) ---*/ int (*f)(); /* IN: Function with arguments (string, length) \ to call when $ ^ _ are encountered */ { external_action = f; return(OK); } /*========================================================================== * tx_out *==========================================================================*/ int tx_out(str, len) /*+++ .PURPOSE This is the output routine. .RETURNS Number of bytes processed. .REMARKS ---*/ char *str; /* text to output */ int len; /* Length of text */ { int output_bytes, j, m; /* ENTER("tx_out"); */ #if DEBUG TRACE_ED_STR2("Output=>",str,len); #endif if (inaux) { BUF_AppendItems(inaux, char, str, len); j = inaux->used; /* Save */ BUF_AppendItem(inaux, char, &zero); inaux->used = j; /* Restore */ return(len); } output_bytes = 0; if (len < 0) FINISH; tx_set(); j = CurrentColumn(); if (j < pd->col_lim[0]) { /* Position at Left Margin */ if (pd->flags & AnchoredPosition) ; else ws->pos += pd->col_lim[0] - j, j = pd->col_lim[0]; } else pd->flags &= ~AnchoredPosition; if (BottomReached()) FINISH; if ((htex.mode != _TeX_VERBATIM_) && (j + len > pd->col_lim[1])) /* Doesn't fit on the line ... */ { tx_smart(); if (blank_lines == 0) tx_nl(); if (BottomReached()) FINISH; j = pd->col_lim[0]; ws->pos += j; } m = ws->pos; /* Position for marker */ output_bytes = Write(ws, str, len); if (output_bytes > 0) { last_issued_char = *(str+output_bytes-1); blank_lines = 0; rule_lines = 0; if ((j + len) == Columns()) /* On a new line... */ blank_lines++, last_issued_char = ' '; if (pd->flags & InField) Mark(m, output_bytes); } FIN: /* EXIT(output_bytes); */ return(output_bytes); } /*========================================================================== * tx_action *==========================================================================*/ int tx_action(str, len) /*+++ .PURPOSE This is the action routine. .RETURNS Number of bytes processed. .REMARKS ---*/ char *str; /* text to output */ int len; /* Length of text */ { char *p, *pe; int i, j; unsigned char old_attr; MID_STATIC char fill_error[] = "Too many \\vfill's"; MID_STATIC char no_math_action[] = "`$' ignored"; MID_STATIC char bad_action[] = "`$' action stopped"; /* ENTER("tx_action"); */ #if DEBUG TRACE_ED_STR2("Action: ",str,len); #endif p = str, pe = str+len; tx_set(); for (; p < pe; p++) switch(*p) { case '0': /* begin / end Environment */ if (*htex.ap == _TeX_BEGIN_) /* New env. */ if_not(open_env()) FINISH; else; else if (*htex.ap == _TeX_END_) /* Close env. */ if_not(close_env()) FINISH; else; else; break; case '{' : /* New Depth */ if (BottomReached()) FINISH; open_depth(); break; case '}': /* Old depth */ close_depth(); break; case '\0': case '\\': /* NUL's may be found after macro substitutions */ continue; case '$': case '^': case '_': /* Mathematical symbols */ if (external_action) { if_not(i = (*external_action)(p, pe-p)) FINISH; p += i-1; } else no_math_action[1] = *p, WARNING(no_math_action); break; case ' ': /* Stretchable blank */ if(inaux) { if ((inaux->used) && (inaux->buf[inaux->used-1] != ' ')) tx_out(blanks, 1); } else tx_blank(); /* Always possible */ break; case '\r': /* New Line */ case_newline: if (inaux) { tx_out("\n", 1); break; } if (blank_lines == 0) tx_nl() ; if (pd->env == 't') tx_set(), nltab(); break; case '\n': /* New paragraph */ if(inaux) { tx_out("\n", 1); break; } while (blank_lines <= 1) { if (BottomReached()) break; tx_nl() ; } break; case '/': /* Skip Line */ if(inaux) { tx_out("\n", 1); break; } if(blank_lines == 0) tx_nl() ; tx_nl() ; break; case '&': /* Tab in Tabular, or `tab' outside */ if(inaux) { tx_out("&", 1); break; } if (pd->env == 't') { if (CurrentColumn() > pd->col_lim[0]) tx_smart(), pd->line_lim[1] += 1; pd0->line_lim[1] = MAX(pd0->line_lim[1], pd->line_lim[1]); if (hfill_no) tx_hfil(); /* Horizontal Fill */ j = pd0->col_no; /* save in case bad & */ pd0->col_no += pd0->col_i; /* Increment column */ pd0->col_i = 1; if (pd0->col_no >= pd0->cols) { WARNING("Too many &'s"); pd0->col_no = j; /* Restore ... */ goto case_newline; } tx_set(); ws->pos = Position(pd0->line_lim[0], pd->col_lim[0]); break; } case 't': /* Put a Tab */ if(inaux) { tx_out("\t", 1); break; } tx_blank(); /* At least one blank */ tabright(blanks, 0); /* Go to next tab */ break; case 'b': Bell(); /* Ring Bell */ break; case 'f': /* Fill vertical or horizontal */ if(inaux) break; fill_error[10] = *++p; if (*p == 'v') /* Vertical Fill */ { if (vfill_no >= MAX_MARKED) { ERROR(fill_error); continue; } if(blank_lines == 0) tx_nl() ; vfill[vfill_no++] = CurrentLine(); } else /* Horizontal Fill */ { if (hfill_no >= MAX_MARKED) { ERROR(fill_error); continue; } hfill[hfill_no++] = CurrentColumn(); } continue; case 'F': /* Mark Field or Redefine Columns */ if(inaux) break; if (BottomReached()) FINISH; switch(*++p) { case 's': tx_mark(); /* Start */ break; case 'e': /* End Field */ if (marked == 0) /* Null Field: At least one byte! */ tx_out(blanks, 1); BUF_AppendItem(&field_def, short, &marked); /* Length */ pd->flags &= ~InField; break; case 't': /* Redefine Columns in a Table */ close_table(); close_depth(), open_depth(); j = ws->pos; if ((rule_lines) && (ws->pos >= ws->dim[1])) ws->pos -= ws->dim[1]; open_table(); tx_set(); if(rule_lines) tx_rule(); else nltab(); ws->pos = j; break; } break; case 'J': /* Justification specifications */ if (BottomReached()) FINISH; switch(*++p) { case 'l': pd->smart = _LEFT_; break; case 'r': pd->smart = _RIGHT_; break; case 'c': pd->smart = _CENTER_; break; case 'j': pd->smart = _JUSTIFY_; break; case 'f': pd->flags |= ForceJustification; break; case 't': inaux = &aux; BUF_Clear(inaux); break; /* Justfy Tab */ case '0': /* End Tab */ if (tabright(aux.buf, aux.used) != aux.used) { --p; FINISH; } inaux = NULL_PTR(BUFFER); break; default : tx_smart(); break; } break; case 'M': /* Move Margins */ if(inaux) break; switch(*++p) { case 'l': pd->col_lim[0] += MARGIN; break; case 'r': pd->col_lim[1] -= MARGIN; break; case 'L': pd->col_lim[0] -= MARGIN; break; case 'R': pd->col_lim[1] += MARGIN; break; case 'i': /* Item */ if_not(tx_item()) { p--; FINISH;} break; case 'I': /* indent */ tx_out(blanks, MARGIN); continue; case 'h': /* hspace */ tex_getparm(1); i = atoi(htex.ap); j = CurrentColumn(); if (j < pd->col_lim[0]) j = pd->col_lim[0]; if (i < 0) { /* Left Move */ j += i; if (j < 0) j = 0; i = CurrentLine(); ws->pos = Position(i,j); pd->flags |= AnchoredPosition; continue; } for ( ; i > 0; i--) { if_not(tx_out(blanks, 1)) FINISH; j = MIN(pd->col_lim[1] - CurrentColumn(), i-1); if (j > 0) { j = MIN(j, sizeof(blanks)); tx_out(blanks, j); i -= j; } } continue; case 'V': /* Test remaining lines */ tex_getparm(1); i = atoi(htex.ap); if (i >= Lines()) continue; if ((ws->pos + i*Columns()) <= ws->marker[1]) continue; p = str; /* Stop here, tx_action will return 0 */ FINISH; case 'H': /* Test remaining cols */ tex_getparm(1); i = atoi(htex.ap); if ((CurrentColumn()+i) > pd->col_lim[1]) tx_nl(); continue; } if (pd->col_lim[0] < 0) pd->col_lim[0] = 0, ERROR("Negative Left Margin"); if (pd->col_lim[1] > Columns()) pd->col_lim[1] = Columns(), ERROR("Bad Right Margin"); continue; case 'm': /* Multicolumn */ if(inaux) break; if (BottomReached()) FINISH; p += multicol(p); break; case 'r': if(inaux) break; tx_crule(); tx_set(); continue; case 'R': if(inaux) break; tx_rule(); tx_set(); continue; case 'V': /* Video Attributes */ if(inaux) break; old_attr = pd->attr; /* Current Attribute */ switch(*++p) { case 'B': i = old_attr | _BOLD_; break; case 'b': i = old_attr | _BLINK_; break; case 'u': i = old_attr | _UNDERSCORE_;break; case 'r': i = old_attr | _REVERSE_; break; case 'R': i = old_attr ^ _REVERSE_; break; case 'n': i = 0; break; default : i = old_attr; break; } j = CurrentColumn(); pd->attr = i; if (old_attr != pd->attr) SetAttr(ws, pd->attr); if (j <= pd->col_lim[0]) current_blank = ws->attr; break; default: bad_action[1] = *p, WARNING(bad_action); p = str - 1; /* Means EOF */ FINISH; } FIN: /* EXIT(p-str); */ return(p-str); } /*========================================================================== * tx_list *==========================================================================*/ int tx_list() /*+++ .PURPOSE List, in the Log File, the list of macros .RETURNS Number of non-uused symbols .REMARKS For debugging purposes. ---*/ { int n; ENTER("+tx_list"); n = tex_list(&htex); EXIT(n); }