Happy christmas

J

jacob navia

Why are C interfaces so low level?

We discussed a bit about this in the thread about getting an URL from
the internet.

Take, for instance, we all some day needed to read an entire
file into RAM to process it. Why there isn't

char *strfromfile(const char *file_name,const char *mode);

As a holidays present, here it is.

#include <string.h>
#include >errno.h>
#include <stdio.h>
#include <stdlib.h>
char *strfromfile(const char *fname,const char *mode)
{
if (fname == NULL || mode == NULL) {
errno = EINVAL;
return NULL;
}
FILE *f = fopen(fname,"rb");
if (f == NULL) {
errno = ENOENT;
return NULL;
}
if (fseek(f,0,SEEK_END) != 0) {
ioerror:
errno = EIO; // IO error
fclose(f);
return NULL;
}
long l = ftell(f);
if (l < 0) goto ioerror;
if (fseek(f,0,SEEK_SET) != 0)
goto ioerror;
char *result = malloc(l+1);
if (result == NULL) {
errno = ENOMEM;
fclose(f);
return NULL;
}
if (fread(result,1,l,f) <= 0)
goto ioerror;
result[l] = 0;
fclose(f);
if (strchr(mode,'b') == NULL) {
char *src = result,*dst = result;
while ((src - result) < l) {
if (*src != '\r')
*dst++ = *src;
src++;
}
*dst = 0;
}
return result;
}

Argument "mode" should be either "r" or "rb" for binary or text mode.
This can be omitted in Unix systems, where this stupid distinction
doesn't exist.

If I do not find a "b" in the "mode" string I eliminate CRs from the
string.

NOTE: This function will not run in the DS9000
 
J

Joe Wright

jacob said:
Why are C interfaces so low level?

We discussed a bit about this in the thread about getting an URL from
the internet.

Take, for instance, we all some day needed to read an entire
file into RAM to process it. Why there isn't

char *strfromfile(const char *file_name,const char *mode);

As a holidays present, here it is.

#include <string.h>
#include >errno.h>
#include <stdio.h>
#include <stdlib.h>
char *strfromfile(const char *fname,const char *mode)
{
if (fname == NULL || mode == NULL) {
errno = EINVAL;
return NULL;
}
FILE *f = fopen(fname,"rb");
if (f == NULL) {
errno = ENOENT;
return NULL;
}
if (fseek(f,0,SEEK_END) != 0) {
ioerror:
errno = EIO; // IO error
fclose(f);
return NULL;
}
long l = ftell(f);
if (l < 0) goto ioerror;
if (fseek(f,0,SEEK_SET) != 0)
goto ioerror;
char *result = malloc(l+1);
if (result == NULL) {
errno = ENOMEM;
fclose(f);
return NULL;
}
if (fread(result,1,l,f) <= 0)
goto ioerror;
result[l] = 0;
fclose(f);
if (strchr(mode,'b') == NULL) {
char *src = result,*dst = result;
while ((src - result) < l) {
if (*src != '\r')
*dst++ = *src;
src++;
}
*dst = 0;
}
return result;
}

Argument "mode" should be either "r" or "rb" for binary or text mode.
This can be omitted in Unix systems, where this stupid distinction
doesn't exist.

If I do not find a "b" in the "mode" string I eliminate CRs from the
string.
What string? Files don't (usually) have strings. They have lines.

What do you do about the SUB character (if you find one) ?

Merry Christmas.
 
F

Flash Gordon

jacob navia wrote, On 24/12/07 23:37:
Why are C interfaces so low level?

We discussed a bit about this in the thread about getting an URL from
the internet.

In general the more flexible the library the more complex the interface.
Take, for instance, we all some day needed to read an entire
file into RAM to process it.

I haven't so far. At least, not in to one string.
Why there isn't

char *strfromfile(const char *file_name,const char *mode);

As a holidays present, here it is.

#include <string.h>
#include >errno.h>

