[alt.sources] popen

zmact61@doc.ic.ac.uk (D Spinellis) (03/05/90)

In article <90061.202350CMH117@psuvm.psu.edu> CMH117@psuvm.psu.edu (Charles Hannum) writes:
>
>popen() cannot be implemented under DOS.

/*
 * popen, pclose functions for MS DOS 
 *
 * (C) Copyright 1988, 1990 Diomidis Spinellis. All rights reserved. 
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that the above copyright notice and this paragraph are
 * duplicated in all such forms and that any documentation,
 * advertising materials, and other materials related to such
 * distribution and use acknowledge that the software was developed
 * by Diomidis Spinellis.
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 *
 */

#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <process.h>

/*
 * Possible actions on an popened file
 */
enum action {
	delete, 			/* Used for "r". Delete the tmp file */
	execute				/* Used for "w". Execute the command. */
};

/*
 * Linked list of things to do at the end of the program execution.
 */
static struct todo {
	FILE *f;			/* File we are working on (to fclose) */
	const char *name;		/* Name of the file (to unlink) */
	const char *command;		/* Command to execute */
	enum action what;		/* What to do (execute or delete) */
	struct todo *next;		/* Next structure */
} *todolist;


/* Clean up function */
static int close_pipes(void);

/*
 * Add a file f running the command command on file name to the list
 * of actions to be done at the end.  The action is specified in what.
 * Return -1 on failure, 0 if ok.
 */
static int
add(FILE *f, const char *command, const char *name, enum action what)
{
	struct todo    *p;

	if ((p = (struct todo *) malloc(sizeof(struct todo))) == NULL)
		return -1;
	p->f = f;
	p->command = command;
	p->name = name;
	p->what = what;
	p->next = todolist;
	todolist = p;
	return 0;
}

FILE *
popen(const char *command, const char *t)
{
	char buff[256];
	char *name;
	FILE *f;
	static init = 0;

	if (!init)
		if (onexit(close_pipes) == NULL)
			return NULL;
		else
			init++;

	if ((name = tempnam(getenv("TMP"), "pp")) == NULL)
		return NULL;

	switch (*t) {
	case 'r':
		sprintf(buff, "%s >%s", command, name);
		if (system(buff) || (f = fopen(name, "r")) == NULL) {
			free(name);
			return NULL;
		}
		if (add(f, command, name, delete)) {
			(void)fclose(f);
			(void)unlink(name);
			free(name);
			return NULL;
		}
		return f;
	case 'w':
		if ((f = fopen(name, "w")) == NULL) {
			free(name);
			return NULL;
		}
		if (add(f, command, name, execute)) {
			(void)fclose(f);
			(void)unlink(name);
			free(name);
			return NULL;
		}
		return f;
	default:
		free(name);
		return NULL;
	}
}

int
pclose(FILE *f)
{
	struct todo *p, **prev;
	char buff[256];
	const char *name;
	int status;

	for (p = todolist, prev = &todolist; p; prev = &(p->next), p = p->next)
		if (p->f == f) {
			*prev = p->next;
			name = p->name;
			switch (p->what) {
			case delete:
				free(p);
				if (fclose(f) == EOF) {
					(void)unlink(name);
					status = EOF;
				} else if (unlink(name) < 0)
					status = EOF;
				else
					status = 0;
				free(name);
				return status;
			case execute:
				(void)sprintf(buff, "%s <%s", p->command, p->name);
				free(p);
				if (system(buff)) {
					(void)unlink(name);
					status = EOF;
				} else if (fclose(f) == EOF) {
					(void)unlink(name);
					status = EOF;
				} else if (unlink(name) < 0)
					status = EOF;
				else
					status = 0;
				free(name);
				return status;
			default:
				return EOF;
			}
		}
	return EOF;
}

/*
 * Clean up at the end.  Called by the onexit handler.
 */
static int
close_pipes(void)
{
	struct todo    *p;

	for (p = todolist; p; p = p->next)
		(void)pclose(p->f);
	return 0;
}
--
Diomidis Spinellis                  Internet:                 dds@cc.ic.ac.uk
Department of Computing             UUCP:                    ...!ukc!iccc!dds
Imperial College                    JANET:                    dds@uk.ac.ic.cc
London SW7 2BZ                      #include "/dev/tty"

wcf@psuhcx.psu.edu (Bill Fenner) (03/07/90)

In article <1669@gould.doc.ic.ac.uk> dds@cc.ic.ac.uk (Diomidis Spinellis) writes:
|In article <90061.202350CMH117@psuvm.psu.edu> CMH117@psuvm.psu.edu (Charles Hannum) writes:
|>popen() cannot be implemented under DOS.
|
|/*
| * popen, pclose functions for MS DOS 

popen() cannot be *properly* implemeted under MSDOS.
-- 
Bill Fenner                   wcf@hcx.psu.edu             ..!psuvax1!psuhcx!wcf
sysop@hogbbs.fidonet.org (1:129/87 - 814/238-9633)     ..!lll-winken!/

CMH117@psuvm.psu.edu (Charles Hannum) (03/07/90)

In article <2149@psuhcx.psu.edu>, wcf@psuhcx.psu.edu (Bill Fenner) says:
>
>In article <1669@gould.doc.ic.ac.uk> dds@cc.ic.ac.uk (Diomidis Spinellis)
>writes:
>|In article <90061.202350CMH117@psuvm.psu.edu> CMH117@psuvm.psu.edu (Charles
>Hannum) writes:
>|>popen() cannot be implemented under DOS.
>|
>|/*
>| * popen, pclose functions for MS DOS
>
>popen() cannot be *properly* implemeted under MSDOS.


Another point (besides the inherent limitation on the amount of data passed
over the pipe) that no one has mentioned:

   *  If the program exits abnormally FOR ANY REASON the temporary file(s)
      will not be erased.

Everyone is willing to offer their own kludgy implementation, to try to show
off, rather than admitting that DOS just doesn't fit pipes.  [B-)]


Virtually,
- Charles Martin Hannum II       "Klein bottle for sale ... inquire within."
    (That's Charles to you!)     "To life immortal!"
  cmh117@psuvm.{bitnet,psu.edu}  "No noozzzz izzz netzzzsnoozzzzz..."
  c9h@psuecl.{bitnet,psu.edu}    "Mem'ry, all alone in the moonlight ..."