2010-01-10 2 views
2
#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; 
} 

Ce programme imprime les dernières lignes -n de l'entrée, en stockant les lignes dans un tableau de pointeurs.print last -n lignes d'entrée

Dans les fonctions readlines, si le pointeur vers le tampon dépasse sa taille maximale, il est enveloppé. Mais je ne comprends pas ce que font exactement la fonction d'enroulement/déroulement. Quelqu'un peut-il me l'expliquer? La façon dont fonctionne le wrap et pourquoi l'auteur de ce code n'a pas retourné -1 si le buffer a débordé?

Répondre

5

Pour démontrer le principe: disons que vous mettez 10 caractères, '0' à '9', dans un 8 tampon -Byte, en utilisant le même schéma:

Après 7 caractères:

+---+---+---+---+---+---+---+---+ 
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | | 
+---+---+---+---+---+---+---+---+ 
^      ^
buffer      p 

Après le 8ème caractère:

+---+---+---+---+---+---+---+---+ 
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 
+---+---+---+---+---+---+---+---+ 
^       ^
buffer       p 

maintenant p est remis à zéro et wrapped est réglé sur 1:

+---+---+---+---+---+---+---+---+ 
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 
+---+---+---+---+---+---+---+---+ 
^
buffer 
    p 

Après le 10ème caractère:

+---+---+---+---+---+---+---+---+ 
| 8 | 9 | 2 | 3 | 4 | 5 | 6 | 7 | 
+---+---+---+---+---+---+---+---+ 
^ ^
buffer p 

Maintenant, le code unwrap() réarrange le tampon pour ressembler à ceci:

+---+---+---+---+---+---+---+---+ 
| 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 
+---+---+---+---+---+---+---+---+ 
^       ^
buffer       p 

Le programme fait ce (plutôt que de simplement abandonner) afin qu'il fonctionne toujours même si le fichier est beaucoup plus grand que le tampon. (À moins que la longueur totale des 10 dernières lignes soit plus grande que celle du tampon, en , auquel cas certaines des 10 premières lignes seront perdues).

+0

@Matthew, de beaux diagrammes! – Hogan

+0

Merci :), ceci l'a expliqué! – Tool

0

Ce programme lit toutes les lignes dans un tableau de lignes. Chaque élément du tableau a une taille fixe. Si une ligne est plus longue que la taille maximale d'une ligne, elle "l'enveloppe" et recommence à remplir le tampon au début du tampon. Unwrap met alors les choses les plus anciennes à la fin de sorte que la ligne semble tronquée à partir du début de la ligne. (Une ligne de 12 caractères dans un tampon de 10 caractères affichera les 10 derniers caractères commençant au 3e caractère.)