You corrected this mistake in a follow up.
#include <stdio.h>
#include <stdlib.h>
char *strfromfile(const char *fname,const char *mode)
{
if (fname == NULL || mode == NULL) {
errno = EINVAL;
return NULL;
}
FILE *f = fopen(fname,"rb");

Wouldn't it be more sensible to use the mode the user passes in?
if (f == NULL) {
errno = ENOENT;
return NULL;
}
if (fseek(f,0,SEEK_END) != 0) {
ioerror:
errno = EIO; // IO error
fclose(f);
return NULL;
}
long l = ftell(f);
if (l < 0) goto ioerror;
if (fseek(f,0,SEEK_SET) != 0)

This is not a portable method of determining file size. Mainly because
there is o portable method. You should at least comment the
non-portabilities.
goto ioerror;
char *result = malloc(l+1);
if (result == NULL) {
errno = ENOMEM;
fclose(f);
return NULL;
}
if (fread(result,1,l,f) <= 0)

Using l as a variable name was a bad idea because it makes it harder to
read the above line, or easier to miss-read it.

Also you fail to allow for it reading fewer then the number of 1 byte
members you specify. This can happen for a number of reasons.
goto ioerror;
result[l] = 0;
fclose(f);
if (strchr(mode,'b') == NULL) {
char *src = result,*dst = result;
while ((src - result) < l) {

Hmm. You have an initialisation, a test, and an increment, wouldn't a
for loop have been more natural?
if (*src != '\r')
*dst++ = *src;
src++;

Since you have opened the file in binary mode and MacOS 9.x and earlier
use '\r' as the line terminator you have just converted the file to one
long line on some systems.
}
*dst = 0;
}
return result;
}

Argument "mode" should be either "r" or "rb" for binary or text mode.
This can be omitted in Unix systems, where this stupid distinction
doesn't exist.

If I do not find a "b" in the "mode" string I eliminate CRs from the
string.

NOTE: This function will not run in the DS9000

You don't need a system that exotic for it to fail.
 
V

vippstar

Why are C interfaces so low level?

We discussed a bit about this in the thread about getting an URL from
the internet.

Take, for instance, we all some day needed to read an entire
file into RAM to process it. Why there isn't

char *strfromfile(const char *file_name,const char *mode);

As a holidays present, here it is.

[ snip ]
Argument "mode" should be either "r" or "rb" for binary or text mode.
This can be omitted in Unix systems, where this stupid distinction
doesn't exist.

If I do not find a "b" in the "mode" string I eliminate CRs from the
string.

NOTE: This function will not run in the DS9000

Why you never free() what you allocate?
I am talking about this
ioerror:
errno = EIO; // IO error
fclose(f);
return NULL;
/* other stuff */
char *result = malloc(l+1);
if (result == NULL) {
errno = ENOMEM;
fclose(f);
return NULL;
}
if (fread(result,1,l,f) <= 0)
goto ioerror;
^^^^^^^^^^^^^ At this point memory is allocated and
not freed.

Merry Christmas to the collective of c.l.c!
 
S

santosh

Why are C interfaces so low level?

We discussed a bit about this in the thread about getting an URL from
the internet.

Take, for instance, we all some day needed to read an entire
file into RAM to process it. Why there isn't

char *strfromfile(const char *file_name,const char *mode);

As a holidays present, here it is.

[ snip ]
Argument "mode" should be either "r" or "rb" for binary or text mode.
This can be omitted in Unix systems, where this stupid distinction
doesn't exist.

If I do not find a "b" in the "mode" string I eliminate CRs from the
string.

NOTE: This function will not run in the DS9000

Why you never free() what you allocate?

<snip>

Because jacob almost always assumes a modern OS like Windows or a UNIX
variant will clean up after the program.

In general, even if the OS may recover the memory, I still prefer
explicitly deallocating them. It better practise and stands up well to
porting to other systems.
 
V

vippstar

