/*	(set TAB size to 5)

	"touch" 37.1 written by Ralph Seichter, Copyright (c) 1992.

	Touching a file means setting its file date and time to the current
	system clock settings.  This  comes handy in combination with tools
	like "make" which naturally depend on proper date settings. I wrote
	my own version of "touch" just to see how it can be done.  :)

	DISCLAIMER:   You agree to use "touch" entirely at your own risk. I
	can not be held responsible for any damage caused by using "touch".
	I declare this program PUBLIC DOMAIN.  You  may do with it whatever
	you wish, as long as you remember the following conditions:

	o  The distribution archive must be left intact.  No file may be
	   changed without comment and absolutely no file may be deleted
	   from the archive, so everyone has the chance to recompile the
	   source (I don't want to slip you a virus).
	o  You must not gain any profit from giving "touch" to others.
	o  You must not include any of this code in commercial software.

	TEMPLATE:	touch PATTERN/A,QUIET/S

	USAGE:	touch ram:foo#?
			touch sys:s/start???sequence
			touch #?.c quiet

	COMMENTS:  Sorry, this was a quick shot which surely leaves much to
	be done for the future (like multiple patterns). But it does what I
	want it to do for me...  ;)
*/

#include	<dos/exall.h>
#include	<exec/memory.h>
#include	<proto/exec.h>
#include	<proto/dos.h>
#include	<stdio.h>
#include	<string.h>

#define	ARG_PATTERN	0
#define	ARG_QUIET		1
#define	ARG_TOTAL		2
#define	BUFSIZE		256



/* globals and prototypes */

STRPTR noMemory = "Not enough memory!\n";

struct TouchArgs {
	STRPTR Orig;			/* pointer to original pattern argument */
	UBYTE Pat[BUFSIZE];		/* pattern buffer */
	UBYTE Dir[BUFSIZE];		/* directory name buffer */
	UBYTE DirSep[2];		/* directory seperator string */
	BOOL Wild;			/* set if pattern contains wildcards */
	BOOL Quiet;			/* set for quiet mode */
	struct DateStamp DateStamp;
};

VOID findDir (struct TouchArgs *);
WORD main (WORD, STRPTR *);
VOID touch (struct TouchArgs *);
VOID touchFile (struct TouchArgs *, STRPTR);



/* the main program */

WORD main (WORD argc, STRPTR *argv)
{
	STRPTR version = "\0$VER: touch 37.1 (28.11.92) by Ralph Seichter";
	STRPTR template = "PATTERN/A,QUIET/S";
	struct RDArgs *args, *rda;
	struct TouchArgs *ta;
	LONG taSize, array[ARG_TOTAL] = {0,0};

	printf ("\2331m%s\2330m\n", &version[7]);
	if (DOSBase->dl_lib.lib_Version >= 37) {
		if (rda = AllocDosObject (DOS_RDARGS, NULL)) {
			if (args = ReadArgs (template, array, rda)) {
				taSize = sizeof (struct TouchArgs);
				if (ta = AllocMem (taSize, MEMF_CLEAR)) {
					ta->Quiet = (array[ARG_QUIET] != 0);
					ta->Orig = (STRPTR)(array[ARG_PATTERN]);
					ta->Wild = ParsePatternNoCase (ta->Orig, ta->Pat, BUFSIZE);
					findDir (ta);
					touch (ta);
					FreeMem (ta, taSize);
				} else
					printf (noMemory);
				FreeArgs (args);
			} else
				printf ("Command template is %s.\n", template);
			FreeDosObject (DOS_RDARGS, rda);
		} else
			printf (noMemory);
	} else
		printf ("Requires dos.library V37\n");
	return (RETURN_OK);
}



/* seperate directory from pattern string */

VOID findDir (struct TouchArgs *ta)
{
	WORD i;
	STRPTR p = ta->Pat;

	for (i = strlen (p) - 1; i >= 0; --i) {
		switch (p[i]) {
			case ':':
				++i;
				stccpy (ta->Dir, p, i + 1);
				strcpy (p, &p[i]);
				i = -1;
				break;
			case '/':
				++i;
				*ta->DirSep = '/';
				stccpy (ta->Dir, p, i);
				strcpy (p, &p[i]);
				i = -1;
		}
	}
}



/* touch one single file */

VOID touchFile (struct TouchArgs *ta, STRPTR name)
{
	struct DateStamp *ds = &ta->DateStamp;

	DateStamp (ds);
	if (SetFileDate (name, ds)) {
		if (!ta->Quiet)
			printf ("\"%s\" touched.\n", name);
	} else
		printf ("Can't touch \"%s\".\n", name);
}



/* here's the touching stuff */

VOID touch (struct TouchArgs *ta)
{
	struct ExAllData *ead, *data;
	struct ExAllControl *eac;
	UBYTE name[BUFSIZE];
	LONG eadSize, err;
	BOOL more;
	BPTR lock;

	if (ta->Wild) {
		if (lock = Lock (ta->Dir, SHARED_LOCK)) {
			if (eac = AllocDosObject (DOS_EXALLCONTROL, NULL)) {
				eac->eac_MatchString = ta->Pat;
				eadSize = sizeof (struct ExAllData);
				if (ead = AllocMem (eadSize, MEMF_CLEAR)) {
					do {
						more = ExAll (lock, ead, eadSize, ED_NAME, eac);
						err = IoErr ();
						if (!more && err != ERROR_NO_MORE_ENTRIES) {
							printf ("ExAll failed!\n");
							break;
						}
						if (eac->eac_Entries != 0) {
							data = ead;
							while (data) {
								sprintf (name, "%s%s%s", ta->Dir, ta->DirSep, data->ed_Name);
								touchFile (ta, name);
								data = data->ed_Next;
							}
						}
					} while (more);
					FreeMem (ead, eadSize);
				} else
					printf (noMemory);
				FreeDosObject (DOS_EXALLCONTROL, eac);
			} else
				printf (noMemory);
			UnLock (lock);
		} else
			printf ("Can't lock directory \"%s\".\n", ta->Dir);
	} else
		touchFile (ta, ta->Orig);
}
