Keeping directory search results of ftw function - c

what I have to do is recursively get ".mp3" archives from a determined pre-specified directory and its subdirectories. I did not have a problem getting the mp3's and printing them on console. I am using the ftw function specified in http://www.gnu.org/software/libc/manual/html_node/Working-with-Directory-Trees.html#Working-with-Directory-Trees, its call-back function would look like this:
/* Call-back of ftw function*/
int filter_mp3s(const char *dir_name, const struct stat *status, int typeflag){
if (typeflag == FTW_D){
struct dirent **mp3list;
int num_archives;
int counter;
num_archives = scandir (dir_name, &mp3list, select_mp3_ext, alphasort);
/* print mp3 names */
if (num_archives > 0) for (counter = 0; counter <= num_archives - 1; counter++) printf("%s\n", mp3list[counter]->d_name);
}
return 0;
}
What I really want to do is put the names of the files into a GTK combo-box widget. Problem is, that function returns an int type and the function is not flexible with its parameters so I could "save" in something the entries. In other words, mp3's are found but I have no idea how I could keep the results in order to load them in the combo-box in other function. I do not want to use global variables...
I'm new into this, thanks in advance for your help.

If the callback doesn't have a customer argument (usually a void*) which appears to be the case, you will have to put found data into a global variable, which is unfortunate.
If that's a problem (i.e. you are in a multithreaded environment) you will have to implement your own version of recursive directory traversal using opendir interface. It's not difficult.

Related

Unique String generator

