7 CopyTo files

There are 6 supporting dvi variations of the ‘CopyTo to-file op group’ dvi command:

From
Start copying (at current address)
Until
End copying (at current address)
Skip
Start skipping (from current address)
Cont
End skipping (at current-address)
Addr integer-label
Associate current address with the integer-label of the given group
Set integer-label
Replace the ‘current address’ in the following Skip/Cont (and From/Until ?) commands with the address associated to the integer-label of the given group by an Addr command

The code

B0 
 \ht:special {t4ht@DCopyTo: \jobname-js.tex From bib } 
B1 
 \ht:special {t4ht@DCopyTo: \jobname-js.tex Skip bib } 
B2 
 \ht:special {t4ht@DCopyTo: \jobname-js.tex Addr1 bib } 
B3 
 \ht:special {t4ht@DCopyTo: \jobname-js.tex Addr2 bib } 
B4 
 \ht:special {t4ht@DCopyTo: \jobname-js.tex Set1 bib } 
 \ht:special {t4ht@DCopyTo: \jobname-js.tex Cont bib } 
 \ht:special {t4ht@DCopyTo: \jobname-js.tex Set2 bib } 
 \ht:special {t4ht@DCopyTo: \jobname-js.tex Skip bib } 
B5 
\ht:special {t4ht@DCopyTo: \jobname-js.tex Until bib } 
B6 

produces the string ‘ B1 B3 ’.

<..CopyTo files..>
 {     <.CopyTo vars.>
    eoln_ch = (int) ’x’;
    while( eoln_ch != EOF ) {
       status = scan_str("CopyTo: ", TRUE, lg_file);
       status = scan_until_str(" ", 1, status, lg_file);
       status = scan_until_str(" ", 2, status, lg_file);
       status = scan_until_str(" ", 3, status, lg_file);
       status = scan_until_str(" ", 4, status, lg_file);
       status = scan_until_end_str("", 5, status, lg_file);
       if( status ){
          if( debug ){
             (IGNORED) printf("...CopyTo: %s%s%s%s%s...\n",
                      match[1], match[2], match[3], match[4], match[5]);
          }
          rec_op = eq_str(match[2],"From ")?  From_op :
                   ( eq_str(match[2],"Until ")? Until_op :
                     ( eq_str(match[2],"Skip ")?  Skip_op :
                       ( eq_str(match[2],"Cont ")?  Cont_op : No_op )));
          if( rec_op == No_op ){ <.try Addr and Set ops.> }
          if( rec_op == No_op ){
             (IGNORED) fprintf(stderr,"--- warning --- ");
             (IGNORED) fprintf(stderr,"CopyTo: %s%s%s%s%s?\n",
                       match[1], match[2], match[3], match[4], match[5]);
          } else {
             <.find file records.>
             <.find to-from record.>
             <.find group record.>
             <.enter op record.>
             <.act on op.>
    }  }  }
    <.release CopyTo resources.>
 }
 -_-_-

<..try Addr and Set ops..>
 ch = match[2];
 if( (ch[0]==’S’) && (ch[1]==’e’) && (ch[2]==’t’) ){
   ch += 3; rec_op = Set_op;
 } else if( (ch[0]==’A’) && (ch[1]==’d’) && (ch[2]==’d’) && (ch[3]==’r’) ){
   ch += 4; rec_op = Addr_op;
 }
 if( rec_op != No_op ){
   addr = 0; while( (*ch>=’0’) && (*ch<=’9’) ){
     addr = addr*10 + *ch - ’0’; ch++;
 } }
 -_-_-

<..release CopyTo resources..>
 for( p = opened_files; p != (struct files_rec*) 0; ){
    (IGNORED) fclose(p->file);
    free((void *)  p->name);
    <.free to-from records.>
    p1= p;  p = p->right;    free((void *)  p1);
 }
 -_-_-

<..free to-from records..>
 for( p1 = p->down; p1 != (struct files_rec*) 0; ){
    <.free group records.>
    p2 = p1; p1 = p1->right;  free((void *)  p2);
 }
 -_-_-

<..free group records..>
 for( p2 = p1->down; p2 != (struct files_rec*) 0; ){
    <.free op records.>
    p3 = p2; p2 = p2->right;  free((void *)  p3);
 }
 -_-_-

<..free op records..>
 for( p3 = p2->down; p3 != (struct files_rec*) 0; ){
   p4 = p3; p3 = p3->down; free((void *)  p4);
 }
 -_-_-

