readline with a default value - c

I am able to limit the user input to 5 characters using GNU readline:
#include <readline/readline.h>
#include <stdio.h>
#include <stdlib.h>
static int limit_rl(FILE *f)
{
if (rl_end > 5) {
return '\b';
}
return rl_getc(f);
}
int main(void)
{
char *str;
rl_getc_function = limit_rl;
str = readline("> ");
printf("%s\n", str);
free(str);
return 0;
}
But, how to read an input with a default value (not a prompt), e.g.:
> ummy
^ cursor here
if user types d and Enter return "dummy"
if user types DEL and Enter return "mmy"

On the homepage of readline a possible use is mentioned:
rl.c is an example program that uses Readline to read a line of input from a user and echo it to the standard output, suitable for use by shell scripts.
and since editing an existing entry could well be part of this, I decided to take a look at its source (direct download link). This indeed shows how to insert a string into the buffer used by readline before it appears on the screen, through the use of a hook function:
Variable: rl_hook_func_t * rl_startup_hook
If non-zero, this is the address of a function to call just before readline prints the first prompt.
(https://cnswww.cns.cwru.edu/php/chet/readline/readline.html#IDX223)
Inside the hook function you can directly manipulate the internal buffer, for example to insert text:
Function: int rl_insert_text (const char *text)
Insert text into the line at the current cursor position. Returns the number of characters inserted.
(https://cnswww.cns.cwru.edu/php/chet/readline/readline.html#IDX295)
The hook function only needs to do this once (it is called only once per readline call inside readline_internal_setup), but apparently rl's author went for the belt-and-suspenders approach and specifically disables it after it has been used.
Relevant snippets from rl.c, comments are mine:
/* a global char * to hold a default initial text */
static char *deftext;
/* the callback function. The argument is supposed to be 'void' per
its declaration:
typedef int rl_hook_func_t (void);
so you cannot provide the default text here */
static int set_deftext ()
{
if (deftext)
{
/* Apparently the "current cursor position" in which text is inserted
is 0, when initially called */
rl_insert_text (deftext);
deftext = (char *)NULL;
/* disable the global 'rl_startup_hook' function by setting it to NULL */
rl_startup_hook = (rl_hook_func_t *)NULL;
}
return 0;
}
// ...
if (deftext && *deftext)
rl_startup_hook = set_deftext;
temp = readline (prompt);

Related

How do you open a FILE with the user input and put it into a string in C

So I have to write a program that prompts the user to enter the name of a file, using a pointer to an array created in main, and then open it. On a separate function I have to take a user defined string to a file opened in main and return the number of lines in the file based on how many strings it reads in a loop and returns that value to the caller.
So for my first function this is what I have.
void getFileName(char* array1[MAX_WIDTH])
{
FILE* data;
char userIn[MAX_WIDTH];
printf("Enter filename: ");
fgets(userIn, MAX_WIDTH, stdin);
userIn[strlen(userIn) - 1] = 0;
data = fopen(userIn, "r");
fclose(data);
return;
}
For my second function I have this.
int getLineCount(FILE* data, int max)
{
int i = 0;
char *array1[MAX_WIDTH];
if(data != NULL)
{
while(fgets(*array1, MAX_WIDTH, data) != NULL)
{
i+=1;
}
}
printf("%d", i);
return i;
}
And in my main I have this.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_WIDTH 144
void getFileName(char* array1[MAX_WIDTH]);
int getLineCount(FILE* data, int max);
int main(void)
{
char *array1[MAX_WIDTH];
FILE* data = fopen(*array1, "r");
int max;
getFileName(array1);
getLineCount(data, max);
return 0;
}
My text file is this.
larry snedden 123 mocking bird lane
sponge bob 321 bikini bottom beach
mary fleece 978 pasture road
hairy whodunit 456 get out of here now lane
My issue is that everytime I run this I keep getting a 0 in return and I don't think that's what I'm supposed to be getting back. Also, in my second function I have no idea why I need int max in there but my teacher send I needed it, so if anyone can explain that, that'd be great. I really don't know what I'm doing wrong. I'll appreciate any help I can get.
There were a number of issues with the posted code. I've fixed the problems with the code and left some comments describing what I did. I do think that this code could benefit by some restructuring and renaming (e.g. array1 doesn't tell you what the purpose of the variable is). The getLineCount() function is broken for lines that exceed MAX_WIDTH and ought to be rewritten to count actual lines, not just calls to fgets.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_WIDTH 144
/**
* Gets a handle to the FILE to be processed.
* - Renamed to indicate what the function does
* - removed unnecessary parameter, and added return of FILE*
* - removed the fclose() call
* - added rudimentary error handling.
**/
FILE *getFile()
{
char userIn[MAX_WIDTH+1];
printf("Enter filename: ");
fgets(userIn, MAX_WIDTH, stdin);
userIn[strlen(userIn) - 1] = 0; // chop off newline.
FILE *data = fopen(userIn, "r");
if (data == NULL) {
perror(userIn);
}
return data;
}
/**
* - removed the unnecessary 'max' parameter
* - removed null check of FILE *, since this is now checked elsewhere.
* - adjusted size of array1 for safety.
**/
int getLineCount(FILE* data)
{
int i = 0;
char array1[MAX_WIDTH+1];
while(fgets(array1, MAX_WIDTH, data) != NULL)
{
i+=1;
}
return i;
}
/**
* - removed unnecessary array1 variable
* - removed fopen of uninitialized char array.
* - added some rudimentary error handling.
*/
int main(void)
{
FILE *data = getFile();
if (data != NULL) {
int lc = getLineCount(data);
fclose(data);
printf("%d\n", lc);
return 0;
}
return 1;
}
There are several things I think you should repair at first:
getFileName should help you getting the file name (as the name says), so in that function you shouldn’t have both array1 and userIn (as a matter of fact array1 is not even used in the function, so it can be eliminated all togheter). The paramater and the file name should be ‘the same’.
data is a local FILE pointer, this means once you exit the function you lose it. My recommandation is to make it global, or pass it as an argument from the main class. Also do not close it 1 line after you open it.
I guess the getLineCount is fine, but usually is a good practice to return and printf in main what is returned.
That max that is passed to the second function maybe to help you with the max size of a line? it might be.
Summing up, your getFileName should return the file name, so that userIn is what should be given by that parameter. The File opening should be done IN THE MAIN FUNCTION and be closed after everything you do related to the file, so at the end. Also, open the file after you get the name of the file.
Hopefully it helps you! Keep us tuned with your progress.

Is it possible to call functions from arrays in C? [duplicate]

This question already has answers here:
How can I use an array of function pointers?
(12 answers)
Closed 4 years ago.
When I was making my terminal i was wondering if I can call a function by array.
(This code is not done yet so please code is a bit messy.)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <unistd.h>
#include <limits.h>
#define true 1
#define false 0
typedef int bool;
/* Static */
static char Input[CHAR_MAX];
static char CurrentDirectory[CHAR_MAX];
static char *Command;
static char *Argument;
static char *Commands[]={"test","test2"};
/* Functions */
int Check_Command();
int test();
int test2();
/* --------- */
int main(){
printf("#######################\n\tterminal\n\tType \"help\" for the list of commands\n#######################\n");
prompt:
printf(">");
fgets(Input,CHAR_MAX,stdin);
int res=Check_Command();
if(res==0){printf("Unknown Command!\n");}
goto prompt;
}
/* Check_Command() function returns 0 if doesn't suceed and returns 1 of it suceeds */
int Check_Command(){
//Since input variable is static, no need to send in arguments
Input[strcspn(Input,"\r\n")]=0;
Command=strtok(Input," ");
Argument=strtok(NULL," ");
int x=0;
while(x<sizeof(Commands)){
if(strcmp(Command,Commands[x])==0){
Commands[x](); <----- Can I call a function like this?
return 1;
}
x++;
}
return 0;
}
/* Commands */
int test(){
printf("Success!\n");
getchar();
exit(0);
}
int test2(){
print("Success [2] \n");
getchar();
exit(0);
}
If this possible then this would be lit, Im too lazy to make commands into a executable and using if statements for all commands.
if you are too lazy to read the whole code here is a basic concept (UNTESTED):
static *Commands[]={"test","test2"};
int main(){
char *Command="test";
int x=0;
while(x<sizeof(Commands)){
if(strcmp(Command,Commands)==0){
Commands[x]();
}
x++
}
}
int test(){
printf("Hi");
}
int test2(){
printf("hey");
}
Edit:
static char Commands[]={test,test2}; DOES NOT WORK
This also includes the "possible duplicate" answer. (Im using Mingw, Windows 10)
It appears that you want to be able to take in a string such as test2 from the user, and then invoke the function test2(). There are two main ways you can approach this:
Homebrew structure mapping names to function pointers.
Using 'dynamic library loading' and function name resolution.
Array of structures
For the first, you define a structure such as:
struct FuncName
{
const char *name;
int (*function)(void);
};
And you can then define an array of these:
struct FuncName functions[] =
{
{ "test", test },
{ "test2", test2 },
};
enum { NUM_FUNCTIONS = sizeof(functions) / sizeof(functions[0]) };
When you get a name from the user, you can search through the array of names and find the matching function pointer to call.
int invoke_function(const char *name)
{
for (int i = 0; i < NUM_FUNCTIONS; i++)
{
if (strcmp(name, functions[i].name) == 0)
{
return (*functions[i].function)();
// Or just: return functions[i].function();
}
}
return -1; // No match found
}
This works reliably on all systems, but the demerit is that you must create the table of function pointers when you compile the program.
Dynamic library
The alternative is to use functions dlopen() and dlsym() from the <dlsym.h> header on Unix (POSIX) systems, or the equivalent on Windows.
Normally, you expect to find the functions in dynamically loaded libraries loaded with dlopen(), but there's usually a way to search the main executable for the names instead (pass a null pointer as the file name to dlopen() on POSIX systems). You can then call dlsym() to get the function pointer corresponding to the name you specify, which you can call.
void *dlh = dlopen(NULL, RTLD_NOW);
int (*funcptr)(void) = (int (*)(void))dlsym("test", dlh);
return (*funcptr)();
This omits error checking and you need the cast to convert from an object pointer (void *) to a function pointer because the C standard does not require that to be doable, but POSIX does (see the specification of
dlsym() already linked to).
Non-uniform function signatures
With both solutions, life is easy if all the callable functions have the same interface. Life is much messier if the different functions have different interfaces (so some expect no arguments, some expect one, some expect two, and the types of the arguments vary between functions, as do the return types). Expect to use lots of casts and be prepared to bludgeon the compiler into submission — isolate the code from everything else so as to leave the non-portable part well separated from the main code.
Beware: no compiler was consulted about the validity of any of this code!

How to return a string from GetOpenFileNameA

This is a function to open a file dialog in Windows and return a string with the file name:
#include <windows.h>
#include <commdlg.h>
#include <string.h>
char* openFileDlg(char FileTypes[]);
char* openFileDlg(char FileTypes[]){
OPENFILENAME ofn;
char szFile[260];
HWND hwnd;
HANDLE hf;
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hwnd;
ofn.lpstrFile = szFile;
ofn.lpstrFile[0] = '\0';
ofn.nMaxFile = sizeof(szFile);
strcpy(ofn.lpstrFilter,FileTypes);
ofn.nFilterIndex = 1;
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = NULL;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
if(GetOpenFileNameA(&ofn)){
char *toReturn;
sprintf(toReturn,"%s",ofn.lpstrFile);
return toReturn;
}
else{
return NULL;
}
}
When I call this function and open a file, the process ends and returns value 3 (which means there is an error). How can I do so that this function returns a string with the path of the selected file?
Edit: I've changed my code to this and it still doesn't work:
#include <windows.h>
#include <commdlg.h>
#include <string.h>
void openFileDlg(char *toReturn[],char FileTypes[]);
void openFileDlg(char *toReturn[],char FileTypes[]){
OPENFILENAME ofn;
/*
Code for the settings of the GetOpenFileNameA, irrelevant in this question.
If you really need to know what's here, look at the code above.
*/
if(GetOpenFileNameA(&ofn)){
strcpy(*toReturn,ofn.lpstrFile);
}
else{
sprintf(*toReturn,"");
}
}
I should also say that if I press the Cancel button in the open file dialog box instead of selecting a file, it works fine. After some tests, I've noticed that it's the line strcpy(*toReturn,ofn.lpstrFile); that causes the error.
The pointer variable toReturn doesn't point anywhere, using it in any way without initializing it (i.e. making it point somewhere valid and big enough) will lead to undefined behavior
You have two solutions really:
Allocate memory dynamically and return a pointer to that. This of course requires the caller to free the memory when done with it.
Have the function take another two arguments: A pointer to a buffer and the length of the buffer. Then copy the string into that buffer, and return a boolean "true" or "false" success/failure status.
I recommend solution number two.
On an unrelated note, there's no need to use the expensive sprintf function in your case, a simple strcpy (or strncpy if you go with the second solution) will do.
You also have to remember in both cases that strings in C have an actual length of one more than e.g. strlen reports, for the terminating '\0' character.
In general, if you want to return a string in C, I'd use one of the following methods:
1) pass in a string buffer for the method to write to:
int openFileDlg(char FileTypes[], char* toReturn, int bufLen) {
/* ... */
snprintf(toReturn, bufLen, /* what you want to print */);
return ERROR; // status-code
}
/* ... */
char errorBuf[80];
int result;
result = openFileDlg(..., errorBuf, sizeof(errorBuf));
2) allocate memory, expect caller to free it:
char* openFileDlg(char FileTypes[]) {
/* ... */
char *toReturn = malloc(/* big enough */);
sprintf(toReturn, /* what you want to print */);
return toReturn;
}
/* ... */
char* error = openFileDlg(...);
if (error) {
/* ... */
free(error);
}
personally, I'd prefer (1) because it's safer. Option (2) is nicer to the API of the function, but has a risk of memory leaks if you forget to free the returned buffer. In a bigger project (especially with multiple people working on it) this is a very real risk.
(I realise this is pretty much the same as Joachim's answer, but his went up as I was writing mine)
You did not allocate memory for your return value. If you know the length of ofn.lpstrFile you could do this:
char *toReturn = malloc( (sizeOfLpstrFile + 1) * sizeof(char)) ;
sprintf(toReturn,"%s",ofn.lpstrFile);
return toReturn;
Still I consider this a bad idea because the calling function will have to free the memory which is not obvious from the interface.

Explanation of missing prototype error message for custom getln function in C

#include <stdio.h>
#include <stdlib.h>
#include <reg51.h>
void main (void) {
SCON = 0x52; // serial port configuration
TMOD = 0x20;
TCON = 0x40;
TH1 = 0xf3; // 2403 baudrate #12mhz
printf("Hello World");
printf("Please enter some text: ");
scanf(getLine());
}
const char *getLine()
{
char *line = NULL, *tmp = NULL;
size_t size = 0, index = 0;
int ch = EOF;
while (ch) {
ch = getc(stdin);
if (ch == EOF || ch == '\n')
ch = 0;
if (size <= index) {
size += CHUNK;
tmp = realloc(line, size);
if (!tmp) {
free(line);
line = NULL;
break;
}
line = tmp;
}
line[index++] = ch;
}
return line;
}
free(str);
That's my code. I think I'm calling getln incorrectly. Is there a way to have the function accept input I can pass in from the user?
This compiler is an evaluation version but I believe it contains the libraries I need.
My goal is to accept a "string", or rather an array of chars and then manipulate its order as a skill test. I only have 2000 KB of memory available to write this.
I'm a bit of a novice when it comes to pointers and not being able to reference. Help or even just explanations are much appreciated.
I'm using a KEIL compiler.
When I select Program>Rebuilt All Target Files to check my errors I receive the following:
assembling STARTUP.A51... assembling XBANKING.A51... compiling
Main.c... MAIN.C(14): warning C206: 'getln': missing
function-prototype MAIN.C(14): error C214: illegal pointer conversion
Target not created
Thank you,
You need to add:
const char *getLine(void);
at the top, below the includes.
This is called a function prototype, and it needs to appear in your source file before the function is used.
You're basically telling the compiler in advance that getLine is a function that takes no arguments and returns const char *. So even though the compiler hasn't seen the definition of the function yet, it can still verify that it's being used correctly when it appears in your main function.
Otherwise the compiler has no idea what getLine is when it hits line 14, and gives an error.
You have correctly defined the function at the bottom, but the C compiler needs a list of functions, called prototypes, at the top. The prototype must include the function type, function name, and any arguments the function takes. For example:
#include <stdio.h>
void hello_world(); //This is the function prototype
int main()
{
hello_world();
}
void hello_world() //You did this part correctly, but C needs the
{ //prototype at the top in order to see this as a
printf("Hello, world!\n"); //defined function
}
In your case, the prototype would simply be:
const char *getLine(void);
and then your program would run without any prototype errors.
Cheers!
Alternatively, if you want to avoid defining the function prototype, define the getLine before main, like
#include ...
const char * getLine() {
...
}
int main() {
...
}

syscall read acting weird

c lang, ubuntu
so i have a task - write a menu with these 3 options:
1. close program
2. show user id
3. show current working directory
i can only use 3 libraries - unistd.h, sys/syscall.h, sys/sysinfo.h.
so no printf/scanf
i need to use an array of a struct im given, that has a function pointer,
to call the function the user wants to use.
problem is on options 2 & 3;
when i pick 2, on the first time it works fine (i think)
second time i pick 2, it works, but then when going to the third iteration,
it doesn't wait for an input, it takes '\n' as an input for some reason, then it says invalid input. (i checked what it takes as input with printf, i printed index after recalculating it and it because -39, so it means selection[0] = 10 = '\n')
that's the first problem, that i just cant find the solution for.
second problem is on the current working directory function;
the SYS_getcwd returns -1 for some reason, which means there's an error, but i cant figure it out.
any explanations for these things?
(also - slen and __itoa are functions i am given - slen returns the length of a string,
__itoa returns a char*, that was the string representation of an integer)
helper.h:
typedef struct func_desc {
char *name;
void (*func)(void);
} fun_desc;
main.c:
#include <unistd.h>
#include "helper.h"
#include <sys/syscall.h>
#include <sys/sysinfo.h>
void exitProgram();
void printID();
void currDir();
int main() {
fun_desc arrFuncs[3];
arrFuncs[0].name = "exitProgram";
arrFuncs[0].func = &exitProgram;
arrFuncs[1].name = "printID";
arrFuncs[1].func = &printID;
arrFuncs[2].name = "currDir";
arrFuncs[2].func = &currDir;
char selection[2];
int index;
const char* menu = "Welcome to the menu. Please pick one of the following actions:\n1.Close the program\n2.Print the current user's id\n3.Print the current directory's id\n";
while(1 == 1) {
syscall(SYS_write, 0, menu, slen(menu));
syscall(SYS_write, 0, "Your selection: ", slen("Your selection: "));
syscall(SYS_read, 1, selection, slen(selection)); //might be a problem
selection[1] = '\0';
index = selection[0] - '0' - 1;
if(index > 2)
syscall(SYS_write, 0, "Invalid input\n", slen("Invalid input\n"));
else
arrFuncs[index].func();
}
return(0);
}
void exitProgram() {
syscall(SYS_write, 0, "The program will close\n", slen("The program will close\n"));
syscall(SYS_exit);
}
void printID() { //problem
char* uid = __itoa(syscall(SYS_getuid));
syscall(SYS_write, 0, uid, slen(uid));
syscall(SYS_write, 0, "\n", slen("\n"));
}
void currDir() { //????
char* buf = __itoa(syscall(SYS_getcwd));
syscall(SYS_write, 0, buf, slen(buf));
syscall(SYS_write, 0, "\n", slen("\n"));
}
You're passing the wrong number of arguments to some of these system calls. In particular:
syscall(SYS_exit);
_exit() takes one argument: the exit code.
char* buf = __itoa(syscall(SYS_getcwd));
getcwd() takes two arguments: a pointer to a buffer to write the string to, and the length of that buffer. In practice, this probably looks something like:
char pathbuf[PATH_MAX];
syscall(SYS_getcwd, pathbuf, sizeof(pathbuf));
If you don't have the header which defines PATH_MAX, define it yourself. 4096 is an appropriate value.
Note that getcwd() writes a string into the buffer passed to it — it does not return a numeric identifier.
As an aside, you may want to save yourself some time by implementing a wrapper to write a string, e.g.
void putstring(const char *str) {
syscall(SYS_write, 0, str, slen(str));
}
since you seem to be doing that a lot.

Resources