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