[comp.sys.ibm.pc.programmer] popen

anigbogu@loria.crin.fr (Julian ANIGBOGU) (02/23/90)

Can some kind soul point me to where I can get a PC implementation of
the Unix C popen() /* for handle to a pipe */. I manipulate huge
rasterfiles(from a scanner) on a Sun and I adopted the policy of
compressing all files to save disk space. I open them with
popen("uncompress -c filename","r") so that they remain compressed on
disk. 

 I now need to port the programs to DOS and to my chagrin my regular
compiler doesn't implement a pipe open.

 Suggestions in any form would be appreciated.

Julian


-- 
				---------------------------------------
e-mail:	anigbogu@loria.crin.fr 	| All opinions expressed here are      |
				|  naturally mine. However ...         |
				----------------------------------------

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

popen() cannot be implemented under DOS.

dbinette@van-bc.UUCP (Dave Binette) (03/03/90)

In article <1503@loria.crin.fr> anigbogu@loria.crin.fr (Julian Anigbogu) writes:
>Can some kind soul point me to where I can get a PC implementation of
>the Unix C popen() /* for handle to a pipe */. I manipulate huge
>rasterfiles(from a scanner) on a Sun and I adopted the policy of
>compressing all files to save disk space. I open them with
>popen("uncompress -c filename","r") so that they remain compressed on
>disk. 


Following this tirade on the inadequacies of DOS is a code fragment that
should help.

To start with... here is an excerpt from a help utility for C


Defines:
  Modes used by the spawn function.

  P_WAIT     child runs separately,
             parent waits until exit.
  P_NOWAIT   child and parent run
             concurrently. (not implemented)
  P_OVERLAY  child replaces parent so that
             parent no longer exists.

Defined in process.h

The critical issue here is P_NOWAIT.
Because under "DOS" processes are sequential there will be no "pipe"
(as we know it in *IX) to waylay disk usage that you are trying to avoid.

{normally *IX uses a fixed size pipe to transfer data from concurrent procs,
 this allows large amounts of data to be passed without consuming disk space}

Under "DOS" the system will actually create a temporary file somewhere. 
When the "parent" process terminates the "child" process is started with its 
stdin reading from the temporary file.

With that horrible scenario in mind.... here is an implimentation
of the popen/pclose commands.
hardly perfect but it might do the trick for READING OUTPUT from
a program.















#ifndef M_XENIX

/* ----------------------------------------------------------------    */
/* Compatability                            */
/* ----------------------------------------------------------------    */

char Popentemp[MAXARGLINE+1];

FILE * popen(char *s, char * fmode)
{
    char    * tpath;
    char    cmd[MAXARGLINE+1];
    FILE    * fp;

    if((tpath = getenv("TMP")) == (char *)0)
        if((tpath = getenv("TEMP")) == (char *)0)
            tpath = "";

    strcpy(Popentemp, tpath);
    strcat(Popentemp, mktemp("\\$PICK_XXXXXX"));
    strcpy(cmd, s);
    strcat(cmd, " > ");
    strcat(cmd, Popentemp);
    system(cmd);
    fp = fopen(Popentemp, fmode);
    return(fp);
}

/* ----------------------------------------------------------------    */

int pclose(FILE * fp)
{
    int r = -1;

    if(fp)
        if(fclose(fp) == 0);
            r = unlink(Popentemp);

    return(r);
}

#endif

anigbogu@loria.crin.fr (Julian ANIGBOGU) (03/03/90)

In article <90061.202350CMH117@psuvm.psu.edu> CMH117@psuvm.psu.edu (Charles Hannum) writes:
>
>popen() cannot be implemented under DOS.
         ^^^^^^
WRONG!! Take a look at Ian Stewartson's implementation of Shell (sh)
for MSDOS. It contains a working version of both popen() and pclose().
After I posted my question, I downloaded his implementation from
comp.sources.misc and found the response there. It's really neat. You
can use it freelly as long as you acknowledge the source by keeping
the copyright notice in there.

Thanks Ian. BTW, that's the kind of code that should be making it to
Usenet. VIVE FREEWARE!!

Couldn't resist! The debate on Shareware has lasted long enough.
Flames to /dev/null !

Julian

-- 
				---------------------------------------
e-mail:	anigbogu@loria.crin.fr 	| All opinions expressed here are      |
				|  naturally mine. However ...         |
				----------------------------------------

steve@thelake.mn.org (Steve Yelvington) (03/04/90)

[In article <90061.202350CMH117@psuvm.psu.edu>,
     Charles Hannum <CMH117@psuvm.psu.edu> writes ... ]

> popen() cannot be implemented under DOS.

