Thread: argv change

  1. #1
    Registered User
    Join Date
    Apr 2009
    Posts
    6

    argv change

    hi,

    this function:

    Code:
    void iterate_dir(char *dir, struct initrd_file_ptr *headers, char *arg)
    {
            DIR *directory;
            struct dirent *finfo;
    
            directory = opendir (dir);
            if (directory != NULL)
            {
                    unsigned int tmpfcount = file_num;
                    while (finfo = readdir (directory))
                    {
                            if(finfo->d_type == DT_REG){
                                    char tmp[strlen (dir) + strlen (finfo->d_name) + 2];
                                    tmp[0]='\0';
                                    strcat (tmp,dir);
                                    strcat (tmp, "/");
                                    strcat (tmp, finfo->d_name);
                                    make_reg_header (finfo->d_name, tmp, file_num, headers);
                                    file_num++;
                            }
                            else if (finfo->d_type == DT_DIR){
                                    if (strcmp (finfo->d_name, ".") != 0 && strcmp (finfo->d_name, "..") != 0){
                                            char tmp[strlen(dir) + strlen(finfo->d_name) + 2];
                                            tmp[0]='\0';
                                            strcat (tmp,dir);
                                            strcat (tmp, "/");
                                            strcat (tmp, finfo->d_name);
                                            iterate_dir (tmp, headers, arg);
                                    }
                            }
                    }
                    char ldname[strlen (dir)+1];
                    ldname[0] = "\0";
                    get_name_from_path (ldname, dir);
                    make_dir_header (ldname, file_num, file_num - tmpfcount, headers);
                    file_num++;
                    closedir(directory);
    
                    printf("the argument:%i\n", (int)*arg); //outputs: "the argument:100"
            }
            printf("the argument:%i\n", (int)*arg); //outputs: "the argument:0"
    }
    is called from main(). *arg is a pointer to *argv[1]. I noticed that every time this function was called, argv[1] was changed to 0 afterward (from the actual argument, 'd' (100, or 0x64) ). The strange thing is, that the first time "printf("the argument:%i\n", (int)*arg);" is called, arg (or argv[1]) is the value it should be ('d'). the second time it's called, arg is 0. The only difference between the two is that the second printf is outside of that if-block. This also happens, when the function doesn't even have the last argument, the pointer to *argv[1] (I only added the argument to debug).


    dracayr
    Last edited by dracayr; 04-09-2009 at 06:02 PM.

  2. #2
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    What are you talking about? How about showing how you're calling this function. As it is here, none of this has anything to do with command line arguments. It's just a function that takes strings and a pointer to a struct.

    Quzah.
    Hope is the first step on the road to disappointment.

  3. #3
    Registered User
    Join Date
    Apr 2009
    Posts
    6
    This is how the function is called:
    iterate_dir(argv[2], headers, argv[1]);

    headers is a local variable in main()
    I only added that last argument, *arg, to the function to debug after I noticed that every time after I called the function, *argv[1] was changed to 0.

    dracayr

  4. #4
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Why do you even have the third argument to the function? You don't use it for anything.


    Quzah.
    Hope is the first step on the road to disappointment.

  5. #5
    Registered User
    Join Date
    Apr 2009
    Posts
    6
    the third argument is a pointer to *argv[1]. And I do use it in the two printf() functions near the bottom. Those two printf()s have different output (*argv[1] is changed), and I'm trying to find out why.

    EDIT: I'm relatively new to C, so It's quite possible that it's something obvious..

    dracayr

  6. #6
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    So what you're saying is this:
    Code:
    int main( int argc, char **argv )
    {
        printf( "%s", argv[1] ); /* <-- what is printed here now */
        myfunction( argv[2] );
        printf( "%s", argv[1] ); /* <-- is not what is being printed here? */
    
        return 0;
    }
    Is that what you're trying to say? If so, can you provide the simplest example of what's happening? Make a small program like I did, but supply 'myfunction' and test it. If it doesn't do what you think your program currently is doing, then you'll have to start pruning out function calls in your current program to track down why it's being changed.

    Just so you know, the argv arguments are mutable. Which means you are allowed to change them during the course of your program's life. There's nothing preventing you from changing them.


    Quzah.
    Hope is the first step on the road to disappointment.

  7. #7
    Registered User
    Join Date
    Apr 2009
    Posts
    6
    Yes, that's exactly what I'm trying to say.

    Even if the argv arguments are mutable, how can they change from one point to another with only a parenthesis between them, as shown in the last 4 lines of the function?

    This is the whole program (as I said, I'm new to C, so this isn't very good code :P ) What the code is supposed to do is take arguments like this:
    ./program [d|f] file/directory [[d|f] file/directory ..]

    the only use of [d|f] is to determine whether the next argument is a directory or a file. If it's a directory, it should be read recursively. The files should then be mapped to a (self made) initrd filesystem (initrd.img). Everything works, for single files (using ./program f file f file2...) and for directories containning only 1 file (./program d directory_with_one_file/). But once the directory has 2 files, the error I described occurs..

    Code:
    #include <stdio.h>
    #include <sys/types.h>
    #include <dirent.h>
    #include <string.h>
    
    #define FS_FILE		0x01
    #define FS_DIRECTORY	0x02
    
    char *get_name_from_path (char *dest, char *path);
    
    struct initrd_file_ptr
    {
    	unsigned char magic;
    	char name[128];
    	unsigned int offset;
    	unsigned int length;
    	unsigned int type;
    };
    
    struct mydirent // One of these is returned by the readdir call, according to POSIX.
    {
    	  char name[128]; // Filename.
    };
    
    unsigned int file_num;
    FILE *ffstream;
    char *initrdfile = "./initrd.img";
    unsigned int off;
    
    int main(char argc, char **argv)
    {
    	int root_file_num = (argc-1)/2;
    	file_num = 0;
    
    	int i;
    	for (i=1; i<=root_file_num; i++)
    	{
    		if (*argv[i*2-1] == 'f')
    		{
    			file_num++;
    		}
    		else if (*argv[i*2-1] == 'd')
    		{
    			iterate_dir_fcount(argv[i*2]);
    		
    		}else
    			printf("Usage: ./filesystem_generator [d|f] file1 [[d|f] file2 ..]\n");
    	}
    
    	printf("file number: %i\n",file_num);
    
    	off = sizeof(int) + sizeof(struct initrd_file_ptr)*file_num;
    	file_num = 0;
    	struct initrd_file_ptr headers[file_num];
    
            for (i=1; i<=root_file_num; i++)
            {
                    if (*argv[i*2-1] == 'f')
                    {
    			char lfname[strlen (argv[i*2])];
    			lfname[0] = '\0';
    			get_name_from_path (lfname, argv[i*2]);
    			make_reg_header (lfname, argv[i*2], file_num, headers);
                            file_num++;
                    }
                    else if (*argv[i*2-1] == 'd')
                    {
    			
    			printf("argv_value:%i\n", (int)*argv[i*2-1]);//outputs 100
                            iterate_dir(argv[i*2], headers, argv[i*2-1]);
    			printf("argv_value:%i\n", (int)*argv[i*2-1]);//outputs 0
    
                    }else
                            printf("2.Usage: ./filesystem_generator [d|f] file1 [[d|f] file2 ..]\n");
            }
    	ffstream = fopen (initrdfile, "w");
    	fwrite (&file_num, sizeof (unsigned int), 1, ffstream);
    	fwrite (headers, sizeof (struct initrd_file_ptr), file_num, ffstream);
    	file_num = 0;
    	i = 1;
    
    
            for (i=1; i<=root_file_num; i++)
            {
                    if (*argv[i*2-1] == 'f')
                    {
    			write_reg_data (argv[i*2], file_num, headers);
                            file_num++;
                    }
                    else if (*argv[i*2-1] == 'd')
                    {
    
    			iterate_dir_write(argv[i*2], headers);
    
                    }else
                            printf("3.Usage: ./filesystem_generator [d|f] file1 [[d|f] file2 ..]:%i\n", (int) *argv[i*2-1]);
            }
    	fclose(ffstream);
    
    	return 0;
    
    
    }
    
    int iterate_dir_fcount(char *dir)
    {
    	DIR *directory;
    	struct dirent *finfo;
    
    	directory = opendir (dir);
    	if (directory != NULL)
    	{
    		file_num++;
    		while (finfo = readdir (directory))
    		{
    			if(finfo->d_type == DT_REG){
    				file_num++;
    				printf("%i: reg file: %s\n", file_num, finfo->d_name);
    			}
    			else if (finfo->d_type == DT_DIR){
    				if (strcmp (finfo->d_name, ".") != 0 && strcmp (finfo->d_name, "..") != 0){
    					char tmp[strlen(dir)+strlen(finfo->d_name)+1];
    					tmp[0]='\0';
    					strcat (tmp,dir);
    					strcat (tmp, "/");
    					strcat (tmp, finfo->d_name);
    					printf("%i: dir: %s\n", file_num+1, tmp);
    					iterate_dir_fcount (tmp);
    				}
    			}
    			else
    				printf("%s: invalid file type\n", finfo->d_name);
    		}
    		closedir (directory);
    	}else
    		printf("failed to open directory: %s\n", dir);
    
    	return 0;
    }
    
    void iterate_dir(char *dir, struct initrd_file_ptr *headers, char *arg)
    {
    	DIR *directory;
    	struct dirent *finfo;
    
    	directory = opendir (dir);
    	if (directory != NULL)
    	{
    		unsigned int tmpfcount = file_num;
    		while (finfo = readdir (directory))
    		{
    			if(finfo->d_type == DT_REG){
    				char tmp[strlen (dir) + strlen (finfo->d_name) + 2];
    				tmp[0]='\0';
    				strcat (tmp,dir);
    				strcat (tmp, "/");
    				strcat (tmp, finfo->d_name);
    				make_reg_header (finfo->d_name, tmp, file_num, headers);
    				file_num++;
    			}
    			else if (finfo->d_type == DT_DIR){
    				if (strcmp (finfo->d_name, ".") != 0 && strcmp (finfo->d_name, "..") != 0){
    					char tmp[strlen(dir) + strlen(finfo->d_name) + 2];
    					tmp[0]='\0';
    					strcat (tmp,dir);
    					strcat (tmp, "/");
    					strcat (tmp, finfo->d_name);
    					iterate_dir (tmp, headers, arg);
    				}
    			}
    		}
    		char ldname[strlen (dir)+1];
    		ldname[0] = "\0";
    		get_name_from_path (ldname, dir);
    		make_dir_header (ldname, file_num, file_num - tmpfcount, headers);
    		file_num++;
    		closedir(directory);
    
    		printf("the argument:%i\n", (int)*arg); //outputs 100
    	}
    
    	
    	printf("the argument:%i\n", (int)*arg); //outputs 0
    }
    
    int iterate_dir_write(char *dir, struct initrd_file_ptr *headers)
    {
    	DIR *directory;
    	struct dirent *finfo;
    
    	directory = opendir (dir);
    	if (directory != NULL)
    	{
    		unsigned int tmpfcount = file_num;
    		while (finfo = readdir (directory))
    		{
    			if(finfo->d_type == DT_REG){
    				char tmp[strlen (dir) + strlen (finfo->d_name) + 1];
    				tmp[0]='\0';
    				strcat (tmp,dir);
    				strcat (tmp, "/");
    				strcat (tmp, finfo->d_name);
    				write_reg_data (tmp, file_num, headers);
    				file_num++;
    			}
    			else if (finfo->d_type == DT_DIR){
    				if (strcmp (finfo->d_name, ".") != 0 && strcmp (finfo->d_name, "..") != 0){
    					char tmp[strlen(dir) + strlen(finfo->d_name) + 1];
    					tmp[0]='\0';
    					strcat (tmp,dir);
    					strcat (tmp, "/");
    					strcat (tmp, finfo->d_name);
    					iterate_dir_write (tmp, headers);
    				}
    			}
    		}
    
    		write_dir_data (file_num-tmpfcount, file_num, headers);
    		file_num++;
    		closedir(directory);
    	}
    
    	return 0;
    }
    
    int make_reg_header (char *fname, char *fpath, unsigned int n, struct initrd_file_ptr *headers)
    {
    	strcpy (headers[n].name, fname);
    	headers[n].offset = off;
    
    	FILE *stream = fopen (fpath, "r");
    
    	if (stream != 0){
    		fseek (stream, 0, SEEK_END);
    		headers[n].length = ftell(stream);
    		off += headers[n].length;
    		headers[n].magic = 0xBF;
    		headers[n].type = FS_FILE;
    		fclose(stream);
    	}else
    		printf("Error -> hole in headers...\n");
    	return 0;
    }
    
    int make_dir_header (char *fname, unsigned int n, unsigned int nfiles, struct initrd_file_ptr *headers)
    {
    	strcpy (headers[n].name, fname);
    	headers[n].offset = off;
    	headers[n].length = nfiles;
    	off += nfiles * sizeof(struct mydirent);
    	headers[n].magic = 0xBF;
    	headers[n].type = FS_DIRECTORY;
    	return 0;
    }
    
    int write_reg_data (char *fpath, int n, struct initrd_file_ptr *headers)
    {    
    	FILE *stream = fopen(fpath, "r");
    	unsigned char *buf = (unsigned char *)malloc(headers[n].length);
    	fread(buf, 1, headers[n].length, stream);
    	fwrite(buf, 1, headers[n].length, ffstream);
    	fclose(stream);
    	free(buf);
    	return 0;
    }
    
    int write_dir_data (unsigned int files_count, int n, struct initrd_file_ptr *headers)
    {
    	struct mydirent dir_listing[files_count];
    	int i;
    	for (i = 0; i<files_count; i++)
    	{
    		strcpy (dir_listing[i].name, headers[n-(i+1)].name);
    	}
    	fwrite(dir_listing, sizeof(struct mydirent), files_count, ffstream);
    
    	return 0;
    }
    	
    
    char *get_name_from_path (char *dest, char *path)
    {
    	int i;
    	int last_index = -1;
    	for (i = 0;; i++)
    	{
    		if (path[i] == '/')
    			last_index = i;
    		if (path[i] == '\0')
    			break;
    	}
    
    
    	strcpy (dest, &path[last_index+1]);
    	return dest; 
    }
    dracayr
    Last edited by dracayr; 04-09-2009 at 06:37 PM.

  8. #8
    Registered User
    Join Date
    Apr 2009
    Posts
    6
    making a local copy of **argv and using that copy would be a workaround I guess, but I'm not sure how to copy **argv

    dracayr

  9. #9
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    I believe there are TWO problems in this section:
    Code:
    		char ldname[strlen (dir)+1];
    		ldname[0] = "\0";
    Let's start with the simple one: The second line should use single-quotes if you want it to be an empty string. Right now, the first character is being set to the address of an empty string, which doesn't fit in a single byte...

    The first line is wrong in the fact that it's only reserving enough space for the directory name. But there is no guarantee that there isn't a filename that is (much) longer than the directory passed into the function.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  10. #10
    Registered User
    Join Date
    Apr 2009
    Posts
    6
    Thank you! the "\0" was the problem. strlen (dir) is correct as a length of the string because in this case, dir is actually the directory name plus the file name. All that get_name_from_path does is search for the last '/' in the string and copy everything behind it to dest.

    Now that works, but I get a segmentation fault afterwards.. I'll post again if I can't resolve that myself

    dracayr
    Last edited by dracayr; 04-10-2009 at 02:55 AM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. c++builder6 change form names problem
    By Leite33 in forum C++ Programming
    Replies: 2
    Last Post: 06-09-2008, 08:20 AM
  2. how to change static char* and not lose mem ?
    By jabka in forum C Programming
    Replies: 15
    Last Post: 09-07-2007, 05:33 PM
  3. Change Value in an array
    By beginner999 in forum C Programming
    Replies: 3
    Last Post: 01-18-2003, 07:16 AM
  4. Replies: 2
    Last Post: 11-08-2002, 03:22 AM
  5. Replies: 2
    Last Post: 09-04-2001, 02:12 PM