ftp.nice.ch/pub/next/developer/hardware/dsp/drbub/srec.tar.gz#/srec/srec.c

This is srec.c in view mode; [Download] [Up]

#include <stdio.h>

#include <ctype.h>

#include <signal.h>

#include <setjmp.h>

#include "srec.h"



/*

        NAME

                srec - convert DSP56000 load file records to Motorola

                       S-record format



        SYNOPSIS

                srec [-1 | -3 | -r] <input file ... >



        DESCRIPTION

                Srec takes as input a DSP56000 absolute load file and produces

                byte-wide Motorola S-record files suitable for PROM burning.

                The DSP56000 START and END records are mapped into S0 and

                S9 records respectively.  All other DSP56000 record types

                are mapped into S1-type records (SYMBOL and COMMENT records

                are currently ignored).  Since the DSP56000 uses a 24-bit

                word size, the words must be split into bytes and stored in

                an appropriate format.  In the default mode of operation the

                program writes the low, middle, and high bytes of each word

                consecutively to the current S1 record being written.  For

                example, given the DSP56000 DATA record below:



                                address field

                                |

                        _DATA P 0000

                        0008F8 300000 340000 094E3E

                        |      |      |      |

                        |      |      |      fourth word

                        |      |      third word

                        |      second word

                        first word



                srec would create the following S1 record:



                          byte count field

                          | address  field              checksum field

                          | |                           |

                        S10D0000F808000000300000343E4E09F9

                                |     |     |     |

                                |     |     |     fourth word

                                |     |     third word

                                |     second word

                                first word



                Output records are written to a file named according to

                the following convention:



                        <basename>.M



                where <basename> is the filename of the input load file

                without extension and M is the memory space specifier

                (X, Y, L, or P) for this set of data words.  Note that a

                separate file is created for each memory space encountered

                in the input file; thus the maximum number of output files

                in the default mode is 4.



                When the -3 option is specified, srec splits each 24-bit

                word into bytes and stores the bytes in three parallel S1

                records.  For example, the following DSP56000 DATA record:



                                address field

                                |

                        _DATA P 0000

                        0008F8 300000 340000 094E3E

                        |      |      |      |

                        |      |      |      fourth word

                        |      |      third word

                        |      second word

                        first word



                would be converted by srec into the three S1 records below:



                          byte count field

                          | address  field

                          | |

                        S1070000F800003EC2 -- low  byte

                        S10700000800004EA2 -- mid  byte

                        S1070000003034098B -- high byte

                                | | | | |

                                | | | | checksum field

                                | | | fourth word

                                | | third word

                                | second word

                                first word



                The three records corresponding to the high, middle, and

                low bytes of each data word are written to separate files.

                The files are named according to the following convention:



                        <basename>.<M><#>



                where <basename> is the filename of the input load file

                without extension, <M> is the memory space specifier

                (X, Y, L, or P) for this set of data words, and # is

                one of the digits 0, 1, or 2 corresponding to low, middle,

                and high bytes, respectively.



                Note that a separate set of byte-wide files is created for

                each memory space encountered in the input file.  Thus the

                number of output files generated is (number of memory spaces

                in input * 3).  The maximum number of output files generated

                with the -3 option is 12.



                The -1 option writes all information to a single file,

                storing the memory space information in the address field

                of the S0 header record.  The values stored in the address

                field and their correspondence to the DSP56000 memory

                spaces are as follows:



                        Value           DSP56000 Memory Space

                        -----           ---------------------

                          1                     X

                          2                     Y

                          3                     L

                          4                     P



                When the memory space changes in the DATA or BLOCKDATA

                record, a new S0 header record is generated.  The resulting

                output file is named <basename>.s, where <basename> is

                the filename of the input load file without extension.

                The -1 and -3 options are mutually exclusive.



                The -r option causes srec to produce the same type of output

                as the default mode, except that the bytes are written high

                to low, rather than low to high.



                Address fields in the DSP56000 records are two bytes and

                are copied as is to the appropriate S1 record (except for

                incrementing as necessary in very long DATA records).  Only

                the module id in the START record is passed as header data

                for the S0 record; the version number, revision number, and

                comment are ignored.



        NOTES

                One (and only one) of the operating system DEFINEs below

                must be activated to obtain appropriate conditional

                compilation.  This can be done either directly in the source

                by changing the 0 DEFINE for the desired operating system

                to a 1, or via the compiler command line (ex. -DATT=1).

                Note that the UNIX flag is simply a logical ORing of the

                more specific Unix OS flags (ATT and BSD) and thus should

                not be specified explicitly.



        OPTIONS

                -1      - write data to a single file, putting memory

                          space information into the address field of the

                          S0 header record. Bytes may be reversed with

                          the -r option.  The -1 and -3 options are

                          mutually exclusive.

                -3      - split each 24-bit word into bytes and store

                          the bytes in three parallel S1 records.   The

                          -1 and -3 options are mutually exclusive.

                -r      - produce the same type of output as default mode,

                          but write bytes high to low, rather than low to

                          high.  to low, rather than low to high.



        DIAGNOSTICS

                The program does some checking for invalid input record

                formats, memory spaces, and hex values.  It obviously

                cannot check for bad data values if the load file has

                been tampered with.  Both START and END records must be

                found in the input file.



        HISTORY

                1.0     The beginning.

                1.1     Added code to support new default mode and -r

                        option (-3 was old default mode).

                1.2     Added support for ATT Unix System V.

                1.3     Fix for bug in default mode where S-record address

                        was not being computed correctly (e.g. not a byte

                        multiple of the 56000 word size).

                1.4     Added support for Macintosh II.

                1.5     Added separate include file, getopt () support,

                        -1 (single output file) option.

                1.6     Fix for bug in default mode when handling BLOCKDATA

                        records; repeated call to reverse bytes was reversing

                        bytes in place!

*/





