Subject: Re: FVWM: [2.0.43] FvwmAudio patch (long)

From: [email-masked] (Albrecht Kadlec)
Date: Thu, 8 Aug 96 00:42:13 +0200

hello all,

after requests for rsynth support (needs spaces between words)
I've made a small patch for 2.0.43 and posted it to the list 
(it included the "string" patch). 

Now I found Mark Boyns patch for 2.0.43.
I reapplied my patches after his patch, and reworked some tiny bits so
that FvwmAudio now supports quoted parameters.

for details, see the ChangeLog.
I post the whole source file, since the context diff was just
marginally smaller, and I didn't want to send patches for plain 2.0.43
and 2.0.43 with Mark Boyns patch.

PS: Chuck: have a look at the WIBNI in the code.

I'll go and get some sleep now,
albrecht

/* 
 * Copyright (C) 1994 Mark Boyns ([email-masked]) and
 *                    Mark Scott ([email-masked])
 *
 * FvwmAudio version 1.1
 *
 * 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.
 */

/* ChangeLog

 * made FvwmAudio insensitive to its name -> can be symlinked.
   corrected some error message deficiencies, code for quoted 'sound' 
   parameters shamelessly stolen from FvwmButtons/parse.c (with minimal
   adjustments)
   FvwmAudio now supports rsynth's say command:
   *FvwmAudioPlayCmd say
   *FvwmAudio add_window	   "add window"      
   *FvwmAudio raise_window	   'raise window'
               -- 08/07/96 Albrecht Kadlec ([email-masked])

 * Fixed FvwmAudio to reflect the changes made to the module protocol.

 * Szijarto Szabolcs <[email-masked]> provided FvwmSound code that used
 $HOSTDISPLAY for the rplay host.  The code has been added to FvwmAudio.

 * Fixed bugs reported by beta testers, thanks!

 * Builtin rplay support has been added to FvwmAudio.  This support is
 enabled when FvwmAudio is compiled with HAVE_RPLAY defined and when
 FvwmAudioPlayCmd is set to builtin-rplay.  I guess it's safe to say
 that FvwmSound is now obsolete. -- Mark Boyns 5/7/94
 
 * FvwmAudio is based heavily on an Fvwm module "FvwmSound" by Mark Boyns
 and the real credit for this really goes to him for the concept.
 I just stripped out the "rplay" library dependencies to allow generic
 audio play command support.

 */

/*
 * This module is based on FvwmModuleDebugger which has the following
 * copyright:
 *
 * This module, and the entire ModuleDebugger program, and the concept for
 * interfacing this module to the Window Manager, are all original work
 * by Robert Nation
 *
 * Copyright 1994, Robert Nation. No guarantees or warantees or anything
 * are provided or implied in any way whatsoever. Use this program at your
 * own risk. Permission to use this program for any purpose is given,
 * as long as the copyright is kept intact.
 */

/*
 * fvwm includes:
 */
#include <stdio.h>
#include <signal.h>
#include <fcntl.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <unistd.h>
#include <ctype.h>
#include <stdlib.h>

/*
 * rplay includes:
 */
#ifdef HAVE_RPLAY
#include <rplay.h>
#undef M_ERROR /* Solaris fix */
#endif

#include "../../configure.h"
#include "../../fvwm/module.h"
#include "../../version.h"
#include "../../libs/fvwmlib.h"     

#define BUILTIN_STARTUP		MAX_MESSAGES
#define BUILTIN_SHUTDOWN	MAX_MESSAGES+1
#define BUILTIN_UNKNOWN		MAX_MESSAGES+2
#define MAX_BUILTIN		3

#define BUFSIZE			512

/* globals */
char	*MyName;
int	MyNameLen;
int	fd_width;
int	fd[2];
char	audio_play_cmd_line[BUFSIZE], audio_play_dir[BUFSIZE];
time_t	audio_delay = 0;	/* seconds */
#ifdef HAVE_RPLAY
int	rplay_fd = -1;
#endif

/* ----------- shamelessly stolen from FvwmButtons/parse.c 
  sorry, had to change trimright(), use safemalloc, MyName+1 
  WIBNI this was in libfvwm(2).a - or fvwm just piped tokens? ------------ */

#define mymalloc safemalloc

