When the first scanf() is used and you answer Y, the second scanf() skips straight to “No option selected. Exiting…”. That message also appears when the keyfile is larger than the sourcefile and the last scanf does it’s job properly. So I’m at a loss here, what is wrong? (code compiles nicely so feel free to try)
EDIT: It would be helpful for downvoters to at least post a reason. I am not a very good programmer and just attempting to learn here.
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
int main(int argc, char **argv)
{
struct stat statbuf;
struct stat keybuf;
int key;
int data;
int output;
int count;
char ans;
FILE * keyfile;
FILE * sourcefile;
FILE * destfile;
if(argc<4)
{
printf("OTP-Bunny 1.0\n");
printf("USAGE: OTP <source file> <output file> <keyfile>\n");
return (0);
}
/* Check number of arguments. */
if(argc>4)
{
printf("Too many arguments.\n");
printf("USAGE: OTP <source file> <output file> <keyfile>\n");
return(1);
}
/* Check if sourcefile can be opened. */
if((sourcefile = fopen(argv[1], "rb"))== NULL)
{
printf("Can't open source file.\n");
printf("Please enter a valid filename.\n");
printf("USAGE: OTP <source file> <output file> <keyfile>\n");
perror("Error");
return (1);
}
/* Get size of sourcefile */
fstat(fileno(sourcefile), &statbuf);
/* Check if keyfile can be opened. */
if((keyfile = fopen(argv[3], "rb"))== NULL)
{
printf("Can't open keyfile.\n");
printf("Please enter a valid filename.\n");
printf("USAGE: OTP <source file> <output file> <keyfile>\n");
perror("Error");
return(1);
}
/* Get size of keyfile */
fstat(fileno(keyfile), &keybuf);
/* Check if keyfile is the same size as, or bigger than the sourcefile */
if((keybuf.st_size) < (statbuf.st_size))
{
printf("Source file is larger than keyfile.\n");
printf("This significantly reduces cryptographic strength.\n");
printf("Do you wish to continue? (Y/N)\n");
scanf("%c", &ans);
if(ans == 'n' || ans == 'N')
{
return (1);
}
if(ans == 'y' || ans == 'Y')
{
printf("Proceeding with Encryption/Decryption.\n");
}
else
{
printf("No option selected. Exiting...\n");
return (1);
}
}
/* Check if destfile can be opened. */
if((keyfile = fopen(argv[2], "wb"))== NULL)
{
printf("Can't open output file.\n");
perror("Error");
return(1);
}
/* Open destfile. */
destfile=fopen(argv[2], "wb");
/* Encrypt/Decrypt and write to output file. */
while(count < (statbuf.st_size))
{
key=fgetc(keyfile);
data=fgetc(sourcefile);
output=(key^data);
fputc(output,destfile);
count++;
}
/* Close files. */
fclose(keyfile);
fclose(sourcefile);
fclose(destfile);
printf("Encryption/Decryption Complete.\n");
/* Delete keyfile option. */
printf("Do you wish to delete the keyfile? (Y/N)\n");
scanf("%c", &ans);
if(ans == 'y' || ans == 'Y')
{
if ( remove(argv[3]) == 0)
{
printf("File deleted successfully.\n");
}
else
{
printf("Unable to delete the file.\n");
perror("Error");
return(1);
}
}
if(ans == 'n' || ans == 'N')
{
return(0);
}
else
{
printf("No option selected. Exiting...\n");
}
return(0);
}
Actually,
scanf()is behaving correctly, but it is a very tricky function to use correctly and it is easy for your expectations to be different from its documented behaviour.Your first
scanf()call reads a single character, leaving the newline behind.Your second
scanf()call reads a newline because that’s next…leading to problems.You can fix the code by using
" %c"; the leading blank skips (optional) white space.In general, the better fix is to use a combination of
fgets()or equivalent (readline()in POSIX 2008, perhaps), andsscanf(). Read a line of data into memory withfgets(); analyze it withsscanf(). That way, you can report the error better too; you have all the information that the user typed available for error reporting.