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