#define trimleft(s) {while(*s==' '||*s=='\t'||*s=='\n')(s)++;}
#define trimright(s) {                                                        \
  register char *t=(s);while(*t) t++;                                         \
  --t; while(t>=s && (*t==' '||*t=='\t'||*t=='\n')) t--;                      \
  t[1]=0;}

/**
*** seekright()
***
*** split off the first continous section of the string into a new allocated
*** string and move the old pointer forward. Accepts and strips quoting with
*** '," or `, and the current quote q can be escaped inside the string with \q.
**/
char *seekright(char **s)
{
  char *b,*t,*r,q;
  trimleft(*s);
  q=**s;
  if(q=='"' || q=='`' || q=='\'')
    {
      b=t=(*s)++;
      while(**s && (**s!=q || (*(*s-1)=='\\' && t--)))
	*t++=*((*s)++);
      if(!**s)
	fprintf(stderr,"%s: Unterminated %c quote found\n",MyName+1,q);
      else (*s)++;
    }
  else
    {
      b=t=*s;
      while(**s && !isspace(**s) && **s!=')' && **s!=',')
	(*s)++;
      t=*s;
    }
  if(t<=b)
    return NULL;
  r=mymalloc(t-b+1);
  strncpy(r,b,t-b);
  r[t-b]=0;
  return r;
}
/* ---------------------- end of borrowed section ----------------------- */

/* prototypes */
void	Loop(int *);
void	process_message(unsigned long,unsigned long *);
void	DeadPipe(int);
void	config(void);
void	done(int);
int     audio_play(short); 

/* define the message table */
char	*messages[MAX_MESSAGES+MAX_BUILTIN] =
{
	"new_page",
	"new_desk",
	"add_window",
	"raise_window",
	"lower_window",
	"configure_window",
	"focus_change",
	"destroy_window",
	"iconify",
	"deiconify",
	"window_name",
	"icon_name",
	"res_class",
	"res_name",
	"end_windowlist",
	"icon_location",
	"map",
	"error",
	"config_info",
	"end_config_info",
	"icon_file",
	"default_icon",
	"string",
/* add builtins here */
	"startup",
	"shutdown",
	"unknown"
};

/* define the sound table  */
char	*sound_table[MAX_MESSAGES+MAX_BUILTIN];

#ifdef HAVE_RPLAY
/* define the rplay table */
RPLAY	*rplay_table[MAX_MESSAGES+MAX_BUILTIN];
#endif

main(int argc, char **argv)
{
	char *temp, *s;

	/* Save our program  name - for error messages */
	temp = argv[0];
	s=strrchr(argv[0], '/');
	if (s != NULL)
		temp = s + 1;

	MyNameLen=strlen(temp)+1;	/* acoount for '*' */
	MyName = safemalloc(MyNameLen+1); /* account for \0 */
	strcpy(MyName,"*");
	strcat(MyName, temp);

	if ((argc != 6)&&(argc != 7))	/* Now Myname is defined */
	{
		fprintf(stderr,"%s Version %s should only be executed by fvwm!\n",
			MyName+1 /* without '*'!!! */, VERSION);
		exit(1);
	}

	/* Dead pipe == Fvwm died */
	signal (SIGPIPE, DeadPipe);  
  
	fd[0] = atoi(argv[1]);
	fd[1] = atoi(argv[2]);

	audio_play_dir[0] = '\0';
	audio_play_cmd_line[0] = '\0';

	/*
	 * Read the sound configuration.
	 */
	config();

	/*
	 * Play the startup sound.
	 */
	audio_play(BUILTIN_STARTUP);
	SendText(fd,"Nop",0);
	Loop(fd);
}

/***********************************************************************
 *
 *  Procedure:
 *	config - read the sound configuration file.
 *
 ***********************************************************************/
