Thread: Scan filename and make a list

  1. #1
    Registered User
    Join Date
    Nov 2008
    Posts
    3

    Question Scan filename and make a list

    Hi everyone. I'm a newbie in C program.
    My problem is:
    I need to search filenames with a part of them, and made a list of them.
    For example, I have these 5 files:
    20081117_ABC1E_1_Prod
    20081118_DEF5G_3_Prod
    20081117_ABC1E_12_Prod
    20081117_ABC1E_21_Prod
    20081117_BCDE2F_1_Prod
    I want to search filenames with "ABC1E" (hier there are 3) and display a list with them.
    How to use these 2 functions?
    First of all, is it possible to search and analyse a filename on the HDD? (in C:\Exemple\ in example)

    I've search on Google and forums since yesterday afternoon.
    Please someone can help me?

  2. #2
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    For working with directory contents, use readdir().

    How you parse the filenames depends on what you want to do -- if it's exactly as you describe, you could loop through each name like this:
    Code:
    for (i=0;i<strlen(name)-4;i++) {
                            if ((name[i]=='A') && (name[i+1]=='B') && 
                                    (name[i+2]=='C') && (name[i+3]=='1') && (name[i+4]=='E'))
                                    {//do stuff with name containing ABC1E}
                    }
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  3. #3
    Why bbebfe is not bbebfe? bbebfe's Avatar
    Join Date
    Nov 2008
    Location
    Earth
    Posts
    27
    For string comparison, try strstr or strspn.
    Do you know why bbebfe is NOT bbebfe?

  4. #4
    Why bbebfe is not bbebfe? bbebfe's Avatar
    Join Date
    Nov 2008
    Location
    Earth
    Posts
    27
    sorry, duplicated post!
    Last edited by bbebfe; 11-21-2008 at 08:22 AM.
    Do you know why bbebfe is NOT bbebfe?

  5. #5
    Why bbebfe is not bbebfe? bbebfe's Avatar
    Join Date
    Nov 2008
    Location
    Earth
    Posts
    27
    I have just written an utility routine for traversing path recently. I think it may be useful to you.

    I have compiled and run it on Linux and Windows both, but if you want to use it on Windows, you have to download an extra dirent.h file from http://www.softagalleria.net/dirent.php since there is no dirent.h on Windows.

    There is a slight main function in my code, it will demostrate how this code works.

    I think there is no memory leak, it's apprecated for any advices, not only for memory leak.

    Don't forget to change the include file path.

    header
    Code:
    /**
     * ztraversal.h : This file defines the structure used by
     *		traversal engine.
     */
    #if _MSC_VER > 1000
    #pragma once
    #endif
    
    #ifndef _INC_ZTRAVERSAL
    #define _INC_ZTRAVERSAL
    
    
    #include <stdio.h>
    #include <sys/stat.h>
    #ifdef WIN32
    #include "dirent.h"
    
    #define	__S_ISTYPE(mode, mask)	(((mode) & S_IFMT) == (mask))
    #define	S_ISDIR(mode)		__S_ISTYPE((mode), S_IFDIR)
    #else /* WIN32 */
    #include <dirent.h>
    #endif /* WIN32 */
    
    
    #define PATH_BUFF_SIZE FILENAME_MAX * 2
    
    #define TRAVERSAL_SUB		0x01
    #define TRAVERSAL_NO_SUB	0x02
    #define TRAVERSAL_LOOP		0x04
    
    
    
    
    struct Traversal_tree_node {
    	struct Traversal_tree_node* parent;
    	char path_buff[PATH_BUFF_SIZE];
    	// we will clean the path buffer tail by using clean_up_ptr, the
    	// length is clean_up_len
    	char* clean_up_ptr;
    	int clean_up_len;
    	DIR* dir;
    };
    
    
    
    static struct Traversal_tree_node* malloc_node(struct Traversal_tree_node* parent, const char* filename);
    static void free_node(struct Traversal_tree_node* pnode);
    int init_traversal_engine(const char* passname, int mode);
    const char* get_next_file();
    void deinit_traversal_engine();
    
    #endif /* _INC_ZTRAVERSAL */
    C file
    Code:
    /**
     * *********** Traversal engine ************
     * This small routine is for traversing path.
     * @usage
     *		init_traversal_engine(filename, traversal_mode);
     *		a loop (get_next_file());
     *		deinit_traversal_engine();
     * @constraint The size of the buffer internal to store the path and filename is
     *		restricted to the FILENAME_MAX * 2
     */
    
    /**
     * The tree node the traversal engine currently traversed.
     * @constraint Be sure to use malloc_node to allocate new node, and
     *		use free_node to recovery the memory.
     */
    #include <stdarg.h>
    
    #ifdef _ZCOMMON_HEAD
    #include "../include/zcommon.h"
    #endif /* _ZCOMMON_HEAD */
    
    #include "../include/ztraversal.h"
    
    
    #ifndef _ZCOMMON_HEAD
    #define Z_ERROR -1
    #define Z_SUCCESS 0
    #endif /* _ZCOMMON_HEAD */
    
    
    static struct Traversal_tree_node* l_path_current = NULL;
    static struct stat l_file_stat;
    static int l_mode = TRAVERSAL_NO_SUB;
    
    
    static int _check_mode(int mode);
    
    #ifndef _ZCOMMON_HEAD
    int log_error(int errcode, const char* error_msg, ...) {
    	va_list args;
    	va_start(args, error_msg);
    	vfprintf(stderr, error_msg, args);
    	va_end(args);
    	return Z_SUCCESS;
    }
    #endif /* _ZCOMMON_HEAD */
    
    
    
    
    
    
    
    /**
     * Initializing the traversal engine, allocating memory and opening the top dir.
     * @constraint filename must be an available path.
     * @para filename a directory name with absolute path
     * @para mode traversal mode 
     *			TRAVERSAL_NO_SUB: engine will ignore the sub directory.
     *			TRAVERSAL_SUB	: engine will go into the sub directory.
     * @return 0 if succeed, otherwise return TE_ERR
     */
    int init_traversal_engine(const char* pathname, int mode) {
    	l_mode = mode;
    	if (_check_mode(mode) == Z_ERROR) {
    		return Z_ERROR;
    	}
    	l_path_current = malloc_node(NULL, pathname);
    	if (l_path_current == NULL) {
    		return Z_ERROR;
    	}
    	return Z_SUCCESS;
    }
    
    static int _check_mode(int mode) {
    	if ((mode & TRAVERSAL_SUB) && (mode & TRAVERSAL_NO_SUB)) {
    		log_error(0x100, "TRAVERSAL_SUB and TRAVERSAL_NO_SUB cannot be set at the same time");
    		return Z_ERROR;
    	}
    	if ((mode & TRAVERSAL_NO_SUB) || (mode& TRAVERSAL_SUB) || (mode & TRAVERSAL_LOOP)) {
    		return Z_SUCCESS;
    	}
    	else {
    		log_error(0x100, "At least one available mode must be set");
    		return Z_ERROR;
    	}
    }
    
    /**
     * Create a new traversal tree node with the specified path filename.
     * @constraint filename must be an available path.
     * @para parent parent node of the new created node, if parent is NULL,
     *		the new one must be the top node.
     * @para filename a directory name with absolute path.
     * @return NULL if there are errors happened, otherwise return the pointer
     *		to the new node.
     */
    static struct Traversal_tree_node* malloc_node(struct Traversal_tree_node* parent, const char* filename) {
    	int filename_len = (int)strlen(filename);
    	struct Traversal_tree_node* node = NULL;
    	if (filename_len + 2/* file separator / and terminal null */ > PATH_BUFF_SIZE) {
    		log_error(0x002, "filename too long");
    		return NULL;
    	}
    	else {
    		node = (struct Traversal_tree_node*)malloc(sizeof(struct Traversal_tree_node));
    		node->dir = NULL;
    		node->dir = opendir(filename);
    		if (node->dir == NULL) {
    			log_error(1111, "Cannot open directory: &#37;s\n", filename);
    			free_node(node);
    			node = NULL;
    			return NULL;
    		}
    		else {
    			memset(node->path_buff, 0, PATH_BUFF_SIZE);
    
    			node->parent = parent;
    			strcpy(node->path_buff, filename);
    #ifdef WIN32
    			strcat(node->path_buff, "\\");
    #endif /* WIN32 */
    			filename_len = (int)strlen(node->path_buff);
    			node->clean_up_ptr = node->path_buff + filename_len;
    			node->clean_up_len = PATH_BUFF_SIZE - filename_len;
    			return node;
    		}
    
    	}
    	
    }
    
    /**
     * Get the next file's name with absolute path in current traversal tree.
     * @return NULL if there are no files in traversal path.
     */
    const char* get_next_file() {
    	struct dirent* process_entry;
    	if (l_path_current == NULL || l_path_current->dir == NULL) {
    		log_error(0x001, "Traversal engine has not been initialized\n");
    		return NULL;
    	}
    	else {
    		memset(l_path_current->clean_up_ptr, 0, l_path_current->clean_up_len);
    	}
    
    	if ((process_entry = readdir(l_path_current->dir)) != NULL) {
    		if (strcmp(process_entry->d_name, ".") == 0 || 
    			strcmp(process_entry->d_name, "..") == 0) {
    			return get_next_file();
    		}
    		strcat(l_path_current->path_buff, process_entry->d_name);
    		stat(l_path_current->path_buff, &l_file_stat);
    		//sub directory
    		if (S_ISDIR(l_file_stat.st_mode)) {
    			
    			if (l_mode & TRAVERSAL_SUB){
    				l_path_current = malloc_node(l_path_current, l_path_current->path_buff);
    				if (l_path_current == NULL) {
    					return NULL;
    				}
    				else {
    					#ifdef _DEBUG
    					printf("directory : %s\n", l_path_current->path_buff);
    					#endif /* _DEBUG */
    				}
    
    				return get_next_file();
    			}
    			// ignore sub directory
    			else {
    				return get_next_file();
    			}
    			
    		}
    		else { //file
    			#ifdef _DEBUG
    			printf("file : %s\n", l_path_current->path_buff);
    			#endif /* _DEBUG */
    			return l_path_current->path_buff;
    		}
    	}
    	// no entry in this directory, let's try going upstairs.
    	else {
    		struct Traversal_tree_node* node = l_path_current->parent;
    		
    		char buff[PATH_BUFF_SIZE];
    		strcpy(buff, l_path_current->path_buff);
    
    		free_node(l_path_current);
    		l_path_current = node;
    		if (l_path_current == NULL) {
    			//go back if loop flag has been set
    			if (l_mode & TRAVERSAL_LOOP) {
    				deinit_traversal_engine();
    				init_traversal_engine(buff, l_mode);
    			}
    			return NULL;
    		}
    		else {
    			return get_next_file();
    		}
    	}
    }
    
    /**
     * Recovery the memory the traversal_engine allocated, and do some
     * cleanups.
     */
    void deinit_traversal_engine() {
    	struct Traversal_tree_node* node = NULL;
    	while (l_path_current != NULL) {
    		node = l_path_current->parent;
    		free_node(l_path_current);
    		l_path_current = node;
    	}
    }
    
    /**
     * Recovery the memory of traversal tree node allocated by malloc_node.
     * para pnode a pointer to a node.
     */
    static void free_node(struct Traversal_tree_node* pnode) {
    	if (pnode != NULL) {
    		if (pnode->dir != NULL) {
    			closedir(pnode->dir);
    			pnode->dir = NULL;
    		}
    		free(pnode);
    	}
    }
    
    int main(int argc, char* argv[]) {
    	const char* filename = NULL;
    	int rc = 0;
    	if (argc != 2) {
    		printf("need path name!");
    	}
    	else {
    		rc = init_traversal_engine(argv[1], TRAVERSAL_NO_SUB);
    		if (rc == Z_SUCCESS) {
    			while ((filename = get_next_file()) != NULL) {
    				printf("file: %s\n", filename);
    			}
    			deinit_traversal_engine();	
    		}
    	}
    	return 0;
    }
    Last edited by bbebfe; 11-21-2008 at 09:27 AM.
    Do you know why bbebfe is NOT bbebfe?

  6. #6
    Registered User
    Join Date
    Nov 2008
    Posts
    3
    thanks everyone, i'll try all your solutions, and i'll tell you if it runs! ^^

  7. #7
    Registered User
    Join Date
    Nov 2008
    Posts
    3
    I'm very sorry Bbebfe, but i've tried to copy your code into my programm, and i must erase a lot of parameters, and i'm a newbie, i don't really understand what you did, and i want to "understand" your solutions.

    MK27 your solution can very help, but i need other help for this moment... ^^"

    So i'll tell it by part.

    First of all, i want to make a list of the files that are in the folder (i'll select them later).

    I've found this code.
    Code:
    #include "gbs.h"
    
    char * extract_filename(char *str){
    	
    	int ch = '\\', result, len;
    	char  *pdest, line[250], *inpfile = {NULL};
    
    	// Search backwards for last backslash in filepath /
    	inpfile = (char *)malloc(200*sizeof(char));
    	pdest = strrchr(str, ch);	result = pdest - str + 1;
    	
    	// if backslash not found in filepath
    	if(pdest == NULL ){
    		printf( "Result:\t&#37;c not found\n" );
    	}
    	
    	// extract filename from file path /
    	len = strlen(str) - result - 1;
    	strncpy(inpfile, &line[result], len);
    	inpfile[len] = NULL;
    	return inpfile;
    }
    I call this application with "str" = my file path (in german...) like this: "D:\Saves\Log_Data\Product" ,i write it as you can see here.

    but i've always the result "Result: \ not found"

    Where is my problem? i've tried to write the path with "\\" but no result, it is worse than this... (no result at all)
    Last edited by Schouf; 11-21-2008 at 09:45 AM. Reason: answer to bbebfe for his help but his great gesture for me

  8. #8
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    The string "D:\Saves\Log_Data\Product" most likely does not contain any backslash characters at all, it is true. You do need "D:\\Saves\\Log_Data\\Product" to get the correct path.

    The function you have posted does not provide any output upon success, it is true; it just returns the filename (or last directory on the list) to the calling function. Well, minus the last two letters, since len is two shorter than it should be. EDIT: Make that one shorter than it should be.
    Last edited by tabstop; 11-21-2008 at 09:50 AM.

  9. #9
    Registered User
    Join Date
    Dec 2007
    Posts
    2,675
    It seems this little snippet would do the job?
    Code:
    char * extract_filename(const char *str){
        const char *fileName = strrchr(str, '\\');
        if (fileName) {
            return strdup(fileName + 1);
        }
        return NULL;
    }

  10. #10
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by Schouf View Post
    Code:
    	int ch = '\\', result, len;
    Is this a typo? An int can only hold one character value.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  11. #11
    Resu Deretsiger Nightowl's Avatar
    Join Date
    Nov 2008
    Location
    /dev/null
    Posts
    186
    Quote Originally Posted by MK27 View Post
    Is this a typo? An int can only hold one character value.
    . . . '\\' is one character . . . it's a backslash.

  12. #12
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  13. #13
    Registered User
    Join Date
    Oct 2008
    Location
    TX
    Posts
    2,059
    one way could be to break-up the filename with strtok() followed by doing a strcmp() to check if the 2nd token matches the string ABC1E.

  14. #14
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    strstr() would work too, just by itself. Assuming you don't care where in the filename the string you're looking for occurs.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  15. #15
    Registered User
    Join Date
    Oct 2008
    Location
    TX
    Posts
    2,059
    Ah! yes strstr() is the better way to go about this.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. linked list problems (null values)
    By scwizzo in forum C++ Programming
    Replies: 2
    Last Post: 12-03-2008, 06:04 PM
  2. WIP Borland C Doubly linked list
    By BCWarrior in forum C Programming
    Replies: 41
    Last Post: 09-25-2007, 12:06 AM
  3. Dikumud
    By maxorator in forum C++ Programming
    Replies: 1
    Last Post: 10-01-2005, 06:39 AM
  4. C programming-Linked list problem
    By male4329 in forum C Programming
    Replies: 18
    Last Post: 06-02-2005, 02:05 AM
  5. BigInt Linked List Long Division
    By abyssknight in forum C Programming
    Replies: 5
    Last Post: 04-01-2004, 07:02 PM

Tags for this Thread