/*
** This software is Copyright (c) 1989, 1990, 1991 by Kent Landfield.
**
** Permission is hereby granted to copy, distribute or otherwise 
** use any part of this package as long as you do not try to make 
** money from it or pretend that you wrote it.  This copyright 
** notice must be maintained in any copy made.
**
*/

#if !defined(lint) && !defined(SABER)
static char SID[] = "@(#)header.c	2.3 5/9/91";
#endif

#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include "article.h"

int fprintf();

int its(s1)
register char *s1;
{
    int strlen();
    int strncmp();

    if (strncmp(s,s1,strlen(s1)) == 0)
        return(TRUE);
    return(FALSE);
}

int line_type()
{
    if (its("Path: "))
        return PATH;
    if (its("From: "))
        return FROM;
    if (its("Newsgroups: "))
        return NEWSGROUP;
    if (its("Subject: "))
        return SUBJECT;
    if (its("Keywords: "))
        return KEYWORDS;
    if (its("Date: "))
        return DATE;
    if (its("Message-ID: "))
        return MSG_ID;
    if (its("Lines: "))
        return NUMLINES;
    if (its("Approved: "))
        return APPROVED;

    /* The following are the auxilliary headers used by */
    /* the moderators of the sources groups. In some    */
    /* cases, line checks are done with "historical"    */
    /* auxilliary headers. Most of the moderators have  */
    /* now standardized on comp.sources.unix's format.  */

    /* Archive header lines for comp.sources.unix     */
    /* for comp.sources.amiga, comp.sources.atari.st, */
    /* comp.sources.misc, and comp.sources.x.         */

    if (its("Submitted-by: "))         
        return SUBMITTED_BY;
    if (its("Posting-number: "))       
        return POSTING_NUMBER;
    if (its("Archive-name: "))
        return ARCH_NAME;

    /* Auxiliary header used as a backward reference   */
    /* to the location of the initially posted sources */
    /* in the event of a patch. This line only exists  */
    /* if the current article is a patch.              */

    if (its("Patch-To: "))
        return PATCH_TO;
    if (its("Patch-to: "))
        return PATCH_TO;

    /* The X-Checksum-Snefru archive was being used by     */
    /* comp.sources.unix and comp.sources.misc to  verify  */
    /* articles.  Once snefru was broken, the moderators   */
    /* of c.s.u and c.s.m switched to use X-Md4-Signature: */
    /* which is based on MD4 (RFC1186).                    */

    if (its("X-Checksum-Snefru: "))
        return X_CHECKSUM;
    if (its("X-Md4-Signature: "))
        return X_CHECKSUM;

    /* The following lines are used by comp.sources.games  */
    /* currently to indicate the environmental keywords    */
    /* indicating what is required by the software to run. */
    /* Supersedes: is also used by comp.sources.misc to    */
    /* indicate when a posting totally replaces another.   */

    if (its("Environment: "))
        return ENVIRONMENT;
    if (its("Supersedes: "))
        return SUPERSEDES;
 
    /* Archive header lines for historical purposes */
    /* once used in comp.sources.misc               */

    if (its("Submitted-By: "))        
        return SUBMITTED_BY;
    if (its("comp.sources.misc: "))
        return POSTING_NUMBER;
    if (its("Archive-Name: "))
        return ARCH_NAME;

    /* Archive header lines for supporting the  */
    /* uunet comp.sources.misc article archives */

    if (its("subject: "))
        return SUBJECT;
    if (its("from: "))
        return FROM;

    /* Archive header lines used in comp.sources.games   */
    /* Archive-name is the same as comp.sources.unix     */

    if (its("Submitted by: "))        
        return SUBMITTED_BY;
    if (its("Comp.sources.games: "))
        return POSTING_NUMBER;

    /* Archive header lines for historical purposes */
    /* once used in mod.sources articles.           */

    if (its("Mod.sources: "))       
        return POSTING_NUMBER;

    /* The following lines are used by comp.archives */
    /* to as auxiliary header lines.  Archive-name   */
    /* is also used.                                 */

    if (its("Original-posting-by: "))       
        return ORIGINAL_POSTING_BY;
    if (its("Original-subject: "))       
        return ORIGINAL_SUBJECT;
    if (its("Archive-site: "))       
        return ARCHIVE_SITE;
    if (its("Archive-directory: "))       
        return ARCHIVE_DIRECTORY;
    if (its("Reposted-by: "))       
        return REPOSTED_BY;
    if (its("Archive: "))
	return ARCHIVE_;

    /* The following lines are used by comp.sources.apple2 */
    /* to indicate the type of the system the software     */
    /* is to run on and the version of the software.       */

    if (its("Architecture: "))
        return ARCHITECTURE;
    if (its("Version-number: "))
        return VERSION_NUMBER;
 
    /* The remainder are other types of lines included */
    /* headers and are includes for formatting output  */
    /* and for potential future use.                   */

    if (its("References: "))
        return REFERENCES;
    if (its("Organization: "))
        return ORGANIZATION;
    if (its("Distribution: "))
        return DISTRIBUTION;
    if (its("Xref: "))
        return XREF;
    if (its("Expires: "))
        return EXPIRE;
    if (its("Article-I.D.: "))
        return ARTICLEID;
    if (its("Reply-To: "))
        return REPLY_TO;
    if (its("Control: "))
        return CONTROL;
    if (its("Sender: "))
        return SENDER;
    if (its("Followup-To: "))
        return FOLLOWUP_TO;
    if (its("Summary: "))
        return SUMMARY;

    return OTHER;
}

