1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690
|
/*@z38.c:Character Mappings:Declarations@*************************************/
/* */
/* THE LOUT DOCUMENT FORMATTING SYSTEM (VERSION 3.39) */
/* COPYRIGHT (C) 1991, 2008 Jeffrey H. Kingston */
/* */
/* Jeffrey H. Kingston (jeff@it.usyd.edu.au) */
/* School of Information Technologies */
/* The University of Sydney 2006 */
/* AUSTRALIA */
/* */
/* 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 3, 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., 59 Temple Place, Suite 330, Boston MA 02111-1307 USA */
/* */
/* FILE: z38.c */
/* MODULE: Character Mappings */
/* EXTERNS: MapLoad(), MapCharEncoding(), MapEncodingName(), */
/* MapPrintEncodings(), MapPrintResources(), MapSmallCaps() */
/* */
/*****************************************************************************/
#include "externs.h"
#define MAX_MAP 20 /* max number of lcm files */
/*****************************************************************************/
/* */
/* Should really be private but have been placed in externs because for */
/* efficiency they are used by z37.c and z34.c */
/* */
/* #define MAX_CHASH 353 */
/* #define MAP_UPPERCASE 0 */
/* #define MAP_LOWERCASE 1 */
/* #define MAP_UNACCENTED 2 */
/* #define MAP_ACCENT 3 */
/* #define MAPS 4 */
/* */
/* typedef struct mapvec { */
/* OBJECT file_name; */
/* FILE_NUM fnum; */
/* BOOLEAN seen_recoded; */
/* int last_page_printed; */
/* OBJECT name; */
/* OBJECT vector[MAX_CHARS]; */
/* FULL_CHAR hash_table[MAX_CHASH]; */
/* FULL_CHAR map[MAPS][MAX_CHARS]; */
/* } *MAP_VEC; */
/* */
/*****************************************************************************/
MAP_VEC MapTable[MAX_MAP]; /* the mappings */
static OBJECT notdef_word; /* notdef word */
static int maptop; /* first free slot in MapTable[] */
/* save 0 for "no mapping" */
/*****************************************************************************/
/* */
/* void MapInit(void) */
/* */
/* Initialize this module. */
/* */
/*****************************************************************************/
void MapInit(void)
{
notdef_word = nilobj;
maptop = 1;
}
/*****************************************************************************/
/* */
/* static int NameInsert(cname) */
/* static FULL_CHAR NameRetrieve(cname) */
/* */
/*****************************************************************************/
#define hash(str, pos) \
{ FULL_CHAR *p = str; \
for( pos = 2 * *p++; *p; pos += *p++); \
pos = pos % MAX_CHASH; \
}
static void NameInsert(FULL_CHAR *cname, int ccode, MAP_VEC map)
{ int pos;
hash(cname, pos);
while( map->hash_table[pos] != (FULL_CHAR) '\0' )
pos = (pos + 1) % MAX_CHASH;
map->vector[ccode] = MakeWord(WORD, cname, no_fpos);
map->hash_table[pos] = ccode;
} /* end NameInsert */
static FULL_CHAR NameRetrieve(FULL_CHAR *cname, MAP_VEC map)
{ int pos; FULL_CHAR ch;
hash(cname, pos);
while( (ch = map->hash_table[pos]) != (FULL_CHAR) '\0' )
{
if( StringEqual(string(map->vector[ch]), cname) )
return ch;
pos = (pos + 1) % MAX_CHASH;
}
return ch;
} /* end NameRetrieve */
/*@::MapLoad()@***************************************************************/
/* */
/* MAPPING MapLoad(file_name, recoded) */
/* */
/* Declare file_name to be a character mapping (LCM) file. A file may be */
/* so declared more than once. Parameter recoded is true if the font that */
/* uses this mapping declares that it needs to be recoded, which in turn */
/* means that this mapping might have to be printed out. Whether or not it */
/* is actually printed depends upon whether we print a font that uses it */
/* and that requires recoding. */
/* */
/*****************************************************************************/
MAPPING MapLoad(OBJECT file_name, BOOLEAN recoded)
{ FILE *fp; MAP_VEC map; MAPPING res;
int i, m, curr_line_num, line_pos, prev_code, dc, count;
unsigned int oc;
int status;
FULL_CHAR buff[MAX_BUFF], cn[MAX_BUFF], ch, mapname[MAX_BUFF],
mapval[MAX_BUFF];
debug2(DCM,D, "MapLoad(%s, %s)", EchoObject(file_name), bool(recoded));
/* if the file name is "-", it means no mapping file is supplied */
if( StringEqual(string(file_name), AsciiToFull("-")) )
{ debug1(DCM, D, "MapLoad returning 0 (file name is %s)",
string(file_name));
return (MAPPING) 0;
}
/* if seen this file name before, just update seen_recoded and return prev */
for( res = 1; res < maptop; res++ )
{
if( StringEqual(string(MapTable[res]->file_name), string(file_name)) )
{ Dispose(file_name);
MapTable[res]->seen_recoded = MapTable[res]->seen_recoded || recoded;
debug1(DCM, D, "MapLoad returning %d (not new)", res);
return res;
}
}
/* initialize PostScript name of all undefined characters */
if( notdef_word == nilobj )
notdef_word = MakeWord(WORD, AsciiToFull(".notdef"), no_fpos);
/* new, so allocate a new slot in MapTable for this new mapping */
if( maptop == MAX_MAP )
Error(38, 1, "too many character mappings", FATAL, &fpos(file_name));
ifdebug(DMA, D, DebugRegisterUsage(MEM_CMAPS, 1, sizeof(struct mapvec)));
MapTable[res = maptop++] = map = (MAP_VEC) malloc( sizeof(struct mapvec) );
if( map == (MAP_VEC) NULL )
Error(38, 2, "run out of memory when loading character mapping",
FATAL, &fpos(file_name));
/* initialize all the fields */
map->file_name = file_name;
debug0(DFS, D, " calling DefineFile from MapLoad");
map->fnum = DefineFile(string(file_name), STR_EMPTY, &fpos(file_name),
MAPPING_FILE, MAPPING_PATH);
fp = OpenFile(map->fnum, FALSE, FALSE);
if( fp == NULL ) Error(38, 3, "cannot open character mapping file %s",
FATAL, PosOfFile(map->fnum), FileName(map->fnum));
map->seen_recoded = recoded;
map->last_page_printed = 0;
StringCopy(buff, AsciiToFull("vec"));
StringCat(buff, StringInt(maptop));
map->name = MakeWord(WORD, buff, no_fpos);
for( m = 0; m < MAPS; m++ )
{ for( i = 0; i < MAX_CHARS; i++ )
map->map[m][i] = '\0';
}
/* unaccented map is defined to be self as default */
for( i = 0; i < MAX_CHARS; i++ )
map->map[MAP_UNACCENTED][i] = i;
for( i = 0; i < MAX_CHARS; i++ ) map->vector[i] = notdef_word;
for( i = 0; i < MAX_CHASH; i++ ) map->hash_table[i] = 0;
/* first pass through the file; read character codes and names only */
prev_code = -1; curr_line_num = 0;
while( (status = ReadOneLine(fp, buff, MAX_BUFF)) != 0 )
{
/* skip comment lines and blank lines */
curr_line_num++;
for( i = 0; buff[i] == ' ' || buff[i] == '\t'; i++ );
if( buff[i] == '#' || buff[i] == '\0' ) continue;
/* parse line and check validity of decimal and octal character codes */
count = sscanf( (char *) buff, "%d %o %s", &dc, &oc, cn);
if( count < 2 )
Error(38, 4, "character code(s) missing in mapping file (line %d)",
FATAL, &fpos(file_name), curr_line_num);
if( dc != oc )
Error(38, 5, "decimal and octal codes disagree in mapping file (line %d)",
FATAL, &fpos(file_name), curr_line_num);
if( dc < 1 && !StringEqual(cn, STR_NOCHAR) )
Error(38, 6, "code %d too small (min is 1) in mapping file (line %d)",
FATAL, &fpos(file_name), dc, curr_line_num);
if( dc < prev_code )
Error(38, 7, "code %d out of order in mapping file (line %d)",
FATAL, &fpos(file_name), dc, curr_line_num);
if( dc == prev_code )
Error(38, 8, "code %d repeated in mapping file (line %d)",
FATAL, &fpos(file_name), dc, curr_line_num);
if( dc > MAX_CHARS )
Error(38, 9, "code %d too large (max is %d) in mapping file (line %d)",
FATAL, &fpos(file_name), dc, MAX_CHARS, curr_line_num);
prev_code = dc;
/* insert character name, if any */
debug2(DCM, DD, " line %d: %s", curr_line_num, cn);
if( count >= 3 && !StringEqual(cn, STR_NOCHAR) )
{
/* insert (cn, dc) pair into hash table; name may be repeated */
if( (ch = NameRetrieve(cn, map)) != 0 )
map->vector[dc] = map->vector[ch];
else
NameInsert(cn, dc, map);
}
}
/* second pass through the file: read mappings */
rewind(fp);
curr_line_num = 0;
while( (status = ReadOneLine(fp, buff, MAX_BUFF)) != 0 )
{
/* skip comment lines and blank lines */
curr_line_num++;
for( i = 0; buff[i] == ' ' || buff[i] == '\t'; i++ );
if( buff[i] == '#' || buff[i] == '\0' ) continue;
/* parse line */
count = sscanf( (char *) buff, "%d %o %s%n", &dc, &oc, cn, &line_pos);
/* find and insert the maps */
while( sscanf( (char *) &buff[line_pos], "%s %[^;];%n",
mapname, mapval, &i) == 2 )
{
debug3(DCM, DD, " line %d: %s %s", curr_line_num, mapname, mapval);
line_pos += i;
if( StringEqual(mapname, AsciiToFull("UC")) )
m = MAP_UPPERCASE;
else if( StringEqual(mapname, AsciiToFull("LC")) )
m = MAP_LOWERCASE;
else if( StringEqual(mapname, AsciiToFull("UA")) )
m = MAP_UNACCENTED;
else if( StringEqual(mapname, AsciiToFull("AC")) )
m = MAP_ACCENT;
else
Error(38, 10, "unknown mapping name %s in mapping file %s (line %d)",
FATAL, &fpos(file_name), mapname, FileName(map->fnum), curr_line_num);
ch = NameRetrieve(mapval, map);
if( ch == (FULL_CHAR) '\0' )
Error(38, 11, "unknown character %s in mapping file %s (line %d)",
FATAL, &fpos(file_name), mapval, FileName(map->fnum), curr_line_num);
map->map[m][dc] = ch;
}
}
fclose(fp);
debug1(DCM, D, "MapLoad returning %d (new mapping)", res);
return res;
} /* end MapLoad */
/*@::MapCharEncoding(), MapEncodingName(), MapPrintEncodings()@***************/
/* */
/* FULL_CHAR MapCharEncoding(str, map) */
/* */
/* Returns the character code corresponding to character name str in */
/* MAPPING enc, or 0 if not found. */
/* */
/*****************************************************************************/
FULL_CHAR MapCharEncoding(FULL_CHAR *str, MAPPING m)
{ MAP_VEC map;
map = MapTable[m];
return (FULL_CHAR) NameRetrieve(str, map);
} /* end MapCharEncoding */
/*****************************************************************************/
/* */
/* FULL_CHAR *MapEncodingName(m) */
/* */
/* Returns the PostScript name of the encoding vector of mapping m */
/* */
/*****************************************************************************/
FULL_CHAR *MapEncodingName(MAPPING m)
{ assert( m < maptop, "MapEncodingName: m out of range!" );
return string(MapTable[m]->name);
} /* end MapEncodingName */
/*****************************************************************************/
/* */
/* void MapEnsurePrinted(MAPPING m, int curr_page) */
/* */
/* Ensure that MAPPING m is printed on page curr_page, if required. */
/* It's required if it has neither been printed on the current page */
/* already, nor on page 1 (page 1 is really the entire document setup). */
/* */
/*****************************************************************************/
void MapEnsurePrinted(MAPPING m, int curr_page)
{ MAP_VEC map = MapTable[m];
assert( map->seen_recoded, "MapEnsurePrinted: not seen_recoded!" );
if( map->last_page_printed < curr_page && map->last_page_printed != 1 )
{ map->last_page_printed = curr_page;
BackEnd->PrintMapping(m);
}
}
/*****************************************************************************/
/* */
/* MapPrintEncodings() */
/* */
/* Print all encoding vectors in existence so far; this counts as printing */
/* them on "page 1", but in fact they will appear in the document setup */
/* section. */
/* */
/*****************************************************************************/
void MapPrintEncodings()
{ MAPPING m; MAP_VEC map;
for( m = 1; m < maptop; m++ )
{ if( MapTable[m]->seen_recoded )
{ BackEnd->PrintMapping(m);
map = MapTable[m];
map->last_page_printed = 1;
}
}
} /* end MapPrintEncodings */
/*****************************************************************************/
/* */
/* MapPrintPSResources(fp) */
/* */
/* Print PostScript resource entries for all encoding vectors on file fp. */
/* */
/*****************************************************************************/
void MapPrintPSResources(FILE *fp)
{ MAPPING m; MAP_VEC map;
for( m = 1; m < maptop; m++ ) if( MapTable[m]->seen_recoded )
{ map = MapTable[m];
fprintf(fp, "%%%%+ encoding %s%s", string(map->name), (char *) STR_NEWLINE);
}
} /* end MapPrintPSResources */
/*@@**************************************************************************/
/* */
/* OBJECT DoWord(buff, q, x, fnum) */
/* */
/* Replace WORD or QWORD x by a small caps version, based on word_font(x). */
/* */
/*****************************************************************************/
static OBJECT DoWord(FULL_CHAR *buff, FULL_CHAR *q, OBJECT x, FONT_NUM fnum)
{ OBJECT res;
*q++ = '\0';
res = MakeWord(type(x), buff, &fpos(x));
word_font(res) = fnum;
word_colour(res) = word_colour(x);
word_underline_colour(res) = word_underline_colour(x);
word_texture(res) = word_texture(x);
word_outline(res) = word_outline(x);
word_language(res) = word_language(x);
word_baselinemark(res) = word_baselinemark(x);
word_strut(res) = word_strut(x);
word_ligatures(res) = word_ligatures(x);
word_hyph(res) = word_hyph(x);
underline(res) = UNDER_OFF;
return res;
} /* end DoWord */
/*****************************************************************************/
/* */
/* OBJECT DoVShift(x, vshift, chld) */
/* */
/* Make an new VSHIFT object with the given shift and child. */
/* */
/*****************************************************************************/
static OBJECT DoVShift(OBJECT x, FULL_LENGTH vshift, OBJECT chld)
{ OBJECT res;
New(res, VSHIFT);
FposCopy(fpos(res), fpos(x));
shift_type(res) = GAP_DEC;
units(shift_gap(res)) = FIXED_UNIT;
mode(shift_gap(res)) = EDGE_MODE;
width(shift_gap(res)) = vshift;
underline(res) = UNDER_OFF;
Link(res, chld);
return res;
}
/*****************************************************************************/
/* */
/* void DoAddGap(new_acat) */
/* */
/* Add a new 0i gap object to new_acat. */
/* */
/*****************************************************************************/
static void DoAddGap(OBJECT new_acat)
{ OBJECT new_g;
New(new_g, GAP_OBJ);
FposCopy(fpos(new_g), fpos(new_acat));
hspace(new_g) = vspace(new_g) = 0;
SetGap(gap(new_g), TRUE, FALSE, TRUE, FIXED_UNIT, EDGE_MODE, 0*IN);
underline(new_g) = UNDER_OFF;
Link(new_acat, new_g);
}
/*@::MapSmallCaps()@**********************************************************/
/* */
/* OBJECT MapSmallCaps(x, style) */
/* */
/* Replace WORD or QWORD x by a small caps version, based on word_font(x). */
/* */
/*****************************************************************************/
#define INIT 0
#define ALL_NON 1
#define ALL_TRANS 2
#define MIXED_NON 3
#define MIXED_TRANS 4
#define transformable(ch) (uc[ch] != '\0')
/* basically temporaries but remembered from call to call for recycling */
static OBJECT font_change_word = nilobj;
static FULL_LENGTH font_change_length = 0;
OBJECT MapSmallCaps(OBJECT x, STYLE *style)
{ MAPPING m; int i; OBJECT new_y, new_x = nilobj, new_acat = nilobj, tmp;
FULL_CHAR buff[MAX_BUFF], *uc, *p, *q;
FONT_NUM small_font = 0; FULL_LENGTH vshift = 0; int state; STYLE new_style;
assert( is_word(type(x)), "MapSmallCaps: !is_word(type(x))" );
debug2(DCM, D, "MapSmallCaps(%s %s)", Image(type(x)), string(x));
/* get the mapping and return if there isn't one for this font */
m = FontMapping(word_font(x), &fpos(x));
if( m == 0 )
{ debug0(DCM, D, "MapSmallCaps returning unchanged (mapping is 0)");
return x;
}
assert( 1 <= m && m < maptop, "MapSmallCaps: mapping out of range!" );
uc = MapTable[m]->map[MAP_UPPERCASE];
/* if plain text, apply the mapping and exit */
if( !(BackEnd->scale_avail) )
{
for( i = 0; string(x)[i] != '\0'; i++ )
if( uc[string(x)[i]] != '\0' )
string(x)[i] = uc[string(x)[i]];
debug1(DCM, D, "MapSmallCaps returning (plain text) %s", EchoObject(x));
return x;
}
/* make sure the small caps size is a reasonable one */
if( smallcaps_len(*style) <= 0 )
Error(38, 12, "small caps size is zero or negative", FATAL, &fpos(x));
/* set up the font change word if not already done */
if( font_change_length != smallcaps_len(*style) )
{ char tmp[100];
font_change_length = smallcaps_len(*style);
sprintf(tmp, "%.2ff", (float) font_change_length / FR);
font_change_word = MakeWord(WORD, AsciiToFull(tmp), no_fpos);
}
state = INIT; q = buff;
for( p = string(x); *p != '\0'; p++ )
{
debug2(DCM, DD, " examining %c (%s)", *p,
transformable(*p) ? "transformable" : "not transformable");
switch( state )
{
case INIT:
/* this state is for when we are at the first character */
if( transformable(*p) )
{ *q++ = uc[*p];
/* work out what the smaller font is going to be, and the vshift */
StyleCopy(new_style, *style);
FontChange(&new_style, font_change_word);
small_font = font(new_style);
vshift = word_baselinemark(x) ? 0 :
(FontHalfXHeight(word_font(x)) - FontHalfXHeight(small_font));
state = ALL_TRANS;
}
else
{ *q++ = *p;
state = ALL_NON;
}
break;
case ALL_NON:
/* in this state, all characters so far are non-transformable */
if( transformable(*p) )
{
/* work out what the smaller font is going to be */
StyleCopy(new_style, *style);
FontChange(&new_style, font_change_word);
small_font = font(new_style);
vshift = word_baselinemark(x) ? 0 :
(FontHalfXHeight(word_font(x)) - FontHalfXHeight(small_font));
/* make a new WORD out of the current contents of buff */
new_y = DoWord(buff, q, x, word_font(x));
/* construct the skeleton of the result to replace x */
New(new_x, ONE_COL);
FposCopy(fpos(new_x), fpos(x));
New(new_acat, ACAT);
FposCopy(fpos(new_acat), fpos(x));
Link(new_x, new_acat);
Link(new_acat, new_y);
DoAddGap(new_acat);
/* start off a new buffer with *p */
q = buff;
*q++ = uc[*p];
state = MIXED_TRANS;
}
else *q++ = *p;
break;
case ALL_TRANS:
/* in this state, all characters so far are transformable */
if( transformable(*p) ) *q++ = uc[*p];
else
{
/* make a new @VShift WORD out of the current contents of buff */
tmp = DoWord(buff, q, x, small_font);
new_y = DoVShift(x, vshift, tmp);
/* construct the skeleton of the result to replace x */
New(new_x, ONE_COL);
FposCopy(fpos(new_x), fpos(x));
New(new_acat, ACAT);
FposCopy(fpos(new_acat), fpos(x));
Link(new_x, new_acat);
Link(new_acat, new_y);
DoAddGap(new_acat);
/* start off a new buffer with *p */
q = buff;
*q++ = *p;
state = MIXED_NON;
}
break;
case MIXED_NON:
/* in this state the previous char was non-transformable, but */
/* there have been characters before that that were transformable */
if( transformable(*p) )
{
/* make a new WORD out of the current contents of buff */
new_y = DoWord(buff, q, x, word_font(x));
/* link the new word into the growing structure that replaces x */
Link(new_acat, new_y);
DoAddGap(new_acat);
/* start off a new buffer with *p */
q = buff;
*q++ = uc[*p];
state = MIXED_TRANS;
}
else *q++ = *p;
break;
case MIXED_TRANS:
/* in this state the previous char was transformable, but there */
/* have been characters before that that were non-transformable */
if( transformable(*p) ) *q++ = uc[*p];
else
{
/* make a new @VShift WORD out of the current contents of buff */
tmp = DoWord(buff, q, x, small_font);
new_y = DoVShift(x, vshift, tmp);
/* link the new word into the growing structure that replaces x */
Link(new_acat, new_y);
DoAddGap(new_acat);
/* start off a new buffer with *p */
q = buff;
*q++ = *p;
state = MIXED_NON;
}
break;
}
}
/* now at termination, clean up the structure */
switch( state )
{
case INIT:
case ALL_NON:
/* original x is OK as is: either empty or all non-transformable */
break;
case ALL_TRANS:
/* make a new @VShift WORD and replace x with it */
tmp = DoWord(buff, q, x, small_font);
new_x = DoVShift(x, vshift, tmp);
ReplaceNode(new_x, x);
Dispose(x);
x = new_x;
break;
case MIXED_NON:
/* make a new WORD, add to new_acat, and replace x */
new_y = DoWord(buff, q, x, word_font(x));
Link(new_acat, new_y);
ReplaceNode(new_x, x);
Dispose(x);
x = new_x;
break;
case MIXED_TRANS:
/* make a new @VShift WORD, add to new_acat, and replace x */
tmp = DoWord(buff, q, x, small_font);
new_y = DoVShift(x, vshift, tmp);
Link(new_acat, new_y);
ReplaceNode(new_x, x);
Dispose(x);
x = new_x;
break;
}
debug1(DCM, D, "MapSmallCaps returning %s", EchoObject(x));
return x;
} /* end MapSmallCaps */
/*****************************************************************************/
/* */
/* BOOLEAN MapIsLowerCase(FULL_CHAR ch, MAPPING m) */
/* */
/* Returns TRUE if ch is a lower-case character in mapping m; i.e. if it */
/* has a corresponding upper-case character. */
/* */
/*****************************************************************************/
BOOLEAN MapIsLowerCase(FULL_CHAR ch, MAPPING m)
{ BOOLEAN res;
debug2(DCM, D, "MapIsLowerCase(%c, %d)", ch, m);
res = (MapTable[m]->map[MAP_UPPERCASE][ch] != '\0');
debug1(DCM, D, "MapIsLowerCase returning %s", bool(res));
return res;
} /* end MapIsLowerCase */
|