C - finding full path of command - c

I am trying to find the full path of a command someone would type in the terminal or console window. I am trying to use
getenv(PATH)
to get the ':' delimited strings of different paths the command may live in, and then use
stat()
to see if it exists in each one.
I am having trouble parsing through the returns of getenv() since I cannot use the string library.
getenv(path) returns:
PATH = /Library/Frameworks/Python.framework/Versions/3.2/bin:/Library/Frameworks/Python.framework/Versions/3.2/bin:/Library/Frameworks/Python.framework/Versions/2.7/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin
I am trying:
char* fullPath = getenv( "PATH" );
struct stat buffer;
int exists;
char* fileOrDirectory = usersCommand
exists = stat( file_or_dir, &buffer );
if ( exists == 0 && ( S_IFDIR & buffer.st_mode ) ) {
//dir exists
} else if ( exists == 0 && ( S_IFREG & buffer.st_mode ) ) {
//file exists
} else {
//neither exists
}
As of now I am not using my fullPath variable. As it is now is it just searching my local directory for the command?
An example command would be 'cd', or 'ls' , etc.
How can I parse through the ':' delimited string and then call stat on each one? I don't exactly understand the purpose of buffer besides having some info on the file or directory status but I feel like it should be taking another parameter so I can input what I am searching for as well as the fullPath.
Thanks

The function strtok is the standard method of tokenizing a string. With that you can build the full path-name of the file.
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
main(int argc, char **argv)
{
char* fullPath = getenv( "PATH" );
struct stat buffer;
int exists;
char* fileOrDirectory = argv[0];
char fullfilename[1024];
char *token = strtok(fullPath, ":");
/* walk through other tokens */
while( token != NULL )
{
sprintf(fullfilename, "%s/%s", token, fileOrDirectory);
exists = stat( fullfilename, &buffer );
if ( exists == 0 && ( S_IFREG & buffer.st_mode ) ) {
printf("found file %s\n", fullfilename);
}
token = strtok(NULL, ":"); /* next token */
}
exit(0);
}

Because string standard library functions are not allowed you need to write a string tokenizer yourself you can do something on the lines of the following code below, You might would have to refine it a little more.
Basically what we are doing here
Get the PATH
find token ':'
memcpy substring upto token -1
update the PATH
repeat until '\0'.
#define MAX_DIR_PATH_SIZE 500
char *get_directory(char **u_path, int *done)
{
int i;
char *temp = malloc(MAX_DIR_PATH_SIZE);
//handle error here
memset(temp,0,MAX_DIR_PATH_SIZE);
if(!u_path || !(*u_path))
return NULL;
int index =0 ;
for(i = 0;i <= MAX_DIR_PATH_SIZE ; i++)
{
if(index)
break;
switch((*u_path)[i]) // proximity of the brackets and * is important
{
case '\0':
*done = 1;
index = 1;
memcpy(temp,*u_path,i+1);
printf("Last substring %s\n",temp);
break;
//Search for token ': ascii = 58'
case 0x3A:
index = 1;
memcpy(temp,*u_path,i);
*u_path = *u_path+i+1;
printf("token found : %s\n",temp);
break;
default:
break;
}
}
//handle error for maximum size overlimit
return temp;
}
int main(int argc, char **argv)
{
char *fullPath = getenv( "PATH" );
char *u_path = fullPath;
struct stat buffer;
int exists;
int done = 0;
char* fileOrDirectory = NULL;
while(!done)
{
fileOrDirectory = get_directory(&u_path,&done);
printf("new path is : %s\n",u_path);
if(fileOrDirectory)
{
exists = stat( fileOrDirectory, &buffer );
if ( exists == 0 && ( S_IFDIR & buffer.st_mode ) ) {
printf("directory size %lu\n",buffer.st_size);
}
else {
//do something else
}
free(fileOrDirectory);
}
}
return 0;
}