char *optarg = NULL;                    /* command argument pointer */

optind = 0;                             /* command argument index */



char Progdef[] = "srec";                /* program default name */

char *Progname = Progdef;               /* pointer to program name */

static char *ifname;                    /* pointer to input file name */

static FILE *ifile = NULL;              /* file pointer for input file */

static opt1 = NO;                       /* 1 file option flag */

static opt3 = NO;                       /* 3 file option flag */

static optrev = NO;                     /* reverse byte option flag */

static unsigned linecount = 1;          /* input file line count */

static char fldbuf[MAXSTR] = {EOS};     /* OMF field buffer */

static char strbuf[MAXSTR] = {EOS};     /* Global string buffer */

static char s0[MAXSTR];                 /* S0 record string */

static char s0str[MAXSTR];              /* S0 string buffer */

static unsigned s0cnt = 1;              /* S0 byte count */

static unsigned s0addr = 0;             /* S0 address */

static unsigned s0sum = 0;              /* S0 checksum */



/*

        pointers to S-record structure arrays

*/

static struct srec *rec[] = {NULL, NULL, NULL, NULL};



extern char *calloc (), *malloc ();

#if BSD

extern char *index (), *rindex ();

#else

extern char *strchr (), *strrchr ();

#endif

char *strup ();

#if LSC

jmp_buf Env;

#endif





#if !LSC

main (argc, argv)

#else

_main (argc, argv)

#endif

int argc;

char *argv[];

{

#if BSD

        int onintr (), onsegv ();

#else

        void onintr (), onsegv ();

#endif

        int c;

        char *p, *q;

        char *basename(), *getenv();

        char *fix_fname ();



/*

        set up for signals; get prog. name, check for command line options

*/



#if MPW || AZTEC

        (void)sigset (SIGINT, onintr);  /* set up for signals */

#else

        (void)signal (SIGINT, onintr);  /* set up for signals */

#endif

        p = basename (argv[0]); /* get command base name */

        if ((q = strrchr (p, '.')) != NULL)

                *q = EOS;

#if VMS

        if ((q = strrchr (p, ';')) != NULL)

                *q = EOS;

#endif

#if MSDOS

        if (_osmajor > 2)

#endif

                Progname = p;



        optarg = NULL;          /* command argument pointer */

        optind = 0;             /* command argument index */

        if (argc < 2)           /* not enough arguments */

                usage ();

        while ((c = getopt (argc, argv, "13r?")) != EOF) {

                switch (c) {

                case '1':       opt1 = YES;

                                break;

                case '3':       opt3 = YES;

                                break;

                case 'r':       optrev = YES;

                                break;

                case '?':

                default:        usage ();

                                break;

                }

                if (optind >= argc)     /* no more args? error */

                        usage ();

        }



/*

        reset argument vector and count

*/



        argc -= optind;                 /* adjust argument count */

        argv = argv[optind];           /* reset argv pointer */

        if (argc < 1 || (opt1 & opt3))

                usage ();



/*

        loop to process files

*/



        while (argc--) {



                ifname = fix_fname (*argv);     /* fix file name */

                if (!(ifile = fopen (ifname, "r")))

                        error2 ("cannot open input file %s", ifname);

                if ((p = strrchr (ifname, '.')) != NULL)

                        *p = EOS;               /* strip extension */



                do_srec ();                     /* process records */



                fclose (ifile);                 /* close input file */

                free (ifname);                  /* free file name */

                argv++;                         /* bump argument pointer */

        }

#if LSC

        return (OK);

#else

        exit (OK);

#endif

}





