| 1 | <html> |
|---|
| 2 | <body> |
|---|
| 3 | |
|---|
| 4 | <h2>Paper Tape Font files</h2> |
|---|
| 5 | <p>I have developed a portable and easy to use ASCII storage format |
|---|
| 6 | for paper tape fonts, called <b>Paper Tape Font file</b>. While |
|---|
| 7 | paper tape fonts were formerly implemented as (perl) scripts, |
|---|
| 8 | with C (and C++) that's no more |
|---|
| 9 | practical, because setting up big nested hashes is not really |
|---|
| 10 | possible. Apart from that, it would not be a good style to set |
|---|
| 11 | up a giant header file with so much static data.</p> |
|---|
| 12 | |
|---|
| 13 | <p>I have considered using popular and approved data formats like |
|---|
| 14 | <i>XML</i> or <i>Jason</i> instead of a "proprietary" new, perhaps |
|---|
| 15 | even binary data format. On the one hand, using XML would have been |
|---|
| 16 | really portable, but also very unhandy, because I would have to look |
|---|
| 17 | for XML processors for Windows, and compiling would be get |
|---|
| 18 | complex and even more complex.</p> |
|---|
| 19 | |
|---|
| 20 | <p>Therefore I've decided in favor of simple ASCII files with some |
|---|
| 21 | not very strict layout. It's really obvious how it works:</p> |
|---|
| 22 | |
|---|
| 23 | <pre> |
|---|
| 24 | |***.*** |a You can write texts almost everywhere in the file, |
|---|
| 25 | | .* * |a just the very first letters, which actually |
|---|
| 26 | |***.*** |a *look* like a papertape (direction of movement, of |
|---|
| 27 | | . | course, from top down), define the bytes from |
|---|
| 28 | |***.*****|e that the letters are made up, which stand directly |
|---|
| 29 | |* .* *|e next to the paper tape. |
|---|
| 30 | |* .* *|e Yes, that's it! This file is a complete papertape |
|---|
| 31 | |* . *|e font file, containing (until now) the letters a and e. |
|---|
| 32 | </pre> |
|---|
| 33 | <!-- yeay, this HTML file is a paper tape file! --> |
|---|
| 34 | |
|---|
| 35 | <h3>Specification of Paper Tape files</h3> |
|---|
| 36 | |
|---|
| 37 | <p>This is a typical paper tape file:</p> |
|---|
| 38 | <pre> |
|---|
| 39 | ---- Start of example file ---- |
|---|
| 40 | The Paper Tape Project -- PAPERTAPE_FONT file. |
|---|
| 41 | The content of this file describes a paper tape font... |
|---|
| 42 | See this small key how the document is structured: |
|---|
| 43 | bits |identification |
|---|
| 44 | 123.45678|char/string |
|---|
| 45 | | . | |
|---|
| 46 | |+++.+++++|m |
|---|
| 47 | | . + |m |
|---|
| 48 | | . + |m this is a comment. |
|---|
| 49 | | . + |m |
|---|
| 50 | |+++.+++++|m |
|---|
| 51 | |+ . +|I |
|---|
| 52 | |+++.+++++|I |
|---|
| 53 | |+ . +|I |
|---|
| 54 | | . | |
|---|
| 55 | | . | |
|---|
| 56 | | . | |
|---|
| 57 | | . | |
|---|
| 58 | |+++.+++++|0 |
|---|
| 59 | Comments can be typed |
|---|
| 60 | right anywhere, everything that doesn't look like |
|---|
| 61 | a paper tape on the right place, is ignored. |
|---|
| 62 | |+ . ++| <- even this one. |
|---|
| 63 | |+ . +|0 |
|---|
| 64 | |+++.+++++|0 |
|---|
| 65 | | . | |
|---|
| 66 | | . | =white_space this is a comment, too. |
|---|
| 67 | | . | =white_space |
|---|
| 68 | | . | |
|---|
| 69 | |
|---|
| 70 | ---- End of example file ---- |
|---|
| 71 | </pre> |
|---|
| 72 | |
|---|
| 73 | <p>As you see, paper tape files are quite funny ASCII files. Here are the |
|---|
| 74 | rules you have to observe:</p> |
|---|
| 75 | |
|---|
| 76 | <ul> |
|---|
| 77 | <li>All lines are ignored, if there's not a papertape border in the |
|---|
| 78 | very first position. The papertape border is defined as |
|---|
| 79 | the pipe character, "<tt>|</tt>".</li> |
|---|
| 80 | |
|---|
| 81 | <li>The papertape "flows" from top to down, like western european |
|---|
| 82 | people write. The bit positions are also from left to right, like |
|---|
| 83 | a real paper tape looks like, including the feed hole between |
|---|
| 84 | bit 3 and 4. Therefore, as the key says, you read a paper tape byte |
|---|
| 85 | like that: |
|---|
| 86 | <pre> |
|---|
| 87 | |123.45678| <- bit positions |
|---|
| 88 | |012.34567| <- how computers count the bits |
|---|
| 89 | e.g. | * . ** *| -> byte value = 2^1 + 2^4 + 2^5 + 2^7 = 178 = 0xbd |
|---|
| 90 | </pre> |
|---|
| 91 | </li> |
|---|
| 92 | |
|---|
| 93 | <li>It's up to you which character you use for indicating an hole |
|---|
| 94 | (logical 1). The only limitation is, that a logical 0 (not holed) |
|---|
| 95 | MUST be an white space (no tab! Only the whitespace character). |
|---|
| 96 | <br/>So all these bytes have the equal values: |
|---|
| 97 | <pre> |
|---|
| 98 | |+ +.++ ++| |
|---|
| 99 | |h e.ll oo| |
|---|
| 100 | |# #.## ##| |
|---|
| 101 | || |.|| ||| (not recommended ;-) ) |
|---|
| 102 | |( ).() ()| (also not recommendable) |
|---|
| 103 | |* *.** **| |
|---|
| 104 | </pre></li> |
|---|
| 105 | |
|---|
| 106 | <li>To allocate a byte to a character, you write that character directly |
|---|
| 107 | after the papertape, |
|---|
| 108 | <pre> |
|---|
| 109 | like this: | * . ** *|r |
|---|
| 110 | but not like this: | *.* ***| w |
|---|
| 111 | </pre> |
|---|
| 112 | That character is called the "ASCII identifier", because it shall be |
|---|
| 113 | ASCII (8bit). You can write comments right after the identifier, |
|---|
| 114 | because everything afterwards will be ignored. |
|---|
| 115 | </li> |
|---|
| 116 | |
|---|
| 117 | <li>There are three cases of bytes: |
|---|
| 118 | <pre> |
|---|
| 119 | * the normal byte |***.*****|p |
|---|
| 120 | that belongs to an | .* *|p |
|---|
| 121 | ASCII character: | . *** |p |
|---|
| 122 | * bytes which have no | . | |
|---|
| 123 | identifier at all | . | |
|---|
| 124 | They are ignored. | . | |
|---|
| 125 | * bytes that belong to |** . ****| special_character |
|---|
| 126 | special characters. | *.* | special_character |
|---|
| 127 | </pre> |
|---|
| 128 | We give attention to special characters later. |
|---|
| 129 | </li> |
|---|
| 130 | |
|---|
| 131 | <li>Typically your paper tape letters span across multiple bytes. In |
|---|
| 132 | Paper Tape files, you write next to <u>*every*</u> byte the character where |
|---|
| 133 | it belongs to. This is read afterwards from up to down, like the |
|---|
| 134 | virtual paper tape direction is: |
|---|
| 135 | <pre> |
|---|
| 136 | |***.*****|p |
|---|
| 137 | | .* *|p |
|---|
| 138 | | . *** |p |
|---|
| 139 | | . | <- this line doesn't belong to p any more. |
|---|
| 140 | </pre> |
|---|
| 141 | Don't mix up with letters. Compare these examples: |
|---|
| 142 | <pre> |
|---|
| 143 | |***.*****|p |***.*****|p |
|---|
| 144 | | .* *|p | .* *|p |
|---|
| 145 | | . *** |p | . *** |p |
|---|
| 146 | | . | | . | |
|---|
| 147 | | . *|y | . *|y |
|---|
| 148 | | . * |y | . * |p |
|---|
| 149 | | .*** |y | .*** |y |
|---|
| 150 | | . * |y | . * |y |
|---|
| 151 | | . *|y | . *|y |
|---|
| 152 | </pre> |
|---|
| 153 | The typo at the right ("p" instead of "y") will overwrite the |
|---|
| 154 | defined paper tape letter "p" above, because letters will always |
|---|
| 155 | be read as blocks. Furthermore the first "y" line is overwritten, |
|---|
| 156 | too, by the later 3 "y" lines. That is, due to the typo error, all |
|---|
| 157 | previous definitions of "p" and "y" before are thrown away. |
|---|
| 158 | <br/>Compare also these examples: |
|---|
| 159 | <pre> |
|---|
| 160 | |***.*****|p |***.*****|p |
|---|
| 161 | | .* *|p | .* *|p |
|---|
| 162 | this does nothing. | . | |
|---|
| 163 | | . *** |p | . *** |p |
|---|
| 164 | | . | | . | |
|---|
| 165 | </pre> |
|---|
| 166 | While the comment line on the left hand example is simply ignored, |
|---|
| 167 | the white space byte on the right hand side is parsed and therefore |
|---|
| 168 | the "p" value destroyed, like in the "y" and "p" example above. |
|---|
| 169 | </li> |
|---|
| 170 | |
|---|
| 171 | <li>Next to the normal ASCII characters, there are special characters. |
|---|
| 172 | Principally, they are treated like ordinary characters, but they |
|---|
| 173 | are not identified with an ASCII value, but with a full name: |
|---|
| 174 | <pre> |
|---|
| 175 | |***.*****|p |
|---|
| 176 | | .* *|p This is an ordinary ASCII character |
|---|
| 177 | | . *** |p |
|---|
| 178 | | . | |
|---|
| 179 | | . | =white_space This is typically used to define |
|---|
| 180 | | . | =white_space how white_spaces have to look |
|---|
| 181 | | . | =white_space like. They typically contain |
|---|
| 182 | | . | only NULL bytes, of course ;-) |
|---|
| 183 | | . | |
|---|
| 184 | | . | =char_spacing And this defines how much space |
|---|
| 185 | | . | is packed between characters. |
|---|
| 186 | | . | Typically one NULL byte. |
|---|
| 187 | | . | |
|---|
| 188 | | *.* * | =secret_file |
|---|
| 189 | |* .* ** | =secret_file The name of a special character |
|---|
| 190 | | **.* ** | =secret_file may not contain whitespaces. |
|---|
| 191 | |* *. *** | =secret_file Thereby normal text/comments |
|---|
| 192 | | .**** | =secret_file can be written next to "special |
|---|
| 193 | | . * | =secret_file character" bytes just like next |
|---|
| 194 | | * . *** | =secret_file to ordinary bytes. |
|---|
| 195 | |***.* ** | =secret_file |
|---|
| 196 | |** . ** | =secret_file After all, the same limitiations |
|---|
| 197 | |** .* ** | =secret_file exist like for normal multiple |
|---|
| 198 | |** . *** | =secret_file byte definitions: Don't break in |
|---|
| 199 | |* . * | =secret_file the flow, like |
|---|
| 200 | | . | <- here, because this would |
|---|
| 201 | | * .* | =secret_file truncate secret_file to <-this byte. |
|---|
| 202 | </pre> |
|---|
| 203 | </li> |
|---|
| 204 | |
|---|
| 205 | <li>Take care that the papertapefont implementation can also write |
|---|
| 206 | paper tape font files. If the utility program is called to change |
|---|
| 207 | one character in your font file, it will read in (and parse) the |
|---|
| 208 | font file and write back the parsed files (including the changes, |
|---|
| 209 | of course). In this process, *ALL* your comments are *LOST*. |
|---|
| 210 | The implementation cannot take care of your comments, this would |
|---|
| 211 | be too complex. |
|---|
| 212 | <br/> |
|---|
| 213 | So if your font file is well commented, don't let the implementation |
|---|
| 214 | write to it.</li> |
|---|
| 215 | |
|---|
| 216 | </ul> |
|---|
| 217 | |
|---|
| 218 | <h3>Specification of the papertapefont.h library</h3> |
|---|
| 219 | <p>I've developed a tiny stand alone C library which does not need |
|---|
| 220 | auxillary libraries like Glib and which will compile at windows, |
|---|
| 221 | too. It's quite simple to use that library. At first, there even |
|---|
| 222 | exists a command line interface that implements most of the |
|---|
| 223 | features. But here's how to use the C functions:</p> |
|---|
| 224 | |
|---|
| 225 | <p>The main "object like" structure is the PAPERTAPE_FONT structure. |
|---|
| 226 | It can be built directly by parsing an already opened file:</p> |
|---|
| 227 | <pre> |
|---|
| 228 | #include <stdio.h> |
|---|
| 229 | #include "papertapefont.h" |
|---|
| 230 | |
|---|
| 231 | FILE* font_file = fopen("/path/to/your/font.file", "r"); |
|---|
| 232 | PAPERTAPE_FONT* font = papertape_font_new_from_file(font_file); |
|---|
| 233 | </pre> |
|---|
| 234 | |
|---|
| 235 | <p>Now the file has been parsed and every available letter is stored |
|---|
| 236 | in RAM. So you can directly go and generate labels: |
|---|
| 237 | |
|---|
| 238 | <pre> |
|---|
| 239 | int label_size; |
|---|
| 240 | byte_t* label_bytes; |
|---|
| 241 | |
|---|
| 242 | label_bytes = papertape_font_get_label(font, |
|---|
| 243 | "Hello World!", &label_size); |
|---|
| 244 | |
|---|
| 245 | // further use, e.g. with LOCHSTREIFEN*: |
|---|
| 246 | LOCHSTREIFEN* papertape = lochstreifen_new(); |
|---|
| 247 | lochstreifen_set_data(label_bytes, label_size); |
|---|
| 248 | </pre> |
|---|
| 249 | |
|---|
| 250 | <p>Of course you can check if your string can be fully generated, too: |
|---|
| 251 | |
|---|
| 252 | <pre> |
|---|
| 253 | if(! papertape_font_string_is_printable(font, "{H4x05]!")) { |
|---|
| 254 | printf("Sorry dude, the current font is not" |
|---|
| 255 | "script kiddie compatible.\n"); |
|---|
| 256 | } |
|---|
| 257 | </pre> |
|---|
| 258 | |
|---|
| 259 | <p>And after all, changing the papertape is fully implemented:</p> |
|---|
| 260 | |
|---|
| 261 | <pre> |
|---|
| 262 | bytes_t* user_generated; |
|---|
| 263 | int len; |
|---|
| 264 | |
|---|
| 265 | let_user_generate_letter("Please make an 'A'", |
|---|
| 266 | &user_generated, &len); |
|---|
| 267 | |
|---|
| 268 | papertape_font_set_char(font, 'A', user_generated, len); |
|---|
| 269 | </pre> |
|---|
| 270 | |
|---|
| 271 | <p>This will change the letter immediately. So the following output |
|---|
| 272 | will give out "ABBA" on the papertape at the end (and not "ABAB"): |
|---|
| 273 | |
|---|
| 274 | <pre> |
|---|
| 275 | bytes_t* output, buf_for_a, buf_for_b; |
|---|
| 276 | int o_len, a_len, b_len; |
|---|
| 277 | |
|---|
| 278 | // print out "ab" on papertape |
|---|
| 279 | output = papertape_font_get_label(font, "ab", &o_len); |
|---|
| 280 | send_to_papertape_puncher(output, o_len); |
|---|
| 281 | |
|---|
| 282 | // flip a and b |
|---|
| 283 | buf_for_a = papertape_font_get_label(font, "a", &a_len); |
|---|
| 284 | buf_for_b = papertape_font_get_label(font, "b", &b_len); |
|---|
| 285 | papertape_font_set_char(font, 'B', buf_for_a, a_len); |
|---|
| 286 | papertape_font_set_char(font, 'A', buf_for_b, b_len); |
|---|
| 287 | |
|---|
| 288 | // print out "ab" on papertape... |
|---|
| 289 | output = papertape_font_get_label(font, "ab", &o_len); |
|---|
| 290 | send_to_papertape_puncher(output, o_len); |
|---|
| 291 | </pre> |
|---|
| 292 | |
|---|
| 293 | <p>If you feel destructive, you can also delete characters: |
|---|
| 294 | |
|---|
| 295 | <pre> |
|---|
| 296 | // clean up all the mess by deleting everything!!111 |
|---|
| 297 | papertape_font_del_char(font, 'a'); |
|---|
| 298 | papertape_font_del_char(font, 'b'); |
|---|
| 299 | if(!papertape_font_del_char(font, 'b')) |
|---|
| 300 | printf("There is no more 'b'. Of course!"); |
|---|
| 301 | output = papertape_font_get_label(font, "abba", &len); |
|---|
| 302 | // this will give out 4 errors at stderr, because |
|---|
| 303 | // no character can be generated. |
|---|
| 304 | </pre> |
|---|
| 305 | |
|---|
| 306 | <p>At last, after messing around you can save the whole changed |
|---|
| 307 | thing (back) to a file. |
|---|
| 308 | |
|---|
| 309 | <pre> |
|---|
| 310 | FILE* target = fopen("/existing/or/new.font.txt", "w"); |
|---|
| 311 | papertape_font_write_to_file(font, target); |
|---|
| 312 | </pre> |
|---|
| 313 | |
|---|
| 314 | <p>Be aware that the following example will stripe out *ALL* |
|---|
| 315 | comments out of your font file: |
|---|
| 316 | |
|---|
| 317 | <pre> |
|---|
| 318 | FILE* needs_cleanup = fopen("font.txt", "r+"); |
|---|
| 319 | PAPERTAPE_FONT* font = papertape_font_new_from_file(needs_cleanup); |
|---|
| 320 | papertape_font_write_to_file(font, needs_cleanup); |
|---|
| 321 | </pre> |
|---|
| 322 | |
|---|
| 323 | <p>In the end, an issue that is a bit more complicated: Special |
|---|
| 324 | characters. This includes white spaces, letter spacing, etc. |
|---|
| 325 | The names for these special characters are noted in the |
|---|
| 326 | papertapefont.h header file, so you can access them directly, |
|---|
| 327 | too, if you want: |
|---|
| 328 | |
|---|
| 329 | <pre> |
|---|
| 330 | byte_t *white = calloc(sizeof(byte_t), 100); |
|---|
| 331 | papertape_font_set_special(font, PAPERTAPE_FONT_SPACE_NAME, |
|---|
| 332 | white, 100); |
|---|
| 333 | // about 1k of bytes: |
|---|
| 334 | papertape_font_get_label(font, "A fairly long text ! ! ! ", &somewhere) |
|---|
| 335 | // deletion sets the space to some kind of default value |
|---|
| 336 | papertape_font_del_special(font, PAPERTAPE_FONT_SPACE_NAME); |
|---|
| 337 | // so this is quite short: |
|---|
| 338 | papertape_font_get_label(font, " s h o r t ", &somewhere); |
|---|
| 339 | </pre> |
|---|
| 340 | |
|---|
| 341 | <p>I think that's all, for the moment. Happy coding :-) |
|---|
| 342 | |
|---|
| 343 | <p>-- Sven Köppel, 04.09.2008 |
|---|