Man can't fly, either. At least not without building an aircraft.

The functionality of popen/pclose can be duplicated by using temporary
files. The calling program need not know the ugly details. For the limited
application mentioned by the original poster -- uncompressing a file and
reading the output -- it's even easier. It need not work internally like
Un*x popen to have the desired results.

I'm writing this on an Atari ST running TOS, which essentially is an
MS-DOS workalike for the Motorola 68000. When I store it, postnews will
pipe it to rnews, which will (among other things) pipe it to uux. So
you're looking at evidence that it can be done in a single-tasking
environment.

Surely it can be done under MS-DOS, too.

cs4g6ag@maccs.dcss.mcmaster.ca (Stephen M. Dunn) (03/04/90)

In article <1503@loria.crin.fr> anigbogu@loria.crin.fr (Julian Anigbogu) writes:
$Can some kind soul point me to where I can get a PC implementation of
$the Unix C popen() /* for handle to a pipe */. I manipulate huge
$rasterfiles(from a scanner) on a Sun and I adopted the policy of
$compressing all files to save disk space. I open them with
$popen("uncompress -c filename","r") so that they remain compressed on
$disk. 
$ I now need to port the programs to DOS and to my chagrin my regular
$compiler doesn't implement a pipe open.

   This isn't a problem with your compiler ... it's just that Unix is a
multi-tasking operating system which can run one program and have its output
piped directly into another program, while DOS is single-tasking and
cannot do this.  DOS's idea of a pipe is as follows:

-run program 1 with its stdout redirected to some file
-run program 2 with its stdin redirected from that file
-delete the temporary file

and the only part of DOS that has any idea of how to do a pipe is the command
interpreter in any case.

   You'll have to implement it yourself by doing the same sort of
thing yourself:  write a function popen that does:

