[comp.os.msdos.programmer] using "system" in C

john@jwt.UUCP (John Temples) (04/05/91)

In article <jono.670739550@dec06> jono@dec06.cs.monash.edu.au (Jonathan Oliver) writes:
>	system("copy file1 file2");
>
>there was not enough memory to perform the copy.

The two problems with your approach are that system() has to load a
copy of the command processor to do its job (which takes additional
time and memory), and you're assuming that there's a command called
"copy" on the system running your program.  Since "copy" is a
COMMAND.COM internal command, and not everyone who runs DOS uses
COMMAND.COM, your program is non-portable.  Also, system() usually
fails when your switch character is not set to "/".  In other words,
system() is not usually a wise choice in any "serious" program.

You should open "file1" and "file2" and do the copy yourself, something
like this:

int	copy(FILE *infile, FILE *outfile)
{
char	buf[BUFSIZ];
int		cnt;

while (cnt = fread(buf, sizeof(*buf), sizeof(buf), infile))
	if (fwrite(buf, sizeof(*buf), cnt, outfile) != cnt)
		return 1;			/* probably disk full */

return 0;
}
-- 
John W. Temples -- john@jwt.UUCP (uunet!jwt!john)

dcc@hpopd.pwd.hp.com (Daniel Creswell) (04/05/91)

Try looking at the routines 'execv' and 'execl' which may do the trick. I think
you'll find that use of 'system' creates a new environment for the command as
it has to create a command.com and then run the program (if it behaves like Unix!). Trouble is you'd have to use 'xcopy' for this I think cos you need to execute another program and copy is resident in command.com. Xcopy doesn't need command.com and so it should be possible to call this directly - provided you can obtain it's path.....

Dunno how much help that is but I think it's the only way to go....

Cheers,Dan C.

tr@SAMADAMS.PRINCETON.EDU (Tom Reingold) (04/06/91)

To my thinking, the solution offered by John Temples is the most
reliable and straightforward.  I would add that since you may want to
preserve the timestamp on the file, that you should look into the
stat() and utime() functions.  I hope they are provided by your
library.  They are in my Microsoft library.  Used properly, you can set
the timestamp on the destination file to be the same as that on the
source file.

If you don't have them, use DOS calls.  I recommend the former because
they are clones of UNIX calls, thus your program is more portable.
--
        Tom Reingold
        tr@samadams.princeton.edu  OR  ...!princeton!samadams!tr
        "Warning: Do not drive with Auto-Shade in place.  Remove
        from windshield before starting ignition."

stanley@phoenix.com (John Stanley) (04/08/91)

john@jwt.UUCP (John Temples) writes:

