Program wyświetla zawartość pliku w trybie szesnastkowo-tekstowym. Prezentuje obsługę parametrów wywołania programu, operacje na plikach w trybie binarnym oraz wykorzystanie funkcji formatowanego wyjścia printf.
Program pobiera nazwę pliku z linii poleceń, jeżeli nie ma nazwy w linii poleceń, program pyta o tę nazwę użytkownika. Do przetwarzania pliku wykorzystano odczyt blokowy. 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 (hex_view.c).
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
/* Liczba linii na jednej stronie - ekranie */
#define PAGE_LENGTH 24
/* Liczba znaków odczytywanych do bufora - tyle znaków będzie w pojedynczej
linii na stronie, najpierw w postaci HEX, potem ASCII */
#define BUFFER_LEN 19
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 plikowy */
int in_chars; /* Liczba znaków odczytanych z pliku
przy pojedynczym odczycie */
unsigned char buffer[ BUFFER_LEN ]; /* Bufor na odczytywane znaki */
int lines = 0; /* Licznik linii "zapełnianych" na
ekranie */
int i = 0; /* Zmienna sterująca iteracji */
if(argc == 1) /* Czy nazwa pliku występuje w linii polecen? */
{
printf("Enter a filename: "); /* Zapytaj o nazwę pliku */
read_string(file_name, 256); /* Wczytaj nazwę pliku */
}
else
strcpy(file_name, args[ 1 ]); /* Pobierz nazwę pliku z tablicy parametrów */
if((file = fopen( file_name, "rb")) == NULL)
{
printf("Sorry, can't open \"%s\" press Enter...", file_name);
(void)getchar(); /* Czekanie na Enter */
return EXIT_FAILURE;
}
/* Odczytuj kolejne bloki, zapamiętaj w zmiennej in_chars ile wczytano
znaków za każdym razem. Jeżeli wczytano < 0 to wystąpił koniec pliku */
while((in_chars = fread(buffer, 1, BUFFER_LEN, file)) > 0)
{
/* Wyświetl zawartość bufora szesnastkowo, na dwóch pozycjach,
z wiodącym zerem, dużymi literami - specyfikacja %02X */
for(i = 0; i < 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żeli nie,
to wyswietla '.' */
for(i = 0; i < in_chars; i++)
printf("%c", isprint(buffer[ i ]) ? buffer[i] : '.');
putchar('\n');
if((++lines % PAGE_LENGTH) == 0) /* Czy ekran zapełniony? */
{
printf( "---- Press Enter for more ---" );
(void)getchar(); /* Czekanie na Enter */
}
}
fclose(file); /* Zamykamy plik */
return EXIT_SUCCESS;
}