[net.sources] More Unix Style Tools for IBMPC.

mohsen@tikal.UUCP (Mohsen Banan) (08/28/85)

Here are some unix style tools that also run on IBM PC.
Cut it and pass it through sh.
Read readme.ut1 first.
Here is a list of the programs in this posting:
expand, dost2b, dosb2t, hxd, which, crc16, sarch.

----------------------- CUT HERE ----------------------
# The rest of this file is a shell script which will extract:
# readme.ut1 mkp makefile pcust1.bat mbstd.h msc3.h crc16.c dosb2t.c dost2b.c expand.c fcrc16.c hxd.c sarch.c which.c
echo x - readme.ut1
cat >readme.ut1 <<'!Funky!Stuff!'
Here are a few simple tools that run identically or very similarly
under msdos and unix. 

I am calling them ust1, Unix Style Tools. Couldn't come up with 
a better name.

They have only minimally been tested under msdos and bsd4.2.
MSC 3.0 was used under msdos.
I did make an effort to make the code portable. They probably would 
run under a few other systems.

Mail bug reports and problems to me. I'll re-post.

expand:
 *  Expand mimics Unix's expand. It is not a full implementation.
 *  Does not support [-tab1,tab2,..,tabn].
 *  Expand is a filter.
 *  It processes the named files or the standard input.
 *  It writes to standard output with tabs changed into blanks.
 *  
 * Usages:
 *  expand [-tabstop] [i_files]
    Back space can easily be added to it.

dost2b:
 *  dost2b is a filter.
 *  dost2b processes i_files or the standard input.
 *  dost2b writes to o_file or standard output.
 *  Converts a DOS text file to binary file.
 *  Replaces <cr><lf> to <lf>.
 *
 * Usages:
 *  dost2b [-o] <o_file> <i_files>

dosb2t:
 *  dosb2t is a filter.
 *  dosb2t processes i_files or the standard input.
 *  dosb2t writes to o_file or standard output.
 *  Converts a DOS binary file to text file.
 *  Replaces <lf> with <cr><lf>.
 *  
 * Usages:
 *  dosb2t [-o] <o_file> <i_files>

hxd:
 *  hxd, Hexadecimal dump is similar unix's "od -x"
 *  Displays the contents of a file in hexadecimal.
 *  If a byte is printable, it is also printed.
 *  For each in put file name of the file is first emited.
 *      file: <i_file>
 *  last line for each input file is length of the file in 
 *      "dec_add:hex_add" format.
 *
 * Usages:
 *  hxd [-o] <o_file> <i_files>
    See Comments in hxd.c.

which:
 *  Tries to mimic Unix's which as closely as possible.
 *  
 * Usages:
 *  which <i_files>
    This is basically Larry Barello's which. 
    For DOS .{com,exe,bat} are tested for existance.
    Only the first one that exists is printed.
    Internal DOS programs could later be added.

crc16:
    This is basically Hugh Redelmeir's version.
    I needed to modify it so that it could also be
    used by sarch.

sarch:
 *      This is a simple archive utility program.
 *      Sarch tries to only rely on the C stdio library functions.
 *      When transferring multiple files between two machines that only have a
 *      single file transfer utility, sarch becomes handy. Multiple files
 *      are converted to a sinle file on one end, transfered to the other 
 *      machine and extracted to the original files at the destination.
 *      System dependent features are very few, keeping it simple
 *      and portable. Efficiency is sacrificed for portability.
 *      CRCs are computed when updateing and when extracting.
 *  
 * Usage:
 *  sarch -{m,u,x,a,t} archname file1 .. filen
 *      -m      Print file names within the archive.
 *      -u      Add or update files to the archive.
 *      -x      Extract files from archive.
 *      -a      Extract all files from the rachive.
 *      -t      PCDOS related. When extracting, test mode is set.
    Sarch is NOT COMPLETE. 
    I am posting it because it can be useful if used carefully.
    No flames on this one, please.
    I am also not happy with th command syntax.
    Only -u and -a work. As is, it is only useful for moving files
    around. 
    sarch -u ar file1 filen   , on one end.
    sarch -a ar , on the other end.


FILES:
    mkp:
        Is a Csh script that runs make.
        It can be useful when you are supporting native and cross
        development. Some don't like it. I do.
    makefile:
        File dependencies only. Needs mkp.
    pcust1.bat:
        run this on the pc to create everything.
    mbstd.h:
        Standard Header I use.
    expand.c dost2b.c dosb2t.c hxd.c sarch.c which.c fcrc16.c crc16.c:
        C source files.
    readme.ut1:
        This file.
    
TO RUN:
    bsd4.2
        first make mkp executable.
        mkp 
    msdos, msc
        make sure that all headers and libraries are there.
        make sure ssetargv.obj is in current directory.
        run pcust1.bat
!Funky!Stuff!
echo x - mkp
cat >mkp <<'!Funky!Stuff!'
#!/bin/csh -f
# This is the make pre-processor program written in the 'C' shell.
#
#   mkp defines a group of parameters and passes them to make.
#   SWITCHES:
#       -f <filename>
#           source <filename. priore to invoking make.
#           If -f is not present and .mkprc exists in the current directory
#           it is sourced. Otherwise if .mkprc exists in the home directory
#           it is sourced.
#       -- 
#           argument parsing is terminated remainder of command line is passed
#           to make as is.
#
set MKPFILE=.mkprc
set mkpname=$0
set mkpname=$mkpname:t
# ### VISIBLE MAKE TOOLS
set MAKE=make
set CC=cc
set AS="as -"
set LK=""
set LD=""
set LINT="lint -u"
set REMOVE="rm -f"
set CTAGS="ctags -w"
# Internal parametrs
set INCFLAGS = -I.
# ### VISIBLE MAKE PARAMETERS
#set CFLAGS = "${INCFLAGS} -DBSD4_2 -Uunix -DMSDOS"
set CFLAGS = "${INCFLAGS} -DBSD4_2 "
set LINTFLAGS = ${INCFLAGS}
set TARGETS
# MKP FLAGS
set S_MKPFILE
# 
umask 002
#
#
# Gather command line options
#
foreach i ($*)
    switch ($1)
    case -f:
        shift argv
        set S_MKPFILE=$1
        breaksw
    case --:
        shift argv
        break
    default:
        break
        breaksw
    endsw
    shift argv
end
#
#
#
#
if ("$S_MKPFILE" != "") then
    set MKPFILE = "$S_MKPFILE"
    source $MKPFILE
else if (-f $MKPFILE) then
    source $MKPFILE
else if (-f $HOME/$MKPFILE) then
    source $HOME/$MKPFILE
endif
#
set TARGETS="$*"
#
$MAKE  "CC=$CC" "AS=$AS" \
    "CFLAGS=$CFLAGS" "LINTFLAGS=$LINTFLAGS" \
    "LINT=$LINT"  \
    "REMOVE=$REMOVE" "CTAGS=$CTAGS" \
    $TARGETS