void	config(void)
{
  char	*buf;
  char	*message;
  char	*sound;
  char	*p;
  int	i, found;
#ifdef HAVE_RPLAY
  int	volume = RPLAY_DEFAULT_VOLUME;
  int	priority = RPLAY_DEFAULT_PRIORITY;
  char	host[128];

  strcpy(host, rplay_default_host());
#endif
  
  /*
   * Intialize all the sounds.
   */
  for (i = 0; i < MAX_MESSAGES+MAX_BUILTIN; i++) {
    sound_table[i] = NULL;
#ifdef HAVE_RPLAY
    rplay_table[i] = NULL;
#endif
  }

  GetConfigLine(fd,&buf);
  while (buf != NULL)
    {
      if (buf[0] == '*')		/* this check is obsolete */
					/* - included in the next if */
	{
	  buf[strlen(buf)-1] = '\0';	/* strip off \n */
	  /*
	   * Search for MyName (normally *FvwmAudio)
	   */
	  if (mystrncasecmp(buf, MyName, MyNameLen) == 0)
	    {
	      p = strtok(buf+MyNameLen, " \t");	
	  
	      if (mystrcasecmp(p, "PlayCmd") == 0) {
		p = strtok(NULL, "\n"); /* allow parameters */
		if (p && *p) {
		  strcpy(audio_play_cmd_line, p);
		}
	      }
	      else if (mystrcasecmp(p, "Dir") == 0) {
		p = strtok(NULL, " \t");
		if (p && *p) {
		  strcpy(audio_play_dir, p);
		}
	      }
	      else if (mystrcasecmp(p, "Delay") == 0) {
		p = strtok(NULL, " \t");
		if (p && *p) {
		  audio_delay = atoi(p);
		}
	      }
	  
#ifdef HAVE_RPLAY
	      /*
	       * Check for rplay configuration options.
	       */
	      else if (mystrcasecmp(p, "RplayHost") == 0)
		{
		  p = strtok(NULL, " \t");
		  if (p && *p)
		    {
		      /*
		       * Check for environment variables like $HOSTDISPLAY.
		       */
		      if (*p == '$')
			{
			  char	*c1, *c2;
			  c2 = host;
			  for (c1 = (char *)getenv(p+1); *c1 && (*c1 != ':'); c1++)
			    {
			      *c2++ = *c1;
			    }
			  *c2 = '\0';
			}
		      else
			{
			  strcpy(host, p);
			}
		    }
		}
	      else if (mystrcasecmp(p, "RplayVolume") == 0)
		{
		  p = strtok(NULL, " \t");
		  if (p && *p) {
		    volume = atoi(p);
		  }
		}
	      else if (mystrcasecmp(p, "RplayPriority") == 0)
		{
		  p = strtok(NULL, " \t");
		  if (p && *p) {
		    priority = atoi(p);
		  }
		}
#endif
	      /*
               * *FvwmAudio <message_type> <audio_file>
	       * for builtin rplay
	       *
	       *  or
	       *
	       * *FvwmAudio <message_type> <"any quoted parameters">
	       * can be (mis)used to call FvwmAudioPlayCmd
	       * with arbitrary parameters e.g: rsynth/say "window raised"
	       *
	       * can even be used to call arbitrary commands,
	       * if the following wrapper is used as FvwmAudioPlayCmd
	       * 
	       *	#!/bin/tcsh
	       *	${argv[1-]}
	       */
	      else  {
		message = p;
		p=strtok(NULL, "");	/* get rest of line */
		sound = seekright(&p);	/* extract next parameter */
	    
		if (!message || !*message || !sound || !*sound)
		  {
		    fprintf(stderr,"%s: incomplete event definition %s\n",
			    MyName+1, buf);
		    GetConfigLine(fd,&buf);
		    continue;
		  }
	    
		found = 0;

	    	for (i = 0; !found && i < MAX_MESSAGES+MAX_BUILTIN; i++)
		  {
		    if (mystrcasecmp(message, messages[i]) == 0) {
#ifdef HAVE_RPLAY
		      rplay_table[i] = rplay_create(RPLAY_PLAY);
		      rplay_set(rplay_table[i], RPLAY_APPEND,
				RPLAY_SOUND,	sound,
				RPLAY_PRIORITY,	priority,
				RPLAY_VOLUME,	volume,
				NULL);
#endif
		      sound_table[i]=sound;
		      found++;
		    }
		  }
		if (!found) fprintf(stderr,"%s: unknown message type: %s\n",
				    MyName+1, message);
	      }
	   }
	}
      GetConfigLine(fd,&buf);
    }
  
#ifdef HAVE_RPLAY
  /*
   * Builtin rplay support is enabled when FvwmAudioPlayCmd == builtin-rplay.
   */
  if (mystrcasecmp(audio_play_cmd_line, "builtin-rplay") == 0)
    {
      rplay_fd = rplay_open(host);
      if (rplay_fd < 0)
	{
	  rplay_perror("rplay_open");
	  done(1);
	}
    }
#endif
}

