[comp.os.minix] POSIX headers, which of the below are correct

cagney@chook.ua.oz (Andrew Cagney - aka Noid) (12/01/89)

I've being trying to compile earl chew's stdio using the POSIX header files
recently posted. Among the problems encountered there is the following:

In POSIX/usr/include/fcntl.h creat is declared as:
	_PROTOTYPE( int creat, (char *__path, int __mode)       	);
  ie	int creat(char *__path, int __mode);
Where as Earl has declared it as:
	int	creat    P((const char *, mode_t)); /* create a file */
  ie	int creat(const char, mode_t);
The two key differences are:
	1. const
	2. mode_t
Which is correct? I suspect that the correct one should be:

	_PROTOTYPE( int creat, (const char *__path, mode_t __mode)     	);
ie	int creat (const char *__path, mode_t __mode);

(Yes I know that the names __path & __mode are optional but they are still
nice :-)

any thoughts?
				Andrew Cagney
				cagney@cs.ua.oz.au

BTW:	This testing is being done using gcc.
	The above form of macro expansion apparently the `done thing' for
	doing prototype declarations. (It is different to the method originally
	used.
	Some other problems encountered were:
		- missing , ... (optional third arguments) etc
		- files incorectly or not included
		- declarations containing syntax errors
		- fiddling so that the correct compiler is used.

nfs@notecnirp.Princeton.EDU (Norbert Schlenker) (12/02/89)

In article <682@augean.OZ: cagney@chook.ua.oz (Andrew Cagney - aka Noid) writes:
:
:I've being trying to compile earl chew's stdio using the POSIX header files
:recently posted. Among the problems encountered there is the following:
:
:In POSIX/usr/include/fcntl.h creat is declared as:
:	_PROTOTYPE( int creat, (char *__path, int __mode)       	);
:  ie	int creat(char *__path, int __mode);
:Where as Earl has declared it as:
:	int	creat    P((const char *, mode_t)); /* create a file */
:  ie	int creat(const char, mode_t);
:The two key differences are:
:	1. const
:	2. mode_t
:Which is correct? I suspect that the correct one should be:
:
:	_PROTOTYPE( int creat, (const char *__path, mode_t __mode)     	);
:ie	int creat (const char *__path, mode_t __mode);
:
:(Yes I know that the names __path & __mode are optional but they are still
:nice :-)
:
:any thoughts?
:				Andrew Cagney
:				cagney@cs.ua.oz.au

Well, it's always nice to see all but the correct possibility chosen.:-)
The correct prototype, per IEEE 1003.1, is:
	_PROTOTYPE( int creat, (char *__path, mode_t __mode)		);
i.e.	int creat(char *__path, mode_t __mode);

The declaration of mode's type is a simple oversight on Andy's part (but
I have to admit that I didn't see it either when I had a sneek peek in
advance of the posting).

The declaration of the pathname is more interesting though.  Functions
like fopen() take a string as one of their arguments, and ANSI insists
that the string be declared "const char *".  ANSI (rightly) figures that
the fopen() user wants a file opened, not a character string mangled, and
enforces that with "const".

Earl's stdio then turns around and hands that string to creat() in some
cases.  Now if creat() is declared to take a "char *" (without the const),
an ANSI compiler, like gcc can be, should fail when compiling fopen().
That's because it isn't legal to loosen the restriction on such a pointer.
(I can't quote chapter and verse from ANSI, but it's so.  Trust me :-)

The only legal way to do this correctly, I believe, is something like:

FILE *fopen(const char *path, const char *mode)
{
...
  char localpath[PATH_MAX+1];
...
  strcpy(localpath, path);
...
  creat(localpath, 0666);
...
}

So there is extra overhead (both time and space) for doing this right.
I understand why Earl did what he did; I did almost the same thing for
my package, but had the audacity to ignore gcc's complaints.

What should be done?  I believe that the correct thing is that POSIX
should be modified to reflect the non-modifiability of the pathname.
After all, programs use creat() to create files, not to mangle pathnames.
But knowing that the standard is virtually set in stone at this point,
I think the correct thing is out of the question.

What will be done?  I am considering changing my code to handle this,
but confess that a change which will cost space and time and which I know
will never be necessary in Minix (since I have the source of creat())
isn't very high on my list of priorities.

Norbert

bammi@dsrgsun.ces.cwru.edu (Jwahar R. Bammi) (12/02/89)

In article <22014@princeton.Princeton.EDU>, nfs@notecnirp (Norbert Schlenker) writes:
>The only legal way to do this correctly, I believe, is something like:
>
>FILE *fopen(const char *path, const char *mode)
>{
>...
>  char localpath[PATH_MAX+1];
>...
>  strcpy(localpath, path);
>...
>  creat(localpath, 0666);
>...
>}
>
>So there is extra overhead (both time and space) for doing this right.
>I understand why Earl did what he did; I did almost the same thing for
>my package, but had the audacity to ignore gcc's complaints.
>
with gcc atleast (i dont have access to any other ansi C compiler) you can
cast a (const char *) to a (char *) without having to make a local copy.
(or vise versa). i dont know for sure if these casts are legal ansi C, but
gcc -pedantic does'nt complain. (assuming of course you really want to do
that). another thing that struck me as strange (unless it has changed recently)
are the protos for strchr, strrchr and the like: 
the proto says `char *strchr(const char *s, int c)' and what you are
really doing is returning either a pointer into s or NULL. should'nt
the return type be `const char *' ? or are you really supposed to return a 
pointer into a writable copy of s? i used casts in all such cases.
--

bang:   {any internet host}!dsrgsun.ces.CWRU.edu!bammi	jwahar r. bammi
domain: bammi@dsrgsun.ces.CWRU.edu
GEnie:	J.Bammi

cechew@bruce.OZ (Earl Chew) (12/05/89)

From article <22014@princeton.Princeton.EDU>, by nfs@notecnirp.Princeton.EDU (Norbert Schlenker):
> :Where as Earl has declared it as:
> :	int	creat    P((const char *, mode_t)); /* create a file */

I must confess that I didn't refer to the standard very carefully when I wrote
that line :-(

> What should be done?  I believe that the correct thing is that POSIX
> should be modified to reflect the non-modifiability of the pathname.
> After all, programs use creat() to create files, not to mangle pathnames.
> But knowing that the standard is virtually set in stone at this point,
> I think the correct thing is out of the question.

From my reading of open(), the standard doesn't say that open() *will* mangle
path names. If it did, you wouldn't be able to say things like:

	fd = open("/etc/termcap", O_RDONLY);

since "strings" are supposed to be regarded as non-modifiable.

On the other hand, the standard doesn't say then open() *will not* mangle the
path name but I do not seriously think that open(), creat(), access(), etc
will modify the path name since that would cause programs passing string
constants to fail. That would break a fair amount of current software.

Furthermore, I refer you to B.1.4, which says, of function parameter lists,

"Function parameter type lists were not used because the Working Group was
aware that some vendors would wish to implement POSIX in terms of a binding to
an historical variant of the C language instead of to the C Standard, since
compilers for the latter would initially not be widespread."

This is probably also the reason that const and volatile, etc, are not used in
the standard.

> What will be done?  I am considering changing my code to handle this,

From the above, I don't seriously think that it is worth while. open() mangling
path names will break more code than just stdio.

Earl
-- 
Earl Chew, Dept of Computer Science, Monash University, Australia 3168
ARPA: cechew%bruce.cs.monash.oz.au@uunet.uu.net  ACS : cechew@bruce.oz
----------------------------------------------------------------------