Przegląd pliku z możliwością wyboru trybu wyświetlania

Wyświetlacz zawartości pliku tekstowego. Możliwe są dwa tryby wyświetlania: tekstowy i szesnastkowy. Domyślnym trybem jest tryb tekstowy. Nazwę pliku i tryb określają argumenty wywołania programu. Pierwszy to nazwa pliku do wyświetlenia, drugi to tryb wyświetlania – t dla trybu tekstowego, h dla szesnastkowego..

Gdy nazwa pliku nie została podana, program pyta o nią i domyślnie wyświetla podgląd tekstowy.

Przykłady wywołania programu (przy założeniu, że wersja wykonywalna nazywa się file_view):

file_view plik.txt
file_view plik.txt t
file_view plik.txt h
file_view

Program stanowi uzupełnienie wykładu z programowania w językach C/C++. Koncepcja przetwarzania plików przedstawiona została tutaj.

Do pobrania wersja źródłowa pliku (file_view.c).

#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>

/* Liczba linii na jednej stronie - ekranie */
#define PAGE_LENGTH 24

/* Maksymalna dlugość linii -- dla dłuższych linii
   program nie będzie działal prawidłowo */
#define TEXT_BUFFER_LEN  256
#define HEX_BUFFER_LEN   19

void pause_if_necessary(int lines_counter)
{
  if((++lines_counter % PAGE_LENGTH) == 0)  /* Czy ekran zapełniony? */
  {
     printf( "---- Press Enter for more ----" );
     (void)getchar(); /* Czekanie na Enter */
  }
}

void text_view(FILE * file)
{
  char buffer[TEXT_BUFFER_LEN]; /* Bufor na odczytywane znaki */
  int  lines = 0;               /* Licznik linii zapełniających ekran */

  /* Odczytuj kolejne linie tekstu */
  putchar('\n');
  while(fgets(buffer, TEXT_BUFFER_LEN, file) != NULL)
  {
    printf("%s", buffer);
    pause_if_necessary(++lines);
  }
}

void hex_view(FILE * file)
{
  unsigned char buffer[HEX_BUFFER_LEN]; /* Bufor na odczytywane znaki */
  int  in_chars;               /* Liczba znaków odczytanych z pliku */
  int  lines = 0;              /* Licznik linii zapełniających ekran */
  int  i;
  /* Odczytuje kolejne bloki, zapamiętuje w zmiennej in_chars ile
     wczytano znaków za kazdym razem. Jeżeli wczytano < 0 to
     wystąpił koniec pliku
  */
  putchar('\n');
  while((in_chars = fread(buffer, 1, HEX_BUFFER_LEN, file)) > 0)
  {
     /* Wyświetla zawartość bufora szesnastkowo, na dwoch pozycjach,
        z wiodącym zerem, dużymi literami - specyfikacja %02X */
    for(i = 0; i < HEX_BUFFER_LEN; i++)
      if(i < in_chars)
        printf("%02X ", buffer[i]);
      else /* Gdy w buforze jest mniej znaków, zwykle ostatni odczyt z pliku */
        printf("   ");
    printf("| ");  /* Separator części szesnastkowej od ASCII */
    /* Wyświetla bufor jako ASCII o ile można, jeżli nie
       to wyswietla '.' */
    for(i = 0; i < in_chars; i++)
        printf("%c", isprint(buffer[i]) ? buffer[i] : '.');
    putchar('\n');
    pause_if_necessary(++lines);
  }
}
char * read_string(char * buffer, size_t buffer_len)
{
  // Funkcja fgets pozwala zabezpieczyć się przed
  // przepełnieniem bufora, stosujemy zamiast funkcji gets.
  // Funkcja ta jednak pozostawia znak '\n' na końcu linii,
  // trzeba go usunąć. Można posłużyć się długością łańcucha
  // i manipulować indeksami, ja wolę poszukać czy nadmiarowy
  // znak występuje i przyciąć łańcuch na jego pozycji
  char * new_line_char;
  fgets(buffer, buffer_len - 2, stdin);
  if((new_line_char = strchr(buffer, '\n')) != 0)
    *new_line_char = '\0';
  return buffer;
}
int main(int argc, char *args[])
{
   char file_name[256];  /* Bufor na nazwę pliku */
   FILE * file;          /* Wskaźnik otwieranego pliku */
   int view_mode = 't';  /* Jaki jest tryb wyświetlania */
   if(--argc == 0)  /* Czy nazwa pliku występuje w linii komend? */
   {
     printf("Enter a filename: "); /* Zapytaj o nazwę pliku */
     read_string(file_name, 256); /* Wczytaj nazwe pliku */
   }
   else
   {
     /* Pobierz nazwę pliku z pierwszego parametru wywołania */
     strcpy(file_name, args[1]);
     /* Opcja wyświetlania z drugiego parametru,o ile istnieje */
     if(argc == 2)
        view_mode = tolower(args[2][0]);
   }
   /* Próba otwarcia pliku */
   if((file = fopen( file_name, "rb")) == NULL)
   {
      printf("Sorry, can't open \"%s\" press Enter...", file_name);
      (void)getchar();
      return EXIT_FAILURE;
   }
   /* Wybór funkcji wyświetlającej */
   switch(view_mode)
   {
     case 'h' : hex_view(file);
                break;
     case 't' :
     default  : text_view(file);
                break;
   }
   fclose(file);
   puts("\n---- Press Enter to quit ----" );
   (void)getchar();
   return EXIT_SUCCESS;
}