read and gather variables in a text file - c

I asked this a while ago but was really vague and I also made some changes to my code.
I have a file that I call "stats.txt" which I open with: (using "C" btw)
fopen("stats.txt", r+)
During the first run of my program, I will ask the user to fill in the variables used to write to the file:
fprintf(fp, "STR: %i(%i)\n", STR, smod);
fprintf(fp, "DEX: %i(%i)\n", DEX, dmod);
etc...
the file looks like this after the programs first run, with all the numbers corresponding to a variable in the program:
Level 1 Gnome Wizard:
STR: 8(-1)
DEX: 14(2)
CON: 14(2)
INT: 13(1)
WIS: 13(1)
CHR: 12(1)
APP: 11(0)
Fort save: 0
Reflex save: 0
Will save: 3
when the program closes and runs for a second time, I have an "IF" statement checking for and displaying text within the "stats.txt" file:
if (fgets(buf, 1000, fp) == NULL)
{
printf("Please enter in your base stats (no modifiers):\n");
enter_stats();
printf("Please indicate your characters level:\n");
printf("I am a level ");
level = GetInt();
Race_check();
spec_check();
printf("------Base saving throws (no modifiers)------\n");
saving_throws();
}
else
{
printf("%s",buf);
}
The problem that I am having is the fact that the program reads the file, but does not transfer any variable values it seems here:
Level 1 Gnome Wizard:
-------------------------
STR: 0(-5)
DEX: 0(-5)
CON: 0(-5)
INT: 0(-5)
WIS: 0(-5)
CHR: 0(-5)
APP: 0(-5)
-----Saving Throws------
Fortitude: 0
Reflex: 0
Will: 0
Can anyone give me their suggestions on how to read the variables as well?
PLease and Thank you

Computers only understand numbers - they don't understand text. This means that you have to write code to convert the numbers (that represent individual characters) back into the values you want and store them somewhere.
For example, you might load the entire file into an "array of char", then search that "array of char" for the 4 numbers that represent STR:, then skip any whitespace (between the STR: and the 0(0)), then convert the character/s 0 into the value 0 and store it somewhere, then check for a ( character, then convert the characters -1 into the value -1 and store it somewhere, then check for the ) character and the newline character \n.
More likely is to arrange the code as a "for each line" loop, where the first characters of a line determine how to process the other characters. E.g. if the first character is - then ignore the line; else if the first 5 characters are level call a function that processes the remainder of the line (1 Gnome Wizard); else if the first few characters are STR:, DEX:, CON, etc call a function to get both numbers (and check for the right brackets, etc); else...
In addition to all this, you should have good error handling. As a rough guide, about half of the code should be checks and error messages (like if( buffer[i] != '(' ) { printf("ERROR: Expecting left bracket after number on line %u", lineNumber); return -1;}).

Related

How do i find the license key for this program?

