Changeset 13 in projects for schriften/papertapefont.c
- Timestamp:
- Sep 5, 2008, 1:58:47 AM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
schriften/papertapefont.c
r12 r13 5 5 * This file contains library routines (see papertapefont.h) for 6 6 * reading and writing "papertape font" files, as well as a 7 * stand alone program.7 * powerful cross platform working stand alone program. 8 8 * 9 9 * To compile the CLI program, define STANDALONE, e.g. … … 12 12 * gcc papertapefont.c -DSTANDALONE=1 13 13 * 14 * See the document "FONT_FILES.txt" in the source code directory 15 * for an introducion and manual. 16 * 14 17 * Initially written in a few hours (500 lines code) between 15 18 * 02:00 and 06:00 at 04.09.2008 19 * Improved and multiple times rewritten the next day to 20 * 1000 lines ;-) 16 21 * 17 22 * (c) 2008 Sven Köppel … … 40 45 #include <string.h> 41 46 42 #define PAPERTAPE_FONT_MAX_LINE_LENGTH 10043 44 47 byte_t papertape_font_line2byte(const char *line); 45 46 PAPERTAPE_FONT* papertape_font_new_from_file(FILE* fh) { 47 PAPERTAPE_FONT* font; 48 char line[PAPERTAPE_FONT_MAX_LINE_LENGTH]; 49 char ascii_id; 50 byte_t* bytes; 51 int bytes_n; 52 int x; 53 54 // allocate new font object 55 font = malloc(sizeof(PAPERTAPE_FONT)); 56 if(!font || !fh) 48 void papertape_font_byte2line(const byte_t byte, FILE *write); 49 50 /** 51 * Allocate a new PAPERTAPE_FONT object, without any character. 52 * You can use papertape_font_new_from_file() if you want to create 53 * a PAPERTAPE_FONT object from file or use papertape_font_import_from_file() 54 * or papertape_font_import_from_schematics() to fill your PAPERTAPE_FONT 55 * object. 56 **/ 57 // implemented as a Macro due to simplicity. 58 59 /** 60 * Load a new papertape font from the file called "filename". This 61 * is some more luxurious than calling the single functions. 62 * @return allocated font object or NULL if not possible. 63 **/ 64 PAPERTAPE_FONT* papertape_font_new_from_file(const char* filename) { 65 FILE* file; 66 PAPERTAPE_FONT* font = papertape_font_new(); 67 if(!font) 57 68 return NULL; 58 69 59 // set up as ensurance, against segfaults or simple fonts: 60 font->ascii_id = PAPERTAPE_FONT_CHARACTER_SPACING_ASCII_ID; 61 font->bytes = PAPERTAPE_FONT_CHARACTER_SPACING_DEFAULT_BYTES; 62 font->bytes_n = sizeof(PAPERTAPE_FONT_CHARACTER_SPACING_DEFAULT_BYTES); 70 file = fopen(filename, "r"); 71 if(!file) { 72 perror("Opening papertape font file"); 73 return NULL; 74 } 75 76 papertape_font_load_file(font, file); 77 return font; 78 } 79 80 /** 81 * This will load all characters found in the filehandle (which must be readable). 82 * Characters loaded here will overwrite previous characters, if present. 83 **/ 84 void papertape_font_load_file(PAPERTAPE_FONT* font, FILE* fh) { 85 #define MAX_LINE 100 86 #define MAX_BYTES 30 87 #define MAX_NAME 30 88 89 // Buffer for the line string currently read in 90 char line[MAX_LINE]; 91 // Buffer for the name string currently read in 92 char name[MAX_NAME] = ""; 93 // Buffer for last name string read in 94 char last_name[MAX_NAME] = ""; 95 // Buffer for the bytes currently read in 96 byte_t bytes[MAX_BYTES]; 97 // Real number of bytes already read in 98 int bytes_n = 0; 99 // the current ascii_id 100 char ascii_id = 0; 101 // the last ascii_id 102 char last_ascii_id = 0; 103 // if we haven't already read in one byte from the new 104 // character, this is set to 1. This will force reading in the 105 // current byte. 106 int new_character = 1; 107 108 // for each character package... 109 while(fgets(line, MAX_LINE, fh) != NULL) { 110 /* 111 * the layout of a typical * the layout of a typical long 112 * ASCII line: * special line: 113 * * 114 * |123.45678|x * |123.45678| =named_thing comments 115 * 012345678901 * 01234567890123456789012345678... 116 * * || 117 * length: 12 characters. * 12 chars-^^- char no. 12 118 * * 119 */ 120 121 /* remove "\n" lines at end. We don't need them. */ 122 if(line[strlen(line)-1] == '\n') 123 line[strlen(line)-1] = '\0'; 63 124 64 /*{ 65 byte_t[] def_spacing = PAPERTAPE_FONT_CHARACTER_SPACING_DEFAULT_BYTES; 66 papertape_font_set_char(font, PAPERTAPE_FONT_CHARACTER_SPACING_ASCII_ID, 67 def_spacing, sizeof(def_spacing)); 68 69 }*/ 70 71 // now parse file. 72 73 // for each character package... 74 while(fgets(line, PAPERTAPE_FONT_MAX_LINE_LENGTH, fh)) { 75 // skip comment lines. They are only allowed at 76 // index positions, not in the data byte lines. 77 if(line[0] == '#') 125 /* skip lines which are not a paper tape or which have no id */ 126 if(line[0] != PAPERTAPE_FONT_BORDER || strlen(line) < 12) 78 127 continue; 79 128 80 ascii_id = line[0]; 81 bytes_n = atoi(&line[1]); // atoi will remove spaces 82 bytes = calloc(sizeof(byte_t), bytes_n); // allocate place for bytes 83 84 // parse the bytes notation 85 for(x=0; x < bytes_n; x++) { 86 // break at end of line 87 if(!fgets(line, PAPERTAPE_FONT_MAX_LINE_LENGTH, fh)) 88 break; 89 // add parsed line to byte array 90 bytes[x] = papertape_font_line2byte(line); 91 } 92 93 papertape_font_set_char(font, ascii_id, bytes, bytes_n); 94 // papertape_font_set_char copies the byte, so we free them here 95 free(bytes); 96 } 97 } 129 ascii_id = line[11]; 130 //fprintf(stderr, "Read in line ascii_id 0x%x (%c)\n", ascii_id, ascii_id); 131 132 // strlen: to avoid segfaults 133 if(strlen(line) > (11 + strlen(PAPERTAPE_FONT_SPECIAL_ID)) && 134 strncmp(line+11, PAPERTAPE_FONT_SPECIAL_ID, strlen(PAPERTAPE_FONT_SPECIAL_ID)) == 0) { 135 // we have a special value with a full name 136 ascii_id = 0; 137 int z; 138 // copy name 139 strncpy(name, &line[11+strlen(PAPERTAPE_FONT_SPECIAL_ID)], MAX_NAME); 140 // truncate name to only one word 141 for(z=0; !(name[z] == ' ' || name[z] == '\0' || name[z] == '\t'); z++); 142 name[z] = '\0'; 143 } 144 145 // if we are still at the same byte like the last one... 146 if(new_character || ascii_id == last_ascii_id || 147 ( ascii_id == 0 && (strcmp(name, last_name) == 0) ) 148 ) { 149 //fprintf(stderr, "Save line for 0x%x as no. %i\n", ascii_id, bytes_n+1); 150 // ...then add this byte to the current char byte array 151 if(bytes_n < MAX_BYTES) 152 // only store if enough place in bytes[] array 153 bytes[bytes_n++] = papertape_font_line2byte(line); 154 // leave "last_" values as they are, because they haven't changed anyway 155 } else { 156 // we are at a new char, so let's push the last char to the list 157 if(last_ascii_id == 0) 158 papertape_font_set_special(font, last_name, bytes, bytes_n); 159 else 160 papertape_font_set_char(font, last_ascii_id, bytes, bytes_n); 161 162 // store first byte from new character 163 bytes[0] = papertape_font_line2byte(line); 164 bytes_n = 1; 165 // and tell the next loop that it has to read in. 166 new_character = 1; 167 } 168 169 // Don't force to read in any more. 170 if(last_ascii_id == ascii_id) 171 new_character = 0; 172 last_ascii_id = ascii_id; 173 strcpy(last_name, name); 174 } // while file 175 176 // we are done, and there's still one character left to push to the list 177 if(last_ascii_id == 0) 178 papertape_font_set_special(font, last_name, bytes, bytes_n); 179 else 180 papertape_font_set_char(font, last_ascii_id, bytes, bytes_n); 181 182 // rewind the file handle (if writing is called on the same file, etc.) 183 rewind(fh); 184 } 185 186 /** 187 * Load Papertape font characters from binary array in order which is given 188 * by the "schematics" string. 189 * 190 **/ 191 void papertape_font_load_schematics(PAPERTAPE_FONT* font, const char *schematics, const byte_t *contents, int content_len) { 192 int schematics_len = strlen(schematics); 193 int schematics_x; 194 int content_offset, content_start, content_end; 195 for(schematics_x=0, content_offset=0; schematics_x < schematics_len; schematics_x++) { 196 // find start of current character 197 for(content_start = content_offset; content_start < content_len && 198 contents[content_start] == 0; content_start++); 199 // find end of current character 200 for(content_end = content_start; content_end < content_len && 201 contents[content_end] != 0; content_end++); 202 // make new character between content_start and content_end 203 papertape_font_set_char(font, schematics[schematics_x], 204 contents + content_start, content_end - content_start); 205 // save offset for next character 206 content_offset = content_end + 1; 207 } 208 } 209 210 98 211 99 212 /** … … 105 218 byte_t value = 0; 106 219 #define isPunched(pos, add) if(line[pos] != ' ') { value += add; } 107 isPunched(0 , 0);220 /* left border */ 108 221 isPunched(1 , 1); 109 222 isPunched(2, 2); 110 223 isPunched(3, 4); 111 isPunched(4, 8); 112 isPunched(5, 16); 113 isPunched(6, 32); 114 isPunched(7, 64); 115 isPunched(8, 128); 224 /* feed hole */ 225 isPunched(5, 8); 226 isPunched(6, 16); 227 isPunched(7, 32); 228 isPunched(8, 64); 229 isPunched(9, 128); 230 /* right border */ 116 231 return value; 117 232 } 118 233 234 /** 235 * This is the invert function of papertape_font_line2byte. It writes to 236 * file handle "write" a line, but without Newline! 237 * 238 **/ 239 void papertape_font_byte2line(const byte_t byte, FILE *write) { 240 #define paintPunched(check) fputc((byte & check) ?\ 241 PAPERTAPE_FONT_WRITE_LOGICAL_1 : ' ', write) 242 fputc(PAPERTAPE_FONT_BORDER, write); /* left border */ 243 paintPunched( 1); /* bit 1 */ 244 paintPunched( 2); /* bit 2 */ 245 paintPunched( 4); /* bit 3 */ 246 fputc(PAPERTAPE_FONT_FEED_HOLE, write); /* feed hole */ 247 paintPunched( 8); /* bit 4 */ 248 paintPunched( 16); /* bit 5 */ 249 paintPunched( 32); /* bit 6 */ 250 paintPunched( 64); /* bit 7 */ 251 paintPunched(128); /* bit 8 */ 252 fputc(PAPERTAPE_FONT_BORDER, write); /* right border */ 253 } 254 255 256 /** 257 * This function adds or changes special characters in the papertape font. 258 * These characters are typically white spaces or word spacings. 259 * 260 * @param font The Papertape Font object, e.g. made by papertape_font_new_...() 261 * @param name The Name ID 262 * @param bytes Your byte array which is supposed to represent the character. The function copies it. 263 * @param bytes_n The length of your byte array (counting from 1, of course) 264 * @return 0 if successfully added, 1 otherwise. (It will never return 1 ;-) ) 265 **/ 266 PAPERTAPE_FONT_CHAR* papertape_font_set_special(PAPERTAPE_FONT* font, const char *name, const byte_t* bytes, int bytes_n) { 267 // allocate the new character structure 268 PAPERTAPE_FONT_CHAR *buf; 269 buf = malloc(sizeof(PAPERTAPE_FONT_CHAR)); 270 271 // copy all values to structure 272 buf->ascii_id = 0x0; 273 buf->bytes_n = bytes_n; 274 buf->bytes = malloc(bytes_n); 275 memcpy(buf->bytes, bytes, bytes_n); 276 buf->name = malloc(strlen(name)); 277 strcpy(buf->name, name); 278 279 // Pack it at the very start 280 buf->next = (font->next != NULL) ? font->next : NULL; 281 font->next = buf; 282 283 return buf; 284 } 119 285 120 286 /** … … 122 288 * Internally, the papertape_font works with a ascii ordered single linked list. So 123 289 * there's no other write access to that list than this function. 290 * 291 * If you want to set/add characters with special long names, use papertape_font_set_special_char. 124 292 * 125 293 * @param font The Papertape Font object, e.g. made by papertape_font_new_...() … … 127 295 * @param bytes Your byte array which is supposed to represent the character. The function copies it. 128 296 * @param bytes_n The length of your byte array (counting from 1, of course) 129 * @return 0 if successfully added, 1 otherwise. (It will never return 1 ;-) )130 **/ 131 intpapertape_font_set_char(PAPERTAPE_FONT* font, char ascii_id, const byte_t* bytes, int bytes_n) {297 * @return A link to the generated character. You don't need it, anyway. 298 **/ 299 PAPERTAPE_FONT_CHAR* papertape_font_set_char(PAPERTAPE_FONT* font, char ascii_id, const byte_t* bytes, int bytes_n) { 132 300 PAPERTAPE_FONT_CHAR *current; 133 301 PAPERTAPE_FONT_CHAR *next; … … 142 310 buf->bytes = malloc(bytes_n); 143 311 memcpy(buf->bytes, bytes, bytes_n); 312 buf->name = NULL; 144 313 buf->next = NULL; 145 146 // Magic ascii id (typically a non printable character) for character spacing147 if(ascii_id == PAPERTAPE_FONT_CHARACTER_SPACING_ASCII_ID) {148 font->bytes = buf->bytes;149 font->bytes_n = buf->bytes_n;150 free(buf); // don't need it.151 return 0;152 }153 314 154 315 // Start going throught the list … … 162 323 current->next = buf; // replace the next pointer with our char 163 324 free(next); // delete the old next pointer. 164 return 0;325 return buf; 165 326 } else if(current->next->ascii_id > ascii_id) { 166 327 // the next one has a bigger ascii_id as we have (perhapse … … 170 331 current->next = buf; // replace the next pointer with our char 171 332 buf->next = next; // pack the next pointer after our pointer 172 return 0;333 return buf; 173 334 } else { 174 335 // the next one has a lower ascii_id as we have, so we have … … 181 342 // or equal to ours. So we simply add our character to the list. 182 343 current->next = buf; 344 return buf; 345 } 346 347 /** 348 * This is an auxillary function to access the linked list. It's not supposed to be used 349 * from outside -- use highlevel functions like set_char or get_label. 350 * @returns Link inside the list, NULL if not found. 351 **/ 352 PAPERTAPE_FONT_CHAR* papertape_font_low_get_char(PAPERTAPE_FONT* font, char ascii_id) { 353 PAPERTAPE_FONT_CHAR* current; 354 current = font; 355 while(current->next != NULL) { 356 if(current->next->ascii_id == ascii_id) { 357 // we have found the right character entry. 358 return current->next; 359 } else 360 current = current->next; 361 } 362 return NULL; 363 } 364 365 /** 366 * This is just like papertape_font_low_get_char, but for special characters. 367 * Ah, one special thing: Special characters are always valid, even if not defined. 368 **/ 369 PAPERTAPE_FONT_CHAR* papertape_font_low_get_special(PAPERTAPE_FONT* font, const char* name) { 370 PAPERTAPE_FONT_CHAR* current; 371 byte_t default_bytes[] = { 0 }; 372 current = font; 373 while(current->next != NULL) { 374 if(current->next->name != NULL && 375 strcmp(current->next->name, name) == 0) { 376 // we have found the right character entry. 377 return current->next; 378 } else 379 current = current->next; 380 } 381 // no special character found. We'll generate one. 382 return papertape_font_set_special(font, name, default_bytes, 1); 383 } 384 385 386 /** 387 * I don't know why one wanted to delete a character, but by using this function you can 388 * do exactly that. 389 * @returns 1 if successful deleted, 0 if not found in list. 390 **/ 391 int papertape_font_del_char(PAPERTAPE_FONT* font, char ascii_id) { 392 // we cannot use papertape_font_low_get_char, because this would need 393 // a double linked list. 394 PAPERTAPE_FONT_CHAR* current; 395 current = font; 396 while(current->next != NULL) { 397 if(current->next->ascii_id == ascii_id) { 398 // we have found the right character entry. 399 if(current->next->next != NULL) { 400 // we are somewhere in the list, so we have to rewrite 401 // the "next" pointer. 402 current->next = current->next->next; 403 } 404 free(current->next); 405 return 1; 406 } else 407 current = current->next; 408 } 409 return 0; 410 } 411 412 /** 413 * This is the same like for normal characters, only for special characters. 414 **/ 415 int papertape_font_del_special(PAPERTAPE_FONT* font, const char* name) { 416 PAPERTAPE_FONT_CHAR* current; 417 current = font; 418 while(current->next != NULL) { 419 if(current->next->name != NULL && 420 strcmp(current->next->name, name) == 0) { 421 // we have found the right character entry. 422 if(current->next->next != NULL) { 423 // we are somewhere in the list, so we have to rewrite 424 // the "next" pointer. 425 current->next = current->next->next; 426 } 427 free(current->next); 428 return 1; 429 } else 430 current = current->next; 431 } 183 432 return 0; 184 433 } … … 199 448 * 200 449 **/ 201 byte_t* papertape_font_get_label(PAPERTAPE_FONT* font, const char* string) { 202 PAPERTAPE_FONT_CHAR* current; 203 //int string_len = strlen(string); 204 int x; // to count throught the string 205 int size = 0; // the size of the output byte array 450 byte_t* papertape_font_get_label(PAPERTAPE_FONT* font, const char* string, int* size) { 451 PAPERTAPE_FONT_CHAR* character_spacing = papertape_font_low_get_special(font, PAPERTAPE_FONT_CHARACTER_SPACING_NAME); 452 int x; // to count throught the string 453 *size = 0; // the size of the output byte array 206 454 byte_t* output; 207 int pos; // current position in output array 208 209 // first step: Count the neccessary size for the output byte array 455 int output_pos; // current position in output array 456 int clen = strlen(string)*2 -1; // length of characters stack array 457 // dynamic stack arrays are ISO C99, compare http://gcc.gnu.org/onlinedocs/gcc-4.3.2/gcc/Variable-Length.html 458 PAPERTAPE_FONT_CHAR *characters[ clen ]; 459 int cpos = 0; // current position in character array 460 461 // pack the font char array together 210 462 for(x=0; string[x] != '\0'; x++) { 211 // skip the font spacing at one character in the string 212 // (because it's only between the letters) 213 if(x != 0) 214 size += font->bytes_n; 215 216 // go throught the list and try to find the current character. 217 current = font; 218 while(1) { 219 if(current->ascii_id == string[x]) { 220 size += current->bytes_n; 221 break; 222 } else if(current->next != NULL) { 223 current = current->next; 224 continue; 225 } else { 226 // We have reached the end of the character 227 // list, but the current character is not available! 228 fprintf(stderr, "papertape_font_get_label: Character \"%c\" in \"%s\" not printable\n", 229 string[x], string); 230 break; 231 } 463 // find white spaces 464 if(string[x] == ' ') 465 characters[cpos] = papertape_font_low_get_special(font, PAPERTAPE_FONT_WHITE_SPACE_NAME); 466 else 467 characters[cpos] = papertape_font_low_get_char(font, string[x]); 468 if(characters[cpos] == NULL) { 469 fprintf(stderr, "papertape_font_get_label: Character \"%c\" in \"%s\" not printable\n", 470 string[x], string); 471 continue; 472 } 473 474 size += characters[cpos]->bytes_n; 475 cpos++; 476 477 // add the characters spacing after each character 478 if(x+1 < strlen(string)) { // but not at the last character 479 characters[cpos] = character_spacing; 480 *size += characters[cpos]->bytes_n; 481 cpos++; 232 482 } 233 483 } 234 484 235 485 // now malloc the output byte array and generate it 236 output = malloc(size); 237 for(x=0,pos=0; string[x] != '\0'; x++) { 238 // go throught the list, another time 239 current = font; 240 while(1) { 241 if(current->ascii_id == string[x]) { 242 memcpy(output+pos, current->bytes, current->bytes_n); 243 pos += current->bytes_n; 244 break; 245 } else if(current->next != NULL) { 246 current = current->next; 247 continue; 248 } // else: Character not found. Ignore it, 249 // because error already printed at first run. 250 } 251 // add the character spacer after each character 252 if(x+1 < strlen(string)) { // but not at the last character 253 memcpy(output+pos, font->bytes, font->bytes_n); 254 pos += font->bytes_n; 255 } 256 } 486 output = malloc(*size); 487 for(cpos=0,output_pos=0; cpos < clen; cpos++, output_pos += characters[cpos]->bytes_n) 488 memcpy(output+output_pos, characters[cpos], characters[cpos]->bytes_n); 257 489 258 490 // we are done. … … 269 501 **/ 270 502 int papertape_font_string_is_printable(PAPERTAPE_FONT *font, const char* string) { 271 PAPERTAPE_FONT_CHAR* current;272 503 int x; 273 504 274 505 for(x=0; string[x] != '\0'; x++) { 275 current = font; 276 while(1) { 277 if(current->ascii_id == string[x]) 278 // this character is clean. 279 break; 280 else if(current->next != NULL) 281 // have not found character yet. 282 current = current->next; 283 else 284 // at the end of list -- character not found! 285 return 0; 286 } 506 if(string[x] == ' ') 507 // white spaces are always printable 508 continue; 509 if(papertape_font_low_get_char(font, string[x]) == NULL) 510 // character not found! 511 return 0; 287 512 } 288 513 … … 304 529 current = font; 305 530 while(1) { 306 // write index line 307 fprintf(fh, "%c %i\n", current->ascii_id, current->bytes_n); 308 // write data binary things. 531 // write bytes and identifiers 309 532 for(x=0; x<current->bytes_n; x++) { 310 #define paintPunched(check) fputc((current->bytes[x] & check) ?\ 311 fputc(PAPERTAPE_FONT_WRITE_LOGICAL_1_CHARACTER, fh) : fputc(' ', fh), fh) 312 paintPunched( 0); 313 paintPunched( 1); 314 paintPunched( 2); 315 paintPunched( 4); 316 paintPunched( 8); 317 paintPunched( 16); 318 paintPunched( 32); 319 paintPunched( 64); 320 paintPunched(128); 533 papertape_font_byte2line(current->bytes[x], fh); 534 if(current->ascii_id == 0) { 535 fputs(PAPERTAPE_FONT_SPECIAL_ID, fh); 536 fputs(current->name, fh); 537 } else 538 fputc(current->ascii_id, fh); 321 539 fputc('\n', fh); 322 540 } 323 541 324 542 // and go on. Or break, if at end. 325 if(current->next != NULL) 543 if(current->next != NULL) { 544 // write a neat NULL byte as eye candy seperation 545 papertape_font_byte2line(0x0, fh); 546 fputc('\n', fh); 326 547 current = current->next; 327 else548 } else 328 549 break; 329 550 } 330 } 331 332 /* If we want it to be a standalone program */ 551 552 return 1; // could be void. 553 } 554 /** 555 * This will print a dump of the papertape font linked list, just for debugging purpose, 556 * to the file handle. It's just fine to give "stderr" at the file handle. 557 **/ 558 void papertape_font_dump(PAPERTAPE_FONT *font, FILE* fh) { 559 PAPERTAPE_FONT_CHAR* current; 560 int ram_bytes = 0; 561 int i = 0; 562 int x; 563 564 current = font; 565 while(1) { 566 ram_bytes += sizeof(PAPERTAPE_FONT_CHAR); 567 if(current->ascii_id == 0 && current->name == NULL) 568 fprintf(fh, "%i. char: Special character, no name (broken), %i bytes allocated\n", i++, current->bytes_n); 569 else if(current->ascii_id == 0) { 570 fprintf(fh, "%i. char: Special character, name \"%s\", %i bytes allocated\n", i++, current->name, current->bytes_n); 571 ram_bytes += strlen(current->name)+1; 572 } else 573 fprintf(fh, "%i. char: \"%c\" (0x%x), %i bytes allocated\n", i++, current->ascii_id, current->ascii_id, current->bytes_n); 574 if(current->bytes == NULL) { 575 fprintf(fh, "No bytes allocated!\n"); 576 } else { 577 ram_bytes += current->bytes_n; 578 for(x=0; x < current->bytes_n; x++) { 579 papertape_font_byte2line(current->bytes[x], fh); 580 fputc('\n', fh); 581 } 582 } 583 584 if(current->next == NULL) { 585 fprintf(fh, "End of list.\n"); 586 fprintf(fh, "Statistics: %i entries, %i total bytes in heap\n", i, ram_bytes); 587 return; 588 } else 589 current = current->next; 590 } 591 } 592 593 /** 594 * The main() method (and auxillary helper functions) is only compiled when the switch 595 * "STANDALONE" is defined. If not, we'll only get the simple library. 596 * 597 **/ 333 598 #ifdef STANDALONE 599 600 /** 601 * A helper method for the standalone main(): Read contents of a stream 602 * in a dynamically allocated heap byte array. 603 **/ 334 604 int file_get_contents(FILE *stream, byte_t **content) { 335 605 byte_t buf[4096]; … … 373 643 } 374 644 645 /** 646 * The main method. We are using an own parameter system with extensive help messages. 647 * No so much parameter flexibility, but it should be enough :-) 648 **/ 375 649 int main(int argc, char **argv) { 376 enum { 377 RENDER_TEXT, 378 WRITE_CHAR, 379 EXPORT, 380 IMPORT, 381 NOTHING 382 } action; 383 action = NOTHING; 384 char *schematics = PAPERTAPE_FONT_SCHEMATICS_DEFAULT; 385 char *render_text; 386 char write_char; 387 char *font_name; 388 FILE *font_file; 389 PAPERTAPE_FONT *font; 390 int c; 650 // Instead of poor getopt emulation, an own parameter system like "svn" CLI client has it 651 if(argc < 3 || strcasecmp(argv[1], "help") == 0) { 652 // argc == 1: Wrong call like "./font", missing subcommand. 653 // Wrong call (like "./font label"), or help call (like "./font help"). 654 // Display help. Or startup help system. 655 if(argc < 3) { 656 fprintf(stderr, "Usage: %s <subcommand> [subcommand option] <font file>\n" 657 "The Papertape font utility program.\n" 658 "Type '%s help <subcommand>' for help on a specific subcommand.\n" 659 "The <subcommand> and <font file> parameters are mandatory\n" 660 "\n" 661 "Available subcommands:\n" 662 " help Starts up this help system\n" 663 " label Prints out a complete label, given as the option\n" 664 " set Sets the character with the ASCII ID (e.g. 0x20), reads from STDIN\n" 665 " del Deletes the character with the ASCII ID from the font file\n" 666 " dump Parses the font file and prints out the result, for debugging\n" 667 " export Exports the font file to STDOUT, according to schematics\n" 668 " import Imports the font file, according to schematics\n" 669 " Default schematics: %s\n", 670 argv[0], argv[0], PAPERTAPE_FONT_SCHEMATICS_DEFAULT); 671 } 672 673 if(argc >= 3) { 674 // verbose Help system. 675 if(strcasecmp(argv[2], "label") == 0) { 676 fprintf(stderr, "label: Print out the compiled bytes for the translated label.\n" 677 "Expects String as subcommand option.\n\n" 678 "Example calls:\n" 679 " Prints out yor text to STDOUT.\n" 680 " $ %s label \"The text you want to label\" your-font-file.ptf:\n" 681 " The same with \"hello world\". Upper/lowercase produces the same result, btw.\n" 682 " $ %s label hello\\ world your-font-file.ptf:\n" 683 " This writes the output to the file hallo-welt.bin:\n" 684 " $ %s label hallo\\ Welt your-font-file.ptf > hallo-welt.bin\n" 685 " This will punch out all files in the directory with the right label before\n" 686 " $ for x in *; do %s label \"$x\" ../fonts/your.ptf | cat - \"$x\" | ./punch; done;\n", 687 argv[0], argv[0], argv[0], argv[0]); 688 } else if(strcasecmp(argv[2], "set") == 0) { 689 fprintf(stderr, "set: Changes or adds a character in the font file\n" 690 "Expects the wanted character as hex or character as subcommand option.\n\n" 691 "Example calls:\n" 692 " This will create a new font file that contains the character 'a':\n" 693 " $ cat how-a-should-look-like.bin | %s set a new-font-file.ptf\n" 694 " This will overwrite the current value of the character 'a':\n" 695 " $ cat a-new-look-for-letter-a.bin | %s set a new-font-file.ptf\n" 696 " This will set the blank space character:\n" 697 " $ echo -en \"\\0\" | %s set \" \" existing-font-file.ptf\n" 698 " This will do exactly the same like above:\n" 699 " $ echo -en \"\\0\" | %s set 0x20 existing-font-file.ptf\n", 700 argv[0], argv[0], argv[0], argv[0]); 701 } else if(strcasecmp(argv[2], "del") == 0) { 702 fprintf(stderr, "del: Deletes one or more characters from a font file\n" 703 "Expects one character as subcommand option.\n\n" 704 "Example calls:\n" 705 " Delete a 'm' from your font file:\n" 706 " $ %s del m your-font-file.ptf\n", 707 argv[0]); 708 } else if(strcasecmp(argv[2], "dump") == 0) { 709 fprintf(stderr, "dump: Parse a font file and print out the results to stdout. This is\n" 710 "pracitcal for detecting syntax errors in the font file.\n\n" 711 "Example calls:\n" 712 " Get a dump:\n" 713 " $ %s dump your-font-file.ptf\n" 714 " Save it somewhere:\n" 715 " $ %s dump your-font-file.ptf > dump.txt\n", 716 argv[0], argv[0]); 717 } else if(strcasecmp(argv[2], "export") == 0|| strcasecmp(argv[2], "import") == 0) { 718 fprintf(stderr, "import/export: Converting font files to complete binary files on the fly\n" 719 "You can give a scheme optionally as subcommand option.\n" 720 "This is the default scheme:\n" 721 " %s\n\n" 722 "Example calls:\n" 723 " Export an existing font file, edit the file with an hex editor and import it again:\n" 724 " $ %s export your-font-file.ptf > font-file-export.bin\n" 725 " $ khexdump font-file-export.bin\n" 726 " [ some GUI editing, and so on...]\n" 727 " $ cat font-file-export.bin | %s import your-font-file.ptf\n" 728 " Import to a new font file from existin g other font mechanism:\n" 729 " $ SCHEME=\"abcdefgh...4567890 ()<>\"\n" 730 " $ perl another-font.pl \"$SCHEME\" | %s import \"%s\" importet-font-file.ptf\n" 731 " Make a new font file which only contains the digits of the old file:\n" 732 " $ %s export \"0123456789\" existing.ptf | %s import \"0123456789\" new.ptf\n", 733 PAPERTAPE_FONT_SCHEMATICS_DEFAULT, argv[0], argv[0], argv[0], argv[0], argv[0], argv[0]); 734 } else { 735 fprintf(stderr, "'%s': unknown subcommand. Type '%s help' for a list of valid commands.\n", 736 argv[2], argv[0]); 737 } 738 } // verbose help 739 return 0; 740 } // Help messages 741 742 if(strcasecmp(argv[1], "export") == 0 || strcasecmp(argv[1], "label") == 0) { 743 // export or label. 744 int size; 745 byte_t *bytes; 746 PAPERTAPE_FONT *font; 747 748 if(! (font=papertape_font_new_from_file(argc == 4 ? argv[3] : argv[2]) )) { 749 fprintf(stderr, "Error creating Papertape font.\n"); 750 return 3; 751 } 752 753 bytes = papertape_font_get_label(font, argc == 4 ? argv[3] : PAPERTAPE_FONT_SCHEMATICS_DEFAULT, &size); 754 fwrite(bytes, size, sizeof(byte_t), stdout); 755 return 0; 756 } else if(strcasecmp(argv[1], "set") == 0 || strcasecmp(argv[1], "del") == 0) { 757 // set and delete 758 char character; 759 FILE *font_file; 760 PAPERTAPE_FONT *font; 761 762 // at first: get the character 763 if(argc == 3) { 764 fprintf(stderr, "%s: Too few arguments! Missing character. Type '%s help %s' for usage.\n", 765 argv[1], argv[0], argv[1]); 766 return 1; 767 } 768 if(strlen(argv[2]) > 1) 769 // A Number like "255", 0x20 or 080. strol will parse it. 770 character = (char)strtol(argv[2], NULL, 0); 771 else 772 // only one character in ASCII. 773 character = argv[2][0]; 774 775 // open file for reading and WRITING. 776 font_file = fopen(argv[3], "r+"); 777 if(!font_file) { 778 perror("Opening font file for writing"); 779 return 2; 780 } 781 font = papertape_font_new(); 782 papertape_font_load_file(font, font_file); 783 784 if(strcasecmp(argv[1], "set")) { 785 // change/add character 786 byte_t *contents; 787 int bytes = file_get_contents(stdin, &contents); 788 printf("Read in %i bytes for letter %c (seen as byte: 0x%x)\n", bytes, character, character); 789 papertape_font_set_char(font, character, contents, bytes); 790 printf("Set character %c successfully.\n", character); 791 } else { 792 // delete character 793 printf(papertape_font_del_char(font, character) ? 794 "Deleted %c successfully from file %s\n" : 795 "Could not find %c in file %s!\n", 796 character, argv[3]); 797 } 798 799 // write papertape file. 800 papertape_font_write_to_file(font, font_file); 801 return 0; 802 } else if(strcasecmp(argv[1], "dump") == 0) { 803 PAPERTAPE_FONT* font = papertape_font_new_from_file(argv[2]); 804 printf("This is a dump from the internal single linked ordered list,\n" 805 "created from the file '%s':\n\n", argv[2]); 806 papertape_font_dump(font, stdout); 807 return 0; 808 } else if(strcasecmp(argv[1], "import") == 0) { 809 // run an import. 810 PAPERTAPE_FONT *font = papertape_font_new(); 811 FILE* font_file; 812 byte_t *contents; 813 int content_len; 814 char *schematics; 815 816 // open file for DESTROYING WRITING. 817 font_file = fopen(argc == 4 ? argv[3] : argv[2], "w"); 818 if(font_file == NULL) { 819 perror("Opening font file for writing"); 820 return 2; 821 } 822 823 schematics = argc == 4 ? argv[2] : PAPERTAPE_FONT_SCHEMATICS_DEFAULT; 824 825 fprintf(stderr, "Reading from stdin, expecting schematics %s\n", schematics); 826 content_len = file_get_contents(stdin, &contents); 827 // debug: print it out! 828 // fwrite(contents, 1, content_len, stdout); exit(0); 391 829 392 // poor man's getopt, for windows portability 393 for(c=1; c<argc; c++) { 394 if(strlen(argv[c]) == 2 && *argv[c] == '-') { 395 argv[c]++; // shift "-" flag thingy. 396 switch(*argv[c]) { 397 case 'h': 398 fprintf(stderr, "Usage: %s [OPTIONS...] [A PAPERTAPE FONT FILE]\n" 399 "The Papertape font utilitie program.\n\n" 400 " optional parameters:\n" 401 " -h display this help message\n" 402 " -l [TEXT] Render this text to STDOUT\n" 403 " -w [ASCII ID] Set the character with that ASCII ID, read from STDIN\n" 404 " -o Export the font file, according to schematics, to STDOUT\n" 405 " -i Import to font file (overwrite it), according to schematics, from STDIN\n\n" 406 " -s [Sch string] Define own schematics for -i/-o. Default is:\n" 407 " %s\n", 408 argv[0], PAPERTAPE_FONT_SCHEMATICS_DEFAULT); 409 return 0; 410 411 case 'l': 412 action = RENDER_TEXT; 413 render_text = argv[++c]; 414 break; 415 416 case 'w': 417 action = WRITE_CHAR; 418 write_char = *argv[++c]; 419 break; 420 421 case 'o': action = EXPORT; break; 422 case 'i': action = IMPORT; break; 423 424 case 's': 425 schematics = argv[++c]; 426 } // switch 427 } // if flag 428 else { 429 // not flag but... Papertape Font file! 430 font_name = argv[c]; 431 } 432 } // for each argv 433 434 // Open Font File 435 if(font_name) { 436 char *mode; 437 switch(action) { 438 case RENDER_TEXT: 439 case EXPORT: mode = "r"; break; 440 case WRITE_CHAR: mode = "rw"; break; 441 case IMPORT: mode = "w"; break; 442 default: 443 fprintf(stderr, "Error: No action specified. Call %s -h\n", argv[0]); 444 return 1; 445 } 446 447 font_file = fopen(font_name, mode); 448 if(!font_file) { 449 perror("Opening font file"); 450 return 2; 451 } 830 // Parse schematics 831 papertape_font_load_schematics(font, schematics, contents, content_len); 832 833 fprintf(stderr, "Readed from stdin successfully. Here you get a dump:\n"); 834 papertape_font_dump(font, stdout); 835 836 // that's it, we are done. Write the papertape font. 837 papertape_font_write_to_file(font, font_file); 838 return 0; 452 839 } else { 453 fprintf(stderr, "Error: No font file specified. Call %s -h\n", argv[0]); 454 } 455 456 // Stupid: papertapefont.c:431: Warnung: Zuweisung erzeugt Zeiger von Ganzzahl ohne Typkonvertierung 457 // Adding (PAPERTAPE_FONT*) did the job. 458 font = (PAPERTAPE_FONT*) papertape_new_from_file(font_file); 459 if(font == NULL) { 460 fprintf(stderr, "Error creating PAPERTAPE_FONT object\n"); 461 return 3; 462 } 463 464 // Perform action 465 if(action == RENDER_TEXT && render_text != NULL) { 466 papertape_font_get_label(font, render_text); 467 } else if(action == WRITE_CHAR) { 468 byte_t *contents; 469 int bytes = file_get_contents(stdin, &contents); 470 printf("Read in %i bytes for letter %c (seen as byte: 0x%x)\n", bytes, write_char, write_char); 471 papertape_font_set_char(font, write_char, contents, bytes); 472 } else if(action == EXPORT) { 473 fprintf(stderr, "Printing file %s with schematics %s\n", font_name, schematics); 474 puts(papertape_font_get_label(font, schematics)); 475 } else if(action == IMPORT) { 476 byte_t *contents; 477 int bytes, x; 478 479 fprintf(stderr, "Reading from stdin, expecting schematics %s\n", schematics); 480 bytes = file_get_contents(stdin, &contents); 481 482 fprintf(stderr, "To be implemented...\n"); 483 484 // Parse schematics 485 /*for(x=0; x<strlen(schematics); x++) { 486 papertape_font_set_char(font, schematics[x], 487 }*/ 488 489 } else { 490 fprintf(stderr, "No correct call! See %s -h\n", argv[0]); 491 } 492 return 0; 493 } 840 fprintf(stderr, "'%s': unknown subcommand. Type '%s help' for a list of valid commands.\n", 841 argv[2], argv[0]); 842 return 1; 843 } 844 } // main 494 845 #endif /* STANDALONE */
Note: See TracChangeset
for help on using the changeset viewer.