a simple textfile based psf font editor suite
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.
 
 
 

207 lines
5.1 KiB

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <ctype.h>
  5. #include "psftools_version.h"
  6. #define LINEBUFSIZE 1024
  7. /* generates a text font template
  8. */
  9. static int psft_generate(const char* outfile, unsigned int version, unsigned int width, unsigned int height, unsigned int nchars, int uni)
  10. {
  11. if (version != 1 && version != 2) {
  12. fprintf(stderr, "psfc: invalid version number: %u\n", version);
  13. return 0;
  14. }
  15. if ((version == 1 && width != 8) || width == 0) {
  16. fprintf(stderr, "psfc: invalid width%s: %u\n", width ? " for version 1 files" : "", width);
  17. return 0;
  18. }
  19. if (height == 0) {
  20. fprintf(stderr, "psfc: invalid height: %u\n", height);
  21. return 0;
  22. }
  23. if (version ==1 && nchars != 256 && nchars != 512) {
  24. fprintf(stderr, "psfc: value for -n must be either 256 or 512 for version 1 psf files\n");
  25. }
  26. FILE *out = stdout;
  27. if (outfile) {
  28. out = fopen(outfile, "w");
  29. if (!out) {
  30. perror("psft");
  31. return 0;
  32. }
  33. }
  34. fprintf(out, "@psf%u\n", version);
  35. fprintf(out, "Width: %u\n", width);
  36. fprintf(out, "Height: %u\n", height);
  37. fprintf(out, "Pixel: #\n");
  38. unsigned int ch, x, y;
  39. for (ch = 0; ch < nchars; ++ch) {
  40. fprintf(out, "@%u", ch);
  41. if (uni) { fprintf(out, ": U+%04x", ch); }
  42. fputc('\n', out);
  43. for (y = 0; y < height; ++y) {
  44. for (x = 0; x < width; ++x) {
  45. fputc('.', out);
  46. }
  47. fputc('\n', out);
  48. }
  49. }
  50. if (out != stdout) { fclose(out); }
  51. return 1;
  52. }
  53. static int skipws(const char* buf, int pos)
  54. {
  55. while (buf[pos] && isspace(buf[pos])) {
  56. ++pos;
  57. }
  58. return pos;
  59. }
  60. /* renumbers glyphs in a text font file
  61. */
  62. static int psft_renumber(const char *infile, const char *outfile)
  63. {
  64. FILE *in = stdin, *out = stdout;
  65. if (infile) {
  66. in = fopen(infile, "r");
  67. if (!in) {
  68. perror("psft");
  69. return 0;
  70. }
  71. }
  72. if (outfile) {
  73. out = fopen(outfile, "w");
  74. if (!out) {
  75. perror("psft");
  76. fclose(in);
  77. return 0;
  78. }
  79. }
  80. char inbuf[LINEBUFSIZE], outbuf[LINEBUFSIZE], *line;
  81. unsigned int cnt = 0, lineno = 0;
  82. while ((line = fgets(inbuf, LINEBUFSIZE, in)) != 0) {
  83. ++lineno;
  84. int pos = skipws(line, 0);
  85. if (line[pos] == '@' && (isdigit(line[pos+1]) || isspace(line[pos+1]) || line[pos+1] == ':')) {
  86. int pos1 = pos + 1;
  87. while (isdigit(line[pos1])) { ++pos1; }
  88. char oc = line[pos+1];
  89. line[pos+1] = '\0';
  90. snprintf(outbuf, LINEBUFSIZE, "%s%d", line, cnt++);
  91. line[pos+1] = oc;
  92. if (strlen(outbuf) + strlen(&line[pos1]) >= LINEBUFSIZE) {
  93. fprintf(stderr, "psft: output line too long for line %u\n", lineno);
  94. fclose(in);
  95. fclose(out);
  96. return 0;
  97. }
  98. strcat(outbuf, &line[pos1]);
  99. line = outbuf;
  100. } else if (line[pos] == '@' && strncasecmp(&line[pos], "@psf", 4) != 0) {
  101. fprintf(stderr, "psft: invalid glyph header in line %u\n", lineno);
  102. fclose(in);
  103. fclose(out);
  104. return 0;
  105. }
  106. fputs(line, out);
  107. }
  108. if (out != stdout) { fclose(out); }
  109. if (in != stdin) { fclose(in); }
  110. return 1;
  111. }
  112. static void usage(const char *cmd)
  113. {
  114. fprintf(stderr, "Usage: %s cmd [opts]\n", cmd);
  115. fputs( "cmd is one of\n"
  116. " ren[umber] [infile [outfile]]\n"
  117. " renumber glyphs. If infile is omitted of -, defaults to stdin.\n"
  118. " If outfile is omitted, defaults to stdout.\n"
  119. " gen[erate] <version> [-w <width>] [-h <height>] [-n <num>] [-u] [outfile]\n"
  120. " generate a new font template. version is 1 or 2, depending on\n"
  121. " the psf version you want to generate. width and height default\n"
  122. " to 8, and num (the amount of chars in the font) defaults to 256.\n"
  123. " Specify -u to add sample unicode values to the template.\n"
  124. " If outfile is omitted, defaults to stdout.\n"
  125. " -h|--help|help\n"
  126. " print this help\n"
  127. , stderr);
  128. fprintf(stderr, "psftools version %s\n", PSFTOOLS_VERSION);
  129. exit(1);
  130. }
  131. int main(int argc, char **argv)
  132. {
  133. if (argc < 2) {
  134. usage(argv[0]);
  135. }
  136. if (strcmp(argv[1], "ren") == 0 || strcmp(argv[1], "renumber") == 0) {
  137. if (argc > 4) {
  138. usage(argv[0]);
  139. }
  140. const char *infile = 0, *outfile = 0;
  141. if (argc >= 3 && strcmp(argv[2], "-") != 0) {
  142. infile = argv[2];
  143. }
  144. if (argc == 4) {
  145. outfile = argv[3];
  146. }
  147. if (!psft_renumber(infile, outfile)) {
  148. exit(1);
  149. }
  150. } else if (strcmp(argv[1], "gen") == 0 || strcmp(argv[1], "generate") == 0) {
  151. if (argc < 3) {
  152. usage(argv[0]);
  153. }
  154. unsigned int version = 0, width = 8, height = 8, num = 256;
  155. const char* outfile = 0;
  156. int uni = 0, arg = 3;
  157. version = strtoul(argv[2], 0, 10);
  158. while (arg + 1 < argc) {
  159. if (!strcmp(argv[arg], "-w")) {
  160. width = (unsigned int) strtoul(argv[arg + 1], 0, 10);
  161. arg += 2;
  162. } else if (!strcmp(argv[arg], "-h")) {
  163. height = (unsigned int) strtoul(argv[arg + 1], 0, 10);
  164. arg += 2;
  165. } else if (!strcmp(argv[arg], "-n")) {
  166. num = (unsigned int) strtoul(argv[arg + 1], 0, 10);
  167. arg += 2;
  168. } else if (!strcmp(argv[arg], "-u")) {
  169. uni = 1;
  170. arg += 1;
  171. } else {
  172. usage(argv[0]);
  173. }
  174. }
  175. if (arg < argc) {
  176. if (!strcmp(argv[arg], "-u")) {
  177. uni = 1;
  178. } else {
  179. outfile = argv[arg];
  180. }
  181. }
  182. if (!psft_generate(outfile, version, width, height, num, uni)) {
  183. exit(1);
  184. }
  185. } else if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "help") == 0) {
  186. usage(argv[0]);
  187. } else {
  188. usage(argv[0]);
  189. }
  190. exit(0);
  191. }