I'm trying to solve this exercise for university. We have to "crack" a program, which is missing a license file that is required to start the program. We are only working with a Linux shell.
So what I've already done is creating this missing license file. It is an .ini that includes a license-holder and a license key. The only thing i'm looking for now is the correct license key. The task says we should use "strace" and "ltrace" to solve this problem.
This is what i get as an output:
fopen("license.ini", "r") =0x55c088307380
fgets("LicenseHolder=annabell.krause#ex"..., 4096, 0x55c088307380) = 0x7ffe72450860
strncmp("LicenseKey=", "LicenseHolder=annabell.krause#ex"..., 11) = 3
strncmp("LicenseHolder=", "LicenseHolder=annabell.krause#ex"..., 14) = 0
sscanf(0x7ffe72450860, 0x55c08753c16b, 0x7ffe72450800, 0xffffc000) = 1
fgets("LicenseKey=aoeklycf", 4096, 0x55c088307380) = 0x7ffe72450860
strncmp("LicenseKey=", "LicenseKey=aoeklycf", 11) = 0
sscanf(0x7ffe72450860, 0x55c08753c121, 0x7ffe72450840, 0xfffff800) = 1
fgets("LicenseKey=aoeklycf", 4096, 0x55c088307380) = 0
memfrob(0x7ffe72450840, 8, 0, 0xfbad2498) = 0x7ffe72450840
strncmp("KEOAFSIL", "aoeklycf", 8) = -22
fwrite("ERROR: License key is invalid.\n", 1, 31, 0x7faeabe60680
ERROR: License key is invalid.
) = 31
+++ exited (status 1) +++
So I guess the answer lies somewhere within the memfrob and strncmp function at the end. But i don't know what's the next step.
Let's look at the library trace call by call. The important part is in step 5.
Analysis
Open the file
fopen("license.ini", "r") =0x55c088307380
Opens the license file.
Parse the license holder
fgets("LicenseHolder=annabell.krause#ex"..., 4096, 0x55c088307380) = 0x7ffe72450860
Reads a line from the file: LicenseHolder=annabell.krause#ex….
strncmp("LicenseKey=", "LicenseHolder=annabell.krause#ex"..., 11) = 3
Does the line start with LicenseKey=? The return value of 3 means no, it does not.
strncmp("LicenseHolder=", "LicenseHolder=annabell.krause#ex"..., 14) = 0
Does the line start with LicenseHolder=? Yes, it does.
sscanf(0x7ffe72450860, 0x55c08753c16b, 0x7ffe72450800, 0xffffc000) = 1
Unfortunately, ltrace has not dereferenced any of the addresses to show us the contents. We know that 0x7ffe72450860 is the current line, so it's presumably pulling out the e-mail address from the current line.
Parse the license key
fgets("LicenseKey=aoeklycf", 4096, 0x55c088307380) = 0x7ffe72450860
It reads another line: LicenseKey=aoeklycf.
strncmp("LicenseKey=", "LicenseKey=aoeklycf", 11) = 0
Does the line start with LicenseKey=? Yes, it does.
sscanf(0x7ffe72450860, 0x55c08753c121, 0x7ffe72450840, 0xfffff800) = 1
It's parsing the current line. Presumably, it's extracting the license key you entered, aoeklycf, and saving it in a variable for later comparison against the expected license key. Something like sscanf(line, "LicenseKey=%s", licenseKey);.
End-of-file
fgets("LicenseKey=aoeklycf", 4096, 0x55c088307380) = 0
It tries to read another line and hits EOF. Ignore the first argument, it's just showing what was left in the buffer from the last call.
License key comparison
memfrob(0x7ffe72450840, 8, 0, 0xfbad2498) = 0x7ffe72450840
"Encrypts" 8 bytes of some memory area by XORing each byte with 42. This can be reversed by running memfrob() again. I put "encrypts" in air quotes because this can barely be called encryption. It's just a little bit of obfuscation.
Notice that 0x7ffe72450840 is the address from the sscanf() above. It's frobbing the variable I called licenseKey above, the LicenseKey= string it extracted from the input file.
strncmp("KEOAFSIL", "aoeklycf", 8) = -22
This is the money line. It compares actual and expected values and fails.
Error message
fwrite("ERROR: License key is invalid.\n", 1, 31, 0x7faeabe60680) = 31
An error is printed.
Synthesis
But the author doesn't want you to be able to run a simple string search like strings ./program to pull the license key out of the executable. To prevent that you have to enter the frobbed version of the license key in license.ini, not the raw string strings finds.
The code might look something like:
char *expected = "aoeklycf";
char actual[BUFSIZE];
sscanf(line, "LicenseKey=%s", actual);
memfrob(actual);
if (strncmp(actual, expected, strlen(expected)) != 0) {
error("ERROR: License key is invalid.\n");
}
Did you extract aoeklycf from the program? If so, you missed the memfrob() step. license.ini needs to list the "encrypted" version of the license key: KEOAFSIL.

How to read one line at a time from a data file and to perform calculations in it before moving to the next line in C Programming?

