<..handle char map mode..>
ch_map_flag = !ch_map_flag;
if( ch_map_flag ){ <.enter char map.> }
else { <.exit char map.> }
-_-_-
The character map is a sequence of lines that are dynamically allocated. Each character is represented by a pair (str,design), where str is a possible empty string and design is a character holding a value 0, 1, 2, or 3.
<..types..>+
struct ch_map_rec{
char* line;
int max, chars;
};
-_-_-
<..vars..>+
static struct ch_map_rec ch_map[HEIGHT];
static int max_map_line, min_map_line;
-_-_-
The following might be too high of a bound. The agreed def of html allows only 1024 characters in a map. However, with the permissible def of html, extra characters hopefully are ignored without causing problems. Also note that we probably going to have leading and trailing row that are not in use, and 120 line for a full page figure is not relly that big of a bound on the numer of lines per page.
<..defines..>+
#define HEIGHT 120
-_-_-
<..design bound..>
4-_-_-
The str is a string holding the text that belongs to the corresponding position: representation for the character, specials, etc. The design hold a drawing content corresponding to space, horizontal line, vertical line, and filled area, respectively. If the str is empty, the design is assumed to be the content of the character. If the string is not empty, it is assumed to be the content of the character.
The string holds character codes in the range of 32–255. Hence, we still have a room to get more sophisticated designs.
<..vars..>+
static BOOL ch_map_flag = FALSE;
-_-_-
<..defines..>+
#define NULL_MAP (struct map_line_type*) 0
-_-_-
<..enter char map..>
init_ch_map();
xresolution = yresolution = 0;
while( special_n-- > 0 ){
ch = get_char();
if( (ch >= ’0’) && (ch <= ’9’) )
{ yresolution = yresolution * 10 + ch - ’0’; }
else if( (ch == ’,’) && !xresolution && yresolution )
{ xresolution = yresolution; yresolution = 0; }
else { <.resolve boundary ch in maps.> }
}
if( !xresolution ) xresolution = yresolution;
if( !xresolution ){ xresolution = XRESOLUTION;
yresolution = YRESOLUTION; }
else { xresolution = xresolution * (INTEGER) (XRESOLUTION / 100);
yresolution = yresolution * (INTEGER) (YRESOLUTION / 100); }
-_-_-
Resolution can be an integer number or a pair of integer numbers separated by a comma. The first for x-resolution, the second for y-resolution. Then we can have a map for boundary characters made up of pairs: character to be replaced followed by replcment.
<..resolve boundary ch in maps..>
xresolution = yresolution = 0;
<.special resolution err.>
-_-_-
<..vars..>+
static INTEGER xresolution, yresolution;
-_-_-
<..defines..>+
#define XRESOLUTION MARGINSP
#ifdef LONG
#define YRESOLUTION 786432L
#else
#define YRESOLUTION 786432
#endif
-_-_-
<..header functions..>+
static void init_ch_map( ARG_I(void) );
-_-_-
<..functions..>+
static void init_ch_map(MYVOID)
{ int i;
for( i=0; i<HEIGHT; i++ ){
ch_map[i].max = 0; ch_map[i].chars = 0; ch_map[i].line = NULL; }
max_map_line = -1;
min_map_line = HEIGHT;
}
-_-_-
The 0.75 constant has been derived by trial and error by centering the nodes of ‘\TreeSpec(\SRectNode)()() \Tree()( 3,dog// 0,boxer & 0,cocker & 3, schnauzer // 0,miniature~~schauzer & 0,standard~~schnauzer & 0,giant~~schnauzer// )’.
<..insert ch to ch-map..>
insert_ch_map((char) ch, TRUE);
-_-_-
<..ch: 1, ruler: 0..>
tag-_-_-
<..header functions..>+
static void insert_ch_map( ARG_II(char,BOOL) );
-_-_-
<..functions..>+
static void insert_ch_map( ch, <.ch: 1, ruler: 0.> )
U_CHAR ch;
BOOL <.ch: 1, ruler: 0.>
;{ int row, col;
<.get row and col for ch.>
if(ch != 10){
if( (ch_map[row].max > MAX_MAP_LINE) || (col > MAX_MAP_LINE) ){
if( ok_map ){ warn_i_int_2( 25, MAX_MAP_LINE, ch);
ok_map = FALSE; }
}else{ <.adjust boundary ch.>
if( row < min_map_line ) min_map_line = row;
if( row > max_map_line ) max_map_line = row;
if( ch_map[row].max ){ <.insert char to nonempty map line.> }
else { <.insert char to empty map line.> }
} } }
-_-_-
Leave the following to the user responsibility of getting the char mappings rightly in the ‘.htf’ fonts.
<..vars..>+
static U_CHAR ok_map = TRUE;
-_-_-
<..get row and col for ch..>
{ double x;
row = (int) ( (y_val>0? y_val : 0.0) / (double) yresolution + 0.5);
if( row >= HEIGHT ){
if( ok_map ){ warn_i_int_2( 34, row, ch); ok_map = FALSE; }
return; }
x = (x_val>0? x_val : 0.0 ) / (double) xresolution + 0.75;
col = (int) x;
if( (ch > ’ ’) && (ch != ’-’) && (ch != ’|’) ){
if( row == prevrow ){
if( (col == prevcol + 1) && (x > prev_x + 0.5) )
insert_ch_map(’ ’, TRUE);
else if( (col > prevcol + 1) && (x < prev_x+0.2)
&& ( ch != ’&’ ))
col = prevcol + 1;
}else prevrow = -1;
prev_x = x
+ (<.(double) char_width( design_ch? design_ch : ch ).>)
/ (double) xresolution;
prevcol = col;
}else prevrow = -1;
prevrow = row;
}
-_-_-
The ‘( ch != ’&’ )’ above is to avoid breaking indirect unicode characters ‘&...;’ in character maps.
<..vars..>+
static int prevcol = -1, prevrow;
static double prev_x;
-_-_-
<..defines..>+
#define MAX_MAP_LINE 500
-_-_-
<..insert char to empty map line..>
int n;
char* p;
ch_map[row].chars = (n = (col + 2 + 5) / 5 * 5) - <.ch: 1, ruler: 0.>;
ch_map[row].max = n - 1;
ch_map[row].line = p = m_alloc(char, n);
while( n-- ){ *(p++) = 0; }
*(ch_map[row].line + col) = ch;
-_-_-
<..insert char to nonempty map line..>
int n;
char* p;
if( ch_map[row].chars > col ){
<.insert char within map line.> }
else{ <.insert char beyond end of map line.> }
-_-_-
Below: 8 = 1 (col starts at 0) + 2 (new ch=ch+bound) + 5 (rounding)
The rounding to 5 to (hopefully) help garbage collection.
<..insert char beyond end of map line..>
n = (col - ch_map[row].chars + 8) / 5 * 5;
ch_map[row].chars += n - <.ch: 1, ruler: 0.>;
ch_map[row].max += n;
ch_map[row].line = (char *)
r_alloc((void *) ch_map[row].line,
(size_t) ch_map[row].max + 1);
while( n-- ) *(ch_map[row].line + ch_map[row].max - n) = 0;
*(ch_map[row].line + ch_map[row].max
- (ch_map[row].chars - col) + !<.ch: 1, ruler: 0.> ) = ch;
-_-_-
<..insert char within map line..>
if( <.ch: 1, ruler: 0.> ){
if( *(ch_map[row].line + ch_map[row].max - 1)
|| (ch_map[row].chars - col == 1) ){ <.get room for ch.> }
col = (ch_map[row].chars--) - col;
p = ch_map[row].line + ch_map[row].max;
while( col ){ unsigned char temp_ch;
if( ((unsigned char) (*p)) < <.design bound.> ) col--;
temp_ch = *(--p); *(p+1) = temp_ch; }
} else {
col = ch_map[row].chars - col;
p = ch_map[row].line + ch_map[row].max;
while( col ){
if( ((unsigned char) (*p)) < <.design bound.> ) col--; p--; }
}
*(++p) = ch;
-_-_-
<..get room for ch..>
ch_map[row].max += 5;
ch_map[row].line = (char *)
r_alloc((void *) ch_map[row].line,
(size_t) ch_map[row].max + 1 );
for( n = 0; n<5; n++ )
*(ch_map[row].line + ch_map[row].max - n) = 0;
ch_map[row].chars += 5;
-_-_-
REMOVE FILTER!!!!!!
<..ruler into ch map..>
long int sv_x_val, sv_y_val, sv_right, sv;
int ch;
sv_x_val = x_val;
sv_y_val = y_val;
sv_right = right;
y_val-=up;
if( right < 0 ){ x_val += right; right = -right; }
if( up < 0 ){ y_val += up; up = -up; }
ch = ( (right > xresolution) && (up > yresolution) ) ?
<.black ch.> : ( ( right > up )? <.h ch.> : <.v ch.> );
right += x_val;
up += sv = y_val;
for( ; x_val < right; x_val += xresolution )
for( y_val = sv ; y_val < up; y_val += yresolution )
insert_ch_map((char) ch, FALSE);
x_val = sv_x_val;
y_val = sv_y_val;
if( sv_x_val + sv_right > max_x_val ) max_x_val = sv_x_val + sv_right;
if( <.ch: 1, ruler: 0.> ) x_val += sv_right;
-_-_-
<..exit char map..>
dump_ch_map();
-_-_-
We need memory of order 2 times the number of characters.
<..dump ch-map at end of page..>
if( ch_map_flag ){
warn_i(27); dump_ch_map(); init_ch_map(); }
-_-_-
‘dump_ch_map();’ creates overflow problems here.
<..header functions..>+
static void dump_ch_map( ARG_I(void) );
-_-_-
<..functions..>+
static void dump_ch_map(MYVOID)
{ int n, i, min, k, extra_sp;
U_CHAR *p;
struct map_line_type *q;
<.min := start of bounding box.>
for( i=min_map_line; i<=max_map_line; i++ ){
if( ( n = ch_map[i].max) > 0 ){
p = ch_map[i].line; k = min; extra_sp = 0;
<.ignore trailing spaces.>
while( 1 + n-- ){
if( --k < 0 ){
if( extra_sp && (((unsigned char) *p) < <.design bound.>)
&& (((unsigned char) *(p+1)) < <.design bound.>) )
{ extra_sp--;
} else { switch( *p ){ <.dump ch.> } }
}
p++;
}
free((void *) ch_map[i].line );
}
if( i<max_map_line ) put_char(’\n’);
}
nomargin = FALSE;
}
-_-_-
<..min := start of bounding box..>
{ int max;
min = 100; max = 0;
for( i=min_map_line; i<=max_map_line; i++ ){
p = ch_map[i].line;
n = ch_map[i].max; if( max < n ) max = n;
k = 0; while( n-- ){ if(*(p++)) break; k++; }
if( ch_map[i].max && (k < min) ) min = k; }
if( (max < 78) && !nomargin ) min = 0;
}
-_-_-
<..ignore trailing spaces..>
{ U_CHAR *s;
s = p + n;
while( n && !(*s) && !(*(s-1)) ){ n--; s--; }
if( n && !(*s) && (((unsigned char) *(s-1)) < <.design bound.>) ) n--;
}
-_-_-
<..dump ch..>
case 0: { put_char(’ ’); break; }
case <.h ch.>: { put_char(’-’); break; }
case <.v ch.>: { put_char(’|’); break; }
case <.black ch.>: { put_char(’#’); break; }
case ’ ’: { extra_sp++; }
default: { <.insert ch from map into file.> break; }
-_-_-
<..insert ch from map into file..>
BOOL tag;
INTEGER count;
tag = TRUE; count = 0;
do{ if( *p == ’<’ ) tag = FALSE;
else if( *p == ’>’ ) tag = TRUE;
else count += tag;
put_char( *p ); n--;
}while( ((unsigned char) *(++p)) >= <.design bound.> );
if( !count ){ n++; p--; }
-_-_-
COUNT the number of characters and issue a warning if over limit (1024 default).