// Prints a file in the terminal separated by pages #include "macro_collections.h" #define TAB_SIZE 4 #define ROW_INI_CAP DOC_LETTERS_IN_ROW #define DOC_LETTERS_IN_ROW 100 #define DOC_ROWS_IN_PAGE 50 #define DOC_MARGIN 4 C_MACRO_COLLECTIONS_ALL(CMC, LIST, (row, row, , , char)) C_MACRO_COLLECTIONS_ALL(CMC, LIST, (doc, document, , , struct row *)) struct row_fval *row_funcs = &(struct row_fval){ NULL }; struct document_fval *doc_funcs = &(struct document_fval){ .free = row_free }; struct document *document_load(const char *file_name); void document_empty_line(FILE *fptr); void document_page_outline(FILE *fptr, int outline); void document_page_margin(FILE *fptr, int margin); void document_print(struct document *doc, FILE *fptr); struct document *document_load(const char *file_name) { FILE *file = fopen(file_name, "r"); if (!file) { cmc_log_error("File %s not found\n", file_name); return NULL; } struct row *initial_row = row_new(ROW_INI_CAP, row_funcs); struct document *doc = doc_new(100, doc_funcs); doc_push_back(doc, initial_row); int ch; while ((ch = getc(file)) != EOF) { char c = (char)ch; struct row *current_row = doc_back(doc); if (c == '\n') { struct row *new_row = row_new(ROW_INI_CAP, row_funcs); doc_push_back(doc, new_row); } else if (c == '\t') { intmax_t left = TAB_SIZE; while (left > 0 && row_count(current_row) < DOC_LETTERS_IN_ROW) { row_push_back(current_row, ' '); left--; } if (left > 0) { struct row *new_row = row_new(ROW_INI_CAP, row_funcs); doc_push_back(doc, new_row); while (left > 0) { row_push_back(new_row, ' '); left--; } } } else if (DOC_LETTERS_IN_ROW == row_count(current_row)) { struct row *new_row = row_new(ROW_INI_CAP, row_funcs); row_push_back(new_row, c); doc_push_back(doc, new_row); } else row_push_back(current_row, c); } return doc; } void document_empty_line(FILE *fptr) { fputs("\t|", fptr); for (size_t i = 0; i < DOC_LETTERS_IN_ROW + DOC_MARGIN * 2; i++) { fputc(' ', fptr); } fputs("\t|\n", fptr); } void document_page_outline(FILE *fptr, int outline /* 0 - header, 1 - footer */) { if (outline == 1) { document_empty_line(fptr); #ifdef DOC_PAGE_NUMBER static intmax_t page = 1; fputs("\t|", fptr); for (size_t i = 0; i < (DOC_LETTERS_IN_ROW + DOC_MARGIN) - 8; i++) { fputc(' ', fptr); } fprintf(fptr, "%8" PRIdMAX "", page); page++; document_page_margin(fptr, 1); document_empty_line(fptr); #endif } fputs("\t+", fptr); for (size_t i = 0; i < DOC_LETTERS_IN_ROW + DOC_MARGIN * 2 + 3; i++) { fputc('-', fptr); } fputs("+\n", fptr); if (outline == 0) document_empty_line(fptr); } void document_page_margin(FILE *fptr, int margin /* 0 - first margin, 1 - second margin */) { if (margin == 0) fputs("\t|", fptr); for (size_t i = 0; i < DOC_MARGIN; i++) { fputc(' ', fptr); } if (margin == 1) fputs("\t|\n", fptr); } void document_print(struct document *doc, FILE *fptr) { fputc('\n', fptr); intmax_t current_page_row = 0, total_rows = doc_count(doc); // Print document for (intmax_t i = 0; i < total_rows; i++, current_page_row++) { if (current_page_row == 0) document_page_outline(fptr, 0); struct row *current_row = doc_get(doc, i); if (!current_row) cmc_log_fatal("Unexpected NULL pointer for %s", "current_row"); document_page_margin(fptr, 0); for (size_t k = 0; k < row_count(current_row); k++) fputc(row_get(current_row, k), fptr); // Trailing margin for (size_t k = 0; k < DOC_LETTERS_IN_ROW - row_count(current_row); k++) fputc(' ', fptr); document_page_margin(fptr, 1); // Print the end of the page and reset if (current_page_row == DOC_ROWS_IN_PAGE - 1) { document_page_outline(fptr, 1); current_page_row = -1; fputc('\n', fptr); } } // Print trailing page if (total_rows % DOC_ROWS_IN_PAGE != 0) { for (size_t i = 0; i < DOC_ROWS_IN_PAGE - current_page_row; i++) document_empty_line(fptr); document_page_outline(fptr, 1); } fputc('\n', fptr); } int main(int argc, char const *argv[]) { if (argc != 2) { cmc_log_error("Please define one argument only for %s", argv[0]); return 1; } struct document *doc = document_load(argv[1]); document_print(doc, stdout); doc_free(doc); return 0; }