<..process the specials..>
long int special_n;
<.end text accent.>
if( tex4ht_special( &ch, &special_n) ) { int sv; sv = ch;
special_on = TRUE; <.process tex4ht special.> special_on = FALSE;
<.check for extra special chars.>
} else { <.non-t4ht special.> }
-_-_-
<..non-t4ht special..>
while( special_n-- ) (void) get_char();
-_-_-
<..header functions..>+
static BOOL tex4ht_special( ARG_II( int*, long int*) );
-_-_-
<..functions..>+
static BOOL tex4ht_special( chr, special_n)
int *chr;
long int *special_n
;{ BOOL tex4ht;
int i;
long unsigned N;
tex4ht = FALSE;
<.get special length.>
if( *special_n > (long int) 4 ){
for(i=4; i<9; i++) special_hd[i]=get_char();
special_hd[9]=’\0’;
<.t4ht special?.>
*chr = special_hd[8];
tex4ht = tex4ht && ( (*chr == ’=’) || (*chr == ’<’) ||
(*chr == ’>’) || (*chr == ’*’) || (*chr == ’@’) ||
(*chr == ’:’) || (*chr == ’"’) || (*chr == ’~’) ||
(*chr == ’;’) || (*chr == ’.’) || (*chr == ’^’) ||
(*chr == ’|’) || (*chr == ’+’) || (*chr == ’!’) );
*special_n -= 5; }
else{ special_hd[4]=’\0’; }
return tex4ht;
}
-_-_-
We want to allow both for ‘\special{t4ht...}’ and ‘\special{T4HT...}’, for cases that the \special is within \uppercase (e.g., ‘ \def~{\special{t4ht=+}} \edef\x{\uppercase{a~b}}\x \uppercase{a~b}’). We end up with all combinations of upper and lower case. ELIMINTE/HANDLE also all possible \special’s with letters after the first four!!!!!!!!!
<..t4ht special?..>
tex4ht = (special_hd[4] == ’t’) || (special_hd[4] == ’T’);
tex4ht = tex4ht && special_hd[5] == ’4’;
tex4ht = tex4ht && ((special_hd[6] == ’h’) || (special_hd[6] == ’H’));
tex4ht = tex4ht && ((special_hd[7] == ’t’) || (special_hd[7] == ’T’));
if( tex4ht && trace_special ){
<.trace specials.>
}
-_-_-
<..get special length..>
*special_n = (long int) (N = get_unt(*chr - <.special 1.> + 1));
for(i=4; i--; ){
special_hd[i] = (unsigned char) (N & 0xFF);
N = N >> 8; }
-_-_-
<..vars..>+
static U_CHAR special_hd[10];
-_-_-
<..process tex4ht special..>
try_new_line();
switch( ch ){
case ’*’: { <.other specials.> break; }
case ’@’: { <.insert char code.> break; }
case ’+’: { <.ivd code in main pass.> break; }
case ’=’: { <.insert verbatim record.> break; }
case ’<’:
case ’>’: { <.redirect html output.> break; }
case ’!’: { <.handle char map mode.> break; }
case ’|’: { gif_ch = !gif_ch; break; }
case ’:’: { <.arithmetics within specials.> break; }
case ’;’: { <.css for characters.> break; }
case ’"’: { <.positioned content.> break; }
case ’~’: { <.grouped-base delivery content.> break; }
case ’.’: { <.change ext of root file.> break; }
case ’^’: { <.classes for math symbols.> break; }
}
-_-_-
The handle requests ... is used for deciding which dvi code should be extracted for gif pictures.
[more]
<..insert verbatim record..>
while( special_n-- > 0 ){
int ch;
BOOL flag;
struct hcode_repl_typ *q;
ch = get_char();
q = hcode_repl;
flag = FALSE;
while( q != (struct hcode_repl_typ*) 0 ){
if( ch == *(q->str) ){ flag = TRUE; break; }
q = q->next;
}
if( flag ){
char *chr;
chr = (q->str) + 1;
while( *chr != 0 ){ put_char( *chr ); chr++; }
} else { put_char( ch ); }
}
-_-_-
<..configure hcode..>
char *str, *repl;
struct hcode_repl_typ *p, *q;
BOOL flag;
if( special_n ){
repl = str = m_alloc(char, (int) special_n + 1);
while( special_n-- > 0 ){
*str = get_char(); str++;
}
*str = 0;
<.delete old hcode pattern.>
<.add new hcode pattern.>
} else {
<.delete all hcode patterns.>
}
-_-_-
<..delete all hcode patterns..>
while( hcode_repl != (struct hcode_repl_typ*) 0 ){
p = hcode_repl;
hcode_repl = hcode_repl->next;
free((void *) p->str);
free((void *) p);
}
-_-_-
<..delete old hcode pattern..>
if( hcode_repl != (struct hcode_repl_typ*) 0 ){
if( *(hcode_repl->str) == *repl ){
p = hcode_repl;
hcode_repl = hcode_repl->next;
free((void *) p->str);
free((void *) p);
} else {
p = hcode_repl;
while( TRUE ){
q = p->next;
if( q == (struct hcode_repl_typ*) 0 ){ break; }
if( *(q->str) == *repl ){
p->next = q->next;
free((void *) q->str);
free((void *) q);
break;
}
p = q;
} } }
-_-_-
<..add new hcode pattern..>
flag = *repl != *(repl+1);
if( !flag ){ flag = *(repl+2) != 0; }
if( flag ){
p = (struct hcode_repl_typ *) m_alloc(struct hcode_repl_typ, 1);
p->str = repl;
p->next = hcode_repl;
hcode_repl = p;
}
-_-_-
<..types..>
struct hcode_repl_typ { char *str;
struct hcode_repl_typ *next; };
-_-_-
<..vars..>+
static struct hcode_repl_typ *hcode_repl
= (struct hcode_repl_typ*) 0;
-_-_-
‘\special{t4ht@i}’ inserts the character code i, if i is negative. If i is positive, the font info is sent as a replacement to the next chracter code (allowing to use that letter character font info for decoration).
The following is ignored within char maps, so we don’t have to worry about the bound of ‘\<design bound\>’.
<..insert char code..>
int code, digit;
special_n--;
switch ( code = get_char() ){
case ’%’: { <.dvi trace.> break; }
case ’@’: { verb_ch = !verb_ch; break; }
case ’/’: { <.on/off special trace.> break; }
case ’e’: { <.get err str.> break; }
case ’!’: { <.recover ignored space.> break; }
case ’(’: { <.ignore spaces.> break; }
case ’)’: { <.end ignore spaces.> break; }
case ’[’: { <.ignore chs.> break; }
case ’]’: { <.end ignore chs.> break; }
case ’?’: { <.cond ignore chs.> break; }
case ’-’: {
if( special_n ) { code = 0; <.code := ....>
put_char( code );
} else { nomargin = TRUE; }
break; }
case ’*’: { <.send string to after next ch.> }
case ’+’: { <.send string to next ch.> break; }
case ’.’: { <.get eoln str.> break; }
case ’,’: { <.get space str.> break; }
case ’_’: { <.ruler ch.> break; }
case ’D’: { <.write to lg file with loc stamp.> break; }
case ’u’: { <.on/off unicode.> break; }
default: { <.send ch to next ch.> }
}
-_-_-
<..vars..>+
static BOOL nomargin = FALSE;
static int next_char = -1;
static U_CHAR *next_str = (char *) 0;
-_-_-
<..defines..>+
#define IGNORED void
-_-_-
<..code := .....>
while( special_n-- > 0 ){
digit = get_char() - ’0’;
if ( (digit < 0) || (digit > 9) ) { warn_i_int(41,digit+’0’) ; }
else { code = code * 10 + digit; }
}
if ( (code < 0) || (code > 255) ) { code = ’?’; warn_i_int(41,’?’) ; }
-_-_-
<..send ch to next ch..>
code -= ’0’; <.code := ....> next_char = code;
if( <.next-str.> ){ print_f(next_str);
free((void *) next_str); next_str = (char *) 0; }
-_-_-
Before reading a tring to be submitted forward, we look for a previous submission. If such exists, we dump it.
<..send string to next ch..>
if( <.next-char.> != -1 ) {
<.open output file.>
(IGNORED) put_4ht_ch( <.next-char.> , cur_o_file );
<.next-char.> = -1;
}
if( <.next-str.> ){ print_f(next_str);
free((void *) next_str); next_str = (char *) 0; }
next_str = get_str( (int) special_n ); special_n = 0;
<.set indirect ch codes.>
-_-_-
Indirect characters are expressed by character codes enclosed within braces. For instance, ‘\special{t4ht@+\string&{35}x0142;}x’.
<..set indirect ch codes..>
{ char *front, *back;
int i;
back = front = next_str;
while( *front != ’\0’ ){
if( *front == ’{’ ){
i = *(++front) - ’0’;
while( *(++front) != ’}’ ){ i = i*10 + (*front - ’0’); }
*front = (char) i;
}
*(back++) = *(front++);
}
*back = ’\0’;
}
-_-_-
<..next-char..>
next_char
-_-_-
<..send string to after next ch..>
keepChar=1;
-_-_-
<..current char for forwarded string..>
if( keepChar ){
keepChar=FALSE;
{ <.insert font char.> }
}
-_-_-
<..vars..>+
static BOOL keepChar = FALSE;
-_-_-
Whenever a new file is opened (\special{t4ht>...}), its record is placed on the top of a stack list. Whenever it is closed (\special{t4ht<...}), the record is removed from the stack, and the file at the top of the stack get opened. A reopening of a file doesn’t affect the stack.
The top of the stack is pointed by ‘opened_files’, the next file with ‘next’, and the backward with ‘prev’. Each record also holds a ‘from_file’ pointer telling from where the file was last opened.
One can ask for a return to the file that activated the current file with the command \special{t4ht*>}, and to send the record to the bottom of the stack with \special{t4ht*>file-name}.
<..redirect html output..>
<.name = file name.>
<.open output file.>
<.p = pointer to file record.>
if( ch == ’>’ ){ <.open tex4ht file.> }
else { <.close tex4ht file.> }
cur_o_file = ( out_file == (FILE *) 0 )? root_file
: out_file;
-_-_-
<..retreat file..>
if( special_n > 0 ){
<.send file record to bottom.>
} else {
<.back up to previous output file.>
}
-_-_-
<..open tex4ht file..>
if( p != (struct files_rec*) 0 ){
out_file = p->file;
p->prev_file = cur_o_file;
free((void *) name );
} else {
if( !(*name) ) out_file = (FILE *) 0;
else { <.open non-root tex4ht file.> }
}
-_-_-
<..open non-root tex4ht file..>
p = m_alloc(struct files_rec, 1);
if( opened_files != (struct files_rec*) 0 ) opened_files->prev = p;
p->prev = (struct files_rec *) 0;
p->next = opened_files; opened_files = p;
p->name = name;
p->file = out_file = open_html_file(name);
p->prev_file = cur_o_file;
-_-_-
<..close tex4ht file..>
if( p == (struct files_rec *) 0 ) bad_special( name );
<.fix pointers around file to be closed.>
if( opened_files != (struct files_rec*) 0 )
{ if( out_file == p->file ) out_file = opened_files->file; }
else out_file = (FILE *) 0;
(IGNORED) fclose( p->file ); free((void *) p->name );
free((void *) p );
-_-_-
<..fix pointers around file to be closed..>
if( p->prev != (struct files_rec*) 0 ) (p->prev)->next = p->next;
else opened_files = p->next;
if( p->next != (struct files_rec*) 0 ) (p->next)->prev = p->prev;
-_-_-
<..close active output files..>
while( opened_files != (struct files_rec*) 0 )
{
(IGNORED) fclose( opened_files->file );
opened_files = opened_files->next;
}
-_-_-
<..back up to previous output file..>
<.find record of cur output file.>
-_-_-
<..find record of cur output file..>
static struct files_rec *p, *q;
for( p = opened_files; p != (struct files_rec*) 0; p = p->next ){
if( (p->file == cur_o_file) && p->prev_file ){
<.error if prev file is closed.>
cur_o_file = p->prev_file;
p->prev_file = (FILE *) 0;
break;
}
}
-_-_-
<..error if prev file is closed..>
for( q = opened_files; q != (struct files_rec*) 0; q = q->next ){
if( q->file == p->prev_file ){
break;
}
}
if( q == (struct files_rec*) 0 ){
warn_i_str(51,q->name);
break;
}
-_-_-
<..send file record to bottom..>
static struct files_rec *p, *q;
U_CHAR name[256];
int i;
<.find file record.>
if( p != (struct files_rec*) 0 ){
<.move the file record.>
}
-_-_-
<..find file record..>
i = 0;
name[(int) special_n] = ’\0’;
while( special_n-- > 0 ){ name[i++] = get_char(); }
for( p = opened_files; p != (struct files_rec*) 0; p = p->next ){
if( eq_str(p->name, name) ){ break; }
}
-_-_-
<..move the file record..>
for( q = p; q->next != (struct files_rec*) 0; q = q->next ){ }
if( q != p ){
q->next = p;
(p->next)->prev = p->prev;
if( opened_files == p ){ opened_files = p->next; }
else { (p->prev)->next = p->next; }
p->prev = q;
p->next = (struct files_rec*) 0;
}
-_-_-
<..name = file name..>
int i=0;
U_CHAR *name;
name = m_alloc(char, (int) special_n+1);
*(name + (int) special_n) = ’\0’;
while( special_n-- > 0 ) *(name + i++) = get_char();
-_-_-
<..p = pointer to file record..>
for( p = opened_files; p != (struct files_rec*) 0; p = p->next )
{ if( eq_str(p->name, name) ) break; }
-_-_-
<..vars..>+
static struct files_rec
*opened_files = (struct files_rec *) 0, *p;
-_-_-
<..defines..>+
struct files_rec{
FILE *file, *prev_file;
char* name;
struct files_rec *next, *prev;
};
-_-_-
<..other specials..>
if( special_n ){
special_n--;
switch ( get_char() ){
case ’<’: { <.import file.> break; }
case ’>’: { <.retreat file.> break; }
case ’!’: { <.system call.> break; }
case ’^’: { <.accent specials.> break; }
case ’@’: { <.halign specials.> break; }
case ’=’: { <.configure hcode.> break; }
default: { <.consume unused specials.> }
}
} else { <.unused special.> }
-_-_-
The library ‘<stdlib.h>’ includes a function ‘int system(const char *cmdstring);’. When cmdstring is NULL, the return value is 0 iff the platform does not support system calls.
mathml.4ht-9-22: \special{t4ht*!perl m2webeq > tmpa.tmp}%
<..system call..>
U_CHAR name[256], ch;
int i=0, n;
struct sys_call_rec *p;
BOOL flag;
name[(int) special_n] = ’\0’;
while( special_n-- > 0 ){ name[i++] = get_char(); }
(IGNORED) printf("System call: %s\n", name);
<.flag = permission for system calls.>
if( flag ){
(IGNORED) printf("System return: %d\n",
system_yes? (int) system(name) : -1 );
} else { (IGNORED) printf("No permission for system call\n"); }
-_-_-
<..get from tex4ht.env file..>
(IGNORED) fseek(dot_file, 0L, <.abs file addr.>);
while ( search_dot_file( ’P’ ) ){ struct sys_call_rec *q;
U_CHAR *p, str[256];
q = m_alloc(struct sys_call_rec, 1);
q->next = system_calls;
system_calls = q;
p = str;
do
*(p++) = ch = (int) getc(dot_file);
while( (ch !=’\n’) && (ch != EOF) );
p--;
*p = ’\0’;
q->filter = m_alloc(char, (int) strlen((char *) str)+1);
(IGNORED) strcpy((char *) q->filter, (char *) str);
}
-_-_-
<..permission for system calls..>
{ struct sys_call_rec *q;
q = m_alloc(struct sys_call_rec, 1);
q->next = system_calls;
q->filter = p + 2;
system_calls = q;
}
-_-_-
<..flag = permission for system calls..>
flag = FALSE;
p = system_calls;
while( p ){
if( (n = (int) strlen((char *) p->filter)) == 1 ) {
flag = flag || (*(p->filter) == ’*’);
} if( strlen((char *) name) >= (unsigned int) n ) {
ch = name[n]; name[n] = ’\0’;
flag = flag || eq_str(p->filter,name);
name[n] = ch;
}
p = p->next;
}
-_-_-
<..defines..>+
struct sys_call_rec{
char* filter;
struct sys_call_rec *next;
};
-_-_-
<..vars..>+
static BOOL system_yes;
static struct sys_call_rec *system_calls = (struct sys_call_rec *) 0;
-_-_-
<..main’s init..>+
{ U_CHAR *yes = NULL;
system_yes = (system( yes ) != 0);
}
-_-_-
<..import file..>
U_CHAR name[256];
int i=0;
FILE* file;
name[(int) special_n] = ’\0’;
while( special_n-- > 0 ){ name[i++] = get_char(); }
file = f_open(name, READ_TEXT_FLAGS);
if( file ) {
<.open output file.>
while( (ch = getc(file)) >=0 ){
(IGNORED) put_4ht_ch(ch,cur_o_file);
}
(IGNORED) fclose(file);
} else { warn_i_str( 1, name ); }
-_-_-
<..arithmetics within specials..>
if( special_n-- ){
int code, n;
U_CHAR str [255], *p;
struct count_rec *q;
code = get_char();
while( special_n > 254 ){ (void) get_char(); special_n--; }
p = str; n = special_n;
while( special_n-- ) { *(p++) = get_char(); }
*p = ’\0’;
<.search counter.>
<.act on counter.>
}
-_-_-
<..types..>+
struct count_rec{
char* str;
int i, depth, max;
int* stack;
struct count_rec* next;
};
-_-_-
<..vars..>+
static struct count_rec *counter = (struct count_rec *) 0;
-_-_-
<..search counter..>
q = counter;
while( q ){
if( eq_str(str,q->str) ) break; q = q->next;
}
if( !q ){
q = m_alloc(struct count_rec, 1);
q->i = q->depth = 0; q->max = 10;
q->next = counter; counter = q;
q->str = m_alloc(char, (int) n+1);
(IGNORED) strcpy((char *) q->str, (char *) str );
q->stack = m_alloc(int, q->max);
}
-_-_-
<..push counter..>
if( q->depth == q->max ){
q->max += 10;
if( (q->stack = (int *) r_alloc( (void *) q->stack,
(size_t) (q->max * sizeof(int)))) == NULL) bad_mem;
}
q->stack[q->depth++] = q->i;
-_-_-
<..pop counter..>
q->depth--;
if( q->max > q->depth + 20 ){ q->max -= 15;
if( (q->stack = (int *) r_alloc( (void *) q->stack,
(size_t) (q->max * sizeof(int)))) == NULL) bad_mem;
}
-_-_-
<..act on counter..>
switch ( code ){
case ’+’: { (q->i)++; break; }
case ’-’: { (q->i)--; break; }
case ’>’: { <.push counter.> break; }
case ’<’: { if( q->depth ){ <.pop counter.> }
break; }
case ’!’: { <.open output file.>
(IGNORED) fprintf(cur_o_file, "%d", q->i); break; }
case ’|’: { if( q->depth ){
<.open output file.>
(IGNORED) fprintf(cur_o_file, "%d", q->stack[q->depth - 1] );
}
break; }
default: { ; }
}
-_-_-