Readline Completion Problem - c

I am trying to get command completion working but it seems like its not working properly..
Please have a look at my code and tell me how I can fix it..
Thanks in advance...
char store_commands() {
char *newEnv;
DIR * dir;
char *new ;
struct dirent * entry;
char *env = getenv("PATH");
do {
newEnv = strsep(&env, ":");
if(newEnv != NULL)
if(strlen(newEnv) > 0) {
dir = opendir(newEnv);
if( dir == NULL ) break;
if(flag == 1) {
flag = 0;
while((entry = readdir(dir)) != NULL) {
new = malloc(strlen(entry->d_name) + 1) ;
new = strcpy(new, entry->d_name);
commands[++count] = new; // add possible commands into an array
printf("---%i %s\n", count ,commands[count]);
}
}
closedir(dir); // close directory
}
} while(newEnv);
return **commands;
}
static char** my_completion( const char * text , int start, int end){
char **matches;
store_commands();
matches = (char **)NULL;
if (start == 0)
matches = rl_completion_matches ((char*)text, &my_generator);
return matches;
}
char * dupstr (char* s) {
char *r;
r = (char*) malloc ((strlen (s) + 1));
strcpy (r, s);
return (r);
}
char* my_generator(const char* text, int state) {
int index, len;
char *comm;
if (!state) {
index = 0;
len = (int)strlen (text);
}
while ( (comm = commands[index])) {
index++;
if (strncmp (comm, text, len) == 0)
return (dupstr(comm));
}
return NULL;
}
int main (int argc, char * argv[]) {
char *command;
using_history();
rl_readline_name = basename(argv[0]);
rl_attempted_completion_function = my_completion;
while ( (command = readline(" $ "))!= NULL ) { // scan stdin
rl_bind_key('\t',rl_complete);
if(strlen(command) > 0)
add_history(command);
}
return 0;
}
Some test cases
l (tab)
Display all 1281 possibilities? (y or n) // all possibilities come up when I put one letter *** all possibilities wrong actually what I meant was all commands including the ones dont start with l
ls (tab)
ls lsbom lsdistcc lsm lso lsvfs // seems alright here
however if I press enter
comm[0]: 'ls' and comm[1]: '(null)' // execution of the command fails!!! WHY????
Execution of the command is failed
: No such file or directory
If I use a static array like this one char *test[7] = {"ls","cat","lso", "mk", "mkd", "mkdir",""}; everything seems fine including execution of the command..

Where are the definitions/declarations for commands[] and count ?
Also: your style is incoherent, the program is barely readable.
Why do you cast the return from malloc() at one place and not at another place?
If (x == 0) {} and if ( !x ) {} are equivalent. Make your choice and stick with it.
The ugly do { ... } while ( ... ); loop can be replaced by a for( ... ; ... ; ...) {} loop, saving you two levels of indentation.

Related

Make login in database and change suffix if login already exists

