libgrapheme

grapheme cluster utility library
git clone git://git.suckless.org/libgrapheme
Log | Files | Refs | LICENSE

util.c (3375B)


      1 /* See LICENSE file for copyright and license details. */
      2 #include <stdint.h>
      3 #include <stdlib.h>
      4 #include <stdio.h>
      5 #include <string.h>
      6 #include <errno.h>
      7 
      8 #include "util.h"
      9 
     10 void
     11 parse_input(int (*process_line)(char **, size_t, char *))
     12 {
     13 	char *line = NULL, **field = NULL, *comment;
     14 	size_t linebufsize = 0, i, fieldbufsize = 0, j, nfields;
     15 	ssize_t len;
     16 
     17 	while ((len = getline(&line, &linebufsize, stdin)) >= 0) {
     18 		/* remove trailing newline */
     19 		if (len > 0 && line[len - 1] == '\n') {
     20 			line[len - 1] = '\0';
     21 			len--;
     22 		}
     23 
     24 		/* skip empty lines and comment lines */
     25 		if (len == 0 || line[0] == '#') {
     26 			continue;
     27 		}
     28 
     29 		/* tokenize line into fields */
     30 		for (i = 0, nfields = 0, comment = NULL; i < (size_t)len; i++) {
     31 			/* extend field buffer, if necessary */
     32 			if (++nfields > fieldbufsize) {
     33 				if ((field = realloc(field, nfields *
     34 				                     sizeof(*field))) == NULL) {
     35 					fprintf(stderr, "realloc: %s\n", strerror(errno));
     36 					exit(1);
     37 				}
     38 				fieldbufsize = nfields;
     39 			}
     40 
     41 			/* skip leading whitespace */
     42 			while (line[i] == ' ') {
     43 				i++;
     44 			}
     45 
     46 			/* set current position as field start */
     47 			field[nfields - 1] = &line[i];
     48 
     49 			/* continue until we reach ';' or '#' or end */
     50 			while (line[i] != ';' && line[i] != '#' &&
     51 			       line[i] != '\0') {
     52 				i++;
     53 			}
     54 			if (line [i] == '#') {
     55 				/* set comment-variable for later */
     56 				comment = &line[i + 1];
     57 			}
     58 
     59 			/* go back whitespace and terminate field there */
     60 			if (i > 0) {
     61 				for (j = i - 1; line[j] == ' '; j--)
     62 					;
     63 				line[j + 1] = '\0';
     64 			} else {
     65 				line[i] = '\0';
     66 			}
     67 
     68 			/* if comment is set, we are done */
     69 			if (comment != NULL) {
     70 				break;
     71 			}
     72 		}
     73 
     74 		/* skip leading whitespace in comment */
     75 		while (comment != NULL && comment[0] == ' ') {
     76 			comment++;
     77 		}
     78 
     79 		/* call line processing function */
     80 		if (process_line(field, nfields, comment)) {
     81 			exit(1);
     82 		}
     83 	}
     84 
     85 	free(line);
     86 	free(field);
     87 }
     88 
     89 static int
     90 valid_hexstring(const char *str)
     91 {
     92 	const char *p = str;
     93 
     94 	while ((*p >= '0' && *p <= '9') ||
     95 	       (*p >= 'a' && *p <= 'f') ||
     96 	       (*p >= 'A' && *p <= 'F')) {
     97 		p++;
     98 	}
     99 
    100 	if (*p != '\0') {
    101 		fprintf(stderr, "invalid code point range '%s'\n", str);
    102 		return 0;
    103 	}
    104 
    105 	return 1;
    106 }
    107 
    108 int
    109 cp_parse(const char *str, uint32_t *cp)
    110 {
    111 	if (!valid_hexstring(str)) {
    112 		return 1;
    113 	}
    114 	*cp = strtol(str, NULL, 16);
    115 
    116 	return 0;
    117 }
    118 
    119 int
    120 range_parse(const char *str, struct range *range)
    121 {
    122 	char *p;
    123 
    124 	if ((p = strstr(str, "..")) == NULL) {
    125 		/* input has the form "XXXXXX" */
    126 		if (!valid_hexstring(str)) {
    127 			return 1;
    128 		}
    129 		range->lower = range->upper = strtol(str, NULL, 16);
    130 	} else {
    131 		/* input has the form "XXXXXX..XXXXXX" */
    132 		*p = '\0';
    133 		p += 2;
    134 		if (!valid_hexstring(str) || !valid_hexstring(p)) {
    135 			return 1;
    136 		}
    137 		range->lower = strtol(str, NULL, 16);
    138 		range->upper = strtol(p, NULL, 16);
    139 	}
    140 
    141 	return 0;
    142 }
    143 
    144 void
    145 range_list_append(struct range **range, size_t *nranges, const struct range *new)
    146 {
    147 	if (*nranges > 0 && (*range)[*nranges - 1].upper == new->lower) {
    148 		/* we can merge with previous entry */
    149 		(*range)[*nranges - 1].upper = new->upper;
    150 	} else {
    151 		/* need to append new entry */
    152 		if ((*range = realloc(*range, (++(*nranges)) * sizeof(**range))) == NULL) {
    153 			fprintf(stderr, "realloc: %s\n", strerror(errno));
    154 			exit(1);
    155 		}
    156 		(*range)[*nranges - 1].lower = new->lower;
    157 		(*range)[*nranges - 1].upper = new->upper;
    158 	}
    159 }