set ret=$status
if ("$ret" != "0") then
    exit 1
endif
exit 0
!Funky!Stuff!
echo x - makefile
cat >makefile <<'!Funky!Stuff!'
# ::::::::::::::::::::::::::::::::::::::::::::::::::
#
#  File: Makefile
#  Description: Makefile for creating  UST1
#
#
#  Audit Trail:  $Log:	makefile,v $
# Revision 1.1  85/08/28  08:38:38  mohsen
# original posting to the net
# 
#
#  $Header: makefile,v 1.1 85/08/28 08:38:38 mohsen Exp $
#
# ::::::::::::::::::::::::::::::::::::::::::::::::::

MAKEFILE = makefile
TARGET = ust1
PUB_H = mbstd.h msc3.h
LCL_H =
LCL_C = expand.c dost2b.c dosb2t.c hxd.c sarch.c which.c fcrc16.c \
		crc16.c 
C_SRC =  ${PUB_H} ${LCL_H} ${LCL_C}

${TARGET}: expand dost2b dosb2t hxd crc16 which sarch
#
expand:   expand.o
		cc -o expand expand.o
#
dost2b:	 dost2b.o
		cc -o dost2b dost2b.o
#
dosb2t:	 dosb2t.o
		cc -o dosb2t dosb2t.o
#
hxd:	 hxd.o
		cc -o hxd hxd.o
#
crc16:	 crc16.o fcrc16.o
		cc -o crc16 crc16.o fcrc16.o
#
sarch:	 sarch.o
		cc -o sarch sarch.o fcrc16.o
#
which:	 which.o
		cc -o which which.o
#
e_make:
	@echo ${MAKEFILE}
e_pub_h:
	@echo ${PUB_H}
e_lcl_h:
	@echo ${LCL_H}
e_lcl_c:
	@echo ${LCL_C}
e_c_src:
	@echo ${C_SRC}
#
ctags:  ${LCL_C}
		$(CTAGS) $(LCL_C)
#
lint:
		$(LINT) $(LCL_C)

!Funky!Stuff!
echo x - pcust1.bat
cat >pcust1.bat <<'!Funky!Stuff!'
cl -c -DMSDOS expand.c
cl -o expand expand.obj ssetargv.obj
cl -c -DMSDOS dost2b.c
cl -o dost2b dost2b.obj ssetargv.obj
cl -c -DMSDOS dosb2t.c
cl -o dosb2t dosb2t.obj ssetargv.obj
cl -c -DMSDOS hxd.c
cl -o hxd hxd.obj ssetargv.obj
cl -c -DMSDOS fcrc16.c
cl -c -DMSDOS crc16.c
cl -o crc16 crc16.obj fcrc16.obj ssetargv.obj
cl -c -DMSDOS sarch.c
cl -o sarch sarch.obj fcrc16.obj ssetargv.obj
cl -c -DMSDOS which.c
cl -o which which.obj ssetargv.obj
!Funky!Stuff!
echo x - mbstd.h
cat >mbstd.h <<'!Funky!Stuff!'
#ifndef MBSTD_H
#define MBSTD_H

#define CHAR    char
#define SCHAR   char
typedef unsigned char  UCHAR;

#define INT     int
#define SINT    int
typedef unsigned int UINT;

#define SHORT   short
#define SSHORT  short
typedef unsigned short USHORT;

#define LONG    long
#define SLONG   long
typedef unsigned long ULONG;

#define DOUBLE  double

#define BOOL    int
#define SUCC_FAIL   int 
#ifndef VOID
#define VOID    void
#endif

#define STATIC  static      /* Names not needed outside this src module  */

#define LOCAL               /* Names not needed outside this software module */
#define LCL_XTRN extern     /* Names defined within this software module */

#define PUBLIC              /* Names needed outside this software module */
#define EXTERN  extern      /* Names defined outside this software module */

#define TRUE    1
#define FALSE   0

#define SUCCESS 0
#define FAIL    (-1)

#endif MBSTD_H
!Funky!Stuff!
echo x - msc3.h
cat >msc3.h <<'!Funky!Stuff!'
#ifndef MSC3_H
#define MSC3_H

#ifdef unix
#define O_TEXT   0x4000
#define O_BINARY 0x8000
setmode(handle, mode)
int handle;
int mode;
{}
#endif

#endif MSC3_H
!Funky!Stuff!
echo x - crc16.c
cat >crc16.c <<'!Funky!Stuff!'
/*+
 * File: crc16.c
 * Description:
 *  Computes crc for the named filenames.
 *  Output has this formatt.
 *      file=[i_file], size=[fsize], crc=[decval](dec)=[hexval](hex)
 *  
 * Usages:
 *  crc16 <i_files>
 *
 *  Author: Mohsen Banan.
 *
 *  This program is public domain software, no warranty intended or
 *  implied.
 *  General permission to copy or modify, but not for profit,  is
 *  hereby  granted.
 *
 * Functions:
 *
 *
 * Audit Trail:  $Log:	crc16.c,v $
 * Revision 1.1  85/08/28  08:38:12  mohsen
 * original posting to the net
 * 
 * 
 *
-*/

#ifdef RCS_VER
static char *rcs = "$Header: crc16.c,v 1.1 85/08/28 08:38:12 mohsen Exp $";
#endif

/* #includes */
#include "mbstd.h"
#include <stdio.h>
#include <ctype.h>
#include <fcntl.h>
#ifdef unix
#include "msc3.h"
#endif
 
/* #defines */

/* external variables */

/* referenced external function declarations */
EXTERN USHORT fcrc16();
/* internal function declarations */
PUBLIC VOID crc16();
PUBLIC VOID cant_open();
STATIC VOID usage();

/* global variables */

/* static variables */
STATIC CHAR * prog_name;


INT
main (argc, argv)
INT argc;
CHAR * argv[];
{
    crc16(argc, argv);
}
    

/*<
 * Function:crc16
 * Description:
 *
 * Returns:
 *  VOID
 *  
>*/
PUBLIC VOID 
crc16 (argc,argv)
INT argc;
CHAR * argv[];
{
    FILE * i_fp;
    FILE * o_fp;

    INT i;
    USHORT crc;
    LONG fsize ;

    i_fp = stdin;
    o_fp = stdout;
    prog_name = argv[0];
    for (i=1; i<argc; ++i) {
        if (*argv[i] == '-') {
            /* To handle concatenated switches */
            INT j;
            j=i;
            while (*(++argv[j])) {
                switch (*argv[j]) {
                case 'o':
                case 'O':
                    if ( !(o_fp = fopen(argv[++i], "w")) ) {
                        cant_open (prog_name, argv[i]);
                        exit (1);
                    }
                    break;
                default:
                    usage();
                    exit(1);
                } /* switch (*argv[j]) */
            } /* while (*(++argv[j])) */
        } /* if '-' */
        else {
            if (!(i_fp = fopen (argv[i], "r"))) {
                cant_open (prog_name, argv[i]);
                exit (1);
            } 
            setmode (fileno(i_fp), O_BINARY);
            setmode (fileno(o_fp), O_TEXT);
            crc = fcrc16 (i_fp, 0, &fsize);
            fprintf (o_fp, "file=%s, size=%ld, crc=%u(dec)=%x(hex)\n",
                    argv[i], fsize, crc, crc);
            fclose (i_fp);
        }
    } /* for i<argc */
    fclose (o_fp);
    exit (0);
}