I'm supposed to write a function that takes a login as argument and store this login at the end of the file named logins.db. If the login already exists in the database, you will add the suffix 1. If the login exists with that suffix, you will try with 2, the 3... until you find a valid login.
And with this 2nd part, I get confused and my code isn't working. I'm a beginner so if you have any tips or know what code I need to add, that would be awesome. Thanks.
#include <stdio.h>
typedef struct user
{
char name[100];
} user;
// ************ FUNCTION SPLIT ************ //
int ft_is_separator(char c, char *charset)
{
int i;
i = 0;
while (charset[i] != '\0')
{
if (c == charset[i])
return (1);
i++;
}
if (c == '\0')
return (1);
return (0);
}
int ft_wordlen(char *str, char *charset)
{
int i;
i = 0;
while (str[i] && !ft_is_separator(str[i], charset))
i++;
return (i);
}
int ft_wordcount(char *str, char *charset)
{
int i;
int count;
if (!str[0])
return (0);
i = 1;
count = !ft_is_separator(str[0], charset);
while (str[i] != '\0')
{
if (ft_is_separator(str[i - 1], charset)
&& !ft_is_separator(str[i], charset))
count ++;
i++;
}
return (count);
}
char *ft_strndup(char *src, int n)
{
char *dest;
int i;
i = 0;
dest = malloc(sizeof(char) * (n + 1));
if (dest == NULL)
return (NULL);
while (i < n && src[i])
{
dest[i] = src[i];
i++;
}
dest[i] = '\0';
return (dest);
}
char **ft_split(char *str, char *charset)
{
char **table;
int i;
int k;
k = 0;
table = malloc(sizeof(char *) * (ft_wordcount(str, charset) + 1));
if (table == NULL)
return (NULL);
i = 0;
while (str[i])
{
if (!ft_is_separator(str[i], charset))
{
table[k] = ft_strndup(&str[i], ft_wordlen(&str[i], charset));
if (table[k] == NULL)
return (NULL);
i = i + ft_wordlen(&str[i], charset);
k++;
}
else
i++;
}
table[k] = NULL;
return (table);
}
// ************ FUNCTION STRCMP ************ //
int ft_strcmp(char *s1, char *s2)
{
int i;
i = 0;
while (s1[i] || s2[i])
{
if (s1[i] != s2[i])
return (s1[i] - s2[i]);
i++;
}
return (0);
}
// ************ FUNCTION MAIN ************ //
int main(void)
{
FILE *fichier = NULL;
user det;
int recsize;
int i = 0;
fichier = fopen("logins.db" , "r+");
if (fichier != NULL)
{
recsize = sizeof(det);
fseek(fichier , 0 ,SEEK_END);
printf("Enter Login : ");
scanf("%s" , det.name);
fprintf(fichier, "user_generator %s \n", det.name);
char **table = ft_split("logins.db" , "/n");
printf("%s \n", table[0]);
while (table[i])
{
if (ft_strcmp(table[i], det.name) == 0)
{
fprintf(fichier, "user_generator %s + %d \n", det.name, i);
}
i++;
}
fclose(fichier);
}
return (0);
}
In attempting to construct the table within main,
char **table = ft_split("logins.db" , "/n");
you are sending in the database name, and not the contents of the file itself. To fix this, you need to read from the file. It would not be practical to put the entire file into a single char array, because you would need to make a massive buffer to estimate just how big the database is. Instead, use the fgets function to read from the file line by line.
char* nextLine = fgets(buffer, maxLength, fichier);
You will need to change some implementation to account for this change but it will separate the file by lines, giving you the next one each time you call the function. However, before you read you need to set the FILE* location back to the start of the file (your fseek() moved the pointer to the end of the file).
Finally, you are likely to run into a problem when modifying the name of the user, as you are incrementing the suffix for every line defined in the table, and not when a username in the table matches with det.name. Also, if det.name is already in the table, you now have to check for det.name + 1 to make sure it does not exist, and so on. This may take more than one loop as well, because the names may not necessarily be sorted.

Equal strings produces different hash index