static

do_srec ()              /* process load file records */

{

        if (!get_start ())              /* no START record */

                error ("no START record");



        for (;;) {                      /* loop forever */



                switch (get_record ()) {

                case START:

                        error ("duplicate START record");

                case END:

                        get_end ();

                        return;

                case DATA:

                        get_data ();

                        break;

                case BDATA:

                        get_bdata ();

                        break;

                case COMMENT:

                        get_comment ();

                        break;

                case SYMBOL:

                        fldbuf[0] = EOS; /* skip  SYMBOL records */

                        break;

                default:

                        if (feof (ifile))

                                error ("no END record");

                        else

                                error ("invalid record type");

                        break;

                }

        }

}





static

get_start ()            /* process START record */

{

        int type;

        char *fbp = fldbuf;

        char *sbp = s0str;



/*

        locate START record

*/



        while ((type = get_record ()) != EOF & type != START)

                ;



        if (type != START)

                return (NO);



/*

        get program name; loop to put into header string

*/



        if (get_field () < 0)           /* pick up program name */

                error ("invalid START record");



        while (*fbp) {

                sprintf (sbp, "%02x", *fbp);

                s0sum += (unsigned)(*fbp++  0xff);

                sbp += 2;

                s0cnt++;

        }



/*

        build S0 record; read past comment

*/



        bld_s0 ((unsigned)NONE);



        if ( (get_field () < 0) ||      /* skip version number */

             (get_field () < 0) ||      /* skip revision number */

             (get_comment () < 0) )     /* skip comment */

                error ("invalid START record");



        if (opt1)                       /* single file option */

                open_files (NONE);



        return (YES);

}





static

get_record ()           /* look for next record in OMF input */

{

        int field = 0;

        char *fbp = fldbuf + 1;



        while (fldbuf[0] != NEWREC & (field = get_field ()) == 0)

                ;



        if (field < 0)

                return (field);



        if (strcmp (fbp, "DATA") == 0)

                return (DATA);

        if (strcmp (fbp, "BLOCKDATA") == 0)

                return (BDATA);

        if (strcmp (fbp, "START") == 0)

                return (START);

        if (strcmp (fbp, "END") == 0)

                return (END);

        if (strcmp (fbp, "SYMBOL") == 0)

                return (SYMBOL);

        if (strcmp (fbp, "COMMENT") == 0)

                return (COMMENT);



        return (NONE);

}





static

get_data ()             /* process DATA records */

{

        int space, i;

        unsigned addr, count = OVRHD;

        struct srec *drec;



        if (get_field () < 0)           /* pick up memory space */

                error ("invalid DATA record");



        if ((space = get_space ()) < 0)

                error ("invalid memory space specifier");



        if (opt1) {                     /* single file option */

                i = space + 1;

                space = NONE;

                if (s0addr != (unsigned)i) {

                        bld_s0 ((unsigned)(i));

                        fputs (s0, rec[0]->fp);

                        s0addr = (unsigned)i;

                }

        } else

                if (!rec[space])        /* see if files are open */

                        open_files (space);



        if (get_field () < 0)           /* read in address field */

                error ("invalid DATA record");

        if (!fldhex ())

                error ("invalid address value");

        sscanf (fldbuf, "%x", addr);   /* convert address */

        if (addr > MAXADDR)

                error ("address value too large");

        if (!opt3)

                addr *= WSIZE;          /* adjust address for serial bytes */



/*

        initialize data record fields

*/



        for (i = 0, drec = rec[space]; i < (opt3 ? WSIZE : 1); i++, drec++) {

                drec->checksum = 0;

                drec->p = drec->buf;

        }



/*

        loop to pick up data

*/



        while (get_field () == 0) {     /* get next data field */



                if (strlen (fldbuf) != WSIZE * 2)

                        error ("improper number of bytes in word");

                if (!fldhex ())

                        error ("invalid data value");

                if (!optrev & !opt3)

                        rev_bytes ();

                get_bytes (space);      /* extract bytes from field */



/*

        if max record count reached, print out current record

*/



                count += opt3 ? 1 : WSIZE;

                if (count >= MAXBYTE + OVRHD) {

                        flush_rec (space, addr, count);

                        addr += count - OVRHD;

                        count = OVRHD;

                }

        }



/*

        new record or EOF encountered; flush out current record

*/



        if (rec[space]->p != rec[space]->buf)

                flush_rec (space, addr, count);

}