-come up with a temporary file name (there should be a call in your
 library to do this; it's a standard DOS function in DOS 3 and up.
-spawn or exec or system your uncompress utility with redirection of stdout
 (how you handle this depends on which call you use)
-fopen the temporary file and return that handle

and a corresponding close that does:

-close the file
-delete the temporary file

   And, of course, this will take up disk space while your program is
running.
-- 
Stephen M. Dunn                               cs4g6ag@maccs.dcss.mcmaster.ca
          <std_disclaimer.h> = "\nI'm only an undergraduate!!!\n";
****************************************************************************
               I Think I'm Going Bald - Caress of Steel, Rush

darcy@druid.uucp (D'Arcy J.M. Cain) (03/04/90)

In article <1503@loria.crin.fr> anigbogu@loria.crin.fr (Julian Anigbogu) writes:
>Can some kind soul point me to where I can get a PC implementation of
>the Unix C popen() /* for handle to a pipe */. I manipulate huge
>rasterfiles(from a scanner) on a Sun and I adopted the policy of
>compressing all files to save disk space. I open them with
>popen("uncompress -c filename","r") so that they remain compressed on
>disk. 
>
> I now need to port the programs to DOS and to my chagrin my regular
>compiler doesn't implement a pipe open.
>
With good reason.  DOS is a single tasking system so you can't have a
program running without putting the current one on hold first.  The best
way to do what you want is to have the uncompression itself as a subroutine
that returns a specified number of bytes and just call it instead of a
read function.  This is the way I did it and it works just fine.  My function
returns one byte at a time although you could easily make the number of
bytes to return a parameter.

This is not really a C question so followups directed to
comp.sys.ibm.pc.programmer

-- 
D'Arcy J.M. Cain (darcy@druid)     |   Thank goodness we don't get all 
D'Arcy Cain Consulting             |   the government we pay for.
West Hill, Ontario, Canada         |
(416) 281-6094                     |

dowding@linc.cis.upenn.edu (John Dowding) (03/04/90)

In article <25F00B67.17161@maccs.dcss.mcmaster.ca> cs4g6ag@maccs.dcss.mcmaster.ca (Stephen M. Dunn) writes:
>
>   And, of course, this will take up disk space while your program is
>running.

If you write write the temp file to a ram disk, won't this give you
nearly the same effect as the UNIX pipe?

John Dowding
dowding@linc.cis.upenn.edu

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

In article <21231@netnews.upenn.edu>, dowding@linc.cis.upenn.edu (John Dowding)
says:
>
>If you write write the temp file to a ram disk, won't this give you
>nearly the same effect as the UNIX pipe?

Close, but *ix pipes are fixed in size.  (The size probably varies from system
to system; I don't know what it is.)  When the pipe is full, the process that
is writing to it is suspended; when it is empty, the process reading from it is
suspended.  This allows a virtually infinite amount of data to pass over the
pipe.  (Just think about "ls -R | find ..." from the root!!)  Writing to a RAM
disk (or *any* disk) under DOS limits the amount of information that can pass
over the pipe.

A side note:  A variant of *ix piping is implemented in OS/2.


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 ..."

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"

roy@comcon.UUCP (Roy M. Silvernail) (03/05/90)

In article <21231@netnews.upenn.edu>, dowding@linc.cis.upenn.edu (John Dowding) writes:
| In article <25F00B67.17161@maccs.dcss.mcmaster.ca> cs4g6ag@maccs.dcss.mcmaster.ca (Stephen M. Dunn) writes:
| >
| >   And, of course, this will take up disk space while your program is
| >running.
| 
| If you write write the temp file to a ram disk, won't this give you
| nearly the same effect as the UNIX pipe?
| 
| John Dowding
| dowding@linc.cis.upenn.edu

Nearly the same, as long as the temp file doesn't outrun the bounds of
your ramdisk. 

I can't tell from experience, 'cause my wimpy litle machine only has
640k, which leaves precious little room for a ramdisk.


-- 
_R_o_y _M_. _S_i_l_v_e_r_n_a_i_l  | UUCP: uunet!comcon!roy  |  "Every race must arrive at this
#include <opinions.h>;#define opinions MINE  |   point in its history"
SnailMail: P.O. Box 210856, Anchorage,       |   ........Mr. Slippery
Alaska, 99521-0856, U.S.A., Earth, etc.      |  <Ono-Sendai: the right choice!>

anigbogu@loria.crin.fr (Julian ANIGBOGU) (03/06/90)

Hello Guys. Given the enormous number of responses I got to my
question on the above subject, I guess it would be in order to give a
summary of the solutions proposed. At the same time I'll like to thank
the following chaps who jumped onto the rescue-waggon. I responded
individually to some but they might have bounced: 

Len Reed, Raymond Chen, Richard Brittain, Chris Larsen, Mr.
HappyWOWface, PeterG, Kaled Keithley, Doug McDonald, Steve Yelvington
etc. Please, don't feel slighted if your name didn't show up!!

Granted that DOS is not multi-tasking OS, one can still fake pipes by
first spawning the program (In my case 'uncompress') that is being
piped , turn the IO parameter from "r" to "w", writing the output to a
TMP file, (which in effect equivalent to writing to STDOUT (if not
already in use) and redirecting into a file which is a longer process
[IMHO]), reopening the file in "r" mode and passing the handle back
the program that spawn 'uncompress'. This seems neat enough for what
I'm doing as the main program is completely unaware of the "dirty
tricks" being played.

I first found my salvation in Ian Stewartson's implementation of the
Unix (sh) ie. after I sent out my question. From some of the responses
I got I'm apparently not the only one confronted with such problems.
What I failed to add in my origal posting was the absence of time
constraint. My goal was having as many compressed rasterfiles as I
could pack onto the hard-disk and uncompressing them as I need them
without the need to explicitely do that in a batch file and calling
the main program recursively. I guessed that if I could get away with
'popen' on Unix it wouldn't cause any harm faking that on DOS.

Julian


-- 
				---------------------------------------
e-mail:	anigbogu@loria.crin.fr 	| All opinions expressed here are      |
				|  naturally mine. However ...         |
				----------------------------------------

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!/

richard@calvin.spp.cornell.edu (Richard Brittain) (03/07/90)

In article <348@comcon.UUCP> roy@comcon.UUCP (Roy M. Silvernail) writes:
>In article <21231@netnews.upenn.edu>, dowding@linc.cis.upenn.edu (John Dowding) writes:
>| In article <25F00B67.17161@maccs.dcss.mcmaster.ca> cs4g6ag@maccs.dcss.mcmaster.ca (Stephen M. Dunn) writes:
>| >
>| >   And, of course, this will take up disk space while your program is
>| >running.
>| 
>| If you write write the temp file to a ram disk, won't this give you
>| nearly the same effect as the UNIX pipe?
>
>I can't tell from experience, 'cause my wimpy litle machine only has
>640k, which leaves precious little room for a ramdisk.
>

With 4DOS, you can set variable TMP to point to a ramdisk, and all pipe
files will go there.  I run mine with a 256k e: drive and this works
for most things.  It is amazing how few programs check status on writes though
- very few report errors when the ramdisk fills up during a pipe operation.
This gives strange truncation of the data file the reason for which might not
be obvious.
I guess people don't expect discs to fill up anymore.
Given how often our 300+ Meg drives fill up on our research machines, I try
to check all writes (when I can be bothered).

Richard Brittain,                   School of Elect. Eng.,  Upson Hall   
                                    Cornell University, Ithaca, NY 14853
ARPA: richard@calvin.spp.cornell.edu	
UUCP: {uunet,uw-beaver,rochester,cmcl2}!cornell!calvin!richard

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 ..."

Ralf.Brown@B.GP.CS.CMU.EDU (03/07/90)

In article <348@comcon.UUCP>, roy@comcon.UUCP (Roy M. Silvernail) wrote:
}I can't tell from experience, 'cause my wimpy litle machine only has
}640k, which leaves precious little room for a ramdisk.

How times have changed....  When I started with PCs in early 1984, I had plenty
of space after putting in a 160K RAMdisk on my 256K machine.  Of course, Turbo
Pascal 1.0 fit on a single 160K disk back then, instead of five 360K disks for
TP5.5 (and that only by compressing a bunch of files)....
--
UUCP: {ucbvax,harvard}!cs.cmu.edu!ralf -=- 412-268-3053 (school) -=- FAX: ask
ARPA: ralf@cs.cmu.edu  BIT: ralf%cs.cmu.edu@CMUCCVMA  FIDO: Ralf Brown 1:129/46
"How to Prove It" by Dana Angluin              Disclaimer? I claimed something?
16. proof by cosmology:
    The negation of the proposition is unimaginable or meaningless.  Popular
    for proofs of the existence of God.

cs4g6ag@maccs.dcss.mcmaster.ca (Stephen M. Dunn) (03/08/90)

In article <1990Mar7.002520.10365@calvin.spp.cornell.edu> richard@calvin.spp.cornell.edu (Richard Brittain) writes:
$With 4DOS, you can set variable TMP to point to a ramdisk, and all pipe
$files will go there.  I run mine with a 256k e: drive and this works
$for most things.  It is amazing how few programs check status on writes though
$- very few report errors when the ramdisk fills up during a pipe operation.

   When using temporary files, yes, it is a very good idea to ensure that
you aren't running out of room.  However, for pipes implemented by DOS
by playing with the file handle for STDOUT, I thought that there was no
way to detect that the disk was full (I could be wrong, though).  I'd
check it in Duncan, but I'm not near my bookshelf right now.
-- 
Stephen M. Dunn                               cs4g6ag@maccs.dcss.mcmaster.ca
          <std_disclaimer.h> = "\nI'm only an undergraduate!!!\n";
****************************************************************************
                   "Oooh yes I need some love" - Rush

richard@calvin.spp.cornell.edu (Richard Brittain) (03/09/90)

In article <25F5D03C.5473@maccs.dcss.mcmaster.ca> cs4g6ag@maccs.dcss.mcmaster.ca (Stephen M. Dunn) writes:
>In article <1990Mar7.002520.10365@calvin.spp.cornell.edu> richard@calvin.spp.cornell.edu (Richard Brittain) writes:
>$...............  It is amazing how few programs check status on writes though
>$- very few report errors when the ramdisk fills up during a pipe operation.
>
>..............................  However, for pipes implemented by DOS
>by playing with the file handle for STDOUT, I thought that there was no
>way to detect that the disk was full (I could be wrong, though).  I'd
>check it in Duncan, but I'm not near my bookshelf right now.

This is what I thought at first until I wrote a test program, explicitly
checking all writes, and used it in a pipe with large files.  At least with
DOS 4.01 and 4DOS 2.2, the program does get a write error.  I used 
ferror(stdout) if it matters.

Richard Brittain,                   School of Elect. Eng.,  Upson Hall   
                                    Cornell University, Ithaca, NY 14853
ARPA: richard@calvin.spp.cornell.edu	
UUCP: {uunet,uw-beaver,rochester,cmcl2}!cornell!calvin!richard

cpp@cci632.UUCP (Carl P. Petito) (03/13/90)

In article <1990Mar7.002520.10365@calvin.spp.cornell.edu> richard@calvin.spp.cornell.edu (Richard Brittain) writes:

>With 4DOS, you can set variable TMP to point to a ramdisk, and all pipe
>files will go there.
[stuff deleted]
>Richard Brittain,                   School of Elect. Eng.,  Upson Hall   
>                                    Cornell University, Ithaca, NY 14853
>ARPA: richard@calvin.spp.cornell.edu	
>UUCP: {uunet,uw-beaver,rochester,cmcl2}!cornell!calvin!richard

Is it possible to hack DOS (specifically 3.3) to create the temporary pipe
files on another drive (i.e. a RAM disk) rather than the root directory of
the current drive?

Carl Petito
Computer Consoles Inc
Rochester, NY 14609

rochester!cci632!op632!cpp