How to read data from txt file> - c

I have a little problem with reading data from file.
I need to read the name, lastname and phone number.
But the data is separated by '|'.
file e.g.
Matthew | McConaughey | 684299275
Humphrey | Bogart | 204050673
Mary | Tyler Moore | 503462885
Loretta | Young | 416211713
I wrote this function
char name[20];
char lastname[40];
int number;
while(!feof(plik)){
int hpl=fscanf(filename, "%s | %s | %d", name, lastname, &number);
}
I have problem when in the file are two-member lastname like 'Tyler Moore', then fscanf return 2
I don't know how I can read them
That is possible to use one fscanf() function ?

It is because, scanf family functions read until space. You can use fgets to get whole line, and then parse it using function multi_tok function that is shown here: https://stackoverflow.com/a/29789623/8842262

Related

The .txt does not correctly edit the text - C

I'm having a problem with the .txt as I have to create a customer record and then I can change the data. What happens is the following, when I create the client the data looks like this:
enter image description here
But when I go to edit the name or the country, it's like that, and what I wanted is for you to make the change without creating new lines.
Name:
enter image description here
Country:
enter image description here
I'm probably missing something or it's the way to save the file, but I don't know!!
This is my code:
typedef struct {
char name[80];
char country[10];
int tin;
int customer_code;
} CLIENT, upd, add;
void
edit_customer()
{
CLIENT add, upd;
int choice;
FILE *bd;
bd = fopen("bd.txt", "a");
printf("Enter the customer code: ");
scanf("%d", &add.customer_code);
printf("\nSelect the type of change you want:\n1 - Name\n2 - Country\n\nEnter your choice:");
scanf("%d", &choice);
switch (choice) {
case 1:
fgets(upd.name, 80, stdin);
printf("Type your name: ");
scanf("%[^\n]s", upd.name);
fprintf(bd, "code: %d | name: %s | tin: %d | country: %s \n",
add.customer_code, upd.name, add.tin, add.country);
printf("Changes saved!");
break;
case 2:
printf("Enter the Country:");
scanf("%s", upd.country);
fprintf(bd, "code: %d | name: %s | tin: %i | country: %s \n",
add.customer_code, add.name, add.tin, upd.country);
printf("Changes saved!");
break;
}
}
Updating the data in a file is not easy. First of all you have to decide how you intend to save your data because the way you modify the data will depend on this. There are many ways to do this but to keep it simple there are two basic ways. The first way is to insert records of fixed size. practically you have to decide the size of each field of your record and it will always have to be the same for all the records of your file. So, taking your struct as example
typedef struct {
char name[80];
char country[10];
int tin;
int customer_code;
} CLIENT;
you could write the records by modifying the formatting of the fprintf a little, for example in this way:
"| code: %-10u | name: %-20.20s | tin: %-10u | country: %-25.25s |\n"
this way your file will contain records like this (knowing their position in the record you wouldn't really need the name of the fields):
| code: 1234561 | name: Super Mario | tin: 1286608618 | country: know the name |
| code: 23 | name: John | tin: 123 | country: Donknow |
now if you want to modify one of the records present, you will have to search for it in your file by reading line by line and saving, before each reading, where the line begins in your file using for example the ftell function. Found the record, load its fields and modify those you want to change and at this point move the file pointer back to the beginning of the line (fseek function) and overwrite the old record with the one just modified.
If, on the other hand, you do not want to use fixed-size records, as you are doing now, the work becomes a little more complicated because unfortunately the files are not elasticized, so if you need to modify a record that has a different length than the one in the file you have to make room for it. There are a thousand ways to do this but in essence you should:
save the records that are under the one you want to modify in the file
modify the record
cut the file at the end of the record you edited
append the part you previously saved to the file
In truth for safety you should:
create a temporary file
copy the records preceding the one to be modified into the temporary file
append the new record
append the remainder of the file except the old record
save the temporary file (fclose)
delete the old file
rename the temporary file with the name of the file just deleted
Apart from that, as the comments say, in your program you try to modify a record that you have not read from the file, so the one modified by the user is the only field that has a value while the others have not been initialized. However, it is not enough. You will have to follow what I have written to you if you want to see your program work.

passing data to bison grammar from flex

Having an issue with my flex / bison grammar. Not sure if it is the way that I have set up the recursion that is shooting myself in the foot.
When trying to access the data passed via yylval I would use the $1... variable for each element of the production. However when doing this it is not splitting the values into each token. It prints the whole production. This only happens with the second sentence in the metadata production, the first seems to be OK.
I was intending to create a check(int token_val) function that contains a switch(token_val) and checks the return value for each token and then acts on its yytext appropriately. Is there a way to use the $ variable notation that will give me the return value from the commands production? Or is this the incorrect way to go about things?
I have checked the references for this but maybe I have missed something, would appreciate someone to clarify.
Code: bison
input: input metadata
| metadata
;
metadata: command op data {printf("%s is valid.\n", $3);} // check_data($1) ?
| data op data op data op data {printf("row data is valid\n\t %s\n", $1);}
;
command: PROD_TITL
| _DIR
| DOP
| DIT
| FORMAT
| CAMERA
| CODEC
| DATE
| REEL
| SCENE
| SLATE
;
op: EQUALS
| COLON
| SEP
;
data: META
| REEL_ID
| SCENE_ID
| SLATE_ID
| TAKE
| MULTI_T
| LENS
| STOP
| FILTERS
;
%%
int main(void) {
return yyparse();
}
lex:
%{
#include <stdio.h>
#include <string.h>
#include "ca_mu.tab.h"
%}
%option yylineno
%%
\"[^"\n]*["\n] {yylval = yytext; return META;}
[aA-aZ][0-9]+ {yylval = yytext; return REEL_ID;}
([0-9aA-zZ]*\/[0-9aA-zZ]*) {yylval = yytext; return SCENE_ID;}
[0-9]+ {yylval = yytext; return SLATE_ID;}
[0-9][aA-zZ]+ {yylval = yytext; return TAKE;}
[0-9]+-[0-9]+ {yylval = yytext; return MULTI_T;}
[0-9]+MM {yylval = yytext; return LENS;}
T[0-9]\.[0-9]+ {yylval = yytext; return STOP;}
"{"([^}]*)"}" {yylval = yytext; return FILTERS;}
Output sample:
"My Production" is valid.
"Dir Name" is valid.
"DOP Name" is valid.
"DIT Name" is valid.
"16:9" is valid.
"Arri Alexa" is valid.
"ProRes" is valid.
"02/12/2020" is valid.
A001 is valid.
23/22a is valid.
001 is valid.
row data is valid
1, 50MM, T1.8, { ND.3 } // $1 prints all tokens?
row data is valid
3AFS, 50MM, T1.8, {ND.3}
input
/* This is a comment */
production_title = "My Production"
director = "Dir Name"
DOP = "DOP Name"
DIT = "DIT Name"
format = "16:9"
camera = "Arri Alexa"
codec = "ProRes"
date = "02/12/2020"
reel: A001
scene: 23/22a
slate: 001
1, 50MM, T1.8, { ND.3 }
3AFS, 50MM, T1.8, {ND.3}
slate: 002
1, 65MM, T1.8, {ND.3 BPM1/2}
slate: 003
1-3, 24MM, T1.9, {ND.3}
END
The problem is here, in your scanner actions:
yylval = yytext;
You must never do this.
yytext points into a temporary buffer which is only valid until the next call to yylex(), and that means you are effectively making yylval a dangling pointer. Always copy the string, as with:
yylval = strdup(yytext);
(Don't forget to call free() on the copied strings when you no longer need the copies.)
I think your language is too simple and doesn't define the structure of the input. For example:
reel: A001 // repetition of reels, consisting of....
scene: 23/22a // repetition of scenes, consisting of...
slate: 001 // repetition of slates, consisting of...
1, 50MM, T1.8, { ND.3 } // repetition of slate data
This is a structure, so the input is:
movie: metadata reels
;
metadata: /* see your stuff */ ;
reels: reel
| reels reel
;
reel: REEL REEL_ID scenes
;
scenes: scene
| scenes scene
;
scene: SCENE SCENE_ID slates
;
slates: slate
| slates slate
;
slate: SLATE SLATE_ID slate_datas
;
slate_datas: slate_data
| slate_datas slate_data
;
slate_data: /*your stuff*/ ;

how to read data from a file with space ignored?

I have this piece of program that I use to read data from file:
void baca(int *n)
{
FILE *f = fopen("namafile.txt", "r");
if (f)
{
while (fscanf(f, "%[^|]|%d|%[^\n]\n", mhs[*n].nama, &mhs[*n].umur, mhs[*n].hp)==3)
{
(*n)++;
}
}
fclose(f);
}
If I write the data in the file like this, then the program reads it correctly:
nko|20|9999
hotma|21|9982882
andi|30|212313
But when I add some spaces like this, somehow it doesn't read it correctly:
nko | 20 | 9999
hotma | 21 | 9982882
andi | 30 | 212313
Can someone give me some hint on what I should do ?
Add a space to the format string to specify where the input can have optional whitespace
fscanf(f, "%[^|] |%d | %[^\n]\n", ...)
// ^^^ ^^^^^ optional whitespace
The conversion "%d" already includes optional leading whitespace.
If your input strings can get messier in the future, you will do better with a separate parser instead of scanf().

enforce student to fill code inside a blank area in a function

I'm using a web based application to grade a C program submitted by a student. For some questions, I would like the student to fill a code in a function. The following is an example screen that the student will see.
go() {
---------------------------------
| |
| |
| |
---------------------------------
}
main() {
go()
}
The student should fill some code inside a box. However, I don't want the student to create a new function like this:
go() {
---------------------------------
| go_help(); |
| } |
| go_help() { printf("hi"); } |
---------------------------------
}
main() {
go()
}
How can I prevent the student to create a new function? The code template together with the code filled by the student will be sent to the queue waiting to be compiled and run by the server. I cannot change or check the code in that queue. The only thing I can do is to change the code template.
Can you put code in your template that will not be displayed in the web page?
If the user sees this:
void go() {
---------------------------------
| |
| |
| |
---------------------------------
}
int main() {
go();
}
But their code is actually substituted into this:
void go() {
int some_name_the_user_will_never_guess_123axpk = 1;
---------------------------------
| |
| |
| |
---------------------------------
(void) some_name_the_user_will_never_guess_123axpk;
}
int main() {
go();
}
Then it won't compile in the case where the user has closed the go function and opened another. Make sure it isn't compiled with the GNU extension for nested functions, though, or the user could define one of those.
You'd also have to conceal the compiler error message from the user, since it will contain the secret name.
[Edit: As a total bodge, if you define functions with every possible 1-character name except g at the start of the template, then call the function the user writes g instead of go, you could statically assert that sizeof(__func__) == 2. That means you can't be in a different function, because the user couldn't call it by a 1-character name.]
[Another edit: rats, that doesn't work either because the user could end their code with #define sizeof(X) (X, 2), or #define __func__ "g", or some such. That's not legal C, but it will in fact allow the user to cheat on pretty much any compiler. Preprocessors tend not to check that the tokens you use are unreserved names. Maybe if you do the static assert, and also do a bunch of checks that none of the tokens you use in that assert are defined as macros.]
I think catching this at compile time will be very difficult (if not impossible). However, I you're willing to settle with a runtime error, the following might work (tested on GCC):
void go() {
---------------------------------
| |
| |
| |
---------------------------------
//make sure nobody redefines __func__ ...
#undef __func__
//... and __builtin_strcmp
#undef __builtin_strcmp
//check if we're still inside go()
assert(__builtin_strcmp(__func__, "go") == 0);
}
int main() {
go();
}
When the student creates a new function, you will have unballanced curly brakets within the fill-in area: (at least) one extra closing one (to close the current function body) and (at least) one extra opening one (to start the new function body). To figure out if this is the case, you need to check whether the curly braces are ballanced within the fill-in area, which you can only do by parsing the submitted text.