I'm a beginner at C programming and I would appreciate some help in order to understand the problem.
Alright so, I have a data file (input.dat) with data like this: (first line) 0 2 3 4 5; (second line) 1 2 3 5 4, (third line and so on...). I'm required to read the data one line at a time until the end of file and print it. This is what I have done so far:
int main(void)
{
float coeffs[5];
FILE *input; /* File pointer to the input file */
fopen_s(&input, "input.dat", "r"); /* Location of the input file */
int count = 0;
/* Loops to read data set*/
while (fscanf_s(input, "%f %f %f %f %f ", &coeffs[0], &coeffs[1], &coeffs[2], &coeffs[3], &coeffs[4]) != EOF)
{
printf("a=%.4f; b=%.4f; c=%.4f; d=%.4f; e=%.4f\n", coeffs[0], coeffs[1], coeffs[2], coeffs[3], coeffs[4]);
count++;
}
return 0;
}
This is showing all of the lines in the data file at once. But this is not what I want. I need to read one line at a time and perform some calculations and conditions for that one line first before I move to the next line. So how can I do that?
Next problem is, for the first line, I need to implement a loop from -10 to +10 with increment of 2 (to get 11 results in total). For example the program will read the first line, display it on the screen, then for the first value -10, the program will calculate and again display something . Then it will do the same for -8, then for -6 and so on until +10. After the 11 results are displayed, the program will then and ONLY then, move to the second line and so on. Hence for each line in the data file, the program will have 11 results. How can I use the loop function with increment of 2 to achieve these 11 results?
I would appreciate if anyone can provide me a simple layout of the structure of the codes which I've to write. NOTE: The formats are a bit different than other compilers as I must use Microsoft Visual Studio to do it.
Add your calculations to your while loop. You are reading one line at a time anyway.
If you want to loop from -10 to 10 with increments of 2, use a for loop.
for(count = -10; count <= 10; count = count + 2)
{
// Calculations
}

Use fscanf to read two lines of integers

