imprimir últimas linhas -n de entrada
Pergunta
#include <stdio.h>
#define MAXLINES 5000 /* Maximum number of lines to display. */
char *lineptr[MAXLINES]; /* Pointer to input lines. */
#define BUFFERSIZE 1000
#define DEFAULT_LAST 10
int readlines(char *lineptr[], char *buffer, int maxlines);
static void unwrap(char *buffer, int index);
static void reverse(char *lineptr[], int nlines);
main(int argc, char *argv[])
{
int nlines, i, last, offset;
char buffer[BUFFERSIZE];
char *p;
last = DEFAULT_LAST;
for (i = 0; i < argc; i++) {
p = argv[i];
if (*p++ == '-') {
last = 0;
while (isdigit(*p)) {
last = last * 10 + *p - '0';
p++;
}
if (*p != '\0') {
printf("invalid argument: %s\n", argv[i]);
last = DEFAULT_LAST;
}
}
}
nlines = readlines(lineptr, buffer, MAXLINES);
if (nlines < 0) {
printf("error: input too big to process\n");
return 1;
}
if (nlines < last) {
printf("error: only printing the last %d lines.\n", nlines);
offset = 0;
} else if (last > MAXLINES) {
offset = nlines - MAXLINES;
} else {
offset = nlines - last;
}
for (i = 0; i < nlines && i < last; i++)
printf("%s\n", lineptr[offset + i]);
return 0;
}
int readlines(char *lineptr[], char *buffer, int maxlines)
{
int c, nlines;
int wrapped;
char *p;
/* The input lines are stored end-to-end in the buffer, with
newlines converted to null bytes. */
wrapped = 0;
p = buffer;
while ((c = getchar()) != EOF) {
if (c == '\n')
*p = '\0';
else
*p = c;
p++;
if (p >= buffer + BUFFERSIZE) {
p = buffer;
wrapped = 1;
}
}
/* Rearrange the buffer so the oldest byte comes first. */
if (wrapped) {
unwrap(buffer, p - buffer);
p = buffer + BUFFERSIZE;
}
p--;
*p = '\0';
nlines = 0;
while (p >= buffer && nlines < maxlines) {
p--;
if (*p == '\0')
lineptr[nlines++] = p + 1;
}
reverse(lineptr, nlines);
return nlines;
}
static void unwrap(char *buffer, int index)
{
char work[BUFFERSIZE];
memmove(work, buffer + index, BUFFERSIZE - index);
memmove(work + BUFFERSIZE - index, buffer, index);
memmove(buffer, work, BUFFERSIZE);
return;
}
static void reverse(char *lineptr[], int nlines)
{
char *tmp;
int i;
for (i = 0; i < nlines / 2; i++) {
tmp = lineptr[i];
lineptr[i] = lineptr[nlines - i - 1];
lineptr[nlines - i - 1] = tmp;
}
return;
}
Este programa imprime últimas linhas -n de entrada, armazenamento de linhas em matriz de ponteiros.
Em funções readlines, se ponteiro para tampão atravessa seu tamanho máximo ele fica wraped. Mas eu não entendo o que faz a função wraping / unwraping fazer exatamente. Alguém pode explicar isso para mim? As obras envoltório maneira e por que razão não o escritor deste código apenas retorna -1 se o buffer transbordou?
Solução
Para demonstrar o princípio: dizer que você estava colocando 10 caracteres, '0' a '9', em um buffer de 8 bytes, usando o mesmo esquema:
Depois de 7 caracteres:
+---+---+---+---+---+---+---+---+
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | |
+---+---+---+---+---+---+---+---+
^ ^
buffer p
Depois do personagem 8º:
+---+---+---+---+---+---+---+---+
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
+---+---+---+---+---+---+---+---+
^ ^
buffer p
então agora p
é reposto e wrapped
é definido como 1:
+---+---+---+---+---+---+---+---+
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
+---+---+---+---+---+---+---+---+
^
buffer
p
Depois do personagem 10:
+---+---+---+---+---+---+---+---+
| 8 | 9 | 2 | 3 | 4 | 5 | 6 | 7 |
+---+---+---+---+---+---+---+---+
^ ^
buffer p
Agora o código unwrap()
reorganiza o buffer para ficar assim:
+---+---+---+---+---+---+---+---+
| 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
+---+---+---+---+---+---+---+---+
^ ^
buffer p
O programa está fazendo isso (ao invés de apenas dar-se) para que ele continuará a funcionar mesmo se o arquivo é muito maior do que o buffer. (A menos que o comprimento total dos últimos 10 linhas é maior do que o tamp, em que caso alguns dos mais cedo das últimas 10 linhas serão perdidos).
Outras dicas
Este programa lê todas as linhas em uma matriz de linhas. Cada elemento na matriz tem tamanho fixo. Se uma linha é mais longo do que o tamanho máximo de uma linha it "embrulha" que é reiniciado e enchendo o tampão no início da memória intermédia.
Unwrap em seguida, coloca o material mais antigo no final para que os olhares linha truncado a partir do início da linha. (A linha de 12 caracteres em um buffer de 10 personagem iria mostrar os últimos 10 caracteres começando a 3ª personagem.)