PUBLIC VOID
cant_open (prog_name,filename)
CHAR * prog_name;
CHAR * filename;
{
    fprintf (stderr, "%s :can not open %s \n", prog_name, filename);
} 

STATIC VOID
usage ()
{
    fprintf (stderr, "Usage: %s <i_files> \n", prog_name);
}



!Funky!Stuff!
echo x - dosb2t.c
cat >dosb2t.c <<'!Funky!Stuff!'

/*+
 * File: dosb2t.c
 * Description:
 *  dosb2t is a filter.
 *  dosb2t processes i_files or the standard input.
 *  dosb2t writes to o_file or standard output.
 *
 *  Converts a DOS binary file to text file.
 *  Replaces <lf> with <cr><lf>.
 *  
 * Usages:
 *  dosb2t [-o] <o_file> <i_files>
 *
 *
 *  Author: Mohsen Banan.
 *
 *  This program is public domain software, no warranty intended or
 *  implied.
 *  General permission to copy or modify, but not for profit,  is
 *  hereby  granted.
 *
 *
 * Functions:
 *
 *
 * Audit Trail:  $Log:	dosb2t.c,v $
 * Revision 1.1  85/08/28  08:38:24  mohsen
 * original posting to the net
 * 
 * 
 *
-*/

#ifdef RCS_VER
static char *rcs = "$Header: dosb2t.c,v 1.1 85/08/28 08:38:24 mohsen Exp $";
#endif

/* #includes */
#include "mbstd.h"
#include <stdio.h>
#include <ctype.h>
#include <fcntl.h>
#ifdef unix
#include "msc3.h"
#endif
 
/* #defines */

/* external variables */

/* referenced external function declarations */

/* internal function declarations */
PUBLIC VOID dosb2t();
PUBLIC VOID cant_open();
STATIC VOID usage();

/* global variables */

/* static variables */
STATIC CHAR * prog_name;


INT
main (argc, argv)
INT argc;
CHAR * argv[];
{
    dosb2t(argc, argv);
}
    

/*<
 * Function:dosb2t
 * Description:
 *
 * Returns:
 *  VOID
 *  
>*/
PUBLIC VOID 
dosb2t (argc,argv)
INT argc;
CHAR * argv[];
{
    FILE * i_fp;
    FILE * o_fp;

    INT i;
    INT c;

    i_fp = stdin;
    o_fp = stdout;
    prog_name = argv[0];
    for (i=1; i<argc; ++i) {
        if (*argv[i] == '-') {
            /* To handle concatenated switches */
            INT j;
            j=i;
            while (*(++argv[j])) {
                switch (*argv[j]) {
                case 'o':
                case 'O':
                    if ( !(o_fp = fopen(argv[++i], "w")) ) {
                        cant_open (prog_name, argv[i]);
                        exit (1);
                    }
                    break;
                default:
                    usage();
                    exit(1);
                } /* switch (*argv[j]) */
            } /* while (*(++argv[j])) */
        } /* if '-' */
        else {
            if (!(i_fp = fopen (argv[i], "r"))) {
                cant_open (prog_name, argv[i]);
                exit (1);
            } 
            setmode (fileno(i_fp), O_BINARY);
            setmode (fileno(o_fp), O_TEXT);
            while (( c = getc (i_fp)) != EOF) {
                putc (c, o_fp);
            }
            fclose (i_fp);
        }
    } /* for i<argc */
    fclose (o_fp);
    exit (0);
}

PUBLIC VOID
cant_open (prog_name,filename)
CHAR * prog_name;
CHAR * filename;
{
    fprintf (stderr, "%s :can not open %s \n", prog_name, filename);
} 

STATIC VOID
usage ()
{
    fprintf (stderr, "Usage: %s [-o] <o_file> <i_files> \n", prog_name);
}


!Funky!Stuff!
echo x - dost2b.c
cat >dost2b.c <<'!Funky!Stuff!'
/*+
 * File: dost2b.c
 * Description:
 *  dost2b is a filter.
 *  dost2b processes i_files or the standard input.
 *  dost2b writes to o_file or standard output.
 *
 *  Converts a DOS text file to binary file.
 *  Replaces <cr><lf> to <lf>.
 *
 * Usages:
 *  dost2b [-o] <o_file> <i_files>
 * 
 *
 *  Author: Mohsen Banan.
 *
 *  This program is public domain software, no warranty intended or
 *  implied.
 *  General permission to copy or modify, but not for profit,  is
 *  hereby  granted.
 *
 *
 * Functions:
 *
 *
 * Audit Trail:  $Log:	dost2b.c,v $
 * Revision 1.1  85/08/28  08:38:28  mohsen
 * original posting to the net
 * 
 * 
 *
-*/

#ifdef RCS_VER
static char *rcs = "$Header: dost2b.c,v 1.1 85/08/28 08:38:28 mohsen Exp $";
#endif

/* #includes */
#include "mbstd.h"
#include <stdio.h>
#include <ctype.h>
#include <fcntl.h>
#ifdef unix
#include "msc3.h"
#endif
 
/* #defines */

/* external variables */

/* referenced external function declarations */

/* internal function declarations */
PUBLIC VOID dost2b();
PUBLIC VOID cant_open();
STATIC VOID usage();

/* global variables */

/* static variables */
STATIC CHAR * prog_name;

INT
main (argc, argv)
INT argc;
CHAR * argv[];
{
    dost2b(argc, argv);
}
    

