Check your return values!
Code:
if (fgets(srcFileName, sizeof srcFileName, stdin) == NULL) {
/* End of input! */
return EXIT_FAILURE;
}
/* Remove the newline (and anything following it,
* except it is never followed by anything in this particular case).
*/
srcFileName[strcspn(srcFileName, "\n")] = '\0';
if (srcFileName[0] == '\0') {
/* Line was empty! */
return EXIT_FAILURE;
}
The strcspn() function is declared in <string.h>, and reports the index of the first character in the specified list (we only listed newline, \n). If the string does not contain any of those, it returns the length of the string. For example, to remove everything following the first digit in string foo, including the digit, you can use
foo[strcspn(foo, "0123456789")] = '\0';
Second, if you include <string.h> and <errno.h>, you can check and report the reason for the file open failure:
Code:
sourceFile = fopen(srcFileName, "r");
if (sourceFile == NULL) {
fprintf(stderr, "%s: %s.\n", srcFileName, strerror(errno));
return EXIT_FAILURE;
}
errno is a special variable declared by <errno.h>. Many C library functions set it to indicate the cause when a problem occurs. It is not zeroed by anything, unless you zero it out yourself (errno = 0; is perfectly legal).
Note that because many functions set it when an error occurs, you cannot do other stuff in between an error and examining errno. You can copy it into an int variable, however. For example, if you wanted to close the sourceFile if opening the output file fails, you could do it thus:
Code:
outputFile = fopen(outFileName, "w");
if (outputFile == NULL) {
const int errnum = errno;
fclose(sourceFile);
fprintf(stderr, "%s: %s.\n", srcFileName, strerror(errnum));
return EXIT_FAILURE;
}
I used const int errnum = errno; instead of int errnum; errnum = errno; above, because errnum is not going to be modified.
(fclose() is one of those functions that is allowed to set errno if fclose() fails. Its failure never means the file handle remains open; it just means an error occurred when the file was closed. If it occurs when closing a file you wrote to, you should treat it as a write error. Most programmers do not bother, though; I hate that.)
It is a good practice to sprinkle const whenever the variable is not supposed to be modified, and also when the pointer target is only to be read, not written to. It helps the compiler check things, and occasionally even generate better code; but most of all it is helpful to other programmers, because they can see which stuff is supposed to be mutable, and which stuff constant. Helps understand what the original programmer intended, you see.