git.y1.nz

lwl

Less with links.
download: http://git.y1.nz/archives/lwl.tar.gz
README | Files | Log | Refs

text.c

      1 #include <ctype.h> /* isprint */
      2 #include <stdlib.h> /* malloc/free */
      3 
      4 #include "config.h"
      5 #include "text.h"
      6 
      7 const char *hex_letters = "0123456789ABCDEF";
      8 
      9 FileContents *
     10 init_contents()
     11 {
     12 	FileContents *ret = malloc(sizeof(FileContents));
     13 
     14 	// TODO use compile-time buffers instead? Only happens once per run..
     15 	ret->buffer = malloc(MAX_FILE_LENGTH * sizeof(char));
     16 	ret->buffer[0] = '\0';
     17 
     18 	ret->lines = malloc(MAX_NEWLINES * sizeof(int));
     19 	ret->line_count = 0;
     20 	ret->lines[ret->line_count++] = 0;
     21 
     22 	ret->highlights = malloc(MAX_MARKUPS * sizeof(Markup *));
     23 	ret->highlight_count = 0;
     24 
     25 	ret->links = malloc(MAX_MARKUPS * sizeof(Markup *));
     26 	ret->link_count = 0;
     27 
     28 	return ret;
     29 }
     30 
     31 Markup *
     32 create_markup(int start, int width, int color)
     33 {
     34 	Markup *ret = malloc(sizeof(Markup));
     35 	ret->start = start;
     36 	ret->width = width;
     37 	ret->color = color;
     38 	ret->active = 0;
     39 	ret->data = NULL;
     40 	return ret;
     41 }
     42 
     43 void
     44 free_markup(Markup *markup)
     45 {
     46 	free(markup);
     47 }
     48 
     49 typedef struct _link {
     50 	int open_square;
     51 	int close_square;
     52 	int open_paren;
     53 	int close_paren;
     54 } Link;
     55 #define CURRENT  links[link_count-1]
     56 
     57 
     58 /* returns the new index of the string terminator of contents->buffer */
     59 int
     60 create_link(FileContents *contents, Link *l) {
     61 	int start = l->open_square;
     62 	int width = l->close_square - l->open_square + 1;
     63 	Markup *link = create_markup(start, width, LINK_COLOR);
     64 
     65 	/* copy the link destination into link->data */
     66 	// TODO only malloc as much as necessary
     67 	int link_length = l->close_paren - l->open_paren - 1;
     68 	link->data = malloc((link_length+1)*sizeof(char));
     69 	for (int i = 0; i < link_length; i++) {
     70 		link->data[i] = contents->buffer[l->open_paren + 1 + i];
     71 		link->data[i+1] = '\0';
     72 	}
     73 
     74 	contents->links[contents->link_count++] = link;
     75 
     76 	/* keep in the square brackets, write over the parens and link */
     77 	contents->buffer[l->open_paren] = '\0';
     78 	return l->open_paren;
     79 }
     80 
     81 /* process the file, but only what's independent of linewraps */
     82 FileContents *
     83 read_contents(FILE *fin)
     84 {
     85 	FileContents *ret = init_contents();
     86 	char ch = '!', previous_ch = '!';
     87 	int i = 0, i0;
     88 	
     89 	Link **links = malloc(1000 * sizeof(Link *));
     90 	int link_count = 0;
     91 
     92 	for (;;) {
     93 		previous_ch = ch;
     94 		ch = fgetc(fin);
     95 		if (ch == EOF) break;
     96 
     97 		if (
     98 			previous_ch == '\\' &&
     99 			(ch == '[' || ch == ']' || ch == '(' || ch == ')')
    100 		) {
    101 			ret->buffer[i-1] = ch;
    102 			continue;
    103 		}
    104 
    105 		/* link parsing. */
    106 		// TODO extract this so it's more modular.
    107 		if (ch == '[' && previous_ch != '\\') {
    108 			link_count++;
    109 			CURRENT = malloc(sizeof(Link));
    110 			CURRENT->close_square =
    111 			CURRENT->open_paren =
    112 			CURRENT->close_paren = -1;
    113 			CURRENT->open_square = i;
    114 		}
    115 		if (link_count != 0 && ch == ']') CURRENT->close_square = i;
    116 		if (link_count != 0 && ch == '(') CURRENT->open_paren = i;
    117 		if (
    118 			link_count != 0 &&
    119 			ch == ')' &&
    120 			CURRENT->open_paren == CURRENT->close_square+1 &&
    121 			CURRENT->open_square < CURRENT->close_square
    122 		) {
    123 			CURRENT->close_paren = i;
    124 			i = create_link(ret, CURRENT);
    125 			free(CURRENT);
    126 			link_count--;
    127 			continue;
    128 		}
    129 
    130 		/* replace tab chars with appropriate numbers of spaces... */
    131 		if (ch == '\t') {
    132 			int x = i - ret->lines[ret->line_count-1];
    133 			int spaces = 8 - (x%8);
    134 			for (int k = 0; k < spaces; k++) ret->buffer[i++] = ' ';
    135 			ret->buffer[i] = '\0';
    136 			continue;
    137 		}
    138 
    139 		if (ch == '\n')
    140 			ret->lines[ret->line_count++] = i+1;
    141 			/* FALL THROUGH */
    142 
    143 		// if (isprint(ch) || ch == '\n') {
    144 			ret->buffer[i++] = ch;
    145 			ret->buffer[i] = '\0';
    146 			continue;
    147 		// }
    148 
    149 		// TODO translate utf-8 apostrophes and double quotes and whatnot
    150 
    151 		/* for weird characters, just display them in hex + highlight. */
    152 		/* this way they're unambiguous, searchable, & comprehensible */
    153 		Markup *highlight = create_markup(i, 3, COLOR_RED);
    154 		highlight->active = 1; /* show it in inverse */
    155 		ret->highlights[ret->highlight_count++] = highlight;
    156 
    157 		ret->buffer[i++] = '.';
    158 		ret->buffer[i++] = hex_letters[((unsigned int) ch / 16) % 16];
    159 		ret->buffer[i++] = hex_letters[(unsigned int) ch % 16];
    160 		ret->buffer[i] = '\0';
    161 	}
    162 
    163 	/* set the value at line_count for calculating line lengths */
    164 	ret->lines[ret->line_count] = i;
    165 
    166 	return ret;
    167 }
    168 
    169 Wrap *
    170 wrap_to(FileContents *contents, int width, int height)
    171 {
    172 	Wrap *ret = malloc(sizeof(Wrap));
    173 
    174 	// TODO count exact number of lines to allocate..
    175 	ret->lines = malloc(3 * MAX_NEWLINES * sizeof(int));
    176 	ret->line_count = 0;
    177 	ret->width = width;
    178 	ret->height = height;
    179 
    180 	/* first line always starts at 0 */
    181 	ret->lines[ret->line_count++] = 0;
    182 
    183 	char ch, nch, nnch;
    184 	int i = 0; /* index in buffer */
    185 	int x = 0; /* horizontal position */
    186 	for (;;) {
    187 		ch = contents->buffer[i++];
    188 		if (ch == '\0') break;
    189 		nch = contents->buffer[i];
    190 
    191 		x++;
    192 		if ((x == width && nch != '\n') || ch == '\n') {
    193 			ret->lines[ret->line_count++] = i;
    194 			x = 0;
    195 		}
    196 	}
    197 
    198 	/* for calculating lines' lengths */
    199 	ret->lines[ret->line_count] = i;
    200 
    201 	return ret;
    202 }

This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.