/*<
 * Function:dost2b
 * Description:
 *
 * Returns:
 *  VOID
 * 
>*/
PUBLIC VOID 
dost2b (argc,argv)
INT argc;
CHAR * argv[];
{
    FILE * i_fp;
    FILE * o_fp;

    INT i;
    INT c;

    i_fp = stdin;
    o_fp = stdout;
    prog_name = argv[0];
    for (i=1; i<argc; ++i) {
        if (*argv[i] == '-') {
            /* To handle concatenated switches */
            INT j;
            j=i;
            while (*(++argv[j])) {
                switch (*argv[j]) {
                case 'o':
                case 'O':
                    if ( !(o_fp = fopen(argv[++i], "w")) ) {
                        cant_open (prog_name, argv[i]);
                        exit (1);
                    }
                    break;
                default:
                    usage();
                    exit(1);
                } /* switch (*argv[j]) */
            } /* while (*(++argv[j])) */
        } /* if '-' */
        else {
            if (!(i_fp = fopen (argv[i], "r"))) {
                cant_open (prog_name, argv[i]);
                exit (1);
            } 
            setmode (fileno(i_fp), O_TEXT);
            setmode (fileno(o_fp), O_BINARY);
            while (( c = getc (i_fp)) != EOF) {
                putc (c, o_fp);
            }
            fclose (i_fp);
        }
    } /* for i<argc */
    fclose (o_fp);
    exit (0);
}

PUBLIC VOID
cant_open (prog_name,filename)
CHAR * prog_name;
CHAR * filename;
{
    fprintf (stderr, "%s :can not open %s \n", prog_name, filename);
} 

STATIC VOID
usage ()
{
    fprintf (stderr, "Usage: %s [-o] <o_file> <i_files> \n", prog_name);
}


!Funky!Stuff!
echo x - expand.c
cat >expand.c <<'!Funky!Stuff!'

/*+
 * File: expand.c
 * Description:
 *  Expand mimics Unix's expand. It is not a full implementation.
 *  Does not support [-tab1,tab2,..,tabn].
 *
 *  Expand is a filter.
 *  It processes the named files or the standard input.
 *  It writes to standard output with tabs changed into blanks.
 *  
 * Usages:
 *  expand [-tabstop] [i_files]
 *
 *
 *  Author: Mohsen Banan.
 *
 *  This program is public domain software, no warranty intended or
 *  implied.
 *  General permission to copy or modify, but not for profit,  is
 *  hereby  granted.
 *
 * Functions:
 *
 *
 * Audit Trail:  $Log:	expand.c,v $
 * Revision 1.1  85/08/28  08:38:31  mohsen
 * original posting to the net
 * 
 * Revision 1.1  85/08/14  13:44:13  mohsen
 * Initial revision
 * 
 * 
 *
-*/

#ifdef RCS_VER
static char *rcs = "$Header: expand.c,v 1.1 85/08/28 08:38:31 mohsen Exp $";
#endif

/* #includes */
#include "mbstd.h"
#include <stdio.h>
#include <ctype.h>
#include <fcntl.h>
#ifdef unix
#include "msc3.h"
#endif
 
/* #defines */

/* external variables */

/* referenced external function declarations */

/* internal function declarations */
PUBLIC VOID expand();
PUBLIC VOID tab_putc();
PUBLIC VOID cant_open();
STATIC VOID usage();

/* global variables */

/* static variables */
STATIC CHAR * prog_name;
STATIC INT tabstop;
STATIC INT cpos;

INT
main (argc, argv)
INT argc;
CHAR * argv[];
{
    expand(argc, argv);
}
    

/*<
 * Function:expand
 * Description:
 *  Parses the command line and calls tab_putc.
 *
 * Returns:
 *  VOID
 * 
>*/
PUBLIC VOID 
expand (argc,argv)
INT argc;
CHAR * argv[];
{
    FILE * i_fp;
    FILE * o_fp;

    INT i;
    INT c;

    i_fp = stdin;
    o_fp = stdout;
    tabstop = 8;
    prog_name = argv[0];
    for (i=1; i<argc; ++i) {
        if (*argv[i] == '-') {
            /* To handle concatenated switches */
            INT j;
            j=i;
            while (*(++argv[j])) {
                if (isdigit(*(argv[j]))) {
                    tabstop = atoi(argv[j]);
                    break;
                }
#if 0
                switch (*argv[j]) {
                case 'o':
                case 'O':
                    if ( !(o_fp = fopen(argv[++i], "w")) ) {
                        cant_open (prog_name, argv[i]);
                        exit (1);
                    }
                    break;
                default:
                    usage();
                    exit(1);
                } /* switch (*argv[j]) */
#endif
            } /* while (*(++argv[j])) */
        } /* if '-' */
        else {
            if (!(i_fp = fopen (argv[i], "r"))) {
                cant_open (prog_name, argv[i]);
                exit (1);
            } 
            setmode (fileno(i_fp), O_TEXT);
            setmode (fileno(o_fp), O_TEXT);
            cpos = 0;
            while (( c = getc (i_fp)) != EOF) {
                tab_putc (c, o_fp);
            }
            fclose (i_fp);
        }
    } /* for i<argc */
    fclose (o_fp);
    exit (0);
}


/*<
 * Function:tab_putc
 * Description:
 *  Converts tabs to the correct number of spaces (tabstop).
 *  tab_putc is recursive.
 *
 * Returns:
 *  VOID
 *
>*/
PUBLIC VOID
tab_putc (c, o_fp)
INT  c;
FILE * o_fp;
{
    if (c == '\n') {
        cpos = 0;
        putc (c, o_fp);
    } else if ( c== '\t') {
        do {
            tab_putc(' ', o_fp);
        } while (cpos % tabstop);
    }
    else {
        cpos++;
        putc (c, o_fp);
    }
}

PUBLIC VOID
cant_open (prog_name,filename)
CHAR * prog_name;
CHAR * filename;
{
    fprintf (stderr, "%s :can not open %s \n", prog_name, filename);
} 

#if 0
STATIC VOID
usage ()
{
    fprintf (stderr, "Usage: %s [-tabstop] [i_files]\n", prog_name);
}
#endif

!Funky!Stuff!
echo x - fcrc16.c
cat >fcrc16.c <<'!Funky!Stuff!'
/*+
 * File: fcrc16
 * Description:
 *	Calculates crc, given a file pointer.
 *
 *
 *  Author: Mohsen Banan.
 *
 *  This program is public domain software, no warranty intended or
 *  implied.
 *  General permission to copy or modify, but not for profit,  is
 *  hereby  granted.
 *
 *
 * Functions:
 *
 *
 * Audit Trail:  $Log:	fcrc16.c,v $
 * Revision 1.1  85/08/28  08:38:33  mohsen
 * original posting to the net
 * 
 * 
 *
-*/

#ifdef RCS_VER
static char *rcs = "$Header: fcrc16.c,v 1.1 85/08/28 08:38:33 mohsen Exp $";
#endif

/* #includes */
#include "mbstd.h"
#include <stdio.h>
 
/* #defines */

/* external variables */

/* referenced external function declarations */

/* internal function declarations */

/* global variables */

/* static variables */


