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