I have a program here that does replicate a memory filesystem (not finished yet), it has to read from a file its commands and they are pretty self explanatory here:
create /foo
create /foo/bar
create /foo/baz
create /foo/baz/qux
write /foo/bar "test"
read /foo/bar
read /foo/baz/qux
read /foo/baz/quux
create /foo/bar
create /dir
create /bar
create /dir/bar
find bar
delete /foo/bar
find wat
find foo
read /foo/bar
create /foo/bar
read /foo/bar
delete_r /foo
exit
I then have a function that given the string it manipulates it to insert folder names in an array strings, a command is a command string and the fullPath string is given by another function that does use the previously created array of strings to compose a new one. Here is the struct and the manipulation structure:
typedef struct _command {
unsigned char command[10];
unsigned char path[255][255];
unsigned char* fullPath;
int pathLevels;
} command;
This is the node structure that does implement the tree-like structure:
typedef struct _node {
int isRoot;
int isDir;
char* message;
int childNumber;
struct _node* childNodes[1024];
unsigned char fullPath[MAX_LEN_PATH];
unsigned char resName[255];
} node;
And the function that does manipulate the string:
command* createCommandMul(unsigned char* str) {
unsigned char* c = str;
command* commandPointer = (command*) malloc(sizeof(command));
//commandPointer->path[0][0] = '/';
//commandPointer->path[0][1] = '\0';
int commandIndex = 0;
int pathLevel = 0;
int pathIndex = 0;
/* Parte Comando */
while(*c != ' ' && commandIndex < 10) {
commandPointer->command[commandIndex] = *c++;
commandIndex++;
}
while(commandIndex<10) {
commandPointer->command[commandIndex] = '\0';
commandIndex++;
}
while(*c == ' ' || *c == '/') c++;
/* Parte Path*/
while(*c != '\0') {
if (*c == '/') {
commandPointer->path[pathLevel][pathIndex] = '\0';
pathLevel++;
pathIndex = 0;
c++;
} else {
commandPointer->path[pathLevel][pathIndex] = *c++;
pathIndex++;
}
}
commandPointer->path[pathLevel][pathIndex] = '\0';
commandPointer->pathLevels = pathLevel;
return commandPointer;
}
I have a createDir function that does check if the node* passed to the function is either a dir or the root (imagine this has a tree);
if it is it creates the node.
int createDir(node* fatherOfChildToCreate, unsigned char* fullPath, command* currentCommand) {
if ((fatherOfChildToCreate->isRoot == 1 || fatherOfChildToCreate->isDir == 1) && fatherOfChildToCreate->childNumber < 1024) {
node* dirToCreate = (node*) malloc(sizeof(node));
command* comando = (command*) currentCommand;
dirToCreate->isDir = 1;
dirToCreate->isRoot = 0;
dirToCreate->message = NULL;
dirToCreate->childNumber = 0;
strcmp(dirToCreate->fullPath, fullPath);
for (int i = 0; i < 1024; i++) dirToCreate->childNodes[i] = NULL;
int index = (int) hashCalc(comando->path[comando->pathLevels]);
printf("Hash di %s = %d", comando->path[comando->pathLevels], index);
fatherOfChildToCreate->childNodes[index] = dirToCreate;
fatherOfChildToCreate->childNumber += 1;
return 1;
} else return 0;
}
Note that this createDirfunctions is created with the purpose of creating a direct subDir of the node* fatherOfChildToCreate so basically the first command of the text file does create /foo using this function because its only parentDir is the root one, which is created in the main().
The second command will search for the /foo directory using this function down below, and since it is the parent directory of /foo/bar that pointer will be passed to the createDir function that will create a childNode in the /foo dir.
node* linearSearchUpper(node* rootNode, unsigned char* upperPath, command* currentCommand) {
command* comandoSearch = (command*) currentCommand;
node* curr = (node*) rootNode;
int counter = comandoSearch->pathLevels;
int index;
unsigned char* upperName = comandoSearch->path[comandoSearch->pathLevels - 1];
for (int i = 0; i < counter; i++) {
index = (int) hashCalc(comandoSearch->path[i]);
printf("Hash di %s = %d", comandoSearch->path[i], index);
if (curr->childNodes[index] == NULL) return NULL;
else curr = curr->childNodes[index];
}
if (strcmp(upperPath, curr->fullPath) == 1) return curr;
}
In all this I've used this hash function to search for the parentDir and inserting a new element in the node->childNodes[] array
unsigned long hashCalc(unsigned char* str) {
unsigned long hash = 5381;
int c;
while (c = *str++)
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
return hash % 1024;
}
Now, I'll paste the main() which is the last function to review.
int main() {
node* rootNode = (node*) createRoot();
command* comando = (command*) malloc(sizeof(command));
unsigned char* upPath = NULL;
unsigned char* allPath = NULL;
unsigned char* line = NULL;
FILE* fp;
size_t len = 0;
ssize_t read;
fp = fopen("/Users/mattiarighetti/Downloads/semplice.txt", "r");
if (fp == NULL)
exit(EXIT_FAILURE);
while ((read = getline(&line, &len, fp)) != -1) {
if (*line == 'f') {
//comandoFind = createCommandFind(line);
} if (*line == 'w') {
//comandoWrite = createCommandWrite(line);
} if (*line == 'c') {
comando = createCommandMul(line);
upPath = upperPath(comando);
allPath = fullPath(comando);
if (comando->pathLevels == 0) {
if (createDir(rootNode, allPath, comando) == 1) printf("ok\n\n");
else printf("no\n\n");
} else {
node* upperNode = (node*) linearSearchUpper(rootNode, upPath, comando);
if (upperNode == NULL) {
printf("no\n\n");
}
else {
if (createDir(upperNode, allPath, comando) == 1) printf("ok\n\n");
else printf("no\n\n");
}
}
}
}
fclose(fp);
if (line)
free(line);
return 0;
}
So, what this does is reading line to line from the file, creating and filling the command struct, it then creates an upPath which is the parent (to be found) and the fullPath. The problem I am getting is that the program uses createDir for the first line of this text file, and this is ok, but reading foo in the comando->path[I] for some strange reason, the hash function gives me 179 which is not correct. The in goes on, the second line it uses linearSearchUpper() to search for the parent folder /foo, so it gives comando->path[I] which is again foo but this time the hashCalc gives me 905 which should be the correct answer so in the end the linearSearchUpper can't find the /foo folder since it doesn't exist in the index 905. This thing happens every time I use a create command or create_dir with folders that are childs of the rootOne, so dirs like /foo, /dir, /bar will give me a strange hash index.
Do you have any idea on why this could happen?
I haven't tried to understand your whole program, but the strings for wich you get the different hashes really are different: One of them retains the new-line character at the end, probably from fgets.
The numerc value of the new-line character in ASCII is 10, so:
hash("foo") == 905;
hash("foo\n") == (33 * hash("foo") + '\n') % 1024
== (33 * 905 + 10) % 1024
== 179
The solution is to either remove trailing spaces from the string you receive from fgets or to use better tokenising, that will guarantee that your tokens don't have leading or trailing spaces.

