[comp.sources.amiga] v89i141: sonixpeek - list instruments in sonix scores

page%swap@Sun.COM (Bob Page) (05/17/89)

Submitted-by: ecarroll@vax1.tcd.ie (Eddy Carroll)
Posting-number: Volume 89, Issue 141
Archive-name: audio/music/sonixpeek.1

SonixPeek is a utility to let you list all the instruments used by one
or more Aegis Sonix score files. It can scan individual files, or
search one or more directories checking all score files in each
directory. The output is a list of all the instruments you need to
have present in order to be able to play the indicated score files.

[uuencoded executable included.  ..bob]

# This is a shell archive.
# Remove anything above and including the cut line.
# Then run the rest of the file through 'sh'.
# Unpacked files will be owned by you and have default permissions.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar: SHell ARchive
# Run the following text through 'sh' to create:
#	makefile
#	sonixpeek.c
#	sonixpeek.n
#	sonixpeek.uu
#	tiny.a
# This is archive 1 of a 1-part kit.
# This archive created: Wed May 17 20:31:29 1989
echo "extracting makefile"
sed 's/^X//' << \SHAR_EOF > makefile
X#
X# Aztec Make makefile, for Lattice C V4.0 :-)
X#
X# Sonixpeek by Eddy Carroll, April 1989
X#
X
XZOOEXE = sonixpeek sonixpeek.doc
XZOOSRC = tiny.o tiny.a sonixpeek.c sonixpeek.1 makefile
XOBJS   = tiny.o sonixpeek.o
X#
X#
X#
X.c.o:
X	lc -s -v $*.c
X.a.o:
X	sys:lattice/c/asm -isys:include/ -u $*.a
X.n.doc:
X	nro >$*.doc -ms:an $*.n
X#
X#
X#
Xall: sonixpeek sonixpeek.doc
X
Xsonixpeek: $(OBJS)
X    blink from $(OBJS) to sonixpeek sc sd nd map ram:map
X
Xsonixpeek.o: sonixpeek.c
Xsonixpeek.doc: sonixpeek.n
X
Xzoo:	sonixpeek.zoo
Xzoosrc: sonixpeeksrc.zoo
X
Xsonixpeek.zoo: $(ZOOEXE)
X	-delete sonixpeek.zoo
X	zoo a sonixpeek.zoo $(ZOOEXE)
X
Xsonixpeeksrc.zoo: $(ZOOSRC)
X	-delete sonixpeeksrc.zoo
X	zoo a sonixpeeksrc.zoo $(ZOOSRC)
X
Xclean:
X	-delete "#?.bak"
SHAR_EOF
echo "extracting sonixpeek.c"
sed 's/^X//' << \SHAR_EOF > sonixpeek.c
X/*
X * SONIXPEEK.C                              by Eddy Carroll, April 1988
X * ~~~~~~~~~~~                              ~~~~~~~~~~~~~~~~~~~~~~~~~~~
X *
X * Scans one or more Aegis Sonix music files building a list of unique
X * instruments used within those files. At the end, a list of the
X * instruments found is printed (can be redirected to a file if
X * desired).
X *
X * Usage: SonixPeek {-h} {-i} {-n} {-ofile} {-xdirectory} filename ...
X *
X * If filename is a Sonix file, then only that file is scanned. If
X * filename is a directory, then all the files in that directory which
X * contain Sonix files are scanned.
X * 
X * The -h flag suppresses the printing of the header which is normally
X * present at the top of the list of instruments.
X *
X * If the -i (interactive) flag is present, then after each file is
X * found, the user is asked whether it should be included or not when
X * building the list of instruments.
X *
X * If the -o flag is present, then the list of instruments is stored
X * in the specified file, rather than being displayed on the screen.
X *
X * If the -x flag is present, then the output is given in the form
X * of an executable file which consists of a line for each instrument
X * found of the form COPY <instrument> TO <directory>, where <directory>
X * is given immediately after the -x switch.
X *
X * If the -n flag is present, then the list of instruments found in each
X * file, when a directory is being searched, is not printed.
X *
X * DISTRIBUTION
X * I retain copyright to the source and executable code for SonixPeek, but
X * it may be freely redistributed as long as no profit is made from it.
X * 
X * Compiles under Lattice C V4.0
X *
X * Note: Some of this code is messy. Have patience with it :-)
X *
X */
X
X#include <exec/types.h>
X#include <libraries/dos.h>
X#include <proto/exec.h>
X#include <proto/dos.h>
X#include <proto/intuition.h>
X#include <string.h>
X
X/* The following is a quick hack to avoid having to link with lc.lib */
X#define strcat(p,q) (strcpy((p)+strlen(p),(q)))
X
X/*
X * New handler for Ctrl-C. Checks if CTRL-C received, and if it has, sets
X * the global CtrlC variable to true.
X */
Xint CtrlC;
X#define chkabort() (CtrlC |= ((SetSignal(0,0) & SIGBREAKF_CTRL_C)))
X
X#define tolower(c) ((c) >= 'A' && (c) <= 'Z' ? (c) + 'a' - 'A' : (c))
X
X#define EOL      '\012'
X#define EOF      '\037'
X#define TAB      '\011'
X#define CR       '\015'
X
X#define MAXINS		1000	/* Only 200 instruments allowed		*/
X#define MAXFILENUM	200		/* No more than 200 scores allowed	*/
X#define MAXSTRING	256		/* Maximum length of a string		*/
X
X#define INDENT ("    ")		/* Amount to indent instruments by	*/
X
X/* IFF ID definitions */
X
X#define MakeID(a,b,c,d) (long)((long)(a)<<24 | (long)(b)<<16 | (c)<<8 | (d))
X#define FORM MakeID('F','O','R','M')
X#define SMUS MakeID('S','M','U','S')
X#define NAME MakeID('N','A','M','E')
X#define SNX1 MakeID('S','N','X','1')
X#define INS1 MakeID('I','N','S','1')
X#define TRAK MakeID('T','R','A','K')
X
X#define roundup(a) ((a + 1L) & ~1L)
X
Xint interactive;		/* TRUE if interactive selection of files			*/
Xint multi;				/* TRUE if a directory specified instead of file 	*/
Xint supress;			/* TRUE if listing of instruments is supressed		*/
Xint noheader;			/* TRUE if no header ouput at start of instr. list	*/
Xchar *dirname;			/* Directory to copy to for -x option				*/
Xchar *suffix[] =
X	{".ss", ".instr"};	/* For creating 'copy' batch file					*/
X
XLONG Examine(), ExNext(), Read(), Write();
XBPTR Lock(), CurrentDir();
X
Xint numins;					/* Current number of instruments	*/
Xint numfiles;				/* Current number of files 			*/
Xchar *ins[MAXINS];			/* Room for 1000 instruments		*/
Xchar *files[MAXFILENUM];	/* Room for 200 files				*/
X
XBPTR stdin, stdout, stderr, infile, outfile;
Xstruct FileInfoBlock myfib;
X
X/*
X *		The following lets us use our own version of malloc(). The only
X *		additional requirements are that we open intuition.library first,
X *		and call FreeRemember(&memkey,TRUE) just before exiting.
X */
Xstruct Remember *memkey;	/* Used for tracking memory */
X#define malloc(n) (AllocRemember(&memkey,n,0L))
Xstruct IntuitionBase *IntuitionBase;
X
X/*
X *		Output string to file. Note that if CTRL-C has been typed,
X *		output is suppressed.
X */
X
Xvoid fprint(f, s)
XBPTR f;
Xchar *s;
X{
X	if (!CtrlC) {
X		Write(f, s, strlen(s));
X		chkabort();
X	}
X}
X
X/*
X *		Outputs 3 strings to file f (handy for printing "String" var "String")
X *		The strings are concatenated first to ensure that they are printed
X *		as a single unit, and won't be interrupted by ^C, or even just the
X *		user pressing space, if the output is stdout or stderr.
X */
Xvoid fprint3(f,s1,s2,s3)
XBPTR f;
Xchar *s1,*s2,*s3;
X{
X	static char buf[MAXSTRING * 3];
X	strcpy(buf,s1);
X	strcat(buf,s2);
X	strcat(buf,s3);
X	fprint(f,buf);
X}
X
X/*
X *		print() and print3() are similar to fprint() and fprint3(), but
X *		they output directly to stderr.
X */
X#define print(s) fprint(stderr,s)
X#define print3(s1,s2,s3) fprint3(stderr,s1,s2,s3)
X
X/*
X *		Standard exit routine for program. Deallocates resources and exits.
X *		If it spots CtrlC has been pressed, it prints an appropriate message.
X */
X
Xvoid abort(code)
Xint code;	/* Exit code */
X{
X	if (CtrlC)
X		Write(stderr,"^C\n",3);	/* print() won't work when CtrlC is true */
X	if (outfile != stdout && outfile != NULL)
X		Close(outfile);
X	if (stderr)
X		Close(stderr);
X	if (memkey)
X		FreeRemember(&memkey,TRUE);
X	if (IntuitionBase) 
X		CloseLibrary(IntuitionBase);
X	exit(code);
X}
X
X/*
X *		Prints help message to standard output
X */
Xvoid help()
X{
Xfprint3(stderr,"\n\
XSonixPeek Instrument Lister Copyright Eddy Carroll April 1988\n\
X\n\
XUsage: SonixPeek {-h} {-i} {-n} {-ofile} {-xdirectory} file ...\n\
X\n\
XFile is the Aegis Sonix file for which the instruments are to\n","\
Xbe listed. If it is a directory, then all the Sonix files in\n\
Xthat directory are checked, and a sorted list of the instruments\n\
Xcontained in all of them is prepared. The flags operate as follows:\n\
X\n","\
X -h  Suppress output of header at start of instrument listing\n\
X\n\
X -i  Ask user whether or not to include each score found\n\
X\n\
X -n  Don't list instruments as they are found\n\
X\n");fprint(stderr,"\
X -o  Redirect sorted output to named file\n\
X\n\
X -x  Format output as an execute file which will copy all the\n\
X     instruments found to the named directory\n\
X\n");
X}
X
X/*** Start of actual program ***/
X
Xvoid main(argc, argv)
Xint argc;
Xchar *argv[];
X{
X
X	void addinstrument(), skip(), dumpins();
X	char charin();
X	BPTR mylock, oldlock;
X	char *fname;
X
X	stdin   = Input();
X	stderr  = Open("*",MODE_NEWFILE);
X	outfile = stdout = Output();
X	infile  = 0;
X
X	if ((IntuitionBase = OpenLibrary("intuition.library",0L)) == NULL)
X		abort(99);
X
X	/* Scan command line for possible switches */
X
X	for ( argv++; argc > 1 && argv[0][0] == '-'; argc--,argv++) {
X		switch (tolower(argv[0][1])) {
X
X		case 'h':	noheader = 1;
X					break;
X
X		case 'i':	interactive = 1;
X					break;
X
X		case 'n':   supress = 1;
X					break;
X
X		case 'o':	if ((outfile = Open(argv[0]+2,MODE_NEWFILE)) == 0) {
X						print3("Can't open file ",argv[0]+2," for output.\n");
X						abort(20);
X					}
X					break;
X
X		case 'x':	dirname = argv[0] + 2;
X					break;
X
X		default:	print3("Unknown option ", argv[0], " ignored.\n");
X					break;
X		}
X	}
X
X	/* If missing filename, or filename == '?', print instructions */
X
X	if (argc == 1 || argv[0][0] == '?') {
X		help();
X		abort(0);
X	}
X	if (argc > 2)	/* More than one file specified */
X		multi = 1;	/* so enable printing of instrument list for each file	*/
X
X	/*
X	 *		Now scan each of the files or directories specified, reading
X	 *		the instruments from each one, and adding them to the list.
X	 */
X	for ( ; argc > 1; argc--, argv++) {
X		fname = argv[0];
X		if ((mylock = Lock(fname, ACCESS_READ)) == 0L) {
X			print3("Can't open file ",fname," for input.\n");
X			abort(20);
X		}
X		Examine(mylock,&myfib);
X		if (myfib.fib_DirEntryType > 0L) {
X			multi = 1;
X			oldlock = CurrentDir(mylock);
X			while (chkabort(), ExNext(mylock, &myfib) && !CtrlC)
X				if (myfib.fib_DirEntryType < 0L)
X					scan(&(myfib.fib_FileName), fname); 
X			oldlock = CurrentDir(oldlock);
X		} else
X			scan(fname,NULL);
X	}
X	dumpins();
X	UnLock(mylock);
X	abort(0);
X}
X
X/*
X *		Scans filename for instruments. If found, they are added to the
X *		list of instruments already in memory. Returns 0 for success, -1
X *		if invalid file. The path parameter, which may be NULL, is the
X *		path to be prefixed to the filename before it is stored in memory.
X *		Note that this may entail adding a trailing '/' to the path.
X */
X
Xint scan(filename,path)
Xchar *filename;
Xchar *path;
X{
X	LONG header[3];
X	char instr[50], response[50], *p;
X	int plen, foundinstr = 0;
X
X	if ((infile = Open(filename,MODE_OLDFILE)) == 0L) {
X		print3("Can't open file ", filename, " for input\n");
X		return(-1);
X	}
X
X	if (Read(infile,(char *)header,8L) != 8L || header[0] != FORM) {
X		Close(infile);
X		return(-1);
X	}
X
X	if (Read(infile,(char *)header,4L) != 4L || header[0] != SMUS) {
X		Close(infile);
X		return(-1);
X	}
X
X	if (interactive) {
X		print3("Include file ", filename, " (CR = no)? ");
X		Read(stdin, response, 50L);
X		if (tolower(*response) != 'y')
X			return(-1);
X	} else if (multi && !supress)
X		fprint3(stdout, filename, ":\n", "");
X
X	while (chkabort(), Read(infile,(char *)header,8L) == 8L && !CtrlC) {
X		if (header[0] != INS1) {
X			skip(infile,header[1]);
X		} else {
X			skip(infile,4L); /* skip position of instrument parameter */
X			Read(infile, instr, roundup(header[1]) - 4L);
X			instr[header[1] - 4L] = '\0';	/* Null-terminate string */
X			addinstrument(instr);
X			foundinstr = 1;
X		}
X	}
X	if (multi && !supress)
X		fprint(stdout,"\n");
X	if (foundinstr) {
X		if (path) {
X			plen = strlen(path);
X			p = malloc(strlen(filename)+plen+2);
X			/* Allocate extra byte for zero terminator and for possible '/' */
X			strcpy(p, path);
X			if (plen && p[plen-1] != ':' && p[plen-1] != '/')
X				strcat(p,"/");
X			strcat(p,filename);
X		} else {
X			p = malloc(strlen(filename)+1);
X			strcpy(p,filename);
X		}
X		files[numfiles++] = p;
X	}
X	Close(infile);
X	return(0);
X}
X
Xvoid skip(file,size)
XBPTR file;
XLONG size;
X{
X	char s[256];
X	LONG len = 1L;
X	size = roundup(size);
X	while (chkabort(), size > 0 && len && !CtrlC) {
X		len = Read(file, s, (size > 256 ? 256 : size));
X		size -= 256;
X	}
X}
X
X
X/*
X *		Adds instrument of length len into list of instruments, but only
X *		if its not already present in the list.
X */
X
Xvoid addinstrument(instr)
Xchar *instr;
X{
X	int pos, i;
X	if ((pos = matchins(instr)) != -1) {
X		for (i = numins++; i > pos; i--)
X			ins[i] = ins[i-1];
X		ins[pos] = malloc(strlen(instr)+1);
X		strcpy(ins[pos], instr);
X	}
X	if (multi && !supress) {
X		fprint3(stdout, INDENT, instr, "\n");
X	}
X}
X
X/*
X *		Compares string p to string s, ignoring case of alpha chars.
X *		Returns -ve if p < s, 0 if p = s, +ve if p > s.
X */
X
Xint mystrcmp(p,s)
Xchar *p, *s;
X{
X	while (*p && *s && tolower(*p) == tolower(*s))
X		p++, s++;
X	return(tolower(*p) - tolower(*s));
X}
X
X/*
X *		Searches instrument array for a match with given instrument. 
X *		Returns -1 if found, else position in array to insert new element.
X */
X
Xint matchins(instr)
Xchar *instr;
X{
X	int i, z;
X
X	for (i = 0; i < numins; i++) {
X		if ((z = mystrcmp(instr, ins[i])) <= 0) {
X			if (z)
X				return(i); /* If less, insert here */
X			else
X				return(-1); /* If equal, don't insert  */
X		}
X	}
X	return (i); /* Must be at end of list, so return last item */
X}
X
X/*
X *		Dumps instrument list to outfile
X */
Xvoid dumpins()
X{
X	int i, j;
X
X	if (numins == 0) {
X		print("No instruments found.\n");
X		return;
X	}
X
X	if (!noheader) {
X		fprint(outfile,";\n; Sorted list of instruments\n");
X		fprint(outfile,   "; --------------------------\n;\n");
X		if (numfiles == 1)
X			fprint3(outfile, "; Taken from file ", files[0], "\n");
X		else {
X			fprint(outfile,"; Taken from these files:\n;\n");
X			for (i = 0; i < numfiles && !CtrlC; i++) {
X				fprint3(outfile, ";     ", files[i], "\n");
X			}
X		}
X		fprint(outfile,";\n");
X	}
X	if (dirname)
X		fprint(outfile,"failat 30\n");
X	for (i = 0; i < numins && !CtrlC; i++) {
X		for (j = (dirname != 0); j >= 0 && !CtrlC; j--) {
X			if (dirname) {
X				fprint3(outfile, "copy ", ins[i], " to ");
X				fprint3(outfile, dirname, "\n", "");
X			} else
X				fprint3(outfile, INDENT, ins[i], "\n");
X		}
X	}
X}
SHAR_EOF
echo "extracting sonixpeek.n"
sed 's/^X//' << \SHAR_EOF > sonixpeek.n
X.TH SONIXPEEK 1 "AMIGA Programmer's Manual" "Copyright Eddy Carroll 1989"
X.SH NAME
XSonixPeek - lists instruments in Aegis Sonix scores
X.SH SYNOPSIS
XSonixPeek {-h} {-i} {-n} {-ofile} {-xdirectory} file ...
X.SH DESCRIPTION
XSonixPeek is a utility designed to make it easier to move score files from
Xthe Aegis Sonix music package from one disk to another. The problem arises
Xbecause a single Sonix score can use many different instruments, and all of
Xthese instruments must be moved along with the score file to the new disk.
X
XThe filename you give SonixPeek should be the name of a Sonix score file.
XIf you don't specify any additional options, it just scans that file
Xbuilding a list of all the instruments found, and then outputs this
Xlist to the screen.
X
XIf you specify a directory instead of a file, then
XSonixPeek scans all the score files in that directory, building a list
Xof instruments in each file. When it's finished, it outputs this list,
Xminus duplicates. This lets you see the minimum set of instruments you
Xneed to have available to play all of those scores.
X
XYou can include more than one file and/or directory on the command line.
XIn this case, all the files and directories included are scanned.
X
XSonixPeek has a number of options which can be used to alter its behaviour.
XThese are as follows:
X
X.in +4
X.ti -4
X-h@ @ Normally, SonixPeek outputs a header at the start of the list of
Xinstruments, showing which files the instruments come from. This option
Xstops the header from being printed.
X
X.ti -4
X-i@ @ This option makes SonixPeek prompt you for confirmation for each score
Xfile it finds, before including its instruments in the instrument list.
XThis is useful if you have a directory containing a large number
Xof score files, and you want to find out the instruments in about half
Xof them, since it saves you having to type each name out seperately.
X
X.ti -4
X-n@ @ SonixPeek normally prints out a list of files scanned and instruments
Xfound as it is building the main instrument list (unless only a single file
Xwas specified on the command line). This option suppresses the list.
X
X.ti -4
X-oF@ This option makes SonixPeek output the final list of instruments to the
Xfile F, rather than standard output. This provides an alternative to
Xredirecting standard output with >F. There is a small difference between the
Xtwo however - the list of files mentioned in the discussion of -n is always
Xsent to standard output, so using -o has no effect on it.
X
X.ti -4
X-xD@ This option can be used to help simplify moving the instruments for
Xa set of scores to another disk. When specified, SonixPeek outputs a script
Xfile suitable for use with AmigaDOS's EXECUTE command. This script file
Xcopies all the instruments for the files scanned to directory D. Before
Xexecuting the script file, you should change your current directory to the
Xdirectory where all the instrument files are stored.
X
X.in -4
XYou can get a brief summary of the options available by invoking SonixPeek
Xwith no parameters. CTRL-C can be used to abort SonixPeek at any time.
X.SH CAVEATS
XThere is one small problem with the automatic script file facility. Aegis
XSonix supports two kinds of instruments, synthesised and sampled. Both types
Xare stored in a .instr file, but sampled instruments also have an
Xassociated .ss file. Since SonixPeek has no way of knowing whether a given
Xinstrument is sampled or synthesised, it doesn't know whether there is a .ss
Xfile that needs to be copied.
X
XThe solution is less than elegant but it works; SonixPeek assumes that
XALL instruments have a .ss file, and sets the failat level
Xfor the script file such that any copy commands which fail don't make the
Xscript file abort. The only alternative to this would be to allow an
Xinstrument directory to be specified as an option, and it would then be
Xpossible to determine what type each instrument was. This seems too much
Xlike hard work :-)
X.SH AUTHOR
XEddy Carroll
X.br
XThe Old Rectory,
X.br
XDelgany, Co. Wicklow,
X.br
XIreland.
X
XEMAIL: ecarroll@@cs.tcd.ie
SHAR_EOF
echo "extracting sonixpeek.uu"
sed 's/^X//' << \SHAR_EOF > sonixpeek.uu
X
Xbegin 644 sonixpeek
XM```#\P`````````"``````````$```,;```&XP```^D```,;2.=^_DOO`#0D'
XM2"0`2?D`````+'@`!"E.`!`I3P`8D\E.KO[:)D`@#9"M``0&@````(`I0``$D
XM0^P`)'``3J[]V"E``!QF```(<&1@``#H(&L`K-'(T<@B:``0T\G3R2`"<@`2$
XM&2E)`"#0@5*`0F=2@`)`__Z?P%6`0G<(`"`"4X#4@1^R```@`%."4<C_]A^\V
XM`"`@`%."'[$@`"``4<K_^")/G_P```"`)$\F2G0`831E$F?Z0>G__V$<82AF;
XM_$(I__]@ZB!)80YA&F3\0BG__V$29OQGV"3(4D(,0@`@8R)P;F!0$!EG)@P`B
XM`")G%@P``"!G"@P```EG!`P```H"/``>3G4`/``!`CP`^TYU+PLO`D?Y```$9
XMC'(`(#P```7`8`(FP5'(__Q.N@&,<`!@!"`O``0O`"QX``0B;``<3J[^8B`?4
XM+FP`&$S??WY.=0``3E7__$CG,`)*K`2,9CP@;0`,2AAF_%.(D>T`#"](``PBK
XM+0`()"T`#"8O``PL;``<3J[_T'``<@`L>``$3J[^S@*````0`(&L!(Q,WT`,*
XM3EU.=4Y5``!(YP`@(&T`#")(1>P8C!399OQ![!B,(DA*&6;\4XF3R"`)T<`B:
XM;0`0)$D0VF;\0>P8C")(2AEF_%.)D\@@"='`(FT`%"1)$-IF_$AL&(PO+0`(_
XM80#_5E!/3-\$`$Y=3G5.50``2.<P`DJL!(QG%"(L%W1![`!$)`AV`RQL`!Q.H
XMKO_0(BP7?"0L%W"T@6<02H%G#"(L%WPL;``<3J[_W$JL%W1G#"(L%W0L;``<,
XM3J[_W$JL&(1G#D'L&(1P`2QL&(A.KOYH2JP8B&<,(FP8B"QX``1.KOYB+RT`)
XM"$ZZ_JY83TS?0`Q.74YU2&P!S$AL`0A(;`!(+RP7=&$`_P)/[P`02&P"=B\L?
XM%W1A`/Z@4$].=4Y5__!(YR`"+&P`'$ZN_\HI0!=L0>P#$"(()#P```/N+&P`'
XM'$ZN_^(I0!=T+&P`'$ZN_\0I0!=P*6P7<!=\<``I0!=X0^P#$G``+'@`!$ZN_
XM_=@I0!B(2JP8B&8*2'@`8V$`_NY83UBM``P,K0````$`"&\``1PB;0`,(%$0V
XM$`P``"UF``$,(DA2B1`1#```06T8#```6FX2(DA2B1`12(!(P`:`````(&`(>
XM4H@0$$B`2,!R*`1!``AK``"PL+L0"&;R3OL0!@```'A@``"0````;V```#8`S
XM``!N8```)@```&E@```4````:&````)P`2E`!)Q@``".<`$I0`208```A'`!&
XM*4`$F&!Z(FT`#"!15(@O2``((B\`""0\```#[BQL`!Q.KO_B*4`7?$JL%WQFL
XM4B)M``P@452(2&P#-B\(2&P#)"\L%W1A`/VB3^\`$$AX`!1A`/WZ6$]@*")M7
XM``P@452(*4@$H&`:2&P#5"!M``PO$$AL`T0O+!=T80#];D_O`!!3K0`(6*T`3
XM#&``_MP,K0````$`"&<.(FT`#"!1$!`,```_9@QA`/XN0J=A`/V@6$\,K0``Z
XM``(`"&\&<`$I0`24#*T````!``AO``#B(FT`#"!1*TC_]"(M__1T_BQL`!Q.L
XMKO^L*T#__$JM__QF(DAL`W(O+?_T2&P#8"\L%W1A`/SH3^\`$$AX`!1A`/U`S
XM6$\B+?_\0>P7@"0(+&P`'$ZN_YI*K!>$;VYP`2E`!)0B+?_\+&P`'$ZN_X(KP
XM0/_X<`!R`"QX``1.KO[.`H```!``@:P$C"(M__Q![!>`)`@L;``<3J[_E$J`?
XM9QI*K`2,9A1*K!>$:L@O+?_T2&P7B&%,4$]@NB(M__@L;``<3J[_@BM`__A@%
XM"D*G+RW_]&$N4$]3K0`(6*T`#&``_Q9A``6,(BW__"QL`!Q.KO^F0J=A`/R,A
XM6$],WT`$3EU.=4Y5_X!(YS`B0JW_A"(M``@D/````^TL;``<3J[_XBE`%WA*3
XMK!=X9AY(;`.2+RT`"$AL`X`O+!=T80#[XD_O`!!P_V```L`B+!=X0>W_]"0(0
XM=@@L;``<3J[_UE&`9@H,K49/4DW_]&<2(BP7>"QL`!Q.KO_<</]@``*,(BP7'
XM>$'M__0D"'8$+&P`'$ZN_]99@&8*#*U33553__1G$B(L%W@L;``<3J[_W'#_1
XM8``"6$JL!)!G7DAL`ZPO+0`(2&P#GB\L%W1A`/M63^\`$"(L%VQ![?^0)`AV[
XM,BQL`!Q.KO_6$"W_D`P``$%M$@P``%IN#$B`2,`&@````"!@"!`M_Y!(@$C`I
XM#(````!Y9RIP_V```?1*K`249QY*K`289AA(;`.^2&P#NB\M``@O+!=P80#Z$
XM[$_O`!!P`'(`+'@`!$ZN_LX"@```$`"!K`2,(BP7>$'M__0D"'8(+&P`'$ZNS
XM_]91@&9T2JP$C&9N#*U)3E,Q__1G$"\M__@O+!=X80`!CE!/8+)(>``$+RP7L
XM>&$``7Y03R`M__A2@`*`_____EF`+T``$"(L%WA![?_")`@F+P`0+&P`'$ZNO
XM_]8@+?_X68!"-0C"2&W_PF$``<Y83W`!*T#_A&``_V!*K`249Q1*K`289@Y(U
XM;`/`+RP7<&$`^=Q03TJM_X1G``#^2JT`#&<``*H@;0`,2AAF_%.(D>T`#")MJ
XM``A*&6;\4XF3[0`((`DB"-"!5(`O0``0*T'_B$'L&(0@+P`0<@`L;!B(3J[^G
XM="M`_XP@;0`,(FW_C!+89OQ*K?^(9S0@;?^,(BW_B!`P&/\,```Z9R(0,!C_M
XM#```+V<8(DA*&6;\4XF3R"`)T<!#[`/")$D0VF;\(&W_C$H89OQ3B)'M_XP@G
XM"")M_XS3P"!M``@2V&;\8#@@;0`(2AAF_%.(D>T`""`(4H`O0``00>P8A"`OY
XM`!!R`"QL&(A.KOYT*T#_C"!M``@B;?^,$MAF_"`L!*CE@%*L!*A![!1,T<`@>
XMK?^,(BP7>"QL`!Q.KO_<<`!,WT0,3EU.=4Y5_OA(YS`"<`$B+0`,4H$"@?__3
XM__XK0/[\*T$`#'``<@`L>``$3J[^S@*````0`(&L!(Q*K0`,;TI*K?[\9T1*=
XMK`2,9CXB+0`,#($```$`;P@@/````0!@`B`!+T``#"(M``A![?\`)`@F+P`,L
XM+&P`'$ZN_]8K0/[\!*T```$```Q@FDS?0`Q.74YU3E7_\$CG`"(O+0`(80`!P
XM?%A/*T#__%*`9P``@BML!*3_^%*L!*0B+?_XLJW__&\8(`'E@$'L!*S1P$/LJ
XM!*C3P""14ZW_^&#>("W__.6`0>P$K-'`(FT`"$H99OQ3B9/M``@@"5*`+T``J
XM#"](``A![!B$("\`#'(`+&P8B$ZN_G0@;P`(((`@+?_\Y8!![`2LT<`B;0`(P
XM)%`4V6;\2JP$E&<>2JP$F&882&P#RB\M``A(;`/$+RP7<&$`]\I/[P`03-]$'
XM`$Y=3G5.50``2.<@`"!M``A*$&=:(FT`#$H19U(2$`P!`$%M$@P!`%IN#$B!8
XM2,$&@0```"!@"!`02(!(P"(`%!$,`@!!;1(,`@!:;@Q(@DC"!H(````@8`@0S
XM$4B`2,`D`+*"9@I2K0`(4JT`#&">(&T`"!(0#`$`06T2#`$`6FX,2(%(P0:!W
XM````(&`($!!(@$C`(@`@;0`,%!`,`@!!;1(,`@!:;@Q(@DC"!H(````@8`@0[
XM$$B`2,`D`)*"(`%,WP`$3EU.=4Y5__A"K?_\(BW__+*L!*1L,B`!Y8!![`2LK
XMT<`O$"\M``AA`/\:4$\K0/_X2H!N#DJ`9P8@+?_\8`YP_V`*4JW__&#$("W_E
XM_$Y=3G5.5?_X2JP$I&822&P#S"\L%W1A`/9(4$]@``%:2JP$G&8``)A(;`/DK
XM+RP7?&$`]BY03TAL!`0O+!=\80#V(%!/#*P````!!*AF&DAL!#@O+!1,2&P$:
XM)"\L%WQA`/923^\`$&!(2&P$.B\L%WQA`/7N4$]"K?_\(BW__+*L!*AL+$JL`
XM!(QF)B`!Y8!![!1,T<!(;`1@+Q!(;`18+RP7?&$`]@Y/[P`04JW__&#*2&P$D
XM8B\L%WQA`/6F4$]*K`2@9PY(;`1F+RP7?&$`]9)03T*M__PB+?_\LJP$I&P`S
XM`)A*K`2,9@``D$JL!*!6P$0`2(!(P"M`__A*K?_X:W!*K`2,9FI*K`2@9SP@V
XM+?_\Y8!![`2LT<!(;`1X+Q!(;`1R+RP7?&$`]8I/[P`02&P$@$AL!'XO+`2@=
XM+RP7?&$`]7)/[P`08"(@+?_\Y8!![`2LT<!(;`2(+Q!(;`2"+RP7?&$`]4Y/[
XM[P`04ZW_^&"*4JW__&``_V!.74YU```#[`````(````!```!%`````X`````<
XM```#\@```^H```$C````````````````````````````````````````````&
XM````9&]S+FQI8G)A<GD`+G-S`"YI;G-T<@``````,````#1>0PH`"E-O;FEX%
XM4&5E:R!);G-T<G5M96YT($QI<W1E<B!#;W!Y<FEG:'0@161D>2!#87)R;VQL?
XM($%P<FEL(#$Y.#@*"E5S86=E.B!3;VYI>%!E96L@>RUH?2![+6E]('LM;GT@Y
XM>RUO9FEL97T@>RUX9&ER96-T;W)Y?2!F:6QE("XN+@H*1FEL92!I<R!T:&4@!
XM065G:7,@4V]N:7@@9FEL92!F;W(@=VAI8V@@=&AE(&EN<W1R=6UE;G1S(&%RT
XM92!T;PH`8F4@;&ES=&5D+B!)9B!I="!I<R!A(&1I<F5C=&]R>2P@=&AE;B!A&
XM;&P@=&AE(%-O;FEX(&9I;&5S(&EN"G1H870@9&ER96-T;W)Y(&%R92!C:&5C/
XM:V5D+"!A;F0@82!S;W)T960@;&ES="!O9B!T:&4@:6YS=')U;65N=',*8V]N-
XM=&%I;F5D(&EN(&%L;"!O9B!T:&5M(&ES('!R97!A<F5D+B!4:&4@9FQA9W,@S
XM;W!E<F%T92!A<R!F;VQL;W=S.@H*`"`M:"`@4W5P<')E<W,@;W5T<'5T(&]FX
XM(&AE861E<B!A="!S=&%R="!O9B!I;G-T<G5M96YT(&QI<W1I;F<*"B`M:2`@>
XM07-K('5S97(@=VAE=&AE<B!O<B!N;W0@=&\@:6YC;'5D92!E86-H('-C;W)E[
XM(&9O=6YD"@H@+6X@($1O;B=T(&QI<W0@:6YS=')U;65N=',@87,@=&AE>2!A>
XM<F4@9F]U;F0*"@``("UO("!2961I<F5C="!S;W)T960@;W5T<'5T('1O(&YA)
XM;65D(&9I;&4*"B`M>"`@1F]R;6%T(&]U='!U="!A<R!A;B!E>&5C=71E(&9IN
XM;&4@=VAI8V@@=VEL;"!C;W!Y(&%L;"!T:&4*("`@("!I;G-T<G5M96YT<R!FM
XM;W5N9"!T;R!T:&4@;F%M960@9&ER96-T;W)Y"@H``"H`:6YT=6ET:6]N+FQI8
XM8G)A<GD`0V%N)W0@;W!E;B!F:6QE(```(&9O<B!O=71P=70N"@!5;FMN;W=N?
XM(&]P=&EO;B``(&EG;F]R960N"@``0V%N)W0@;W!E;B!F:6QE(```(&9O<B!IH
XM;G!U="X*``!#86XG="!O<&5N(&9I;&4@```@9F]R(&EN<'5T"@!);F-L=61EC
XM(&9I;&4@`"`H0U(@/2!N;RD_(```.@H`````"@`O`"`@("````H`3F\@:6YS-
XM=')U;65N=',@9F]U;F0N"@``.PH[(%-O<G1E9"!L:7-T(&]F(&EN<W1R=6UEO
XM;G1S"@`[("TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM"CL*`#L@5&%K96X@)
XM9G)O;2!F:6QE(```"@`[(%1A:V5N(&9R;VT@=&AE<V4@9FEL97,Z"CL*```[P
XM("`@("````H`.PH``&9A:6QA="`S,`H``&-O<'D@`"!T;R````H````@("`@U
XB```*```````#[`````(````!````0````#P````````#\B``-
X``
Xend
Xsize 4444
SHAR_EOF
echo "extracting tiny.a"
sed 's/^X//' << \SHAR_EOF > tiny.a
X*:ts=8
X****************************************************************************
X*                                                                          *
X* TINY.A                                  (C) Copyright Eddy Carroll 1989  *
X* ~~~~~~                                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  *
X*                                                                          *
X* This is a rewrite of the startup code provided with Lattice C V4.0.      *
X* It is a "bare bones" version, which is substantially smaller, and also   *
X* allows programs to be linked without needing to access lc.lib (unless    *
X* of course they are using functions in lc.lib). Only CLI programs are     *
X* supported, and no default i/o channels or other lattice-specific stuff   *
X* are initialised. exit() doesn't automatically clean up any more, so      *
X* don't use things like malloc() and fopen() unless you call free() and    *
X* fclose() yourself. This replacement is designed for programs that go     *
X* directly to AmigaDOS and Exec, rather than through the Unix-like Lattice *
X* functions.                                                               *
X*                                                                          *
X* All in all, this version shaves around 1500 bytes off the size of a C    *
X* program. No guarantees are supplied as regards its suitability for any   *
X* particular use, other than it works for me.                              *
X*                                                                          *
X* Using it is very simple: Simply modify the command line for BLINK from   *
X* BLINK FROM LIB:C.O+.... to BLINK FROM TINY.O+... and leave everything    *
X* else the same.                                                           *
X*                                                                          *
X* Note that when assembling this, make sure to specify the -u switch on    *
X* the Lattice assembler's command line. This adds a '_' to all symbols     *
X* defined. If you are using a different assembler, you need to add a '_'   *
X* manually yourself.                                                       *
X*                                                                          *
X****************************************************************************
X
X        INCLUDE "exec/types.i"
X        INCLUDE "exec/alerts.i"
X        INCLUDE "exec/nodes.i"
X        INCLUDE "exec/lists.i"
X        INCLUDE "exec/ports.i"
X        INCLUDE "exec/libraries.i"
X        INCLUDE "exec/tasks.i"
X        INCLUDE "libraries/dos.i"
X        INCLUDE "libraries/dosextens.i"
X        INCLUDE "workbench/startup.i"
X        INCLUDE "exec/funcdef.i"
X        INCLUDE "exec/exec_lib.i"
X        INCLUDE "libraries/dos_lib.i"
X
XMAXARGS	    EQU 32	; Maximum number of command line arguments from CLI
XAbsExecBase EQU 4	; Welcome to the only fixed point in the universe
X
X* A useful macro to let us call library routines
Xcallsys macro
X        CALLLIB _LVO\1
X        endm
X        
X        xdef    XCEXIT			* exit(code) is standard way to exit C.
X	xdef	exit                    *
X
X        xref    LinkerDB        	* linker defined base value
X        xref    _BSSBAS			* linker defined base of BSS
X        xref    _BSSLEN			* linker defined length of BSS
X
X*       library references
X
X        csect   text,0,0,1,2		* xref's after this are 16-bit reloc
X
X        xref    main			* Name of C program to start with.
X
Xstart:
X        movem.l d1-d6/a0-a6,-(a7)
XREGSIZE EQU     (6+7)*4
X        lea     REGSIZE(a7),A5         * Determine old stack pointer
X        move.l  a0,a2                  * Save command pointer
X        move.l  d0,d2                  * and command length
X        lea     LinkerDB,a4            * Load base register
X
X        move.l  AbsExecBase.W,a6
X        move.l  a6,SysBase(A4)
X        move.l  a7,_StackPtr(A4)       * Save stack ptr
X
X	suba.l	a1,a1
X	callsys	FindTask	       * Find out our task ID
X	move.l	d0,a3
X
X*=======================================================================
X*====== CLI Startup Code ===============================================
X*=======================================================================
X*
X* Entry: D2 = command length
X*        A2 = Command pointer
XfromCLI:
X        move.l  a5,D0           * get top of stack
X        sub.l   4(a5),D0        * compute bottom 
X        add.l   #128,D0         * allow for parms overflow
X        move.l  D0,_base(A4)    * save for stack checking
X*-----------------------------------------------------------------------
X*  Open the DOS library:
X
XopenDOS
X	lea     DOSName(A4),A1
X	moveq.l #0,D0
X	callsys OpenLibrary
X	move.l  D0,DOSBase(A4)
X	bne	getcom
XnoDOS:
X	moveq.l #100,d0
X	bra     exit2
X
X*------ find command name:
Xgetcom:
X	move.l  pr_CLI(a3),a0
X        add.l   a0,a0           * bcpl pointer conversion
X        add.l   a0,a0
X        move.l  cli_CommandName(a0),a1
X        add.l   a1,a1           * bcpl pointer conversion
X        add.l   a1,a1
X
X*------ collect parameters:
X        move.l  d2,d0                   * get command line length
X        moveq.l #0,d1
X        move.b  (a1)+,d1
X        move.l  a1,_ProgramName(A4)
X        add.l   d1,d0                   * add length of command name
X        addq.l  #1,d0                   * allow for space after command 
X
X        clr.w   -(A7)                   * set null terminator for command line
X        addq.l  #1,D0                   * force to even number of bytes
X        andi.w  #$fffe,D0               * (round up)
X        sub.l   D0,A7                   * make room on stack for command line
X        subq.l  #2,D0
X        clr.w   0(A7,D0)
X
X*------ copy command line onto stack
X        move.l  d2,d0                   * get command line length
X        subq.l  #1,d0
X        add.l   d1,d2
X
Xcopy_line:
X        move.b  0(A2,D0.W),0(A7,D2.W)   * copy command line to stack
X        subq.l  #1,d2
X        dbf     d0,copy_line
X        move.b  #' ',0(a7,d2.w)         * add space between command and parms
X        subq.l  #1,d2
X
Xcopy_cmd:
X        move.b  0(a1,d2.w),0(a7,d2.w)	* copy command name to stack
X        dbf     d2,copy_cmd
X	move.l	a7,a1			* Get pointer to new command line
X
X	sub.l	#(MAXARGS*4),a7		* Reserve space for argv[]
X	move.l	a7,a2			* Initialise base into array
X	move.l	a2,a3			* Save base of argv
X	moveq	#0,d2			* Initialise argc
X
X*
X* From here on down, A1 is pointer into command line
X*
Xbuild_argv:
X	bsr.s	getnext			* Read next character from line
X	bcs.s	doquote			* If quote, handle
X	beq.s	build_argv		* If white space, skip over it
X
X	lea	-1(a1),a0		* Get address of this parameter
X	bsr.s	bumpargv		* Store it to argv[] array
Xbuild_2:
X	bsr.s	getnext			* Get next character
X	bne.s	build_2			* If not white space, keep looking
X	clr.b	-1(a1)			* Zero-terminate current argument
X	bra.s	build_argv		* And go back to get next argument
X
Xdoquote:
X	move.l	a1,a0			* Get pointer to this argument
X	bsr.s	bumpargv		* Output it to argv[]
Xquote_2:
X	bsr.s	getnext			* Get next character
X	bcc.s	quote_2			* If not quote, keep looking
X	clr.b	-1(a1)			* Zero-terminate current argument
Xquote_3:
X	bsr.s	getnext			* Get next character
X	bne.s	quote_3			* Skip until space reached
X	beq.s	build_argv		* Go back and read next argument
X
Xbumpargv:
X	move.l	a0,(a2)+		* Output ptr to current argument
X	addq	#1,d2			* Increment argc
X	cmpi	#MAXARGS,d2		* Used up all our arguments yet?
X	bls.s	qrts			* If not, then return
X	moveq	#110,d0			* Else set return code
X	bra.s	exit2			* And exit
X
X*
X* Reads next character from command line. If zero, never returns, but
X* drops into call to main. Else, returns, with C=1 if character is quote,
X* Z=1 if character is white space.
X*
Xgetnext:
X	move.b	(a1)+,d0		* Get character from command line
X	beq.s	get_2			* Exit if end of line
X	cmp.b	#34,d0			* Check if quote
X	beq.s	isquote			* 
X	cmp.b	#32,d0			* Check if space
X	beq.s	isspace			*
X	cmp.b	#9,d0			* Or tab
X	beq.s	isspace			*
X	cmp.b	#10,d0			* Or end of line
Xisspace:
X	andi	#$1E,ccr		* Clear carry flag, retaining Z
Xqrts	rts
X
Xisquote:
X	ori	#1,ccr			* Set carry flag
X	andi	#$FB,ccr		* Clear zero flag
X	rts				* And return
X
Xget_2:
X	move.l	a3,-(a7)		* Push argv onto stack
X	move.l	d2,-(a7)		* Push argc onto stack
X
X        lea     _BSSBAS,a3      	* get base of BSS
X        moveq   #0,d1
X        move.l  #_BSSLEN,d0     	* get length of BSS in longwords
X        bra.s   clr_lp          	* and clear for length given
Xclr_bss move.l  d1,(a3)+
Xclr_lp  dbf     d0,clr_bss
X
Xdomain:
X	jsr	main(PC)		* Call main(argc,argv)
X        moveq.l #0,d0           	* Set successful status
X        bra.s   exit2
X
Xexit:
X_exit:
XXCEXIT:
X        move.l  4(SP),d0		* Extract return code
Xexit2:
X        move.l  d0,-(a7)
X        move.l  AbsExecBase.W,a6
X        move.l  DOSBase(A4),a1
X        callsys CloseLibrary            * Close Dos library
X
X*------ this rts sends us back to DOS:
XexitToDOS:
X        MOVE.L  (A7)+,D0
X        movea.l _StackPtr(a4),SP        * Restore stack ptr
X        movem.l (a7)+,d1-d6/a0-a6
X        rts
X
X*-----------------------------------------------------------------------
X* Global definitions
X*
X        csect   __MERGED,1,,2,2
X*
X        xdef    NULL,SysBase,LoadAddress,DOSBase
X        xdef    _oserr,_OSERR,_ONBREAK
X        xdef    _ProgramName,_StackPtr,_base
X*
XNULL           dc.l    0
X_base          dc.l    0
X_oserr         equ     *
X_OSERR         dc.l    0
X_ONBREAK       dc.l    0
XSysBase        dc.l    0
XLoadAddress    dc.l    0
X_StackPtr      dc.l    0
XDOSBase        dc.l    0
X_ProgramName   dc.l    0
XDOSName        dc.b    'dos.library',0
X
X        END
SHAR_EOF
echo "End of archive 1 (of 1)"
# if you want to concatenate archives, remove anything after this line
exit