I want to make a program (network server-client).
One of the specification for this program is next:
The server will receive the sent packages and save it into a file, with a unique name (generated by the server at the moment the transfer starts.
Ex __tf_"unique_random_string".txt
I made a function that returns a pointer to a "unique" string created.
The problem is: If i stop the server and then start it again it will generate the same names.
Ex:this file names were generated and then i stopped the server.
__ft_apqfwk.txt
__ft_arzowk.txt
__ft_cdyggx.txt
I start it again and i try to generate 3 file names. Them will be the same.
Sorry for my english. I'm still learning it.
My function to generate this "unique string" is:
char *create_random_name(void)
{
const char charset[] = "abcdefghijklmnopqrstuvwxyz";
char *file_name;
int i=0;
int key;
if((file_name = malloc(16 * sizeof ( char )) ) == NULL)
{
printf("Failed to alloc memory space\n");
return NULL;
}
strcpy(file_name,"__ft_");
for(i=5 ; i<11 ; i++)
{
key = rand() % (int)(sizeof(charset)-1);
file_name[i]=charset[key];
}
strcat(file_name,".txt");
file_name[15] = '\0';
return file_name;
}
One option is saving to a file the names that have been used, and using them as a checklist. You also want to seed rand with something like srand(time(NULL)).
another is ignoring the randomisation, and just going in order, e.g. aaa, aab aac...aba ,abb etc. Again, save where your cycle is up to on a file.
Your question seems a little bit unclear but if you want to generate a unique string there are a couple of things you can consider:
Get System timestamp ( yyyy-MM-dd-HH-mm-ss-fff-tt)
Use Random function to generate a random number
Combine this with your function and I am sure you will get a unique string.
Hope it helps !
If it's available, you could avoid manually generating random names that might collide and let the system do it for you (and handle collision resolution by creating a new name) by using mkstemps. This is also safer because it opens the file for you, removing the risk of a random name being generated, verified to be unique, then trying to open it and discovering another thread/process raced in and created it.
char name[] = "/path/to/put/files/in/__ft_XXXXXX.txt";
int fd = mkstemps(name, strlen(".txt"));
if (fd == -1) { ... handle error ... }
After mkstemps succeeds, name will hold the path to the file (it's mutated in place, replacing the XXXXXX string), and fd will be an open file descriptor to that newly created file; if you need a FILE*, use fdopen to convert to a stdio type.
Before calling rand(),--- once and only once---, call srand(time()) to initialize the random number generator.
Before settling on any specific file name, call stat() to assure that file name does not already exist.

Reading and selecting files using dirent.h in C

I'm new into programming microcontrollers, and I have a problem.
I'm trying to make a device that plays music from USB. I can read from USB, but I have no idea how to choose a certain file. I'm using dirent.
My code so far:
while (true) {
USBHostMSD msd("usb");
//setup PWM hardware for a Class D style audio output
PWMout.period(1.0/400000.0);
// wait until connected to a USB device
while(!msd.connect()) {
Thread::wait(500);
}
FILE *wave_file;
lcd.cls();
lcd.locate(0,3);
DIR *dir;
struct dirent *ent;
int i=0;
int stevilo_datotek =0;
dir = opendir ("/usb/");
if (dir != NULL)
{
while ((ent = readdir (dir)) != NULL)
{
lcd.printf ("%s\n", ent->d_name[0]);
}
}
Now this code displays what's on USB. How can I navigate through files on USB using the buttons on the device? I'd like to know if there's a way to assign certain song a certain number so I can navigate. I've studied dirent.h file for so long, and I can't find where dirent saves the file order (if it does).
You may be confusing the purpose of dirent.h In short it may be difficult to see the forest for the trees.
You can read the information (ent->d_name, note that ent->d_name is a pointer to an array of chars, often called a 'string') into a data structure (like an array or a list), then use that struct with code that detects button presses to move an index into the array information either up or down (to a greater or lesser index, make sure to check that your index doesn't go outside the range or your structure). Or you can create code where your while loop waits on a button press and only reads the file name then (using seekdir to go backwards).
UPDATE (to response to comment):
Keep in mind that filesystems are tree structures like so:
/ (root) +--- dir1 ----------------------------+- dir1.1
---- dir2 (empty) -- file1.1
---- dir3 ---- dir3.1 +--- file3.1
---- file1 ---- file3.2
---- file2
You have to decide how to handle that, are you going to only support one directory (make them put all their music files in one place), allow them to navigate directories, or look through all directories selecting only files you know how to play?
There is no inherit order to the files (or sub-directories) and in some systems files can be added or deleted at any time.
Here is a very simple-minded example of one way to keep the list of directory entries:
char *names[400]; // make space for 400 names
int ix;
ix = 0;
if (dir != NULL)
{
while ((ent = readdir (dir)) != NULL)
{
lcd.printf ("%s\n", ent->d_name[0]);
// allocate memory to store the name
names[ix] = (char*) malloc(strlen(ent->d_name)); // strlen from string.h
// malloc from stdlib.h
// copy the name from the directory entry
strcpy(names[ix], ent->d_name); // strcpy from string.h
ix++;
if (ix >= 400)
{
// do something because your array isn't big enough
}
}
}
Now you have your names in the array 'names' and can address them by index. The value 'ix-1' is your last name, 0 is your first name. Your button presses can increment/decrement the index into your name array which identifies the name you want. Keep in mind that some of those names might be directory names rather than file names.
Admittedly this is simply-minded, you might want to allocation the array rather than use a fixed value (in fact you have to if you want to pass the 'names' array to a calling function), there are "secure" versions of strcpy (meant to help prevent memory overflow corruption), etc. but it should give you an idea about how you can keep the names in memory.

Function overriding in C

I have a requirement in C similar to function overriding. I have 2 devices with different device IDs. I have a process which just calls device_create(device_id). The process doesn't know which device_create to call. It is upto driver of the device to execute device_create if the device_id matches to driver's device Id. Is there any way to do it in C?
If you use different shared objects (or dlls) to implement the function you could handle this programatically on your own. You could create a plugin like structure and use something like the Command pattern.
Not exactly simple, but can help with your problem.
Cheers.
OK. Understand I'm still of the mark, but leave this post for now.
You do not know the ID when process starts. When HW is attached you read the ID and want to call correct function based on the ID but without using the ID directly?
The closest I can think of as a simple solution is by using an array of function pointers:
void (*funs[3])(void) = {
&device_create100,
&device_create200,
NULL
};
But then only if you can normalize the ID to match index of the array. Say all ID's are in the range 1000-1032 that would be an 32 long function pointer array where you can use ID - 1000.
As this is rather unlikely you could resort to a sorted list, binary tree, hash table or the like on which you do a lookup.
struct node {
int (*fun)(void);
int id;
struct *node left;
struct *node right;
}
This is of course then assuming you have a rather big list of possible ID's and a switch is out of the question.
Old post.
What about function pointers:
int (*device_create)(int);
int device_create_init(int id)
{
switch (id) {
case 0x0a:
device_create = &device_create_100;
break;
case 0x0b:
device_create = &device_create_200;
break;
}
/* After first call, the now set device_create_xxx function will be
invoked on device_create() */
return device_create(id);
}
int main(void)
{
device_create = &device_create_init;
/* Loop */
return 0;
}

query about few threading terms

I am understanding and implementing the concept of threading in my application. Since now things are going good. But I have few questions still unanswered and they are making me slow now. I would appreciate if anyone replies to even any of them
In Createthread(), can we only take 1 argument? as I have seen in MSDN website and all other examples that I have seen I saw only 1 argument, LPVOID.
The other thing is , what does the return value DWORD WINAPI means as a return value? Can we have only DWORD , int or any other return type. I suppose it has something to do with HANDLE (may be)
I want to use the array of the thread, hence I learn the array to functions, and (as I have understood) threads are itself just a function called by CreateThread() routine, hence I tried to implement that concept there but could not because of the return type DWORD WINAPI was not allowing me to do so?
I have one single thread for saving files, now I want its array so that I can save multiple files at the same time (not exaclty the same starting time, but sort of parallel file saving). How can I do that?
Thanks
Shan
Indeed, you can only take one argument, of type void * (LPVOID).
However, since it can point to anything, it can point to a struct
or object (usually allocated on the heap for lifetime reasons).
WINAPI is not part of the return value, it's the function's calling
convention. The function must return a DWORD or anything that fit
in it. It must NOT return a pointer, because a pointer can't fit a
DWORD in Win64.
I don't understand, please elaborate what you're
trying to do.
Usually for this you need a single thread function,
passed several times to CreateThread() with a different argument
each time. Don't forget to keep the thread handles (which you'll
likely save in an array) until you stop needing them and close them
with CloseHandle().
for the point number three I guess I understood and will try differently. I was using
DWORD WINAPI save_uwpi_file0( LPVOID )
{
while(1)
{
if(release == 1 && flag_oper1 == 1)
{
int w_cnt = 0; FILE *opfile;
char fname[30] = "txt_file0.txt";
//opening file for write
opfile = fopen(fname , "w");
printf("assigning memory for file 1 \n");
ssint *Lmem = (ssint *)malloc( sizeof(ssint)*size_of_memory);
memcpy(Lmem, pInDMA, sizeof(ssint)*size_of_memory);
release = 0;
printf("relseaing for second file saving\n");
for( int nbr = 0; nbr < size_of_memory; nbr++){
fprintf(opfile , "%hi\n", Lmem[nbr] );
}
printf("aligned free 1\n");
free(Lmem);
fclose(opfile);
printf("File saved 1\n\n");
return 1;
} //if statement ends
}
}
and I was using following to make the pointer to (thread) function
DWORD WINAPI (* save_uwpi_file0)(LPVOID);
I guess I should try something like
DWORD (* save_uwpi_file0)(LPVOID);
I will do it and post the result here

How avoid using global variable when using nftw

I want to use nftw to traverse a directory structure in C.
However, given what I want to do, I don't see a way around using a global variable.
The textbook examples of using (n)ftw all involve doing something like printing out a filename. I want, instead, to take the pathname and file checksum and place those in a data structure. But I don't see a good way to do that, given the limits on what can be passed to nftw.
The solution I'm using involves a global variable. The function called by nftw can then access that variable and add the required data.
Is there any reasonable way to do this without using a global variable?
Here's the exchange in previous post on stackoverflow in which someone suggested I post this as a follow-up.
Using ftw can be really, really bad. Internally it will save the the function pointer that you use, if another thread then does something else it will overwrite the function pointer.
Horror scenario:
thread 1: count billions of files
thread 2: delete some files
thread 1: ---oops, it is now deleting billions of
files instead of counting them.
In short. You are better off using fts_open.
If you still want to use nftw then my suggestion is to put the "global" type in a namespace and mark it as "thread_local". You should be able to adjust this to your needs.
/* in some cpp file */
namespace {
thread_local size_t gTotalBytes{0}; // thread local makes this thread safe
int GetSize(const char* path, const struct stat* statPtr, int currentFlag, struct FTW* internalFtwUsage) {
gTotalBytes+= statPtr->st_size;
return 0; //ntfw continues
}
} // namespace
size_t RecursiveFolderDiskUsed(const std::string& startPath) {
const int flags = FTW_DEPTH | FTW_MOUNT | FTW_PHYS;
const int maxFileDescriptorsToUse = 1024; // or whatever
const int result = nftw(startPath.c_str(), GetSize, maxFileDescriptorsToUse , flags);
// log or something if result== -1
return gTotalBytes;
}
No. nftw doesn't offer any user parameter that could be passed to the function, so you have to use global (or static) variables in C.
GCC offers an extension "nested function" which should capture the variables of their enclosing scopes, so they could be used like this:
void f()
{
int i = 0;
int fn(const char *,
const struct stat *, int, struct FTW *) {
i++;
return 0;
};
nftw("path", fn, 10, 0);
}
The data is best given static linkage (i.e. file-scope) in a separate module that includes only functions required to access the data, including the function passed to nftw(). That way the data is not visible globally and all access is controlled. It may be that the function that calls ntfw() is also part of this module, enabling the function passed to nftw() to also be static, and thus invisible externally.
In other words, you should do what you are probably doing already, but use separate compilation and static linkage judiciously to make the data only visible via access functions. Data with static linkage is accessible by any function within the same translation unit, and you avoid the problems associated with global variables by only including functions in that translation unit that are creators, maintainers or accessors of that data.
The general pattern is:
datamodule.h
#if defined DATAMODULE_INCLUDE
<type> create_data( <args>) ;
<type> get_data( <args> ) ;
#endif
datamodule.c
#include "datamodule.h"
static <type> my_data ;
static int nftwfunc(const char *filename, const struct stat *statptr, int fileflags, struct FTW *pfwt)
{
// update/add to my_data
...
}
<type> create_data( const char* path, <other args>)
{
...
ret = nftw( path, nftwfunc, fd_limit, flags);
...
}
<type> get_data( <args> )
{
// Get requested data from my_data and return it to caller
}

Resources