<..act on op..>
 if( rec_op == Until_op ){
   for( p = to_rec->down;
            p != (struct files_rec*) 0;  p = p->down ){
     if( p->op == From_op ){ from_op = p; break; }
   }
   if( p == (struct files_rec*) 0 ){
     <.missing From for CopyTo.>
   } else {
     <.perform ops.>
     <.remove ops.>
   }
 }
 -_-_-

<..perform ops..>
 in_file = from_rec->file;
 out_file = to_rec->file;
 start_loc = from_op->loc;
 write_on = TRUE;
 (IGNORED) fseek(in_file, (long) start_loc, <.abs file addr.>);
 for( p= from_op;  p != to_rec; p = p->up ){
   switch( p->op ){
     case Until_op:{ <.Until op.> break; }
     case  Skip_op:{ <.Skip op.>  break; }
     case  Cont_op:{ <.Cont op.>  break; }
     case   Set_op:{ <.Set op.>   break; }
     default: {  }
 } }
 -_-_-

<..Until op..>
 if( write_on ){
    end_loc = p->loc;
    for(; start_loc<end_loc; start_loc++) {
       (IGNORED) putc( getc(in_file), out_file );
 }  }
 -_-_-

<..Skip op..>
 if( write_on ){
    end_loc = p->loc;
    for(; start_loc<end_loc; start_loc++) {
       (IGNORED) putc( getc(in_file), out_file );
    }
 }
 write_on = FALSE;
 -_-_-

<..Cont op..>
 end_loc = p->loc;
 if( write_on ){
    for(; start_loc<end_loc; start_loc++) {
       (IGNORED) putc( getc(in_file), out_file );
    }
 } else {
    start_loc = end_loc;
    (IGNORED) fseek(in_file, (long) end_loc, <.abs file addr.>);
 }
 write_on = TRUE;
 -_-_-

<..Set op..>
 addr = -1;
 for( p1 = from_op->up; p1 != to_rec;  p1 = p1->up ){
   if( (p1->op == Addr_op) && (p1->label == p->label) ){
     addr = p1->loc; break;
 } }
 if( addr != -1 ){ (p->up)->loc = addr; }
 -_-_-

<..remove ops..>
 to_rec->down = from_op->down;
 if( from_op->down != (struct files_rec*) 0){
     (from_op->down)->up = to_rec;
 }
 for( p = from_op; p != to_rec; ){
   p1 = p;  p = p->up; free((void *)  p1);
 }
 if( to_rec->down == (struct files_rec*) 0){
   if( to_rec->left == (struct files_rec*) 0 ){
     (to_rec->up)->down =  to_rec->right;
   } else {
     (to_rec->left)->right = to_rec->right;
   }
   if( to_rec->right != (struct files_rec*) 0 ){
     (to_rec->right)->left = to_rec->left;
   }
   p1 = to_rec; to_rec = to_rec->up;  free((void *)  p1);
 }
 -_-_-

<..missing From for CopyTo..>
 (IGNORED) fprintf(stderr,"%sMissing ‘CopyTo From’:\n", "--- warning --- ");
 for( p = to_rec->down; p != (struct files_rec*) 0;  p = p->down ){
   (IGNORED) fprintf(stderr,"   %s %s%d %s\n", to_rec->name,
           p->op == From_op ?  "From  " :
              ( p->op == Until_op ?   "Until " :
                ( p->op == Skip_op ?   "Skip  " :
                  ( p->op == Cont_op?   "Cont " :
                  ( p->op == Addr_op?   "Addr " :
                  ( p->op == Set_op?   "Set " : "No_op " ))))),
           p->loc, from_rec->name
          );
 }
 -_-_-

<..enter op record..>
 p = m_alloc(struct files_rec, 1);
 p->down = to_rec->down;  to_rec->down = p;
 p->up = to_rec;
 if( p->down != (struct files_rec*) 0 ){
   (p->down)->up = p;
 }
 *(match[4] + (int) strlen((char *) match[4]) - 1) = ’\0’;
 p->loc = (int) get_long_int(match[4]);
 p->op  = rec_op;
 p->label = addr;
 -_-_-

<..find group record..>
 if( to_rec->down == (struct files_rec*) 0 ){
   <.add first group record.>
 } else {
   to_rec = to_rec->down;
   for( p = to_rec->right; p != (struct files_rec*) 0;  p = p->right ){
     if( eq_str(to_rec->group,match[3]) ){ break; }
     to_rec = p;
   }
   if( !eq_str(to_rec->group,match[3]) ){
     <.add next group record.>
 } }
 -_-_-

