atobm.c revision eaef79e5
1/* $Xorg: atobm.c,v 1.4 2001/02/09 02:05:28 xorgcvs Exp $ */
2/*
3
4Copyright 1988, 1993, 1998  The Open Group
5
6Permission to use, copy, modify, distribute, and sell this software and its
7documentation for any purpose is hereby granted without fee, provided that
8the above copyright notice appear in all copies and that both that
9copyright notice and this permission notice appear in supporting
10documentation.
11
12The above copyright notice and this permission notice shall be included
13in all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
19OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21OTHER DEALINGS IN THE SOFTWARE.
22
23Except as contained in this notice, the name of The Open Group shall
24not be used in advertising or otherwise to promote the sale, use or
25other dealings in this Software without prior written authorization
26from The Open Group.
27
28*/
29/* $XFree86: xc/programs/bitmap/atobm.c,v 3.4 2001/07/25 15:05:12 dawes Exp $ */
30
31/*
32 * atobm - ascii to bitmap filter
33 * Author:  Jim Fulton, MIT X Consortium
34 */
35
36#include <stdio.h>
37#include <ctype.h>
38#include <X11/Xos.h>
39#include <stdlib.h>
40
41char *ProgramName;
42
43static void doit(FILE *fp, char *filename, char *chars,
44		 int xhot, int yhot, char *name);
45
46static void
47usage (void)
48{
49    fprintf (stderr, "usage:  %s [-options ...] [filename]\n\n",
50	     ProgramName);
51    fprintf (stderr,
52	"where options include:\n");
53    fprintf (stderr,
54	"    -chars cc        chars to use for 0 and 1 bits, respectively\n");
55    fprintf (stderr,
56	"    -name variable   name to use in bitmap file\n");
57    fprintf (stderr,
58	"    -xhot number     x position of hotspot\n");
59    fprintf (stderr,
60	"    -yhot number     y position of hotspot\n");
61    fprintf (stderr, "\n");
62    exit (1);
63}
64
65
66static char *
67cify_name (char *name)
68{
69    int length = name ? strlen (name) : 0;
70    int i;
71
72    for (i = 0; i < length; i++) {	/* strncpy (result, begin, length); */
73	char c = name[i];
74	if (!((isascii(c) && isalnum(c)) || c == '_')) name[i] = '_';
75    }
76    return name;
77}
78
79static char *
80StripName(char *name)
81{
82  char *begin = strrchr(name, '/');
83  char *end, *result;
84  int length;
85
86  begin = (begin ? begin+1 : name);
87  end = strchr(begin, '.');	/* change to strrchr to allow longer names */
88  length = (end ? (end - begin) : strlen (begin));
89  result = (char *) malloc (length + 1);
90  strncpy (result, begin, length);
91  result [length] = '\0';
92  return (result);
93}
94
95int
96main (int argc, char *argv[])
97{
98    int i;
99    int xhot = -1, yhot = -1;
100    char *filename = NULL;
101    char *chars = "-#";
102    char *name = NULL;
103    FILE *fp;
104
105    ProgramName = argv[0];
106
107    for (i = 1; i < argc; i++) {
108	char *arg = argv[i];
109
110	if (arg[0] == '-') {
111	    switch (arg[1]) {
112	      case '\0':
113		filename = NULL;
114		continue;
115	      case 'c':
116		if (++i >= argc) usage ();
117		chars = argv[i];
118		continue;
119	      case 'n':
120		if (++i >= argc) usage ();
121		name = argv[i];
122		continue;
123	      case 'x':
124		if (++i >= argc) usage ();
125		xhot = atoi (argv[i]);
126		continue;
127	      case 'y':
128		if (++i >= argc) usage ();
129		yhot = atoi (argv[i]);
130		continue;
131	      default:
132		usage ();
133	    }
134	} else {
135	    filename = arg;
136	}
137    }
138
139    if (strlen (chars) != 2) {
140	fprintf (stderr,
141	 "%s:  bad character list \"%s\", must have exactly 2 characters\n",
142		 ProgramName, chars);
143	exit (1);
144    }
145
146    if (filename) {
147	fp = fopen (filename, "r");
148	if (!fp) {
149	    fprintf (stderr, "%s:  unable to open file \"%s\".\n",
150		     ProgramName, filename);
151	    exit (1);
152	}
153    } else {
154	fp = stdin;
155    }
156
157    if (!name) name = filename ? StripName (filename) : "";
158    cify_name (name);
159    doit (fp, filename, chars, xhot, yhot, name);
160
161    if (filename) (void) fclose (fp);
162    exit (0);
163}
164
165
166static void
167doit (FILE *fp,
168      char *filename,
169      char *chars,
170      int xhot, int yhot,
171      char *name)
172{
173    int i, j;
174    int last_character;
175    char buf[BUFSIZ];
176    char *cp, *newline;
177    int width = 0, height = 0;
178    int len;
179    int removespace = (((isascii(chars[0]) && isspace(chars[0])) ||
180			(isascii(chars[1]) && isspace(chars[1]))) ? 0 : 1);
181    int lineno = 0;
182    int bytes_per_scanline = 0;
183    struct _scan_list {
184	int allocated;
185	int used;
186	unsigned char *scanlines;
187	struct _scan_list *next;
188    } *head = NULL, *slist = NULL;
189    static unsigned char masktable[] = {
190	0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
191    int padded = 0;
192
193#define NTOALLOC 16
194#define NewSList() \
195	    slist = (struct _scan_list *) calloc (1, sizeof *slist); \
196	    if (!slist) { \
197		fprintf (stderr, "%s:  unable to allocate scan list\n", \
198			 ProgramName); \
199		return; \
200	    } \
201	    slist->allocated = NTOALLOC * bytes_per_scanline; \
202	    slist->scanlines = (unsigned char *) calloc(slist->allocated, 1); \
203	    if (!slist->scanlines) { \
204		fprintf (stderr, "%s:  unable to allocate char array\n", \
205			 ProgramName); \
206		return; \
207	    } \
208	    slist->used = 0; \
209	    slist->next = NULL;
210
211    while (1) {
212	buf[0] = '\0';
213	lineno++;
214	if (fgets (buf, sizeof buf, fp) == NULL) break;
215
216	cp = buf;
217	if (removespace) {
218	    for (cp = buf; *cp && isascii(*cp) && isspace(*cp); cp++) ;
219	}
220	if (*cp == '\n' || !*cp) continue;  /* empty line */
221
222	newline = strchr(cp, '\n');
223	if (!newline) {
224	    fprintf (stderr, "%s:  line %d too long.\n",
225		     ProgramName, lineno);
226	    return;
227	}
228
229	if (removespace) {
230	    for (; --newline > cp && isascii(*newline) && isspace(*newline); );
231	    newline++;
232	}
233
234	if (newline == cp + 1) continue;
235
236	*newline = '\0';
237	len = strlen (cp);
238
239	if (width == 0) {
240	    width = len;
241	    padded = ((width & 7) != 0);
242	    bytes_per_scanline = (len + 7) / 8;
243	    NewSList ();
244	    head = slist;
245	} else if (width != len) {
246	    fprintf (stderr,
247		     "%s:  line %d is %d characters wide instead of %d\n",
248		     ProgramName, lineno, len, width);
249	    return;
250	}
251
252	if (slist->used + 1 >= slist->allocated) {
253	    struct _scan_list *old = slist;
254	    NewSList ();
255	    old->next = slist;
256	}
257
258	/* okay, parse the line and stick values into the scanline array */
259	for (i = 0; i < width; i++) {
260	    int ind = (i & 7);
261	    int on = 0;
262
263	    if (cp[i] == chars[1]) {
264		on = 1;
265	    } else if (cp[i] != chars[0]) {
266		fprintf (stderr, "%s:  bad character '%c' on line %d\n",
267			 ProgramName, cp[i], lineno);
268	    }
269
270	    if (on) slist->scanlines[slist->used] |= masktable[ind];
271	    if (ind == 7) slist->used++;
272	}
273	if (padded) slist->used++;
274	height++;
275    }
276
277    printf ("#define %s_width %d\n", name, width);
278    printf ("#define %s_height %d\n", name, height);
279    if (xhot >= 0) printf ("#define %s_x_hot %d\n", name, xhot);
280    if (yhot >= 0) printf ("#define %s_y_hot %d\n", name, yhot);
281    printf ("\n");
282    printf ("static unsigned char %s_bits[] = {\n", name);
283
284    j = 0;
285    last_character = height * bytes_per_scanline - 1;
286    for (slist = head; slist; slist = slist->next) {
287	for (i = 0; i < slist->used; i++) {
288	    printf (" 0x%02x", slist->scanlines[i]);
289	    if (j != last_character) putchar (',');
290	    if ((j % 12) == 11) putchar ('\n');
291	    j++;
292	}
293    }
294    printf (" };\n");
295    return;
296}
297