String Search C program without using built-in functions

I have a problem in my C program. This is the String Search program. The problem is when I type the String aabaaacaamaad, the result comes NULL when I search for ab in it but it should not as ab is there in aabaaacaamaad. The same result also comes with am and ad which is right but why does it come with aabaaacaamaad? Code:
char* MyStrstr(char* pszSearchString, char* pszSearchWord);
int main(int argc, char* argv[])
{
char szTemp1[20] = {0};
char szTemp2[10] = {0};
char * pszTemp1 = NULL;
strcpy(szTemp1, "aabaaacaamaad");
strcpy(szTemp2, "aa");
pszTemp1 = MyStrstr(szTemp1, szTemp2);
printf("%s", pszTemp1);
getch();
return 0;
}
char* MyStrstr(char* pszSearchString, char* pszSearchWord)
{
int nFcount = 0;
int nScount = 0;
int nSearchLen = 0;
int nIndex = 0;
char* pszDelString = NULL;
if(pszSearchString == NULL || pszSearchWord == NULL) {
return NULL;
}
while(pszSearchWord[nSearchLen] != '\0') {
nSearchLen++;
}
if(nSearchLen <= 0){
return pszSearchString;
}
for(nFcount = 0; pszSearchString[nFcount] != '\0'; nFcount++) {
if(pszSearchString[nFcount] == pszSearchWord[nScount]) {
nScount++;
} else {
nScount = 0;
}
if(nScount == nSearchLen) {
nIndex = (nFcount - nScount) + 1;
pszDelString = pszSearchString + nIndex;
return pszDelString;
}
}
return NULL;
}
I see what your code is trying to do, you want to avoid a loop in a loop but however you're missing one thing. When a match fails you're not going back but still moving forward in pszSearchString while you should not. The result of this flaw is that with incomplete matches you skip characters. That's the reason why the strstr function originally uses a loop in a loop so for every character in pszSearchString there is an new loop to match with pszSearchWord. Here the original strstr.c file from BSD/Darwin:
char * strstr(const char *in, const char *str)
{
char c;
size_t len;
c = *str++;
if (!c)
return (char *) in; // Trivial empty string case
len = strlen(str);
do {
char sc;
do {
sc = *in++;
if (!sc)
return (char *) 0;
} while (sc != c);
} while (strncmp(in, str, len) != 0);
return (char *) (in - 1);
}

