I'm using this code to read a file into a buffer. The file is full of structs of evaluacion type (including some char and int variables).
Now I have the whole file in a buffer, how can I find the values of one variable in the buffer now?
For example buf.notamedia < 4. There are supposed to be many of them inside the file.
#include <unistd.h>
#include <sys/stat.h>
int revisanotas(int fd)
{
int nbytes = 1;
int nbytese = 0;
evaluacion buf;
struct stat datos;
fstat(fd, &datos);
printf("Size of file = %d \n", datos.st_size);
char *buffer = (char *)malloc(datos.st_size);
int actual = read(fd, buffer, datos.st_size);
printf("actual = %d\n", actual);
if (buf.notamedia >= 4.5 && buf.notamedia < 5)
{
/* ... */
}
}
Any idea is very welcome
I'm doing as you said, but I'm only getting one iteration, I don't know what I'm doing wrong :(
evaluacion* buffer=(evaluacion*)malloc(datos.st_size);
int actual = read(fd,buffer,datos.st_size);
printf("Number of structs = %d", (datos.st_size/(sizeof(evaluacion))));
for (i=0;i<(datos.st_size/(sizeof(evaluacion)));i++);
{
printf("Notamedia = %f\n",buffer[i].notamedia);
if (buffer[i].notamedia >= 4.5 && buffer[i].notamedia < 5)
{
printf("Notamedia = %f\n",buffer[i].notamedia);
}
{
}
}
}
Easiest to define the buffer as a pointer to the data structure and use that to dereference the data (although you should ensure the file size is a multiple of the structure size).
i.e.
evaluacion* buffer = (evaluation*)malloc(datos.st_size);
if(buffer[0].notamedia >= 4.5)
You can then increment the index to access other structures you loaded.
Thanks for the comments, I think I solved the problem, I modified the code:
#include <unistd.h>
#include <sys/stat.h>
int revisanotas(int fd)
{
int nbytes=1;
int nbytese=0;
int i=0;
int n=0;
struct stat datos;
fstat(fd, &datos);
evaluacion buf;
printf("File size = %d \n", datos.st_size);
evaluacion* buffer=(evaluacion*)malloc(datos.st_size);
int actual = read(fd,buffer,datos.st_size);
do
{
i++;
if (buffer[i].notamedia >= 4.5 && buffer[i].notamedia < 5)
{
n=n+1;
/*printf("Notamedia = %f\n",buffer[i].notamedia);
*/
buffer[i].notamedia=5;
}
}while (i<(datos.st_size/(sizeof(evaluacion))));
nbytese=write(fd,buffer,datos.st_size);
printf("Written bytes = %d\n",nbytese);
return(n);
}
Now, If the condition is matched, I'm modifying the buffer. Once I read all the structs I write the file in the disk again, but I still have a problem, every time, instead of write the file in the same position, seems like I'm adding the same information after the old one, so if I read the file once I get 3.5Mb, two times 7MB and so on :S.
Any idea what can I do?
Thanks
Related
I have a hard time figuring out how to pass an array of structs with strings in them through a pipe to a child process.
I created two demos to show my problem.
demo_int.c
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main()
{
pid_t child;
int pfd[2];
if (pipe(pfd) == -1)
{
exit(1);
}
child = fork();
if (child < 0)
{
exit(1);
}
if (child == 0)
{
close(pfd[1]);
int *arr = malloc(10 * sizeof(int));
if (arr == NULL)
{
exit(1);
}
read(pfd[0], arr, 10 * sizeof(int));
close(pfd[0]);
printf("child process read:\n");
for (int i = 0; i < 10; ++i)
{
printf("%d\n", arr[i]);
}
free(arr);
exit(0);
}
else
{
int *arr = malloc(10 * sizeof(int));
if (arr == NULL)
{
exit(1);
}
for (int i = 0; i < 10; ++i)
{
arr[i] = i;
}
printf("array to be written:\n");
for (int i = 0; i < 10; ++i)
{
printf("%d\n", arr[i]);
}
close(pfd[0]);
write(pfd[1], arr, 10 * sizeof(int));
close(pfd[1]);
free(arr);
printf("parent process done\n");
wait(NULL);
}
}
I created this, so I can be sure that the problem is not with the "dynamic array" part, but with the "structs" part, and maybe more specifically the "string in a struct" part.
This produces the expected result:
array to be written:
0
1
2
3
4
5
6
7
8
9
parent process done
child process read:
0
1
2
3
4
5
6
7
8
9
With valgrind reporting no errors or leaks.
However when I try the same with the problematic structs:
demo_person.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
typedef struct Person
{
char *name;
int age;
} Person;
int main()
{
pid_t child;
int pfd[2];
if (pipe(pfd) == -1)
{
exit(1);
}
child = fork();
if (child < 0)
{
exit(1);
}
if (child == 0)
{
close(pfd[1]);
Person *arr = malloc(10 * sizeof(Person));
if (arr == NULL)
{
exit(1);
}
read(pfd[0], arr, 10 * sizeof(Person));
close(pfd[0]);
printf("child process read:\n");
for (int i = 0; i < 10; ++i)
{
printf("%s %d\n", arr[i].name, arr[i].age);
}
for (int i = 0; i < 10; ++i)
{
free(arr[i].name);
}
free(arr);
exit(0);
}
else
{
Person *arr = malloc(10 * sizeof(Person));
if (arr == NULL)
{
exit(1);
}
for (int i = 0; i < 10; ++i)
{
char *name = malloc(8 * sizeof(char));
if (name == NULL)
{
exit(1);
}
sprintf(name, "%s%d", "Person", i);
arr[i].name = malloc(8 * sizeof(char));
if (arr[i].name == NULL)
{
exit(1);
}
strcpy(arr[i].name, name);
arr[i].age = i;
free(name);
}
printf("array to be written:\n");
for (int i = 0; i < 10; ++i)
{
printf("%s %d\n", arr[i].name, arr[i].age);
}
close(pfd[0]);
write(pfd[1], arr, 10 * sizeof(Person));
close(pfd[1]);
for (int i = 0; i < 10; ++i)
{
free(arr[i].name);
}
free(arr);
printf("parent process done\n");
wait(NULL);
}
}
The output is:
array to be written:
Person0 0
Person1 1
Person2 2
Person3 3
Person4 4
Person5 5
Person6 6
Person7 7
Person8 8
Person9 9
parent process done
child process read:
0
1
2
3
4
5
6
7
8
9
free(): invalid pointer
With valgrind reporting loads of errors (as expected after this output).
I found similiar looking questions, but none of the answers seemed to help.
EDIT:
Thanks to the answer I now understand that the problem is with the dynamically allocated string and only the mallocing process can access it, but the real program in which I encountered this problem has been populated (kind of) like this, as in it already uses these dinamically allocated strings.
Is there a way to pass the strings like this, or do I have to solve it somehow with new char[N] arrays?
The memory you allocate with malloc and the pointer it returns are only valid in the process you do the call to malloc.
When you write the structure through the pipe you only write the (current process unique) pointer, not the memory it points to.
The quick and simple solution is to use an actual array instead:
typedef struct Person
{
char name[10];
int age;
} Person;
What you've stumbled upon is commonly solved using what's known as "serialization," which allows you to reliably send and receive data over a wire (pipe, network socket, file, etc). A popular serialization format is JSON, for its wide support and easy readability, but there's nothing stopping you from creating your own serialization format, and just using that!
A common way to pack binary data reliably is to use a header-payload format, where the header contains information about what kind of data is in the payload, and also how long the payload is. From there, it's as simple as reading in a fixed size header, parsing it, then reading the payload on the receiving end.
Something like this may work for you:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
struct simple_header {
char kind; /* I arbitrarily chose a char, which could use something like 's' for string, 'i' for int, etc. Commonly you will see an enum used here */
int length; /* You could use a negative length to indicate errors of some kind, or just use a simple size_t */
};
struct simple_payload {
unsigned char *data;
};
int serialize_string(int fd, const char *payload) {
// Automatically find the size, for convenience
size_t length = strlen(payload);
// Set aside a header and populate it
struct simple_header header;
header.kind = 's';
header.length = (int) length; // This could be checked better, but also just a simple example
// Send the header over the wire, doing minimal error checking
int ret = write(fd, &header, sizeof(header));
if(ret < 0) return ret;
// Send the payload
ret = write(fd, payload, length);
return ret;
}
int deserialize(int fd, struct simple_payload *destination) {
struct simple_header received_header;
int ret = read(fd, &received_header, sizeof(received_header));
if(ret < 0) return ret;
// This solution totally ignores endianness, which you will need to consider if sending and receiving on different computers
// Always work with zeroed buffers when you can, leave room for NULL bytes
destination->data = calloc(received_header.length + 1, 1);
ret = read(fd, destination->data, received_header.length);
if(ret < 0) {
free(destination->data);
return ret;
}
switch(received_header.kind) {
case 's':
/* do something special for strings */
;
default:
return -1; /* unsupported format */
}
return ret;
}
If this is anything more than a pet project, though, I'd recommend looking into serialization formats and their libraries (header-only will be easiest to integrate). With serialization, the devil really is in the details, the unhandled errors and endianness considerations can lead to data corruption, so if you value the data you're sending, please use a library! My included example does not cover:
when the header lies about payload length
payloads that exceed the length of whats in the header
Failed reads/writes, leading you to think you're reading a header when actually you're reading a payload
Error detection/correction (CRC, Reed-Solomon etc)
Struct alignment issues (packed vs unpacked)
When i try run with the reviews.csv file the code gives segmention
fault don't know why!! Can someone HELP me with that... In
guião1v2.h only are the structs made for this. In the code i add
some comments for being much easier understand what i'm doing.
I don't know how to fix this!!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "guião1v2.h"
#define COUNT 1024
#define MAX_LINE 10000000 //random num (the files given are big)
int main(int arg , char*argv[]){
int i = 0;
char buffer[COUNT];
char *buffer2 = malloc(COUNT);
User *user = malloc(sizeof(User)*MAX_LINE);
Review *reviews = malloc(sizeof(Review)*MAX_LINE);
//i do the allocation of memory.
FILE *files;
files = fopen(argv[1],"r"); //opening the file
if(files == NULL)
{
printf("Failed to open file");//in case of fail to open the file
exit(1);
}
if(strcmp(argv[1], "reviews.csv") == 0)
{
while (fgets(buffer2,COUNT,files))//trying to pass from the file to the struct
{
reviews[i].id = strdup(strsep(&buffer2,";"));
reviews[i].user_id =strdup(strsep(&buffer2,";"));
reviews[i].business_id =srdup(strsep(buffer2,";"));
reviews[i].stars = atof(strsep(&buffer2,";"));
reviews[i].useful = atoi(strsep(&buffer2,";"));
reviews[i].funny = atoi(strsep(&buffer2,";"));
reviews[i++].cool = atoi(strsep(&buffer2,";"));
}
for(int j=0; j < i-1; j++)//testing if the data was well copied.
{
printf("%s", reviews[j].id); //param
printf("%s", reviews[j].user_id); //param
printf("%s", reviews[j].business_id); //param
printf("%f", reviews[j].stars); //param
printf("%d", reviews[j].useful); //param
printf("%d", reviews[j].funny);
printf("%d", reviews[j].cool);
printf("\n");
}
}
fclose(files); // When i don't need the file i close it
free(user);//I give free to the memory
free(reviews);// Same thing
free(buffer2);
return 0;
}
Segmentation faults occurs only incase there are some memory issues. The code above uses command line argument as well as dynamic allocation through malloc.
I suggest remove the command line arguments from main() to make the code looks simpler. The problem here related to memory so try to specify memory statically not dynamically using malloc(),calloc() etc.
I recently got an assignment to sort members in a struct by last name and if they are the same to sort by first name. What i have so far only reads their name and age from the file but I am not properly grapsing how I would be able to sort it. So far I gathered the data from the file but im at a loss from there. I followed a code I saw but i didnt get a proper grasping of the process so i reverted back to step one.
struct Members{
int id;
char fname[50];
char lname[50];
int age;
}bio;
int main(){
int i=0;
FILE *fptr;
file = fopen("Members Bio.txt", "r");
while ( fscanf(file, "%d%s%s%d", &bio[i].id,bio[i].fname,bio[i].lname,&bio[i].age) != EOF)
{
printf("%d %s %s %d %d\n", bio[i].id,bio[i].fname, bio[i].lname, bio[i].age);
i++;
}
fclose(fptr);
}
Can anyone help me out on this one?
Code goes something like this for your case.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Members{
int id;
char fname[50];
char lname[50];
int age;
};
typedef int (*compare_func)(void*, void*);
int struct_cmp(void* s1, void* s2)
{
int l_result = strcmp(((struct Members*) s1)->lname, \
((struct Members*) s2)->lname);
if (l_result < 0)
return 1;
else if (l_result > 0)
return 0;
else
return (strcmp(((struct Members*) s1)->fname, \
((struct Members*) s2)->fname) < 0 ? 1 : 0);
}
void sort(void* arr,long ele_size,long start,long end,compare_func compare)
{
// Generic Recursive Quick Sort Algorithm
if (start < end)
{
/* Partitioning index */
void* x = arr+end*ele_size;
long i = (start - 1);
void* tmp=malloc(ele_size);
for (long j = start; j <= end - 1; j++)
{
if ((*compare)(arr+j*ele_size,x))
{
i++;
// Swap is done by copying memory areas
memcpy(tmp,arr+i*ele_size,ele_size);
memcpy(arr+i*ele_size,arr+j*ele_size,ele_size);
memcpy(arr+j*ele_size,tmp,ele_size);
}
}
memcpy(tmp,arr+(i+1)*ele_size,ele_size);
memcpy(arr+(i+1)*ele_size,arr+end*ele_size,ele_size);
memcpy(arr+end*ele_size,tmp,ele_size);
i= (i + 1);
sort(arr,ele_size,start, i - 1,compare);
sort(arr,ele_size,i + 1, end,compare);
}
}
int main()
{
FILE* fp;
int bio_max = 3;
struct Members bio[bio_max]; // Define bio to be large enough.
/* Open FILE and setup bio matrix */
/* For testing */
bio[0].id = 0;
strcpy(bio[0].fname, "");
strcpy(bio[0].lname, "Apple");
bio[0].age = 0;
bio[1].id = 1;
strcpy(bio[1].fname, "");
strcpy(bio[1].lname, "Cat");
bio[1].age = 1;
bio[2].id = 2;
strcpy(bio[2].fname, "");
strcpy(bio[2].lname, "Bat");
bio[2].age = 2;
/* Sort the structure */
sort(bio, sizeof(struct Members), 0, bio_max - 1, struct_cmp);
/* Print the sorted structure */
for (int i = 0; i < bio_max; i++) {
printf("%d %s %s %d\n", bio[i].id, bio[i].fname, \
bio[i].lname, bio[i].age);
}
}
Output
0 Apple 0
2 Bat 2
1 Cat 1
If the strings are not sorting in the way you want, you can redefine the struct_cmp function. Code is self explanatory, the base logic in the code is pass an array and swap elements using memcpy functions. You cant use simple assignment operator if you want to be generic, so that is why the element size is explicitly passed.
Edit
The code was not handling the condition, if lname are same. I missed it thanks for #4386427 for pointing this out.
I think you should define bio to be an array. And google sort algorithms please. Also recommend you google how to use libc function qsort.
it's my first post so I apologize in advance if I've posted the code format wrong.
I've been trying to work out where I'm going wrong here for awhile now and haven't been able to find an answer. I keep getting a segmentation fault after two Lines of a text file have been scanned into my arrays. Text file follows the pattern of : City1 City2 distance.
I feel like it has something to do with the memory but I can't understand why.
#include <stdio.h>
#include <stdlib.h>
#include <string.h> //Chosen to use this library to break text file down.
#include "list.h" //Using file created in lab 3 earlier this year.
#define DYNAMIC_RESIZE 0 ///Might not be needed...
#define Max_Lines 40
#define LINE_SIZE 150
int main()
{
FILE *Distances_File = fopen("Distances.txt", "r");
char *City1[Max_Lines];
char *City2[Max_Lines];
int *Distances[Max_Lines];
City1[Max_Lines] = malloc(sizeof(Max_Lines));
City2[Max_Lines] = malloc(sizeof(Max_Lines));
Distances[Max_Lines] = malloc(sizeof(Max_Lines));
char File_Line[LINE_SIZE];
int Line_Count = 0;
if (!Distances_File) {
printf("File could not open");
return 1;
}
if ( Distances_File != NULL )
{
///Intro to the program.
printf("This is a program that will calculate the shortest distance between selected \ncities.");
printf("\nSo wish me luck :(\n \n");
while(fgets(File_Line, sizeof(File_Line), Distances_File))
{
//printf("%s", File_Line);
sscanf(File_Line, "%s%s%s", City1[Line_Count], City2[Line_Count], Distances[Line_Count]);
///Still issue of Distances being a char.
printf("%s\n%s\n%s\n\n", City1[Line_Count], City2[Line_Count], Distances[Line_Count]);
Line_Count++;
printf("%d", Line_Count);
}
}
}
This statement
char *City1[Max_Lines];
declare an array of char pointers and the size of the array is Max_Lines.
And here you are allocating memory to an invalid index of the array:
City1[Max_Lines] = malloc(sizeof(Max_Lines));
Max_Lines value is 40, so the valid index of the array of size Max_Lines will be 0-39.
You need to allocate memory to all the pointers of array City1 and City2 before using them.
May you write a function to perform this allocation, like this:
void allocate_city_mem(char *arr[], size_t sz) {
for(size_t i = 0; i < sz; i++) {
arr[i] = malloc(LINE_SIZE);
if (NULL == arr[i])
exit(EXIT_FAILURE);
}
}
In doing so, you need to make sure to free the dynamically allocated memory once you have done with it. You can do:
void free_city_mem(char *arr[], size_t sz) {
for(size_t i = 0; i < sz; i++) {
free(arr[i]);
arr[i] = NULL;
}
}
In your program, I can see that the Max_Lines and LINE_SIZE are small values, so as an alternative you can do this:
char City1[Max_Lines][LINE_SIZE];
With this, you don't need to take care of any allocation/deallocation of memory.
Also, no need to take the array of integer pointer for storing distance. Distances could be an array of integers.
In your code, you are calling fopen() and checking the return value of it (if (!Distances_File) {....) somewhere below in the code after calling malloc. As a good programming practice, you should immediately check the return value of library function in such cases because if they fail, there is no point in proceeding further.
Also, when using scanf family functions, make sure that format specifier corresponding to the parameter passed should be correct.
Collectively all above points, the main() will be something like this:
int main() {
FILE *Distances_File = fopen("Distances.txt", "r");
if (!Distances_File) {
printf("File could not open");
return 1;
}
char City1[Max_Lines][LINE_SIZE];
char City2[Max_Lines][LINE_SIZE];
int Distances[Max_Lines];
char File_Line[LINE_SIZE];
int Line_Count = 0;
//Intro to the program.
printf("This is a program that will calculate the shortest distance between selected \ncities.");
printf("\nSo wish me luck :(\n \n");
while(fgets(File_Line, sizeof(File_Line), Distances_File)) {
printf("Line number : %d\n", Line_Count+1);
//printf("%s", File_Line);
sscanf(File_Line, "%s%s%d", City1[Line_Count], City2[Line_Count], &Distances[Line_Count]);
///Still issue of Distances being a char.
printf("%s\n%s\n%d\n\n", City1[Line_Count], City2[Line_Count], Distances[Line_Count]);
Line_Count++;
}
return 0;
}
You have undefined behavior accessing City1[Max_Lines] where the size of the array is Max_Lines. You should change it instead allocate memory and make those pointers point to it. So you will do something like this:-
#define MAXLEN 100
...
for(size_y i = 0; i < Max_Lines; i++){
City1[i] = malloc(MAXLEN);
/* check malloc return value */
}
And also here you can simply do this too,
char City1[Max_Lines][MAXLEN];
Because here if you want to get MAXLEN byte buffer then instead of dynamic allocation you can do this. The only problem is that if Max_lines and MAXLEN is larger then there is a possibilty of constrained by stack size. Then dynamic allocation will be a rescue.
Also you should check the return value fopen. There are cases when fopen fails. You need to handle those cases separately.
try below variant:
#include <stdio.h>
#include <stdlib.h>
#include <string.h> //Chosen to use this library to break text file down.
//#include "list.h" //Using file created in lab 3 earlier this year.
#define DYNAMIC_RESIZE 0 ///Might not be needed...
#define Max_Lines 40
#define LINE_SIZE 150
typedef struct {
char data[LINE_SIZE];
} LineBuffer;
int main()
{
FILE *Distances_File = fopen("Distances.txt", "r");
LineBuffer *City1;
LineBuffer *City2;
int *Distances;
char File_Line[LINE_SIZE];
int Line_Count = 0;
City1 = (LineBuffer *)malloc(sizeof(LineBuffer)*Max_Lines);
City2 = (LineBuffer *)malloc(sizeof(LineBuffer)*Max_Lines);
Distances = (int *)malloc(Max_Lines);
if (!Distances_File) {
printf("File could not open");
return 1;
}
if ( Distances_File != NULL ) {
///Intro to the program.
printf("This is a program that will calculate the shortest distance between selected \ncities.");
printf("\nSo wish me luck :(\n \n");
while(fgets(File_Line, sizeof(File_Line), Distances_File) && Line_Count < Max_Lines)
{
//printf("%s", File_Line);
sscanf(File_Line, "%s%s%d", City1[Line_Count], City2[Line_Count], Distances[Line_Count]);
///Still issue of Distances being a char.
printf("%s\n%s\n%d\n\n", City1[Line_Count], City2[Line_Count], Distances[Line_Count]);
Line_Count++;
printf("%d", Line_Count);
}
}
free(City1);
free(City2);
free(Distances);
}
edit
sizeof(int) should be 4 bytes so malloc(sizeof(Max_Lines)) will allocate 4 bytes
I know about fscanf(), fgets() and those other functions to read the next line of a text file. However, if you are given a text file by 'cat msg1.txt | ./anonymizer' would you use the same functions?
For my program the code for the main is:
int main (void)
{
char input[1000]= {'\0'}; //the sentence the user will enter
printf("Enter a sentence:");
scanf("%[^\n]", input);
char newSentence[1000]={'\0'};
sentence=(char *) &newSentence;
line=getText(input,0);
divide(input);
printf("%s\n",sentence);
return 0;
}
In the command line I enter:
gcc -o anonymizer anonymizer.c
cat msg1.txt | ./anonymizer
My msg1 text file contains:
Hi, my email addresses are h.potter#hogwarts.edu and 1a#2b3c#lkj#
Although it's not an email addresses, I'd hate if# you saw my
secret#word. Gary.zenkel#nbcuni.comHoever, input variable only
contains the first line: 'Hi, my email addresses are
h.potter#hogwarts.edu and 1a#2b3c#lkj#'
How can I get the input variable to contain the other two lines?
Almost. While it may not actually be defined in such a way, scanf(...) is essentially equivalent to fscanf(stdin, ...). Similar for gets/fgets. You should be able to use either to read from your standard input stream.
To my limited knowledge (I could be wrong), with the standard libc, there are no efficient ways to read a line when you do not know the max line length. You may get memory overflow with scanf() and gets() because they do not check the length of your buffer. If you use fgets(), you may waste time on frequent strlen() and realloc(). If you use fgetc(), it will be slow as fgetc() has a huge overhead.
For efficient line reading, we have to keep some intermediate information. It is not that easy. I am attaching an implementation. It is quite complicated, but it is very efficient and generic. If you do not care about the details, you may just focus on the main() function about how to use the routines.
To try this program:
gcc -Wall prog.c; ./a.out < input.txt > output.txt
Program:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#ifndef kroundup32
#define kroundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x))
#endif
#define kstype_t FILE* // type of file handler
#define ksread_f(fp, buf, len) fread((buf), 1, (len), (fp)) // function to read a data chunk
typedef struct {
int l, m; // l: length of string; m: allocated size
char *s; // string
} kstring_t;
typedef struct {
kstype_t f; // file handler
int begin, end, is_eof, bufsize;
unsigned char *buf; // buffer
} kstream_t;
kstream_t *ks_open(kstype_t fp, int bufsize)
{
kstream_t *ks;
ks = (kstream_t*)calloc(1, sizeof(kstream_t));
ks->bufsize = bufsize;
ks->buf = (unsigned char*)malloc(bufsize);
ks->f = fp;
return ks;
}
void ks_close(kstream_t *ks)
{
free(ks->buf); free(ks);
}
int ks_readline(kstream_t *ks, int delimiter, kstring_t *str)
{
str->l = 0;
if (ks->begin >= ks->end && ks->is_eof) return -1;
for (;;) {
int i;
if (ks->begin >= ks->end) {
if (!ks->is_eof) {
ks->begin = 0;
ks->end = ksread_f(ks->f, ks->buf, ks->bufsize);
if (ks->end < ks->bufsize) ks->is_eof = 1;
if (ks->end == 0) break;
} else break;
}
for (i = ks->begin; i < ks->end; ++i)
if (ks->buf[i] == delimiter) break;
if (str->m - str->l < i - ks->begin + 1) {
str->m = str->l + (i - ks->begin) + 1;
kroundup32(str->m);
str->s = (char*)realloc(str->s, str->m);
}
memcpy(str->s + str->l, ks->buf + ks->begin, i - ks->begin);
str->l = str->l + (i - ks->begin);
ks->begin = i + 1;
if (i < ks->end) break;
}
if (str->s == 0) {
str->m = 1;
str->s = (char*)calloc(1, 1);
}
str->s[str->l] = '\0';
return str->l;
}
int main()
{
kstream_t *ks;
kstring_t str;
str.l = str.m = 0; str.s = 0; // initialize the string struct
ks = ks_open(stdin, 4096); // initialize the file handler
while (ks_readline(ks, '\n', &str) >= 0) // read each line
puts(str.s); // print it out
ks_close(ks); free(str.s); // free
return 0;
}