C - Read in file according to a format

I am trying to read a file in a specific file format in c.
the file contains some data items. every data item is seprated by a flag.
the file should look look like this:
file-header: "FIL0"
file-id: 0x1020304
flag : 0|1 : uint8_t
length : uint32_t
char[length] : int utf-8
so its: [File-Header] [FileID] [Flag | Length | Data ] [Flag | Length | Data] ...
--> "FIL0" | 0xFFFFFF | 0 or 1 | Data as char[] | 0 or 1 | ... (next data item) ....
My Problem occurs when reading in the file. My idea is to open the file and scan through it using some sscanf-magic.
FILE *fp;
fp = fopen("data.dat". "r");
/* scan file for data components */
while (fgets(buffer, sizeof buffer, fp) != NULL) /* read in file */
{
/* scan for sequence */
if (sscanf(buffer, "%5s", fil0_header) == 1) /* if the "FIL0" header is found */
{
printf("FIL0-header found: %s\n", buffer);
// proceed and scan for [FLAG] [LENGTH] [DATA]
// sscanf()
if (sscanf(buffer, "%u", node) == 1)
{
// doesnt seem to work
}
// read in length of string and extract stringdata
else
{
printf("FIL0-Header not found, found instead: %s\n", buffer);
// do something
}
}
My problem that I have a hard time with my buffer and the varying data types in the file.
The comparision of fil0-header works alright, but:
how to read in the next hexadeciaml number (sscanf using %D)
how scan for the flag which is 1 byte
how to extract the length which is 4 bytes
A problem is, that the check for the flag starts at the beginning of the buffer.
but the pointer should be moved on, after the FIL0-header is found.
I'd be gratefull for any help!
Please help me to find the proper sscanf() -calls:
and want to read it in and retrieve the single parts of my file:
On single [File-Header]
and many {[FileID] [Flag | Length | Data ]} {...} items
well you could just read the file per byte using
line[0] = (char) fgetc(fp);
line[1] = (char) fgetc(fp);
and so on or leave out the cast to retrieve an int-value... should do the trick to do an easy right to left scan of the file (or line - as you say there arent any line breaks)...
You probably could use some standard parsing techniques, for instance have a lexer and a recursive parser. You should define your input syntax more in details. You could perhaps use parser generators (but it might be overkill for your simple example) like ANTLR ...
I suggest you to read some good textbook on parsing (& compiling), it will learn you a lot of useful stuff.

Resources