/*<
 * Function:crc16_table
 * Description:
 *
 *  * Calculate CRC16 of a file.
 *  * CRC16 polynomial: x**0 + x**2 + x**15 + x**16 (0xA001)
 *  * (CCITT polynomial: x**0 + x**5 + x**12 + x**16 (0x8408))
 *  * 
 *  * D. Hugh Redelmeier  1983 April 15
 *
 *  Mohsen Banan: I don't know how CRCs work yet. 
 *  None of what is to follow is original work.
 *
 *
 * Returns:
 * 
>*/
#if 0
VOID 
crc16_table()
{
    register unsigned s, t;
    register int i;

    printf("unsigned short crctab[256] = {");
    for (t=0; ; ) {
        if (t%8 == 0)
            printf("\n");
        s = t;
        for (i=8; i--; )
            s = s>>1 ^ (s&1? 0xA001 : 0);
        printf("\t0x%04x", s);
        if (++t == 256)
            break;
        printf(",");
        }
    printf("};\n");
}
#endif

unsigned short crctab[256] = {
    0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
    0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
    0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,
    0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
    0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
    0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
    0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
    0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
    0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
    0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
    0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
    0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
    0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
    0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
    0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
    0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
    0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
    0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
    0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
    0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
    0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
    0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
    0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
    0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
    0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
    0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
    0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
    0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
    0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
    0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
    0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
    0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040};



/*<
 * Function:fcrc16
 * Description:
 *  The algorithm comes from 
 *  "Byte-wise CRC Calculations" by Aram Perez,
 *  IEEE Micro June 1983 pp.40-50
 *
 * Returns:
 *  VOID
 * 
>*/
    
PUBLIC USHORT 
fcrc16 (i_fp, prev_crc, p_fsize)
FILE * i_fp;
USHORT prev_crc;
LONG * p_fsize;
{
    USHORT crc, x;
    INT c;
    LONG  fsize;

    crc = prev_crc;
    fsize = 0L;
    while ((c=getc(i_fp)) != EOF) {
        /* these are really the same.
         * crc = crctab[(crc^c)&0xff] ^ crc>>8;
         */
        x = (c^crc) & 0xFF;
        crc >>= 8;
        crc ^= crctab[x];
        ++fsize;
    }
	rewind(i_fp);		/* I don't like side effects */
    *p_fsize = fsize;
    return (crc);
}
!Funky!Stuff!
echo x - hxd.c
cat >hxd.c <<'!Funky!Stuff!'
/*+
 * File: hxd
 * Description:
 *  hxd, Hexadecimal dump is similar unix's "od -x"
 *  Displays the contents of a file in hexadecimal.
 *  If a byte is printable, it is also printed.
 *  format of output is :
 *  dec_add:hex_add word word word word word word word word  string  
 *  where:
 *      dec_add == Start address for that line in decimal. 
 *      hex_add == Start address for that line in hex. 
 *      word == Representation of two bytes in hex. Two characters
 *              for each byte. First two characters in "word" represent
 *              the byte that was read sooner.
 *      string == If the character is printable, it is printed.
 *                Otherwise a '.' is printed. '.'is printed as '.'.
 *  For each in put file name of the file is first emited.
 *      file: <i_file>
 *  last line for each input file is length of the file in 
 *      "dec_add:hex_add" format.
 *
 * Usages:
 *  hxd [-o] <o_file> <i_files>
 *
 *
 *  Author: Mohsen Banan.
 *
 *  This program is public domain software, no warranty intended or
 *  implied.
 *  General permission to copy or modify, but not for profit,  is
 *  hereby  granted.
 *
 *
 * Functions:
 *
 *
 * Audit Trail:  $Log:	hxd.c,v $
 * Revision 1.1  85/08/28  08:38:36  mohsen
 * original posting to the net
 * 
 * 
 *
-*/

#ifdef RCS_VER
static char *rcs = "$Header: hxd.c,v 1.1 85/08/28 08:38:36 mohsen Exp $";
#endif

/* #includes */
#include "mbstd.h"
#include <stdio.h>
#include <ctype.h>
#include <fcntl.h>
#ifdef unix
#include "msc3.h"
#endif
 
/* #defines */

/* external variables */

/* referenced external function declarations */

/* internal function declarations */
PUBLIC VOID hxd();
PUBLIC VOID hxdump();
PUBLIC VOID cant_open();
PUBLIC VOID printisc();
STATIC VOID usage();

/* global variables */

/* static variables */
STATIC CHAR * prog_name;

INT
main (argc, argv)
INT argc;
CHAR * argv[];
{
    hxd(argc, argv);
}
    

/*<
 * Function:hxd
 * Description:
 *  Parses the command line and calls hxdump.
 *  
 * Returns:
 *  VOID
 * 
>*/
PUBLIC VOID 
hxd (argc,argv)
INT argc;
CHAR * argv[];
{
    FILE * i_fp;
    FILE * o_fp;
    INT i;

    prog_name = argv[0];
    i_fp = stdin;
    o_fp = stdout;
    for (i=1; i<argc; ++i) {
        if (*argv[i] == '-') {
            /* To handle concatenated switches */
            INT j;
            j=i;
            while (*(++argv[j])) {
                switch (*argv[j]) {
                case 'o':
                case 'O':
                    if ( !(o_fp = fopen(argv[++i], "w")) ) {
                        cant_open(prog_name, argv[i]);
                        exit(1);
                    }
                    break;
                default:
                    usage();
                    exit(1);
                } /* switch (*argv[j]) */
            } /* while (*(++argv[j])) */
        } /* if '-' */
        else {
            if (!(i_fp = fopen (argv[i], "r"))) {
                cant_open (prog_name,  argv[i]);
                exit (1);
            } 
            fprintf (o_fp, "file:   %s", argv[i]);
            setmode (fileno(i_fp), O_BINARY);
            setmode (fileno(o_fp), O_TEXT);
            hxdump (i_fp, o_fp);
            fclose (i_fp);
        }
    } /* for i<argc */
    fclose (o_fp);
    exit (0);
}


/*<
 * Function:HX_DUMP
 * Description:
 *
 * Arguments:
 *
 * Returns:
 *
 * Side Effects:
 *
 * Calls:
 * 
>*/
PUBLIC VOID
hxdump (i_fp, o_fp)
FILE * i_fp;
FILE * o_fp;
{
#define BYTESPERLINE 16
    LONG i = 0L;
    INT c;
    INT chars[BYTESPERLINE];
    INT j=0;
    INT k;

    while ((c = getc (i_fp)) != EOF) {
        if (! (i % BYTESPERLINE)) {
            if (i) {
                j=0;
                fprintf (o_fp, "  ");
                printisc (o_fp,chars, BYTESPERLINE);
            }
                
            fprintf (o_fp, "\n%07ld:%07lx", i,i );
        }
        if (!(i++ & 1)) {
            putc (' ', o_fp);
        }
        fprintf (o_fp, "%02x", c);
        chars[j++] = c;
    }
    if (k = (i % BYTESPERLINE)) {
        INT jj;
        k = BYTESPERLINE - k;
        for (jj=0; jj < (5*k/2)  ;++jj) {
            putc(' ', o_fp);
        }
    }
    fprintf (o_fp, "  ");
    printisc (o_fp, chars, BYTESPERLINE);
    fprintf (o_fp, "\n%07ld:%07lx\n", i,i);
}