Call by reference of a string with double pointer

Hi guys I got some problems with using a function with a reference to a string as argument. I read that you should use e double pointer for this, but I can't get it to work.
This is (partly) my code.
enum errCode { ERR_NONE = 0, ERR_EMPTY, ERR_FULL, ERR_MEM, ERR_INIT, ERR_COMMAND, ERR_UNDEFINED };
typedef enum errCode ErrCode;
typedef enum {
no = 0, add, del, src, show, exit
} Command;
int main(void) {
char stringval[50];
char stringval2[50];
ErrCode err;
Command currentCommand = no;
printf("Enter a command\n");
if (fgets(stringval, 50, stdin) != NULL) {
char *p;
if ((p = strchr(stringval, '\n')) != NULL)
*p = '\0';
}
ErrHandler(
extractCommand(&currentCommand, stringval, &stringval2)
);
printf("stringval 2 = %s.\n", stringval2);
return 0;
}
ErrCode extractCommand(Command *command, char *inputString, char **outputString) {
char *strTemp;
char *strTemp2;
//Get the first word of the string
strTemp = strtok(inputString, " ");
strTemp2 = strtok(NULL, " ");
*outputString = strTemp2;
//Check if it equals a command
if (strcmp(strTemp, "exit") == 0) {
*command = exit;
return ERR_NONE;
} else if (strcmp(strTemp, "add") == 0) {
*command = add;
return ERR_NONE;
} else if (strcmp(strTemp, "del") == 0) {
*command = del;
return ERR_NONE;
} else if (strcmp(strTemp, "src") == 0) {
*command = src;
return ERR_NONE;
} else if (strcmp(strTemp, "show") == 0) {
*command = show;
return ERR_NONE;
} else {
*command = no;
printf("%s", strTemp);
return ERR_COMMAND;
}
}
This is what my output looks like:
Enter a command
add this is a test
stringval 2 = z˜ˇøÀo‡èK‡èT¯ˇø.
I obviously want to have the second word of the inputted string, but I'm doing something wrong.
Thx for the help!
stringVal2 is not initialised and is never populated: that is reason junk is being printed. There is no need in this case to pass a char**, passing a char* will work. However, this:
outputString = strTemp2;
does not copy the content of strTemp2 to outputString: it makes outputString point to the same address as strTemp2: use strcpy().
A double pointer, char** for example, is commonly passed to a function when that function allocates a new buffer for the argument (which is not the case in the posted code):
char* buf = NULL;
my_alloc(&buf);
void my_alloc(char** p)
{
*p = malloc(10);
}

function to split a filepath into path and file

