String inside struct become weird symbols after passing to a method - c

I have a struct named task. It's a linked list that contains a struct timing and a command. It's used to store the command I have to execute at a certain time:
// and here is the struct command:
struct argument {
size_t length; // length of the data string
char *data;
};
typedef struct argument argument;
struct command {
int argc; // amount of arguments(words) in argv
argument *argv; // here I already tried put argument **argv
};
typedef struct command command;
I initialize the task with task *this_task = malloc(sizeof(task));
and initialize the command with command *cmds = malloc(sizeof(command)).
I add the commands with this method:
command *addToCommand(command *cmd, size_t argSize, char *arg) {
argument *currentArgument = malloc(sizeof(argument) + argSize * sizeof(char));
if (currentArgument == NULL) {
cmd = NULL;
return cmd;
}
currentArgument->length = argSize;
currentArgument->data = arg;
if (cmd == NULL) {
cmd = malloc(sizeof(command));
if (cmd == NULL) return cmd;
cmd->argv = malloc(sizeof(argument));
cmd->argv[0] = *currentArgument;
cmd->argc = 1;
} else {
cmd->argc++;
cmd->argv = realloc(cmd->argv, (cmd->argc) * sizeof(argument));
cmd->argv[cmd->argc-1] = *currentArgument;
}
return cmd;
}
and then set it with this_task->cmd = cmds;
Now the problem: just after I did all this I printed the first argv of my task with printf( "%s\n", this_task->cmd->argv[0].data), and it showed 'test-0' like it should.
But the moment when I send it to an another method, like addTask(this_task), and print it again on the first line of the addTask method it shows weird symbols like "p<a�".
For example for this code :
void addTask(task *task_to_add) {
printf("arg inside addTask = '%s'\n", task_to_add->cmd->argv[0].data);
// i'm doing things here but even when everything is commented the bug happen
}
printf("arg before addTask = '%s'\n", this_task->cmd->argv[0].data);
addTask(this_task);
printf("arg after addTask = '%s'\n", this_task->cmd->argv[0].data);
Shows:
arg before addTask = 'test-0'
arg inside addTask = '`��'
arg after addTask = '`��'
In this project, I'm writing the command to a pipe, and reading it in the code above. While trying to make a minimal reproducible example, I noticed that when I remove the part reading from pipes and directly force the value for "test-0", it works correctly. So does the problem happen because of the way I'm reading the pipes? I also tried the solution of the "possible duplicate," but it didn't work. The issue is probably from how I read from the pipe.
I also noticed that if I don't have any other printf before the one displaying "arg before addTask ...", the arg before show " ", I commented it and wrote "THIS PRINTF" near it
How I compile and run:
gcc src/saturnd.c -o saturnd
gcc src/cassini.c -o cassini
./saturnd
./cassini (in another terminal)
The code who's reading the pipe:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdint.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <endian.h>
struct argument {
size_t length;
char *data;
};
typedef struct argument argument;
struct command {
int argc;
argument *argv;
};
typedef struct command command;
struct task {
int id;
struct timing *timing;
command *cmd;
struct task *next;
};
typedef struct task task;
struct timing {
uint64_t minutes;
uint32_t hours;
uint8_t daysofweek;
};
int readHere;
task *tasks = NULL;
command *addToCommand(command *cmd, size_t argSize, char *arg) {
// printf("adding to cmd %s\n", arg);
argument *currentArgument = malloc(sizeof(argument) + argSize * sizeof(char));
if (currentArgument == NULL) {
cmd = NULL;
return cmd;
}
currentArgument->length = argSize;
currentArgument->data = arg;
if (cmd == NULL) {
cmd = malloc(sizeof(command));
if (cmd == NULL) return cmd;
cmd->argv = malloc(sizeof(argument));
cmd->argv[0] = *currentArgument;
cmd->argc = 1;
} else {
cmd->argc++;
cmd->argv = realloc(cmd->argv, (cmd->argc) * sizeof(argument));
cmd->argv[cmd->argc - 1] = *currentArgument;
}
return cmd;
}
void addTask(task *task_to_add) {
printf("arg inside addTask = '%s'\n", task_to_add->cmd->argv[0].data);
}
int main() {
char *readHere_path = "saturndReadPipe";
mkfifo(readHere_path, S_IRWXU | S_IRWXG | S_IRWXO);
readHere = open(readHere_path, O_RDONLY);
task *this_task = malloc(sizeof(task));
this_task->id = 0;
struct timing *reply_time = malloc(sizeof(struct timing));
reply_time->minutes = 5; // test vars
reply_time->hours = 5; // test vars
reply_time->daysofweek = 5; // test vars
uint32_t reply_argc;
read(readHere, &reply_argc, sizeof(reply_argc));
reply_argc = be32toh(reply_argc);
// reply_argc should be 2, because we wrote only 2 words "echo" and "test-0"
command *cmds = NULL;
for (int j = 0; j < (int) reply_argc; j++) {
uint32_t argSize_uint;
read(readHere, &argSize_uint, sizeof(argSize_uint));
int argSize = be32toh(argSize_uint);
int newSize = argSize + 1;
char arg[newSize];
int data_read = (int) read(readHere, &arg, argSize);
arg[data_read] = '\0';
//printf("read '%s' from pipe\n", arg); // THIS PRINTF
cmds = addToCommand(cmds, newSize, arg);
}
this_task->cmd = cmds;
this_task->next = NULL;
printf("arg before addTask = '%s'\n", this_task->cmd->argv[0].data);
addTask(this_task);
printf("arg after addTask = '%s'\n", this_task->cmd->argv[0].data);
exit(0);
}
The code which is writing in the pipe:
#include <stdlib.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <endian.h>
int main() {
char *writeHere_path = "saturndReadPipe";
int writeHere = open(writeHere_path, O_WRONLY | O_TRUNC);
uint32_t cmd_argc = htobe32(2);
write(writeHere, &cmd_argc, sizeof(cmd_argc));
// sending "echo"
uint32_t length = htobe32(4);
write(writeHere, &length, sizeof(length));
char *cmd_data = "echo";
uint8_t d[4];
int j = 0;
for (; j < 4; ++j)
d[j] = cmd_data[j];
write(writeHere, &d, sizeof(d));
// sending "test-0"
length = htobe32(4);
write(writeHere, &length, sizeof(length));
cmd_data = "test-0";
uint8_t dd[4];
j = 0;
for (; j < 4; ++j)
dd[j] = cmd_data[j];
write(writeHere, &dd, sizeof(dd));
exit(0);
}

