#--------------------------------CUT HERE-------------------------------------
#! /bin/sh
#
# This is a shell archive. Save this into a file, edit it
# and delete all lines above this comment.  Then give this
# file to sh by executing the command 'sh file'. The files
# will be extracted into the current directory owned by
# you with default permissions.

echo 'x - exec_with_piped.c'
sed 's/^X//' << '________This_Is_The_END________' > exec_with_piped.c
X/*
X ************************************************************************
X *		Execute a shell command feeding 
X *		    from a named FIFO pipe
X *
X * Synopsys
X *	exec_with_piped Named-pipe-name "Command-to-execute"
X *
X * where Named-pipe-name is the name of a special file (FIFO pipe)
X * created as
X *	/etc/mknod Named-pipe-name p
X * The "Command-to-execute" is passed for interpretation to a shell, which
X * is forked as a child process. This shell's standard input (which is also
X * Command's standard input) is redirected to feed from the Named-pipe.
X * When there is no more data in the Named-pipe, this code re-opens the pipe
X * and waits for the next portion of data to be put into it. This code ends
X * when the Command it runs exits.
X *
X * Usage example:
X *	/etc/mknod FIFO-PIPE p
X *	exec_with_piped FIFO-PIPE "rsh nrcbss Mathematica" &
X *	echo "Mathematica-command-1" > FIFO-PIPE
X *		... see the result on the screen ...
X *	echo "Mathematica-command-2" > FIFO-PIPE
X *		... see the result on the screen ...
X *		....
X *	cat file-with-Mathematica-commands > FIFO-PIPE
X *		... see the result on the screen ...
X *	echo "Quit" > FIFO-PIPE
X *
X * Another example:
X *	mknod mypipe p
X *	exec_with_piped mypipe "telnet localhost 25" &
X *	echo "vrfy <postmaster>" > mypipe
X *	echo "quit" > mypipe
X *
X * Warning
X * If you try to get the same result by simply entering
X *	rsh nrcbss Mathematica < FIFO-PIPE &
X * Mathematica will finish right after reading the first command from the pipe,
X * without waiting for other commands. When a program opens a pipe for the
X * first time and tries to read from it, the program blocks until somebody
X * writes something into the pipe. The first program then unblocks, and can
X * read the data. Once the data are scooped out (until EOF), any successive
X * reading from the pipe would instantly end in EOF (rather than in suspension
X * of the reader). To restore the blocking behavior (and make the reader
X * wait for a new portion of data), the pipe must be reopened. 
X *
X * $Id: exec_with_piped.c,v 1.4 1997/11/14 19:29:48 oleg Exp oleg $
X *
X ************************************************************************
X */
X
X#include <stdio.h>
X#include <assert.h>
X#include <stdlib.h>
X#include <string.h>
X#include <fcntl.h>
X#include <signal.h>
X#include <unistd.h>
X
Xtypedef struct {
X	int fno;		/* OS's file handle		*/
X	char * name;		/* The full name of the file	*/
X} AFile;
X
X/*
X *-----------------------------------------------------------------------
X *			   AFile package
X */
X
X		/* Open AFile; uses the same arguments as open(2) */
Xstatic AFile open_afile(const char * name, const int open_mode)
X{
X  AFile file;
X  assert( name != 0 && (file.name = strdup(name)) != 0 );
X  if( (file.fno = open(name,open_mode)) == -1 )
X    perror("Problem opening a file"),
X    fprintf(stderr,"\nFile '%s' could not be opened due to a problem above\n",
X    		   name),
X    exit(4);
X  return file;
X}
X
Xstatic AFile reopen_afile(AFile file, const int open_mode)
X{
X  if( close(file.fno) == -1 )
X    perror("Problem closing a file"), exit(4);
X  if( (file.fno = open(file.name,open_mode)) == -1 )
X    perror("Problem re-opening a file"),
X    fprintf(stderr,"\nFile '%s' could not be re-opened due to a problem above\n",
X    		   file.name),
X    exit(4);
X  return file;
X}
X
X		/* popen AFile; uses the same arguments as open(2) */
Xstatic AFile popen_afile(const char * name, const int open_mode)
X{
X  AFile file;
X  FILE * ffile;
X  assert( name != 0 && (file.name = strdup(name)) != 0 );
X
X  if( (ffile = popen(name,((open_mode & O_ACCMODE) == O_RDONLY) ? "r" : "w")) 
X  	== (FILE*)0 )
X    perror("Problem opening a pipe"),
X    fprintf(stderr,
X    	"\nCommand '%s' could not be launched due to a problem above\n",
X    	file.name),
X     exit(4);
X  setbuf(ffile,(char*)0);		/* Free the FILE buffer		*/
X  file.fno = fileno(ffile);
X  return file;
X}
X
X
X		/* Copy in_file into out_file until the EOF		*/
Xstatic void relay(const AFile out_file, const AFile in_file)
X{
X  char buffer[512];
X  for(;;)
X  {
X    register const int n = read(in_file.fno,buffer,sizeof(buffer));
X    if( n == 0 )
X      return;			/* We've read nothing => EOF		*/
X    else if( n > 0 && n == write(out_file.fno,buffer,n) )
X      continue;
X    else
X      perror("input/output error"), exit(4);
X  }
X}
X
X/*
X *========================================================================
X *			Initialization routines
X */
X
Xstatic void help(void)
X{
X  fprintf(stderr,"\n\n\tExecute a shell command feeding from a named FIFO pipe");
X  fprintf(stderr,"\nSynopsys");
X  fprintf(stderr,"\n\texec_with_piped Named-pipe-name \"Command-to-execute\"");
X  fprintf(stderr,"\n\nwhere");
X  fprintf(stderr,
X	  "\nNamed-pipe-name is the name of a special file (FIFO pipe)");
X  fprintf(stderr,"\n\tcreated by /etc/mknod File-name p");
X  fprintf(stderr,"\nCommand-to-execute is passed to a shell to interpret");
X  fprintf(stderr,
X	  "\nSee title comments in the source code for details");
X  fprintf(stderr,"\n\n");
X  exit(1);
X}
X
X
X/*
X *-----------------------------------------------------------------------
X *				Root module
X *  Parse the command string
X *  Two arguments are expected (excluding the pgm name as the 0. arg),
X *  PIPE name and the command-to-execute-string
X */
X
Xint main(int argc, char * argv[])
X{
X AFile in_file, out_file;
X
X if( argc != 3 )                        /* Too few or too many arguments*/
X   help();
X
X in_file = open_afile(argv[1],O_RDONLY);
X out_file = popen_afile(argv[2],O_WRONLY);
X
X signal(SIGCHLD,exit);	/* quit when the subprocess (created by popen())*/
X			/* is finished					*/
X  
X for(;;)
X {
X    relay(out_file,in_file);
X    in_file = reopen_afile(in_file,O_RDONLY);      
X }
X return 0;
X}
X
X
X
X
________This_Is_The_END________
if test `wc -l < exec_with_piped.c` -ne 186; then
echo 'shar: exec_with_piped.c was damaged during transit (should have had 186 lines)'
fi


