From:	CSBVAX::MRGATE!info-vax-relay@kl.sri.com@SMTP  7-JUN-1988 03:04
To:	ARISIA::EVERHART
Subj:	C-source for BAKWRD/TAIL program


Received: from CORNELLC.CCS.CORNELL.EDU by KL.SRI.COM with TCP; Tue 31 May 88 04:39:08-PDT
Received: from HWALHW50.BITNET by CORNELLC.CCS.CORNELL.EDU ; Tue, 31 May 88 07:15:40 EDT
Date:     Tue, 31 May 88 12:35 N
From:     <BOL%HWALHW50.BITNET@CORNELLC.CCS.CORNELL.EDU>
Subject:  C-source for BAKWRD/TAIL program
To:       info-vax@kl.sri.com
X-Original-To:  info-vax@kl.sri.com, BOL

Because of the many requests for a copy of the BAKWRD/TAIL program
I decided to send it to INFO-VAX.


The program consists of the sources

    BAKWRD.C, TYPRFM1.C, TYPRFM2.C, TYPRFM3.C, TYPRFM5.C and RMSIO.C

and the includefiles

    BAKWRD.H and RMSIO.H

It should be linked by the command

    LINK BAKWRD,TYPRFM1,TYPRFM2,TYPRFM3,TYPRFM5,RMSIO,SYS$LIBRARY:VAXCRTL/LIB

 ......................................... BAKWRD.C
/*
    Program BAKWRD

    Programmed by C.J. BOL, Agricultural University Wageningen.
        bitnet: BOL@HWALHW50
        surf:   LUWRVD::BOL
        phone:  (+31) 08370-84715

    This program reads a file, starting at the fileend, n records
    at the time. So BAKWRD file/10 gives you groups of 10 records in
    correct order, starting with the last 10 records in the file.

    Not supported are relative, indexed and hashed files.

    $ BAKWRD == "$DEV:[USER]BAKWRD "
    $ BAKWRD [file[/n]]

*/
#define MAIN
#include stdio
#include "bakwrd.h"

main(argc,argv)char *argv[];{
        int *rmsopen(),i,j,n,blk;
        char *pc,fnam[100];

        *fnam = 0;
        if(argc>2) {
            printf("\007Only one argument permitted\n");
            exit();
        }
        if(argc==2)
            strcpy(fnam,argv[1]);

        do{
            jrec     = MAXREC;
            pergroep = groep = 1;
            inrec    = nline = 0;
            if(argc!=2){
                printf("\nfile[/n] >");
                if(!gets(fnam))
                    exit();
            }
            for(i=j=0; fnam[i] ; i++)
                if(fnam[i]>' ')
                    fnam[j++] = toupper(fnam[i]);
            fnam[j] = 0;

            if(*fnam == 0)
                exit();

            if(pc = strchr(fnam,'/')){
                *pc++ = 0;
                pergroep = atoi(pc);
            }

            if(!(fh = rms_open(fnam))){
                printf("?Cannot open [%s]\n",fnam);
                continue;
            }
            rms_info(fh,"fop org rat rfm mrs alq ebk ffb fsz",
                &fop,&org,&rat,&rfm,&mrs,&alq,&ebk,&ffb,&fsz);

            switch(org){
                case 0:  break;
                case 16: printf("\n\007Relative files not supported!\n");
                         continue;
                case 32: printf("\n\007Indexed files not supported!\n");
                         continue;
                case 48: printf("\n\007Hashed files not supported!\n");
                         continue;
                default: printf("\n\007Only sequential files are supported!\n");
                         continue;
            }

            filesize = (ebk-1)*512 + ffb;       /* filesize in char     */

            if(pergroep <= 0)
                pergroep = 1;
            else{
                if(mrs<=0)
                    mrs = 255;
                if(pergroep*mrs > MAXREC-pergroep) {
                    pergroep = MAXREC/(mrs+1);
                    if(pergroep==0){
                       printf("\n? Max. recordsize=%d is too big!\n",mrs);
                       rms_close(fh);
                       continue;
                    }
                    printf("\n\007Groupsize modified, now %d\n",pergroep);
                }
            }

            blk   = ebk - (ffb ? 0:1);
            blok1 = blok2 = delim = 0;
            switch(rfm){
                case 1 : typrfm1(blk); break;  /* FIXED LENGTH          */
                case 2 : typrfm2();    break;  /* VAR                   */
                case 3 : typrfm3(blk); break;  /* VAR+FIXEDLENGTHCONTROL*/
                case 5 :                       /* STREAM (LF)           */
                case 6 : typrfm5(blk); break;  /* ..     (CR)           */
                default:
                        printf("\nNot supported record format rfm=%d",rfm);
            }
        }while(argc!=2);
}