You do not copy string only assign the pointer to it. I would do it a bit different way.
typedef struct argument {
size_t length; // length of the data string
char data[];
}argument;
typedef struct command {
int argc; // amount of arguments(words) in argv
argument *argv[];
}command;
command *addToCommand(command *cmd, const size_t argSize, const char *restrict arg)
{
int newargc = cmd ? cmd -> argc + 1 : 1;
argument *currentArgument = malloc(sizeof(*currentArgument) +
(argSize + 1) * sizeof(currentArgument -> data[0])); //if argsize includes null terminating character remove "+1"
if (currentArgument)
{
currentArgument->length = argSize;
strcpy(currentArgument->data, arg);
cmd = realloc(cmd, sizeof(*cmd) + newargc * sizeof(cmd -> argv[0]));
if(cmd)
{
cmd -> argc = newargc;
cmd -> argv[newargc -1] = currentArgument;
}
}
return cmd;
}

Related

VSSCANF Error, Extracting variables from response buffer in c [By Line & By Keyword]

If I extract a single variable from the response buffer both (by line number or keyword) methods are working ok. But if I am trying to extract multiple variables of multiple types like string, int, and float it's not working after a string extraction successfully.
(commented unnessury code)
godbolt link is here
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
uint8_t res_buf[2048];
uint8_t line_counts;
} MODULE_Typedef; //module buffer
// validate and get response pointer by line number
uint8_t *MODULE_ATRespGetByLineNumber(MODULE_Typedef *module, uint8_t resp_line) {
uint8_t *resp_buf = module->res_buf;
uint8_t *resp_line_buf = 0;
uint8_t line_num = 1;
if (resp_line > module->line_counts || resp_line <= 0) {
return 0;
}
for (line_num = 1; line_num <= module->line_counts; line_num++) {
if (resp_line == line_num) {
resp_line_buf = resp_buf;
return resp_line_buf;
}
resp_buf += strlen(resp_buf) + 1;
}
return 0;
}
//parse response by line number
uint16_t MODULE_ATRespParseLine(MODULE_Typedef *module, uint8_t resp_line, const char *resp_expr, ...) {
va_list args;
int resp_args_num = 0;
const char *resp_line_buf = 0;
if ((resp_line_buf = MODULE_ATRespGetByLineNumber(module, resp_line)) == 0) {
return -1;
}
// printf("\r\nOK = %s\r\n",resp_line_buf);
va_start(args, resp_expr);
resp_args_num = vsscanf(resp_line_buf, resp_expr, args);
va_end(args);
return resp_args_num;
}
//validate and get response pointer by keyword
uint8_t *MODULE_ATRespGetByKeyword(MODULE_Typedef *module, uint8_t *keyword) {
char *resp_buf = module->res_buf;
char *resp_line_buf = 0;
uint16_t line_num = 1;
for (line_num = 1; line_num <= module->line_counts; line_num++) {
if (strstr(resp_buf, keyword)) {
resp_line_buf = resp_buf;
return resp_line_buf;
}
resp_buf += strlen(resp_buf) + 1;
}
return 0;
}
//parse response using keyword
uint16_t MODULE_ATRespParse(MODULE_Typedef *module, uint8_t *keyword, uint8_t *resp_expr, ...)
{
uint16_t resp_args_num = 0;
char *resp_line_buf = MODULE_ATRespGetByKeyword(module, keyword);
va_list args;
if (resp_line_buf) {
va_start(args, resp_expr);
resp_args_num = vsscanf(resp_line_buf, resp_expr, args);
va_end(args);
return resp_args_num;
}
}
int main() {
char opr[20] = {"ERROR"};
uint8_t gpsv1 = 0,gpsv2 = 0,gpsv3 = 0,gpsv4 = 0,gpsv5 = 0,gpsv6 = 0,gpsv7 = 0,gpsv8 = 0,gpsv9 = 0,gpsv10 = 0,gpsv11=0;
uint8_t mode = -1,format = -1,act = -1;
MODULE_Typedef resp1 = {
.res_buf = {"+CREG: 0,2,AIRTEL,45"},
.line_counts = 1,
};
printf("\r\n\r\n\r\nbuffer res1 = %s\r\n",resp1.res_buf);
MODULE_ATRespParse(&resp1,"+CREG:","+CREG: %d, %d, %[^,]s,%d",&mode,&format,opr,&act);
printf("\r\nmode = %d\nformat = %d\noperator = %s\nnwk = %d\n",mode,format,opr,act);
}
my input buffer:
buffer res1 = +CREG: 0,2,AIRTEL,45
extracted variables from it :
mode = 0
format = 2
operator = AIRTEL
nwk = 255
You have to pass the correct variable pointer according to format specifiers. If you are using %d, It means your argument type shall be int *.
Change your variables type uint8_t to int (for %d)
Change %d to %2 SCNu8 (for uint8_t)
These solutions should be fixed your problem.
godbolt

