This code works. It will accept an arbitrary list of paragraphs in the file, and the set of lines in each paragraph is allowed to be of arbitrary length, too.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct data
{
int number;
char **lines;
int num_lines;
int max_lines;
};
int main(void)
{
struct data *info = 0;
int num_entries = 0;
int max_entries = 0;
char line[4096];
while (fgets(line, sizeof(line), stdin) != 0)
{
int number;
char hash;
if (sscanf(line, "%d%c", &number, &hash) != 2 || hash != '#')
{
fprintf(stderr, "Format error (number# expected): %s", line);
return(1);
}
if (max_entries >= num_entries)
{
int new_size = (max_entries + 2) * 2;
struct data *new_info = realloc(info, new_size * sizeof(*new_info));
if (new_info == 0)
{
fprintf(stderr, "Out of memory\n");
return(1);
}
info = new_info;
max_entries = new_size;
}
struct data *curr = &info[num_entries];
curr->number = number;
curr->lines = 0;
curr->max_lines = 0;
curr->num_lines = 0;
while (fgets(line, sizeof(line), stdin) != 0)
{
char *p = strchr(line, '\n');
if (p == 0)
{
fprintf(stderr, "Format error: no newline? (%s)\n", line);
return(1);
}
*p = '\0';
if (strcmp(line, "#") == 0)
break;
if (curr->max_lines >= curr->num_lines)
{
int new_size = (curr->max_lines + 2) * 2;
char **new_lines = realloc(curr->lines, new_size * sizeof(*new_lines));
if (new_lines == 0)
{
fprintf(stderr, "Out of memory\n");
return(1);
}
curr->lines = new_lines;
curr->max_lines = new_size;
}
curr->lines[curr->num_lines] = strdup(line);
if (curr->lines[curr->num_lines] == 0)
{
fprintf(stderr, "Out of memory\n");
return(1);
}
curr->num_lines++;
}
num_entries++;
}
for (int i = 0; i < num_entries; i++)
{
printf("%d#\n", info[i].number);
for (int j = 0; j < info[i].num_lines; j++)
printf(" %d: %s\n", j, info[i].lines[j]);
}
return(0);
}
Given the input file:
13#
Unlucky for some
#
20121221#
The end of the world?
No, it seems that we survived yet another doomsday!
#
18#
More lines,
And more lines still.
The verse is weird.
The terse is worse.
#
19#
As for one,
Then another,
It is still too short
For comfort,
But the fifth line shall trigger
an extra reallocation.
#
20#
All for one,
And one for all!
The Three Musketeers?
Nay, D'Artagnan, the Four Musketeers.
Yahoo! Bing? Google?
#
It gives the output:
13#
0: Unlucky for some
20121221#
0: The end of the world?
1: No, it seems that we survived yet another doomsday!
18#
0: More lines,
1: And more lines still.
2: The verse is weird.
3: The terse is worse.
19#
0: As for one,
1: Then another,
2: It is still too short
3: For comfort,
4: But the fifth line shall trigger
5: an extra reallocation.
20#
0: All for one,
1: And one for all!
2: The Three Musketeers?
3: Nay, D'Artagnan, the Four Musketeers.
4: Yahoo! Bing? Google?
There is undoubtedly room for improvement in the code, but it seems to work (though it does not release the memory before it exits). It assumes that there is a function char *strdup(const char *str)
that allocates enough space for a copy of the string it is given.