/* * Text layout and parsing functions * * Copyright (C) 2019 Patrick McDermott * * This file is part of fbcon2png. * * fbcon2png is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * fbcon2png is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with fbcon2png. If not, see . */ #include "text.h" #include #include #include #include #include #include "font.h" #include "i18n.h" #include "output.h" #include "sgr.h" #define MAX(a, b) (((a) > (b)) ? (a) : (b)) struct text { size_t size; size_t read; unsigned char *string; size_t width; size_t height; }; static unsigned char _getc(struct text *text, FILE *stream, unsigned char *c) { int i_c; assert(text); assert(stream); assert(c); if (text->read == text->size) { text->size += 8192; text->string = realloc(text->string, text->size); } i_c = fgetc(stream); if (i_c == EOF) { i_c = 0; } return text->string[text->read++] = *c = i_c; } struct text * text_new(FILE *stream) { struct text *text; size_t width; int eol; unsigned char c; assert(stream); text = calloc(1, sizeof(*text)); if (!text) { error(_("Cannot allocate memory for text object")); return NULL; } width = 0; eol = 0; _getc(text, stream, &c); while (c) { if (c == 0x1B && _getc(text, stream, &c) == '[') { /* CSI */ _getc(text, stream, &c); for (; c >= 0x30 && c <= 0x3F; _getc(text, stream, &c)); for (; c >= 0x20 && c <= 0x2F; _getc(text, stream, &c)); if (c >= 0x40 && c <= 0x7E) { _getc(text, stream, &c); } else { error(_("Invalid control sequence at line %lu " "column %lu"), text->height + 1, width + 1); } eol = 0; } else if (c == '\n') { text->width = MAX(text->width, width); width = 0; ++text->height; _getc(text, stream, &c); eol = 1; } else { ++width; _getc(text, stream, &c); eol = 0; } } if (!eol) { ++text->height; } return text; } size_t text_get_width(const struct text *text) { assert(text); return text->width; } size_t text_get_height(const struct text *text) { assert(text); return text->height; } size_t text_set_width(struct text *text, size_t width) { assert(text); assert(width > 0); return text->width = MAX(text->width, width); } size_t text_set_height(struct text *text, size_t height) { assert(text); assert(height > 0); return text->height = MAX(text->height, height); } void text_render(const struct text *text, const struct font *font, png_byte **rows) { unsigned char *string_start; unsigned char *string; size_t row; size_t col; unsigned char *parameter; png_color fg = {170, 170, 170}; png_color bg = { 0, 0, 0}; assert(text); assert(font); assert(rows); string_start = calloc(strlen((char *) text->string) + 1, sizeof(*text->string)); if (!string_start) { error(_("Cannot allocate memory for text rendering")); return; } memcpy(string_start, text->string, strlen((char *) text->string) + 1); string = string_start; row = 0; col = 0; while (string && *string) { if (*string == 0x1B && *(++string) == '[') { /* CSI */ ++string; parameter = string; for (; *string >= 0x30 && *string <= 0x3F; ++string); for (; *string >= 0x20 && *string <= 0x2F; ++string); if (*string >= 0x40 && *string <= 0x7E) { if (*string == 'm') { *string = '\0'; sgr(parameter, &fg, &bg); } ++string; } } else if (*string == '\n') { for (; col < text->width; ++col) { font_render(font, &fg,&bg, ' ', rows, row, col); } col = 0; ++row; ++string; } else { font_render(font, &fg, &bg, *string, rows, row, col); ++col; ++string; } } for (; row < text->height; ++row) { for (; col < text->width; ++col) { font_render(font, &fg, &bg, ' ', rows, row, col); } col = 0; } free(string_start); } struct text * text_destroy(struct text **text_p) { struct text *text; assert(text_p && *text_p); text = *text_p; free(text->string); free(text); return text = NULL; }