I have defined some structs and I have created a function that reads the data from a XML and inserts it into a DialogueRules struct.
Everything should work, but after the execution some values remain untouched, even if they should. I have debugged and I have discovered that they are set properly, but when I exit the dialogue_load funcion they lose their values. (I runned Valgrind and it does not find anything weird)
After more debugging, I have discovered that some pointers, like dr->l_topic[1].name, point to a direction in the main, point to another one inside dialogue_load, and they point to the original function when I go back to the main.
I do not have a single clue about why it fails, what is the cause?
The code is as follows:
DialogueRules * dr=create_dialog(); //Reserve memory for the pointer
printf("t0: %d \n",dr->l_topic[1].name); //The pointer has the original value
dialogue_load("rules.xml",dr); //Loads the xml
printf("t2: %d \n",dr->l_topic[1].name); //The pointer has the original value
Dialogue_load is
STATUS dialogue_load(char * file_name,DialogueRules *dr){
printf("t1: %d \n",dr->l_topic[1].name);//The pointer has another value!
//Load the xml
xmlDocPtr doc;
xmlNodePtr node;
if (!file_name) {
return ERROR;
}
if ((doc = xmlParseFile(file_name))== NULL) {
fprintf(stderr,"File %s has not XML format.\n", file_name);
return ERROR;
}
node = xmlDocGetRootElement(doc);
if (node == NULL) {
fprintf(stderr, "Empty document\n");
xmlFreeDoc(doc);
return ERROR;
}
if (xmlStrcmp(node->name, (const xmlChar*) ROOT)) {
fprintf(stderr,"Expected <%s>, instead of %s\n", ROOT, node->name);
xmlFreeDoc(doc);
return ERROR;
}
node = node->xmlChildrenNode;
while(node != NULL) {
if (!xmlStrcmp(node->name, (const xmlChar*) RULES)) {
dreader_process_rules(doc, node->xmlChildrenNode, dr);
}
else if (!xmlStrcmp(node->name, (const xmlChar*) TOPICS)) {
dreader_process_topics(doc, node->xmlChildrenNode, dr);
}
node = node->next;
}
xmlFreeDoc(doc);
return OK;
}
Create_dialog is
DialogueRules *create_dialog() {
DialogueRules * dialog = (DialogueRules*)malloc(sizeof(DialogueRules));
dialog->num_rules=0;
dialog->num_topic=0;
return dialog;
}
The structs are the following:
typedef struct _Topic
{
Id id;
char name[WORD_SIZE+1]; /* topic name */
Set * topic_rules; /* set of rule indexes associated with a topic */
} Topic;
typedef struct _Rule
{
Id id; /* rule identifier */
char * pattern [MAX_PATTERNS];/* If the string matches any of these input patterns, then executes this rule */
int num_patterns;/* number of patterns */
char * template [MAX_PATTERNS]; /* List of pos sible templates that can be used as a response */
int num_templates; /* number of possible answers */
int last; /* Last used template */
} Rule;
typedef struct _DialogueRules
{
Rule l_rule[MAX_RULES]; /* vector to store rules */
int num_rules; /* number of rules stored in l_rule */
Topic l_topic[MAX_TOPICS]; /* vector to store topics */
int num_topic; /* number of topicsstored in l_topic */
} DialogueRules;
EDIT:
The output when using %p is:
t0: 0x7f57d20afe98
t1: 0x7f57d20afe80
t2: 0x7f57d20afe98
Edit 2:
The makefile rule for main is:
main.o: main.c
$(CC) ${CFLAGS} ${CXML2} -c main.c -o main.o
and for dialoguerrulesreader(which contains dialog_rule) is
DialogueRulesReader.o: DialogueRulesReader.c DialogueRulesReader.h
${CC} ${CXML2} -c $< ${LXML2}
(Take in account that
CC=gcc -ggdb
CFLAGS=-Wall -pedantic -ansi
CXML2=`xml2-config --cflags`
LXML2=`xml2-config --libs`
)
As discovered in comments; you should use the same CFLAGS to build all units. It turned out that using different flags (particularly -ansi on one file, and no standard specification on the other) caused the structs to have different sizes in two different units.
Related
Well, I am trying to append data using C programming and libxml2 modulel but am facing a lot of problems as I am fairly new to this.
My code is designed to first fetch me an Element Node from the XML file based on the user input and then grab the parent of that child node and append another child in it.
XML FILE:
<policyList>
<policySecurity>
<policyName>AutoAdd</policyName>
<deviceName>PA-722</deviceName>
<status>ACTIVE</status>
<srcZone>any</srcZone>
<dstZone>any</dstZone>
<srcAddr>5.5.5.5</srcAddr>
<dstAddr>5.5.5.4</dstAddr>
<srcUser>any</srcUser>
<application>any</application>
<service>htds</service>
<urlCategory>any</urlCategory>
<action>deny</action>
</policySecurity>
<policySecurity>
<policyName>Test-1</policyName>
<deviceName>PA-710</deviceName>
<status>ACTIVE</status>
<srcZone>any</srcZone>
<dstZone>any</dstZone>
<srcAddr>192.168.1.23</srcAddr>
<dstAddr>8.8.8.8</dstAddr>
<srcUser>vivek</srcUser>
<application>any</application>
<service>http</service>
<urlCategory>any</urlCategory>
<action>deny</action>
</policySecurity>
</policyList>
C CODE:
int main(){
xmlDocPtr pDoc = xmlReadFile("/var/www/db/db_policy.xml", NULL, XML_PARSE_NOBLANKS | XML_PARSE_NOERROR | XML_PARSE_NOWARNING | XML_PARSE_NONET);
if (pDoc == NULL)
{
fprintf(stderr, "Document not parsed successfully.\n");
return 0;
}
root_element = xmlDocGetRootElement(pDoc);
if (root_element == NULL)
{
fprintf(stderr, "empty document\n");
xmlFreeDoc(pDoc);
return 0;
}
printf("Root Node is %s\n", root_element->name);
xmlChar* srcaddr = "5.5.5.5";
xmlChar *xpath = (xmlChar*) "//srcAddr";
xmlNodeSetPtr nodeset;
xmlXPathObjectPtr result;
int i;
xmlChar *keyword;
xmlXPathContextPtr context;
xmlNodePtr resdev;
xmlChar* resd;
context = xmlXPathNewContext(pDoc);
if (context == NULL) {
printf("Error in xmlXPathNewContext\n");
}
result = xmlXPathEvalExpression(xpath, context);
xmlXPathFreeContext(context);
if (result == NULL) {
printf("Error in xmlXPathEvalExpression\n");
}
if(xmlXPathNodeSetIsEmpty(result->nodesetval)){
xmlXPathFreeObject(result);
printf("No result\n");
};
if (result) {
nodeset = result->nodesetval;
for (i=0; i < nodeset->nodeNr; i++) {
keyword = xmlNodeListGetString(pDoc, nodeset->nodeTab[i]->xmlChildrenNode, 1);
printf("keyword: %s\n", keyword);
if(strcmp(keyword, srcaddr) == 0){
xmlNodePtr pNode = xmlNewNode(0, (xmlChar*)"service");
xmlNodeSetContent(pNode, (xmlChar*)"nonser");
xmlAddSibling(result, pNode);
printf("added");
}
xmlFree(keyword);
}
xmlXPathFreeObject (result);
}
xmlFreeDoc(pDoc);
xmlCleanupParser();
return (1);
}
On running this code, it gets compiled and executed(with a few warnings, but nothing that hinders execution), but it does not add anything to my XML File.
I think this topic is old but I just had a similar problem. So, I am just sharing for those who still have similar problems.
On running this code, it gets compiled and executed(with a few warnings, but nothing that hinders execution), but it does not add anything to my XML File.
First of all: In my opinion warnings in C are so much worse than errors because it lets you run the wrong code. So, my very first advice is not to ignore the warnings (although I am not in a position to advise anyone but anyway).
Second: When I was running this code, I saw a warning which makes sense:
> warning: passing argument 1 of ‘xmlAddSibling’ from incompatible
> pointer type [-Wincompatible-pointer-types]
>
> note: expected ‘xmlNodePtr {aka struct _xmlNode *}’ but argument is of
> type ‘xmlXPathObjectPtr {aka struct _xmlXPathObject *}’
As you check the xmlAddSibling from http://www.xmlsoft.org/html/libxml-tree.html you can see:
xmlNodePtr xmlAddSibling (xmlNodePtr cur, xmlNodePtr elem)
Which means the type of both of the arguments should be of xmlNodePtr. However, "result" has the type of xmlXPathObjectPtr which means the pointer types are completely different. What you really want to do is to add a child to a parent that you have found based on the string that you compared: (if(strcmp(keyword, srcaddr) == 0)).
So your way to find the parent is completely correct. But two problems are: first you never updated the "result" (if we assume you imagined the "result" is the parent which is not correct) because "nodeset->nodeTab[i]" is in a for loop that never puts anything in "result". The second problem is even if you updated the "result" based on "nodeset->nodeTab[i]", still they have different types of the pointers (as we discussed previously). So, you have to use xmlAddSibling for the correct parent and with the correct pointer type. As you can see hereunder, the "nodeTab" has the type of "xmlNodePtr" which we were looking for, and "nodeset->nodeTab[i]" is the parent.
Structure xmlNodeSet
struct _xmlNodeSet {
int nodeNr : number of nodes in the set
int nodeMax : size of the array as allocated
> `xmlNodePtr * nodeTab : array of nodes in no particular order`
}
So you should change the:
xmlAddSibling(result, pNode);
to:
xmlAddSibling(nodeset->nodeTab[i], pNode);
Finally: you didn't save the changes. So, save it by adding
xmlSaveFileEnc("note.xml", pDoc, "UTF-8");
before
xmlFreeDoc(pDoc);
With these changes, I was able to run your code with your XML file and with no warnings.
Your commands modify the DOM representation of the XML in memory, but you missed writing it back to the file. So adding the following line should solve your problem:
...
}
// write back to file:
xmlSaveFileEnc("/var/www/db/db_policy.xml", pDoc, "UTF-8");
xmlFreeDoc(pDoc);
xmlCleanupParser();
return (1);
The purpose of this code is to read the following txts(d.txt,e.txt,f.txt) and do the actions that are required in order to put the alphabet with the correct order into the output.txt. The code suppose to work since in output.txt i get the correct results but there is a problem with the testing i did using the printf (it's at the end of newfile function). In order to run i give as input d.txt and output.txt.
It should print
top->prev points to file :d
top->prev points to file :e
but instead it prints the following and i can't find the reason
top->prev points to file :d
top->prev points to file :f
d.txt:
abc
#include e.txt
mno
e.txt:
def
#include f.txt
jkl
f.txt:
ghi
code:
%{
#include <stdio.h>
#include <stdlib.h>
struct yyfilebuffer{
YY_BUFFER_STATE bs;
struct yyfilebuffer *prev;
FILE *f;
char *filename;
}*top;
int i;
char temporal[7];
void newfile(char *filename);
void popfile();
void create();
%}
%s INC
%option noyywrap
%%
"#include " {BEGIN INC;}
<INC>.*$ {for(i=1;i<strlen(yytext)-2;i++)
{
temporal[i-1]=yytext[i];
}
newfile(temporal);
BEGIN INITIAL;
}
<<EOF>> {popfile();
BEGIN INITIAL;
}
%%
void main(int argc,int **argv)
{
if ( argc < 3 )
{
printf("\nUsage yybuferstate <filenamein> <filenameout>");
exit(1);
}
else
{
create();
newfile(argv[1]);
yyout = fopen(argv[2], "w");
yylex();
}
system("pause");
}
void create()
{
top = NULL;
}
void newfile(char *filename)
{
struct yyfilebuffer *newptr;
if(top == NULL)
{
newptr = malloc(1*sizeof(struct yyfilebuffer));
newptr->prev = NULL;
newptr->filename = filename;
newptr->f = fopen(filename,"r");
newptr->bs = yy_create_buffer(newptr->f, YY_BUF_SIZE);
top = newptr;
yy_switch_to_buffer(top->bs);
}
else
{
newptr = malloc(1*sizeof(struct yyfilebuffer));
newptr->prev = top;
newptr->filename = filename;
newptr->f = fopen(filename,"r");
newptr->bs = yy_create_buffer(newptr->f, YY_BUF_SIZE);
top = newptr;
yy_switch_to_buffer(top->bs); //edw
}
if(top->prev != NULL)
{
printf("top->prev points to file : %s\n",top->prev->filename);
}
}
void popfile()
{
struct yyfilebuffer *temp;
temp = NULL;
if(top->prev == NULL)
{
printf("\n Error : Trying to pop from empty stack");
exit(1);
}
else
{
temp = top;
top = temp->prev;
yy_switch_to_buffer(top->bs);
system("pause");
}
}
You need to think about how you manage memory, remembering that C does not really have a string type in the way you might be used to from other languages.
You define a global variable:
char temporal[7];
(which has an odd name, since globals are anything but temporary), and then fill in its value in your lexer:
for(i=1;i<strlen(yytext)-2;i++) {
temporal[i-1]=yytext[i];
}
There are at least three problems with the above code:
temporal only has room for a six-character filename, but nowhere do you check to make sure that yyleng is not greater than 6. If it is, you will overwrite random memory. (The flex-generated scanner sets yyleng to the length of the token whose starting address is yytext. So you might as well use that value instead of computing strlen(yytext), which involves a scan over the text.)
You never null-terminate temporal. That's OK the first time, because it has static lifetime and will therefore be filled with zeros at program initialization. But the second and subsequent times you are counting on the new filename to not be shorter than the previous one; otherwise, you'll end up with part of the previous name at the end of the new name.
You could have made much better use of the standard C library. Although for reasons I will note below, this does not solve the problem you observe, it would have been better to use the following instead of the loop, after checking that yyleng is not too big:
memcpy(temporal, yytext + 1, yyleng - 2); /* Copy the filename */
temporal[yyleng - 2] = '\0'; /* NUL-terminate the copy */
Once you make the copy in temporal, you give that to newfile:
newfile(temporal);
And in newfile, what we see is:
newptr->filename = filename;
That does not copy filename. The call to newfile passed the address of temporal as an argument, so within newfile, the value of the parameter filename is the address of temporal. You then store that address in newptr->filename, so newptr->filename is also the address of temporal.
But, as noted above, temporal is not temporary. It is a global variable whose lifetime is the entire lifetime of the program. So the next time your lexical scanner encounters an include directive, it will put it into temporal, overwriting the previous contents. So what then happens to the filename member in the yyfilebuffer structure? Answer: nothing. It still points to the same place, temporal, but the contents of that place have changed. So when you later print out the contents of the string pointed to by that filename field, you'll get a different string from the one which happened to be in temporal when you first created that yyfilebuffer structure.
On the whole, you'll find it easier to manage memory if newfile and popfile "own" the memory in the filebuffer stack. That means that newfile should make a copy of its argument into freshly-allocated storage, and popfile should free that storage, since it is no longer needed. If newfile makes a copy, then it is not necessary for the lexical-scanner action which calls newfile to make a copy; it is only necessary for it to make sure that the string is correctly NUL-terminated when it calls newfile.
In short, the code might look like this:
/* Changed parameter to const, since we are not modifying its contents */
void newfile(const char *filename) {
/* Eliminated this check as obviously unnecessary: if(top == NULL) */
struct yyfilebuffer *newptr = malloc(sizeof(struct yyfilebuffer));
newptr->prev = top;
// Here we copy filename. Since I suspect that you are on Windows,
// I'll write it out in full. Normally, I'd use strdup.
newptr->filename = malloc(strlen(filename) + 1);
strcpy(newptr->filename, filename);
newptr->f = fopen(filename,"r");
newptr->bs = yy_create_buffer(newptr->f, YY_BUF_SIZE);
top = newptr;
yy_switch_to_buffer(top->bs); //edw
if(top->prev != NULL) {
printf("top->prev points to file : %s\n",top->prev->filename);
}
}
void popfile() {
if(top->prev == NULL) {
fprintf(stderr, "Error : Trying to pop from empty stack\n");
exit(1);
}
struct yyfilebuffer temp = top;
top = temp->prev;
/* Reclaim memory */
free(temp->filename);
free(temp);
yy_switch_to_buffer(top->bs);
system("pause");
}
Now that newfile takes ownership of the string passed to it, we no longer need to make a copy. Since the action clearly indicates that you expect the argument to the #include to be something like a C #include directive (surrounded either by "..." or <...>), it is better to make that explicit:
<INC>\".+\"$|"<".+">"$ {
/* NUL-terminate the filename by overwriting the trailing "*/
yytext[yyleng - 1] = '\0';
newfile(yytext + 1);
BEGIN INITIAL;
}
Full disclosure: This is my first time doing any significant programming in C, and my first post on Stack Overflow.
I'm working on code that will eventually be used with Bison to implement a small subset of the Scheme/Racket language. All of this code is in a single C file. I have three structs: Binding, Lambda, and SymbolEntry. I'm not using the Lambda struct yet, it's just there for completeness. I also have a symbol table that holds symbol entries. printSymbolTable() does exactly what the name implies:
typedef struct
{
char* name;
char* value;
} Binding;
typedef struct
{
int numBindings;
Binding** bindings;
char* functionBody;
} Lambda;
typedef struct
{
Binding* binding;
Lambda* function;
} SymbolEntry;
SymbolEntry* symbolTable = NULL;
int numSymbols = 0;
void printSymbolTable()
{
if (symbolTable)
{
int i = 0;
for (i; i < numSymbols; i++)
{
printf("\tsymbolTable[%i]: %s = %s\n", i, symbolTable[i].binding->name, symbolTable[i].binding->value);
}
}
}
I'm currently trying to work out the logic for defining and looking up variables. The 2 relevant functions:
// Takes a name and an exprssion and stores the result in the symbol table
void defineVar(char* name, char* expr)
{
printf("\nSetting %s = %s\n", name, expr);
printf("Previous number of symbols: %i\n", numSymbols);
Binding props;
props.name = name;
props.value = expr;
SymbolEntry entry;
entry.binding = &props;
entry.function = NULL;
symbolTable = realloc(symbolTable, sizeof(SymbolEntry) * ++numSymbols);
if (!symbolTable)
{
printf("Memory allocation failed. Exiting.\n");
exit(1);
}
symbolTable[numSymbols - 1] = entry;
printf("New number of symbols: %i\n", numSymbols);
printf("defineVar result:\n");
printSymbolTable();
}
// Test storing and looking up at least 4 variables, including one that is undefined
void testVars()
{
printf("Variable tests\n");
defineVar("foo", "0");
printf("After returning from defineVar:\n");
printSymbolTable();
defineVar("bar", "20");
printf("After returning from defineVar:\n");
printSymbolTable();
}
main() calls testVars(). I get no warnings or errors when compiling, and the program executes successfully. However, this is the result:
Variable tests
Setting foo = 0
Previous number of symbols: 0
New number of symbols: 1
defineVar result:
symbolTable[0]: foo = 0
After returning from defineVar:
symbolTable[0]: 1�I��^H��H���PTI��# = �E
Setting bar = 20
Previous number of symbols: 1
New number of symbols: 2
defineVar result:
symbolTable[0]: bar = 20
symbolTable[1]: bar = 20
After returning from defineVar:
symbolTable[0]: 1�I��^H��H���PTI��# = �E
symbolTable[1]: 1�I��^H��H���PTI��# = �E���
Not only am I getting junk values when outside of the defineVar() function, but the call to define bar shows incorrect non-junk values as well. I'm not sure what I'm doing wrong, but I assume it's probably something with realloc(). However, a similar strategy worked when parsing a string into individual tokens, so that's what I was trying to emulate. What am I doing wrong?
Because it's pointing to variables (or variable — at least props, haven't read further) local to functions and the stack frame is discarded (and soon overwritten) after you return.
I've got stuck on my homework with SQLite. I use 2 columns; the first for product, the second for count. A user adds new products, which updates the count. We have to control, that the user doesn't add the same product again, or prevent him from picking more units than are available. We have to use it frequently, so I created functions:
int exists(char *param, sqlite3** ppDb) //0 if product exists
{
int error = 0;
char *a = NULL;
sqlite3_stmt **ppStmt = NULL;
const char **pzTail = NULL;
char *zSQL = sqlite3_mprintf("SELECT 'products' FROM 'table' WHERE 'products' LIKE '%q'", param);
//HERE IT FALS
error = sqlite3_prepare_v2(
*ppDb, /* Database handle */
zSQL, /* SQL statement, UTF-8 encoded */
(sizeof(zSQL)+1), /* Maximum length of zSql in bytes. */
ppStmt, /* OUT: Statement handle */
pzTail /* OUT: Pointer to unused portion of zSql */
);
sqlite3_free(zSQL);
a = (char*) sqlite3_column_text(*ppStmt, 0);
return strcmp(a, param); //0 if same -> product is in db yet
}
//similar one for count
Call
int main(int argc, const char *argv[])
{
sqlite3 *pDb;
int error = 0;
//parsing input
error = sqlite3_open(argv[1], &pDb);
if (error == 0)
{
sqlite3_exec(
pDb, /* An open database */
"CREATE TABLE 'table' ('products', 'quantity')", /* SQL */
0, /* Callback function */
NULL, /* 1st argument to callback */
NULL /* Error msg written here */
);
if (exists(param[1], &pDb) == 0)
{
fprintf (stderr, "ERROR: Product exists yet\n");
}
else
{
char *zSQL = sqlite3_mprintf("INSERT INTO 'table' VALUES ('%q', '0')", param[1]);
error = sqlite3_exec(
pDb, /* An open database */
zSQL, /* SQL to be evaluated */
0, /* Callback function */
NULL, /* 1st argument to callback */
NULL /* Error msg written here */
);
sqlite3_free(zSQL);
if (error == 0) printf("Added\n");
else printf("%i", error);
}
}
else return 1;
return 0;
}
It fails on sqlite3_prepare_v2. I expect there is a problem with the pointer on pDb, but I wasn't able to fix it (I'm not fan of pointers - too strong a tool for beginner). When it fails, the debugger stacked on line 93396 in sqlite3.c (*ppStmt = 0; - it writes somewhere, where it should'nt).
Compiled on linux x64:
gcc -std=c99 -Wall -pedantic -Wextra -Werror -DSQLITE_THREADSAFE=0 -ldl -o sqlite main.c sqlite3.c
Nothing wrong (if I've copied wrongly brackets, ignore it - it's not the problem), SQLite 3.7.14.1
Sorry for my English, I'm from Czech.
sqlite3_prepare_v2 wants to write the statement pointer into your output variable, but you are not giving it a pointer to this pointer variable, you are giving it a NULL pointer.
Use:
sqlite3_stmt *pStmt;
sqlite3_prepare_v2(..., &pStmt, ...);
Also note that identifiers should be quoted with "double quotes" or [brackets] or
`backticks`
but not with 'single quotes', which are used for literal strings.
I've got a little problem with an exercise I have to finish. We have to implement a recurisve "ls" program which prints out the "n" biggest files. But there are some problems.
1)
I have three files, main.c, list.c and list.h. In list.h I have included string.h ,stdio.h,stdlib.h,declared a struct (char* filename,long long filesize and struct element* next) and two methods (append,printlist). In list.c I have included list.h and implemented the two methods append and printlist. In main.c I have included unistd.h,dirent.h, sys/stat.h and list.h.
When I try to compile it with "gcc main.c" I get the error "used of undeclared methods append and printlist" but if I'm using Eclipse it builds just fine. How can I solve this?
Exact errors
/tmp/ccLbHnqR.o: In function `main':
main.c:(.text+0x189): undefined reference to `printliste'
/tmp/ccLbHnqR.o: In function `ftop':
main.c:(.text+0x1f6): undefined reference to `append'
2)
To implement the functionality I tried to use a self-sorting list, i.e. go through the list until the last value that is bigger than the new value, then set the pointer of the new value to the pointer of the last value and the pointer of the last value is the new value.
In theory it should work, but in practice it isn't.
The append methods looks like this
void append(struct element **lst, char* filename, long long filesize){
struct element *newElement;
struct element *lst_iter = *lst;
newElement = malloc(sizeof(*newElement)); // create new element
newElement->filename = filename;
newElement->filesize = filesize;
newElement->next = NULL; // important to find the end of the list
if ( lst_iter != NULL ) { // if elements are existing
//if our element is bigger than the first element
if(lst_iter->filesize < newElement->filesize){
newElement->next = lst_iter;
*lst = newElement;
} else {
while(lst_iter->next != NULL){
if(lst_iter->filesize > newElement->filesize) lst_iter = lst_iter->next;
else break;
}
newElement->next = lst_iter->next;
lst_iter->next = newElement;
}
}
else // if the list is empty our value is the new value
*lst=newElement;
}
I'm using this method from my "ftop" method, which gets a directory, adds every file in this directory to the list and for each directory it calls "ftop" again.
void ftop(char* path){
DIR *dir;
struct dirent *ent;
//open the directory
dir = opendir(path);
if (dir != NULL) {
//for each file/directory in it
while ((ent = readdir(dir)) != NULL) {
struct stat st;
//if it is a file, append it to the list
if(S_ISREG(st.st_mode)){
append(&list, ent->d_name, st.st_size);
} else {
//if it is a directory, use recursion
ftop(ent->d_name);
}
}
}
}
But I don't get it why it isn't working. I know you don't want to do the homework of others, but I would be thankful for every hint you could give me.
P.s.: If you want the full code
main.c
list.c
You want
gcc -o main main.c list.c
that is — specify both files.