static

get_bdata ()            /* process BLOCKDATA records */

{

        int space, i, j;

        unsigned addr, repeat, count = OVRHD;

        struct srec *drec;



        if (get_field () < 0)           /* pick up memory space */

                error ("invalid BLOCKDATA record");



        if ((space = get_space ()) < 0)

                error ("invalid memory space specifier");



        if (opt1) {                     /* single file option */

                i = space + 1;

                space = NONE;

                if (s0addr != (unsigned)i) {

                        bld_s0 ((unsigned)(i));

                        fputs (s0, rec[0]->fp);

                        s0addr = (unsigned)i;

                }

        } else

                if (!rec[space])        /* see if files are open */

                        open_files (space);



        if (get_field () < 0)           /* read in address field */

                error ("invalid BLOCKDATA record");

        if (!fldhex ())

                error ("invalid address value");

        sscanf (fldbuf, "%x", addr);   /* convert address */

        if (addr > MAXADDR)

                error ("address value too large");

        if (!opt3)

                addr *= WSIZE;          /* adjust address for serial bytes */



        if (get_field () < 0)           /* read in repeat field */

                error ("invalid BLOCKDATA record");

        if (!fldhex ())

                error ("invalid count value");

        sscanf (fldbuf, "%x", repeat); /* save repeat value */



        if (get_field () < 0)           /* read in value field */

                error ("invalid BLOCKDATA record");

        if (!fldhex ())

                error ("invalid data value");

        if (strlen (fldbuf) != WSIZE * 2)

                error ("improper number of bytes in word");

        if (!fldhex ())

                error ("invalid data value");

        if (!optrev & !opt3)

                rev_bytes ();



/*

        initialize data record fields

*/



        for (i = 0, drec = rec[space]; i < (opt3 ? WSIZE : 1); i++, drec++) {

                drec->checksum = 0;

                drec->p = drec->buf;

        }



/*

        loop to generate data records

*/



        for (j = 0; j < repeat; j++) {



                get_bytes (space);      /* extract bytes from field */



/*

        if max record count reached, print out current record

*/



                count += opt3 ? 1 : WSIZE;

                if (count >= MAXBYTE + OVRHD) {

                        flush_rec (space, addr, count);

                        addr += count - OVRHD;

                        count = OVRHD;

                }

        }



/*

        new record or EOF encountered; flush out current record

*/



        if (rec[space]->p != rec[space]->buf)

                flush_rec (space, addr, count);

}





static

get_end ()              /* process END record, clean up, and exit */

{

        int i, field, space;

        unsigned count = 1;     /* always a checksum byte */

        unsigned addr, checksum = 0;

        struct srec *drec;



        if ((field = get_field ()) > 0) /* try to get address field */

                error ("invalid END record");



        if (field == 0) {

                if (!fldhex ())

                        error ("invalid address value");

                sscanf (fldbuf, "%x", addr);   /* convert address */

                if (addr > MAXADDR)

                        error ("address value too large");

                if (!opt3)

                        addr *= WSIZE;  /* adjust address for serial bytes */

                checksum = (unsigned)sum_addr (addr);

                count = OVRHD;

        }



        for (space = 0; space < (opt1 ? 1 : MSPACES); space++) {

                if (rec[space]) {

                        for (i = 0, drec = opt1 ? rec[0] : rec[space];

                             i < (opt3 ? WSIZE : 1); i++, drec++) {

                                sprintf (strbuf, "S9%02x%s%02x\n",

                                         count,  field == 0 ? fldbuf : "",

                                         ~(checksum + count)  0xff);

                                fputs (strup (strbuf), drec->fp);

                                fclose (drec->fp);

                        }

                        free (rec[space]);

                        rec[space] = NULL;

                }

        }

}





static

sum_addr (addr)         /* sum bytes of address */

unsigned addr;

{

        return ((addr  0xff) + ((addr >> 8)  0xff));

}





static

get_bytes (space)       /* move bytes from field buffer into record buffer */

int space;

