atobm.c revision 7515ee80
1/* 2 3Copyright 1988, 1993, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included 12in all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR 18OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20OTHER DEALINGS IN THE SOFTWARE. 21 22Except as contained in this notice, the name of The Open Group shall 23not be used in advertising or otherwise to promote the sale, use or 24other dealings in this Software without prior written authorization 25from The Open Group. 26 27*/ 28 29/* 30 * atobm - ascii to bitmap filter 31 * Author: Jim Fulton, MIT X Consortium 32 */ 33 34#include <stdio.h> 35#include <ctype.h> 36#include <X11/Xos.h> 37#include <X11/Xfuncproto.h> 38#include <stdlib.h> 39 40static char *ProgramName; 41 42static void doit(FILE *fp, const char *filename, const char *chars, 43 int xhot, int yhot, const char *name); 44 45static void _X_NORETURN _X_COLD 46usage (const char *msg) 47{ 48 if (msg) 49 fprintf(stderr, "%s: %s\n", ProgramName, msg); 50 fprintf (stderr, "usage: %s [-options ...] [filename]\n\n%s\n", 51 ProgramName, 52 "where options include:\n" 53 " -chars cc chars to use for 0 and 1 bits, respectively\n" 54 " -name variable name to use in bitmap file\n" 55 " -xhot number x position of hotspot\n" 56 " -yhot number y position of hotspot\n"); 57 exit (1); 58} 59 60static void _X_NORETURN _X_COLD 61missing_arg (const char *option) 62{ 63 char msg[32]; 64 65 snprintf(msg, sizeof(msg), "%s requires an argument", option); 66 usage(msg); 67} 68 69static char * 70cify_name (char *name) 71{ 72 int length = name ? strlen (name) : 0; 73 int i; 74 75 for (i = 0; i < length; i++) { /* strncpy (result, begin, length); */ 76 char c = name[i]; 77 if (!((isascii(c) && isalnum(c)) || c == '_')) name[i] = '_'; 78 } 79 return name; 80} 81 82static char * 83StripName(char *name) 84{ 85 char *begin = strrchr(name, '/'); 86 char *end, *result; 87 int length; 88 89 begin = (begin ? begin+1 : name); 90 end = strchr(begin, '.'); /* change to strrchr to allow longer names */ 91 length = (end ? (end - begin) : strlen (begin)); 92 result = (char *) malloc (length + 1); 93 strncpy (result, begin, length); 94 result [length] = '\0'; 95 return (result); 96} 97 98int 99main (int argc, char *argv[]) 100{ 101 int i; 102 int xhot = -1, yhot = -1; 103 char *filename = NULL; 104 const char *chars = "-#"; 105 const char *name = NULL; 106 FILE *fp; 107 108 ProgramName = argv[0]; 109 110 for (i = 1; i < argc; i++) { 111 char *arg = argv[i]; 112 113 if (arg[0] == '-') { 114 switch (arg[1]) { 115 case '\0': 116 filename = NULL; 117 continue; 118 case 'c': 119 if (++i >= argc) missing_arg("-chars"); 120 chars = argv[i]; 121 continue; 122 case 'n': 123 if (++i >= argc) missing_arg("-name"); 124 name = argv[i]; 125 continue; 126 case 'x': 127 if (++i >= argc) missing_arg("-xhot"); 128 xhot = atoi (argv[i]); 129 continue; 130 case 'y': 131 if (++i >= argc) missing_arg("-yhot"); 132 yhot = atoi (argv[i]); 133 continue; 134 default: 135 fprintf(stderr, "%s: unrecognized option '%s'\n", 136 ProgramName, argv[i]); 137 usage (NULL); 138 } 139 } else { 140 filename = arg; 141 } 142 } 143 144 if (strlen (chars) != 2) { 145 fprintf (stderr, 146 "%s: bad character list \"%s\", must have exactly 2 characters\n", 147 ProgramName, chars); 148 exit (1); 149 } 150 151 if (filename) { 152 fp = fopen (filename, "r"); 153 if (!fp) { 154 fprintf (stderr, "%s: unable to open file \"%s\".\n", 155 ProgramName, filename); 156 exit (1); 157 } 158 } else { 159 fp = stdin; 160 } 161 162 if (!name) 163 name = filename ? cify_name (StripName (filename)) : ""; 164 doit (fp, filename, chars, xhot, yhot, name); 165 166 if (filename) (void) fclose (fp); 167 exit (0); 168} 169 170struct _scan_list { 171 int allocated; 172 int used; 173 unsigned char *scanlines; 174 struct _scan_list *next; 175}; 176 177#define NTOALLOC 16 178static inline struct _scan_list * 179_new_scan_list(int bytes_per_scanline) { 180 struct _scan_list *slist = (struct _scan_list *) calloc (1, sizeof(*slist)); 181 if (!slist) { 182 return NULL; 183 } 184 slist->allocated = NTOALLOC * bytes_per_scanline; 185 slist->scanlines = (unsigned char *) calloc(slist->allocated, 1); 186 if (!slist->scanlines) { 187 free(slist); 188 return NULL; 189 } 190 slist->used = 0; 191 slist->next = NULL; 192 193 return slist; 194} 195 196static void 197doit (FILE *fp, 198 const char *filename, 199 const char *chars, 200 int xhot, int yhot, 201 const char *name) 202{ 203 int i, j; 204 int last_character; 205 char buf[BUFSIZ]; 206 char *cp, *newline; 207 int width = 0, height = 0; 208 int len; 209 int removespace = (((isascii(chars[0]) && isspace(chars[0])) || 210 (isascii(chars[1]) && isspace(chars[1]))) ? 0 : 1); 211 int lineno = 0; 212 int bytes_per_scanline = 0; 213 struct _scan_list *head = NULL, *slist = NULL; 214 static unsigned char masktable[] = { 215 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }; 216 int padded = 0; 217 218 while (1) { 219 buf[0] = '\0'; 220 lineno++; 221 if (fgets (buf, sizeof buf, fp) == NULL) break; 222 223 cp = buf; 224 if (removespace) { 225 for (cp = buf; *cp && isascii(*cp) && isspace(*cp); cp++) ; 226 } 227 if (*cp == '\n' || !*cp) continue; /* empty line */ 228 229 newline = strchr(cp, '\n'); 230 if (!newline) { 231 fprintf (stderr, "%s: line %d too long.\n", 232 ProgramName, lineno); 233 return; 234 } 235 236 if (removespace) { 237 for (; --newline > cp && isascii(*newline) && isspace(*newline); ); 238 newline++; 239 } 240 241 if (newline == cp) continue; 242 243 *newline = '\0'; 244 len = strlen (cp); 245 246 if (head == NULL) { 247 width = len; 248 padded = ((width & 7) != 0); 249 bytes_per_scanline = (len + 7) / 8; 250 head = slist = _new_scan_list(bytes_per_scanline); 251 252 if (!slist) { 253 fprintf (stderr, "%s: unable to allocate scan list\n", ProgramName); 254 return; 255 } 256 } else if (width != len) { 257 fprintf (stderr, 258 "%s: line %d is %d characters wide instead of %d\n", 259 ProgramName, lineno, len, width); 260 goto bail; 261 } 262 263 if (slist->used + 1 >= slist->allocated) { 264 struct _scan_list *old = slist; 265 old->next = slist = _new_scan_list(bytes_per_scanline); 266 267 if (!slist) { 268 fprintf (stderr, "%s: unable to allocate scan list\n", ProgramName); 269 goto bail; 270 } 271 } 272 273 /* okay, parse the line and stick values into the scanline array */ 274 for (i = 0; i < width; i++) { 275 int ind = (i & 7); 276 int on = 0; 277 278 if (cp[i] == chars[1]) { 279 on = 1; 280 } else if (cp[i] != chars[0]) { 281 fprintf (stderr, "%s: bad character '%c' on line %d\n", 282 ProgramName, cp[i], lineno); 283 } 284 285 if (on) slist->scanlines[slist->used] |= masktable[ind]; 286 if (ind == 7) slist->used++; 287 } 288 if (padded) slist->used++; 289 height++; 290 } 291 292 printf ("#define %s_width %d\n", name, width); 293 printf ("#define %s_height %d\n", name, height); 294 if (xhot >= 0) printf ("#define %s_x_hot %d\n", name, xhot); 295 if (yhot >= 0) printf ("#define %s_y_hot %d\n", name, yhot); 296 printf ("\n"); 297 printf ("static unsigned char %s_bits[] = {\n", name); 298 299 j = 0; 300 last_character = height * bytes_per_scanline - 1; 301 for (slist = head; slist; slist = slist->next) { 302 for (i = 0; i < slist->used; i++) { 303 printf (" 0x%02x", slist->scanlines[i]); 304 if (j != last_character) putchar (','); 305 if ((j % 12) == 11) putchar ('\n'); 306 j++; 307 } 308 } 309 printf (" };\n"); 310 bail: 311 for (slist = head; slist != NULL; slist = head) { 312 head = slist->next; 313 free(slist->scanlines); 314 free(slist); 315 } 316 return; 317} 318