How to Combine 2 Struct arrays in C

iv tried a lot of solutions to try to get this working (i.e using memcpy etc) I cant seem to find the issue, depending on what I try I either end up with gibberish or SEGV
iv spent a lot of time already googling and trying different ways, i still cant figure out why the arrays won't combine successfully
#include <stdio.h>
#include <stdint.h>
#include <dirent.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/syscall.h>
#include <unistd.h>
#define log_info printf
typedef struct
{
char* name;
//size_t size;
} entry_t;
/* qsort struct comparison function (C-string field) */
static int struct_cmp_by_name(const void* a, const void* b)
{
entry_t* ia = (entry_t*)a;
entry_t* ib = (entry_t*)b;
return strcmp(ia->name, ib->name);
/* strcmp functions works exactly as expected from comparison function */
}
entry_t* get_item_entries(const char* dirpath, int* count)
{
struct dirent* dent;
char buffer[512]; // fixed buffer
int dfd = 0,
n, r = 1; // item counter, rounds to loop
entry_t* p = NULL; // we fill this struct with items
loop:
n = 0;
printf("loop: %d, count:%d\n", r, *count);
// try to open dir
dfd = open(dirpath, O_RDONLY, 0);
if (dfd < 0)
{
printf("Invalid directory. (%s)\n", dirpath);
*count = -1;
return NULL;
}
else
{
printf("open(%s)\n", dirpath);
}
memset(buffer, 0, sizeof(buffer));
while (syscall(SYS_getdents, dfd, buffer, sizeof(buffer)) != 0)
{
dent = (struct dirent*)buffer;
while (dent->d_fileno)
{ // skip `.` and `..`
if (!strncmp(dent->d_name, "..", 2)
|| !strncmp(dent->d_name, ".", 1)) goto skip_dent;
// deal with filtering outside of this function, we just skip .., .
switch (r)
{ // first round: just count items
case 1:
{
// skip special cases
if (dent->d_fileno == 0) goto skip_dent;
break;
}
// second round: store filenames
case 0: p[n].name = strdup(dent->d_name); break;
}
n++;
skip_dent:
dent = (struct dirent*)((void*)dent + dent->d_reclen);
if (dent == (void*)&buffer[512]) break; // refill buffer
}
memset(buffer, 0, sizeof(buffer));
}
close(dfd);
// on first round, calloc for our list
if (!p)
{ // now n holds total item count, note it
p = calloc(n, sizeof(entry_t));
*count = n;
}
// first round passed, loop
r--; if (!r) goto loop;
// report count
printf("%d items at %p, from 1-%d\n", *count, (void*)p, *count);
/* resort using custom comparision function */
qsort(p, *count, sizeof(entry_t), struct_cmp_by_name);
// report items
//for (int i = 0; i < num; ++i) log_error( "%s", p[i].name);
return p;
}
int main(int argc, char* argv[])
{
int HDD_count = -1;
uint32_t total = -1;
int ext_count = -1;
entry_t* e = NULL;
entry_t *HDD = get_item_entries("/mnt/f/n", &HDD_count);
entry_t* ext = get_item_entries("/mnt/f/dls", &ext_count);
total = ext_count + HDD_count;
e = (entry_t*)malloc(sizeof *e * total);
if (e != NULL)
{
for (int i = 1; i < HDD_count; i++)
{
log_info("HDD[%i].name %s\n", i, HDD[i].name);
e[i].name = strdup(HDD[i].name);
}
for (int i = 1; i < ext_count; i++)
{
log_info("ext[%i].name %s\n", i, ext[i].name);
e[i + HDD_count].name = strdup(ext[i].name);
}
}
else
printf("Failed to Allocate the Array");
char tmp[256];
int i = 1, j;
for(j = 1; j <= total; j++)
{
snprintf(&tmp[0], 255, "%s", e[ j].name);
log_info("%i:%s\n", j , tmp);
}
return 0;
}
Here is a rewrite of a snippet of main() that I mentioned in my comment above:
#define CHECK(p, msg) if(!(p)) { printf("%s:%d: %s", __FILE__, __LINE__, msg); return 1;}
...
entry_t *HDD = get_item_entries("/mnt/f/n", &HDD_count);
CHECK(HDD, "HDD failed to get entries");
entry_t *ext = get_item_entries("/mnt/f/dls", &ext_count);
CHECK(ext, "ext failed to get entries");
uint32_t total = HDD_count + ext_count;
entry_t *e = malloc(total * sizeof(*e));
CHECK(e, "malloc failed");
for(int i = 0; i < HDD_count; i++) {
log_info("HDD[%i].name %s\n", i, HDD[i].name);
e[i].name = strdup(HDD[i].name);
}
// write a function instead of duplicating code?
for (int i = 0; i < ext_count; i++) {
log_info("ext[%i].name %s\n", i, ext[i].name);
e[HDD_count + i].name = strdup(ext[i].name);
}
It looks like a short lived program, but I would still free the values from strdup() and e itself.

