1 /* +-------------------------------------------------------------------+ */
2 /* | Copyright 1993, David Koblas (koblas@netcom.com)                  | */
3 /* | Copyright 1995, 1996 Torsten Martinsen (bullestock@dk-online.dk)  | */
4 /* |                                                                   | */
5 /* | Permission to use, copy, modify, and to distribute this software  | */
6 /* | and its documentation for any purpose is hereby granted without   | */
7 /* | fee, provided that the above copyright notice appear in all       | */
8 /* | copies and that both that copyright notice and this permission    | */
9 /* | notice appear in supporting documentation.  There is no           | */
10 /* | representations about the suitability of this software for        | */
11 /* | any purpose.  this software is provided "as is" without express   | */
12 /* | or implied warranty.                                              | */
13 /* |                                                                   | */
14 /* +-------------------------------------------------------------------+ */
15 
16 /* $Id: readRC.c,v 1.17 2005/03/20 20:15:32 demailly Exp $ */
17 
18 #include <stdio.h>
19 #include <pwd.h>
20 #include <ctype.h>
21 #include <X11/Intrinsic.h>
22 #include <X11/Xos.h>
23 #include <sys/stat.h>
24 #include "xpaint.h"
25 #include "image.h"
26 #include "rc.h"
27 #include "misc.h"
28 
29 
30 #ifndef NOSTDHDRS
31 #include <stdlib.h>
32 #include <unistd.h>
33 #endif
34 
35 /*
36 #ifdef __STDC__
37 extern char *mktemp(char *);
38 #else
39 extern char *mktemp();
40 #endif */ /* __STDC__ */
41 
42 
43 #define RC_FILENAME	".XPaintrc"
44 
45 static String defaultRC[] =
46 {
47 #include "DefaultRC.txt.h"
48 };
49 
50 /*
51 **   RC File Syntax
52 **
53 **     solid    [ name | x-rgb-def | r g b ]
54 **
55 **     solid!   [ name | x-rgb-def | r g b ]
56 **
57 **     pattern  [ BeginData\n ... \nEndData | filename ]
58 **
59 **     pattern! [ BeginData\n ... \nEndData | filename ]
60 **
61 **     brush    [ BeginData\n ... \nEndData | filename ]
62 **
63 **     brush!    [ BeginData\n ... \nEndData | filename ]
64 **
65 **     \n# -- comment
66 **
67 ** Note:  solid!  or  pattern!  or  brush!  mean :
68 **        take color/pattern/brush only if screen depth is > 8 bits
69  */
70 
71 #define EQ(a,b)		(strcasecmp(a,b) == 0)
72 
73 static int tempIndex = -1;
74 static char *tempName[20];
75 static RCInfo *baseInfo = NULL;
76 
77 void
openTempDir(char * buf)78 openTempDir(char *buf)
79 {
80     char *tmp, *home;
81 
82     if ((tmp = getenv("TMPDIR")) != NULL) {
83         sprintf(buf, "mkdir -p \"%s\"", tmp);
84         system(buf);
85         strncpy(buf, tmp, 200);
86     } else
87     if ((home = getenv("HOME")) != NULL) {
88         sprintf(buf, "%s/.xpaint", home);
89         mkdir(buf, 0777);
90         sprintf(buf, "%s/.xpaint/tmp", home);
91         mkdir(buf, 0777);
92     } else
93         strncpy(buf, P_tmpdir, 200);
94 }
95 
96 FILE *
openTempFile(char ** np)97 openTempFile(char **np)
98 {
99     int fd;
100     char buf[256];
101 
102     openTempDir(buf);
103     buf[200] = '\0';
104     strcat(buf, "/XPaint-XXXXXX");
105     fd = mkstemp(buf);
106     if (fd == -1) return NULL;
107 
108     tempName[++tempIndex] = XtNewString(buf);
109     if (np != NULL)
110         *np = tempName[tempIndex];
111     return fdopen(fd, "w");
112 }
113 
114 void
removeTempFile(void)115 removeTempFile(void)
116 {
117     if (tempIndex < 0)
118 	return;
119     if (tempName[tempIndex] != NULL) {
120 	unlink(tempName[tempIndex]);
121 	XtFree((XtPointer) tempName[tempIndex]);
122     }
123     tempName[tempIndex--] = NULL;
124 }
125 
126 static void
addImage(RCInfo * info,Image * image,Boolean isBrush)127 addImage(RCInfo * info, Image * image, Boolean isBrush)
128 {
129     if (isBrush) {
130 	info->brushes = (Image **)
131 	    XtRealloc((XtPointer) info->brushes,
132 		      (info->nbrushes + 1) * sizeof(Image *));
133 	info->brushes[info->nbrushes++] = image;
134     } else {
135 	info->images = (Image **)
136 	    XtRealloc((XtPointer) info->images,
137 		      (info->nimages + 1) * sizeof(Image *));
138 	info->images[info->nimages++] = image;
139     }
140 }
141 
142 static void
addSolid(RCInfo * info,char * color)143 addSolid(RCInfo * info, char *color)
144 {
145     info->colors = (char **) XtRealloc((XtPointer) info->colors,
146 				       (info->ncolors + 1) * sizeof(char *));
147     info->colors[info->ncolors++] = XtNewString(color);
148 }
149 
150 static RCInfo *
makeInfo(void)151 makeInfo(void)
152 {
153     RCInfo *info;
154 
155     info = XtNew(RCInfo);
156     info->freed = False;
157     info->nimages = 0;
158     info->nbrushes = 0;
159     info->colorFlags = NULL;
160     info->colorPixels = NULL;
161     info->images = XtNew(Image *);
162     info->brushes = XtNew(Image *);
163     info->ncolors = 0;
164     info->colors = XtNew(char *);
165 
166     baseInfo = info;
167 
168     return info;
169 }
170 
171 void
FreeRC(RCInfo * info)172 FreeRC(RCInfo * info)
173 {
174     int i;
175 
176     if (info->colors != NULL) {
177 	for (i = 0; i < info->ncolors; i++)
178 	    XtFree((XtPointer) info->colors[i]);
179 	XtFree((XtPointer) info->colors);
180     }
181     if (info->colorFlags != NULL)
182 	XtFree((XtPointer) info->colorFlags);
183     if (info->colorPixels != NULL)
184 	XtFree((XtPointer) info->colorPixels);
185 
186     for (i = 0; i < info->nimages; i++)
187 	ImageDelete(info->images[i]);
188     if (info->images != NULL)
189 	XtFree((XtPointer) info->images);
190 
191     for (i = 0; i < info->nbrushes; i++)
192 	ImageDelete(info->brushes[i]);
193     if (info->brushes != NULL)
194 	XtFree((XtPointer) info->brushes);
195 
196     XtFree((XtPointer) info);
197 
198     if (info == baseInfo)
199 	baseInfo = NULL;
200 }
201 
202 /*
203  * Expand leading tilde in path name.
204  */
205 static char *
expand(char * path)206 expand(char *path)
207 {
208     static char out[512];
209     char name[80];
210     char *pp = path, *cp;
211     struct passwd *pw;
212 
213     if (*path != '~')
214 	return path;
215     path++;
216     cp = name;
217     while (*pp != '/' && *pp != '\0')
218 	*cp++ = *pp++;
219     *cp = '\0';
220     if (name[0] == '\0') {
221 	pw = getpwuid(getuid());
222     } else {
223 	pw = getpwnam(name);
224     }
225     if (pw == NULL)
226 	return path;
227     strcpy(out, pw->pw_dir);
228     strcat(out, "/");
229     strcat(out, pp);
230 
231     return out;
232 }
233 
234 static Boolean
readRC(RCInfo ** info,char * file)235 readRC(RCInfo ** info, char *file)
236 {
237     FILE *fd = fopen(file, "r");
238     char buf[512];
239     int lineno = 0;
240     int argc;
241     char *argv[128 + 2];
242 
243     if (fd == NULL)
244 	return False;
245 
246     while (fgets(buf, sizeof(buf), fd) != NULL) {
247 	lineno++;
248 	if (buf[0] == '#' || buf[0] == '!')
249 	    continue;
250 	StrToArgv(buf, &argc, argv);
251 	if (argc == 0)
252 	    continue;
253 	if (EQ(argv[0], "reset")) {
254 	    FreeRC(*info);
255 	    *info = makeInfo();
256 	} else if (EQ(argv[0], "defaultsize")) {
257 	} else if (EQ(argv[0], "solid") ||
258 	           (EQ(argv[0], "solid!") && Global.vis.depth>8)) {
259 	    addSolid(*info, argv[1]);
260 	} else if (EQ(argv[0], "pattern") || EQ(argv[0], "brush") ||
261 	           ((EQ(argv[0], "pattern!") || EQ(argv[0], "brush!")) &&
262                    Global.vis.depth>8)) {
263 	    char *nm;
264 	    Image *image;
265 	    int isBrush = EQ(argv[0], "brush") || EQ(argv[0], "brush!");
266 
267 	    if (EQ(argv[1], "BeginData")) {
268 		FILE *ofd;
269 
270 		ofd = openTempFile(&nm);
271 		while (fgets(buf, sizeof(buf), fd) != NULL) {
272 		    if (strncmp(buf, "EndData", 7) == 0)
273 			break;
274 		    if (ofd != NULL)
275 			fputs(buf, ofd);
276 		}
277 		if (ofd != NULL) {
278 		    fclose(ofd);
279 		} else {
280 		    removeTempFile();
281 		    continue;
282 		}
283 	    } else {
284 		nm = expand(argv[1]);
285 	    }
286 
287 	    if ((image = ReadMagic(nm)) != NULL)
288 		addImage(*info, image, isBrush);
289 
290 	    removeTempFile();
291 	}
292     }
293 
294     return True;
295 }
296 
297 /*
298 **  Simple RC reading strategy:
299 **    load default
300 **    append users ~/.XPaintrc
301 **    append users ./.XPaintrc
302 **
303  */
304 RCInfo *
ReadDefaultRC()305 ReadDefaultRC()
306 {
307     static Boolean inited = False;
308     static Boolean have[2] =
309     {False, False};
310     static time_t lastMtime;
311     static RCInfo *info = NULL;
312     static char homeRC[256];
313     FILE *fd;
314     int i;
315     char *tn;
316     struct passwd *pw = getpwuid(getuid());
317     struct stat statbufA, statbufB;
318     char *rcf;
319     Boolean defaultDone = False;
320 
321     if (!inited) {
322 	inited = True;
323 	if (pw != NULL && pw->pw_dir != NULL) {
324 	    strcpy(homeRC, pw->pw_dir);
325 	    strcat(homeRC, "/");
326 	    strcat(homeRC, RC_FILENAME);
327 	} else {
328 	    homeRC[0] = '\0';
329 	}
330     }
331     if ((rcf = GetDefaultRC()) != NULL) {
332 	if (stat(rcf, &statbufA) < 0)	/* missing file? */
333 	    goto readit;
334 
335 	if (info == NULL || statbufA.st_mtime > lastMtime) {
336 	    info = makeInfo();
337 	    readRC(&info, rcf);
338 	    lastMtime = statbufA.st_mtime;
339 	    defaultDone = True;
340 	}
341     } else {
342 	if (info != NULL) {
343 	    Boolean hA, hB;
344 
345 	    hA = (stat(homeRC, &statbufA) >= 0);
346 	    hB = (stat(RC_FILENAME, &statbufB) >= 0);
347 
348 	    if (hA != have[0] || hB != have[1])
349 		goto readit;
350 
351 	    if (hA && statbufA.st_mtime > lastMtime)
352 		goto readit;
353 	    if (hB && statbufB.st_mtime > lastMtime)
354 		goto readit;
355 
356 	    /*
357 	    **  No change
358 	     */
359 	    return info;
360 	}
361       readit:
362 	if (info != NULL)
363 	    FreeRC(info);
364 	info = makeInfo();
365 
366 	/*
367 	**  Set time information
368 	 */
369 	have[0] = (stat(homeRC, &statbufA) >= 0);
370 	have[1] = (stat(RC_FILENAME, &statbufB) >= 0);
371 
372 	if (have[0] && have[1]) {
373 	    if (statbufA.st_mtime > statbufB.st_mtime)
374 		lastMtime = statbufA.st_mtime;
375 	    else
376 		lastMtime = statbufB.st_mtime;
377 	} else if (have[0]) {
378 	    lastMtime = statbufA.st_mtime;
379 	} else if (have[1]) {
380 	    lastMtime = statbufB.st_mtime;
381 	}
382 	/*
383 	**  Load the default RC
384 	 */
385 	if (!defaultDone && ((fd = openTempFile(&tn)) != NULL)) {
386 	    for (i = 0; i < XtNumber(defaultRC); i++) {
387 		fputs(defaultRC[i], fd);
388 		putc('\n', fd);
389 	    }
390 	    fclose(fd);
391 
392 	    readRC(&info, tn);
393 	    removeTempFile();
394 	}
395 	/*
396 	**  Load ~/.XPaintrc
397 	 */
398 	if (homeRC[0] != '\0')
399 	    readRC(&info, homeRC);
400 
401 	/*
402 	**  Load ".XPaintrc"
403 	 */
404 	readRC(&info, RC_FILENAME);
405     }
406 
407     if (info->ncolors == 0 && info->nimages == 0) {
408 	addSolid(info, "black");
409 	addSolid(info, "white");
410 	addSolid(info, "red");
411 	addSolid(info, "green");
412 	addSolid(info, "blue");
413 	addSolid(info, "cyan");
414 	addSolid(info, "magenta");
415 	addSolid(info, "yellow");
416     }
417     return info;
418 }
419 
420 RCInfo *
ReadRC(char * file)421 ReadRC(char *file)
422 {
423     RCInfo *info = makeInfo();
424 
425     if (!readRC(&info, file)) {
426 	/*
427 	**  Error occured
428 	 */
429 	FreeRC(info);
430 	return NULL;
431     }
432     return info;
433 }
434 
435