Here's something to try:
// Variables needed during iteration.
char* start = fullPath;
char sep = ':';
char* iter;
char trialPath[BUFSIZ];
// Get the path
char* originalPath = getenv( "PATH" );
// Make a copy of the path since we are going to modify it
// while we are iterating on it.
char* fullPath = malloc(strlen(originalPath) + 1);
strcpy(fullPath, originalPath);
start = fullPath;
// Iterate over the path.
for ( char* iter = start; *iter != '\0'; ++iter )
{
if ( *iter == sep )
{
*iter = '\0';
// Now, start is a directory.
// Check whether the user command is at this location.
strcpy(trialPath, start);
strcat(trialPath, "/");
strcat(trialPath, usersCommand);
// Now use stat to check whether the file exists and
// it is an executable.
// ....
// If not, reset where start points to.
start = iter + 1;
}
}
// Deallocate memory allocated earliner.
free(fullPath);

Related

How to change the extension of the file

There are similar questions but my problem is a little more specific. I have a C code that takes file.txt and returns file.txt.rle when I am encoding by using RLE algorithm. Same way I decode that and want to write from file.txt.rle and return file.txt. The following code is what I am using as I go from file.txt to file.txt.rle:
char name[NAME_SIZE];
if(sprintf(name, "%s.rle", argv[1]) >= sizeof(name)){
fprintf(stderr, "Destination file name is too long\n");
}
while((o_fp = fopen(name, "wb")) == NULL){
fprintf(stderr, "Can't create the file to be written\n");
exit(1);
}
How can I accomplish to change the extension from file.txt.rle to file.txt when I decode? A full code won't help because I will use this in a code that decodes an encoded file.
Note: The given will always be in .txt.rle format and the returning file should always convert it to .txt.
You can simply do this with:
strrchr to find where is the last period in string,
strlen / malloc to allocate memory to store the new name,
sprintf to create the new name.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/* this function will create a new name, replacing the existing extension
by the given one.
returned value should be `free()` after usage
/!\ warning:
* validity of parameters is not tested
* return of strdup and malloc are not tested.
*/
char *replace_ext(const char *org, const char *new_ext)
{
char *ext;
/* copy the original file */
char *tmp = strdup(org);
/* find last period in name */
ext = strrchr(tmp , '.');
/* if found, replace period with '\0', thus, we have a shorter string */
if (ext) { *ext = '\0'; }
/* compute the new name size: size of name w/o ext + size of ext + 1
for the final '\0' */
size_t new_size = strlen(tmp) + strlen(new_ext) + 1;
/* allocate memory for new name*/
char *new_name = malloc(new_size);
/* concatenate the two string */
sprintf(new_name, "%s%s", tmp, new_ext);
/* free tmp memory */
free(tmp);
/* return the new name */
return new_name;
}
int main(void)
{
int i;
char *tests[] = { "test.ext", "test.two.ext", "test_no_ext", NULL};
for (i = 0; tests[i]; ++i)
{
char *new_name = replace_ext(tests[i], ".foo");
printf("%s --> %s\n", tests[i], new_name);
free(new_name);
}
return 0;
}
Here is an implementation.
The magic here is carried out by the change_file_name(org, dest, size, ext), that checks whether the name org ends with ext, and in that case copies the name up to that point.
Hope this helps.
/* Changes the name of the sys input file. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
bool change_file_name(const char * org, char * dest, size_t max_length, const char * file_ext)
{
bool toret = false;
const size_t name_length = strlen( org );
const size_t ext_length = strlen( file_ext );
const size_t new_name_size = name_length - ext_length;
if ( name_length > ext_length
&& name_length < max_length
&& strcmp( org + new_name_size, file_ext ) == 0 )
{
strncpy( dest, org, name_length - ext_length );
*( dest + new_name_size ) = 0;
toret = true;
}
return toret;
}
void convert_file(const char * org, const char * dest)
{
printf( "Processing file '%s' into '%s'\n", org, dest );
}
int main(int argc, char *argv[])
{
const int NAME_SIZE = 1024;
const char * rle_ext = ".rle";
char new_name[NAME_SIZE];
int toret = EXIT_SUCCESS;
if ( argc == 2 ) {
if ( change_file_name( argv[ 1 ], new_name, NAME_SIZE, rle_ext ) ) {
printf( "The new name is: '%s'\n", new_name );
convert_file( argv[ 1 ], new_name );
} else {
toret = EXIT_FAILURE;
fprintf( stderr,
"Name results empty, is not ending in '%s' or is too large: '%s'\n",
rle_ext,
argv[ 1 ] );
}
} else {
toret = EXIT_FAILURE;
fprintf( stderr, "Usage: %s <file name>.txt.rle\n", argv[ 0 ] );
}
return toret;
}
You can use strsep (successor to strtok) to tokenize your input filename and copy the parts which you are interested in and discarding the rest.
If your input filename is always of the form file.txt.rle, you can use the below code.
char *name = malloc(sizeof(char) * NAME_SIZE);
if(sprintf(name, "%s.rle", argv[1]) >= sizeof(name)){
fprintf(stderr, "Destination file name is too long\n");
}
char *token = NULL;
char *newfilename = malloc(sizeof(char) * (NAME_SIZE-4)); //strlen(".rle") = 4
uint8_t offset = 0;
memset(newfilename, 0, (NAME_SIZE-4));
while ((token = strsep(&name, ".")) != NULL) {
if(strcmp(token, "rle") == 0) {
break;
}
strncpy(newfilename+offset, token, strlen(token));
offset += strlen(token);
newfilename[offset] = '.';
offset += 1;
}
newfilename[strlen(newfilename)-1] = '\0';

Extract the file name and its extension in C

So we have a path string /home/user/music/thomas.mp3.
Where is the easy way to extract file name(without extension, "thomas") and it's extension ("mp3") from this string? A function for filename, and for extension. And only GNU libc in our hands.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_FILENAME_SIZE 256
char *filename(char *str) {
char *result;
char *last;
if ((last = strrchr(str, '.')) != NULL ) {
if ((*last == '.') && (last == str))
return str;
else {
result = (char*) malloc(MAX_FILENAME_SIZE);
snprintf(result, sizeof result, "%.*s", (int)(last - str), str);
return result;
}
} else {
return str;
}
}
char *extname(char *str) {
char *result;
char *last;
if ((last = strrchr(str, '.')) != NULL) {
if ((*last == '.') && (last == str))
return "";
else {
result = (char*) malloc(MAX_FILENAME_SIZE);
snprintf(result, sizeof result, "%s", last + 1);
return result;
}
} else {
return ""; // Empty/NULL string
}
}
Use basename to get the filename and then you can use something like this to get the extension.
char *get_filename_ext(const char *filename) {
const char *dot = strrchr(filename, '.');
if(!dot || dot == filename) return "";
return dot + 1;
}
Edit:
Try something like.
#include <string.h>
#include <libgen.h>
static void printFileInfo(char *path) {
char *bname;
char *path2 = strdup(path);
bname = basename(path2);
printf("%s.%s\n",bname, get_filename_ext(bname));
free(path2);
}
Regarding your actual code (all the other answers so far say to scrap that and do something else, which is good advice, however I am addressing your code as it contains blunders that it'd be good to learn about in advance of next time you try to write something).
Firstly:
strncpy(str, result, (size_t) (last-str) + 1);
is not good. You have dest and src around the wrong way; and further this function does not null-terminate the output (unless the input is short enough, which it isn't). Generally speaking strncpy is almost never a good solution to a problem; either strcpy if you know the length, or snprintf.
Simpler and less error-prone would be:
snprintf(result, sizeof result, "%.*s", (int)(last - str), str);
Similary in the other function,
snprintf(result, sizeof result, "%s", last + 1);
The snprintf function never overflows buffer and always produces a null-terminated string, so long as you get the buffer length right!
Now, even if you fixed those then you have another fundamental problem in that you are returning a pointer to a buffer that is destroyed when the function returns. You could fix ext by just returning last + 1, since that is null-terminated anyway. But for filename you have the usual set of options:
return a pointer and a length, and treat it as a length-counted string, not a null-terminated one
return pointer to mallocated memory
return pointer to static buffer
expect the caller to pass in a buffer and a buffer length, which you just write into
Finally, returning NULL on failure is probably a bad idea; if there is no . then return the whole string for filename, and an empty string for ext. Then the calling code does not have to contort itself with checks for NULL.
Here is a routine I use for that problem:
Separates original string into separate strings of path, file_name and extension.
Will work for Windows and Linux, relative or absolute style paths. Will handle directory names with embedded ".". Will handle file names without extensions.
/////////////////////////////////////////////////////////
//
// Example:
// Given path == "C:\\dir1\\dir2\\dir3\\file.exe"
// will return path_ as "C:\\dir1\\dir2\\dir3"
// Will return base_ as "file"
// Will return ext_ as "exe"
//
/////////////////////////////////////////////////////////
void GetFileParts(char *path, char *path_, char *base_, char *ext_)
{
char *base;
char *ext;
char nameKeep[MAX_PATHNAME_LEN];
char pathKeep[MAX_PATHNAME_LEN];
char pathKeep2[MAX_PATHNAME_LEN]; //preserve original input string
char File_Ext[40];
char baseK[40];
int lenFullPath, lenExt_, lenBase_;
char *sDelim={0};
int iDelim=0;
int rel=0, i;
if(path)
{ //determine type of path string (C:\\, \\, /, ./, .\\)
if( (strlen(path) > 1) &&
(
((path[1] == ':' ) &&
(path[2] == '\\'))||
(path[0] == '\\') ||
(path[0] == '/' ) ||
((path[0] == '.' ) &&
(path[1] == '/' ))||
((path[0] == '.' ) &&
(path[1] == '\\'))
)
)
{
sDelim = calloc(5, sizeof(char));
/* // */if(path[0] == '\\') iDelim = '\\', strcpy(sDelim, "\\");
/* c:\\ */if(path[1] == ':' ) iDelim = '\\', strcpy(sDelim, "\\"); // also satisfies path[2] == '\\'
/* / */if(path[0] == '/' ) iDelim = '/' , strcpy(sDelim, "/" );
/* ./ */if((path[0] == '.')&&(path[1] == '/')) iDelim = '/' , strcpy(sDelim, "/" );
/* .\\ */if((path[0] == '.')&&(path[1] == '\\')) iDelim = '\\' , strcpy(sDelim, "\\" );
/* \\\\ */if((path[0] == '\\')&&(path[1] == '\\')) iDelim = '\\', strcpy(sDelim, "\\");
if(path[0]=='.')
{
rel = 1;
path[0]='*';
}
if(!strstr(path, ".")) // if no filename, set path to have trailing delim,
{ //set others to "" and return
lenFullPath = strlen(path);
if(path[lenFullPath-1] != iDelim)
{
strcat(path, sDelim);
path_[0]=0;
base_[0]=0;
ext_[0]=0;
}
}
else
{
nameKeep[0]=0; //works with C:\\dir1\file.txt
pathKeep[0]=0;
pathKeep2[0]=0; //preserves *path
File_Ext[0]=0;
baseK[0]=0;
//Get lenth of full path
lenFullPath = strlen(path);
strcpy(nameKeep, path);
strcpy(pathKeep, path);
strcpy(pathKeep2, path);
strcpy(path_, path); //capture path
//Get length of extension:
for(i=lenFullPath-1;i>=0;i--)
{
if(pathKeep[i]=='.') break;
}
lenExt_ = (lenFullPath - i) -1;
base = strtok(path, sDelim);
while(base)
{
strcpy(File_Ext, base);
base = strtok(NULL, sDelim);
}
strcpy(baseK, File_Ext);
lenBase_ = strlen(baseK) - lenExt_;
baseK[lenBase_-1]=0;
strcpy(base_, baseK);
path_[lenFullPath -lenExt_ -lenBase_ -1] = 0;
ext = strtok(File_Ext, ".");
ext = strtok(NULL, ".");
if(ext) strcpy(ext_, ext);
else strcpy(ext_, "");
}
memset(path, 0, lenFullPath);
strcpy(path, pathKeep2);
if(rel)path_[0]='.';//replace first "." for relative path
free(sDelim);
}
}
}
Here is an old-school algorithm that will do the trick.
char path[100] = "/home/user/music/thomas.mp3";
int offset_extension, offset_name;
int len = strlen(path);
int i;
for (i = len; i >= 0; i--) {
if (path[i] == '.')
break;
if (path[i] == '/') {
i = len;
break;
}
}
if (i == -1) {
fprintf(stderr,"Invalid path");
exit(EXIT_FAILURE);
}
offset_extension = i;
for (; i >= 0; i--)
if (path[i] == '/')
break;
if (i == -1) {
fprintf(stderr,"Invalid path");
exit(EXIT_FAILURE);
}
offset_name = i;
char *extension, name[100];
extension = &path[offset_extension+1];
memcpy(name, &path[offset_name+1], offset_extension - offset_name - 1);
Then you have both information under the variables name and extension
printf("%s %s", name, extension);
This will print:
thomas mp3
I know this is old. But I tend to use strtok for things like this.
/* strtok example */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_TOKENS 20 /* Some reasonable values */
#define MAX_STRING 128 /* Easy enough to make dynamic with mallocs */
int main ()
{
char str[] ="/home/user/music/thomas.mp3";
char sep[] = "./";
char collect[MAX_TOKENS][MAX_STRING];
/* Not really necessary, since \0 is added inplace. I do this out of habit. */
memset(collect, 0, MAX_TOKENS * MAX_STRING);
char * pch = strtok (str, sep);
int ccount = 0;
if(pch != NULL) {
/* collect all seperated text */
while(pch != NULL) {
strncpy( collect[ccount++], pch, strlen(pch));
pch = strtok (NULL, sep);
}
}
/* output tokens. */
for(int i=0; i<ccount; ++i)
printf ("Token: %s\n", collect[i]);
return 0;
}
This is a rough example, and it makes it easy to deal with the tokens afterwards. Ie the last token is the extension. Second last is the basename and so on.
I also find it useful for rebuilding paths for different platforms - replace / with \.

