/*
 *  RequestFile clone for AmigaDOS 2.04 (V37).
 *  Use RequestFile 38.x if you have AmigaDOS 2.1 (V38) or better.
 *  Copyright (C) 1994 Torsten Poulin Nielsen
 *
 *  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.
 *
 *             The author can be contacted by mail at
 *               Torsten Poulin
 *               Banebrinken 99, 2, 77
 *               DK-2400 Copenhagen NV
 *               Denmark
 *             or via email: torsten@diku.dk
 *
 *
 * Differences from RequestFile 38.x:
 *   - The PUBSCREEN/K option is a no-op.
 *   - Only the first six chars of the POSITIVE and NEGATIVE
 *     strings are used.
 *   - Other Asl V38 features missing from Asl V37 are emulated
 *     with a call-back hook function.
 *
 * With the risk of sounding repetitive: Do yourself a favour
 * and use version 38.x, if you can. It is smaller and more
 * flexible.
 *
 * $Id: RequestFile.c,v 1.2 94/02/09 00:23:42 Torsten Rel $
 * $Log:	RequestFile.c,v $
 * Revision 1.2  94/02/09  00:23:42  Torsten
 * Changed DIR to DRAWER in template.
 * Filenames are now printed all on one line,
 * separated by one space. They are enclosed in quotes, too.
 * WARN (5) is returned if the request is cancelled.
 * We return FAIL (20) if the requester didn't open for some reason.
 *    The above should make us more compatible :)
 * 
 * Revision 1.1  94/01/31  14:16:55  Torsten
 * Initial revision
 * 
 */

#include <exec/types.h>
#include <exec/memory.h>
#include <dos/dosextens.h>
#include <dos/rdargs.h>
#include <dos/dosasl.h>
#include <libraries/asl.h>
#include <workbench/startup.h>
#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/asl_protos.h>

#ifdef __SASC
#include <pragmas/exec_pragmas.h>
#include <pragmas/dos_pragmas.h>
#include <pragmas/asl_pragmas.h>
#endif
#ifndef __AMIGADATE__
#define __AMIGADATE__ "(31.1.94)"
#endif

#include <string.h>

#define PATHLEN 512
#define TEMPLATE \
"DRAWER,FILE/K,PATTERN/K,TITLE/K,POSITIVE/K,NEGATIVE/K,ACCEPTPATTERN/K,\
REJECTPATTERN/K,SAVEMODE/S,MULTISELECT/S,DRAWERSONLY/S,\
NOICONS/S,PUBSCREEN/K"

char const ver[] = "$VER: RequestFile 37.2 " __AMIGADATE__;
char const cop[] = "$COPYRIGHT: © 1994 Torsten Poulin$";

struct userdata {
  struct Library *DOSBase;
  STRPTR accept;
  STRPTR reject;
  UBYTE noicons[17]; /* more than enough for parsing #?.info */
};

CPTR HookFunc(LONG, CPTR, struct FileRequester *);