addc(c)char c;{
    if(inrec==0 &&(c==' ' || c== '\t')) return; /* skip trailing blanks */
    rec[--jrec] = (c==delim? '\n' : c);
    inrec++;
    if(c == delim)
        if(++nline >= pergroep){
            if(pergroep > 1)
                 printf("\n\033[7m group %6d    \033[0m",groep++);
            fwrite(rec+jrec,inrec,1,stdout);
            inrec = nline = 0;
            jrec     = MAXREC;
        }
}
  ...............................................RMSIO.C
#include "rmsio.h"
int status,n;

int rms_open(fnam)
char *fnam;
{

        FILE_HEADER *fh;

        fh = malloc(SFH);
        fh->fab = cc$rms_fab;           fh->rab = cc$rms_rab;
        fh->nam = cc$rms_nam;           fh->all = cc$rms_xaball;
        fh->dat = cc$rms_xabdat;        fh->fhc = cc$rms_xabfhc;
        fh->key = cc$rms_xabkey;        fh->pro = cc$rms_xabpro;
        fh->rdt = cc$rms_xabrdt;        fh->sum = cc$rms_xabsum;

        koppel(fh);
        fh->fab.fab$b_fac = FAB$M_GET | FAB$M_BIO;
        fh->fab.fab$l_fna = fnam;
        fh->fab.fab$b_fns = strlen(fnam);

        status = sys$open(&fh->fab);

        if(status != RMS$_NORMAL){
            return(0);
            if(status == RMS$_FNF)
                printf("\n?file not found\n");
            else{
                printf("\nError with file %s",fnam);
                exit(status);
            }
            return(0);
        }
        else{
            status = sys$connect(&fh->rab);
            if(status != RMS$_NORMAL){
                printf("\nConnect failed for file %s",fnam);
                exit(status);
            }
                return(fh);
        }
}

koppel(fh)
FILE_HEADER *fh;{
        fh->fab.fab$l_nam = &fh->nam;   fh->fab.fab$l_xab = &fh->all;
        fh->all.xab$l_nxt = &fh->key;   fh->key.xab$l_nxt = &fh->fhc;
        fh->fhc.xab$l_nxt = &fh->dat;   fh->dat.xab$l_nxt = &fh->pro;
        fh->pro.xab$l_nxt = &fh->rdt;   fh->rdt.xab$l_nxt = &fh->sum;
        fh->sum.xab$l_nxt = 0;
        fh->rab.rab$l_fab = &fh->fab;
}

rms_close(fh)
FILE_HEADER *fh;{
        if(fh){
            status = sys$close(&fh->fab);
            if(status != RMS$_NORMAL)
                exit(status);
            free((char *) fh);
        }
}

shortcpy(a,b,n)short *a,*b;{
        while(n--){
            *a++ = *b++;
        }
}

int bio_read(fh,buf,lbuf,blknr)
FILE_HEADER *fh;
char *buf;{
        int n;

        fh->rab.rab$l_ubf = buf;
        fh->rab.rab$w_usz = lbuf;
        fh->rab.rab$b_rac = RAB$M_BIO;
        if(blknr)fh->rab.rab$l_bkt = blknr;

        status = sys$read(&fh->rab);
        n      = fh->rab.rab$w_rsz;
        if(status == RMS$_NORMAL)
            return(n);
        if(status == RMS$_EOF)
            return(-1);
        else
            exit(status);
}

rms_info(fh,s,x)
FILE_HEADER *fh;
char *s;{
        int **px,i,j,k;
        char item[10];
        for(px = &x, i = 0; *s ; i++){
            while(*s == ' ' && *s)              /* skip noise   */
                s++;
            for(j=0; *s && *s > ' ' ; item[j++] = *s++);
            item[j] = 0;
            **px++ = k = get_item(fh,item);
        }
}

