I have many objects saved in a file as the following form:
{
"name":"name1",
"city":"city1",
"phone":"125698745663"
},
I have a file that content objects as these last, So I would write a function that take as parameter a file, then give us as an output a list of strings, every string is an object of the file, for example name1 city1 125698745663.
Actually I found that a little hard and I have been searching many days for that, I don't want to use libraries already exist cause I have read many documentation but they was difficult to understand for me.
I tried to write some functions.
That's my essay:
#include<stdlib.h>
/*
{
"name":"name1",
"city":"city1",
"phone":"125698745663"
}
/* Boxes of my list */
typedef_struct box
{
char* current_string;
box* next;
}box;
/* Define the structure of the list that I'll return after*/
typedef_struct list
{
box* beginning;
}list;
/*The function that return the list of the objects that existed in our files*/
**char lire (FILE* my_file) //It is possibly to put the path of the file as an argument
{
char* nameFile;
printf("enter the name of the file");
scanf("%s", &nameFile);
my_file = fopen( "nameFile","r");
if (my_file != NULL)
{
box* temp;
int i=0;
list* my_list;
int first_time = 0;
/* browse file elements */
do
{
char c = fgetc(my_file);
/* I put the following condition to get the value without its key*/
if(c == ":")
{
while(c!=",")
{
temp->current_string[i] = c;
i++;
// printf("%c",c);
c=fgetc(my_file);
}
}
/*I put this condition to pass to the following element of the list and fill it*/
if(c == "}")
{
first_time++;
/*This condition is for getting the begining of the list because it is what distinguishes the list*/
if(first_time==1)
my_list->beginning->current_string = temp->current_string;
temp = temp->next;
}
} while (c != EOF);
fclose(my_file);
}
return my_list;
}```
Well, I believe that C, especially without JSON library like cjson is not the appropriate tool to do that.
You might have a look to a list of command-line tools related to JSON:
https://ilya-sher.org/2018/04/10/list-of-json-tools-for-command-line/
I think the best is to download a command-line tool (pre-compiled if possible) and extract the information you need.
An example how to use jq:
Get outputs from jq on a single line
You can download jq from here:
https://stedolan.github.io/jq/download/
EDIT: give an example
After jq download, you can use it from the command line cmd.exe:
jq-win64.exe
jq - commandline JSON processor [version 1.6]
Usage: jq-win64.exe [options] <jq filter> [file...]
jq-win64.exe [options] --args <jq filter> [strings...]
jq-win64.exe [options] --jsonargs <jq filter> [JSON_TEXTS...]
...
test.json
[{
"name":"name1",
"city":"city1",
"phone":"125698745663"
},
{
"name":"name2",
"city":"city2",
"phone":"125698745663"
}
]
jq command line:
> jq-win64.exe ".[]|.name+\",\"+.city+\",\"+.phone" test.json
"name1,city1,125698745663"
"name2,city2,125698745663"
.[] basically means that one wants to iterate over a JSON array.
|.name basically means that one wants to extract name, add a , and .city and so on.
Related
=============================================================
edit : im sorry it seems like i havent explained well
what my program does is
open file for reading => load list from the file => operations chosen by user will be applies to list (not file)(add-search-display-reset)\ => import change to file(in case there is any)
if the user chooses to only add an employee and quit will it be better to append the added node to the end of file, close and free list or its okay to open file for reading and overwrite all the nodes from the beggining
this last option will save me a lot of lines of code but will it save time and energy for the user while execution ?
=============================================================
i am workig on a (c language) school project where we have to use both lists and files to :
display a list of employees
add employees
search an employee
reset list
save and quit
so i am looking for the best way to do it, and as i know a good code is the one that ensures the program uses as less memory as it can and be as fast as it can.
what i am asking you is
after opening the file that contains the infos of employees and loadig it to the list, and modifying the list by add or reset, would it be better to :
open the file for "w" and fill it with the list.
or open it for "a+" to add from last employee.
note that this last way i will have to memorize the initial_number_of_lines (aka nodes) and look for the 'initial last node' to start loading from it.
note : the employee variables are first_name last_name and salary; VERIFY(file) returns 1 i file opened returns 0 if not;
void load_file(list *list, char *filename)
{
if (current_number_of_lines != initial_number_of_lines || list_reset == 1)
{
if (current_number_of_lines > initial_number_of_lines && list_reset == 0)
{
FILE *file = fopen(filename, "a+");
if (VERIFY(file) == 1)
{
for (int i = 0; i < initial_number_of_lines; i++)
{
list = list->next;
}
while (list != NULL)
{
fprintf(file, "%s\t%s\t%lf\n", list->emp.Fname, list->emp.Lname, list->emp.salary);
list = list->next;
}
}
fclose(file);
}
else if (list_reset == 1)
{
FILE *file = fopen(filename, "w");
while (list != NULL)
{
fprintf(file, "%s\t%s\t%lf\n", list->emp.Fname, list->emp.Lname, list->emp.salary);
list = list->next;
}
fclose(file);
}
else
printf("Error\n");
}
freeList(list);
}
If all your add operations adds the new node to the end of the list, you will get better performance using a+. On the other hand, the code will be more simple if you always rewrite the the whole file. So what is most important for you? Performance or simple code? I would start with the simple approach.
Some other notes.
It's pretty strange that you call the function load_file when it actually writes the file.
The variables: current_number_of_lines, initial_number_of_lines, list_reset seem to be global variables. Using global variables is something you should avoid.
The logic (aka if statements) seems too complicated. You can simply do:
void load_file(list *list, char *filename)
{
if (list_reset == 1)
{
...
}
else if (current_number_of_lines > initial_number_of_lines)
{
...
}
else if (current_number_of_lines < initial_number_of_lines)
{
printf("Error\n");
}
freeList(list);
}
If you use "w" to fopen() then it will truncate file to zero length or create text file for writing. The stream is positioned at the beginning of the file. You have to write all records to the file.
If you use "a+" to fopen() then the file will be open for reading and appending (writing at end of file). The file is created if it does not exist. Output is always appended to the end of the file. Warning: POSIX is silent on what the initial read position is when using this mode. In the mode, you will only write records that needs to be added.
Please also note that neither of the methods are well suited for sharing the data between two or more applications.
If new records are added at the end of the list, obviously it is faster to append those records ate the end of the file ("a+" mode).
Since you have a text file (made of text lines), it is unfortunately not possible to update the changed records. In that case, you must write everything from the list to the file ("w" mode).
If you change you file format in order to use a fixed size record then you can optimize the writing by positioning the file on the record and then write. For that, you'll define your record as a struct containing fixed size strings. And of course add an item in that struct to remember where it has been read from the list.
I create a code in C to find all file names in a directory, this code is recursive so if it finds other directories within this will review the others directories. The search in the directory and the search of files works well,, because i printed on screen what the program read and i realized that find all filenames and does not repeat any filename. The problem i have is that i saves into an array of strings of characters the file name found, and when you find all the files i will have in the main the arrangement of strings with all the file names, but when i printed on screen that arrangement there is not all the files in it, but a few repeated files names. The ultimate goal of this program is not print all file names in screen, the purpose is to save in the arrangement all the file names .I can not see the error, if someone can tell me something that I'm doing wrong I'll be grateful.
void findfiles(char *root,char *p[],int *tam){
DIR * dir;
struct dirent *entrada;
struct stat stt;
dir = opendir(root);
char *aux;
char nombre[BUFFER_TAM];
char buf[30];
if (dir == NULL) {
printf("hola4\n");
return;
}
while ((entrada = readdir(dir)) != NULL) {
if (strcmp(entrada->d_name,".")==0 || strcmp(entrada->d_name,"..")==0);
else {
if (entrada->d_type == DT_DIR){
strcpy(nombre,root);
strcat(nombre,"/");
strcat(nombre,entrada->d_name);
findfiles(nombre,p,tam);
}
else {
strcpy(nombre,root);
strcat(nombre,"/");
strcat(nombre,entrada->d_name);
p[*tam]=malloc(strlen(nombre)+1);
p[*tam]=nombre;
*tam = *tam +1;
}
}
}
}
void main(){
char *archivos[BUFFER_TAM];
char root[BUFFER_TAM]="/home/jesusmolina/Documentos";
int i=0,tam=0;
findfiles(root,archivos,&tam);
for (i;i<tam;i++)
printf("%s\n",archivos[i]);
}
p[*tam]=malloc(strlen(nombre)+1);
p[*tam]=nombre;
You allocate a chunk of memory, then immediately lose the pointer to that memory and leak it. You probably wanted:
p[*tam]=malloc(strlen(nombre)+1);
strcpy(p[*tam], nombre);
I'm writing a function/method in C that is supposed to do the following:
/** * Recieves the list of arguments and copies to conffile the name
of * the configuration file. * Returns 1 if the default file name
was used or 2 if * the parameter -f existed and therefor the
specified name was used. Returns 0 if there is a -f * parameter
but is invalid. (last argument)
*/
Basically one of these two option will be "asked" by the program:
1- controller -f FCFS|LOOK
2- controller FCFS|LOOK
If the second is asked, we enter the case of using the default name.
int get_conf_name(char* argv[], char* conffile) {
// Searches for -f
s = strstr(*argv, "-f");
if(s != NULL){
if(//its valid){
strcpy(conffile, //the name of the file which comes after -f
return 2
}
else return 0
}
else{
strcpy(confile, "config.vss")
return 1
}
}
The problem here is how do I get the word after -f and copy it to confile? And, can I access argv the same way I access conffile, since one of them is an array?
I thought of using a for loop and a strlen, but that would be a lot of unecessary work for the computer wouldn't it?
I think the assignment expects you to go through the individual arguments one by one, comparing them to "-f".
If you see no -f, you know that the default file needs to be used
If you see the flag in the final position, you know that the -f is invalid
If you see the flag in the position k, then the file name will be in argv[k+1]
The skeleton of your program should look like this:
bool foundFlag = false;
for (int i = 1 ; i < argc ; i++) {
if (strcmp(argv[i], "-f") == 0) {
if (i == argc-1) {
// Error
} else {
// argv[i+1] is the file name;
}
foundFlag = true;
break;
}
}
if (!foundFlag) {
// Default name is used
}
I have been trying to implement a way to make my program bilingual : the user could chose if the program should display French or English (in my case).
I have made lots of researches and googling but I still cannot find a good example on how to do that :/
I read about gettext, but since this is for a school's project we are not allowed to use external libraries (and I must admit I have nooo idea how to make it work even though I tried !)
Someone also suggested to me the use of arrays one for each language, I could definitely make this work but I find the solution super ugly.
Another way I thought of is to have to different files, with sentences on each line and I would be able to retrieve the right line for the right language when I need to. I think I could make this work but it also doesn't seem like the most elegant solution.
At last, a friend said I could use DLL for that. I have looked up into that and it indeed seems to be one of the best ways I could find... the problem is that most resources I could find on that matter were coded for C# and C++ and I still have no idea how I would do to implement in C :/
I can grasp the idea behind it, but have no idea how to handle it in C (at all ! I do not know how to create the DLL, call it, retrieve the right stuff from it or anything >_<)
Could someone point me to some useful resources that I could use, or write a piece of code to explain the way things work or should be done ?
It would be seriously awesome !
Thanks a lot in advance !
(Btw, I use visual studio 2012 and code in C) ^^
If you can't use a third party lib then write your own one! No need for a dll.
The basic idea is the have a file for each locale witch contains a mapping (key=value) for text resources.
The name of the file could be something like
resources_<locale>.txt
where <locale> could be something like en, fr, de etc.
When your program stars it reads first the resource file for specified locale.
Preferably you will have to store each key/value pair in a simple struct.
Your read function reads all key/value pair into a hash table witch offers a very good access speed. An alternative would be to sort the array containing the key/value pairs by key and then use binary search on lookup (not the best option, but far better than iterating over all entries each time).
Then you'll have to write a function get_text witch takes as argument the key of the text resource to be looked up an return the corresponding text in as read for the specified locale. You have to handle keys witch have no mapping, the simplest way would be to return key back.
Here is some sample code (using qsort and bsearch):
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define DEFAULT_LOCALE "en"
#define NULL_ARG "[NULL]"
typedef struct localized_text {
char* key;
char* value;
} localized_text_t;
localized_text_t* localized_text_resources = NULL;
int counter = 0;
char* get_text(char*);
void read_localized_text_resources(char*);
char* read_line(FILE*);
void free_localized_text_resources();
int compare_keys(const void*, const void*);
void print_localized_text_resources();
int main(int argc, char** argv)
{
argv++;
argc--;
char* locale = DEFAULT_LOCALE;
if(! *argv) {
printf("No locale provided, default to %s\n", locale);
} else {
locale = *argv;
printf("Locale provided is %s\n", locale);
}
read_localized_text_resources(locale);
printf("\n%s, %s!\n", get_text("HELLO"), get_text("WORLD"));
printf("\n%s\n", get_text("foo"));
free_localized_text_resources();
return 0;
}
char* get_text(char* key)
{
char* text = NULL_ARG;
if(key) {
text = key;
localized_text_t tmp;
tmp.key = key;
localized_text_t* result = bsearch(&tmp, localized_text_resources, counter, sizeof(localized_text_t), compare_keys);
if(result) {
text = result->value;
}
}
return text;
}
void read_localized_text_resources(char* locale)
{
if(locale) {
char localized_text_resources_file_name[64];
sprintf(localized_text_resources_file_name, "resources_%s.txt", locale);
printf("Read localized text resources from file %s\n", localized_text_resources_file_name);
FILE* localized_text_resources_file = fopen(localized_text_resources_file_name, "r");
if(! localized_text_resources_file) {
perror(localized_text_resources_file_name);
exit(1);
}
int size = 10;
localized_text_resources = malloc(size * sizeof(localized_text_t));
if(! localized_text_resources) {
perror("Unable to allocate memory for text resources");
}
char* line;
while((line = read_line(localized_text_resources_file))) {
if(strlen(line) > 0) {
if(counter == size) {
size += 10;
localized_text_resources = realloc(localized_text_resources, size * sizeof(localized_text_t));
}
localized_text_resources[counter].key = line;
while(*line != '=') {
line++;
}
*line = '\0';
line++;
localized_text_resources[counter].value = line;
counter++;
}
}
qsort(localized_text_resources, counter, sizeof(localized_text_t), compare_keys);
// print_localized_text_resources();
printf("%d text resource(s) found in file %s\n", counter, localized_text_resources_file_name);
}
}
char* read_line(FILE* p_file)
{
int len = 10, i = 0, c = 0;
char* line = NULL;
if(p_file) {
line = malloc(len * sizeof(char));
c = fgetc(p_file);
while(c != EOF) {
if(i == len) {
len += 10;
line = realloc(line, len * sizeof(char));
}
line[i++] = c;
c = fgetc(p_file);
if(c == '\n' || c == '\r') {
break;
}
}
line[i] = '\0';
while(c == '\n' || c == '\r') {
c = fgetc(p_file);
}
if(c != EOF) {
ungetc(c, p_file);
}
if(strlen(line) == 0 && c == EOF) {
free(line);
line = NULL;
}
}
return line;
}
void free_localized_text_resources()
{
if(localized_text_resources) {
while(counter--) {
free(localized_text_resources[counter].key);
}
free(localized_text_resources);
}
}
int compare_keys(const void* e1, const void* e2)
{
return strcmp(((localized_text_t*) e1)->key, ((localized_text_t*) e2)->key);
}
void print_localized_text_resources()
{
int i = 0;
for(; i < counter; i++) {
printf("Key=%s value=%s\n", localized_text_resources[i].key, localized_text_resources[i].value);
}
}
Used with the following resource files
resources_en.txt
WORLD=World
HELLO=Hello
resources_de.txt
HELLO=Hallo
WORLD=Welt
resources_fr.txt
HELLO=Hello
WORLD=Monde
run
(1) out.exe /* default */
(2) out.exe en
(3) out.exe de
(4) out.exe fr
output
(1) Hello, World!
(2) Hello, World!
(3) Hallo, Welt!
(4) Hello, Monde!
gettext is the obvious answer but it seems it's not possible in your case. Hmmm. If you really, really need a custom solution... throwing out a wild idea here...
1: Create a custom multilingual string type. The upside is that you can easily add new languages afterwards, if you want. The downside you'll see in #4.
//Terrible name, change it
typedef struct
{
char *french;
char *english;
} MyString;
2: Define your strings as needed.
MyString s;
s.french = "Bonjour!";
s.english = "Hello!";
3: Utility enum and function
enum
{
ENGLISH,
FRENCH
};
char* getLanguageString(MyString *myStr, int language)
{
switch(language)
{
case ENGLISH:
return myStr->english;
break;
case FRENCH:
return myStr->french;
break;
default:
//How you handle other values is up to you. You could decide on a default, for instance
//TODO
}
}
4: Create wrapper functions instead of using plain old C standard functions. For instance, instead of printf :
//Function should use the variable arguments and allow a custom format, too
int myPrintf(const char *format, MyString *myStr, int language, ...)
{
return printf(format, getLanguageString(myStr, language));
}
That part is the painful one : you'll need to override every function you use strings with to handle custom strings. You could also specify a global, default language variable to use when one isn't specified.
Again : gettext is much, much better. Implement this only if you really need to.
the main idea of making programs translatable is using in all places you use texts any kind of id. Then before displaying the test you get the text using the id form the appropriate language-table.
Example:
instead of writing
printf("%s","Hello world");
You write
printf("%s",myGetText(HELLO_WORLD));
Often instead of id the native-language string itself is used. e.g.:
printf("%s",myGetText("Hello world"));
Finally, the myGetText function is usually implemented as a Macro, e.g.:
printf("%s", tr("Hello world"));
This macro could be used by an external parser (like in gettext) for identifying texts to be translated in source code and store them as list in a file.
The myGetText could be implemented as follows:
std::map<std::string, std::map<std::string, std::string> > LangTextTab;
std::string GlobalVarLang="en"; //change to de for obtaining texts in German
void readLanguagesFromFile()
{
LangTextTab["de"]["Hello"]="Hallo";
LangTextTab["de"]["Bye"]="Auf Wiedersehen";
LangTextTab["en"]["Hello"]="Hello";
LangTextTab["en"]["Bye"]="Bye";
}
const char * myGetText( const char* origText )
{
return LangTextTab[GlobalVarLang][origText ].c_str();
}
Please consider the code as pseudo-code. I haven't compiled it. Many issues are still to mention: unicode, thread-safety, etc...
I hope however the example will give you the idea how to start.
I have looked around at the libxml2 code samples and I am confused on how to piece them all together.
What are the steps needed when using libxml2 to just parse or extract data from an XML file?
I would like to get hold of, and possibly store information for, certain attributes. How is this done?
I believe you first need to create a Parse tree. Maybe this article can help, look through the section which says How to Parse a Tree with Libxml2.
libxml2 provides various examples showing basic usage.
http://xmlsoft.org/examples/index.html
For your stated goals, tree1.c would probably be most relevant.
tree1.c: Navigates a tree to print
element names
Parse a file to a tree, use
xmlDocGetRootElement() to get the root
element, then walk the document and
print all the element name in document
order.
http://xmlsoft.org/examples/tree1.c
Once you have an xmlNode struct for an element, the "properties" member is a linked list of attributes. Each xmlAttr object has a "name" and "children" object (which are the name/value for that attribute, respectively), and a "next" member which points to the next attribute (or null for the last one).
http://xmlsoft.org/html/libxml-tree.html#xmlNode
http://xmlsoft.org/html/libxml-tree.html#xmlAttr
I found these two resources helpful when I was learning to use libxml2 to build a rss feed parser.
Tutorial with SAX interface
Tutorial using the DOM Tree (code example for getting an attribute value included)
Here, I mentioned complete process to extract XML/HTML data from file on windows platform.
First download pre-compiled .dll form http://xmlsoft.org/sources/win32/
Also download its dependency iconv.dll and zlib1.dll from the same page
Extract all .zip files into the same directory. For Ex: D:\demo\
Copy iconv.dll, zlib1.dll and libxml2.dll into c:\windows\system32 deirectory
Make libxml_test.cpp file and copy following code into that file.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <libxml/HTMLparser.h>
void traverse_dom_trees(xmlNode * a_node)
{
xmlNode *cur_node = NULL;
if(NULL == a_node)
{
//printf("Invalid argument a_node %p\n", a_node);
return;
}
for (cur_node = a_node; cur_node; cur_node = cur_node->next)
{
if (cur_node->type == XML_ELEMENT_NODE)
{
/* Check for if current node should be exclude or not */
printf("Node type: Text, name: %s\n", cur_node->name);
}
else if(cur_node->type == XML_TEXT_NODE)
{
/* Process here text node, It is available in cpStr :TODO: */
printf("node type: Text, node content: %s, content length %d\n", (char *)cur_node->content, strlen((char *)cur_node->content));
}
traverse_dom_trees(cur_node->children);
}
}
int main(int argc, char **argv)
{
htmlDocPtr doc;
xmlNode *roo_element = NULL;
if (argc != 2)
{
printf("\nInvalid argument\n");
return(1);
}
/* Macro to check API for match with the DLL we are using */
LIBXML_TEST_VERSION
doc = htmlReadFile(argv[1], NULL, HTML_PARSE_NOBLANKS | HTML_PARSE_NOERROR | HTML_PARSE_NOWARNING | HTML_PARSE_NONET);
if (doc == NULL)
{
fprintf(stderr, "Document not parsed successfully.\n");
return 0;
}
roo_element = xmlDocGetRootElement(doc);
if (roo_element == NULL)
{
fprintf(stderr, "empty document\n");
xmlFreeDoc(doc);
return 0;
}
printf("Root Node is %s\n", roo_element->name);
traverse_dom_trees(roo_element);
xmlFreeDoc(doc); // free document
xmlCleanupParser(); // Free globals
return 0;
}
Open Visual Studio Command Promt
Go To D:\demo directory
execute cl libxml_test.cpp /I".\libxml2-2.7.8.win32\include" /I".\iconv-1.9.2.win32\include" /link libxml2-2.7.8.win32\lib\libxml2.lib command
Run binary using libxml_test.exe test.html command(Here test.html may be any valid HTML file)
You can refere this answer.
here they store data into structure format and use further by passing structure address to a function.
You can find detail code in c for use.
code ->> this