{

        int i, j;

        register char *fbp, *p;

        struct srec *drec;



        fbp = fldbuf;

        /* loop to move bytes, sum for checksum */

        for (i = 0, drec = rec[space]; i < WSIZE; i++, drec += opt3 ? 1 : 0) {

                p = drec->p;

                *p++ = *fbp++;

                *p++ = *fbp++;

                *p = EOS;

                sscanf (drec->p, "%x", j);

                drec->checksum += (unsigned)j;

                drec->p = p;

        }

}





static

flush_rec (space, addr, count)  /* flush S1 record to the appropriate file */

int space;

unsigned addr, count;

{

        int i;

        struct srec *drec;



        for (i = 0, drec = rec[space]; i < (opt3 ? WSIZE : 1); i++, drec++) {

                drec->checksum += (unsigned)sum_addr (addr);

                sprintf (strbuf, "S1%02x%04x%s%02x\n",

                         count, addr, drec->buf,

                         ~(drec->checksum + count)  0xff);

                fputs (strup (strbuf), drec->fp);

                drec->checksum = 0;

                drec->p = drec->buf;

        }

}





static

rev_bytes ()            /* reverse the bytes in fldbuf */

{

        char c;



        c = fldbuf[0];

        fldbuf[0] = fldbuf[4];

        fldbuf[4] = c;

        c = fldbuf[1];

        fldbuf[1] = fldbuf[5];

        fldbuf[5] = c;

}





static

open_files (space)      /* open S-record ouput files */

int space;

{

        struct srec *drec;

        char fn[MAXSTR], *p;

        register i;

        char c;



/*

        allocate S-record structure array; construct output file name

*/



        if ((drec = (struct srec *)calloc (opt3 ? WSIZE : 1, sizeof (struct srec))) == NULL)

                error ("cannot allocate S-record structure");

        rec[space] = drec;              /* squirrel pointer away */

        c = opt1 ? 's' : fldbuf[0];

        sprintf (fn, "%s.%c", ifname, isupper (c) ? tolower (c) : c);

        p = fn + strlen (fn);



/*

        loop to open all files, write out S0 record

*/



        if (!opt3) {            /* don't need three files */

                if ((drec->fp = fopen (fn, "w")) == NULL)

                        error2 ("cannot open output file %s", fn);

                if (!opt1)

                        fputs (s0, drec->fp);

        } else

                for (i = WSIZE - 1, rec[space] = drec; i >= 0; i--, drec++) {

                        *p = (char)(i + '0');

                        *(p + 1) = EOS;

                        if ((drec->fp = fopen (fn, "w")) == NULL)

                                error2 ("cannot open output file %s", fn);

                        fputs (s0, drec->fp);

                }

}





static

get_field ()            /* get next OMF field from ifile; put in fldbuf */

{

        register c;

        register char *p;



        while ((c = fgetc (ifile)) != EOF & isspace (c))

                if (c == '\n')

                        linecount++;



        if (c == EOF)                   /* end of object file */

                return (EOF);



        for (p = fldbuf, *p++ = c;      /* loop to pick up field value */

             (c = fgetc (ifile)) != EOF & !isspace (c);

             *p++ = c)

                ;



        *p = EOS;                       /* null at end of value */

        if (c != EOF)

                ungetc (c, ifile);      /* put back last char. if not EOF */



        return (*fldbuf == NEWREC ? 1 : 0);/* let caller know if new record */

}





static

get_comment ()          /* get comment from OMF file; put in fldbuf */

{

        register c;

        register char *p;



        while ((c = fgetc (ifile)) != EOF & c != '\n' & isspace (c))

                ;                       /* skip white space (except newline) */



        if (c == EOF || c != '\n')      /* end of file or synch error */

                return (EOF);



        linecount++;

        for (p = fldbuf; (c = fgetc (ifile)) != EOF & c != '\n'; *p++ = c)

                ;                       /* loop to pick up comment */

        if (c == '\n')

                linecount++;



        *p = EOS;                       /* null at end of comment */



        return (0);                     /* good return */

}





static

bld_s0 (space)

unsigned space;

{

        sprintf (s0, "S0%02x%04x%s%02x\n",

                s0cnt, space, s0str, ~(s0sum + s0cnt + space)  0xff);

        strup (s0);

}





static

get_space ()                    /* return memory space attribute */

{

        switch (fldbuf[0]) {

        case 'X':

        case 'x':

                return (XMEM);

        case 'Y':

        case 'y':

                return (YMEM);

        case 'P':

        case 'p':

                return (PMEM);

        case 'L':

        case 'l':

                return (LMEM);

        default:

                return (-1);

        }

}





