/*
**  WaitNotify.c
**
**  Copyright (c)1994 by Tobias Ferber,  All Rights Reserved
*/

#define VERSION "1.1"
static char versiontag[] = "$VER: $Id: waitnotify.c,v 1.1 1994/12/14 18:38:48 tf Exp $";

/****** WaitNotify ***********************************************************
*
*   NAME
*	WaitNotify -- Wait for a file or directory modification
*
*   SYNOPSIS
*	WaitNotify NAME/A/M,QUIET/S,FMT=FORMAT/K
*
*   FUNCTION
*	WaitNotify posts a notification request on the given files
*	or directories.  The command will not return until at least
*	one of them has been modified.  For files, it will return
*	after the file is closed.
*
*	The optional format string will be printed when the file or
*	directory changes.  The first "%s" in it will be replaced by
*	the name.
*
*   INPUTS
*	NAME          - name of the files or directories which you want
*			to observe
*	QUIET         - suppresses warnings and error messages (but sets
*			the return value to allow later diagnostis
*	FORMAT        - string to print on exit.
*
*   EXAMPLES
*	;Wait for a change in our startup-sequence
*	WaitNotify S:Startup-Sequence
*
*	;Wait for a change in either startup script and report its name
*	WaitNotify S:Startup-Sequence S:User-Startup FMT="%s*N"
*
*	;Show the first file which changes via More
*	More `WaitNotify S:Startup-Sequence S:User-Startup FMT=%s`
*
*   BUGS
*	Not all	filesystems will support file notification. In particular,
*	most network filesystems won't support it.
*
*
*   DISCLAIMER
*	This file is part of the WaitNotify distribution.
*
*	WaitNotify 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 1 of the License,
*	or (at your option) any later version.
*
*	WaitNotify 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 the program; see the file COPYING.  If not, write to
*	the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
*   COPYRIGHT
*	WaitNotify is Copyright (C)1994 by Tobias Ferber.
*	You can reach me via E-mail: ukjg@rz.uni-karlsruhe.de
*
******************************************************************************
*
*
*/

#include <exec/types.h>
#include <exec/memory.h>
#include <dos/dos.h>
#include <dos/notify.h>

#include <stdio.h>
#include <stdarg.h>

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

#define NIL(type) (type)0

void display_version_information(void)
{
  static char license[]=
    "WaitNotify is free software; you can redistribute it and/or modify\n"
    "it under the terms of the GNU General Public License as published\n"
    "by the Free Software Foundation; either version 1 of the License,\n"
    "or (at your option) any later version.\n"
    "\n"
    "WaitNotify is distributed in the hope that it will be useful,\n"
    "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
    "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
    "GNU General Public License for more details.\n"
    "\n"
    "You should have received a copy of the GNU General Public License\n"
    "along with WaitNotify; see the file COPYING.  If not, write to the\n"
    "Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n"
    ;

  puts("\nWaitNotify Version " VERSION " (compiled " __DATE__ ", " __TIME__ ")\n"
       "(c)Copyright 1994 by Tobias Ferber, ukjg@rz.uni-karlsruhe.de\n");

  puts(license);
}

int quiet = 0;

void echo(const char *fmt, ...)
{
  va_list argp;
  va_start(argp,fmt);

  if(!quiet)
  {
    fprintf(stderr,"WaitNotify: ");
    vfprintf(stderr,(char *)fmt,argp);
    fprintf(stderr,"\n");
    fflush(stderr);
  }

  va_end(argp);
}


void unset_notify(struct NotifyRequest *nr)
{
  if(nr)
  {
    BYTE sigbit;

    EndNotify(nr);

    sigbit= nr->nr_stuff.nr_Signal.nr_SignalNum;

    if(sigbit != -1)
      FreeSignal(sigbit);

    FreeVec(nr);
  }
}



struct NotifyRequest *set_notify(char *fname)
{
  struct NotifyRequest *nr;

  if( (nr= AllocVec(sizeof(struct NotifyRequest), MEMF_CLEAR)) )
  {
    BYTE sigbit;

    if( (sigbit= AllocSignal(-1)) != -1)
    {
      nr->nr_Name = fname;
      nr->nr_Flags = NRF_SEND_SIGNAL;
      nr->nr_stuff.nr_Signal.nr_Task = FindTask(NULL);
      nr->nr_stuff.nr_Signal.nr_SignalNum = sigbit;

      if (StartNotify(nr) == DOSFALSE)
      {
        echo("StartNotify() failed for \"%s\"",fname);
        FreeVec(nr);
        nr= NIL(struct NotifyRequest *);
        FreeSignal(sigbit);
      }
    }
    else
    {
      echo("AllocSignal() failed for \"%s\"",fname);
      FreeVec(nr);
      nr= NIL(struct NotifyRequest *);
    }
  }
  else
  {
    echo("Not enough free store");
  }

  return nr;
}



int main(int argc, char **argv)
{
  struct NotifyRequest *notifys[32];
  ULONG signals[32], sigmask = SIGBREAKF_CTRL_C;
  struct RDArgs *a;
  LONG args[3] = { 0,0,0 };
  char *fmt= NIL(char *);
  int rv = RETURN_OK;

  if( a= ReadArgs("NAME/A/M,QUIET/S,FMT=FORMAT/K", args, NULL) )
  {
    char **flist= (char **)args[0];
    int i;

    if(args[1])
      quiet= 1;

    if(args[2])
      fmt= (char *)args[2];

    for(i=0; i<32; i++) notifys[i]= NIL(struct NotifyRequest *);

    for(i=0; (i<32) && flist[i] && (rv==RETURN_OK); i++)
    {
      struct NotifyRequest *nr;

      if( (nr= set_notify(flist[i])) )
      {
        notifys[i]= nr;
        signals[i]= (1L << nr->nr_stuff.nr_Signal.nr_SignalNum);
        sigmask |= signals[i];
      }
      else rv = RETURN_ERROR;
    }

    if( i >= 32 )
    {
      echo("Too many notifys");
      rv = RETURN_ERROR;
    }

    if(rv == RETURN_OK)
    {
      ULONG sigset = Wait(sigmask);

      if(sigset & SIGBREAKF_CTRL_C)
        rv = RETURN_WARN;

      if(fmt)
      {
        for(i=0; (i<32) && notifys[i]; i++)
          if(sigset & signals[i])
            printf(fmt,flist[i]);
      }
    }

    for(i=0; (i<32) && notifys[i]; i++)
      unset_notify(notifys[i]);
  }

  else /* !ReadArgs */
  {
    if(argc == 1)
      display_version_information();
    else
      PrintFault(IoErr(), NULL);

    rv= RETURN_FAIL;
  }

  return rv;
}
