I am trying to do simple shell as an exercise to myself. I am writing a function that should find an executable in the PATH, and return a pointer to a string, that contains the full path to executable. Here is what I have so far;
/*bunch of includes here*/
/*
* Find executable in path, return NULL
* if can't find.
*/
char *find_executable(char *command)
{
const char *PATH = getenv("PATH");
DIR *dp;
/* get each pathname, and try to find executable in there. */
}
int main(int argc,char *argv[])
{ /* nothing intersting here ...*/
}
I was wondering how should I separate each part of the path, and process these parts in a for loop.
say paths would be separated by ;
You can use strtok function to generate splitted token.
e.g.
char *str = "/foo/a1/b1;/bar/a1/b1"
Now you can use strtok function as
char delims[] = ";"
char *result = NULL;
result = strtok( str, delims );
while( result != NULL ) {
dp = result;
result = strtok( NULL, delims );
}
Related
I'm trying to get the string thet's after /xxx/, there is a must be forward slashes, two of them, then the string that I need to extract.
Here is my code, but I don't know where to set the null terminator, there is a math problem here
char str[100] = "/709/usr/datapoint/nviTemp1";
char *tmp;
char token[100];
tmp = strchr(str+1, '/');
size_t len = (size_t)(tmp-str)+1;
strncpy(token, str+len, strlen(str+len));
strcat(token,"\0");
I want to extract whatever after /709/ which is usr/datapoint/nviTemp1
Note that /709/ is variable and it could be any size but for sure there will be two forward slashes.
Simple improvement:
char str[100] = "/709/usr/datapoint/nviTemp1";
char *tmp;
char token[100];
tmp = strchr(str+1, '/');
if (tmp != NULL) strncpy(token, tmp + 1, sizeof(token)); else token[0] = '\0';
tmp points the slash after "/709", so what you want is right after there.
You don't have to calculate the length manually.
Moreover, strncpy copies at most (third argument) characters, so it should be the length of the destination buffer.
If you know for sure that the string starts with `"/NNN/", then it is simple:
char str[100] = "/709/usr/datapoint/nviTemp1";
char token[100];
strcpy(token, str+5); // str+5 is the first char after the second slash.
If you need to get everything after the second slash:
char str[100] = "/709/usr/datapoint/nviTemp1";
char token[100];
char* slash;
slash = strchr(str, '/'); // Expect that slash == str
slash = strchr(slash+1, '/'); // slash is second slash.
strcpy(token, slash+1); // slash+1 is the string after the second slash.
You can use a counter and a basic while loop:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
if (argc < 2) return 0;
char *s = argv[1];
char slash = '/';
int slash_count = 0;
while (slash_count < 2 && *s)
if (*s++ == slash) slash_count++;
printf("String: %s\n", s);
return 0;
}
Then you can do whatever you want with the s pointer, like duplicating it with strdup or using strcat, strcpy, etc...
Outputs:
$ ./draft /709/usr/datapoint/nviTemp1
String: usr/datapoint/nviTemp1
$ ./draft /70905/usr/datapoint/nviTemp1
String: usr/datapoint/nviTemp1
You can make use of sscanf-
sscanf(str,"%*[/0-9]%s",token);
/* '/709/' is read and discarded and remaining string is stored in token */
token will contain string "usr/datapoint/nviTemp1" .
Working example
I'm writing a program that when executed in a directory will generate a text file with all of the contents in that directory. I'm getting the directory path from the **argv to main and because I'm using netbeans and cygwin I have to do some string manipulation of the obtained path in my char* get_path(char **argv) function. The directory path size will always vary therefore I'm assigning space with malloc to store it in the memory.
Program snippet:
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include "dbuffer.h" //my own library
#include "darray.h" //my own library
ARR* get_dir_contents( char* path)
{
DBUFF *buff = NULL;
ARR *car = NULL;
DIR *dir_stream = NULL;
struct dirent *entry = NULL;
dir_stream = opendir(path);
if(opendir(path)==NULL) printf("NULL");
//... more code here
return car;
}
char* get_path(char **argv)
{
char *path = malloc(sizeof(char)* sizeof_pArray( &argv[0][11] ) + 3 );
strcpy(path, "C:");
strcat(path, &argv[0][11]);
printf("%s, sizeof: %d \n",path, sizeof_pArray(path));
return path;
}
int main(int argc, char** argv)
{
char *p = get_path(argv);
ARR *car = get_dir_contents(&p[0]);
//... more code here
return (EXIT_SUCCESS);
}
The problem is that the string that I have doesn't initialize the dir_stream pointer. I suspect it is because of some discrepancy between pointers and string literals but I can't pinpoint what it is exactly. Also the fact that dirent library function expects DIR *opendir(const char *dirname); const char might have something to do with it.
Output:
C:/Users/uk676643/Documents/NetBeansProjects/__OpenDirectoryAndListFiles/dist/Debug/Cygwin_4.x-Windows/__opendirectoryandlistfiles, sizeof: 131
NULL
RUN FAILED (exit value -1,073,741,819, total time: 2s)
there are some things here that can go wrong so
I would suggest doing something like this instead
char* get_path(char *argv)
{
char *path = malloc(sizeof(char)* strlen(argv) );
if (path != NULL)
{
strcpy(path, "C:");
strcat(path, argv + 11);
printf("%s, sizeof: %d \n",path, strlen(path));
}
return path;
}
...
char* p = get_path(*argv);
note: you don't need the extra 3 bytes, since you allocate including the 11 bytes you later skip. although instead of having the 11 bytes offset you may want to decompose the string and then later put it together so that it is portable. E.g. using strtok you could split that path and replace the parts you don't need.
Could it be a simple confusion about argv ? Please insert the following lines
just at the beginning of your main() , is it what you expected ?
printf("\n argv[0]== %s" , argv[0] );
getchar();
printf("\n argv[1]== %s" , argv[1] );
getchar();
OK, so we work from argv[0] , please try this for get_path
char *get_path(char *argv)
{
int i=0;
// +2 to add the drive letter
char *path = malloc(sizeof(char)* strlen(argv)+2 );
if (path != NULL)
{
strcpy(path, "C:");
strcat(path, argv);
// we get the path and the name of calling program
printf("\n path and program== %s",path);
printf("%s, sizeof: %d \n",path, strlen(path));
// now remove calling program name
for( i=strlen(path) ; ; i--)
{
// we are working in windows
if(path[i]=='\\') break;
path[i]='\0';
}
}
return path;
}
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);
I'm new to C and I've been working on this task for about 7 hours now - please don't say I didn't try.
I want to parse the path of a self-written webserver in C. Let's say I call
http://localhost:8080/hello/this/is/a/test.html
then the browser gets
GET /hello/this/is/a/test.html HTTP/1.1
I want to parse /hello/this/is/a/test.html, so the complete string between "GET " (note the white space after GET) and the first white space after /../../..html.
What I tried so far:
int main() {
...
char * getPathOfGetRequest(char *);
char *pathname = getPathOfGetRequest(buf);
printf("%s\n\n%s", buf, pathname);
...
}
char * getPathOfGetRequest(char *buf) {
char *startingGet = "GET ";
char buf_cpy[BUFLEN];
memcpy(buf_cpy, buf, sizeof(buf));
char *urlpath = malloc(1000);
char *path = malloc(1000);
urlpath = strstr(buf_cpy, startingGet);
char delimiter[] = " ";
path = strtok(urlpath, delimiter);
path = strtok(NULL, delimiter);
return path;
}
The pathname always only has 4 correct chars and may or may not be filled with other unrelated chars, like /hell32984cn)/$"ยง$. I guess it has something to do with strlen(startingGet), but I can't see the relationship between it. Where is my mistake?
Question code with commentary:
char * getPathOfGetRequest(char *buf) {
char *startingGet = "GET ";
char buf_cpy[BUFLEN];
memcpy(buf_cpy, buf, sizeof(buf));
The above memcpy will likely only copy 4 bytes from buf to buf_cpy.
This is due to buf being a pointer to a char.
sizeof(buf) is the size of a pointer (likely: 4).
Perhaps, instead of using 'sizeof()', it would have been better to use 'strlen()'.
char *urlpath = malloc(1000);
char *path = malloc(1000);
urlpath = strstr(buf_cpy, startingGet);
Perhaps the questioner is not clear on why urlpath was allocated 1000 bytes of memory. In any case, the above assignment will cause that 1000 bytes to be leaked, and defeats the purpose of the 'urlpath=malloc(1000)'.
The actual effect of the above statements is urlpath = buf_cpy;, as strstr() will return the position of the beginning of 'GET ' in the buf_copy.
char delimiter[] = " ";
path = strtok(urlpath, delimiter);
Likewise, the above assignment will cause the 1000 bytes allocated to path to be leaked, and defeats the purpose of the 'path=malloc(1000)' above.
path = strtok(NULL, delimiter);
return path;
}
An alternitive coding:
char *getPathOfGetRequest(const char *buf)
{
const char *start = buf;
const char *end;
char *path=NULL;
size_t pathLen;
/* Verify that there is a 'GET ' at the beginning of the string. */
if(strncmp("GET ", start, 4))
{
fprintf(stderr, "Parse error: 'GET ' is missing.\n");
goto CLEANUP;
}
/* Set the start pointer at the first character beyond the 'GET '. */
start += 4;
/* From the start position, set the end pointer to the first white-space character found in the string. */
end=start;
while(*end && !isspace(*end))
++end;
/* Calculate the path length, and allocate sufficient memory for the path plus string termination. */
pathLen = (end - start);
path = malloc(pathLen + 1);
if(NULL == path)
{
fprintf(stderr, "malloc() failed. \n");
goto CLEANUP;
}
/* Copy the path string to the path storage. */
memcpy(path, start, pathLen);
/* Terminate the string. */
path[pathLen] = '\0';
CLEANUP:
/* Return the allocated storage, or NULL in the event of an error, to the caller. */
return(path);
}
And, finally, if 'strtok()' must be used:
char *getPathOfGetRequest(char *buf)
{
char *path = NULL;
if(strtok(buf, " "))
{
path = strtok(NULL, " ");
if(path)
path=strdup(path);
}
return(path);
}
I need my program to take a series of file names (stored in a single "String" and separated by commas) and act on them.
The psuedo code would be:
for each filename in some_string
open filename
operate on contents of filename
close filename
The issue is that I'm stuck separating some_string ("filename1,filename2,...,filenamen") into [filename 1], [filename 2], ... [filename n].
Edit: to clarify, it seems simpler to keep some_string intact and extract each file name as needed, which is what I'm attempting to do.
My code, as it stands, is pretty clunky (and quite disgusting...)
int j = 0;
char *tempS = strdup(filenames);
while (strchr(tempS, ',')) {
char *ptr = strchr(tempS, ',');
*ptr++ = '.';
numFiles++;
}
for (; j < numFiles; j++) {
char *ptr = strchr(tempS, ',');
//don't know where to go from here...
fin = openFile(tempS);
if (fin != NULL) {
//do something
}
fclose(fin);
}
It's not done, obviously. I correctly find the number of files, but I'm a little lost when it comes to figuring out how to separate one at a time from the source string and operate on it.
You can use strtok for this
char *fname = strtok(tempS, ",");
while (fname != NULL) {
/* process filename */
fname = strtok(NULL, ",");
}
strtok delivers the strings separated by comma, one by one.
Usually for splitting string in C, strok() function from C standard library is used.
#include <string.h>
...
char *token;
char *line = "string1,string2,string3";
char *search = ",";
token = strtok(line, search);
token = strtok(NULL, search);
strtok() is not multithreaded-safe. If that matters to you, you should use strtok_r(). For example:
char *savedptr = NULL /* to be passed back to strtok_r in follow-on calls */
char *tempS = strdup( some_string ); /* to keep your original intact */
char *fname = strtok_r(tempS, ",", savedptr);
while (fname != NULL) {
/* process fname ... */
fname = strtok_r(NULL, ",", savedptr); /* pass savedptr back to strtok_r */
}