static char *

fix_fname (fname)               /* add extension to file name if reqd */

char *fname;

{

        int len = strlen (fname);

        char *fn;

        register char *p, *np, *ep = NULL;

        static char *defext = ".lod";



        if ((fn = malloc (len + MAXEXTLEN + 1)) == NULL)

                error ("cannot allocate file name");

        strcpy (fn, fname);



        np = p = fn + len;      /* save end */



        while (p != fn) {

                if (*--p == '.')

                        ep = p;

#if MSDOS

                if (*p == '\\' || *p == ':')

#endif

#if VMS

                if (*p == ']' || *p == ':')

#endif

#if UNIX

                if (*p == '/')

#endif

#if MAC

                if (*p == ':')

#endif

                        break;

                else

                        continue;

                }

        if (p != fn)

                p++;



        if (!ep) {      /* no extension supplied */

                strcpy (np, defext);

                ep = np;

                np += strlen (defext);

        }



        if (np - p > BASENAMLEN) {      /* filename too long -- truncate */

                np = p + (BASENAMLEN - MAXEXTLEN);

                p = np;

                while (*ep & np < p + MAXEXTLEN)

                        *np++ = *ep++;

                *np = EOS;

        }

        return (fn);

}





static char *

strup (str)                     /* convert all alpha chars in str to upper */

char *str;

{

        register char *p = str;



        while (*p) {

                if (isalpha (*p) & islower (*p))

                        *p = toupper (*p);

                p++;

        }

        return (str);

}





static

fldhex ()                       /* insure fldbuf contains hex value */

{

        register char *p = fldbuf;



        while (*p) {

                if (!isxdigit (*p))

                        break;

                p++;

        }

        if (!*p)

                return (YES);

        else

                return (NO);

}





static char *

basename (str)                  /* return base part of file name in str */

char *str;

{

        register char *p;



        if (!str)               /* empty input */

                return (NULL);



        for (p = str + strlen (str); p >= str; --p)

#if MSDOS

                if( *p == '\\' || *p == ':')

#endif

#if VMS

                if( *p == ']' || *p == ':')

#endif

#if UNIX

                if( *p == '/' )

#endif

#if MAC

                if( *p == ':' )

#endif

                        break;



        return (p < str ? str : ++p);

}





getopt (argc, argv, optstring)  /* get option letter from argv */

int argc;

char *argv[];

char *optstring;

{

        register char c;

        register char *place;

        static char *scan = NULL;

        extern char *index();



        optarg = NULL;



        if (scan == NULL || *scan == '\0') {

                if (optind == 0)

                        optind++;

        

                if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0')

                        return(EOF);

                if (strcmp(argv[optind], "--")==0) {

                        optind++;

                        return(EOF);

                }

        

                scan = argv[optind]+1;

                optind++;

        }



        c = *scan++;

        place = index(optstring, c);



        if (place == NULL || c == ':') {

                (void)fprintf(stderr, "%s: unknown option -%c\n", argv[0], c);

                return('?');

        }



        place++;

        if (*place == ':') {

                if (*scan != '\0') {

                        optarg = scan;

                        scan = NULL;

                } else if (optind < argc) {

                        optarg = argv[optind];

                        optind++;

                } else {

                        (void)fprintf( stderr, "%s: -%c argument missing\n", 

                                        argv[0], c);

                        return( '?' );

                }

        }



        return(c);

}





#if BSD

static

#else

static void

#endif

onintr ()                       /* clean up from signal */

{

        error ("Interrupted");

}





static

usage ()                        /* display usage on stderr, exit nonzero */

{

        fprintf (stderr, "usage: %s [-1 | -3 | -r] <input file ... >\n",

                Progname);

#if LSC

        longjmp (Env, 1);

#else

        exit (ERR);

#endif

}





static

error (str)

char *str;

{

        fprintf (stderr, "%s: at line %d: ", Progname, linecount);

        fprintf (stderr, "%s\n", str);

#if LSC

        longjmp (Env, 1);

#else

        exit (ERR);

#endif

}





static

error2 (fmt, str)

char *fmt, *str;

{

        fprintf (stderr, "%s: at line %d: ", Progname, linecount);

        fprintf (stderr, fmt, str);

        fprintf (stderr, "\n");

#if LSC

        longjmp (Env, 1);

#else

        exit (ERR);

#endif

}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.