/*
** libmatch.c
**
** Libraries and Devices Manager: MatchNode Package
**
** $Id: libmatch.c,v 3.0 94/08/09 17:28:23 GF Exp Locker: GF $
**
**************************************************************************
**
** Copyright © 1994 by Gabriele Falcioni. All Rights Reserved.
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
**
** For inquiries, comments, donations, bug reports, write to:
**
** Gabriele Falcioni
** via E. Cialdini, 50
** I-60122 Ancona
** ITALY
**
*/

#include <string.h>

#include <exec/types.h>
#include <exec/memory.h>
#include <exec/resident.h>
#include <exec/libraries.h>
#include <exec/execbase.h>
#include <dos/dos.h>
#include <dos/dosasl.h>

#include <proto/dos.h>
#include <proto/exec.h>

#include <usrh/filefinder.h>
#include "libman.h"

/* --- My favourite macros -------------------------------------------- */

#define STDMEM (MEMF_PUBLIC|MEMF_CLEAR)

#define ConStruct(type)		((type *)AllocMem(sizeof(type),STDMEM))
#define DiStruct(ptr)		FreeMem((ptr),sizeof(*(ptr)))
#define ClearStruct(ptr)	memset((ptr),0,sizeof(*(ptr)))

#ifndef FOREVER
#define FOREVER for (;;)
#endif

#ifndef STREQ
#define STREQ(s1,s2) (!strcmp((s1),(s2)))
#endif

/* -------------------------------------------------------------------- */

/*
 * NAME
 * CreateNodeMatcher -- NodeMatcher Constructor
 *
 * SYNOPSIS
 * nm = CreateNodeMatcher(names,list);
 *
 * struct NodeMatcher *CreateNodeMatcher(UBYTE **,struct List *);
 *
 * FUNCTION
 * It creates and initializes an instance of NodeMatcher structure.
 * It's used to find the nodes matching a list of names. These names
 * can be standard AmigaDOS patterns. The nodes are linked in an Exec
 * Style list. The matcher supports user breaks (checks are made on
 * SIGBREAKF_CTRL_C).
 *
 * INPUTS
 * names - a pointer to an array of pointers to null-terminated strings.
 *         These can be standard AmigaDOS patterns.
 * list  - the list to search for matching nodes.
 *
 * RESULTS
 * nm - a pointer to an initialized NodeMatcher structure or NULL if not
 *      enough memory.
 *
 * SEE ALSO
 * DeleteNodeMatcher(), MatchNodes()
 */

struct NodeMatcher *CreateNodeMatcher(UBYTE **names,struct List *list)
{
	register struct NodeMatcher *nm;

	if (nm = ConStruct(struct NodeMatcher)) {
		register LONG maxlen,len;

		nm->names = names;
		nm->list  = list;

		maxlen = 0;
		while (*names) {
			len = strlen(*names++);
			if (len > maxlen) maxlen = len;
		}
		++maxlen;
		maxlen <<= 1;

		nm->buflen = maxlen;
		nm->bufptr = AllocMem(maxlen,0L);

		if (nm->bufptr) return nm;

		DiStruct(nm);
	}

	return NULL;
}

/*
 * NAME
 * DeleteNodeMatcher -- NodeMatcher Distructor
 *
 * SYNOPSIS
 * DeleteNodeMatcher(nm);
 *
 * VOID DeleteNodeMatcher(register struct NodeMatcher *);
 *
 * FUNCTION
 * It frees the resources allocated by CreateNodeMatcher().
 *
 * INPUTS
 * nm - a pointer to a valid NodeMatcher structure. A NULL pointer is
 *      tolerated and ignored.
 *
 * SEE ALSO
 * CreateNodeMatcher()
 */

VOID DeleteNodeMatcher(register struct NodeMatcher *nm)
{
	if (nm) {
		if (nm->bufptr) FreeMem(nm->bufptr,nm->buflen);
		DiStruct(nm);
	}
}

/*
 * NAME
 * MatchNodes -- runs the matcher
 *
 * SYNOPSIS
 * node = MatchNodes(nm);
 *
 * struct Node *MatchNodes(register struct NodeMatcher *);
 *
 * FUNCTION
 * It searches the list for matching nodes. It returns a pointer to the
 * matching node or NULL if no more nodes or an error occurred. The latter
 * case can be distinguished examining the return value of IoErr():
 * 0 for no more nodes or a valid AmigaDOS error code.
 * This function checks the SIGBREAKF_CTRL_C signal and exits with error
 * ERROR_BREAK (from IoErr()) if someone has raised this signal.
 *
 * INPUTS
 * nm - a pointer to a valid NodeMatcher structure.
 *
 * RESULT
 * node - a pointer to a matching node or NULL if no more nodes or an error
 *        occurred. Check IoErr() for more:
 *        zero means no mode nodes,
 *        an AmigaDOS error code means *problems*.
 *
 * NOTE
 * No arbitration is made to access the list. It's *not* a wise idea to
 * pass a system list to this function...
 *
 * SEE ALSO
 * CreateNodeMatcher()
 */

struct Node *MatchNodes(register struct NodeMatcher *nm)
{
	register UBYTE **names;
	register struct Node *node;

	names = nm->names;
	node  = nm->next;

	while (*names) {

		if (!node) {
			if (ParsePattern(*names,nm->bufptr,nm->buflen) == -1) return NULL;
			node = nm->list->lh_Head;
		}

		while (node->ln_Succ) {

			if (CheckSignal(SIGBREAKF_CTRL_C)) {
				nm->names = names;
				nm->next  = node;

				SetIoErr(ERROR_BREAK);
				return NULL;
			}

			if (MatchPattern(nm->bufptr,node->ln_Name)) {
				nm->names = names;
				nm->next  = node->ln_Succ;

				SetIoErr(0);
				return node;
			}

			node = node->ln_Succ;
		}

		++names;
		node = NULL;
	}

	nm->names = names;
	nm->next  = NULL;

	SetIoErr(0);
	return NULL;
}