Core dump generates when Sytemd starts a c program that opens a link every few hours

I am trying to write a program that opens up the google meet link for a particular class four minutes before it starts.
The program works perfectly fine when I run it directly from the command line, but when I launch it using a systemd service, it fails with a core-dump error.
here is the service file:
[Unit]
Description=Simple G Meet Autojoiner
Wants=network.target
After=syslog.target network-online.target
[Service]
Type=simple
ExecStart=/usr/local/bin/sgma
[Install]
WantedBy=multi-user.target
here is the program it's trying to launch:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <libnotify/notify.h>
typedef struct {
int hour;
int min;
char *sub;
char *link;
} Class;
const char FILE_NAME[] = "/schedule.txt";
const int NUM_CLASSES = 24;
void notify(char *class_name)
{
notify_init ("Joining Class");
NotifyNotification * Hello = notify_notification_new (class_name, "Starting in a few mins", "dialog-information");
notify_notification_show (Hello, NULL);
g_object_unref(G_OBJECT(Hello));
notify_uninit();
}
void get_schedule(FILE *file, Class schedule[NUM_CLASSES], int current_day)
{
char line[100];
int hour;
char dayfound = 0;
while(fgets(line, sizeof(line), file)) {
if ((line[0] == '[' && atoi(&line[1]) == current_day)) {
dayfound = 1;
continue;
}
/* Ignore the rest of the file */
if (dayfound && line[0] == '\n') {
dayfound = 0;
break;
}
if (dayfound) {
hour = atoi(strtok(line, ":"));
schedule[hour - 9].hour = hour;
schedule[hour - 9].min = atoi(strtok(NULL, "\t"));
schedule[hour - 9].sub = strdup(strtok(NULL, "\t")); /* We copy it first because strtok returns a pointer */
schedule[hour - 9].link = strdup(strtok(NULL, "\t"));
}
}
}
void join_meet(Class schedule[NUM_CLASSES], time_t now)
{
struct tm *current_local;
int cur_min;
int cur_hour;
int min_left;
for (int i = 0; i < NUM_CLASSES; ++i) {
now = time(NULL);
current_local = localtime(&now);
cur_min = current_local->tm_min;
cur_hour = current_local->tm_hour;
if (schedule[i].hour != -1) {
if (cur_hour <= schedule[i].hour) {
min_left = (schedule[i].hour - cur_hour) * 60 + schedule[i].min - cur_min - 4;
if (min_left < 0) continue;
sleep(min_left * 60);
if (fork() == 0) {
notify(schedule[i].sub);
execlp("xdg-open", "xdg-open", schedule[i].link, NULL);
}
}
}
}
}
int main()
{
time_t now = time(NULL);
struct tm *local = localtime(&now);
int current_day = local->tm_wday;
char full_path[100];
strcpy(full_path, getenv("XDG_DATA_HOME"));
strncat(full_path, FILE_NAME, 100 - strlen(full_path) - 1);
FILE *file = fopen(full_path, "r");
if (file == NULL) {
perror(full_path);
exit(EXIT_FAILURE);
}
Class schedule[NUM_CLASSES];
for (int i = 0; i < NUM_CLASSES; ++i)
schedule[i].hour = -1;
get_schedule(file, schedule, current_day);
fclose(file);
join_meet(schedule, now);
return 0;
}

Comparing contents of files for groupings of words

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!)

libvlc_media_get_duration always returns 0

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.

Resources