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