PUBLIC VOID
cant_open (prog_name,filename)
CHAR * prog_name;
CHAR * filename;
{
    fprintf (stderr, "%s :can not open %s \n", prog_name, filename);
} 

STATIC VOID
usage ()
{
    fprintf (stderr, "Usage: %s [-o] <o_file> <i_file> \n", prog_name);
     
}


PUBLIC VOID
printisc (o_fp, chars, length)
FILE * o_fp;
INT chars[];
INT length;
{
    INT i;

    for (i=0; i<length; ++i) {
        if (isprint (chars[i])) {
            putc (chars[i], o_fp);
        } else {
            putc ('.', o_fp);
        }
    }
}
!Funky!Stuff!
echo x - sarch.c
cat >sarch.c <<'!Funky!Stuff!'
/*+
 * File: SARCH
 * Description:
 *      This is a simple archive utility program.
 *      Sarch tries to only rely on the C stdio library functions.
 *      When transferring multiple files between two machines that only have a
 *      single file transfer utility, sarch becomes handy. Multiple files
 *      are converted to a sinle file on one end, transfered to the other 
 *      machine and extracted to the original files at the destination.
 *      System dependent features are very few, keeping it simple
 *      and portable. Efficiency is sacrificed for portability.
 *		CRCs are computed when updateing and when extracting.
 *  
 * Usage:
 *  sarch -{m,u,x,a,t} archname file1 .. filen
 *      -m      Print file names within the archive.
 *      -u      Add or update files to the archive.
 *      -x      Extract files from archive.
 *      -a      Extract all files from the rachive.
 *      -t      PCDOS related. When extracting, test mode is set.
 *
 *
 *  Author: Mohsen Banan.
 *
 *  This program is public domain software, no warranty intended or
 *  implied.
 *  General permission to copy or modify, but not for profit,  is
 *  hereby  granted.
 *
 *
 * Functions:
 *
 *  Sarch relies on the archive manipulating functions:
 *      ar_open(), ar_close()
 *      ar_get(), ar_put(), ar_seek().
 *      ar_get, gets (extracts) a file from the archive.
 *      ar_put, puts (adds) a file to the archive.
 *
 *
 * Audit Trail:  $Log:	sarch.c,v $
 * Revision 1.1  85/08/28  08:38:52  mohsen
 * original posting to the net
 * 
 * Revision 1.1  85/08/13  17:30:27  mohsen
 * Initial revision
 * 
 * Revision 1.2  85/04/25  10:27:22  mohsen
 * In this version sarch was working fine with the -a and -u options.
 * 
 * Revision 1.1  85/04/19  16:24:43  mohsen
 * Initial revision
 * 
 *
-*/

#ifdef RCS_VER
static char *rcs = "$Header: sarch.c,v 1.1 85/08/28 08:38:52 mohsen Exp $";
#endif

/* #includes */
#include "mbstd.h"
#include <stdio.h>
#include <fcntl.h>
#ifdef unix
#include "msc3.h"
#endif
 
/* #defines */
#define AR_BSTR     "<archive>"
#define AR_ESTR     "<archive>"

/*
 * All fileds of ARCH_HDR are strings (0 terminated),
 * All fields are left justified.
 */
typedef struct {
    CHAR ar_bstr[16];       /* begining archive string */
    CHAR fname[16];
    CHAR fsize[8];
    CHAR fcrc[8];
    CHAR ar_estr[16];       /* end archive string */
} ARCH_HDR;

/* external variables */

/* referenced external function declarations */
EXTERN USHORT fcrc16();

/* internal function declarations */
PUBLIC VOID sarch();
PUBLIC FILE * ar_open();
PUBLIC INT ar_close();
PUBLIC SUCC_FAIL ar_put();
PUBLIC SUCC_FAIL ar_get();
PUBLIC SUCC_FAIL ar_seek();
LOCAL VOID wr_hdr();
LOCAL SUCC_FAIL rd_hdr();
LOCAL VOID fld2str();
PUBLIC VOID cpf();
PUBLIC VOID cant_open();
STATIC VOID usage();

/* global variables */

/* static variables */
STATIC CHAR * prog_name;
STATIC ARCH_HDR gw_hdr;         /* generic write archive header */
STATIC ARCH_HDR gr_hdr;         /* generic read archive header */
STATIC BOOL txt_mode_flag;

INT
main (argc, argv)
INT argc;
CHAR * argv[];
{
    sarch(argc, argv);
}
    

/*<
 * Function:SARCH
 * Description:
 *  Parses the command line and relies on archive manipulating functions to do
 *  what it should do.
 *
 * Returns:
 *  VOID
 * 
>*/
PUBLIC VOID 
sarch (argc,argv)
INT argc;
CHAR * argv[];
{
    FILE * ar_fp;

    BOOL    add_flag;
    BOOL    xt_flag;
    BOOL    xt_all_flag;

    INT i;

    add_flag = xt_flag = xt_all_flag = txt_mode_flag = FALSE;
    ar_fp = stdout;
    prog_name = argv[0];

    sprintf (gw_hdr.ar_bstr, "%-15s", AR_BSTR);
    sprintf (gw_hdr.ar_estr, "%-15s", AR_ESTR);

    for (i=1; i<argc; ++i) {
        if (*argv[i] == '-') {
            /* To handle concatenated switches */
            INT j;
            j=i;
            while (*(++argv[j])) {
                switch (*argv[j]) {
                case 'u':
                case 'U':
                    /*
                     * add or update a file to the archive
                     */
                    if (!(ar_fp = ar_open (argv[++i], "w"))) {
                        cant_open(prog_name, argv[i]);
                        exit (1);
                    }
                    add_flag = TRUE;
                    break;
                case 'x':
                case 'X':
                    /*
                     * Extract a file from the archive.
                     */
                    if (!(ar_fp = ar_open (argv[++i], "r"))) {
                        cant_open(prog_name,argv[i]);
                        exit(1);
                    }
                    xt_flag = TRUE;
                    break;
                case 'a':
                case 'A':
                    /*
                     * Extract all files with in this archive
                     */
                    if (!(ar_fp = ar_open (argv[i+1], "r"))) {
                        cant_open(prog_name,argv[i]);
                        exit(1);
                    }
                    xt_all_flag = TRUE;
                    break;
                case 't':
                case 'T':
                    txt_mode_flag = TRUE;
                    break;
                default:
                    usage();
                    exit(1);
                } /* switch (*argv[j]) */
            } /* while (*(++argv[j])) */
        } /* if '-' */
        else if (ar_fp == stdout) {
            /* 
             * This is equivalent to "-u" option, ar_fp is stdout.
             */
             add_flag = TRUE;
        }
        else {
            /*
             * the rest of command line arguments are assumed to be file names.
             */
            if (add_flag) {
                ar_put (ar_fp, &gw_hdr,argv[i]);
            }
            else if (xt_flag) {
                ar_seek (ar_fp, &gr_hdr, argv[i]);
                ar_get (ar_fp,&gr_hdr);
            }
            else if (xt_all_flag) {
                while ( ar_seek (ar_fp, &gr_hdr,(CHAR *) NULL) == SUCCESS ) {
                    ar_get (ar_fp, &gr_hdr);
                }
            }
            else {
                /*
                OOPS();
                */
            }
        }
    } /* for i<argc */
    ar_close (ar_fp);
    exit (0);
}