echo 'x - nntp_scripting.sh'
sed 's/^X//' << '________This_Is_The_END________' > nntp_scripting.sh
X#!/bin/sh
X#	An example of using exec_with_piped for scripting things
X#		(NNTP server in this example) via telnet
X#
X#  	This example would print subject fields of the first 5 articles
X#			of a given newsgroup
X#
X# This is not intended to be a newsreader of sorts or a tutorial
X# on the NNTP protocol. This is just an example of a non-trivial
X# client-server interaction, done entirely in sh, and for which you
X# really need exec_with_piped
X#
X# It is a bit non-trivial communication as it requires some _dialog_
X# with a server and actually listening to what the server is saying.
X# The communication protocol is as follows
X# ...initiate connection to a NNTP server...
X# get>
X# send>group rec.arts.startrek.info
X# get>211 7 2884 2890 rec.arts.startrek.info
X#		Note, 2884 is an id of the 1st article the server has
X#		      2890 is an id of the last article
X# send>xhdr subject 2884-2888
X# get>221 subject fields follow
X# get>...
X# get>.
X# send>quit
X# get>205 orion.blahblah.com closing connection.  Goodbye.
X#
X# Note, one needs exec_with_piped even for simpler things, which do not
X# require such an elaborate dialog. For example, to find a real name of
X# a postmaster, the simplest solution that springs to mind is:
X# 	mknod mypipe p
X# 	telnet localhost 25 < mypipe &
X# 	echo "vrfy <postmaster>" > mypipe
X# It leads to a complete disaster: try if you're adventurous (but be
X# prepare to kill that telnet subprocess, probably from another terminal)
X# Simple (echo "vrfy <postmaster>"; echo "quit") | telnet localhost 25
X# may actually work on SYSVR4 systems (like Solaris 2.4 or other
X# STREAM-based OS), but would fail on BSD-type systems
X# (even on FreeBSD 2.0.5): somehow the first thing telnet gets from
X# its redirected input (pipe) is EOF, which forces it to quit right away.
X#
X# exec_with_piped works always, on BSD- and SystemV-alike!
X# And you can do non-trivial dialogs like the one described above
X# and implemented below.
X# It was tested on SunSparc Solaris 2.4 and SunOS 4.1.1,
X# DEC Alpha/Digital Unix V3.2, FreeBSD 2.0.5, Sequent S81/Dynix V3.1.4
X# The original code was written on SGI IRIX 4.x
X
X
X
X#		Configuration info: please adjust
XPIPE_NAME=mypipe
XMKNOD="mknod $PIPE_NAME p"	# FreeBSD (and other BSD4.4-like) should use
X				# "mkfifo $PIPE_NAME" instead mknod...
XNNTP_HOST=news.infinop.com
XNEWSGROUP=rec.arts.startrek.info
X
X# 		Main body
X/bin/rm -f $PIPE_NAME		# got rid of a stale pipe (if was any)
X$MKNOD				# and make a fresh one
X
XPC=0				# Set up the "program counter" of our FSM
X				# to begin
X./exec_with_piped $PIPE_NAME "telnet $NNTP_HOST 119" |
Xwhile read code line; do
X#echo "line> $code $line"
Xcase "$PC/$code" in
X
X		# wait for the "nntp ready" message
X	"0/200") PC=1; echo "group $NEWSGROUP" > $PIPE_NAME
X	;;
X		# analyze response from the "group" command
X		# which tells us ids (numbers) of the first and the last
X		# articles on the server
X		# add to the local sh-environment:
X		#	query_range_lo, query_range_hi
X	"1/211") PC=2;
X		 eval `echo $line | awk '{ first_article=$2; last_article=$3; \
X                          next_article=first_article+5;		\
X                          if( next_article > last_article )	\
X                            next_article=last_article;        	\
X			  print "query_range_lo=" first_article \
X			  	";query_range_hi=" next_article; }'`
X	  echo "xhdr subject ${query_range_lo}-${query_range_hi}" > $PIPE_NAME
X	;;
X	
X		# Single dot terminates the output from xhdr
X		# we quit afterwards
X	"2/.")  PC=3; echo "quit" > $PIPE_NAME
X	;;
X
X		# Just print whatever xhdr has to say
X	2/*)    echo "$code $line"
X	;;
X
X		# Got server's final good-bye and here we quit
X	3/*)    exit
X	;;
Xesac
Xdone &
Xsleep 1
Xecho "" > $PIPE_NAME	# Make the initial nudge
Xwait
________This_Is_The_END________
if test `wc -l < nntp_scripting.sh` -ne 104; then
echo 'shar: nntp_scripting.sh was damaged during transit (should have had 104 lines)'
fi

