I'm writing a media player in pure C and I'm using libvlc. Currently I'm developing media library and i'm writing directory walker and media file parser. It works pretty fine with various metadata like artists or albums, etc., but libvlc_media_get_duration always returns 0. I tried everything and searched everywhere, but I can't make it work. Can anybody help me?
Here is the code:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <vlc/vlc.h>
#include <stdarg.h>
#include <stdbool.h>
#include <dirent.h>
#include <sys/stat.h>
void strcopy(char **dst, const char *src) {
unsigned int size = strlen(src);
*dst = (char *) realloc(*dst, sizeof(char) * (size + 1));
strncpy(*dst, src, size);
*(*dst+size) = 0;
}
void strconcat(char **dst, int n, ...) {
va_list args;
unsigned int count = 0;
// Count
va_start(args, n);
for (unsigned short i = 0; i < n; i++)
count += strlen(va_arg(args, char*));
va_end(args);
// Allocate
*dst = (char *) realloc(*dst, sizeof(char) * (count+1));
unsigned int cursor = 0;
va_start(args, n);
for(unsigned short i = 0; i < n; i++) {
char *src = va_arg(args, char*);
strncpy((*dst+cursor), src, strlen(src));
cursor += strlen(src);
*(*dst+cursor) = 0;
}
va_end(args);
}
void /* Process tags and add file to database */
__db_add_file(libvlc_instance_t *inst, const char *url, bool compute_hash) {
// Create new media
libvlc_media_t *media = libvlc_media_new_path(inst, url);
libvlc_media_parse(media);
if (libvlc_media_is_parsed(media)) {
printf("%s\n", url);
printf("%llu\n", libvlc_media_get_duration(media));
}
libvlc_media_release(media);
}
void /* Walker over directory */
__db_dir_walker(libvlc_instance_t *inst, const char *dir_url, bool compute_hash) {
// Build base path
char *base_url = NULL;
if (dir_url[strlen(dir_url)-1] != '/')
strconcat(&base_url, 2, dir_url, "/");
else
strcopy(&base_url, dir_url);
// Create necessary variables
struct dirent *entry;
DIR *dir;
struct stat fs;
// Try to open dir
if (!(dir = opendir(dir_url))) return;
while (entry = readdir(dir)) {
// Strip parent entries
if ((strcmp(".", entry->d_name) == 0) ||
(strcmp("..", entry->d_name) == 0)) continue;
char *dir_full_path = NULL;
strconcat(&dir_full_path, 2, base_url, entry->d_name);
if (stat(dir_full_path, &fs) < 0) return;
if (S_ISDIR(fs.st_mode)) { // Process directory
__db_dir_walker(inst, dir_full_path, compute_hash);
} else { // Process media file
__db_add_file(inst, dir_full_path, compute_hash);
}
}
// Free memory
closedir(dir);
}
void
db_scan_directory(const char *dir_url, bool compute_hash) {
// Try to open target dir
if (!opendir(dir_url)) return;
// Preload vlc instance for tag data retrieving
libvlc_instance_t *inst = libvlc_new(0, NULL);
// Walk over directory
__db_dir_walker(inst, dir_url, compute_hash);
// Free resources
libvlc_release(inst);
}
int main () {
db_scan_directory("/media/storage/music/Blur/", false);
return 0;
}
Thank you!
If there is anybody who wants to know answer on this question too, here it is:
You need to play to get the duration.
Thanks to Jean-Baptiste Kempf from Videolan Forums.
The best method is probably to call libvlc_media_parse() or its asynchronous counter-part libvlc_media_parse_async().
After calling libvlc_media_parse() your meta data (including duration) will be filed.
Related
I was trying to figure out the best way to keep a record of file pointers as well as individual information for each file such as a file path.
My question is, having a folder struct that holds an array of file pointers, and a file struct that holds information for files, how could merge these two concepts so that can I hold an array of file pointers, and store the file path for each of those files?
Header file for a folder struct below:
#ifndef FOLDER_STRUCT_H
#define FOLDER_STRUCT_H
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
struct folder_
{
FILE **files;
size_t current_size;
size_t capacity;
};
typedef struct folder_ folder_t;
folder_t *folder_create(size_t initial_size); //-----------------------Create a folder struct
void folder_destroy(folder_t *folder); //------------------------------Destroy a folder struct
bool folder_insert_file(folder_t *const folder, FILE *const file); //--Insert a file
FILE *folder_get_file(folder_t *const folder, size_t index); //--------Get a file by index
FILE **folder_get_file_list(folder_t *const folder); //----------------Get a list of files
int folder_get_size(folder_t *folder); //------------------------------Get folder size
int folder_get_total_capacity(folder_t *folder); //--------------------Get folder capacity
#endif
Header file for a file struct used to record file information such as a file path:
#ifndef FILE_H
#define FILE_H
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
struct file_
{
FILE *file;
char *file_path;
};
typedef struct file_ file_t;
#endif
The generic approach is if you need both at the same time use another struct, and if you need either use a union probably with a tag field to tell which of the struct it holds. In your case, it sounds like you have 1 folder to n files, so your folder_file_ struct would have an array of files_. If you have more than one folder, then you need an array of folder_file_.
FILE * usually implies an open file handle. Is that really your use case? Opposed to a bunch of paths, and you only open the file as you have to operate on it. Also, why is FILE ** opposed to a FILE *?
Usually is best to let the system manage the file pointers. The file can be reopened outside your struct for example. Or just closed. The struct can get a copy of a FILE* but there is no way to know if it points to the same file as of the moment of creation.
Anyway, sometimes we may need a way to store info for a collection of files.
An EXAMPLE
typedef struct
{
char* name;
FILE* F;
} File;
typedef struct
{
size_t size;
size_t cap; // capacity
size_t inc; // increment
File** info; // data array
} Folder;
Inside File we can store sizes, dates, maybe permissions.
Folder is an array of pointers to File. cap and size are the usual, inc is the size of increment of Folder in files.
A few functions are implemented:
Folder* create(size_t capacity, size_t step);
Folder* destroy(Folder*);
int insert(File*, Folder*);
int show(Folder*, const char*);
int trim(Folder*);
int get_pos(const char* f_name, Folder*);
insert() accepts a File pointer is easy to customize File.
trim() releases all pointers not in use
show() accepts a title, for convenience
get_pos() returns the position of the provided file in the array
destroy() returns NULL to ease in invalidate the pointer in the same line
main for this test
int main(void)
{
const char tst_size = 10;
const char* scan[] = {"File_7533.tst", "File_7500.tst"};
srand(220520);
Folder* tst = create(4, 4);
show(tst, "just created");
char f_name[20] = {0};
for (int i = 0; i < tst_size; i += 1)
{
sprintf(f_name, "File_%04d.tst", 1+rand()%10000);
insert_this(f_name,NULL,tst);
}
sprintf(f_name, "%d files inserted", tst_size);
show(tst, f_name);
trim(tst);
show(tst, "after trim()");
for (int i = 0; i < sizeof(scan) / sizeof(scan[0]);i+=1)
printf( "search por \"%s\" returned %d\n", scan[i],
get_pos(scan[i], tst));
tst = destroy(tst);
return 0;
}
a Folder is created with size 4 and incrementable in groups of 4
10 files are inserted
the contents are listed
search for 2 files
the thing is destroyed
test output
just created
[0/4 files (step = 4)]
insert() size extended to 8
insert() size extended to 12
10 files inserted
[10/12 files (step = 4)]
0 File_2037.tst
1 File_5785.tst
2 File_6602.tst
3 File_7231.tst
4 File_0854.tst
5 File_7102.tst
6 File_7533.tst
7 File_6460.tst
8 File_1717.tst
9 File_1948.tst
trim() new size: 10
after trim()
[10/10 files (step = 4)]
0 File_2037.tst
1 File_5785.tst
2 File_6602.tst
3 File_7231.tst
4 File_0854.tst
5 File_7102.tst
6 File_7533.tst
7 File_6460.tst
8 File_1717.tst
9 File_1948.tst
search for "File_7533.tst" returned 6
search for "File_7500.tst" returned -1
Folder structure destroyed
stuff.h
#ifndef STUFF_H
#define STUFF_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
char* name;
FILE* F;
} File;
typedef struct
{
size_t size;
size_t cap; // capacity
size_t inc; // increment
File** info; // data array
} Folder;
Folder* create(size_t capacity, size_t step);
Folder* destroy(Folder*);
int insert(File*, Folder*);
int show(Folder*, const char*);
int trim(Folder*);
int get_pos(const char* f_name, Folder*);
#endif
stuff.c
#include "stuff.h"
Folder* create(size_t capacity, size_t step)
{
Folder* nw = (Folder*)malloc(sizeof(Folder));
if (nw == NULL) return NULL;
nw->size = 0;
nw->cap = capacity;
nw->inc = step;
nw->info = (File**) malloc(nw->cap*sizeof(File*));
for (int i = 0; i < nw->cap; i += 1)
nw->info[i] = NULL;
return nw;
}
Folder* destroy(Folder* f)
{
if (f == NULL) return NULL;
for (int i = 0; i < f->size; i += 1)
{
free(f->info[i]->name);
free(f->info[i]);
}
free(f->info);
free(f);
printf("Folder structure destroyed\n");
return NULL;
}
int insert(File* item, Folder* f)
{
if (f == NULL) return -1;
if (item == NULL) return -2;
if (f->size >= f->cap)
{ // extends folder struct size
size_t new_size = f->cap + f->inc;
File* p = realloc((void*)f->info, new_size*sizeof(File*));
if (p == NULL) return -3; // error extending
f->info = (File**) p;
f->cap = new_size;
printf("insert() size extended to %zd\n", f->cap);
};
// ok, new File then
File* nw = (File*)malloc(sizeof(File));
nw->name = (char*)malloc(1 + strlen(item->name));
strcpy(nw->name, item->name);
nw->F = item->F;
f->info[f->size] = nw;
f->size += 1;
return (int)f->size;
}
int show(Folder* f, const char* msg)
{
if (msg != NULL) printf("%s\n", msg);
printf(
"[%zd/%zd files (step = %zd)\n", f->size, f->cap,
f->inc);
for (int i = 0; i < f->size; i += 1)
{
printf("%3d %s\n", i, f->info[i]->name);
}
printf("\n");
return 0;
}
int trim(Folder* f)
{
if (f == NULL) return -1;
if (f->cap == f->size) return 0; // nothing to do
File* p = realloc((void*)f->info, f->size * sizeof(File*));
if (p == NULL) return -3; // error extending
f->info = (File**) p;
f->cap = f->size;
printf("trim() new size: %zd\n", f->cap);
return 0;
};
int get_pos(const char* f_name, Folder* f)
{
if (f_name == NULL) return -1;
for (int i = 0; i < f->size; i += 1)
if (strcmp(f_name, f->info[i]->name) == 0) return i;
return -1;
}
Note to SO "code reviewers": I do cast all malloc() pointers, as I do not like implicit things and I like them as additional reminders of things to come.
so I've been set a task of creating a faux string struct and implementing all the usual string functions on my faux string struct. I'm stuck on the tests of my strcat implementation called append, with the first test failing (segfault) being the 5th line. My function for creating new structs should be OK because it passed all the tests, but I've included it just incase.
I've already been able to successfully implement length, get, set and copy functions for my faux string structs.
The struct:
struct text {
int capacity;
char *content;
};
typedef struct text text;
My function for creating new structs:
text *newText(char *s) {
printf("new Text from %s\n", s);
int sizeNeeded = (strlen(s)+1);
int sizeGot = 24;
while (sizeNeeded > sizeGot) {
sizeGot = sizeGot * 2;
}
text *out = malloc(sizeGot);
char *c = malloc(sizeGot);
strcpy(c, s);
out->content = c;
out->capacity = (sizeGot);
printf("the capacity is %d\n", sizeGot);
return out;
free(c);
}
My append function:
void append(text *t1, text *t2) {
printf("t1 content is %s, t2 content is %d\n", t1->content, *t2->content);
int sizeNeeded = (t1->capacity + t2->capacity);
int sizeGot = 24;
while (sizeNeeded > sizeGot) {
sizeGot = sizeGot * 2;
}
char *stringy = calloc(sizeGot, 32);
stringy = strcat(t1->content, t2->content);
free(t1);
t1 = newText(stringy);
}
and finally the tests:
void testAppend() {
text *t = newText("car");
text *t2 = newText("pet");
append(t, t2);
assert(like(t, "carpet"));
assert(t->capacity == 24);
text *t3 = newText("789012345678901234");
append(t, t3);
assert(like(t, "carpet789012345678901234"));
assert(t->capacity == 48);
freeText(t);
freeText(t2);
freeText(t3);
}
You are allocating memory in the wrong way. You could fix this by using a flexible array member like this:
typedef struct {
int capacity;
char content[];
} text;
text *out = malloc(sizeof(text) + sizeof(something));
strcpy(out->content, str);
...
And obviously code such as this is nonsense:
return out;
free(c);
}
Enable compiler warnings and listen to them.
Och, some errors you have:
Inside text_new you allocate memory for text *out using text *out = malloc(sizeGot); when sizeGot = 24 is a constant value. You should allocate sizeof(*out) or sizeof(text) bytes of memory for it.
I don't know what for int sizeGot = 24; while (sizeNeeded > sizeGot) the loop inside text_new and append is for. I guess the intention is to do allocations in power of 24. Also it mostly looks like the same code is in both functions, it does look like code duplication, which is a bad thing.
Inside append You pass a pointer to t1, not a double pointer, so if you modify the t1 pointer itself the modification will not be visible outside of function scope. t1 = newText(stringy); is just pointless and leaks memory. You could void append(text **t1, text *t2) and then *t1 = newText(stringy). But you can use a way better approach using realloc - I would expect append to "append" the string, not to create a new object. So first resize the buffer using realloc then strcat(&t1->content[oldcapacity - 1], string_to_copy_into_t1).
int sizeNeeded = (t1->capacity + t2->capacity); is off. You allocate capacity in power of 24, which does not really interact with string length. You need to have strlen(t1->content) + strlen(t2->content) + 1 bytes for both strings and the null terminator.
Try this:
size_t text_newsize(size_t sizeNeeded)
{
// I think this is just `return 24 << (sizeNeeded / 24);`, but not sure
int sizeGot = 24;
while (sizeNeeded > sizeGot) {
sizeGot *= 2;
}
return sizeGot;
}
text *newText(char *s) {
printf("new Text from %s\n", s);
if (s == NULL) return NULL;
int sizeNeeded = strlen(s) + 1;
int sizeGot = text_newsize(sizeNeeded);
text *out = malloc(sizeof(*out));
if (out == NULL) {
return NULL;
}
out->content = malloc(sizeGot);
if (out->content == NULL) {
free(out);
return NULL;
}
strcpy(out->content, s);
out->capacity = sizeGot;
printf("the capacity is %d\n", sizeGot);
return out;
}
and this:
int append(text *t1, text *t2) {
printf("t1 content is %s, t2 content is %s\n", t1->content, t2->content);
int sizeNeeded = strlen(t1->content) + strlen(t2->content) + 1;
if (t1->capacity < sizeNeeded) {
// this could a text_resize(text*, size_t) function
int sizeGot = text_newsize(sizeNeeded);
void *tmp = realloc(t1->content, sizeGot);
if (tmp == NULL) return -ENOMEM;
t1->content = tmp;
t1->capacity = sizeGot;
}
strcat(t1->content, t2->content);
return 0;
}
Some remarks:
Try to handle errors in your library. If you have a function like void append(text *t1, text *t2) let it be int append(text *t1, text *t2) and return 0 on success and negative number on *alloc errors.
Store the size of everything using size_t type. It's defined in stddef.h and should be used to represent a size of an object. strlen returns size_t and sizeof also returns size_t.
I like to put everything inside a single "namespace", I do that by prepending the functions with a string like text_.
I got some free time and decided to implement your library. Below is the code with a simple text object storing strings, I use 24 magic number as allocation chunk size.
// text.h file
#ifndef TEXT_H_
#define TEXT_H_
#include <stddef.h>
#include <stdbool.h>
struct text;
typedef struct text text;
text *text_new(const char content[]);
void text_free(text *t);
int text_resize(text *t, size_t newsize);
int text_append(text *to, const text *from);
int text_append_mem(text *to, const void *from, size_t from_len);
const char *text_get(const text *t);
int text_append_str(text *to, const char *from);
char *text_get_nonconst(text *t);
size_t text_getCapacity(const text *t);
bool text_equal(const text *t1, const text *t2);
#endif // TEXT_H_
// text.c file
//#include "text.h"
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <assert.h>
struct text {
size_t capacity;
char *content;
};
text *text_new(const char content[])
{
text * const t = malloc(sizeof(*t));
if (t == NULL) goto MALLOC_ERR;
const struct text zero = {
.capacity = 0,
.content = NULL,
};
*t = zero;
if (content != NULL) {
const int ret = text_append_str(t, content);
if (ret) {
goto TEXT_APPEND_ERR;
}
}
return t;
TEXT_APPEND_ERR:
free(t);
MALLOC_ERR:
return NULL;
}
void text_free(text *t)
{
assert(t != NULL);
free(t->content);
free(t);
}
int text_resize(text *t, size_t newcapacity)
{
// printf("%s %d -> %d\n", __func__, t->capacity, newcapacity);
// we resize in chunks
const size_t chunksize = 24;
// clap the capacity into multiple of 24
newcapacity = (newcapacity + chunksize - 1) / chunksize * chunksize;
void * const tmp = realloc(t->content, newcapacity);
if (tmp == NULL) return -ENOMEM;
t->content = tmp;
t->capacity = newcapacity;
return 0;
}
int text_append_mem(text *to, const void *from, size_t from_len)
{
if (to == NULL || from == NULL) return -EINVAL;
if (from_len == 0) return 0;
const size_t oldcapacity = to->capacity == 0 ? 0 : strlen(to->content);
const size_t newcapacity = oldcapacity + from_len + 1;
int ret = text_resize(to, newcapacity);
if (ret) return ret;
memcpy(&to->content[newcapacity - from_len - 1], from, from_len);
to->content[newcapacity - 1] = '\0';
return 0;
}
int text_append_str(text *to, const char *from)
{
if (to == NULL || from == NULL) return -EINVAL;
return text_append_mem(to, from, strlen(from));
}
int text_append(text *to, const text *from)
{
if (to == NULL || from == NULL) return -EINVAL;
if (text_getCapacity(from) == 0) return 0;
return text_append_str(to, text_get(from));
}
const char *text_get(const text *t)
{
return t->content;
}
const size_t text_strlen(const text *t)
{
return t->capacity == 0 ? 0 : strlen(t->content);
}
size_t text_getCapacity(const text *t)
{
return t->capacity;
}
bool text_equal_str(const text *t, const char *str)
{
assert(t != NULL);
if (str == NULL && t->capacity == 0) return true;
const size_t strlength = strlen(str);
const size_t t_strlen = text_strlen(t);
if (t_strlen != strlength) return false;
if (memcmp(text_get(t), str, strlength) != 0) return false;
return true;
}
// main.c file
#include <stdio.h>
int text_testAppend(void) {
text *t = text_new("car");
if (t == NULL) return -1;
text *t2 = text_new("pet");
if (t2 == NULL) return -1;
if (text_append(t, t2)) return -1;
assert(text_equal_str(t, "carpet"));
assert(text_getCapacity(t) == 24);
text *t3 = text_new("789012345678901234");
if (t3 == NULL) return -1;
if (text_append(t, t3)) return -1;
assert(text_equal_str(t, "carpet789012345678901234"));
assert(text_getCapacity(t) == 48);
text_free(t);
text_free(t2);
text_free(t3);
return 0;
}
int main()
{
text *t1 = text_new("abc");
text_append_str(t1, "def");
printf("%s\n", text_get(t1));
text_free(t1);
printf("text_testAppend = %d\n", text_testAppend());
return 0;
}
Hello I am developing a program for the Raspberry in C (the in-progress project can be found here).
I noted there are some errors in the task1 function so I created an equivalent program in my Desktop (running Ubuntu) to find the error, where the task1 was readapted as below:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "stub.h"
#include "globals.h"
#include "utils.h"
#include <pthread.h>
#define INPIN 25
void takePic(char picname[24]);
//This thread reads the PIR sensor output
void task1()
{
unsigned char val_read = 0;
static unsigned char alarm_on = FALSE;
static const unsigned int maxNumPics=10;
static char folderPath[] = "/home/usr/Documents/alarmSys_rasp/alarm_new/pics/";
char fileNameTodelete[73];
fileNameTodelete[0] = '\0';
strcat(fileNameTodelete, folderPath);
//INITIALIZING
pinMode(INPIN, INPUT);
//create folder where to save pics
createFolder(folderPath);
char* names[24];
char picname[24];
int res = 0;
picname[0] = '\0';
static unsigned int numPicsInFolder;
//delete if more than 10 files
while((numPicsInFolder = filesByName(names, folderPath))>maxNumPics)
{
fileNameTodelete[0] = '\0';
strcat(fileNameTodelete, folderPath);
strcat(fileNameTodelete, names[0]);
printf("%s\n", fileNameTodelete);
remove(fileNameTodelete);
}
static unsigned int nexEl;
nexEl = numPicsInFolder % maxNumPics;
printf("Entering while\n");
while(1)
{
//static const unsigned int del = 300;
val_read = digitalRead(INPIN);
if (val_read && (!alarm_on)) //motion detected
{
printf("\nDetected movement\n");
if (numPicsInFolder >= maxNumPics)
{
printf("\nMax num pics\n");
fileNameTodelete[0] = '\0';
strcat(fileNameTodelete, folderPath);
strcat(fileNameTodelete, names[nexEl]);
printFiles(names, numPicsInFolder);
printf("File to be deleted %d: %s, ", nexEl, names[nexEl]);
//printf("%s\n", fileNameTodelete);
if ((res = remove(fileNameTodelete))!=0)
{
printf("Error deleting file: %d\n", res);
}
}
else
{
printf("\nNot reached max num pics\n");
numPicsInFolder++;
}
//update buffer
takePic(picname);
printf("value returned by takePic: %s\n", picname);
//names[nexEl] = picname;
strcpy(names[nexEl], picname); //ERROR HERE
printFiles(names, numPicsInFolder);
printf("curr element %d: %s\n",nexEl, names[nexEl]);
nexEl++;
nexEl %= maxNumPics;
printf("\nDetected movement: alarm tripped\n\n");
alarm_on = TRUE;
/*Give some time before another pic*/
}
else if (alarm_on && !val_read)
{
alarm_on = FALSE;
printf("\nAlarm backed off\n\n");
}
}
}
void takePic(char picname[24])
{
/*Build string to take picture*/
int err;
//finalcmd is very long
char finalcmd[150];
finalcmd[0] = '\0';
getDateStr(picname);
char cmd1[] = "touch /home/usr/Documents/alarmSys_rasp/alarm_new/pics/";
char cmdlast[] = "";
strcat(finalcmd, cmd1);
strcat(picname, ".jpg");
strcat(finalcmd, picname);
strcat(finalcmd, cmdlast);
system(finalcmd);
if ((err=remove("/var/www/html/*.jpg"))!=0)
{
printf("Error deleting /var/www/html/*.jpg, maybe not existing\n" );
}
//system(finalcmd_ln);
//pthread_mutex_lock(&g_new_pic_m);
g_new_pic_flag = TRUE;
printf("\nPicture taken\n\n");
}
DESCRIPTION
The main function calls the task1 function defined in the file task1.c. The function creates a file in the folder ./pics/ every time the condition (val_read && (!alarm_on)) is verified (in the simulation this condition is satisfied every 2 loops). The function allows only 10 files in the folder. If there are already 10, it deletes the oldest one and creates the new file by calling the function takePic.
The name of files are stored in a array of strings char* names[24]; and the variable nexEl points to the element of this array having the name of the oldest file so that it is replaced with the name of the new file just created.
PROBLEM
The problem is the following: the array char* names[24] is correctly populated at the first iteration but already in the second iteration some elements are overwritten. The problem arises when the folder has the maximum number of files (10) maybe on the update of the array.
It seems the calls to printf overwrite some of its elements so that for example one of them contains the string "Error deleting /var/www/html/*.jpg, maybe not existing\n" printed inside the funtion takePic.
What am I missing or doing wrong with the management of arrays of strings?
UTILITIES FUNCTIONS
To be complete here are shortly described and reported other functions used in the program.
The function getDateStr builds a string representing the current date in the format yyyy_mm_dd_hh_mm_ss.
The function filesByName builds an array of strings where each string is the name of a file in the folder ./ ordered from the last file created to the newest.
The function printFiles prints the previous array.
void getDateStr(char str[20])
{
char year[5], common[3];
time_t t = time(NULL);
struct tm tm = *localtime(&t);
str[0]='\0';
sprintf(year, "%04d", tm.tm_year+1900);
strcat(str, year);
sprintf(common, "_%02d", tm.tm_mon + 1);
strcat(str, common);
sprintf(common, "_%02d", tm.tm_mday);
strcat(str, common);
sprintf(common, "_%02d", tm.tm_hour);
strcat(str, common);
sprintf(common, "_%02d", tm.tm_min);
strcat(str, common);
sprintf(common, "_%02d", tm.tm_sec);
strcat(str, common);
//printf("%s\n", str);
}
unsigned int countFiles(char* dir)
{
unsigned int file_count = 0;
DIR * dirp;
struct dirent * entry;
dirp = opendir(dir); /* There should be error handling after this */
while ((entry = readdir(dirp)) != NULL) {
if (entry->d_type == DT_REG) { /* If the entry is a regular file */
file_count++;
}
}
return file_count;
}
void printFiles(char* names[24], unsigned int file_count)
{
for (int i=0; i<file_count; i++)
{
printf("%s\n", names[i]);
}
}
unsigned int filesByName(char* names[24], char* dir)
{
unsigned int file_count = 0;
DIR * dirp;
struct dirent * entry;
dirp = opendir(dir); /* There should be error handling after this */
while ((entry = readdir(dirp)) != NULL) {
if (entry->d_type == DT_REG) { /* If the entry is a regular file */
//strncpy(names[file_count], entry->d_name,20);
//names[file_count] = malloc(24*sizeof(char));
names[file_count] = entry->d_name;
file_count++;
}
}
closedir(dirp);
char temp[24];
if (file_count>0)
{
for (int i=0; i<file_count-1; i++)
{
for (int j=i; j<file_count; j++)
{
if (strcmp(names[i], names[j])>0)
{
strncpy(temp, names[i],24);
strncpy(names[i], names[j],24);
strncpy(names[j], temp, 24);
}
}
}
}
return file_count;
}
For the simulation I created also the following function (digitalRead is actually a function of the wiringPi C library for the Raspberry):
int digitalRead(int INPIN)
{
static int res = 0;
res = !res;
return res;
}
In task1, you have char *names[24]. This is an array of char pointers.
In filesByName, you do
names[file_count] = entry->d_name;
but should be doing
names[file_count] = strdup(entry->d_name);
because you can't guarantee that d_name persists or is unique after the function returns or even within the loop. You were already close with the commented out malloc call.
Because you call filesByName [possibly] multiple times, it needs to check for names[file_count] being non-null so it can do a free on it [to free the old/stale value from a previous invocation] before doing the strdup to prevent a memory leak.
Likewise, in task1,
strcpy(names[nexEl], picname); //ERROR HERE
will have similar problems and should be replaced with:
if (names[nexEl] != NULL)
free(names[nexEl]);
names[nexEl] = strdup(picname);
There may be other places that need similar adjustments. And, note that in task1, names should be pre-inited will NULL
Another way to solve this is to change the definition of names [everywhere] from:
char *names[24];
to:
char names[24][256];
This avoids some of the malloc/free actions.
getDateStr() uses a char buffer that is always too small. Perhaps other problems exists too.
void getDateStr(char str[20]) {
char year[5], common[3];
....
sprintf(common, "_%02d", tm.tm_mon + 1); // BAD, common[] needs at least 4
Alternative with more error checking
char *getDateStr(char *str, size_t sz) {
if (str == NULL || sz < 1) {
return NULL;
}
str[0] = '\0';
time_t t = time(NULL);
struct tm *tm_ptr = localtime(&t);
if (tm_ptr == NULL) {
return NULL;
}
struct tm tm = *tm_ptr;
int cnt = snprintf(year, sz, "%04d_%02d_%02d_%02d_%02d_%02d",
tm.tm_year+1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec);
if (cnt < 0 || cnt >= sz) {
return NULL;
}
return str;
}
Background:
I am currently working on a project. The main objective is to read files and compare groupings of words. Only user interaction will be to specify group length. My programs are placed into a directory. Inside that directory, there will be multiple textfiles(Up to 30). I use
system("ls /home/..... > inputfile.txt");
system("ls /home/..... > inputfile.txt");
From there, I open the files from inputfile.txt to read for their contents.
Now to the actual question/problem part.
The method I am using for this is a queue because FIFO. (Code "link.c":http://pastebin.com/rLpVGC00
link.c
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include "linkedlist.h"
struct linkedList
{
char *data;
int key;
int left;
int right;
int size;
};
LinkedList createLinkedList(int size)
{
LinkedList newLL = malloc(sizeof *newLL);
newLL->data = malloc(sizeof(int) * (size+1));
newLL->size = size;
newLL->left = 0;
newLL->right = 0;
return newLL;
}
bool isFull(LinkedList LL)
{
return abs(abs(LL->left)- abs(LL->right)) == LL->size;
}
void insertFront(LinkedList LL, char *newInfo)
{
if(isFull(LL))
{
printf("FULL");
exit(1);
}
LL->data[((--(LL->left) % LL->size) + LL->size) % LL->size] = newInfo;
}
bool isEmpty(LinkedList LL)
{
return LL->left == LL->right;
}
const char * removeEnd(LinkedList LL)
{
if(isEmpty(LL))
{
return "EMPTY";
//exit(1);
}
return LL->data[((--(LL->right) % LL->size) + LL->size) % LL->size];
}
I get two warnings when I compile with link.c and my main (Start11.c)
link.c: In function ‘insertFront’:
link.c:39:64: warning: assignment makes integer from pointer without a cast [enabled by default]
LL->data[((--(LL->left) % LL->size) + LL->size) % LL->size] = newInfo;
^
link.c: In function ‘removeEnd’:
link.c:54:5: warning: return makes pointer from integer without a cast [enabled by default]
return LL->data[((--(LL->right) % LL->size) + LL->size) % LL->size];
^
FULL start11.c code: http://pastebin.com/eskn5yxm .
From bulk of read() function that I have questions about:
fp = fopen(filename, "r");
//We want two word or three word or four word PHRASES
for (i = 0; fgets(name, 100, fp) != NULL && i < 31; i++)
{
char *token = NULL; //setting to null before using it to strtok
token = strtok(name, ":");
strtok(token, "\n");//Getting rid of that dirty \n that I hate
strcat(fnames[i], token);
char location[350];
//Copying it back to a static array to avoid erros with fopen()
strcpy(location, fnames[i]);
//Opening the files for their contents
fpp = fopen(location, "r");
printf("\nFile %d:[%s] \n", i+1, fnames[i]);
char* stringArray[400];
//Reading the actual contents
int y;
for(j = 0; fgets(info,1600,fpp) != NULL && j < 1600; j++)
{
for( char *token2 = strtok(info," "); token2 != NULL; token2 = strtok(NULL, " ") )
{
puts(token2);
++y;
stringArray[y] = strdup(token2);
insertFront(index[i],stringArray[y]);
}
}
}
//Comparisons
char take[20010],take2[200100], take3[200100],take4[200100];
int x,z;
int count, count2;
int groupV,groupV2;
for(x = 0; x < 10000; ++x)
{
if(removeEnd(index[0])!= "EMPTY")
{
take[x] = removeEnd(index[0]);
}
if(removeEnd(index[1])!= "EMPTY")
{
take2[x] = removeEnd(index[1]);
}
if(removeEnd(index[2])!= "EMPTY")
{
take3[x] = removeEnd(index[2]);
}
}
for(z = 0; z < 10; z++)
{
if(take[z] == take2[z])
{
printf("File 1 and File 2 are similar\n");
++count;
if(count == groupL)
{
++groupV;
}
}
if(take[z] == take3[z])
{
printf("File 1 and File 3 are similar\n");
++count2;
if(count == groupL)
{
++groupV2;
}
}
}
Are those two warnings before the reason why when I try to compare the files it'll not be correct? (Yes I realize I "hardcoded" the comparisons. That is just temporary till I get some of this down...)
I'll post header files as a comment. Won't let me post more than two links.
Additional notes:
removeEnd() returns "EMPTY" if there is if there is nothing left to remove.
insertFront() is a void function.
Before I created this account so I can post, I read a previous question regarding strttok and how if I want to insert something I have to strdup() it.
I have not added my free functions to my read() function. I will do that last too.
start.h (pastebin.com/NTnEAPYE)
#ifndef START_H
#define START_H
#include "linkedlist.h"
void read(LinkedList LL,char* filename, int lineL);
#endif
linkedlist.h (pastebin.com/ykzbnCTV)
#include <stdlib.h>
#include <stdio.h>
#ifndef LINKEDLIST_H
#define LINKEDLIST_H
typedef int bool;
typedef struct linkedList *LinkedList;
LinkedList createLinkedList(int size);
bool isFull(LinkedList LL);
void insertFront(LinkedList LL, char *newInfo);
const char * removeEnd(LinkedList LL);
bool isEmpty(LinkedList LL);
#endif
The main problem is around the removeEnd (resp. insertFrom) function:
const char * removeEnd(LinkedList LL)
{
if (...)
return "EMPTY";
else
return LL->data[xxx];
you return a const char * in the first return but a char in the second return, hence the warning, which is a serious one.
And when you compare return value to "EMPTY" in the caller, it's just wrong: you should use strcmp instead of comparing arrays which may be the same depending on compilers which group same strings in the same location, but only by chance (and not portable!)
Problem 1: what's the best data structure to save the directory structure?
Problem 2: I have tried to use a general tree to solve it, but there are a lot of problems:
The number of files under a directory is not certain. So the number of child nodes under a tree node is also not certain. and I try to add a keyword nchild to each node, showing nchild child nodes. so there are nchild pointers (saved with **child) to the child nodes. And once that, **child and *child should be dynamically allocated space with no certain child nodes. So you know, this is really difficult to release these spaces(and the program below is not called free()). Is there a better way to solve it?
And sometimes the program below would get the garbage characters when I output the directory tree, which make me really confused. while debugging it, found that is the function ent=readdir(pDir); has read garbage characters. But when I write another simple program to read the same directory, that goes well. I think the problem is the recursive function, but I didn't get any idea. I will be appreciated if some one can give me a idea. Thanks!
```
#include <dirent.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <stdio.h>
typedef struct tree_file_s
{
char path[512];
time_t date;
char type;
long size;
int nchild;
struct tree_file_s **child;
} tree_file_t;
int dir_child_len(const char *dir)
{
int nchild = 0;
DIR *pDir;
struct dirent *ent;
pDir = opendir(dir);
while((ent=readdir(pDir)) != NULL)
{
if (strcmp(ent->d_name, ".")==0 || strcmp(ent->d_name, "..")==0)
{
continue;
}
nchild++;
}
return nchild;
}
void tree_create(tree_file_t *tft, const char *dir)
{
int nchild; // the tft has n child
DIR *pDir;
struct dirent *ent; // the directory dir dirent info
struct stat file_stat; // the new file's stat info
stat(dir, &file_stat);
nchild = dir_child_len(dir);
pDir = opendir(dir);
// Initialize the parent
//tft->path = calloc(1, strlen(dir)+1);
strcpy(tft->path, dir);
tft->date = file_stat.st_mtime;
tft->type = 'D';
tft->size = file_stat.st_size;
tft->nchild = nchild;
tft->child = calloc(1, nchild);
nchild = 0;
while ((ent=readdir(pDir)) != NULL)
{
if (ent->d_type & DT_DIR)
{
if (strcmp(ent->d_name, ".")==0 || strcmp(ent->d_name, "..")==0)
{
continue;
}
tree_file_t *new_dir = calloc(1, sizeof(tree_file_t));
tft->child[nchild] = new_dir;
char *new_path = calloc(1, strlen(dir)+strlen(ent->d_name)+1);
sprintf(new_path, "%s/%s", dir, ent->d_name);
tree_create(new_dir, new_path);
free(new_path);
} else {
tree_file_t *new_file = calloc(1, sizeof(tree_file_t));
char *new_path = calloc(1, strlen(dir)+strlen(ent->d_name)+1);
// new_file->path = calloc(1, strlen(dir)+strlen(ent->d_name)+1);
sprintf(new_path, "%s/%s", dir, ent->d_name);
stat(new_path, &file_stat);
strcpy(new_file->path, new_path);
free(new_path);
new_file->date = file_stat.st_mtime;
new_file->type = 'F';
new_file->size = file_stat.st_size;
new_file->nchild = 0;
new_file->child = 0;
tft->child[nchild] = new_file;
}
//free(new_path);
//new_path = 0;
nchild++;
}
}
void display_tree(tree_file_t *tft)
{
int nchild, i;
nchild = tft->nchild;
printf("%c: %s\n", tft->type, tft->path);
for(i = 0; i < nchild; i++)
{
if(tft->child[i]->type == 'F')
{
printf("%c: %s\n", tft->child[i]->type, tft->child[i]->path);
} else {
display_tree(tft->child[i]);
}
}
}
int main(int argc, const char *argv[])
{
if(argc != 2)
{
printf("Usage: a.out dir\n");
exit(0);
}
char dir[512];
strcpy(dir, argv[1]);
tree_file_t *tft = calloc(1, sizeof(tree_file_t));
tree_create(tft, dir);
display_tree(tft);
return 0;
}
```
When you allocate space for new_path you need to add 2 (one for the slash, one for the null terminator). And you never close the directories you open (use closedir()).
An even more serious error is this line:
tft->child = calloc(1, nchild);
which only allocates nchild bytes, not enough to hold nchild pointers! Try:
tft->child = calloc(nchild, sizeof(*tft->child));