After some reflection on user Kevin's post hereKevin's post here, I thought it might be useful to capture some of the comment discussion permanently and also provide to users who don't use C very much (I don't myself lately), a deeper explanation of what is going on.
int read_some_type(char *filename, struct some_type *result){
int rc = 0;
{ //<1> "Code is broken on entry" shell
if(!result){
rc = -1;
goto out;
}
{ //<2> "Try to open a file" shell
int fd = open(filename, O_RDONLY);
if(fd == -1){
rc = -1;
goto out;
}
{ //<3> "Try to allocate" shell
// Normally we'd allocate this on the stack; assume struct some_type is huge.
char *str = malloc(sizeof(struct some_type));
if(!str){
rc = -1;
goto out_open;
}
{ //<4> "Evaluate and act" shell
ssize_t size;
size_t total = 0;
while(total != sizeof(struct some_type)){
size = read(fd, &str[total], total - sizeof(struct some_type));
if(size <= 0){
rc = -1;
goto out_malloc;
}
total += size;
}
memcpy(result, str, sizeof(struct some_type));
out_malloc:
} //</4>
free(str);
out_open:
} //</3>
close(fd);
out:
} //</2>
} //</1>
// This is strictly unnecessary, but we could add code here in the future.
// For example, we might check errno and call perror(3) or similar.
return rc;
}
int read_some_type(char *filename, struct some_type *result){
int rc = 0;
{ //<1> "Code is broken on entry" shell
if(!result){
rc = -1;
goto out;
}
{ //<2> "Try to open a file" shell
int fd = open(filename, O_RDONLY);
if(fd == -1){
rc = -1;
goto out;
}
{ //<3> "Try to allocate" shell
// Normally we'd allocate this on the stack; assume struct some_type is huge.
char *str = malloc(sizeof(struct some_type));
if(!str){
rc = -1;
goto out_open;
}
{ //<4> "Evaluate and act" shell
ssize_t size;
size_t total = 0;
while(total != sizeof(struct some_type)){
size = read(fd, &str[total], total - sizeof(struct some_type));
if(size <= 0){
rc = -1;
goto out_malloc;
}
total += size;
}
memcpy(result, str, sizeof(struct some_type));
out_malloc:
} //</4>
free(str);
out_open:
} //</3>
close(fd);
out:
} //</2>
} //</1>
// This is strictly unnecessary, but we could add code here in the future.
// For example, we might check errno and call perror(3) or similar.
return rc;
}