Это проблема, которую нужно разделить на небольшие, чтобы ее легко решить.
Прочитайте входной файл строка за строки
а. если это команда форматирования, измените состояние программы с опциями форматирования
b.else напечатать строку, правильно отформатированную во временном файле
Переопределите входной файл с содержимым временного файла.
Сначала давайте определим несколько типов, которые будут использованы позже. Если вы новичок в C, я приглашаю вас проверить this page и прочитать, что такое enum
, struct
и union
.
Перечисление возможных команд
typedef enum Command_e { CMD_NONE, LW , LM , FT , LS } Command;
enumaration из различного рода линий. В основном у Вас есть два вида линий: регулярные линии, чтобы быть отформатированы, и один, содержащие команды
typedef enum LineType_e { LT_NONE, REGULAR , COMMAND } LineType;
структуры, представляющая линию. Строка содержит ее тип. Кроме того, строка REGULAR
содержит ее длину и ее содержание. A COMMAND
содержит его тип и его параметр. Мы будем представлять значения on
и off
соответственно на 1
и 0
.
typedef struct Line_s
{
LineType type;
union
{
struct cmd_s
{
Command type;
int arg;
} cmd;
struct reg_s
{
char * str;
size_t len;
} reg;
} content;
} Line;
В C нет стандарта getline
функция. Тем не менее, это легко сделать с помощью функции fgets
.
// Read a line from the stream and returns a string containing every
// characters of the line until a newline character is read or end-of-file
// is reached. size is filled with the size of the string including the
// newline character.
// If end-of-file is reached before any character is read, the function
// returns NULL
char * getline(FILE * stream, size_t * s)
{
char * buf = NULL; // Buffer to return
int cnt = 0;
int size = 0; // Buffer size
int start = 0; // Where to start writing in the buffer
do
{
// Resize the buffer to (2^cnt * BUFF_SIZE) and fill the expanded
// part with the a null character
size = BUFF_SIZE * (1 << cnt);
start = BUFF_SIZE * (1 << (cnt - 1)) - 1;
start = start < 0 ? 0 : start;
buf = realloc(buf, size * sizeof(char));
memset(& buf[start], '\0', size - start);
// Read a maximum of (size - start) characters from the stream or
// until a newline character has been reached
fgets(& buf[start], size - start, stream);
cnt ++;
} // Loop until a complete line has been read
while(buf[size - 2] != '\0' &&
buf[size - 2] != '\n' &&
! feof(stdin));
// If nothing has been read from the file, free the memory and returns
// a NULL pointer
if(buf[0] == '\0')
{
free(buf);
buf = NULL;
(* s) = 0;
}
else
{
(* s) = strlen(buf);
}
return buf;
}
Где BUFF_SIZE
макрос, который определяет типичный размер для буфера. Эта функция требует включения string.h
, поскольку она использует memset
и stdlib.h
для использования realloc
.
С помощью этой функции вы можете легко написать другую, которая будет читать строку файла в строке и заполнить структуру Line
, переданную как входную, и вернуть целое число, равное нулю, если конец файла достигнут.
int getNextLine(FILE * stream, Line * line)
{
size_t size;
char * str = getline(stream, & size);
if(! str)
{
line->type = LT_NONE;
return 0;
}
str[size - 1] = '\0'; // Remove the newline character
if(size - 1 > 2)
{
if(str[0] == 'L' && (str[1] == 'W' || str[1] == 'M' || str[1] == 'S'))
{
// If the remaining of the string is made characters between '0' and
// '9', then, str is a LW, LM or LS command
int val = 0;
int i;
for(i = 2; i < size - 1; i ++)
{
if(str[i] < '0' || str[i] > '9') break;
val = val * 10 + (str[i] - '0');
}
if(i < size - 1)
{
line->type = REGULAR;
line->content.reg.str = str;
line->content.reg.len = size;
}
else
{
line->type = COMMAND;
line->content.cmd.arg = val;
switch(str[1])
{
case 'W' : line->content.cmd.type = LW; break;
case 'M' : line->content.cmd.type = LM; break;
case 'S' : line->content.cmd.type = LS; break;
}
}
return 1;
}
if(size - 1 == 4 && str[0] == 'F' && str[1] == 'T' &&
str[2] == 'o' && str[3] == 'n')
{
// FTon command found
line->type = COMMAND;
line->content.cmd.type = FT;
line->content.cmd.arg = 1;
return 1;
}
if(size - 1 == 5 && str[0] == 'F' && str[1] == 'T' &&
str[2] == 'o' && str[3] == 'f' && str[4] == 'f')
{
// FToff command found
line->type = COMMAND;
line->content.cmd.type = FT;
line->content.cmd.arg = 0;
return 1;
}
}
// If we reach this point no command have been found
line->type = REGULAR;
line->content.reg.str = str;
line->content.reg.len = size;
return 1;
}
Теперь вы почти закончили. В основном цикле, который остановится, когда getNextLine
вернется 0
, вы можете установить несколько переменных в соответствии с полученными вами командами, а когда вы получаете регулярную линию, вы можете просто вызвать функцию формата, которая выведет строку, отформатированную так, как должна поток. Вот пример такой функции.
void format(FILE * stream, Line line, int ft, int lw, int lm, int ls)
{
if(! ft)
{
// If the formatting is disabled, simply send the line to the stream
fprintf(stream, "%s\n", line.content.reg.str);
}
else
{
int i;
int j;
char f[16] = { 0 };
sprintf(f, "%%.%ds\n", lw - lm);
i = 0;
do
{
for(j = 0; j < lm; j ++) fprintf(stream, " ");
fprintf(stream, f, & line.content.reg.str[i * (lw - lm)]);
for(j = 0; j < ls; j ++) fprintf(stream, "\n");
i++;
}
while(i * (lw - lm) < line.content.reg.len);
}
}
временный файл я говорил ранее, могут быть открыты с помощью функции tmpfile
. Когда вы достигнете конца входного файла, вам просто нужно закрыть ваш входной файл и скопировать содержимое временного файла в него. Это делается просто с buffers
и fprintf
. Не забудьте освободить память, вызвав функцию free
после того, как вы напечатали форматированную строку во временном файле, чтобы избежать утечек памяти.
В конце файла, как
FTon
LW30
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam est arcu, congue vehicula consectetur in, tempus ac ex. Integer urna lectus, maximus vel felis sed, dapibus gravida risus. Curabitur diam arcu, accumsan at magna id, laoreet condimentum ante.
FToff
Nulla id velit justo. Aenean leo risus, interdum lobortis enim sit amet, aliquet elementum dolor. Morbi pretium velit sed mauris molestie viverra. Cras ut cursus nibh. Aliquam ut aliquam nunc, eget rhoncus sapien.
LS1
Sed efficitur justo aliquam orci molestie, vel condimentum dui semper. Sed lobortis dignissim ligula ut bibendum. Pellentesque finibus euismod massa a congue.
FTon
Sed placerat quam eget ante rutrum pretium a in orci. Quisque id lorem dapibus, tincidunt lorem et, convallis orci. Etiam sed placerat ante.
LM5
Donec mi est, sodales sed faucibus ac, elementum eu velit. Nam mollis varius porttitor. Sed dignissim sodales malesuada.
LW15
Donec nec tempus turpis, at condimentum velit.
даст вам следующий вывод
Lorem ipsum dolor sit amet, co
nsectetur adipiscing elit. Ali
quam est arcu, congue vehicula
consectetur in, tempus ac ex.
Integer urna lectus, maximus
vel felis sed, dapibus gravida
risus. Curabitur diam arcu, a
ccumsan at magna id, laoreet c
ondimentum ante.
Nulla id velit justo. Aenean leo risus, interdum lobortis enim sit amet, aliquet elementum dolor. Morbi pretium velit sed mauris molestie viverra. Cras ut cursus nibh. Aliquam ut aliquam nunc, eget rhoncus sapien.
Sed efficitur justo aliquam orci molestie, vel condimentum dui semper. Sed lobortis dignissim ligula ut bibendum. Pellentesque finibus euismod massa a congue.
Sed placerat quam eget ante ru
trum pretium a in orci. Quisqu
e id lorem dapibus, tincidunt
lorem et, convallis orci. Etia
m sed placerat ante.
Donec mi est, sodales sed
faucibus ac, elementum e
u velit. Nam mollis variu
s porttitor. Sed dignissi
m sodales malesuada.
Donec nec
tempus tur
pis, at co
ndimentum
velit.
Пожалуйста, сообщите, какие именно проблемы в коде, что вам нужна помощь с. Вы пытались решить проблему? – Gerhard
Не рекомендуется изменять файл и читать его снова. Вместо этого вы должны анализировать его на лету. Однако ответ зависит от структуры файла, который вы берете в качестве входных данных. Без дополнительной информации мы не можем помочь –
@Gerhard Я отредактировал его, я повторил свою проблему в абзаце после кода. Пожалуйста, скажите мне, нужно ли мне быть более ясным. –