Why are C interfaces so low level?
We discussed a bit about this in the thread about getting an URL from
the internet.
Take, for instance, we all some day needed to read an entire
file into RAM to process it. Why there isn't
char *strfromfile(const char *file_name,const char *mode);
As a holidays present, here it is.
[ snip ]
Argument "mode" should be either "r" or "rb" for binary or text mode.
This can be omitted in Unix systems, where this stupid distinction
doesn't exist.
If I do not find a "b" in the "mode" string I eliminate CRs from the
string.
NOTE: This function will not run in the DS9000
Why you never free() what you allocate?

<snip>

Because jacob almost always assumes a modern OS like Windows or a UNIX
variant will clean up after the program.

In general, even if the OS may recover the memory, I still prefer
explicitly deallocating them. It better practise and stands up well to
porting to other systems.


That is silly, Jacob does not care to free his memory but he cares to
close his file streams?
 
S

santosh

Why are C interfaces so low level?
We discussed a bit about this in the thread about getting an URL
from the internet.
Take, for instance, we all some day needed to read an entire
file into RAM to process it. Why there isn't
char *strfromfile(const char *file_name,const char *mode);
As a holidays present, here it is.
[ snip ]
Argument "mode" should be either "r" or "rb" for binary or text
mode. This can be omitted in Unix systems, where this stupid
distinction doesn't exist.
If I do not find a "b" in the "mode" string I eliminate CRs from
the string.
NOTE: This function will not run in the DS9000
Why you never free() what you allocate?

<snip>

Because jacob almost always assumes a modern OS like Windows or a
UNIX variant will clean up after the program.

In general, even if the OS may recover the memory, I still prefer
explicitly deallocating them. It better practise and stands up well
to porting to other systems.


That is silly, Jacob does not care to free his memory but he cares to
close his file streams?

I agree. He should treat memory with the same care given to other
resources. Presumably, he feels that data corruption may occur if he
did not explicitly close the streams. That may or may not be true.
 
I

Ian Collins

jacob said:
Why are C interfaces so low level?

We discussed a bit about this in the thread about getting an URL from
the internet.

Take, for instance, we all some day needed to read an entire
file into RAM to process it. Why there isn't
Because any half decent OS provides a simple means of doing it. C also
runs on plenty of platforms that done have files.
char *strfromfile(const char *file_name,const char *mode);

As a holidays present, here it is.
Been and gone here...
 
S

santosh

Ian said:
Because any half decent OS provides a simple means of doing it. C
also runs on plenty of platforms that done have files.

And this particular task is also doable in standard C with no loss in
functionality or efficiency. I understand that the Committee had an
overall policy to include only those new functions in the Standard
library that would be impossible or difficult to replicate in user
code. This is opposite to the philosophy of the C++ Committee.
 
O

Old Wolf

Take, for instance, we all some day needed to read an entire
file into RAM to process it. Why there isn't

char *strfromfile(const char *file_name,const char *mode);

As a holidays present, here it is.

Your code doesn't even work properly in anything except Windows

Great present!
errno = ENOENT;
errno = ENOMEM;