> In article <jono.670739550@dec06> jono@dec06.cs.monash.edu.au (Jonathan Olive
> >	system("copy file1 file2");
> >
> >there was not enough memory to perform the copy.
> 
> The two problems with your approach are that system() has to load a
> copy of the command processor to do its job (which takes additional
> time and memory), 

   A valid complaint about system() on any OS.

> and you're assuming that there's a command called
> "copy" on the system running your program.  

   Copy is one of those commands that seems to be everywhere. If you
were trying to do a 'hyteiwk a b', you might be worried that hyteiwk is
not everywhere. Or, you could supply a copy of it with each system you
sell. Added value! 

> Since "copy" is a
> COMMAND.COM internal command, and not everyone who runs DOS uses
> COMMAND.COM, your program is non-portable.  

   Do other PC OS's really not have a command called 'copy'? Do they
REALLY not have the capability of having a simple batch file to create
that command? How poor a system!

> Also, system() usually
> fails when your switch character is not set to "/".  

   I have heard that much software fails when the switch isn't /.

> In other words,
> system() is not usually a wise choice in any "serious" program.

   I disagree. The only drawback to system() is the speed penalty of loading
another shell. There are some very good uses for system().

> You should open "file1" and "file2" and do the copy yourself, something
> like this:

   Here is the best proof that system() is the proper choice. You have
left out the hardest part of the operation -- opening the files. True,
MS-DOS and UNIX are quite happy with stream files. But when you invoke
the name of the god Portability, you invoke more than those OS's. Look
at VMS (and probably MVS and a dozen others), who have many types of
files. (In fact, VMS's stream_lf file came about only after C was
implemented on it.) If you dare open a fixed length record file with
stream attributes, you get faulty data. How do you tell the record type?
You have to stat() the file. 

   Now, to be portable, you will need to code into your open function a
test for many different file types. And hope that the next release of
the OS doesn't add a few more. Or, you can code in a simple system() of
'copy a b', and let the OS writers worry about file types and anything
else system specific. And if you don't have a 'copy' command, write a
batch file (or alias, or ...) to do it.

   Here is another good use for system(). How do you print from within a
program? I hate to tell you, but opening the device LPT1:, or PRN:, is
REALLY non-portable. Not even from OS to OS, but from one PC to another.
With the easy possibility of 5 printers attached to one PC, and a myriad
others through networks, plus all the other OS's and the odd ways they
handle printers, system() is about the only option. Either that, or you
write configuration code to handle every case you can think of, and I
can guarantee that you will miss some. And you will have trouble getting
data to the printer yourself that 'copy' will not. I have one program
that I have gone to the extent of 'biosprint()' and there is STILL a
problem with something swallowing bytes here and there that does not 
happen with 'copy'.

   So, write your data to a file. Use the system command 'printfile
filename'. Then write a batch file to implement the printfile command.
Yeah, it is slower, but it sure beats trying to maintain a mountain of
code, and it allows the USER to configure his printing as he wishes.
When you can tell a customer 'here is how to do what you want', instead
of 'not supported', you both win.

john@jwt.UUCP (John Temples) (04/09/91)

In article <Nuq3Z1w163w@phoenix.com> stanley@phoenix.com (John Stanley) writes:
>   Copy is one of those commands that seems to be everywhere.
>   Do other PC OS's really not have a command called 'copy'? Do they
>REALLY not have the capability of having a simple batch file to create
>that command? How poor a system!

You don't even have to go to another OS to lose "copy" -- just install
the MKS toolkit, or any other package which replaces COMMAND.COM with
something usable.

Have you ever seen a professional program which, in its installation
instructions, says "now, if your system does not have a 'copy' command,
you must create a batch file that copies a file from the first argument
to the second."  I certainly haven't.  And what if you have a 'copy'
command, but the arguments to it are not interpreted as 'copy from to'?

>> Also, system() usually
>> fails when your switch character is not set to "/".  
>
>   I have heard that much software fails when the switch isn't /.

I wouldn't go so far as to say "much", but why use a system call which
has a known common failure mode?  (under DOS, anyway.)

>The only drawback to system() is the speed penalty of loading
>another shell.

What about the memory cost of the extra shell?  Certainly a concern
under DOS, and the reason this thread was started!

>   Here is the best proof that system() is the proper choice. You have
>left out the hardest part of the operation -- opening the files. True,
>MS-DOS and UNIX are quite happy with stream files. But when you invoke
>the name of the god Portability, you invoke more than those OS's.

If you're going to write a program that does file I/O and try to run it
on different platforms which have different file system semantics,
you're not going to be able to avoid OS-specific code.  Ok, so you've
copied a file with the system() call.  Now how do you *read* a file
into your program?

> Here is another good use for system(). How do you print from within a
>program? [...] system() is about the only option.  So, write your data
>to a file. Use the system command 'printfile filename'. Then write a
>batch file to implement the printfile command.

Yea, but the "printfile" command already exists on my system and sends
the file to the line printer.  I guess I can't use your program to
print files to the laser printer, huh?  And again, have you ever seen a
professional program that required you to set up a batch file to print
programs?  Or for that matter, a program that required a user to even
know what a batch file is?

The correct way to do it, if you want to configure for different
printing environments, is to ask the user what command will print a
file to the desired printer.  Then exec() or spawn() this program,
handing it the print file on its standard input, if possible.  Of
course, under a single-tasking environment like DOS, you may end up
having to talk directly to the hardware.
-- 
John W. Temples -- john@jwt.UUCP (uunet!jwt!john)