Simple question I hope. I have a function that keeps prompting for user input (characters) and returns a character once it finds that the input is valid under certain conditions. I'm writing tests for this and other similar functions, but don't know how to fake user input. By the way, I'm using scanf() to get user input.
You can change the behaviour of standard input to read from a file with freopen. Place the test input in a file and call this before your test.
freopen("filename", "r", stdin);
You can do something like
echo -e "Test string\nAnother string" | ./a.out
The string of echo command should be in the sequence which the program requires
cat test_str_file | ./a.out
The file test_str_file should contain the test strings in the sequence the program requires
On the other hand you can simply replace the code's input section with some dummy sections. If you have a separate module for input, then replace it with dummy.
If you're on unix or cygwin, you can invoke your executable and ask it to use a text file as stdin. For example:
bash$ ./a.out < input_file
Why not just call the function with a default value?
This is a very naive solution, but it may do what you want:
char getFakeUserInput()
{
static char* fakeInput = "This is some user input\n";
static int pos = 0;
if(pos >= strlen(fakeInput))
return '\0';
return fakeInput[pos++]
}
Move the validation to another function. And test it independently. Or fake the user input refactor the remainder to take in a function pointer that is called back to collect some letters. That should enable a simple fake.
I've not written C for a long time but something like could also work
/* test this independentaly */
int isvalid(char* chars){
/* do stuff and return result */
}
/*real function */
char* getinput() {
scanf(....)
return stuff_from_scanf;
}
/*fake/mock function */
char* getinputFake(char * testString) {
return testString;
}
test() {
int result = isvalue(getinputFake("test data"));
/* rest of test */
}
You don't need to test the scanf function, but you could replace it with a fscanf and pass in the stream with the chars like this
stdin
char* getinput(FILE * stream) {
fscanf(stream....)
return stuff_from_fscanf;
}
test() {
FILE * stream = .....; /*create a dummy stream say from */
int result = isvalue(getinput(stream);
/* rest of test */
}
Related
In my C program, I use printf to print a formatted string to stdout then readline to get input from user with the ability to move cursor and navigate history. The issue is that if I enter a character then press backspace, the whole line, including the string printed by printf, gets deleted. Is there a way to fix this bad behavior? Should I report this as a bug to readline developers? Or should I print my formatted text to a buffer then use it as a prompt to readline?
A sample similar to the code:
...
printf("Some formatted text",...);
foo(buffer,length);
....
Inside foo:
{
...
temp=readline(NULL);
//Checking length...
...
strcpy(buffer,temp);
free(temp);
....
}
If you want a string to appear on the same terminal line as the line you're entering and reading with readline, you should make the string the 'prompt' argument to readline. This is difficult with the way you have things set up (the prompt printed outside of a function that calls readline), but if you can change that you can fix it:
char prompt[64]; // or some larger size
snprintf(prompt, sizeof(prompt), "Some formatted test", ...
foo(prompt, buffer, length);
foo(const char *prompt, char *buffer, size_t length) {
...
temp = readline(prompt);
// Checking length
I am writing an interactive REPL program in c.
Some examples of commands (lines starting with >) I would like to handle are:
$ ./my_program // run the program
> add user
id: 123 // this is the output of above command
> update user 123 name "somename"
> remove user 123
> quit
So basically the command is a line with multiple strings.
This is how I am trying to handle the commands.
scan the whole line
parse the command and get a corresponding int value unique to command
do whatever needs to be done for the command
#include <stdio.h>
int parse_cmd(const char *buffer)
{
// parse command
}
int main(int argc, const char **argv)
{
// init code
char buffer[100];
int cmd;
while (1) {
printf("> ");
scanf("%[^\n]%*c", buffer);
cmd = parse_cmd(buffer);
if (cmd < 0) {
printf("error: invalid command\n");
continue;
}
switch (cmd) {
// handle commands
}
}
// deinit code
}
There are a lot of cli programs I have seen that take command inputs in similar way.
I wonder if there is a general way of writing cli programs?
I can write code to parse the commands, just wanted to know the standard approach for such situations?
While there's no real standard way, quite a lot of opensource console tools with an interactive mode use the GNU readline library (https://tiswww.case.edu/php/chet/readline/rltop.html).
It's actually quite easy to use, even simpler than implementing everything 100% correctly by yourself.
Your example rebased on readline:
int main(int argc, const char **argv)
{
// init code
int cmd;
char* line;
while (1) {
line = readline("> ");
if (line) {
cmd = parse_cmd(line);
switch (cmd) {
// handle commands
default:
printf("error: invalid command\n");
}
free(line);
} else {
break;
}
}
// deinit code
}
This isn't any more complex than your example, but you immediately gain:
command line editing at the interactive prompt, with correct handling of each and every possible terminal
correct handling of EOF (important if stdin is redirected)
unlimited input line size
And it's not very hard to add a command history, with arrow-up and down to repeat previous lines, incremental search, optionally persisted to a file, et et.
There's not really a standard way to do it. This is not a 100% fair comparison, but your question is kind of like if there is a standard way to construct a compiler, because you are in fact constructing a language, although a very simple one.
But one reasonably common way that works fairly well for simple programs is this approach. Let's assume that we have two commands add and del. Create a function for both these commands. First we search for one of the strings "add " or "del ". Notice the spaces. Put a pointer on the next character and call the corresponding function with the rest of the line as argument and allow them to determine things.
Here is some pseudo:
parse(bufferptr)
word = getFirstWord(bufferptr)
ptr = bufferptr + strlen(word)
if word == "add"
return add(ptr)
else if word == "del"
return del(ptr)
return -1
add(bufferptr)
word = getFirstWord(bufferptr)
if userExist(word)
return -1
else
return addUser(word)
del(bufferptr)
word = getFirstWord(bufferptr)
if not userExist(word)
return -1
else
return delUser(word)
buffer = input()
int res = parse(buffer)
First of all, I'm new to C so pardon me if asking too much.
I have a function that tokenize an input by the user so let's say
user input: test -f myFile
then after the tokenize function it becomes
abc[0] = test
abc[1] = -f
abc[2] = myFile
However, at the same time, I also need to use the return value from that input (test) statement whether it is FALSE or TRUE (file exist or not exist).
I did (MY PROBLEM)
if (*abc != '1') {
printf ("nope.");
}
in hope for telling me first whether that file is valid / exist or not, before I call some other function. However, it says warning comparison between pointer and integer.
My original plan is:
// ask the user for input
// tokenize the input
if (*abc != '1') { // check the return value from the input
printf ("nope.");
}
// call another function
Any input why MYPROBLEM doesn't work? How do I execute test after I tokenize?
If you want to check whether anything was added to abc, you would have to initialize your array to NULs prior to calling tokenize and then afterwards, if (**abc == '\0') would tell you that nothing was tokenized.
However, it's probably better for your tokenize function to return a flag that indicates success or failure in addition to populating your array.
As for executing test, you can use the system() function or one of the exec() functions.
I need to create a program that does this:
execute a command with popen
do things with the output of popen(use the FILE in a lot of things)
stay checking for popen output changes, if have one, re execute everything.
The source code is here: https://gitorious.org/clyv/clyv
So I only want to execute all the rest of the program AGAIN if there is a change in the output of popen (must be compared with the first output)
The program should do everything first time, and after, only do everything and print again if there is a change on popen output. The popen should verified once a second.
Update
I didn't get any answer that solve my problem here, but reading a C tutorial i saw something about threads, and it sounds like the solution to me, i will see what i can do.
You are free to call popen() as many times as needed. But, to properly release resources used by a call to popen(), you need to call pclose().
In your case, you probably want to just poll the output occasionally, and emit something whenever it is necessary to do so.
first_time = 1;
need_to_print = 1;
for (;;) {
FILE *fp = popen(...);
/* read input ... */
pclose(fp);
/* parse input ... */
if (first_time) {
/* save contents for future comparison... */
first_time = 0;
} else {
need_to_print = /* result of comparing saved contents with new contents */;
}
if (need_to_print) {
/* print something ... */
}
sleep(INTERVAL);
}
You can use
//an array of 2 string buffers
char output[2][1024];
//the string buffer index in use
int flip = 0;
FILE *fp;
void executeTestCommand() {
int resultSize;
fp = popen("free -m | awk 'NR==3 {print $3}'" "r");
if (fp == NULL) {
perror("Failed to run command");
}
else {
result_size = fread(output, 1, 1024 - 1, fp);
//place string terminator
output[flip][result_size] = '\0';
}
//flip the buffers
flip = flip ^ 1;
pclose(fp);
}
int main() {
//init with empty string
output[0][0] = '\0';
output[1][0] = '\0';
//for ever
for(;;) {
executeTestCommand();
//if the last command output differs from the current
//command output
if (strcmp(output[0], output[1])) {
//execute the rest of the command here
}
}
return 0;
}
Cheers!
You want to close the file pointer (you don't want any memory leaks) since you are going to use the same FILE * fp variable again with popen.
Later edit: hope it helps:). You might want to insert a sleep statement inside the for ever block because this will be cpu intensive.
#AlinUngureanu #JonathanLeffler #jxh
I published the source on git! Now you can see what i want
https://gitorious.org/clyv/clyv
I am trying to simulate a shell terminal in c, one of the functionalities is to be provide a simple memory to remember the last command executed. So how I am going about is:
Every time the user enters a command (String) the string is saved in a file (command_histroy.txt)
If the user enters "r" (command=="r"), the terminal calls the function getSavedCommand(), as I am only saving only one command so my function is:
char* getSavedCommand(void){
char cmd[1000];
int i=0;
char* filename = "files/command_history.txt";
FILE* file = fopen(filename,"r");
if(file!=NULL){
int c;
do{
c = fgetc(file);
cmd[i]=c;
i++;
} while (c != EOF);
}else{
puts("Error Reading file");
}
return cmd;
}
So as in the file "command_history.txt", there is only one line stored, I reassumed that it would return this one line in an array of chars. To test I printed the results:
cmd = getSavedCommand();
printf("|%s|",cmd);
And the result I get is:
arj#arj-Inspiron-1545:~/projet$ ./a.out
|ls -l /home/arj
�|
arj#arj-Inspiron-1545:~/projet$
What I want is:
|ls -l /home/arj|
I think the EOF is creating the problem. Can someone help me?
One of the problem is you don't null terminate your array before returning. You need something like cmd[i] = '\0' at the end.
One more serious problem is you are returning a pointer to an object that is destroyed when the function returns. cmd object has automatic storage and is destroyed at the end of the function. Use malloc to allocate the array, or pass a pointer to the array as the argument of your getSavedFunction.
This functionality (plus command line edition, and a slew of other goodies) is the whole point of GNU readline (if on Linux, it is probably provided as a prebuilt package) or its BSD clone libedit (probably already available on BSD Unix).