1 /*@z11.c:Style Service:EchoStyle()@*******************************************/
2 /*                                                                           */
3 /*  THE LOUT DOCUMENT FORMATTING SYSTEM (VERSION 3.39)                       */
4 /*  COPYRIGHT (C) 1991, 2008 Jeffrey H. Kingston                             */
5 /*                                                                           */
6 /*  Jeffrey H. Kingston (jeff@it.usyd.edu.au)                                */
7 /*  School of Information Technologies                                       */
8 /*  The University of Sydney 2006                                            */
9 /*  AUSTRALIA                                                                */
10 /*                                                                           */
11 /*  This program is free software; you can redistribute it and/or modify     */
12 /*  it under the terms of the GNU General Public License as published by     */
13 /*  the Free Software Foundation; either Version 3, or (at your option)      */
14 /*  any later version.                                                       */
15 /*                                                                           */
16 /*  This program is distributed in the hope that it will be useful,          */
17 /*  but WITHOUT ANY WARRANTY; without even the implied warranty of           */
18 /*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            */
19 /*  GNU General Public License for more details.                             */
20 /*                                                                           */
21 /*  You should have received a copy of the GNU General Public License        */
22 /*  along with this program; if not, write to the Free Software              */
23 /*  Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307 USA   */
24 /*                                                                           */
25 /*  FILE:         z11.c                                                      */
26 /*  MODULE:       Style Service                                              */
27 /*  EXTERNS:      EchoStyle(), SpaceChange(), BreakChange()                  */
28 /*                                                                           */
29 /*****************************************************************************/
30 #include "externs.h"
31 
32 
33 #if DEBUG_ON
34 /*****************************************************************************/
35 /*                                                                           */
36 /*  FULL_CHAR *EchoStyle(style)                                              */
37 /*                                                                           */
38 /*  Returns a string showing the value of the style.                         */
39 /*                                                                           */
40 /*****************************************************************************/
41 
EchoStyle(STYLE * style)42 FULL_CHAR *EchoStyle(STYLE *style)
43 { static FULL_CHAR res[100];
44   static char buff[100];
45   static char *hyphwords[] = { "hyph_undef", "hyph_off", "hyph_on" };
46   static char *fillwords[] = { "fill_undef", "fill_off", "fill_on" };
47   static char *spacewords[] = { "lout", "comp", "troff", "tex" };
48   static char *displaywords[] = { "undef", "adjust", "outdent", "oragged",
49 				  "left", "centre", "right", "do" };
50 
51   StringCopy(res, AsciiToFull("["));
52   StringCat(res, EchoCatOp(VCAT,mark(line_gap(*style)),join(line_gap(*style))));
53   StringCat(res, EchoGap(&line_gap(*style)));
54   StringCat(res, AsciiToFull(", "));
55   if( font(*style) == 0 )
56     StringCat(res, AsciiToFull("nofont"));
57   else
58   {
59     StringCat(res, FontFamilyAndFace(font(*style)));
60     StringCat(res, AsciiToFull(" "));
61     StringCat(res, EchoLength(FontSize(font(*style), nilobj)));
62   }
63   StringCat(res, AsciiToFull(" ("));
64   StringCat(res, AsciiToFull(spacewords[space_style(*style)]));
65   StringCat(res, AsciiToFull(" "));
66   StringCat(res, EchoGap(&space_gap(*style)));
67   StringCat(res, AsciiToFull("), "));
68   StringCat(res, AsciiToFull(hyph_style(*style) < 3 ?
69 		    hyphwords[hyph_style(*style)] : "?"));
70   StringCat(res, AsciiToFull(":"));
71   StringCat(res, AsciiToFull(fill_style(*style) < 3 ?
72 		    fillwords[fill_style(*style)] : "?"));
73   StringCat(res, AsciiToFull(":"));
74   StringCat(res, AsciiToFull(display_style(*style) < 7 ?
75 		    displaywords[display_style(*style)] : "?"));
76   if( small_caps(*style) > 0 ) StringCat(res, AsciiToFull(":smallcaps"));
77   if( vadjust(*style) ) StringCat(res, AsciiToFull(":vadjust"));
78   if( hadjust(*style) ) StringCat(res, AsciiToFull(":hadjust"));
79   if( padjust(*style) ) StringCat(res, AsciiToFull(":padjust"));
80   if( yunit(*style) != 0 )
81   { StringCat(res, AsciiToFull(":y="));
82     StringCat(res, EchoLength(yunit(*style)));
83   }
84   if( zunit(*style) != 0 )
85   { StringCat(res, AsciiToFull(":z="));
86     StringCat(res, EchoLength(zunit(*style)));
87   }
88   if( nobreakfirst(*style) ) StringCat(res, AsciiToFull(":NBF"));
89   if( nobreaklast(*style) ) StringCat(res, AsciiToFull(":NBL"));
90   if( marginkerning(*style) ) StringCat(res, AsciiToFull(":MK"));
91   sprintf(buff, ":C%d:P%d", colour(*style), texture(*style));
92   StringCat(res, AsciiToFull(buff));
93   StringCat(res, AsciiToFull("]"));
94   return res;
95 } /* end EchoStyle */
96 #endif
97 
98 
99 /*@::SpaceChange()@***********************************************************/
100 /*                                                                           */
101 /*  SpaceChange(style, x)                                                    */
102 /*                                                                           */
103 /*  Change the current space style as indicated by object x.                 */
104 /*                                                                           */
105 /*****************************************************************************/
106 
changespace(STYLE * style,OBJECT x)107 static void changespace(STYLE *style, OBJECT x)
108 { GAP res_gap;  unsigned gap_inc;
109   assert( is_word(type(x)), "changespace: type(x)!" );
110   if( beginsbreakstyle(string(x)[0]) )
111   {
112     /* should be a new space style option */
113     if( StringEqual(string(x), STR_SPACE_LOUT) )
114 	space_style(*style) = SPACE_LOUT;
115     else if( StringEqual(string(x), STR_SPACE_COMPRESS) )
116 	space_style(*style) = SPACE_COMPRESS;
117     else if( StringEqual(string(x), STR_SPACE_SEPARATE) )
118 	space_style(*style) = SPACE_SEPARATE;
119     else if( StringEqual(string(x), STR_SPACE_TROFF) )
120 	space_style(*style) = SPACE_TROFF;
121     else if( StringEqual(string(x), STR_SPACE_TEX) )
122 	space_style(*style) = SPACE_TEX;
123     else Error(11, 1, "unknown option to %s symbol (%s)",
124 	   WARN, &fpos(x), KW_SPACE, string(x));
125   }
126   else /* should be a new space gap */
127   { GetGap(x, style, &res_gap, &gap_inc);
128     if( gap_inc != GAP_ABS && units(res_gap) != units(space_gap(*style)) )
129     { Error(11, 2, "spacing %s is not compatible with current spacing",
130 	WARN, &fpos(x), string(x));
131     }
132     else
133     { units(space_gap(*style)) = units(res_gap);
134       mode(space_gap(*style))  = mode(res_gap);
135       width(space_gap(*style)) = gap_inc == GAP_ABS ? width(res_gap) :
136 	     gap_inc == GAP_INC ? width(space_gap(*style)) + width(res_gap) :
137 	     find_max(width(space_gap(*style)) - width(res_gap), 0);
138     }
139   }
140   debug1(DSS, D, "SpaceChange returning %s", EchoStyle(style));
141 } /* end SpaceChange */
142 
143 
SpaceChange(STYLE * style,OBJECT x)144 void SpaceChange(STYLE *style, OBJECT x)
145 { OBJECT link, y;
146   debug2(DSS, D, "SpaceChange(%s, %s)", EchoStyle(style), EchoObject(x));
147   switch( type(x) )
148   {
149     case NULL_CLOS: break;
150 
151     case WORD:
152     case QWORD:	if( !StringEqual(string(x), STR_EMPTY) )
153 		  changespace(style, x);
154 		break;
155 
156 
157     case ACAT:	for( link = Down(x);  link != x;  link = NextDown(link) )
158 		{ Child(y, link);
159 		  if( type(y) == GAP_OBJ || type(y) == NULL_CLOS )  continue;
160 		  else if( is_word(type(y)) )
161 		  { if( !StringEqual(string(y), STR_EMPTY) )
162 		      changespace(style, y);
163 		  }
164 		  else Error(11, 3, "invalid left parameter of %s",
165 			 WARN, &fpos(x), KW_SPACE);
166 		}
167 		break;
168 
169 
170     default:	Error(11, 4, "invalid left parameter of %s",
171 		  WARN, &fpos(x), KW_SPACE);
172 		break;
173   }
174   debug1(DSS, D, "SpaceChange returning %s", EchoStyle(style));
175 } /* end SpaceChange */
176 
177 
178 /*@::BreakChange()@***********************************************************/
179 /*                                                                           */
180 /*  BreakChange(style, x)                                                    */
181 /*                                                                           */
182 /*  Change the current break style as indicated by object x.                 */
183 /*                                                                           */
184 /*****************************************************************************/
185 
changebreak(STYLE * style,OBJECT x)186 static void changebreak(STYLE *style, OBJECT x)
187 { GAP res_gap;  unsigned gap_inc;
188   debug0(DSS, D, "[ changebreak");
189   if( beginsbreakstyle(string(x)[0]) )
190   {
191     /* should be a new break style option */
192     if( StringEqual(string(x), STR_BREAK_HYPHEN) )
193 	hyph_style(*style) = HYPH_ON;
194     else if( StringEqual(string(x), STR_BREAK_NOHYPHEN) )
195 	hyph_style(*style) = HYPH_OFF;
196     else if( StringEqual(string(x), STR_BREAK_ADJUST) )
197 	fill_style(*style) = FILL_ON, display_style(*style) = DISPLAY_ADJUST;
198     else if( StringEqual(string(x), STR_BREAK_OUTDENT) )
199 	fill_style(*style) = FILL_ON, display_style(*style) = DISPLAY_OUTDENT;
200     else if( StringEqual(string(x), STR_BREAK_RAGGED) )
201 	fill_style(*style) = FILL_ON, display_style(*style) = DISPLAY_LEFT;
202     else if( StringEqual(string(x), STR_BREAK_CRAGGED) )
203 	fill_style(*style) = FILL_ON, display_style(*style) = DISPLAY_CENTRE;
204     else if( StringEqual(string(x), STR_BREAK_RRAGGED) )
205 	fill_style(*style) = FILL_ON, display_style(*style) = DISPLAY_RIGHT;
206     else if( StringEqual(string(x), STR_BREAK_ORAGGED) )
207 	fill_style(*style) = FILL_ON, display_style(*style) = DISPLAY_ORAGGED;
208     else if( StringEqual(string(x), STR_BREAK_LINES) )
209 	fill_style(*style) = FILL_OFF, display_style(*style) = DISPLAY_LEFT;
210     else if( StringEqual(string(x), STR_BREAK_CLINES) )
211 	fill_style(*style) = FILL_OFF, display_style(*style) = DISPLAY_CENTRE;
212     else if( StringEqual(string(x), STR_BREAK_RLINES) )
213 	fill_style(*style) = FILL_OFF, display_style(*style) = DISPLAY_RIGHT;
214     else if( StringEqual(string(x), STR_BREAK_OLINES) )
215 	fill_style(*style) = FILL_OFF, display_style(*style) = DISPLAY_ORAGGED;
216     else if( StringEqual(string(x), STR_BREAK_NOFIRST) )
217 	nobreakfirst(*style) = TRUE;
218     else if( StringEqual(string(x), STR_BREAK_FIRST) )
219 	nobreakfirst(*style) = FALSE;
220     else if( StringEqual(string(x), STR_BREAK_NOLAST) )
221 	nobreaklast(*style) = TRUE;
222     else if( StringEqual(string(x), STR_BREAK_LAST) )
223 	nobreaklast(*style) = FALSE;
224     else if( StringEqual(string(x), STR_BREAK_MARGINKERNING) )
225 	marginkerning(*style) = TRUE;
226     else if( StringEqual(string(x), STR_BREAK_NOMARGINKERNING) )
227 	marginkerning(*style) = FALSE;
228     else Error(11, 5, "found unknown option to %s symbol (%s)",
229 	   WARN, &fpos(x), KW_BREAK, string(x));
230   }
231   else /* should be a new inter-line gap */
232   { GetGap(x, style, &res_gap, &gap_inc);
233     if( gap_inc != GAP_ABS && units(res_gap) != units(line_gap(*style)) )
234       Error(11, 6, "line spacing %s is not compatible with current spacing",
235         WARN, &fpos(x), string(x));
236     else
237     { units(line_gap(*style)) = units(res_gap);
238       mode(line_gap(*style))  = mode(res_gap);
239       width(line_gap(*style)) = gap_inc == GAP_ABS ? width(res_gap) :
240 	gap_inc == GAP_INC ? width(line_gap(*style)) + width(res_gap) :
241 	find_max(width(line_gap(*style)) - width(res_gap), 0);
242     }
243   }
244   debug0(DSS, D, "] changebreak");
245 } /* end changebreak */
246 
BreakChange(STYLE * style,OBJECT x)247 void BreakChange(STYLE *style, OBJECT x)
248 { OBJECT link, y;
249   GAP res_gap;  unsigned gap_inc;
250   debug3(DSS, D, "BreakChange(%s, %s at %s)", EchoStyle(style),
251     EchoObject(x), EchoFilePos(&fpos(x)));
252   switch( type(x) )
253   {
254     case NULL_CLOS: break;
255 
256     case WORD:
257     case QWORD:	if( !StringEqual(string(x), STR_EMPTY) )
258 		{
259 		  debug1(DSS, D, "BreakChange WORD examining %s", (string(x)));
260 		  if( StringEqual(string(x), STR_BREAK_SETOUTDENT) )
261 		  {
262 		    debug1(DSS, D, " found %s", STR_BREAK_SETOUTDENT);
263 		    Error(11, 11, "width missing after %s in %s",
264 		      WARN, &fpos(x), STR_BREAK_SETOUTDENT, KW_BREAK);
265 		  }
266 		  else
267 		  {
268 		    debug1(DSS, D, " not found %s", STR_BREAK_SETOUTDENT);
269 		    changebreak(style, x);
270 		  }
271 		}
272 		break;
273 
274 
275     case ACAT:	for( link = Down(x);  link != x;  link = NextDown(link) )
276 		{ Child(y, link);
277 		  if( type(y) == GAP_OBJ || type(y) == NULL_CLOS )  continue;
278 		  else if( is_word(type(y)) )
279 		  { if( !StringEqual(string(y), STR_EMPTY) )
280 		    {
281 		      debug1(DSS, D, "BreakChange examining %s", (string(y)));
282 		      if( StringEqual(string(y), STR_BREAK_SETOUTDENT) )
283 		      {
284 			debug1(DSS, D, "  found %s", STR_BREAK_SETOUTDENT);
285 			if( NextDown(link)==x || NextDown(NextDown(link))==x )
286 			{
287 			  Error(11, 11, "width missing after %s in %s",
288 			    WARN, &fpos(x), STR_BREAK_SETOUTDENT, KW_BREAK);
289 			}
290 			else
291 			{
292 			  link = NextDown(NextDown(link));
293 			  Child(y, link);
294 			  GetGap(y, style, &res_gap, &gap_inc);
295 			  outdent_len(*style) = gap_inc == GAP_ABS ?
296 			    width(res_gap) : gap_inc == GAP_INC ?
297 			    outdent_len(*style) + width(res_gap) :
298 			    find_max(outdent_len(*style) - width(res_gap), 0);
299 			}
300 		      }
301 		      else if( StringEqual(string(y), STR_BREAK_SCALE) )
302 		      {
303 			debug1(DSS, D, "  found %s", STR_BREAK_SCALE);
304 			if( NextDown(link)==x || NextDown(NextDown(link))==x )
305 			{
306 			  Error(11, 12, "scale factor missing after %s in %s",
307 			    WARN, &fpos(x), STR_BREAK_SCALE, KW_BREAK);
308 			}
309 			else
310 			{
311 			  float val;
312 			  link = NextDown(NextDown(link));
313 			  Child(y, link);
314 			  val = GetScaleFactor(y);
315 			  blanklinescale(*style) = (int) (val * SF);
316 			}
317 		      }
318 		      else
319 		      {
320 			debug1(DSS, D, "  not found %s", STR_BREAK_SETOUTDENT);
321 			changebreak(style, y);
322 		      }
323 		    }
324 		  }
325 		  else Error(11, 7, "invalid left parameter of %s",
326 			 WARN, &fpos(x), KW_BREAK);
327 		}
328 		break;
329 
330 
331     default:	Error(11, 8, "invalid left parameter of %s",
332 		  WARN, &fpos(x), KW_BREAK);
333 		break;
334   }
335   debug1(DSS, D, "BreakChange returning %s", EchoStyle(style));
336 } /* end BreakChange */
337 
338 
339 /*@::YUnitChange(), ZUnitChange()@********************************************/
340 /*                                                                           */
341 /*  YUnitChange(style, x)                                                    */
342 /*                                                                           */
343 /*  Change the current value of the y unit as indicated by object x.         */
344 /*                                                                           */
345 /*****************************************************************************/
346 
YUnitChange(STYLE * style,OBJECT x)347 void YUnitChange(STYLE *style, OBJECT x)
348 { GAP res_gap; unsigned gap_inc;
349   GetGap(x, style, &res_gap, &gap_inc);
350   if( units(res_gap) != FIXED_UNIT )
351     Error(11, 9, "this unit not allowed with %s symbol",
352       WARN, &fpos(x), KW_YUNIT);
353   else
354   { if( gap_inc == GAP_ABS ) yunit(*style) = width(res_gap);
355     else if( gap_inc == GAP_INC ) yunit(*style) += width(res_gap);
356     else yunit(*style) = find_max(yunit(*style) - width(res_gap), 0);
357   }
358 } /* end YUnitChange */
359 
360 
361 /*****************************************************************************/
362 /*                                                                           */
363 /*  ZUnitChange(style, x)                                                    */
364 /*                                                                           */
365 /*  Change the current value of the z unit as indicated by object x.         */
366 /*                                                                           */
367 /*****************************************************************************/
368 
ZUnitChange(STYLE * style,OBJECT x)369 void ZUnitChange(STYLE *style, OBJECT x)
370 { GAP res_gap; unsigned gap_inc;
371   GetGap(x, style, &res_gap, &gap_inc);
372   if( units(res_gap) != FIXED_UNIT )
373     Error(11, 10, "this unit not allowed with %s symbol",
374       WARN, &fpos(x), KW_ZUNIT);
375   else
376   { if( gap_inc == GAP_ABS ) zunit(*style) = width(res_gap);
377     else if( gap_inc == GAP_INC ) zunit(*style) += width(res_gap);
378     else zunit(*style) = find_max(zunit(*style) - width(res_gap), 0);
379   }
380 } /* end ZUnitChange */
381