I want to ask something that I write in C.
I use the fopen() command to open and read a text file that contains only two lines. in
first line is an integer N number, and in the second line is the N integer numbers that the first line says.
Eg.
-------------- nubmers.txt --------------
8 <-- we want 8 numbers for the 2nd line
16 8 96 46 8 213 5 16 <-- and we have 8 numbers! :)
but I want to take restrictions when the file openend.
the number N should be between 1 ≤ Ν ≤ 1.000.000. If not then show an error message. If the file is ok then the programm continue to run with another code.
Here is what I done until now:
int num;
....
fscanf(fp,"%d",&num); // here goes the fscanf() command
if(num<1 || num>1000000) // set restrictions to integer
{
printf("The number must be 1<= N <= 1.000.000",strerror(errno)); // error with the integer number
getchar(); // wait the user press a key
return 0; // returning an int of 0, exit the program
}
else // if everything works.....
{
printf("work until now"); // Everything works until now! :)
getchar(); // wait the user press a key
return 0; // returning an int of 0, exit the program
}
But the problem is that the restriction checks only for the first line number , it's correct though, but don't read the numbers in the second line.
What I mean is that :
Lets say that I have the number 10 in the first line.
The code will analyze the number, will check for restrictions and will proceed to the 'else' part
else // if everything works.....
{
printf("work until now"); // Everything works until now! :)
getchar(); // wait the user press a key
return 0; // returning an int of 0, exit the program
}
..and it will said that everything is working.
But what if I have 20 numbers in the second line? -when I need only 10
Eg.
-------------- nubmers.txt --------------
10
16 8 96 46 8 213 5 16 8 9 21 5 69 64 58 10 1 7 3 6
So I hoped be as cleared as I could. My question is that I need a code in the program, besides the 1st restriction, that have also another one restriction under the first that will read the second line of the txt file with the numbers and check if there are as many numbers as the first line says!
How do I do that?
If you guys want any other declarations feel free to ask!
Hope I was clear with my problem :)
This will check the number of integers and report too many or not enough. The integers are not saved except for each one being read into the value. Do you want to store each integer?
fscanf(fp,"%d",&num); // here goes the fscanf() command
if(num<1 || num>1000000) // set restrictions to integer
{
printf("The number must be 1<= N <= 1.000.000",strerror(errno)); // error with the integer number
getchar(); // wait the user press a key
return 0; // returning an int of 0, exit the program
}
else // if everything works.....
{
int i = 0;
int value = 0;
while ( fscanf ( fp, "%d", &value) == 1) { // read one integer
i++; // this loop will continue until EOF or non-integer input
}
if ( i > num) {
printf ( "too many integers\n");
}
if ( i < num) {
printf ( "not enough integers\n");
}
getchar(); // wait the user press a key
return 0; // returning an int of 0, exit the program
}
use a loop that takes the first num and checks is is the number of integers in next line:
int z = num;
while(z--){
if (getchar() == EOF)
printf("err")
}
Do it like this:
fscanf(fp,"%d",&num);
// next lines of code (restrictions). Then place the below code before getchar in the else
int temp[num+1];// space to store num integers to temp and 1 space to check for extra number
for(i=0;i<num;i++)
{
if(fscanf(fp,"%d",&temp[i]) != 1)// fscanf will automatically read 2nd line and store them in temp array
//error ! Less numbers in file !
}
if(fscanf(fp,"%d",&temp[num]==1) //if still numbers can be scanned
//Extra numbers found in line 2

C: Write to a specific line in the text file without searching

Hello I have file with text:
14
5 4
45 854
14
4
47 5
I need to write a text to a specific line. For example to the line number 4 (Doesn't matter whether I will append the text or rewrite the whole line):
14
5 4
45 854
14 new_text
4
47 5
I have found function fseek(). But in the documentation is written
fseek(file pointer,offset, position);
"Offset specifies the number of positions (bytes) to be moved from the location specified bt the position."
But I do not know the number of bites. I only know the number of lines. How to do that? Thank you
You can't do that, (text) files are not line-addressable.
Also, you can't insert data in the middle of a file.
The best way is to "spool" to a new file, i.e. read the input line by line, and write that to a new file which is the output. You can then easily keep track of which line you're on, and do whatever you want.
I will assume that you are going to be doing this many times for a single file, as such you would be better indexing the position of each newline char, for example you could use a function like this:
long *LinePosFind(int FileDes)
{
long * LinePosArr = malloc(500 * sizeof(long));
char TmpChar;
long LinesRead = 0;
long CharsRead = 0;
while(1 == read(FileDes, &TmpChar, 1))
{
if (!(LinesRead % 500)
{
LinePosArr = realloc(LinePosArr, (LinesRead + 500) * sizeof(long));
}
if (TmpChar == '\n')
{
LinePosArr[LinesRead++] = CharsRead;
}
CharsRead++;
}
return LinePosArr;
}
Then you can save the index of all the newlines for repeated use.
After this you can use it like so:
long *LineIndex = LinePosFind(FileDes);
long FourthLine = LineIndex[3];
Note I have not checked this code, just written from my head so it may need fixes, also, you should add some error checking for the malloc and read and realloc if you are using the code in production.

What could cause a Labwindows/CVI C program to hate the number 2573?

Using Windows
So I'm reading from a binary file a list of unsigned int data values. The file contains a number of datasets listed sequentially. Here's the function to read a single dataset from a char* pointing to the start of it:
function read_dataset(char* stream, t_dataset *dataset){
//...some init, including setting dataset->size;
for(i=0;i<dataset->size;i++){
dataset->samples[i] = *((unsigned int *) stream);
stream += sizeof(unsigned int);
}
//...
}
Where read_dataset in such a context as this:
//...
char buff[10000];
t_dataset* dataset = malloc( sizeof( *dataset) );
unsigned long offset = 0;
for(i=0;i<number_of_datasets; i++){
fseek(fd_in, offset, SEEK_SET);
if( (n = fread(buff, sizeof(char), sizeof(*dataset), fd_in)) != sizeof(*dataset) ){
break;
}
read_dataset(buff, *dataset);
// Do something with dataset here. It's screwed up before this, I checked.
offset += profileSize;
}
//...
Everything goes swimmingly until my loop reads the number 2573. All of a sudden it starts spitting out random and huge numbers.
For example, what should be
...
1831
2229
2406
2637
2609
2573
2523
2247
...
becomes
...
1831
2229
2406
2637
2609
0xDB00000A
0xC7000009
0xB2000008
...
If you think those hex numbers look suspicious, you're right. Turns out the hex values for the values that were changed are really familiar:
2573 -> 0xA0D
2523 -> 0x9DB
2247 -> 0x8C7
So apparently this number 2573 causes my stream pointer to gain a byte. This remains until the next dataset is loaded and parsed, and god forbid it contain a number 2573. I have checked a number of spots where this happens, and each one I've checked began on 2573.
I admit I'm not so talented in the world of C. What could cause this is completely and entirely opaque to me.
You don't specify how you obtained the bytes in memory (pointed to by stream), nor what platform you're running on, but I wouldn't be surprised to find your on Windows, and you used the C stdio library call fopen(filename "r"); Try using fopen(filename, "rb");. On Windows (and MS-DOS), fopen() translates MS-DOS line endings "\r\n" (hex 0x0D 0x0A) in the file to Unix style "\n", unless you append "b" to the file mode to indicate binary.
A couple of irrelevant points.
sizeof(*dataset) doesn't do what you think it does.
There is no need to use seek on every read
I don't understand how you are calling a function that only takes one parameter but you are giving it two (or at least I don't understand why your compiler doesn't object)

Resources