Lets say I have a function:
void split_path_file(char** p, char** f, char *pf)
{
//malloc and set *p to file path, malloc and set *f to file name
//pf is the pointer to the full file and path "C:\sponge\bob\square.pants"
// edit: leave pf in its origional state
}
Whats the best way to accomplish this?
void split_path_file(char** p, char** f, char *pf) {
char *slash = pf, *next;
while ((next = strpbrk(slash + 1, "\\/"))) slash = next;
if (pf != slash) slash++;
*p = strndup(pf, slash - pf);
*f = strdup(slash);
}
(If pf == slash, then there is no directory component.)
Maybe a bit late to the party, but the best solution I have found and have been using for years is the two functions dirname and basename
path dirname basename
"/usr/lib" "/usr" "lib"
"/usr/" "/" "usr"
"usr" "." "usr"
"/" "/" "/"
They are great for separating parts of a path/filename. Together with realpath() they are IMHO unbeatable in simplicity and power.
http://linux.die.net/man/3/basename
http://man7.org/linux/man-pages/man3/realpath.3.html
Go backwards through the string until you reach the first '\\' then set *f to everything after it and *p to everything before and the '\\'.
The simplest way seems to be to start from the end and work towards the beginning, looking for the first delimiter character. You then have two cases: either you found one or you didn't. Something like this should do it for you:
#include <stdlib.h>
#include <string.h>
void split_path_file(char **p, char **f, char *pf) {
char *newcopy = malloc(strlen(pf) + 1);
strcpy(newcopy, pf);
for (z=newcopy+strlen(newcopy); z>newcopy; z--) {
if (*z == '/' || *z == '\\')
break;
}
if (z > newcopy) {
*p = newcopy;
*z = '\0';
*f = z+1;
} else {
*f = newcopy;
*p = NULL;
}
}
Update: #ephemient's comment below points out the above approach doesn't leave *p and *f suitable for calling free(). If this is important, something a little more complicated like this will be needed:
#include <stdlib.h>
#include <string.h>
void split_path_file(char **p, char **f, char *pf) {
/* Find last delimiter. */
char *z;
for (z=pf+strlen(pf); z>=pf; z--) {
if (*z == '/' || *z == '\\')
break;
}
if (z >= pf) {
/* There is a delimiter: construct separate
path and filename fragments. */
printf("--> %i\n", z-pf);
*p = malloc(z-pf+1);
strncpy(*p, pf, z-pf);
(*p)[z-pf] = '\0';
*f = malloc(strlen(z));
strcpy(*f, z+1);
} else {
/* There is no delimiter: the entire
string must be a filename. */
*p = NULL;
*f = malloc(strlen(pf)+1);
strcpy(*f, pf);
}
}
I came up with the following, of course this assumes that pf is malloced.
void split_path_file(char** p, char **f, char *pf)
{
char *posp = strrchr(pf, '\\');
*posp = '\0';
*p = strdup(pf);
*f = strdup(posp+1);
*posp = '\\';
}
Not sure if this is a better approach than above answers.
int
stripfilenameandpath (char *path, char *onlypath, char *onlyfilename)
{
/*
documentacao
path = path com path e arquivo
onlypath = somente o path
onlyfilename = somente o arquivo sem o path
*/
int ret;
int i;
int p;
char temp[255];
char *fixo;
#ifdef WIN32
const int separator = '\\';
#else
const int separator = '/';
#endif
fixo = path;
if (path == NULL)
{
if (onlypath != NULL)
{
memset (onlypath, 0, 1);
}
if (onlyfilename != NULL)
{
memset (onlyfilename, 0, 1);
}
return 1;
}
ret = strlen (path);
if (!ret)
{
if (onlypath != NULL)
{
memset (onlypath, 0, 1);
}
if (onlyfilename != NULL)
{
memset (onlyfilename, 0, 1);
}
return 0;
}
for (i = 0; i -1; i--)
{
if (temp[i] == separator)
{
temp[i + 1] = 0;
break;
}
p++;
}
p = ret - p;
fixo += p + 1;
if (onlypath != NULL)
{
strcpy (onlypath, temp);
}
if (onlyfilename != NULL)
{
strcpy (onlyfilename, fixo);
}
return 0;
}

Resources