Getting folder from a path

Let's say that I have a path as a string (like this one):
/ROOT/DIRNAME/FILE.TXT
How can I get the parent folder of file.txt (DIRNAME in this case)?
For a path that should have at least one directory in it:
char str[1024]; // arbitrary length. just for this example
char *p;
strcpy(str, "/ROOT/DIRNAME/FILE.TXT"); // just get the string from somewhere
p = strrchr(str, '/');
if (p && p != str+1)
{
*p = 0;
p = strrchr(p-1, '/');
if (p)
print("folder : %s\n", p+1); // print folder immediately before the last path element (DIRNAME as requested)
else
printf("folder : %s\n", str); // print from beginning
}
else
printf("not a path with at least one directory in it\n");
Locate last occurrence of / using strrchr. Copy everything from beginning of string to the found location. Here is the code:
char str[] = "/ROOT/DIRNAME/FILE.TXT";
char * ch = strrchr ( str, '/' );
int len = ch - str + 1;
char base[80];
strncpy ( base, str, len );
printf ( "%s\n", base );
Working just with string; no knowledge of symlink or other types assumed.
You can also do it simply using pointers. Just iterate to the end of the path and then backup until you hit a /, replace it with a null-terminating char and then print the string:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (int argc, char *argv[]) {
if (argc < 2 ) {
fprintf (stderr, "Error: insufficient input, usage: %s path\n", argv[0]);
return 1;
}
char *path = strdup (argv[1]);
char *p = path;
while (*p != 0) p++;
while (--p)
if (*p == '/') {
*p = 0;
break;
}
printf ("\n path = %s\n\n", path);
if (path) free (path);
return 0;
}
output:
$ ./bin/spath "/this/is/a/path/to/file.txt"
path = /this/is/a/path/to

