Editing a line in a text file using temp file C - c

I am trying to edit a line in a textfile but i have an unexpected behavior while i am editing the file. What i want to do is adjust a specific line (points : 100) of a text that looks like. In the function i pass arguments by value the new coins to be adjusted and the offset of the file with ftell->user_point. What i get as an output is weird. I try to copy the rest of the file to a temp,with an edited line, and then copy it back to the original file from the point that i copied to temp.(thats the user_point offset with ftell).
Here is the original fie with entries like that:
...
_______________________________________
nickname : geo
password : cuvctq
Name : george
Surname : papas
points : 100
participated :
past draws : 0
Chosen No. :
future draws : 0
Registered : Sun Feb 05 19:23:50 2012
...
What i get after 2nd edit run is:
...
_______________________________________
nickname : geo
password : cuvctq
Name : george
Surname : papaspoints : 98
participated :
past draws : 0
Chosen No. :
future draws : 0
Registered : Sun Feb 05 19:23:50 2012
...
At the end of the text i get one extra \n after i edit the
file whch is something i dont want :/
and so further edit will spoil the text...
I also get an EXTRA \n at the end of the line which, at least what i think so, is due to "r+" mode which is something that i also dont want...
void coins_adjust(int coins_new,int user_point)
{
int lines,i,ln_point_copy;
char buffer[50],buff_copied[50];
FILE *lottary,*temp;
memset(buff_copied,'\0',sizeof(char)*50);
lottary=fopen("customers.txt","r");
temp=fopen("temp.txt","w");
fseek(lottary,user_point,SEEK_SET);
for (lines=0;lines<5;lines++)
{
memset(buffer,'\0',sizeof(char)*50);
if (lines==5)
ln_point_copy=ftell(lottary); //from TEMP to CUSTOMERS
fgets (buffer ,50 , lottary);
}
coins_new+=atoi(buffer+15);
strncpy(buff_copied,buffer,15); //copy 15 chars and fill with null
memset(buffer,'\0',sizeof(char)*50);
itoa (coins_new,buffer,10); //fix the new line to be entered
strcat(buff_copied,buffer); //the edited line is as it is supposed
strcat(buff_copied,"\n"); //to be with \n at the end.
puts(buff_copied);
printf("%s",buff_copied);fflush(stdout);
fprintf(temp,"%s",buff_copied);
for(i=getc(lottary); i!=EOF; i=getc(lottary)) //copy to temp
{
putc(i, temp);
}
fclose(lottary);
fclose(temp);
temp=fopen("temp.txt","r");
lottary=fopen("customers.txt","r+");
fseek(lottary,ln_point_copy,SEEK_SET);
for(i=getc(temp); i!=EOF; i=getc(temp)) //copy until eof
{
putc(i, lottary);
}
fclose(lottary);fclose(temp);
}
I have debugged the program and everything seems to work at least on what values are passed to the arrays where i store the line chars but i cant see why it ignores the \n of the previous line when i try to copy it back to the original... There seems to be a \r char that i cant get rid of while i copy back to the original...
Thanks in advance.

I was more thinking about something like this:
void change_points(int new_points)
{
FILE *input = fopen("customers.txt", "r");
FILE *output = fopen("temp.txt", "w");
char buffer[256];
while (fgets(buffer, sizeof(buffer), input))
{
/* Look for the correct line */
/* Can also use e.g. "if (strncmp(buffer, "points", 6) == 0)"
* if it's at the start of the line
*/
if (strstr(buffer, "points") != NULL)
{
int old_points;
sscanf(buffer, "%*s : %d ", &old_points);
/* Format how you like it */
fprintf(output, "%-13s: %d\n", "points", new_points + old_points);
}
else
fputs(buffer, output);
}
fclose(output);
fclose(input);
/* The file "temp.txt" now contains the modifeed text */
/* Copy either using "fgets"/"fputs", or using "fread"/"fwrite" */
input = fopen("temp.txt", "r");
output = fopen("customers.txt", "w");
while (fgets(buffer, sizeof(buffer), input))
fputs(buffer, output);
fclose(output);
fclose(input);
}
It's shorter, simpler, maybe more effective (looping over line-by-line instead of char-by-char), and the line you are looking for can be anywhere in the file without you knowing its exact position.