/*<
 * Function:ar_open
 * Description:
 *  Opens an archive directory.
 *
 * Returns:
 *  Same as fopen.
 *
 * 
>*/
PUBLIC FILE *
ar_open(path, type)
CHAR * path;
CHAR * type;
{
    FILE * fp;
    if ( fp=fopen(path,type) ) {
        setmode (fileno(fp), O_BINARY);
    }
    return (fp);
}



/*<
 * Function:ar_close
 * Description:
 *  Closes an archive file
 *
 * Returns:
 *  same as fclose.
 * 
>*/
PUBLIC INT
ar_close(ar_fp)
FILE * ar_fp;
{
    return (fclose(ar_fp));
}



/*<
 * Function: ar_put
 * Description:
 *  Puts the contents of the file specified in "path" into the archive.
 *  Archive header is written prior to copying the file.
 *
 * Returns:
 *  SUCCESS:    
 *      No problems.
 *  FAIL:
 *      Couldn't open the file that it is supposed to put it in.
 * 
>*/
PUBLIC SUCC_FAIL
ar_put(ar_fp, p_ar_hdr, path)
FILE * ar_fp;
ARCH_HDR * p_ar_hdr;
CHAR * path;
{
    FILE * fp;
    SUCC_FAIL retval;
    LONG fsize;
    USHORT crc;

    retval = SUCCESS;
    if (!(fp = fopen(path, "r"))) {
        cant_open (prog_name, path);
        retval = FAIL;
    } else {
        setmode (fileno(fp), O_BINARY);
        crc = fcrc16(fp, (USHORT)0, &fsize);
        rewind(fp);
        sprintf (p_ar_hdr->fsize, "%-7ld", fsize);
        sprintf (p_ar_hdr->fcrc, "%-7x", (int)crc);
        sprintf (p_ar_hdr->fname, "%-15s", path);
        wr_hdr(ar_fp, p_ar_hdr);
        cpf (fp, ar_fp, fsize);
        fclose(fp);
    }
    return (retval);
}


/*<
 * Function:ar_get
 * Description:
 *  Gets (extracts) the contents of a file from the archive.
 *  and stores it in the file specified in the archive header.
 *  ar_get is to be invoked after the execution of ar_seek.
 *
 * Returns:
 *  SUCCESS:
 *      Every thing went fine.
 *  FAIL:
 *      Couldn't open the file.
 *
 * 
>*/
PUBLIC SUCC_FAIL
ar_get(ar_fp, p_ar_hdr)
FILE  * ar_fp;
ARCH_HDR * p_ar_hdr;
{
    FILE * fp;
    SUCC_FAIL retval;
    LONG fsize;
    LONG nfsize;
    USHORT crc;
    USHORT ncrc;
    UINT   int_crc;

    retval = SUCCESS;

    if (!(fp = fopen(p_ar_hdr->fname, "w+"))) {
        cant_open (prog_name, p_ar_hdr->fname);
        retval = FAIL;
    } else {
		setmode(fileno(fp), O_BINARY);
        sscanf (p_ar_hdr->fsize, "%ld", &fsize);
        cpf((FILE *)ar_fp, fp, fsize);
        rewind(fp);
        ncrc = fcrc16(fp, (USHORT)0, &nfsize);
        sscanf (p_ar_hdr->fcrc, "%x", &int_crc);
        crc = int_crc;
        if ( (crc != ncrc) || (fsize != nfsize) ) {
            retval = FAIL;
            fprintf(stderr, "%s: Problem extacting %s size=%ld, crc=%x\n",
                    prog_name, p_ar_hdr->fname, fsize, (int)crc);
            fprintf(stderr, "%s: Problem extacting %s nsize=%ld, ncrc=%x\n",
                    prog_name, p_ar_hdr->fname, nfsize, (int)ncrc);
        }
        fclose(fp);
    }
    return (retval);
}


/*<
 * Function: ar_seek
 * Description:
 *  If path is NULL, the current archive header is read into
 *  p_ar_hdr.
 *  Otherwise, the archive is searched for the specified file
 *  name addressed by path.
 *
 * Returns:
 *  SUCCESS if found.
 *  FAIL    if not found, or problem.
 *
 * 
>*/
LOCAL SUCC_FAIL
ar_seek(ar_fp, p_ar_hdr, path) 
FILE * ar_fp;
ARCH_HDR * p_ar_hdr;
CHAR * path;
{
    SUCC_FAIL retval;

    retval = SUCCESS;
    if (!path ) {
        /* then get it any way */
        retval = rd_hdr(ar_fp, p_ar_hdr);
    } else {
        
    }
    return (retval);
}


/*<
 * Function:wr_hdr
 * Description:
 *  Copy the contents of ARCH_HDR to the archive header.
 *  See rd_hdr for the file archive header picture.
 *
 * Returns:
 *  VOID
 * 
>*/
LOCAL VOID
wr_hdr (ar_fp, p_ar_hdr)
FILE * ar_fp;
ARCH_HDR * p_ar_hdr;
{
    fprintf (ar_fp , "%-15s", p_ar_hdr->ar_bstr);
    fprintf (ar_fp , "%-15s", p_ar_hdr->fname);
    fprintf (ar_fp , "%-7s", p_ar_hdr->fsize);
    fprintf (ar_fp , "%-7s", p_ar_hdr->fcrc);
    fprintf (ar_fp , "%-15s", p_ar_hdr->ar_estr);
    putc ('\n',ar_fp);
}