Parsing a complex string in C

I have a String like this:
"00:00:00 000~00:02:00 0000|~00:01:00 0000;00:01:00 0000~",
I want to get each of the items like "00:00:00 000".
My idea is that first, split the string by ";", then split by "|", and finally split by "~".
But the problem is that I can't get it if it's null, such like "00:01:00 0000~", the part after "~", I wanna get it and set a default value to it then store it somewhere else, but the code doesn't work. What is the problem?
Here is my code:
int main(int argc, char *argv[])
{
char *str1, *str2, *str3, *str4, *token, *subtoken, *subt1, *subt2;
char *saveptr1, *saveptr2, *saveptr3;
int j;
for (j = 1, str1 = argv[1]; ; j++, str1 = NULL) {
token = strtok_r(str1, ";", &saveptr1);
if (token == NULL)
break;
printf("%d: %s\n", j, token);
int flag1 = 1;
for (str2 = token; ; str2 = NULL) {
subtoken = strtok_r(str2, "|", &saveptr2);
if (subtoken == NULL)
break;
printf(" %d: --> %s\n", flag1++, subtoken);
int flag2 = 1;
for(str3 = subtoken; ; str3 = NULL) {
subt1 = strtok_r(str3, "~", &saveptr3);
if(subt1 == NULL) {
break;
}
printf(" %d: --> %s\n",flag2++, subt1);
}
}
}
exit(EXIT_SUCCESS);
} /* main */
You can simplify your algorithm if you first make all delimiters uniform. First replace all occurrences of , and | with ~, then the parsing will be easier. You can do this externally via sed or vim or programmatically in your C code. Then you should be able to get the 'NULL' problem easily. (Personally, I prefer not to use strtok as it modifies the original string).
It is indeed easier to just write a custom parser in this case.
The version below allocates new strings, If allocating new memory is not desired, change the add_string method to instead just point to start, and set start[len] to 0.
static int add_string( char **into, const char *start, int len )
{
if( len<1 ) return 0;
if( (*into = strndup( start, len )) )
return 1;
return 0;
}
static int is_delimeter( char x )
{
static const char delimeters[] = { 0, '~', ',', '|',';' };
int i;
for( i=0; i<sizeof(delimeters); i++ )
if( x == delimeters[i] )
return 1;
return 0;
}
static char **split( const char *data )
{
char **res = malloc(sizeof(char *)*(strlen(data)/2+1));
char **cur = res;
int last_delimeter = 0, i;
do {
if( is_delimeter( data[i] ) )
{
if( add_string( cur, data+last_delimeter,i-last_delimeter) )
cur++;
last_delimeter = i+1;
}
} while( data[i++] );
*cur = NULL;
return res;
}
An example usage of the method:
int main()
{
const char test[] = "00:00:00 000~00:02:00 0000|~00:01:00 0000;00:01:00 0000~";
char **split_test = split( test );
int i = 0;
while( split_test[i] )
{
fprintf( stderr, "%2d: %s\n", i, split_test[i] );
free( split_test[i] );
i++;
}
free( split_test );
return 0;
}
Instead of splitting the string, it might be more suitable to come up with a simple finite state machine that parses the string. Fortunately, your tokens seem to have an upper limit on their length, which makes things a lot easier:
Iterate over the string and distinguish four different states:
current character is not a delimiter, but previous character was (start of token)
current character is a delimiter and previous character wasn't (end of token)
current and previous character are both not delimiters (store them in temporary buffer)
current and previous character are both delimiters (ignore them, read next character)
It should be possible to come up with a very short (10 lines?) and concise piece of code that parses the string as specified.

Readline Completion Problem

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.

Resources