For instance, \over. Such operations require delivery of information backward and forward to the group boundaries. For backward delivery, a preprocessing phase is introduced.
Upon encountering a \special{t4ht~...} we arrive here. An empty content is an on/off flag. When it is turned on, we make a preprocessing pass to collect information.
<..grouped-base delivery content..>
if( special_n ){
<.main pass for group special.>
} else if( (group_dvi = !group_dvi) == TRUE ){
long curr_pos;
int ch, sv_stack_n;
<.subp vars.>
<.init subp vars.> stack_id = 0;
curr_pos = ftell(dvi_file); sv_stack_n = stack_n;
<.send info backward.>
<.exit early pass.>
(IGNORED) fseek(dvi_file, curr_pos, <.abs file addr.>);
group_dvi = TRUE; stack_n = sv_stack_n; stack_id = 0;
} else { <.exit group special.> }
-_-_-
<..vars..>+
static BOOL group_dvi = FALSE;
-_-_-
<..main’s vars..>+
int stack_id=0;
-_-_-
<..main pass for group special..>
U_CHAR in_ch;
if( (in_ch = get_char()) == ’>’ ) {
<.store forward submissions.>
} else if( in_ch == ’!’ ) {
<.store path-based forward submissions.>
} else {
if( !group_dvi ){ warn_i(42); }
(IGNORED) fseek(dvi_file, (long) --special_n,
<.relative file addr.>);
special_n = 0;
}
-_-_-
[example]
<..vars..>+
static int stack_n = 0;
static struct stack_entry* stack;
-_-_-
<..types..>+
struct stack_entry{
long int x_val, y_val;
INTEGER dx_1, dx_2, dy_1, dy_2;
BOOL text_on;
BOOL <.BOOl stack accented.>;
<.struct stack_entry.>
};
-_-_-
<..stack = m-alloc.....>
stack = m_alloc(struct stack_entry,<.size of stack for nested boxes.>);
<.initialize grouping stack.>
-_-_-
<..size of stack for nested boxes..>
((int) stack_len + 2)
-_-_-
The ‘\special{t4ht^>*...*...}’ asks for delimiters on the next group or token, whichever comes first. That information is stored in the stack even for characters, which implies an implicit stack greater by one than that requested by the dvi code. The extra 2 in size reults from the pointer being on the next empty entry?
<..struct stack_entry..>+
int stack_id;
struct group_info * begin;
struct stack_end_entry * end;
-_-_-
<..types..>+
struct group_info{
int stack_id;
U_CHAR *info;
struct group_info* next;
};
-_-_-
<..initialize grouping stack..>
{ int i;
for( i=<.size of stack for nested boxes.>-1; i>=0; i--){
stack[i].begin = (struct group_info *) 0;
stack[i].end = (struct stack_end_entry *) 0;
stack[i].stack_id = -1;
<.initialized entries for grouping stack.>
} }
-_-_-
<..store forward submissions..>
if( special_n == 1 ){
special_n--;
switch( get_char() ){
case ’[’: { ignore_end_group++; break; }
case ’]’: { ignore_end_group--; break; }
default: { <.unused special.> }
}
} else {
struct stack_end_entry *p;
U_CHAR *q;
int j;
j = get_char() - ’0’ + stack_n - 1;
if( --special_n ){
if (j >= stack_len ) { j = stack_len - 1; }
p = m_alloc(struct stack_end_entry,1);
p->next = stack[ j ].end;
stack[ j ].end = p;
q = p->send = m_alloc(char,special_n+1);
while( --special_n ) *q++ = get_char();
*q = ’\0’;
} }
-_-_-
We create a linked list for forward submissions.
<..types..>+
struct stack_end_entry{
struct stack_end_entry *next;
U_CHAR *send;
};
-_-_-
<..retrieve forward submissions..>
struct stack_end_entry *q, *p, *t;
q = stack[ stack_n-1 ].end;
p = stack[ stack_n-1 ].end = (struct stack_end_entry *) 0;
while( q ){
t = q->next; q->next = p; p = q; q = t;
}
while( p ){
if( ! ignore_end_group ){ print_f( p->send ); }
free((void *) p->send );
q = p; p = p->next; free((void *) q );
}
-_-_-
<..get forward deliveries..>
while( stack[stack_n-1].end ){
<.retrieve forward submissions.>
}
-_-_-
<..vars..>+
static int ignore_end_group;
-_-_-
<..exit group special..>
{ int stack_n;
for( stack_n=<.size of stack for nested boxes.>;
stack_n>0; stack_n--){
group_dvi = TRUE; <.get forward deliveries.>
group_dvi =FALSE;
<.check forward deliveries.>
} }
-_-_-
<..check forward deliveries..>
while( stack[stack_n-1].begin ){
struct group_info *p;
warn_i_str(44, stack[stack_n-1].begin->info);
p = stack[stack_n-1].begin;
stack[stack_n-1].begin = p->next;
free((void *) p );
}
stack[stack_n-1].stack_id = -1;
-_-_-
The following is needed for pops that appear before the leading push. Such pops can emerge from preceding code.
<..send info back to group open..>
struct group_info *p;
U_CHAR *q;
int j;
j = ch - ’0’ + stack_n - 1;
if (j >= stack_len ) { j = stack_len - 1; }
p = m_alloc(struct group_info,1);
p->next = stack[ j ].begin; stack[ j ].begin = p;
p->stack_id = stack[ j ].stack_id;
q = p->info = m_alloc(char,i+1);
while( --i ) *q++ = get_char();
*q = ’\0’;
-_-_-
“Backward” submissions to levels higher than 0 are forward transmission and they can be moved to the main pass. That will buy a little saving in memory, and possibly less fragmentation there due to dynamic allocation of mem.
<..push/pop on backward submissions..>
case <.sv loc op.>: {
<.stack-id into linked list.>
stack[stack_n].stack_id = stack_id++;
<.push-id + 1.> stack_n++;
if( stack_n > <.size of stack for nested boxes.> ){ warn_i(40); }
break;
}
case <.retrieve loc op.>: {
stack_n--; <.pop-id + 1.>
stack[stack_n].stack_id = -1;
break;
}
-_-_-
The following changes the previously unknown stack-id, represented by -1, of a future deeper PUSH with the stack-id of that PUSH. That PUSH is just have been reached. We also want to reverse the order within that sub-list.
<..stack-id into linked list..>
{ struct group_info *p, *last;
if( (last = p = stack[ stack_n ].begin) != (struct group_info *)0 )
if( p->stack_id == -1 ){
<.modify id of sub sequence.>
<.reverse stack sub sequence.>
}
}
-_-_-
<..modify id of sub sequence..>
while( p ){
if( p->stack_id != -1 ){ break; }
p->stack_id = stack_id;
last = p;
p = p->next;
}
-_-_-
<..reverse stack sub sequence..>
while ( stack[ stack_n ].begin != last ){
p = (stack[ stack_n ].begin) -> next;
(stack[ stack_n ].begin) -> next = last->next;
last->next = stack[ stack_n ].begin;
stack[ stack_n ].begin = p;
}
-_-_-
<..get backward deliveries..>
{ struct group_info *p;
if( group_dvi &&
( (p = stack[stack_n].begin ) != (struct group_info *)0)
){
while( p ){
if( p->stack_id != stack_id ) break;
print_f(p->info);
stack[stack_n].begin = p->next;
free((void *) p );
p = stack[stack_n].begin;
}
}
stack_id++;
}
-_-_-
The following reverses the list at the end of the preprocessing pass.
<..exit early pass..>
{ struct group_info *first, *second, *temp;
int i;
for(i = stack_len; i >= 0; i--){
first = stack[i].begin;
if( first ) {
second = first->next;
while( second ){
temp = second->next;
second->next = first;
first = second;
second = temp;
}
(stack[i].begin)->next = (struct group_info *) 0;
stack[i].begin = first;
} } }
-_-_-
Used for collecting information to be sent backward to the entry point of the group. The information is stored in linked lists of type ‘struct group_info’, accessed through ‘stack[ level-of-nesting ].begin’.
Each PUSH is offered an id. Upon reaching a PUSH, its id is stored in ‘stack[ level-of-nesting ].stack_id’. Upon reaching a ‘\special{t4ht~<...message...}’, the message is inserted into the linked list, together with its PUSH id. The messages are retrieved in the main pass, as the PUSHES are traversed for the second time.
<..send info backward..>
while( group_dvi ){
<.extract backward submissions.>
}
-_-_-
Only ‘~’ tex4ht specials are significant here. The ones of the form ‘\special{t4ht~}’ act as end-points for the preprocessing, and ‘\special{t4ht~<...}’ act as backward info delivers.
<..hooks for backward submissions..>
case <.special 1.>: case <.special 2.>:
case <.special 3.>: case <.special 4.>: { long int i;
if( tex4ht_special( &ch, &i ) ){
if( ch == ’~’ ){
<.handle requests for backward submissions.>
} else {
(IGNORED) fseek(dvi_file, (long) i, <.relative file addr.>);
}
}else{ <.ignore non-t4ht special.> }
break;
}
-_-_-
<..ignore non-t4ht special..>
U_CHAR *ch;
ch = special_hd + 4;
while( *ch ){ ch++; }
(IGNORED) fseek(dvi_file, (long) i, <.relative file addr.>);
-_-_-
<..handle requests for backward submissions..>
if( i==0 ){
group_dvi = FALSE ;
}else{
switch( get_char() ){
case ’<’: {
if( i-- ){ U_CHAR ch;
if( (ch = get_char()) == ’*’ )
{ <.send back over token / group.> }
else if( (ch == ’[’) && (i==1) ){
i--; <.hide back token / group.>
}
else if( (ch == ’]’) && (i==1) ){
i--; <.end hide back token / group.>
}
else if( (ch == ’-’) && (i==1) ){
i--; <.latex back token / group.>
}
else if( (ch == ’+’) && (i==1) ){
i--; <.end latex back token / group.>
}
else if( (ch == ’(’) && (i==1) ){
i--; <.back token / group.>
}
else if( (ch == ’)’) && (i==1) ){
i--; <.end back token / group.>
}
else { <.send info back to group open.> }
}
break; }
default: { (IGNORED) fseek(dvi_file, (long) --i,
<.relative file addr.>); break; }
} }
-_-_-
When sv_stack_n==stack_n the sending back NEED NOT be in the level of the opening \special{t4ht~}. This is so because it can happen that we have, for instance, ‘\special ~<POP><PUSH>’
Fonts Definition:
<..ignore font def on preview pass..>
case <.def 4 byte font.>: (void) get_char();
case <.def 3 byte font.>: (void) get_char();
case <.def 2 byte font.>: (void) get_char();
case <.def 1 byte font.>: { int i;
for( i=14; i; i-- ){ ch = get_char(); }
i = ch + get_char();
(IGNORED) fseek(dvi_file, (long) i, <.relative file addr.>);
break; }
-_-_-
Fonts Activation:
<..fonts and default ignored on preview pass..>
case <.font 1-byte.>:
case <.font 2-bytes.>:
case <.font 3-bytes.>:
case <.font int.>: {
INTEGER n;
n = ch - <.font 1-byte.> + 1;
cr_fnt = (int) ((n==4)? get_int(4) : get_unt((int) n));
cr_fnt = search_font_tbl( cr_fnt );
break; }
default: {
if( (ch < <.font 0.>) || (ch > <.font 63.>) ) {
if( ch == <.end page op.> ) { warn_i(46); }
else { warn_i_int(45,ch); }
} else { cr_fnt = ch - <.font 0.>;
cr_fnt = search_font_tbl( cr_fnt );
}
break;
}
-_-_-
<..subp vars..>
int cr_fnt;
-_-_-
<..init subp vars..>
cr_fnt = cur_fnt;
-_-_-
<..extract backward submissions..>
if( (ch = get_char()) >= 128 ) {
switch( ch ){
<.indirect chars on early backward submissions pass.>
<.ignore font def on preview pass.>
<.ignore on preview pass.>
<.push/pop on backward submissions.>
<.hooks for backward submissions.>
<.fonts and default ignored on preview pass.>
}
} else { <.ch-id + 1.> }
-_-_-
<..indirect chars on early backward submissions pass..>
case 128: case 129: case 130: case 131: case 133:
case 134: case 135: case 136: {
ch = (int) get_unt( (ch-(ch>132)) % 4 +1);
<.ch-id + 1.>
break;
}
-_-_-
<..ignore on preview pass..>
case <.insert rule + move op.>:
case <.insert rule + nomove op.>:{
(IGNORED) fseek(dvi_file, 8L, <.relative file addr.>);
break;
}
-_-_-
<..ignore on preview pass..>+
case <.start page op.>: {
(IGNORED) fseek(dvi_file, 44L, <.relative file addr.>); break; }
-_-_-
<..ignore on preview pass..>+
case <.mv hor 1-byte.>: case <.mv hor 2-byte.>:
case <.mv hor 3-byte.>: case <.mv hor 4-byte.>: {
(IGNORED) (get_int( ch - <.mv hor 1-byte.> + 1 )); break; }
case <.dx.1 store and mv hor 1-byte.>:
case <.dx.1 store and mv hor 2-byte.>:
case <.dx.1 store and mv hor 3-byte.>:
case <.dx.1 store and mv hor 4-byte.>: {
(IGNORED) (get_int( ch - <.dx.1 store and mv hor 1-byte.> + 1));
break; }
case <.dx.2 store and mv hor 1-byte.>:
case <.dx.2 store and mv hor 2-byte.>:
case <.dx.2 store and mv hor 3-byte.>:
case <.dx.2 store and mv hor 4-byte.>: {
(IGNORED) (get_int( ch - <.dx.2 store and mv hor 1-byte.> + 1));
break; }
case <.mv ver 1-byte.>: case <.mv ver 2-byte.>:
case <.mv ver 3-byte.>: case <.mv ver 4-byte.>: {
(IGNORED) (get_int( ch - <.mv ver 1-byte.> + 1));
break; }
case <.dy.1 store and mv ver 1-byte.>:
case <.dy.1 store and mv ver 2-byte.>:
case <.dy.1 store and mv ver 3-byte.>:
case <.dy.1 store and mv ver 4-byte.>: {
(IGNORED) (get_int( ch - <.dy.1 store and mv ver 1-byte.> + 1));
break; }
case <.dy.2 store and mv ver 1-byte.>:
case <.dy.2 store and mv ver 2-byte.>:
case <.dy.2 store and mv ver 3-byte.>:
case <.dy.2 store and mv ver 4-byte.>: {
(IGNORED) (get_int( ch - <.dy.2 store and mv ver 1-byte.> + 1));
break; }
-_-_-
<..ignore on preview pass..>+
case <.mv hor dist dx.1.>:
case <.mv hor dist dx.2.>:
case <.mv ver dist dy.1.>:
case <.mv ver dist dy.2.>:
{ break; }
-_-_-
<..process dvi op ’ch’..>+
case <.sv loc op.>: { <.push values to stack.> break; }
case <.retrieve loc op.>: { <.pop values from stack.> break; }
-_-_-
The dvi stacking code refers to the information ‘x_val’, ‘y_val’, ‘dx_1’, ‘dx_2’, ‘dy_1’, and ‘dy_2’.
<..push values to stack..>
<.halign at entry to group.>
<.get backward deliveries.>
stack[stack_n].text_on = text_on;
push_stack(); <.get back sub/sup before group.>
<.path group at entry to group.>
<.trace dvi push.>
<.add push class del.>
-_-_-
<..header functions..>+
static void push_stack( ARG_I(void) );
-_-_-
<..functions..>+
static void push_stack(MYVOID)
{
stack[stack_n].x_val = x_val;
stack[stack_n].dx_1 = dx_1;
stack[stack_n].dx_2 = dx_2;
stack[stack_n].y_val = y_val;
stack[stack_n].dy_1 = dy_1;
stack[stack_n].dy_2 = dy_2;
<.push inherit del.>
stack_n++;
if( stack_n > <.size of stack for nested boxes.> ){
warn_i(40);
}
<.init end math accented.>
}
-_-_-
<..push inherit del..>
stack[stack_n+1].sv_no_left_del = stack[stack_n+1].no_left_del;
stack[stack_n+1].no_left_del = stack[stack_n].no_left_del;
-_-_-
<..pop uninherit del..>
stack[stack_n].no_left_del = stack[stack_n].sv_no_left_del;
-_-_-
The first statement partially handles spaces after text that is inserterted to the left of the current location (e.g., items of list).
<..pop values from stack..>
<.add pop class del.>
<.path group at exit from group.>
<.get forward deliveries.>
<.trace dvi pop.>
<.halign at exit from group.>
pop_stack();
if( ((x_val+0.6*word_sp) < stack[stack_n].x_val) ) put_char(’ ’);
text_on = stack[stack_n].text_on;
-_-_-
<..header functions..>+
static void pop_stack( ARG_I(void) );
-_-_-
<..functions..>+
static void pop_stack(MYVOID)
{
<.end math accented.>
<.pop uninherit del.>
--stack_n;
x_val = stack[stack_n].x_val;
dx_1 = stack[stack_n].dx_1;
dx_2 = stack[stack_n].dx_2;
y_val = stack[stack_n].y_val;
dy_1 = stack[stack_n].dy_1;
dy_2 = stack[stack_n].dy_2;
}
-_-_-
TeX places subscripts and superscripts on the most recent group or token. We are looking where the most recent of these tokens starts, and store there the desired info.
We keep a delimiter stack for the parenthesis, and include there also the opening and closing of groups. The latter one are employed to deal with parenthese that are not balanced, for instance, ‘\left( ... \right.’.
<..pop-id + 1..>
if( !back_id_off ){
if( !id_hide ){ ch_token = FALSE;
sv_id = stack[stack_n].stack_id; }
while( del_stack != (struct del_stack_entry*) 0 ){
struct del_stack_entry* p;
int id;
del_stack = (p = del_stack)->next;
id = p->id;
free((void *) p );
if( id == -1 ) break;
} }
-_-_-
<..push-id + 1..>
if( !back_id_off )
{ struct del_stack_entry *p;
p = m_alloc(struct del_stack_entry,1);
p->next = del_stack;
p->id = p->fnt = -1;
del_stack = p;
}
-_-_-
<..ch-id + 1..>
ch_id++;
if(!back_id_off ){
if( !id_hide ){ ch_token = TRUE; sv_id = ch_id; }
switch( math_class_of( ch, cr_fnt ) ){
case <.math open.>: { del_stack = push_del( (char) ch, cr_fnt);
break; }
case <.math close.>: {
del_stack = pop_del( (char) ch, id_hide, cr_fnt); break; }
default:{ ; }
} }
-_-_-
<..math close..>
5
-_-_-
Assumption made: closing del is in the same font as the opening one.
<..header functions..>+
static struct del_stack_entry* push_del( ARG_II(char, int) );
-_-_-
<..functions..>+
static struct del_stack_entry* push_del(ch, cr_fnt) U_CHAR ch;
int cr_fnt
;{ struct del_stack_entry *p;
p = m_alloc(struct del_stack_entry,1);
p->next = del_stack;
p->ch = ch;
p->fnt = cr_fnt;
p->id = ch_id;
return p;
}
-_-_-
<..header functions..>+
static struct del_stack_entry* pop_del( ARG_III(char,int,int) );
-_-_-
<..functions..>+
static struct del_stack_entry* pop_del(ch, id_hide, cr_fnt)
U_CHAR ch;
int id_hide;
int cr_fnt
;{
if( del_stack != (struct del_stack_entry*) 0 ){
if( (cr_fnt == del_stack->fnt) &&
( *(font_tbl[cr_fnt].math + (ch - font_tbl[cr_fnt].char_f))
== del_stack->ch) ){
struct del_stack_entry * p;
if( !id_hide && !id_latex ){ sv_id = del_stack->id; }
del_stack = (p = del_stack)->next; free((void *) p );
} }
return del_stack;
}
-_-_-
What the id_latex does here?
<..vars..>+
static struct del_stack_entry *del_stack;
-_-_-
<..main’s init..>+
del_stack = (struct del_stack_entry *) 0;
-_-_-
<..types..>+
struct del_stack_entry{
struct del_stack_entry *next;
U_CHAR ch;
int fnt, id;
};
-_-_-
<..vars..>+
static int ch_id, sv_id, id_latex, back_id_off;
-_-_-
<..main’s init..>+
back_id_off = 1; id_latex = 0;
-_-_-
<..init ch-id..>
ch_id = 0;
-_-_-
<..subp vars..>+
BOOL ch_token;
int id_hide;
-_-_-
<..init subp vars..>+
sv_id = 0; <.init ch-id.>
id_hide = 0; ch_token = TRUE;
while( del_stack != (struct del_stack_entry*) 0 ){
struct del_stack_entry* p;
del_stack = (p = del_stack)->next;
free((void *) p );
}
-_-_-
<..hide back token / group..>
id_hide++;
-_-_-
<..end hide back token / group..>
id_hide--;
-_-_-
<..latex back token / group..>
id_latex++;
-_-_-
<..end latex back token / group..>
id_latex--;
-_-_-
<..back token / group..>
back_id_off++;
-_-_-
<..end back token / group..>
back_id_off--;
-_-_-
<..types..>+
struct send_back_entry{
struct send_back_entry *next;
U_CHAR *send;
int id;
};
-_-_-
<..vars..>+
static struct send_back_entry *back_token, *back_group;
-_-_-
<..main’s init..>+
back_token = back_group = m_alloc(struct send_back_entry,1);
back_token->id = -1;
-_-_-
<..send back over token / group..>
struct send_back_entry *p, *q, *t=0;
if( back_id_off ){
while( i-- ){ (IGNORED) get_char(); }
} else {
p = m_alloc(struct send_back_entry,1);
p->send = get_str( (int)( i - 1 ));
if( ch_token ){
<.send back to char.>
} else {
p->id = (sv_id<0? 0 : sv_id) + push_id;
if( back_group->id < p->id )
{ p->next = back_group; back_group = p; }
else
{ q = back_group;
while( q->id >= p->id ) { t = q; q = q->next; }
p->next = t->next; t->next = p;
}
}
}
-_-_-
Keep [consistency] between back on group and back on token
<..send back to char..>
p->id = sv_id;
if( sv_id > back_token->id ){
p->next = back_token; back_token = p;
} else {
q = back_token;
while( sv_id <= q->id ){ t = q; q = q->next; }
p->next = t->next; t->next = p;
}
-_-_-
The following reverses the linked lists for ids and groups, so that the early entries will get at the head instead of the tail.
<..exit early pass..>+
back_group = rev_list( back_group );
back_token = rev_list( back_token );
back_token = back_insert ( back_token, 0);
<.init ch-id.>
-_-_-
<..header functions..>+
static
struct send_back_entry * rev_list( ARG_I(struct send_back_entry *) );
-_-_-
<..functions..>+
static struct send_back_entry * rev_list(back_group)
struct send_back_entry *back_group
;{ struct send_back_entry *p, *q, *t;
if( back_group->id == -1 ){ return back_group; }
p = back_group; q = p->next;
while( p->id != -1 ){
t = q->next; q->next = p; p = q; q = t;
}
back_group->next = p;
return p->next;
}
-_-_-
<..get back sub/sup before group..>
if( group_dvi ) {
back_group = back_insert ( back_group, push_id);
}
-_-_-
<..get back sub/sup before ch..>
if( group_dvi ){
if( ( ch < 132 ) ||
( (ch > 127) && (ch < 137) && (ch != <.insert rule + move op.> ) )
){
ch_id++;
back_token = back_insert ( back_token, ch_id);
} }
-_-_-
<..header functions..>+
static struct send_back_entry *
back_insert( ARG_II(struct send_back_entry *, int) );
-_-_-
<..functions..>+
static struct send_back_entry * back_insert(back, id)
struct send_back_entry *back;
int id
;{
while( back->id == id ){
struct send_back_entry *p;
print_f( back->send );
back = (p = back)->next;
free((void *) p->send );
free((void *) p );
}
return back;
}
-_-_-
The current instructions are motivated by the ‘\sqrt’ structure
and the ‘\root ...\of {...}’ construct
For instance,
<..struct stack_entry..>+
struct group_path * path_start, * path_end;
-_-_-
<..types..>+
struct group_path{
U_CHAR action;
U_CHAR *path;
U_CHAR *info;
struct group_path * next;
};
-_-_-
<..initialized entries for grouping stack..>+
stack[i].path_start = (struct group_path *) 0;
stack[i].path_end = (struct group_path *) 0;
-_-_-
<..store path-based forward submissions..>
struct group_path *p, *t;
U_CHAR *q, str[256];
int n;
p = m_alloc(struct group_path,1);
<.record action and path.>
<.record info for path.>
n = stack_n - 1;
if( p->action == ’>’ ){
p->next = stack[ n ].path_end;
stack[ n ].path_end = p;
} else {
p->next = (struct group_path *) 0;
if( stack[n].path_start == (struct group_path *) 0 ) {
stack[n].path_start = p;
} else {
t = stack[n].path_start;
while( t->next != (struct group_path *) 0 ) { t = t->next; }
t->next = p;
} }
-_-_-
<..record action and path..>
n = 0;
while( --special_n ) {
str[n] = get_char();
if( ( str[n] != ’e’) && (str[n] != ’s’) ){ break; }
n++;
}
if((
( str[n] != ’<’) && (str[n] != ’>’) &&
( str[n] != ’/’) && (str[n] != ’-’)
) || (n==0) ){
str[n+1] = ’\0’;
err_i_str(38,str);
}
p->action = str[n]; str[n] = ’\0’;
p->path = m_alloc(char,n+1);
(IGNORED) strcpy((char *) p->path, (char *) str);
-_-_-
<..record info for path..>
q = p->info = m_alloc(char,special_n+1);
while( --special_n ) *q++ = get_char();
*q = ’\0’;
-_-_-
<..path group at entry to group..>
{
<.vars for path processing.>
if( <.radical-line-off.> ){
<.end ignore spaces.>
<.radical-line-off.> = FALSE;
}
if( stack_n > 1 ){
p = stack[stack_n - 2].path_start;
if( p != (struct group_path *) 0 ){
<.traverse path starts on entry.>
}
p = stack[stack_n - 2].path_end;
if( p != (struct group_path *) 0 ){
<.traverse path ends on entry.>
}
<.connect the revised path lists.>
} }
-_-_-
<..vars for path processing..>
struct group_path *start_head, *start_tail,
*parent_start_head, *parent_start_tail,
*end_head, *end_tail,
*parent_end_head, *parent_end_tail,
*p, *q;
int place=0;
start_head = start_tail = parent_start_head = parent_start_tail
= end_head = end_tail = parent_end_head
= parent_end_tail = (struct group_path *) 0;
-_-_-
<..connect the revised path lists..>
stack[stack_n - 1].path_start = start_head;
stack[stack_n - 1].path_end = end_head;
stack[stack_n - 2].path_start = parent_start_head;
stack[stack_n - 2].path_end = parent_end_head;
-_-_-
<..traverse path starts on entry..>
while( p != (struct group_path *) 0 ){
<.process a path-start at entry.>
q = p;
p = p->next;
q->next = (struct group_path *) 0;
<.update temporary start paths.>
}
-_-_-
<..traverse path ends on entry..>
while( p != (struct group_path *) 0 ){
<.process a path-end at entry.>
q = p;
p = p->next;
q->next = (struct group_path *) 0;
<.update temporary end paths.>
}
-_-_-
<..update temporary start paths..>
switch( place ){
case <.store at parent path-start.>:
if( parent_start_head == (struct group_path *) 0 ){
parent_start_head = parent_start_tail = q;
} else {
parent_start_tail = parent_start_tail->next = q;
}
break;
case <.store at path-start.>:
if( start_head == (struct group_path *) 0 ){
start_head = start_tail = q;
} else {
start_tail = start_tail->next = q;
}
break;
case <.delete path entry.>:
<.delete path entry q.>
break;
}
-_-_-
<..update temporary end paths..>
switch( place ){
case <.store at parent path-end.>:
if( parent_end_head == (struct group_path *) 0 ){
parent_end_head = parent_end_tail = q;
} else {
parent_end_tail = parent_end_tail->next = q;
}
break;
case <.store at path-end.>:
if( end_head == (struct group_path *) 0 ){
end_head = end_tail = q;
} else {
end_tail = end_tail->next = q;
}
break;
case <.delete path entry.>:
<.delete path entry q.>
break;
}
-_-_-
<..store at parent path-start..>
0 -_-_-
<..store at parent path-end..>
1 -_-_-
<..store at path-start..>
2 -_-_-
<..store at path-end..>
3 -_-_-
<..delete path entry..>
4 -_-_-
<..delete path entry q..>
free((void *) q->path );
free((void *) q->info );
free((void *) q );
-_-_-
The ‘e’ records at the parent’s path-start are moved to the path-start list of the current group, with the leading ‘e’ removed from the path. The only exception is for paths of length 1 with actions ‘<’ and ‘-’. They contribute their content to the output, and then discarded.
The ‘s’ records at the parent’s path-start list stay at that list, with the ‘s’ character removed from the path.
The other records remain at the parent path-start list, to be removed at the end of that group.
<..process a path-start at entry..>
if( *(p->path ) == ’e’ ) {
(IGNORED) strcpy((char *) p->path, (char *) p->path+1);
if( *(p->path) == ’\0’ ) {
switch( p->action ){
case ’<’: print_f( p->info );
place = <.delete path entry.>;
break;
case ’/’: ignore_chs++;
place = <.store at path-start.>; break;
case ’-’: <.radical-line-off.> = TRUE;
<.ignore spaces.>
place = <.delete path entry.>; break;
}
} else {
place = <.store at path-start.>;
}
} else {
if( *(p->path ) == ’s’ ) {
(IGNORED) strcpy((char *) p->path, (char *) p->path+1);
}
place = <.store at parent path-start.>;
}
-_-_-
The ‘s’ records at the parent’s path-end list stay at that list, with the ‘s’ character removed from the path.
The ‘e’ records are moved to the path-end list of the current group, with the leading ‘e’ removed from the path.
The other records are left intact at the parent’s path-end list.
<..process a path-end at entry..>
if( *(p->path ) == ’e’ ) {
(IGNORED) strcpy((char *) p->path, (char *) p->path+1);
place = <.store at path-end.>;
} else {
if( *(p->path ) == ’s’ ) {
(IGNORED) strcpy((char *) p->path, (char *) p->path+1);
}
place = <.store at parent path-end.>;
}
-_-_-
<..path group at exit from group..>
{
struct group_path *p, *q;
if( stack_n > 1 ){
p = stack[stack_n - 1].path_start;
if( p != (struct group_path *) 0 ){
<.traverse path starts on exit.>
}
p = stack[stack_n - 1].path_end;
if( p != (struct group_path *) 0 ){
<.traverse path ends on exit.>
} } }
-_-_-
<..traverse path starts on exit..>
while( p != (struct group_path *) 0 ){
<.process a path-start at exit.>
q = p;
p = p->next;
<.delete path entry q.>
}
-_-_-
<..traverse path ends on exit..>
while( p != (struct group_path *) 0 ){
<.process a path-end at exit.>
q = p;
p = p->next;
<.delete path entry q.>
}
-_-_-
<..process a path-start at exit..>
if( *(p->path) != ’\0’ ) {
<.warn 38 for path.>
} else {
switch( p->action ){
case ’/’: ignore_chs--; break;
default: {
<.warn 38 for path.>
break;
} } }
-_-_-
<..process a path-end at exit..>
if( *(p->path) != ’\0’ ) {
<.warn 38 for path.>
} else {
switch( p->action ){
case ’>’: print_f( p->info ); break;
default: {
<.warn 38 for path.>
break;
} } }
-_-_-
<..warn 38 for path..>
char str[256];
(IGNORED) strcpy(str, "...."); *(str+3) = p->action;
(IGNORED) strct(str,p->info); warn_i_str(38,str);
-_-_-