You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

262 line
6.8 KiB

  1. /*
  2. * libcucul Canvas for ultrafast compositing of Unicode letters
  3. * Copyright (c) 2006-2007 Sam Hocevar <sam@zoy.org>
  4. * All Rights Reserved
  5. *
  6. * $Id$
  7. *
  8. * This library is free software. It comes without any warranty, to
  9. * the extent permitted by applicable law. You can redistribute it
  10. * and/or modify it under the terms of the Do What The Fuck You Want
  11. * To Public License, Version 2, as published by Sam Hocevar. See
  12. * http://sam.zoy.org/wtfpl/COPYING for more details.
  13. */
  14. /*
  15. * This file contains FIGlet and TOIlet font handling functions.
  16. */
  17. #include "config.h"
  18. #include "common.h"
  19. #if !defined(__KERNEL__)
  20. # include <stdio.h>
  21. # include <stdlib.h>
  22. # include <string.h>
  23. #endif
  24. #include "cucul.h"
  25. #include "cucul_internals.h"
  26. struct cucul_figfont
  27. {
  28. /* Used by the FIGlet driver */
  29. unsigned long int hardblank;
  30. unsigned int height, baseline, max_length;
  31. int old_layout;
  32. unsigned int print_direction, full_layout, codetag_count;
  33. unsigned int glyphs;
  34. cucul_canvas_t *fontcv;
  35. unsigned int *lookup;
  36. };
  37. int cucul_canvas_set_figfont(cucul_canvas_t *cv, char const *path)
  38. {
  39. cucul_figfont_t *ff = NULL;
  40. if(path)
  41. {
  42. ff = _cucul_open_figfont(path);
  43. if(!ff)
  44. return -1;
  45. }
  46. if(cv->ff)
  47. _cucul_free_figfont(cv->ff);
  48. cv->ff = ff;
  49. return 0;
  50. }
  51. #define STD_GLYPHS (127 - 32)
  52. #define EXT_GLYPHS (STD_GLYPHS + 7)
  53. cucul_figfont_t * _cucul_open_figfont(char const *path)
  54. {
  55. char altpath[2048];
  56. char buf[2048];
  57. char hardblank[10];
  58. cucul_figfont_t *ff;
  59. char *data = NULL;
  60. cucul_file_t *f;
  61. unsigned int i, j, size, comment_lines;
  62. ff = malloc(sizeof(cucul_figfont_t));
  63. if(!ff)
  64. {
  65. seterrno(ENOMEM);
  66. return NULL;
  67. }
  68. /* Open font: if not found, try .tlf, then .flf */
  69. f = _cucul_file_open(path, "r");
  70. if(!f)
  71. {
  72. snprintf(altpath, 2047, "%s.tlf", path);
  73. altpath[2047] = '\0';
  74. f = _cucul_file_open(altpath, "r");
  75. }
  76. if(!f)
  77. {
  78. snprintf(altpath, 2047, "%s.flf", path);
  79. altpath[2047] = '\0';
  80. f = _cucul_file_open(altpath, "r");
  81. }
  82. if(!f)
  83. {
  84. free(ff);
  85. seterrno(ENOENT);
  86. return NULL;
  87. }
  88. /* Read header */
  89. ff->print_direction = 0;
  90. ff->full_layout = 0;
  91. ff->codetag_count = 0;
  92. _cucul_file_gets(buf, 2048, f);
  93. if(sscanf(buf, "%*[ft]lf2a%6s %u %u %u %i %u %u %u %u\n", hardblank,
  94. &ff->height, &ff->baseline, &ff->max_length,
  95. &ff->old_layout, &comment_lines, &ff->print_direction,
  96. &ff->full_layout, &ff->codetag_count) < 6)
  97. {
  98. debug("figfont error: `%s' has invalid header: %s", path, buf);
  99. _cucul_file_close(f);
  100. free(ff);
  101. seterrno(EINVAL);
  102. return NULL;
  103. }
  104. if(ff->old_layout < -1 || ff->old_layout > 63 || ff->full_layout > 32767
  105. || ((ff->full_layout & 0x80) && (ff->full_layout & 0x3f) == 0
  106. && ff->old_layout))
  107. {
  108. debug("figfont error: `%s' has invalid layout %i/%u",
  109. path, ff->old_layout, ff->full_layout);
  110. _cucul_file_close(f);
  111. free(ff);
  112. seterrno(EINVAL);
  113. return NULL;
  114. }
  115. ff->hardblank = cucul_utf8_to_utf32(hardblank, NULL);
  116. /* Skip comment lines */
  117. for(i = 0; i < comment_lines; i++)
  118. _cucul_file_gets(buf, 2048, f);
  119. /* Read mandatory characters (32-127, 196, 214, 220, 228, 246, 252, 223)
  120. * then read additional characters. */
  121. ff->glyphs = 0;
  122. ff->lookup = NULL;
  123. for(i = 0, size = 0; !_cucul_file_eof(f); ff->glyphs++)
  124. {
  125. if((ff->glyphs % 2048) == 0)
  126. ff->lookup = realloc(ff->lookup,
  127. (ff->glyphs + 2048) * 2 * sizeof(int));
  128. if(ff->glyphs < STD_GLYPHS)
  129. {
  130. ff->lookup[ff->glyphs * 2] = 32 + ff->glyphs;
  131. }
  132. else if(ff->glyphs < EXT_GLYPHS)
  133. {
  134. static int const tab[7] = { 196, 214, 220, 228, 246, 252, 223 };
  135. ff->lookup[ff->glyphs * 2] = tab[ff->glyphs - STD_GLYPHS];
  136. }
  137. else
  138. {
  139. if(_cucul_file_gets(buf, 2048, f) == NULL)
  140. break;
  141. /* Ignore blank lines, as in jacky.flf */
  142. if(buf[0] == '\n' || buf[0] == '\r')
  143. continue;
  144. /* Ignore negative indices for now, as in ivrit.flf */
  145. if(buf[0] == '-')
  146. {
  147. for(j = 0; j < ff->height; j++)
  148. _cucul_file_gets(buf, 2048, f);
  149. continue;
  150. }
  151. if(!buf[0] || buf[0] < '0' || buf[0] > '9')
  152. {
  153. debug("figfont error: glyph #%u in `%s'", ff->glyphs, path);
  154. free(data);
  155. free(ff->lookup);
  156. free(ff);
  157. seterrno(EINVAL);
  158. return NULL;
  159. }
  160. if(buf[1] == 'x')
  161. sscanf(buf, "%x", &ff->lookup[ff->glyphs * 2]);
  162. else
  163. sscanf(buf, "%u", &ff->lookup[ff->glyphs * 2]);
  164. }
  165. ff->lookup[ff->glyphs * 2 + 1] = 0;
  166. for(j = 0; j < ff->height; j++)
  167. {
  168. if(i + 2048 >= size)
  169. data = realloc(data, size += 2048);
  170. _cucul_file_gets(data + i, 2048, f);
  171. i = (uintptr_t)strchr(data + i, 0) - (uintptr_t)data;
  172. }
  173. }
  174. _cucul_file_close(f);
  175. if(ff->glyphs < EXT_GLYPHS)
  176. {
  177. debug("figfont error: only %u glyphs in `%s', expected at least %u",
  178. ff->glyphs, path, EXT_GLYPHS);
  179. free(data);
  180. free(ff->lookup);
  181. free(ff);
  182. seterrno(EINVAL);
  183. return NULL;
  184. }
  185. /* Import buffer into canvas */
  186. ff->fontcv = cucul_create_canvas(0, 0);
  187. cucul_import_memory(ff->fontcv, data, i, "utf8");
  188. free(data);
  189. /* Remove EOL characters. For now we ignore hardblanks, don’t do any
  190. * smushing, nor any kind of error checking. */
  191. for(j = 0; j < ff->height * ff->glyphs; j++)
  192. {
  193. unsigned long int ch, oldch = 0;
  194. for(i = ff->max_length; i--;)
  195. {
  196. ch = cucul_get_char(ff->fontcv, i, j);
  197. /* Replace hardblanks with U+00A0 NO-BREAK SPACE */
  198. if(ch == ff->hardblank)
  199. cucul_put_char(ff->fontcv, i, j, ch = 0xa0);
  200. if(oldch && ch != oldch)
  201. {
  202. if(!ff->lookup[j / ff->height * 2 + 1])
  203. ff->lookup[j / ff->height * 2 + 1] = i + 1;
  204. }
  205. else if(oldch && ch == oldch)
  206. cucul_put_char(ff->fontcv, i, j, ' ');
  207. else if(ch != ' ')
  208. {
  209. oldch = ch;
  210. cucul_put_char(ff->fontcv, i, j, ' ');
  211. }
  212. }
  213. }
  214. return ff;
  215. }
  216. int _cucul_free_figfont(cucul_figfont_t *ff)
  217. {
  218. cucul_free_canvas(ff->fontcv);
  219. free(ff->lookup);
  220. free(ff);
  221. return 0;
  222. }