int get_item(fh,s)
FILE_HEADER *fh;
char *s;{
        if(!strcmp("org",s)) return(fh->fab.fab$b_org);
        if(!strcmp("fop",s)) return(fh->fab.fab$l_fop);
        if(!strcmp("rat",s)) return(fh->fab.fab$b_rat);
        if(!strcmp("rfm",s)) return(fh->fab.fab$b_rfm);
        if(!strcmp("mrs",s)) return(fh->fhc.xab$w_lrl);
        if(!strcmp("alq",s)) return(fh->fab.fab$l_alq);
        if(!strcmp("fsz",s)) return(fh->fab.fab$b_fsz);

        if(!strcmp("ebk",s)) return(fh->fhc.xab$l_ebk);
        if(!strcmp("ffb",s)) return(fh->fhc.xab$w_ffb);
        printf("\n?Not supplied %s",s);
}
  ............................................... typrfm1.c
#include "bakwrd.h"
typrfm1(blk){                   /* FIXED length records */
        delim = '\n';
        switch(rat){
            case 2 : rfm1rat2(blk); break;
            default: rfm1ratx(blk);
        }
}
rfm1rat2(blk){                  /* FIXED length rec, add CR */
        int i,n,l;
        unsigned char c;

        blk++;

        for(l = mrs; blk>1  ; ){
            blk = blk-MAXBLOK>0 ? blk-MAXBLOK : 1;
            n = BIO_READ(fh,buf,MAXBUF,blk);

            for(i=n; --i >= 0 ;){
                addc(buf[i]);
                if(--l == 0){
                    addc(delim);
                    l = mrs;
                }
            }
        }
        nline = pergroep+1;
        addc(delim);
        rms_close(fh);
}
rfm1ratx(blk){                  /* FIXED length rec, CR in data */
        int i,n,l;
        unsigned char c;

        blk++;

        for(l = mrs; blk>1  ; ){
            blk = blk-MAXBLOK>0 ? blk-MAXBLOK : 1;
            n = BIO_READ(fh,buf,MAXBUF,blk);
            for(i=n; --i >= 0 ;){
                addc(buf[i]);
                if(--l == 0){
                    addc(delim);
                    l = mrs;
                }
            }
        }

        nline = pergroep+1;
        addc(delim);
        rms_close(fh);
}
  ............................................... typrfm2.c
#include "bakwrd.h"

typrfm2(){                              /* VARIABLE length      */
        int file_eind,vorige_begin,nieuwe_begin;

        blok1 = blok2 = 0;

        file_eind = (filesize+1)/2;     /* adres van laatste short in file */

        for(vorige_begin = file_eind+1 ; ; vorige_begin = nieuwe_begin){

            nieuwe_begin = zoek_terug(1,vorige_begin,0);
            if(nieuwe_begin == vorige_begin || nieuwe_begin == 0)
                break;

            switch(rat){                /* don't mind bit 3 and up */
                case 0: pri_rec(nieuwe_begin,0);        /* "none"       */
                         addc(delim);
                         break;
                case 1: pri_rec(nieuwe_begin,1);        /* "fortran"    */
                         addc(delim);
                         break;
                case 2: pri_rec(nieuwe_begin,2);        /*  "list"      */
                         addc(delim);
                         break;

                default: printf("\nRFM=2, RAT=%d not supported!\n",rat);
            }
        }
        nline = pergroep+1;
        addc(delim);
        rms_close(fh);
}
int zoek_terug(n,vorige_begin,intest){
        unsigned short read_short();
        int recls,mrss,begin,begin1,l;
        if(vorige_begin <= 1 || n == 0){
            return(vorige_begin);
        }

        recls = 0;                      /*     recordlength in shorts */
        mrss  = (mrs+1)/2;              /* max.   ,,           ,,     */
        if(mrss == 0) mrss = 200 > filesize ? filesize:200;
        begin = vorige_begin-1;

        for(; begin > 0 && recls <= mrss+1; recls++, begin--){
            l = read_short(begin);
            if((l+1)/2 == recls){
                if(intest) return(1);
                if(zoek_terug(2,begin,1))   /* test if record ok        */
                    return(begin);
            }
        }
        return(0);
}
pri_rec(begin,rat)int rat;{
        unsigned short read_short();
        int ie,recl;
        char read_char();

        ie = 2*begin+ (recl = read_short(begin));
        if(rat == 0 && read_char(ie) == '\n'){
            recl--;
            ie--;
        }
        if(rfm == 3) recl -= fsz;       /* correction for VFC           */
                                        /* if fixed length control      */
        for(; recl ; recl--)
            addc(read_char(ie--));
}