Related

The last character is not printed to a file

I am trying to figure out why using C function strtok is not working properly for me. Here's the problem:
I have a file which contains two types of information: headers and text descriptions. Each line in the file is either a header or part of a text description. A header starts with '>'. The description text follows the header and can span multiple lines. At the end of the text there is an empty line which separates the description from the next header. My aim is to write two separate files: one contains the headers on each line and the other contains the corresponding description on a line by itself. To implement the codes in C, I used fgets to read the file one line at a time into dynamically allocated memory. In order to write the description text on one single line, I used `strtok to get rid of any new line characters exists in the text.
My code is working properly for the header files. However, for the descriptions file, I noticed that the last character of the text is not printed out to the file even though it is printed to the stdout.
FILE *headerFile = fopen("Headers", "w"); //to write headers
FILE *desFile = fopen("Descriptions", "w"); //to write descriptions
FILE *pfile = fopen("Data","r");
if ( pfile != NULL )
{
int numOfHeaders =0;
char **data1 = NULL; //an array to hold a header line
char **data2 = NULL; //an array to hold a description line
char line[700] ; //maximum size for the line
while (fgets(line, sizeof line, pfile ))
{
if(line[0] =='>') //It is a header
{
data1 = realloc(data1,(numOfHeaders +1)* sizeof(*data1));
data1[numOfHeaders]= malloc(strlen(line)+1);
strcpy(data1[numOfHeaders],line);
fprintf(headerFile, "%s",line);//writes the header
if(numOfHeaders >0)
fprintf(desFile, "\n");//writes a new line in the desc file
numOfHeaders++;
}
//it is not a header and not an empty line
if(line[0] != '>' && strlen(line)>2)
{
data2 = realloc(data2,(numOfHeaders +1)* sizeof(*data2));
data2[numOfHeaders]= malloc(strlen(line)+1);
char *s = strtok(line, "\n ");
strcpy(data2[numOfHeaders],s);
fprintf(desFile, "%s",data2[numOfHeaders]);
printf(desFile, "%s",data2[numOfHeaders]);
}
} //end-while
fclose(desFile);
fclose(headerFile);
fclose(pfile );
printf("There are %d headers in the file.\n",numOfHeaders);
}
As mentioned in the comments:
fprintf(desFile, "%s",data2[numOfHeaders]); //okay
printf(desFile, "%s",data2[numOfHeaders]); //wrong
Second line should be:
printf("%s",data2[numOfHeaders]); //okay
Or, you could do this:
sprintf(buffer, "%s",data2[numOfHeaders]);
fprintf(desFile, buffer);
printf(buffer);
Other possible issues:
Without an input file it is not possible to know for certain what strtok() is doing, but here is a guess based on what you have described:
In these two lines:
data2[numOfHeaders]= malloc(strlen(line)+1);
char *s = strtok(line, "\n ");
if the string contained in data2 has any embedded spaces, s will only contain the segment occurring before that space. And because you are only calling it once before line gets refreshed:
while (fgets(line, sizeof line, pfile ))
only one token (the very first segment) will be read.
Not always, but Normally, strtok() is called in a loop:
char *s = {0};
s= strtok(stringToParse, "\n ");//make initial call before entering loop
while(s)//ALWAYS test to see if s contains new content, else NULL
{
//do something with s
strcpy(data2[numOfHeaders],s);
//get next token from string
s = strtok(NULL, "\n ");//continue to tokenize string until s is null
}
But, as I said above, you are calling it only once on that string before the content of the string is changed. It is possible then, that the segment not printing has simply not yet been tokenized by strtok().

C Linux fscanf not reading all of line

I'm working with some code written by someone else to scan key value string pairs from a config file. The code is:
void readProfile(char * profileName) {
FILE *f;
int i=0;
f = fopen(profileName, "r");
if (NULL != f) {
while (fscanf(f, "%s%s", &pvtProperties[i].key[0],
&pvtProperties[i].value[0]) == 2) {
i++;
}
fclose(f);
}
numberOfProperties = i;
setCurrentProfileName(profileName);
}
However when reading this plaintext config file below, it has a problem with the 4th line:, the value is truncated to "https://dev.xxxx.com:58443/services/PvtTransferSer". Each line of the config file is separated by \r\n. From that point on the reading of the rest of the file is messed up, values becoming keys etc. Why is this happening? The keys and values are char arrays of 80 chars each.
Config file:
PASSWORD xxxx
REMOTE_UPDATES_ENABLE 1
REMOTE_DIAGNOSTICS_ENABLE 1
PVT_TRANSFER_WS_ADDRESS https://www.xxxx.com:58443/services/PvtTransferService
PVT_DIAGNOSTIC_WS_ADDRESS https://www.xxxx.com:58443/services/PvtDiagnosticService
PVT_UPDATE_WS_ADDRESS https://www.xxxx.com:58443/services/PvtUpdateService
PVT_ADJUSTMENT_WS_ADDRESS https://www.xxxx.com:58443/services/PvtAdjustmentService
DAILY_RESTART_ENABLE 1
HOUR_PAST_MIDNIGHT_FOR_RESTART 7
MAX_RESTART_RANDOMIZATION_SECONDS 30
MINIMUM_UPTIME_SECONDS_BETWEEN_RESTARTS 7200
CLEAR_CACHE_ON_RESTART_ENABLE 0
MINIMUM_SECONDS_BETWEEN_REMOTE_UPDATE_CHECKS 3600
SECONDS_BETWEEN_CONTROLLER_CONFIGURATION_CHECKS 300
CONNECTIVITY_LOSS_DETECTION_ENABLE 1
SMART_COMM_ENABLE 1
TIME_SYNC_ENABLE 1
FACTORY_RESET_ENABLE 1
CM_POLL_PROTOCOL http
You can solve your phase issue by using fgets to pull a line in at a time from the file; then sscanf to parse that line buffer for each record.

How to open a file with a user inputted variable in C?

I'm writing a POS program as a school assignment. I'm using multiple txt files as a database. The program is suppose to allow the user to enter a SKU number (e.g. 123) then it will open a txt file in a database (e.g. database/123.txt). It then pull info from the txt file such as a price and allow the user to add multiple files and end with a total. The user can also add to the database by creating new SKUs. They are also able to view transaction history. The issue I am having is I can't seem to figure out how to record a number from a user and then use that number to open a text file beginning with that number. (e.g. use enters 123 then 123.txt is opened.)
Here is the section of my code that I need help with:
// Function to start a transaction
int transaction(void)
{
// Define Variables
char buf[1000], nDatabase[100];
float nPrice[500], nTotal;
// Instructions
printf("You have started a transaction.\n");
printf("Enter the SKU number below.\n");
printf("Enter 0 to complete the transaction.\n");
// Begin loop here
do
{
FILE *ptr_file;
// record SKU number
/*remove test tools later*/
printf("we r here\n");
scanf("Enter the SKU: %c\n", &nDatabase);
printf("now we r here\n");
// Open database file
/*Change location later*/
ptr_file = fopen("database/123.txt", "r");
// If file is not found return 1
if (!ptr_file)
{
printf("Could not match that SKU number.\n");
return 1;
}
while (fgets(buf, 1000, ptr_file) != NULL)
printf("%s\n", buf);
scanf("%s", &nPrice[0]);
// Close file
fclose(ptr_file);
while (nDatabase == 0);
nTotal = nPrice[0] + nPrice[1];
printf("Your total is: $%.2f\n", &nTotal);
return 0;
}
}
printf( "Enter the SKU: " ) ; // <-- scanf if only for input, the prompt must be output separately
scanf( "%s\n", nDatabase);
// ^ ^
// | |_No & here - nDatabase is an array
// |
// |_Accept a string not a character
Then you might form a complete file name with sprintf, e.g.
char filename[MAX_FNAME] ;
sprintf( filename, "database/%s,txt", nDatabase ) ;
Be aware that no error checking or overrun protection is performed by the above - you may want to consider adding some.
You need to concatenate the user input with you database path, and extension.
Check this post: C string append

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.

Why does my program read an extra structure?

I'm making a small console-based rpg, to brush up on my programming skills.
I am using structures to store character data. Things like their HP, Strength, perhaps Inventory down the road. One of the key things I need to be able to do is load and save characters. Which means reading and saving structures.
Right now I'm just saving and loading a structure with first name and last name, and attempting to read it properly.
Here is my code for creating a character:
void createCharacter()
{
char namebuf[20];
printf("First Name:");
if (NULL != fgets(namebuf, 20, stdin))
{
char *nlptr = strchr(namebuf, '\n');
if (nlptr) *nlptr = '\0';
}
strcpy(party[nMember].fname,namebuf);
printf("Last Name:");
if (NULL != fgets(namebuf, 20, stdin))
{
char *nlptr = strchr(namebuf, '\n');
if (nlptr) *nlptr = '\0';
}
strcpy(party[nMember].lname,namebuf);
/*Character created, now save */
saveCharacter(party[nMember]);
printf("\n\n");
loadCharacter();
}
And here is the saveCharacter function:
void saveCharacter(character party)
{
FILE *fp;
fp = fopen("data","a");
fwrite(&party,sizeof(party),1,fp);
fclose(fp);
}
and the loadCharacter function
void loadCharacter()
{
FILE *fp;
character tempParty[50];
int loop = 0;
int count = 1;
int read = 2;
fp= fopen("data","r");
while(read != 0)
{
read=fread(&tempParty[loop],sizeof(tempParty[loop]),1,fp);
printf("%d. %s %s\n",count,tempParty[loop].fname,tempParty[loop].lname);
loop++;
count++;
}
fclose(fp);
}
So the expected result of the program is that I input a name and last name such as 'John Doe', and it gets appended to the data file. Then it is read in, maybe something like
1. Jane Doe
2. John Doe
and the program ends.
However, my output seems to add one more blank structure to the end.
1. Jane Doe
2. John Doe
3.
I'd like to know why this is. Keep in mind I'm reading the file until fread returns a 0 to signify it's hit the EOF.
Thanks :)
Change your loop:
while( fread(&tempParty[loop],sizeof(tempParty[loop]),1,fp) )
{
// other stuff
}
Whenever you write file reading code ask yourself this question - "what happens if I read an empty file?"
You have an algorithmic problem in your loop, change it to:
read=fread(&tempParty[loop],sizeof(tempParty[loop]),1,fp);
while(read != 0)
{
//read=fread(&tempParty[loop],sizeof(tempParty[loop]),1,fp);
printf("%d. %s %s\n",count,tempParty[loop].fname,tempParty[loop].lname);
loop++;
count++;
read=fread(&tempParty[loop],sizeof(tempParty[loop]),1,fp);
}
There are ways to ged rid of the double fread but first get it working and make sure you understand the flow.
Here:
read=fread(&tempParty[loop],sizeof(tempParty[loop]),1,fp);
printf("%d. %s %s\n",count,tempParty[loop].fname,tempParty[loop].lname);
You are not checking whether the read was successful (the return value of fread()).
while( 1==fread(&tempParty[loop],sizeof*tempParty,1,fp) )
{
/* do anything */
}
is the correct way.
use fopen("data","rb")
instead of fopen("data","r") which is equivalent to fopen("data","rt")
You've got the answer to your immediate question but it's worth pointing out that blindly writing and reading whole structures is not a good plan.
Structure layouts can and do change depending on the compiler you use, the version of that compiler and even with the exact compiler flags used. Any change here will break your ability to read files saved with a different version.
If you have ambitions of supporting multiple platforms issues like endianness also come into play.
And then there's what happens if you add elements to your structure in later versions ...
For robustness you need to think about defining your file format independently of your code and having your save and load functions handle serialising and de-serialising to and from this format.

Resources