ENOENT and ENOMEM are not defined (it is implementation-specific
whether such things exist)
if (strchr(mode,'b') == NULL) {
char *src = result,*dst = result;
while ((src - result) < l) {
if (*src != '\r')
*dst++ = *src;
src++;
}
*dst = 0;

This code is Windows-specific.

This has got to be the dumbest snippet I've seen in a
while. If you open the file in text mode then the
implementation performs this newline conversion and
any other such conversions for you. Why reinvent
the wheel?
 
M

Malcolm McLean

santosh said:
And this particular task is also doable in standard C with no loss in
functionality or efficiency. I understand that the Committee had an
overall policy to include only those new functions in the Standard
library that would be impossible or difficult to replicate in user
code. This is opposite to the philosophy of the C++ Committee.
It's not a good policy.
For instance everyone can knock up a strcpy() in a matter of minutes. You
can even improve the ANSI version somewhat.
But if you are reading standard, workaday code, that is maybe manipulating a
user report in a protein program, its a big help if the calls are familiar
with you. You don't want to be distracted by

if( str_lsetsafe(fred, FREDLEN, jim, 0, -1) == ERRVAL)
goto genbufferror;

when all we're doing is setting fred equal to jim.
 
J

jacob navia

Flash said:
Wouldn't it be more sensible to use the mode the user passes in?

No, because in text mode the standard doesn't guarantee that ftell and
fseek will work correctly!
Using l as a variable name was a bad idea because it makes it harder to
read the above line, or easier to miss-read it.

Yes, will change that to len
Also you fail to allow for it reading fewer then the number of 1 byte
members you specify. This can happen for a number of reasons.
goto ioerror;
result[l] = 0;
fclose(f);
if (strchr(mode,'b') == NULL) {
char *src = result,*dst = result;
while ((src - result) < l) {

Hmm. You have an initialisation, a test, and an increment, wouldn't a
for loop have been more natural?
if (*src != '\r')
*dst++ = *src;
src++;

Since you have opened the file in binary mode and MacOS 9.x and earlier
use '\r' as the line terminator you have just converted the file to one
long line on some systems.

Yes, will not work in DS9000 and MAC os9.x Easy to change though.
There is no portable way to know what line separator the system uses.
 
J

jacob navia

santosh said:
Why are C interfaces so low level?

We discussed a bit about this in the thread about getting an URL from
the internet.

Take, for instance, we all some day needed to read an entire
file into RAM to process it. Why there isn't

char *strfromfile(const char *file_name,const char *mode);

As a holidays present, here it is.

[ snip ]
Argument "mode" should be either "r" or "rb" for binary or text mode.
This can be omitted in Unix systems, where this stupid distinction
doesn't exist.

If I do not find a "b" in the "mode" string I eliminate CRs from the
string.

NOTE: This function will not run in the DS9000
Why you never free() what you allocate?

<snip>

Because jacob almost always assumes a modern OS like Windows or a UNIX
variant will clean up after the program.

In general, even if the OS may recover the memory, I still prefer
explicitly deallocating them. It better practise and stands up well to
porting to other systems.

It was just a memory leak santosh...
 
S

santosh

Malcolm said:
It's not a good policy.

It depends. Going the other way and including everything except the
Kitchen sink, as the C++ people have done might also be criticised by
some.
For instance everyone can knock up a strcpy() in a matter of minutes.
You can even improve the ANSI version somewhat.

If my program would significantly benefit from the improvement in
functionality or speed, then I'd use the platform specific version,
over the stock one supplied with the library.

But this is somewhat rare. Usually if a function is available as a part
of a Standard library, you'd do well to use it.
But if you are reading standard, workaday code, that is maybe
manipulating a user report in a protein program, its a big help if the
calls are familiar with you. You don't want to be distracted by

if( str_lsetsafe(fred, FREDLEN, jim, 0, -1) == ERRVAL)
goto genbufferror;

when all we're doing is setting fred equal to jim.

True. Nevertheless the overall philosophy of C is for it to supply
minimal functionality and thereby preserve ease of portability and
efficiency. If you want an extensive Standard library, try C++, Java,
Perl, Python, Tcl and others.
 
I

Ian Collins

santosh said:
It depends. Going the other way and including everything except the
Kitchen sink, as the C++ people have done might also be criticised by
some.
They didn't, they took the sensible path of standardising a container
and algorithms library that was in widespread use.

The next version will do much the same with the most widely used parts
of boot. It's a natural process of library evolution that the C
standard appears to have lost sight of.

If you want a true kitchen sink approach, try Java...
 
C

CBFalconer

jacob said:
Flash Gordon wrote:
.... snip ...


Yes, will not work in DS9000 and MAC os9.x Easy to change though.
There is no portable way to know what line separator the system
uses.

Yes there is. Just open the file in text mode (i.e. without the
"rb") and wait until you detect a '\n' in the stream. That is
exactly where a line separator occured.
 
J

jacob navia

CBFalconer said:
Yes there is. Just open the file in text mode (i.e. without the
"rb") and wait until you detect a '\n' in the stream. That is
exactly where a line separator occured.
So What?

You think the function should discover each time
it is called the line separator?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,050
Latest member
AngelS122

Latest Threads

Top