void data(hpfield, size, fldname, header_id)
char *hpfield;
int  size;
char *fldname;
int  header_id;
{
    register char *ptr;
    register char *p;
    char *strncpy();
    char *strcpy();
    char *strchr();

    for (ptr = strchr(s, ':'); isspace(*++ptr); )
        ;
    if (*ptr != '\0') {
        (void) strncpy(hpfield, ptr, size - 1);
        /*
         * Strip trailing newlines, blanks, and tabs from hpfield.
         */
        for (p = hpfield; *p; ++p)
             ;
        while (--p >= hpfield && (*p == '\n' || *p == ' ' || *p == '\t'))
             ;
        *++p = '\0';
    }

    (void) strcpy(header.header[header_id], hpfield);

    if (debug)
       (void) fprintf(logfp,"%s: %s\n",fldname, hpfield);
}

void dump_article()
{
    char *type_str;

    switch(article.rectype) {
             case PATCH  : type_str = "PATCH";
                           break;
      case ADMINISTRATION: type_str = "ADMINISTRATION"; 
                           break;
      case INFORMATIONAL : type_str = "INFORMATIONAL"; 
                           break;
                 default : type_str = "NORMAL"; 
                           break;
    }

    (void) fprintf(logfp,"Article:           [%s]\n",article.newsarticle);
    (void) fprintf(logfp,"   newsgroup:      [%s]\n",article.newsgroup);
    (void) fprintf(logfp,"   filename:       [%s]\n",article.filename);
    (void) fprintf(logfp,"   volume:         [%d]\n",article.volume);
    (void) fprintf(logfp,"   issue:          [%d]\n",article.issue);
    (void) fprintf(logfp,"   record type:    [%s]\n", type_str);
    if (article.rectype == PATCH) {
        (void) fprintf(logfp,"   patch volume:   [%d]\n",article.patch_volume);
        (void) fprintf(logfp,"   patch issue:    [%s]\n",article.patch_issue);
    }
    (void) fprintf(logfp,"   reposted:       [%s]\n", 
                   article.repost ? "YES": "NO");
    (void) fprintf(logfp,"   description:    [%s]\n",article.description);
    (void) fprintf(logfp,"   author's name:  [%s]\n",article.author_name);
    (void) fprintf(logfp,"   author's logon: [%s]\n\n",article.author_signon);
}