<..add first group record..>
 to_rec->down = p = m_alloc(struct files_rec, 1);
 p->up = to_rec;
 p->right = p->left = p->down = (struct files_rec*) 0;
 p->name = to_rec->name;
 p->file = to_rec->file;
 p->from_rec = from_rec;
 p->loc = -1;
 p->op = No_op;
 p->group = m_alloc(char, (int) strlen((char *) match[3]) + 1);
 (IGNORED) strcpy((char *)  p->group, (char *) match[3] );
 to_rec = p;
 -_-_-

<..add next group record..>
 to_rec->right = p = m_alloc(struct files_rec, 1);
 p->left = to_rec;
 p->right = p->down = (struct files_rec*) 0;
 p->up = to_rec->up;
 p->name = to_rec->name;
 p->file = to_rec->file;
 p->from_rec = from_rec;
 p->loc = -1;
 p->group = m_alloc(char, (int) strlen((char *) match[3]) + 1);
 (IGNORED) strcpy((char *)  p->group, (char *) match[3] );
 to_rec = p;
 -_-_-

<..find to-from record..>
 if( to_rec->down == (struct files_rec*) 0 ){
   <.add first to-from record.>
 } else {
   to_rec = to_rec->down;
   for( p = to_rec->right; p != (struct files_rec*) 0;  p = p->right ){
     if( to_rec->from_rec == from_rec ){ break; }
     to_rec = p;
   }
   if( to_rec->from_rec != from_rec ){
     <.add next to-from record.>
 } }
 -_-_-

<..add first to-from record..>
 to_rec->down = p = m_alloc(struct files_rec, 1);
 p->up = to_rec;
 p->right = p->left = p->down = (struct files_rec*) 0;
 p->name = to_rec->name;
 p->file = to_rec->file;
 p->from_rec = from_rec;
 p->loc = -1;
 p->op = No_op;
 to_rec = p;
 -_-_-

<..add next to-from record..>
 to_rec->right = p = m_alloc(struct files_rec, 1);
 p->left = to_rec;
 p->right = p->down = (struct files_rec*) 0;
 p->up = to_rec->up;
 p->name = to_rec->name;
 p->file = to_rec->file;
 p->from_rec = from_rec;
 p->loc = -1;
 to_rec = p;
 -_-_-

<..find file records..>
 file_name = match[1];
 *(file_name + (int) strlen((char *) file_name) - 1) = ’\0’;
 strcpy((char *) file_mode, WRITE_TEXT_FLAGS);
 for(i=1; i<=2; i++){
   <.search CopyTo file.>
   file_name = match[5];
   strcpy((char *) file_mode, <.CopyTo read flags.>);
 }
 -_-_-

<..search CopyTo file..>
 for( p = opened_files; p != (struct files_rec*) 0;  p = p->right ){
    if( eq_str(file_name,p->name) ) { break; }
 }
 if( p == (struct files_rec*) 0 ){
   p = m_alloc(struct files_rec, 1);
   p->right = opened_files;   opened_files = p;
   p->down =  (struct files_rec*) 0;
   strcpy((char *) p->file_mode, (char *) file_mode);
   p->name = m_alloc(char, (int) strlen((char *) file_name) + 1);
   (IGNORED) strcpy((char *)  p->name, (char *) file_name );
   if( (p->file = fopen(file_name, file_mode)) == NULL )
     { (IGNORED) warn_i_str(5,file_name); }
 }
 to_rec = from_rec;  from_rec = p;
 -_-_-

<..defines..>+
 struct files_rec{
   FILE* file;
   char *name, *group, op;
   Q_CHAR file_mode[5];
   int loc, label;
   struct files_rec  *from_rec, *right, *left, *down, *up;
 };
 #define No_op     0
 #define From_op   1
 #define Until_op  2
 #define Skip_op   3
 #define Cont_op   4
 #define Addr_op   5
 #define Set_op    6
 -_-_-

<..CopyTo vars..>
 Q_CHAR *file_name, file_mode[5];
 int i, start_loc, end_loc, addr = 0;
 char rec_op, *ch;
 static struct files_rec *to_rec, *from_rec,
    *opened_files = (struct files_rec *) 0,
    *p, *p1, *p2, *p3, *p4, *from_op;
 FILE *in_file, *out_file;
 BOOL write_on;
 -_-_-