/***********************************************************************
 *
 *  Procedure:
 *	Loop - wait for data to process
 *
 ***********************************************************************/
void Loop(int *fd)
{
	unsigned long	header[HEADER_SIZE], *body;
	char		*cbody;
	int		body_length,count,count2=0, total;
	time_t 		now, last_time = 0;
	unsigned long	code;
	
	while (1)
	{
		if ((count = read(fd[1],header,
				  HEADER_SIZE*sizeof(unsigned long))) > 0)
		{
			/*
			 * Ignore messages that occur during the delay
			 * period.
			 */
			now = time(0);
			if (now < (last_time + audio_delay))
			{
				continue;
			}
			last_time = now;
			
			if(header[0] == START_FLAG)
			{
				body_length = header[2]-HEADER_SIZE;
				body = (unsigned long *)
					safemalloc(body_length * sizeof(unsigned long));
				cbody = (char *)body;
				total = 0;
				while(total < body_length*sizeof(unsigned long))
				{
					if((count2=read(fd[1],&cbody[total],
						body_length*sizeof(unsigned long)-total)) >0)
						total += count2;
					else if(count2 < 0)
						DeadPipe(0);
				}

				/*
				 * code will equal the number of shifts in the
				 * base-2 header[1] number.  Could use log here
				 * but this should be fast enough.
				 */
				code = -1;
				while (header[1])
				{
					code++;
					header[1] >>= 1;
				}
				
				/*
				 * Play the sound.
				 */
				if (code >= 0 && code < MAX_MESSAGES)
				{
					audio_play(code);
				}
				else
				{
					audio_play(BUILTIN_UNKNOWN);
				}
				
				free(body);
			}
		}
		if(count <= 0)
			DeadPipe(1);
	}
}

/***********************************************************************
 *
 *  Procedure:
 *	SIGPIPE handler - SIGPIPE means fvwm is dying
 *
 ***********************************************************************/
void DeadPipe(int nonsense)
{
	done(0);
}

/***********************************************************************
 *
 *  Procedure:
 *	done - common exit point for FvwmAudio.
 *
 ***********************************************************************/
void	done(int n)
{
	audio_play(BUILTIN_SHUTDOWN);
	exit(n);
}

/***********************************************************************
 *
 * Procedure:
 *
 *    audio_play - actually plays sound from lookup table
 *
 **********************************************************************/
int audio_play(short sound) 
{
	static char buf[BUFSIZE];

#ifdef HAVE_RPLAY
	if (rplay_fd != -1)
	{
		if (rplay_table[sound])
		{
			if (rplay(rplay_fd, rplay_table[sound]) < 0)
			{
				rplay_perror("rplay");
			}
		}
		return 0;
	}
#endif
	if (sound_table[sound])
	{
		memset(buf,0,BUFSIZE);

		/*
		 * Don't use audio_play_dir if it's NULL or if the sound file
		 * is an absolute pathname.
		 */
		if (audio_play_dir[0] == '\0' || sound_table[sound][0] == '/')
		{
			sprintf(buf,"%s %s", audio_play_cmd_line, sound_table[sound]);
		}
		else
		{
			sprintf(buf,"%s %s/%s &", audio_play_cmd_line, audio_play_dir,
				sound_table[sound]);
		}
		return system(buf);
	}  

	return 1;
}

-- 
We all know Santa as a fat, jolly old man. Well, he may be fat and he
may be old, but he ain't always jolly. There was this one year when
Mrs. Claus decided she wanted to be a feminist, the reindeer went on
strike, and the elves sued because they wanted to be called
"vertically challenged toy manufacturers".
So Santa retreated to his office to rest, when an angel entered and
said, "Santa..."
"What do you want?" was the reply.
"Well," the angel answered,"The Christmas Tree arrived today."
"So?" Santa said.
"Well, I was wondering where you wanted me to put it."
And that, my friends, is why Angels sit on top of trees.
--
Visit the official FVWM web page at <URL:http://www.hpc.uh.edu/fvwm/>.
To unsubscribe from the list, send "unsubscribe fvwm" in the body of a
message to [email-masked].
To report problems, send mail to [email-masked].