void init_article()
{
    article.newsgroup[0] = '\0';
    article.newsarticle[0] = '\0';
    article.filename[0] = '\0';
    article.volume = -1;
    article.issue = -1;
    article.rectype = NORMAL;
    article.repost = FALSE;
    article.patch_volume = -1;
    article.package_name[0] = '\0';
    article.patch_issue[0] = '\0';
    article.description[0] = '\0';
    article.author_name[0] = '\0';
    article.author_signon[0] = '\0';

    header.from[0] = '\0';         	/* From:                 */
    header.path[0] = '\0';         	/* Path:                 */
    header.nbuf[0] = '\0';         	/* Newsgroups:           */
    header.subject[0] = '\0';      	/* Subject:              */
    header.ident[0] = '\0';        	/* Message-ID:           */
    header.replyto[0] = '\0';      	/* Reply-To:             */
    header.references[0] = '\0';   	/* References:           */
    header.subdate[0] = '\0';      	/* Date: (submission)    */
    header.subtime = 0;            	/* subdate in secs       */
    header.expdate[0] = '\0';      	/* Expires:              */
    header.ctlmsg[0] = '\0';       	/* Control:              */
    header.sender[0] = '\0';       	/* Sender:               */
    header.followup_to[0] = '\0';  	/* Followup-to:          */
    header.distribution[0] = '\0'; 	/* Distribution:         */
    header.organization[0] = '\0'; 	/* Organization:         */
    header.numlines[0] = '\0';     	/* Lines:                */
    header.intnumlines = 0;        	/* Integer Version       */
    header.keywords[0] = '\0';     	/* Keywords:             */
    header.summary[0] = '\0';      	/* Summary:              */
    header.approved[0] = '\0';     	/* Approved:             */
    header.xref[0] = '\0';         	/* Xref:                 */
    header.supersedes[0] = '\0';   	/* Supersedes:           */
    header.submitted_by[0] = '\0'; 	/* Submitted_by:         */
    header.posting_num[0] = '\0';  	/* Posting-number:       */
    header.archive_name[0] = '\0'; 	/* Archive-name:         */
    header.patch_to[0] = '\0';     	/* Patch-To:             */
    header.x_checksum[0] = '\0';	/* X-Checksum-Snefru: or */
                                 	/* X-Md4-Signature       */
    header.orig_poster[0] = '\0';	/* Original-posting-by:  */
    header.orig_subject[0] = '\0';	/* Original-subject:     */
    header.archive_site[0] = '\0';	/* Archive-site:         */
    header.archive_dir[0] = '\0';	/* Archive-directory:    */
    header.reposter[0] = '\0';		/* Reposted-by:          */
    header.architecture[0] = '\0';	/* Architecture:         */
    header.version_number[0] = '\0';	/* Version-number:       */
    header.archive[0] = '\0';		/* Archive:		 */
    header.environment[0] = '\0';	/* Environment:		 */
}

