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