char read_char(nr){
        int bloknr,i;

        if((bloknr = (nr+511)/512) < blok1 || bloknr > blok2){
            blok2 = bloknr+1;
            blok1 = blok2-MAXBLOK+1;
            BIO_READ(fh,&file_blok,MAXBUF,blok1 = blok1 > 0 ? blok1 : 1);
        }
        return( file_blok.blokc[nr-(blok1-1)*512 - 1]);
}
unsigned short read_short(nr){
        int bloknr,i;
        if((bloknr = (nr+255)/256) < blok1 || bloknr > blok2){
            blok2 = bloknr+1;
            blok1 = blok2-MAXBLOK+1;
            BIO_READ(fh,&file_blok,MAXBUF,blok1 = blok1 > 0 ? blok1 : 1);
        }
        return( file_blok.bloks[nr-(blok1-1)*256 - 1]);
}
  ............................................... typrfm3.c
#include "bakwrd.h"

typrfm3(){                      /* VARIABLE length FIXED-length control  */
        int file_eind,vorige_begin,nieuwe_begin;

        blok1 = blok2 = 0;
        mrs   = mrs+fsz;                /* correction for fixed-length-control*/
        file_eind = (filesize+1)/2;     /* last short in file   */

        for(vorige_begin = file_eind+1 ; ; vorige_begin = nieuwe_begin){
            nieuwe_begin = zoek_terug(1,vorige_begin,0);
            if(nieuwe_begin == vorige_begin || nieuwe_begin == 0)
                break;

            switch(rat){
                case 4: pri_rec(nieuwe_begin,4);        /*  "list"      */
                         addc(delim);
                         break;
                default: printf("\nRFM=3, RAT=%d not supported!\n",rat);
            }
        }
        nline = pergroep+1;
        addc(delim);
        rms_close(fh);
}
  ............................................... typrfm5.c
#include "bakwrd.h"

typrfm5(blk){                           /* STREAM records       */
        if(rfm==5) delim = '\n';        /* delimited by LF      */
        if(rfm==6) delim = '\r';        /* ..           CR      */
        rfm5(blk);
}
rfm5(blk){                              /* STREAM CR/LF in data */
        int i,n,l;
        unsigned char c;

        blk++;
        for(l = mrs; blk>1 ;){
            blk = blk-MAXBLOK > 0 ? blk-MAXBLOK : 1;
            n = BIO_READ(fh,buf,MAXBUF,blk);
            for(i=n; --i >= 0 ;){
                addc(buf[i]);
            }
        }
        nline = pergroep+1;
        addc(delim);
        rms_close(fh);
}
  ............................................... bakwrd.h
#ifdef MAIN
#define extern
#endif

#define MAXBLOK 10
#define MAXBUF MAXBLOK*512
#define MAXREC 30000            /* ruimte voor "pergroep" records       */
#define toupper(c) (c>='a' && c<='z' ? c-'a'+'A' : c)

extern int ebk,ffb,alq,bls,deq,fop,org,mbc,mbf,mrs,rat,rfm,nblok,fsz;
extern int *fh,fase,jrec,inbuf,filesize,obkt,nline,pergroep,groep,inrec;
extern int blok1,blok2;

extern char delim,rec[MAXREC+1];
extern unsigned char buf[MAXBUF+1];

union blok {
        char blokc[MAXBUF];
        unsigned short bloks[MAXBUF/2];
} file_blok;
  ............................................... rmsio.h
#include rms
typedef struct {
        struct FAB fab;
        struct RAB rab;
        struct NAM nam;
        struct XABALL all;
        struct XABKEY key;
        struct XABDAT dat;
        struct XABFHC fhc;
        struct XABPRO pro;
        struct XABRDT rdt;
        struct XABSUM sum;} FILE_HEADER;

#define SFH sizeof(FILE_HEADER)
char *malloc();
  ............................................... that's all









 ------------------------------------------------------------------------------
                |\
                | |             Kees Bol
                | |  _                      Bitnet : BOL@HWALHW50
                | | / \                     Surf   : LUWRVD::BOL
                | |/  |                     Phone  : (+31) 08370-84715
                |   /||  /\
                 \_/ || / /
                     ||/ /
W A G E N I N G E N  |  /     A G R I C U L T U R A L   U N I V E R S I T Y
                     \_/
                        T H E   N E T H E R L A N D S
-------------------------------------------------------------------------------