/*<
 * Function:rd_hdr
 * Description:
 *  Reads a header and fills up the ARCH_HDR.
 *
0         1         2         3         4         5         6   
0123456789012345678901234567890123456789012345678901234567890
123456789012345678901234567890123456789012345678901234567890
b              b              b      b     b
    ar_bstr        fname        fsize  fcrc     ar_estr
 *
 * Returns:
 *  SUCCESS:
 *  FAIL:
 *      archive header is bad.
 *
 * 
>*/
LOCAL SUCC_FAIL
rd_hdr (ar_fp, p_ar_hdr)
FILE * ar_fp;
ARCH_HDR * p_ar_hdr;
{
    SUCC_FAIL   retval;
    CHAR    hdr_line[256];
    INT i;

    retval = SUCCESS;
    if (!fgets (hdr_line, 255,ar_fp)) {
        retval = FAIL;
    } else {
        fld2str (&hdr_line[0], p_ar_hdr->ar_bstr, 15);

        for (i=15; i<30; ++i) {
            if ( hdr_line[i] != ' ') {  
                p_ar_hdr->fname[i-15] = hdr_line[i];
            } else {
                break;
            }
        }
        p_ar_hdr->fname[i-15] = '\0';
                
        fld2str (&hdr_line[30], p_ar_hdr->fsize, 7);
        fld2str (&hdr_line[37], p_ar_hdr->fcrc, 7);
        fld2str (&hdr_line[43], p_ar_hdr->ar_estr, 15);
    }
    return (retval);

}

LOCAL VOID
fld2str ( fld, str, size)
CHAR * fld;
CHAR * str;
INT size;
{
    INT i;
    for (i=0; i<size; ++i) {
        *str++ = *fld++;
    }
    *str = '\0';
}

    

/*<
 * Function:cpf
 * Description:
 *  Copy the first <fsize> bytes of <src_fp> to <dst_fp>
 *
 * Returns:
 *	VOID
 *
 * Side Effects:
 *	Both src_fp and dst_fp characters pointers are moved.
 *
>*/
LOCAL VOID
cpf (src_fp, dst_fp, fsize)
FILE * src_fp;
FILE * dst_fp;
LONG fsize;
{
    LONG i;
    for (i=0; i<fsize; ++i) {
        putc(getc(src_fp), dst_fp);
    }
}


PUBLIC VOID
cant_open (prog_name,filename)
CHAR * prog_name;
CHAR * filename;
{
    fprintf (stderr, "%s :can not open %s \n", prog_name, filename);
} 

STATIC VOID
usage ()
{
    fprintf (stderr, "Usage: %s [-u] [-x] <filename> \n", prog_name);
}

!Funky!Stuff!
echo x - which.c
cat >which.c <<'!Funky!Stuff!'
/*+
 * File: which.c
 * Description:
 *  Tries to mimic Unix's which as closely as possible.
 *  
 * Usages:
 *  which <i_files>
 * 
 *
 *  Author: Mohsen Banan.
 *
 *  This program is public domain software, no warranty intended or
 *  implied.
 *  General permission to copy or modify, but not for profit,  is
 *  hereby  granted.
 *
 * Functions:
 *
 *
 * Audit Trail:  $Log:	which.c,v $
 * Revision 1.1  85/08/28  08:38:54  mohsen
 * original posting to the net
 * 
 * 
 *
-*/

#ifdef RCS_VER
static char *rcs = "$Header: which.c,v 1.1 85/08/28 08:38:54 mohsen Exp $";
#endif

/* #includes */
#include "mbstd.h"
#include <stdio.h>
 
/* #defines */
#ifdef BSD4_2
#define strchr index
#endif

/* external variables */

/* referenced external function declarations */
EXTERN char *getenv();
EXTERN char *strchr();
EXTERN char *strcat();

/* internal function declarations */
PUBLIC VOID which();
STATIC CHAR * get_head();
STATIC BOOL is_runable();
STATIC VOID usage();

/* global variables */

/* static variables */
STATIC CHAR * prog_name;

INT
main (argc, argv)
INT argc;
CHAR * argv[];
{
    which(argc, argv);
}
    

/*<
 * Function:which
 * Description:
 *
 * Returns:
 *  VOID
 * 
>*/
PUBLIC VOID 
which (argc,argv)
INT argc;
CHAR * argv[];
{

    INT i;
    CHAR * head, * nxt_head;        /* head concept is a-la Csh */
    BOOL end_of_path;
    BOOL not_in_path;
    STATIC CHAR file_buf[256];
    STATIC CHAR path_buf[512];
    CHAR * orig_path;

    prog_name = argv[0];
    if (argc < 2) {
        usage();
        exit(1);
    }
    if ((orig_path = getenv("PATH")) == NULL) {
        orig_path = ".";
    }
    for (i=1; i<argc; ++i) {
        end_of_path = FALSE;
        not_in_path = TRUE;
        strcpy (path_buf, orig_path);
        nxt_head = head = path_buf;
        while ( ! end_of_path ) {
            nxt_head = get_head (head);
            if ( nxt_head == NULL) {
                end_of_path = TRUE;
            } else {
                *nxt_head = '\0';
            }
#ifdef unix
            sprintf (file_buf, "%s/%s",(*head ? head:"."), argv[i]);
#endif
#ifdef MSDOS
            sprintf (file_buf, "%s\\%s",(*head ? head:"."), argv[i]);
#endif
            head = ++nxt_head;
            if ( is_runable(file_buf) ) {
                printf ("%s\n", file_buf);
                not_in_path = FALSE;
            }
        }
        if ( not_in_path ) {
            printf ("No %s in %s\n", argv[i], orig_path);
        }
    } /* for i<argc */
    exit (0);
}

STATIC VOID
usage ()
{
    fprintf (stderr, "Usage: %s cmd [cmd, ..]\n", prog_name);
}


STATIC CHAR * 
get_head (head)
CHAR * head;
{
#ifdef unix
    return (strchr( head, ':'));
#endif
#ifdef MSDOS
    return (strchr( head, ';'));
#endif
}

STATIC BOOL
is_runable (file_buf)
CHAR * file_buf;
{
    BOOL ret_val;
    CHAR * name, * root_name;   /* root is as defined by Csh */

    ret_val = FALSE;
#ifdef unix
    if ( access(file_buf, 1) == 0 ) {
        ret_val = TRUE;
    }
#endif
#ifdef MSDOS
    for (root_name=file_buf; *root_name; ++root_name);
    name = strcat(file_buf, ".com");
    if ( access(name, 0) == 0 ) {
        ret_val = TRUE;
    }
    else {
        *root_name = '\0';
        name = strcat(file_buf, ".exe");
        if ( access(name, 0) == 0 ) {
            ret_val = TRUE;
        }
        else {
            *root_name = '\0';
            name = strcat(file_buf, ".bat");
            if ( access(name, 0) == 0 ) {
                ret_val = TRUE;
            }
        }
    }
    printf ("\n %s \n", name);
#endif
    return (ret_val);
}
!Funky!Stuff!


-- 

       !uw-beaver!tikal!mohsen                Mohsen Banan
       Teltone Corporation                    11811 93rd Ave. N.E. #304
       P.O. Box 657                           Kirkland, Wa 98033  USA
       Kirkland, Wa 98033  USA                tel: +1 (206) 821-8560
       tel: +1 (206) 827-9626