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