long reqfile(void)
{
  struct Library *AslBase;
  struct Library *DOSBase;
  struct RDArgs *rdarg;
  struct FileRequester *fr;
  struct TagItem tags[10];
  struct WBArg *frargs;
  int t = 0;
  long flags = 0;
  UBYTE *dirname, *accept = NULL, *reject = NULL;
  long patlen;
  long rc = RETURN_OK;

  struct userdata ud;
    
  struct {
    STRPTR path;
    STRPTR file;
    STRPTR pattern;
    STRPTR title;
    STRPTR positive;
    STRPTR negative;
    STRPTR acceptpat;
    STRPTR rejectpat;
    LONG save;
    LONG multi;
    LONG drawers;
    LONG noicons;
    STRPTR pubscreen;
  } opt;

  if (DOSBase = OpenLibrary("dos.library", 37)) {
    if (AslBase = OpenLibrary("asl.library", 37)) {
      if (dirname = AllocVec(PATHLEN+1, MEMF_ANY)) {
	memset((char *) &opt, 0, sizeof(opt));
	memset((char *) &ud, 0, sizeof(ud));
	ud.DOSBase = DOSBase;

	if (rdarg = ReadArgs(TEMPLATE, (LONG *) &opt, NULL)) {

	  if (opt.path) {
	    tags[t].ti_Tag = ASL_Dir;
	    tags[t++].ti_Data = (ULONG) opt.path;
	  }
	  if (opt.file) {
	    tags[t].ti_Tag = ASL_File;
	    tags[t++].ti_Data = (ULONG) opt.file;
	  }
	  if (opt.pattern) {
	    tags[t].ti_Tag = ASL_Pattern;
	    tags[t++].ti_Data = (ULONG) opt.pattern;
	    flags |= FILF_PATGAD;
	  }
	  if (opt.title) {
	    tags[t].ti_Tag = ASL_Hail;
	    tags[t++].ti_Data = (ULONG) opt.title;
	  }
	  if (opt.positive) {
	    tags[t].ti_Tag = ASL_OKText;
	    if (strlen(opt.positive) > 6)
	      opt.positive[6] = '\0'; /* Truncate the string */
	    tags[t++].ti_Data = (ULONG) opt.positive;
	  }
	  if (opt.negative) {
	    tags[t].ti_Tag = ASL_CancelText;
	    if (strlen(opt.negative) > 6)
	      opt.positive[6] = '\0'; /* Truncate the string */
	    tags[t++].ti_Data = (ULONG) opt.negative;
	  }
	  if (opt.save) flags |= FILF_SAVE;
	  if (opt.multi) flags |= FILF_MULTISELECT;
	  if (opt.drawers) {
	    tags[t].ti_Tag = ASL_ExtFlags1;
	    tags[t++].ti_Data = FIL1F_NOFILES;
	  }

	  /* Emulate the AcceptPattern, RejectPattern, and RejectIcons
           * features of V38 Asl.library...
	   */
	  if (opt.acceptpat || opt.rejectpat || opt.noicons) {
	    if (opt.acceptpat) {
	      patlen = strlen(opt.acceptpat) * 2 + 2;
	      if (accept = AllocVec(patlen+1, MEMF_ANY))
		if (ParsePatternNoCase(opt.acceptpat, accept, patlen) == 1)
		  ud.accept = accept;
	    }
	    if (opt.rejectpat) {
	      patlen = strlen(opt.rejectpat) * 2 + 2;
	      if (reject = AllocVec(patlen+1, MEMF_ANY))
		if (ParsePatternNoCase(opt.rejectpat, reject, patlen) == 1)
		  ud.reject = reject;
	    }
	    if (opt.noicons)
	      ParsePatternNoCase("#?.info", ud.noicons, 16);
	    flags |= FILF_DOWILDFUNC;
	    tags[t].ti_Tag = ASL_HookFunc;
	    tags[t++].ti_Data = (ULONG) HookFunc;
	  }

	  tags[t].ti_Tag = ASL_FuncFlags;
	  tags[t++].ti_Data = flags;
	  tags[t].ti_Tag = TAG_END;

	  if (fr = (struct FileRequester *)
	      AllocAslRequest(ASL_FileRequest, tags)) {
	    fr->rf_UserData = (APTR) &ud;
	    if (AslRequest(fr, NULL)) {
	      if (opt.multi && fr->rf_NumArgs) {
		frargs = fr->rf_ArgList;
		for (t = 0; t < fr->rf_NumArgs; t++) {
		  strcpy(dirname, fr->rf_Dir);
		  AddPart(dirname, frargs[t].wa_Name, PATHLEN);
		  PutStr("\"");
		  PutStr(dirname);
		  PutStr(t < fr->rf_NumArgs - 1 ? "\" " : "\"\n");
		}
	      }
	      else {
		strcpy(dirname, fr->rf_Dir);
		AddPart(dirname, fr->rf_File, PATHLEN);
		PutStr("\"");
		PutStr(dirname);
		PutStr("\"\n");
	      }
	    }
	    else if (IoErr())
	      rc = RETURN_FAIL; /* something went wrong */
	    else
	    {
	      /* Nothing selected */
	      rc = RETURN_WARN;
	      SetIoErr(ERROR_BREAK);
	    }
	    FreeAslRequest(fr);
	  }
	  FreeArgs(rdarg);
	}
	else rc = RETURN_FAIL;
	if (accept) FreeVec(accept);
	if (reject) FreeVec(reject);
	FreeVec(dirname);
      }
      else rc = RETURN_FAIL;
      CloseLibrary(AslBase);
    }
    else {
      SetIoErr(ERROR_INVALID_RESIDENT_LIBRARY); /* Not a perfect message */
      rc = RETURN_FAIL;
    }
    if (rc == RETURN_FAIL) PrintFault(IoErr(), "RequestFile");
    CloseLibrary(DOSBase);
  }
  else rc = RETURN_FAIL;
  return rc;
}


CPTR HookFunc(LONG type, CPTR obj, struct FileRequester *fr)
{
  struct Library *DOSBase = ((struct userdata *) fr->rf_UserData)->DOSBase;
  STRPTR fname = ((struct AnchorPath *) obj)->ap_Info.fib_FileName;
  STRPTR accept = ((struct userdata *) fr->rf_UserData)->accept;
  STRPTR reject = ((struct userdata *) fr->rf_UserData)->reject;
  STRPTR noicons = ((struct userdata *) fr->rf_UserData)->noicons;
  static BOOL returnvalue;
  BOOL acc = TRUE, rej = FALSE, icon = FALSE;

  if (accept) acc = MatchPatternNoCase(accept, fname);
  if (reject) rej = MatchPatternNoCase(reject, fname);
  if (noicons) icon = MatchPatternNoCase(noicons, fname);

  returnvalue = acc && !rej && !icon;
  return (CPTR) !returnvalue;
}

