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#ifdef HAVE_CONFIG_H 35# include "config.h" 36#endif 37 38#include <stdio.h> 39#include <ctype.h> 40#include <X11/Xos.h> 41#include <X11/Xfuncproto.h> 42#include <stdlib.h> 43 44static char *ProgramName; 45 46static void doit(FILE *fp, const char *filename, const char *chars, 47 int xhot, int yhot, const char *name); 48 49static void _X_NORETURN _X_COLD 50usage (const char *msg, int exitval) 51{ 52 if (msg) 53 fprintf(stderr, "%s: %s\n", ProgramName, msg); 54 fprintf (stderr, "usage: %s [-options ...] [filename]\n\n%s\n", 55 ProgramName, 56 "where options include:\n" 57 " -chars cc chars to use for 0 and 1 bits, respectively\n" 58 " -help print this message\n" 59 " -name variable name to use in bitmap file\n" 60 " -version print version info\n" 61 " -xhot number x position of hotspot\n" 62 " -yhot number y position of hotspot\n"); 63 exit(exitval); 64} 65 66static void _X_NORETURN _X_COLD 67missing_arg (const char *option) 68{ 69 char msg[32]; 70 71 snprintf(msg, sizeof(msg), "%s requires an argument", option); 72 usage(msg, 1); 73} 74 75static char * 76cify_name (char *name) 77{ 78 int length = name ? strlen (name) : 0; 79 int i; 80 81 for (i = 0; i < length; i++) { /* strncpy (result, begin, length); */ 82 char c = name[i]; 83 if (!((isascii(c) && isalnum(c)) || c == '_')) name[i] = '_'; 84 } 85 return name; 86} 87 88static char * 89StripName(char *name) 90{ 91 char *begin = strrchr(name, '/'); 92 char *end, *result; 93 int length; 94 95 begin = (begin ? begin+1 : name); 96 end = strchr(begin, '.'); /* change to strrchr to allow longer names */ 97 length = (end ? (end - begin) : strlen (begin)); 98 result = (char *) malloc (length + 1); 99 strncpy (result, begin, length); 100 result [length] = '\0'; 101 return (result); 102} 103 104int 105main (int argc, char *argv[]) 106{ 107 int i; 108 int xhot = -1, yhot = -1; 109 char *filename = NULL; 110 const char *chars = "-#"; 111 const char *name = NULL; 112 FILE *fp; 113 114 ProgramName = argv[0]; 115 116 for (i = 1; i < argc; i++) { 117 char *arg = argv[i]; 118 119 if (arg[0] == '-') { 120 switch (arg[1]) { 121 case '\0': 122 filename = NULL; 123 continue; 124 case 'c': 125 if (++i >= argc) missing_arg("-chars"); 126 chars = argv[i]; 127 continue; 128 case 'h': 129 if (strcmp(arg, "-help") == 0) { 130 usage(NULL, 0); 131 } 132 goto unknown; 133 case 'n': 134 if (++i >= argc) missing_arg("-name"); 135 name = argv[i]; 136 continue; 137 case 'v': 138 if (strcmp(arg, "-version") == 0) { 139 puts(PACKAGE_STRING); 140 exit(0); 141 } 142 goto unknown; 143 case 'x': 144 if (++i >= argc) missing_arg("-xhot"); 145 xhot = atoi (argv[i]); 146 continue; 147 case 'y': 148 if (++i >= argc) missing_arg("-yhot"); 149 yhot = atoi (argv[i]); 150 continue; 151 default: 152 unknown: 153 fprintf(stderr, "%s: unrecognized option '%s'\n", 154 ProgramName, argv[i]); 155 usage(NULL, 1); 156 } 157 } else { 158 filename = arg; 159 } 160 } 161 162 if (strlen (chars) != 2) { 163 fprintf (stderr, 164 "%s: bad character list \"%s\", must have exactly 2 characters\n", 165 ProgramName, chars); 166 exit (1); 167 } 168 169 if (filename) { 170 fp = fopen (filename, "r"); 171 if (!fp) { 172 fprintf (stderr, "%s: unable to open file \"%s\".\n", 173 ProgramName, filename); 174 exit (1); 175 } 176 } else { 177 fp = stdin; 178 } 179 180 if (!name) 181 name = filename ? cify_name (StripName (filename)) : ""; 182 doit (fp, filename, chars, xhot, yhot, name); 183 184 if (filename) (void) fclose (fp); 185 exit (0); 186} 187 188struct _scan_list { 189 int allocated; 190 int used; 191 unsigned char *scanlines; 192 struct _scan_list *next; 193}; 194 195#define NTOALLOC 16 196static inline struct _scan_list * 197_new_scan_list(int bytes_per_scanline) { 198 struct _scan_list *slist = (struct _scan_list *) calloc (1, sizeof(*slist)); 199 if (!slist) { 200 return NULL; 201 } 202 slist->allocated = NTOALLOC * bytes_per_scanline; 203 slist->scanlines = (unsigned char *) calloc(slist->allocated, 1); 204 if (!slist->scanlines) { 205 free(slist); 206 return NULL; 207 } 208 slist->used = 0; 209 slist->next = NULL; 210 211 return slist; 212} 213 214static void 215doit (FILE *fp, 216 const char *filename, 217 const char *chars, 218 int xhot, int yhot, 219 const char *name) 220{ 221 int i, j; 222 int last_character; 223 char buf[BUFSIZ]; 224 char *cp, *newline; 225 int width = 0, height = 0; 226 int len; 227 int removespace = (((isascii(chars[0]) && isspace(chars[0])) || 228 (isascii(chars[1]) && isspace(chars[1]))) ? 0 : 1); 229 int lineno = 0; 230 int bytes_per_scanline = 0; 231 struct _scan_list *head = NULL, *slist = NULL; 232 static unsigned char masktable[] = { 233 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }; 234 int padded = 0; 235 236 while (1) { 237 buf[0] = '\0'; 238 lineno++; 239 if (fgets (buf, sizeof buf, fp) == NULL) break; 240 241 cp = buf; 242 if (removespace) { 243 for (cp = buf; *cp && isascii(*cp) && isspace(*cp); cp++) ; 244 } 245 if (*cp == '\n' || !*cp) continue; /* empty line */ 246 247 newline = strchr(cp, '\n'); 248 if (!newline) { 249 fprintf (stderr, "%s: line %d too long.\n", 250 ProgramName, lineno); 251 return; 252 } 253 254 if (removespace) { 255 for (; --newline > cp && isascii(*newline) && isspace(*newline); ); 256 newline++; 257 } 258 259 if (newline == cp) continue; 260 261 *newline = '\0'; 262 len = strlen (cp); 263 264 if (head == NULL) { 265 width = len; 266 padded = ((width & 7) != 0); 267 bytes_per_scanline = (len + 7) / 8; 268 head = slist = _new_scan_list(bytes_per_scanline); 269 270 if (!slist) { 271 fprintf (stderr, "%s: unable to allocate scan list\n", ProgramName); 272 return; 273 } 274 } else if (width != len) { 275 fprintf (stderr, 276 "%s: line %d is %d characters wide instead of %d\n", 277 ProgramName, lineno, len, width); 278 goto bail; 279 } 280 281 if (slist->used + 1 >= slist->allocated) { 282 struct _scan_list *old = slist; 283 old->next = slist = _new_scan_list(bytes_per_scanline); 284 285 if (!slist) { 286 fprintf (stderr, "%s: unable to allocate scan list\n", ProgramName); 287 goto bail; 288 } 289 } 290 291 /* okay, parse the line and stick values into the scanline array */ 292 for (i = 0; i < width; i++) { 293 int ind = (i & 7); 294 int on = 0; 295 296 if (cp[i] == chars[1]) { 297 on = 1; 298 } else if (cp[i] != chars[0]) { 299 fprintf (stderr, "%s: bad character '%c' on line %d\n", 300 ProgramName, cp[i], lineno); 301 } 302 303 if (on) slist->scanlines[slist->used] |= masktable[ind]; 304 if (ind == 7) slist->used++; 305 } 306 if (padded) slist->used++; 307 height++; 308 } 309 310 printf ("#define %s_width %d\n", name, width); 311 printf ("#define %s_height %d\n", name, height); 312 if (xhot >= 0) printf ("#define %s_x_hot %d\n", name, xhot); 313 if (yhot >= 0) printf ("#define %s_y_hot %d\n", name, yhot); 314 printf ("\n"); 315 printf ("static unsigned char %s_bits[] = {\n", name); 316 317 j = 0; 318 last_character = height * bytes_per_scanline - 1; 319 for (slist = head; slist; slist = slist->next) { 320 for (i = 0; i < slist->used; i++) { 321 printf (" 0x%02x", slist->scanlines[i]); 322 if (j != last_character) putchar (','); 323 if ((j % 12) == 11) putchar ('\n'); 324 j++; 325 } 326 } 327 printf (" };\n"); 328 bail: 329 for (slist = head; slist != NULL; slist = head) { 330 head = slist->next; 331 free(slist->scanlines); 332 free(slist); 333 } 334 return; 335} 336