void store_line()
{
    int atoi();
    char *strchr(), *strcpy(), *strstrip(), *substr();
    char *dp, *sp;
    char wrk[256];

    switch(line_type()) {

    case PATH: /*PATH REQUIRED************************/
        data(header.path, sizeof(header.path), "PATH:", PATH);
        break;

    case FROM: /*FROM REQUIRED************************/
        data(header.from, sizeof(header.from), "FROM:", FROM);
        break;

    case NEWSGROUP: /*NEWSGROUP REQUIRED**************/
        data(header.nbuf, sizeof(header.nbuf), "NEWSGROUPS:", NEWSGROUP);
        if ((sp = strchr(s,':')) != NULL) {
             do {
                 ++sp;
             } while(!isalpha(*sp));
             /* remove all crossposting labels */
             if ((dp = strchr(sp,',')) != NULL)
                 *dp = '\0';
             (void) strcpy(article.newsgroup,sp);
        }
        break;

    case SUBJECT: /*SUBJECT REQUIRED******************/
        data(header.subject, sizeof(header.subject), "SUBJECT:", SUBJECT);
        /* 
        ** Save the subject as the description for articles
        ** that have no volume/issue format. Later in the
        ** code, this subject line minus the volume/issue
        ** is stored back in the .description element if
        ** the volume/issue indicator is found.
        */
        (void) strcpy(article.description, header.subject);

        /*
        ** Check to see if this article is a repost of
        ** a previously posted article.
        */
        if (substr(s, "REPOST") != NULL)
            article.repost = TRUE;

        /*
        ** Time to get the filename. Assure that it is in a 
        ** volume/issue (v01INF1 or v01ADM1 or v01SRC001 or
        ** v01i001) format.
        */
        if ((sp = strchr(s,'v')) == NULL) 
            return;          /* no volume indicator */

        /* 
        ** Is there a number that follows 
        ** the volume indicator ? 
        */
        if (*(sp+1) < '0' || *(sp+1) > '9')
            return;   /* The volume number is missing */

        /*
        ** Is there a second ':' as well ?
        */
        (void) strcpy(article.filename,sp);
        if ((dp = strchr(article.filename,':')) == NULL) 
            return;   /* not in v01i001: format */

        /*
        ** terminate the article's filename and 
        ** store the article's description 
        */
        *dp = '\0';
        (void) strcpy(article.description, strstrip(++dp));

        /*
        ** Store the filename in a work 
        ** buffer so I can stomp on it. 
        */
        (void) strcpy(wrk, article.filename);

        ++sp; /* increment past the 'v' */

        /* 
        ** This is an informational posting.
        */
        if ((dp = substr(wrk, "INF")) != NULL) {
            article.rectype = INFORMATIONAL;
            article.issue = atoi((dp+3));
        }

        /* 
        ** This is an administration posting.
        */
        else if ((dp = substr(wrk, "ADM")) != NULL) {
            article.rectype = ADMINISTRATION;
            article.issue = atoi((dp+3));
        }

        /* 
        ** This is a comp.sources.apple2 posting.
        ** Why this is needed, I don't know...
        */
        else if ((dp = substr(wrk, "SRC")) != NULL) {
            article.issue = atoi((dp+3));
        }

        /*
        **  check to see if there is an issue indicator 
        */
        else if ((dp = strchr(wrk,'i')) != NULL) {
             /* parse the issue from the filename */
             article.issue = atoi(dp+1);
        }
        else
            return;   /* proven guilty. not volume/issue format */

        /* parse the volume from the filename */
        *dp = '\0';
        article.volume = atoi(sp);

        break;

    case DATE:
        data(header.subdate, sizeof(header.subdate), "DATE:", DATE);
        break;

    case EXPIRE:
        data(header.expdate, sizeof(header.expdate), "EXPIRES:", EXPIRE);
        break;

    case MSG_ID:
        data(header.ident, sizeof(header.ident), "MESSAGE-ID:", MSG_ID);
        break;

    case REPLY_TO:
        data(header.replyto, sizeof(header.replyto), "REPLY-TO:", REPLY_TO);
        break;

    case REFERENCES:
        data(header.references, sizeof(header.references), "REFERENCES:", REFERENCES);
        break;

    case SENDER:
        data(header.sender, sizeof(header.sender), "SENDER:", SENDER);
        break;

    case FOLLOWUP_TO:
        data(header.followup_to, sizeof(header.followup_to),"FOLLOWUP-TO:", FOLLOWUP_TO);
        break;

    case CONTROL:
        data(header.ctlmsg, sizeof(header.ctlmsg),"CONTROL:", CONTROL);
        break;

    case DISTRIBUTION:
        data(header.distribution, sizeof(header.distribution),"DISTRIBUTION:", DISTRIBUTION);
        break;

    case ORGANIZATION:
        data(header.organization, sizeof(header.organization),"ORGANIZATION:", ORGANIZATION);
        break;

    case NUMLINES:
        data(header.numlines, sizeof(header.numlines),"LINES:", NUMLINES);
        header.intnumlines = atoi(header.numlines);
        break;

    case KEYWORDS:
        data(header.keywords, sizeof(header.keywords), "KEYWORDS:",KEYWORDS);
        break;

    case APPROVED:
        data(header.approved, sizeof(header.approved), "APPROVED:",APPROVED);
        break;

    case ENVIRONMENT:
        data(header.environment, sizeof(header.environment),"ENVIRONMENT:",ENVIRONMENT);
        break;

    case SUPERSEDES:
        data(header.supersedes, sizeof(header.supersedes),"SUPERSEDES:",SUPERSEDES);
        break;

    case XREF:
        data(header.xref, sizeof(header.xref),"XREF:",XREF);
        break;

    case SUMMARY:
        data(header.summary, sizeof(header.summary),"SUMMARY:", SUMMARY);
        break;

    case POSTING_NUMBER:
        data(header.posting_num, sizeof(header.posting_num), "POSTING_NUMBER:", POSTING_NUMBER);
        /*
        ** Well we almost have a standard here...
        **
        ** comp.sources.amiga, comp.sources.atari.st, comp.sources.games
        ** comp.sources.sun, comp.sources.x, comp.sources.unix all use 
        ** Posting-Number: lines as follows:
        **    Volume #, Issue #
        ** indicates a source posting while
        **    Volume #, Info #
        ** is used for all the periodic and administration postings.
        ** For informational only... c.s.u once used
        **    Volume #, Number # 
        ** to indicate a source posting. Really. Check volume 10...
        ** 
        ** comp.sources.misc uses the same Posting-number: lines for
        ** source postings but used 
        **    Volume #, Administrivia #
        ** for all the periodic and administration postings.
        ** In the future, comp.sources.misc will use the Info format
        ** in order to move towards a standard.
        **
        ** comp.sources.apple2 uses the following Posting-number:
        ** lines for the INF, source and Administration postings.
        **    Volume 1, Information: 1
        **    Volume 1, Source:1
        **    Volume 1, Administrivia: 17
        **
        ** If the volume number and issue cannot be determined from
        ** the subject line then lets give it a try here...
        */
        if (article.volume == -1 || article.issue == -1) {
            if ((sp = strchr(s,'V')) != NULL) {
                do {
                    ++sp;
                } while((*sp) && (!isdigit(*sp)));
 
                /* Is there something there... */

                if (!*sp)
                    return;

                /*
                ** Time to get the volume number..
                ** Save it off so that the string can
                ** be stomped on..  What I am going to do here
                ** is to assure that I have both a volume and
                ** an issue number prior to setting any variables
                ** the describe the article type...
                */
                (void) strcpy(wrk,sp);
                if ((dp = strchr(wrk,',')) != NULL)
                    *dp++ = '\0';
                else          /* bad format, bail out... */
                    return;
    
                /*
                ** Now let's position to the type of the posting..
                */
                while((*dp) && (!isalpha(*dp)))
                     ++dp;

                if (!*dp)      /* Is there something there... */
                    return;

                /*
                ** Now it is time to get the Info,Issue,Administrivia,
                ** Information or Source number....
                */
                sp = dp;
            
                do {
                    ++sp;
                } while((*sp) && (!isdigit(*sp)));
 
                if (!*sp)      /* Is there something there... */
                    return;

                /*
                ** We have a seemingly valid Posting-number: line.
                ** Now we can start setting values...
                */
                article.volume = atoi(wrk);
                article.issue = atoi(sp);

                /*
                ** Determine the type of the posting and
                ** set the rectype variable.
                */
                if (strncmp(dp,"Info",4) == 0) 
                    /* covers c.s.u and c.s.a2 as well */
                    article.rectype = INFORMATIONAL;

                if (strncmp(dp,"Administrivia",4) == 0) {
                    if (strcmp(article.newsgroup,"comp.sources.misc") == 0)
                        article.rectype = INFORMATIONAL;
                    else /* comp.sources.apple2 */
                        article.rectype = ADMINISTRATION;
                }
                /*
                ** fill in the volume/issue filename
                */
                if (strcmp(article.newsgroup,"comp.sources.apple2") == 0) {
                    if (article.rectype == INFORMATIONAL) 
                        (void) sprintf(article.filename,"v%3.3dINF%3.3d",
                                          article.volume, article.issue);
                    else if (article.rectype == ADMINISTRATION) 
                            (void) sprintf(article.filename,"v%3.3dADM%3.3d",
                                              article.volume, article.issue);
                    else 
                            (void) sprintf(article.filename,"v%3.3dSRC%3.3d",
                                              article.volume, article.issue);
                }
                else {
                    if (article.rectype == INFORMATIONAL) 
                        (void) sprintf(article.filename,"v%2.2dINF%1.1d",
                                          article.volume, article.issue);
                    else
                        (void) sprintf(article.filename,"v%2.2di%3.3d",
                                        article.volume, article.issue);
                }
            }
        }
        break;

    case SUBMITTED_BY:
        data(header.submitted_by, sizeof(header.submitted_by), "SUBMITTED_BY:", SUBMITTED_BY);
        /* 
        ** Save the author's name and sign on if specified 
        ** Can be in any of the following formats:
	**	kent@sparky.uucp 
	**	kent@sparky.imd.sterling.com (Kent Landfield)
	**	Kent Landfield <kent@sparky.imd.sterling.com>
        */
        if ((sp = strchr(s,':')) != NULL) {
            (void) strcpy(article.author_signon,(sp+2));
            /*
            ** Has a name been attached to the signon ?
            */
            if ((dp = strchr(article.author_signon,'<')) != NULL) {
                *(dp-1) = '\0';
                (void) strcpy(article.author_name, article.author_signon);
                (void) strcpy(article.author_signon, ++dp);
                /*
                ** Save the name, removing the <>.
                */
                if ((dp = strchr(article.author_signon,'>')) != NULL)
                    *dp = '\0';
            }
            else if ((dp = strchr(article.author_signon,'(')) != NULL) {
                *(dp-1) = '\0';
                /*
                ** Save the name, removing the ().
                */
                (void) strcpy(article.author_name, ++dp);
                if ((dp = strchr(article.author_name,')')) != NULL)
                    *dp = '\0';
            }
        }
        break;

    case ARCH_NAME:
        data(header.archive_name,sizeof(header.archive_name),"ARCH_NAME:", ARCH_NAME);
        break;

    case PATCH_TO:
        data(header.patch_to,sizeof(header.patch_to),"PATCH_TO:", PATCH_TO);
        article.rectype = PATCH;        /* set the article type */

        /*
	** Parse the initially posted article's package-name, volume 
        ** and issue.  The format of the auxiliary header is:
        ** 
        ** Patch-To: rkive: Volume 5, Issue 110
        ** Or in the case of multipart initial postings,
        ** Patch-To: rkive: Volume 5, Issue 110-120
        ** Or in the case of multipart non-sequential initial postings,
        ** Patch-To: rkive: Volume 5, Issue 110, 115, 116-120
        **
        */

        /* 
        ** First get the package-name
        */

        dp = strchr(s,':');    /* This exists or we would not be here */
        while ((*++dp == ' ') || *dp == '\t');  /* skip spaces, tabs  */

        sp = dp;
        if ((dp = strchr(sp,':')) != NULL) {
             *dp = '\0';
             /* 
             ** Now let's check to see if the moderator got it right...
             ** Check to assure that a valid archive-name has been 
             ** specified in the Patch-To: line...
             */
             if (strchr(sp,' ') != NULL)  {
                 dp = s;  /* reset to start of string if no package-name */
                 (void) strcpy(article.package_name,"Unknown");
             }
             else 
                 (void) strcpy(article.package_name,sp);
        }
        else {
             dp = s;  /* reset to start of string if no package-name */
             (void) strcpy(article.package_name,"Unknown");
        }
            
        /* 
        ** Next, get the volume number.
        */

        ++dp;
        while (*dp && (!isdigit(*dp)))
              ++dp;
        sp = dp;
        while (*dp && (isdigit(*dp)))
              ++dp;
        *dp = '\0';
        article.patch_volume = atoi(sp);

        /* 
        ** Now get the issue number. 
        ** It is stored as a string but error check that
        ** just numbers, '-' and ',' are in the string.
        */

        ++dp;
        while (*dp && (!isdigit(*dp)))
              ++dp;

        sp = article.patch_issue;
        while (*dp && (isdigit(*dp) || *dp == '-' || 
                         *dp == ',' || *dp == ' ')) {
              if (*dp != ' ')
                  *sp++ = *dp;
              ++dp;
        }
        *sp = '\0';
        break;

    case X_CHECKSUM:
        data(header.x_checksum,sizeof(header.x_checksum),"X_CHECKSUM:", X_CHECKSUM);
        break;

    case ORIGINAL_POSTING_BY:
        data(header.orig_poster,sizeof(header.orig_poster),"ORIGINAL_POSTING_BY:",ORIGINAL_POSTING_BY);
        break;

    case ORIGINAL_SUBJECT:
        data(header.orig_subject,sizeof(header.orig_subject),"ORIGINAL-SUBJECT:",ORIGINAL_SUBJECT);
        break;

    case ARCHIVE_SITE:
        data(header.archive_site,sizeof(header.archive_site),"ARCHIVE_SITE:",ARCHIVE_SITE);
        break;

    case ARCHIVE_DIRECTORY:
        data(header.archive_dir,sizeof(header.archive_dir),"ARCHIVE_DIRECTORY:",ARCHIVE_DIRECTORY);
        break;

    case REPOSTED_BY:
        data(header.reposter,sizeof(header.reposter),"REPOSTED_BY:",REPOSTED_BY);
        break;

    case ARCHITECTURE:
        data(header.architecture,sizeof(header.architecture),"ARCHITECTURE:",ARCHITECTURE);
        break;

    case VERSION_NUMBER:
        data(header.version_number,sizeof(header.version_number),"VERSION_NUMBER:",VERSION_NUMBER);
        break;

    case ARCHIVE_:
        data(header.archive,sizeof(header.archive),"ARCHIVE:",ARCHIVE_);
	break;
    }
    return;
}
