2 * xrdb - X resource manager database utility
8 * DIGITAL EQUIPMENT CORPORATION
9 * MAYNARD, MASSACHUSETTS
10 * MASSACHUSETTS INSTITUTE OF TECHNOLOGY
11 * CAMBRIDGE, MASSACHUSETTS
12 * ALL RIGHTS RESERVED.
14 * THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE AND
15 * SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT CORPORATION.
16 * DIGITAL MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR
17 * ANY PURPOSE. IT IS SUPPLIED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
19 * IF THE SOFTWARE IS MODIFIED IN A MANNER CREATING DERIVATIVE COPYRIGHT RIGHTS,
20 * APPROPRIATE LEGENDS MAY BE PLACED ON THE DERIVATIVE WORK IN ADDITION TO THAT
24 * Permission to use, copy, modify, and distribute this software and its
25 * documentation for any purpose and without fee is hereby granted, provided
26 * that the above copyright notice appear in all copies and that both that
27 * copyright notice and this permission notice appear in supporting
28 * documentation, and that the name of Digital Equipment Corporation not be
29 * used in advertising or publicity pertaining to distribution of the software
30 * without specific, written prior permission.
34 * this program is used to load, or dump the resource manager database
37 * Original Author: Jim Gettys, August 28, 1987
38 * Extensively Modified: Phil Karlton, January 5, 1987
39 * Modified a Bunch More: Bob Scheifler, February, 1991
47 #include <X11/Xutil.h>
48 #include <X11/Xatom.h>
50 #include <X11/Xmu/SysUtil.h>
57 #ifdef NEED_SYS_PARAM_H
58 # include <sys/param.h> /* defines MAXHOSTNAMELEN on BSD & Linux */
62 # include <netdb.h> /* defines MAXHOSTNAMELEN on Solaris */
65 #define SCREEN_RESOURCES "SCREEN_RESOURCES"
69 /* expected to be in path */
72 #define CPP "/usr/lib/cpp"
73 #endif /* __UNIXOS2__ */
76 #define INIT_BUFFER_SIZE 10000
77 #define INIT_ENTRY_SIZE 500
92 #define RESOURCE_PROPERTY_NAME "RESOURCE_MANAGER"
93 #define BACKUP_SUFFIX ".bak" /* for editting */
95 typedef struct _Entry {
100 typedef struct _Buffer {
104 typedef struct _Entries {
109 /* dynamically allocated strings */
110 #define CHUNK_SIZE 4096
111 typedef struct _String {
116 static char *ProgramName;
117 static Bool quiet = False;
118 static char tmpname[32];
119 static char *filename = NULL;
121 static Bool need_real_defines = False;
122 static char tmpname2[32];
125 static char tmpname3[32];
127 static int oper = OPLOAD;
128 static char *editFile = NULL;
129 static const char *cpp_program = NULL;
130 static const char* const cpp_locations[] = { CPP };
131 static const char *backup_suffix = BACKUP_SUFFIX;
132 static Bool dont_execute = False;
133 static String defines;
134 static int defines_base;
135 #define MAX_CMD_DEFINES 512
136 static char *cmd_defines[MAX_CMD_DEFINES];
137 static int num_cmd_defines = 0;
138 static String includes;
140 static Buffer buffer;
141 static Entries newDB;
143 static void fatal(const char *, ...) _X_ATTRIBUTE_PRINTF(1,2) _X_NORETURN;
144 static void addstring ( String *arg, const char *s );
145 static void addescapedstring ( String *arg, const char *s );
146 static void addtokstring ( String *arg, const char *s );
147 static void FormatEntries ( Buffer *b, Entries *entries );
148 static void StoreProperty ( Display *display, Window root, Atom res_prop );
149 static void Process ( int scrno, Bool doScreen, Bool execute );
150 static void ShuffleEntries ( Entries *db, Entries *dbs, int num );
151 static void ReProcess ( int scrno, Bool doScreen );
153 #ifndef HAVE_ASPRINTF
154 /* sprintf variant found in newer libc's which allocates string to print to */
155 static int _X_ATTRIBUTE_PRINTF(2,3)
156 asprintf(char ** ret, const char *format, ...)
162 va_start(ap, format);
163 len = vsnprintf(buf, sizeof(buf), format, ap);
169 if (len < sizeof(buf))
175 *ret = malloc(len + 1); /* snprintf doesn't count trailing '\0' */
178 va_start(ap, format);
179 len = vsnprintf(*ret, len + 1, format, ap);
193 #endif /* HAVE_ASPRINTF */
196 InitBuffer(Buffer *b)
198 b->room = INIT_BUFFER_SIZE;
200 b->buff = malloc(INIT_BUFFER_SIZE*sizeof(char));
205 FreeBuffer(Buffer *b)
212 AppendToBuffer(Buffer *b, const char *str, int len)
214 while (b->used + len > b->room) {
215 b->buff = realloc(b->buff, 2*b->room*(sizeof(char)));
218 strncpy(b->buff + b->used, str, len);
223 InitEntries(Entries *e)
225 e->room = INIT_ENTRY_SIZE;
227 e->entry = malloc(INIT_ENTRY_SIZE*sizeof(Entry));
231 FreeEntries(Entries *e)
235 for (i = 0; i < e->used; i++) {
236 if (e->entry[i].usable) {
237 free(e->entry[i].tag);
238 free(e->entry[i].value);
241 free((char *)e->entry);
245 AddEntry(Entries *e, Entry *entry)
249 for (n = 0; n < e->used; n++) {
250 if (!strcmp(e->entry[n].tag, entry->tag)) {
251 /* overwrite old entry */
252 if (e->entry[n].lineno && !quiet) {
254 "%s: \"%s\" on line %d overrides entry on line %d\n",
255 ProgramName, entry->tag, entry->lineno,
258 free(e->entry[n].tag);
259 free(e->entry[n].value);
260 entry->usable = True;
261 e->entry[n] = *entry;
262 return; /* ok to leave, now there's only one of each tag in db */
266 if (e->used == e->room) {
267 e->entry = realloc(e->entry, 2 * e->room * (sizeof(Entry)));
270 entry->usable = True;
271 e->entry[e->used++] = *entry;
276 CompareEntries(const void *e1, const void *e2)
278 return strcmp(((const Entry *)e1)->tag, ((const Entry *)e2)->tag);
282 AppendEntryToBuffer(Buffer *b, Entry *entry)
284 AppendToBuffer(b, entry->tag, strlen(entry->tag));
285 AppendToBuffer(b, ":\t", 2);
286 AppendToBuffer(b, entry->value, strlen(entry->value));
287 AppendToBuffer(b, "\n", 1);
291 * Return the position of the first unescaped occurrence of dest in string.
292 * If lines is non-null, return the number of newlines skipped over.
295 FindFirst(const char *string, char dest, int *lines)
302 if (*string == '\\') {
303 if (*++string == '\0')
305 } else if (*string == dest)
307 if (*string == '\n' && lines)
314 GetEntries(Entries *entries, Buffer *buff, int bequiet)
316 const char *line, *colon, *temp, *str;
324 for ( ; str < buff->buff + buff->used;
325 str = line + 1, lineno += lines_skipped) {
326 line = FindFirst(str, '\n', &lines_skipped);
329 line = buff->buff + buff->used;
334 if (!bequiet && *str == '#') {
336 if (sscanf (str, "# %d", &dummy) == 1 ||
337 sscanf (str, "# line %d", &dummy) == 1)
342 *temp && *temp != '\n' && isascii(*temp) && isspace(*temp);
344 if (!*temp || *temp == '\n') continue;
346 colon = FindFirst(str, ':', NULL);
347 if (!colon || colon > line) {
348 if (!bequiet && !quiet)
350 "%s: colon missing on line %d, ignoring line\n",
351 ProgramName, lineno);
355 /* strip leading and trailing blanks from name and store result */
356 while (*str == ' ' || *str == '\t')
358 length = colon - str;
359 while (length && (str[length-1] == ' ' || str[length-1] == '\t'))
361 entry.tag = malloc(length + 1);
362 strncpy(entry.tag, str, length);
363 entry.tag[length] = '\0';
365 /* strip leading and trailing blanks from value and store result */
367 while (*colon == ' ' || *colon == '\t')
369 length = line - colon;
370 entry.value = malloc(length + 1);
371 strncpy(entry.value, colon, length);
372 entry.value[length] = '\0';
373 entry.lineno = bequiet ? 0 : lineno;
375 AddEntry(entries, &entry);
380 GetEntriesString(Entries *entries, char *str)
386 buff.used = strlen(str);
387 GetEntries(entries, &buff, 1);
392 ReadFile(Buffer *b, FILE *input)
394 char buf[BUFSIZ + 1];
398 while (!feof(input) && (bytes = fread(buf, 1, BUFSIZ, input)) > 0) {
402 for (p = buf; p = strchr(p, '\r'); ) {
403 if (p[-1] == '\\' && p[1] == '\n') {
405 strcpy(p - 1, p + 2);
409 AppendToBuffer(b, buf, bytes);
411 AppendToBuffer(b, "", 1);
415 AddDef(String *buff, const char *title, const char *value)
418 if (need_real_defines) {
419 addstring(buff, "\n#define ");
420 addtokstring(buff, title);
421 if (value && (value[0] != '\0')) {
422 addstring(buff, " ");
423 addstring(buff, value);
429 if (oper == OPSYMBOLS)
430 addstring(buff, "\n-D");
432 addstring(buff, " -D");
434 addstring(buff, "-D");
435 addtokstring(buff, title);
436 if (value && (value[0] != '\0')) {
437 addstring(buff, "=");
438 addescapedstring(buff, value);
443 AddSimpleDef(String *buff, const char *title)
445 AddDef(buff, title, (char *)NULL);
449 AddDefQ(String *buff, const char *title, const char *value)
452 if (need_real_defines)
453 AddDef(buff, title, value);
456 if (value && (value[0] != '\0')) {
457 AddSimpleDef(buff, title);
458 addstring(buff, "=\"");
459 addescapedstring(buff, value);
460 addstring(buff, "\"");
462 AddDef(buff, title, NULL);
466 AddNum(String *buff, const char *title, int value)
469 snprintf(num, sizeof(num), "%d", value);
470 AddDef(buff, title, num);
474 AddDefTok(String *buff, const char *prefix, char *title)
478 snprintf(name, sizeof(name), "%s%s", prefix, title);
479 AddSimpleDef(buff, name);
483 AddDefHostname(String *buff, const char *title, const char *value)
489 strncpy (name, value, sizeof(name)-1);
490 name[sizeof(name)-1] = '\0';
491 for (s = name; (c = *s); s++) {
492 if (!isalpha(c) && !isdigit(c) && c != '_' && c != '.' && c != ':' && c != '-')
495 AddDef(buff, title, name);
499 AddUndef(String *buff, const char *title)
502 if (need_real_defines) {
503 addstring(buff, "\n#undef ");
504 addstring(buff, title);
509 if (oper == OPSYMBOLS)
510 addstring(buff, "\n-U");
512 addstring(buff, " -U");
514 addstring(buff, "-U");
515 addtokstring(buff, title);
519 DoCmdDefines(String *buff)
524 for (i = 0; i < num_cmd_defines; i++) {
525 arg = cmd_defines[i];
527 val = strchr(arg, '=');
530 AddDefQ(buff, arg + 2, val + 1);
533 AddSimpleDef(buff, arg + 2);
534 } else if (arg[1] == 'U') {
535 AddUndef(buff, arg + 2);
536 } else if (!strcmp(arg, "-undef") && oper != OPSYMBOLS) {
537 addstring(buff, " -undef");
543 Resolution(int pixels, int mm)
548 return ((pixels * 100000 / mm) + 50) / 100;
553 DoDisplayDefines(Display *display, String *defs, char *host)
555 #ifndef MAXHOSTNAMELEN
556 #define MAXHOSTNAMELEN 255
558 char client[MAXHOSTNAMELEN], server[MAXHOSTNAMELEN], *colon;
562 XmuGetHostname(client, MAXHOSTNAMELEN);
563 strncpy(server, XDisplayName(host), sizeof(server));
564 server[sizeof(server) - 1] = '\0';
565 /* search for final colon to skip over any embedded colons in IPv6
566 numeric address forms */
567 colon = strrchr(server, ':');
570 /* remove extra colon if there are exactly two, since it indicates
571 DECnet. Three colons is an IPv6 address ending in :: though. */
572 if ((colon > server) && (*(colon-1) == ':') &&
573 ( ((colon - 1) == server) || (*(colon-2) != ':') ) ) {
577 sscanf(colon, "%d", &n);
579 if (!*server || !strcmp(server, "unix") || !strcmp(server, "localhost"))
580 strcpy(server, client);
581 AddDefHostname(defs, "HOST", server); /* R3 compatibility */
582 AddDefHostname(defs, "SERVERHOST", server);
583 AddDefTok(defs, "SRVR_", server);
584 AddNum(defs, "DISPLAY_NUM", n);
585 AddDefHostname(defs, "CLIENTHOST", client);
586 AddDefTok(defs, "CLNT_", client);
587 AddNum(defs, "VERSION", ProtocolVersion(display));
588 AddNum(defs, "REVISION", ProtocolRevision(display));
589 AddDefQ(defs, "VENDOR", ServerVendor(display));
590 AddDefTok(defs, "VNDR_", ServerVendor(display));
591 AddNum(defs, "RELEASE", VendorRelease(display));
592 AddNum(defs, "NUM_SCREENS", ScreenCount(display));
593 extnames = XListExtensions(display, &n);
595 AddDefTok(defs, "EXT_", extnames[n]);
596 XFreeExtensionList(extnames);
599 static const char *ClassNames[] = {
608 #define NUM_CLASS_NAMES (int)(sizeof(ClassNames) / sizeof(ClassNames[0]))
611 DoScreenDefines(Display *display, int scrno, String *defs)
615 XVisualInfo vinfo, *vinfos;
619 screen = ScreenOfDisplay(display, scrno);
620 visual = DefaultVisualOfScreen(screen);
621 vinfo.screen = scrno;
622 vinfos = XGetVisualInfo(display, VisualScreenMask, &vinfo, &nv);
623 AddNum(defs, "SCREEN_NUM", scrno);
624 AddNum(defs, "WIDTH", screen->width);
625 AddNum(defs, "HEIGHT", screen->height);
626 AddNum(defs, "X_RESOLUTION", Resolution(screen->width,screen->mwidth));
627 AddNum(defs, "Y_RESOLUTION", Resolution(screen->height,screen->mheight));
628 AddNum(defs, "PLANES", DisplayPlanes(display, scrno));
629 AddNum(defs, "BITS_PER_RGB", visual->bits_per_rgb);
630 if (visual->class >= 0 && visual->class < NUM_CLASS_NAMES) {
631 AddDefQ(defs, "CLASS", ClassNames[visual->class]);
632 snprintf(name, sizeof(name), "CLASS_%s", ClassNames[visual->class]);
633 AddNum(defs, name, (int)visual->visualid);
637 "%s: unknown visual type %d for default visual id 0x%lx\n",
638 ProgramName, visual->class, visual->visualid);
640 switch(visual->class) {
645 AddSimpleDef(defs, "COLOR");
648 for (i = 0; i < nv; i++) {
649 for (j = i; --j >= 0; ) {
650 if (vinfos[j].class == vinfos[i].class &&
651 vinfos[j].depth == vinfos[i].depth)
655 if (vinfos[i].class >= 0 && vinfos[i].class < NUM_CLASS_NAMES) {
656 snprintf(name, sizeof(name), "CLASS_%s_%d",
657 ClassNames[vinfos[i].class], vinfos[i].depth);
658 AddNum(defs, name, (int)vinfos[i].visualid);
662 "%s: unknown visual type %d for visual id 0x%lx\n",
663 ProgramName, vinfos[i].class, vinfos[i].visualid);
667 XFree((char *)vinfos);
671 FindEntry(Entries *db, Buffer *b)
678 entry.usable = False;
683 phoney.entry = &entry;
684 GetEntries(&phoney, b, 1);
687 for (i = 0; i < db->used; i++) {
691 if (strcmp(e->tag, entry.tag))
694 if (strcmp(e->value, entry.value))
702 EditFile(Entries *new, FILE *in, FILE *out)
715 if (!fgets(buff, BUFSIZ, in))
717 AppendToBuffer(&b, buff, strlen(buff));
718 c = &b.buff[b.used - 1];
719 if ((*(c--) == '\n') && (b.used == 1 || *c != '\\'))
722 if ((e = FindEntry(new, &b)))
723 fprintf(out, "%s:\t%s\n", e->tag, e->value);
725 fwrite(b.buff, 1, b.used, out);
728 for (i = 0; i < new->used; i++) {
731 fprintf(out, "%s:\t%s\n", e->tag, e->value);
735 static void _X_NORETURN
739 "usage: %s [-options ...] [filename]\n\n"
740 "where options include:\n"
741 " -help print this help message\n"
742 " -version print the program version\n"
743 " -display host:dpy display to use\n"
744 " -all do all resources [default]\n"
745 " -global do screen-independent resources\n"
746 " -screen do screen-specific resources for one screen\n"
747 " -screens do screen-specific resources for all screens\n"
748 " -n show but don't do changes\n"
749 " -cpp filename preprocessor to use [%s]\n"
750 " -nocpp do not use a preprocessor\n"
751 " -query query resources\n"
752 " -load load resources from file [default]\n"
753 " -override add in resources from file\n"
754 " -merge merge resources from file & sort\n"
755 " -edit filename edit resources into file\n"
756 " -backup string backup suffix for -edit [%s]\n"
757 " -symbols show preprocessor symbols\n"
758 " -remove remove resources\n"
759 " -retain avoid server reset (avoid using this)\n"
760 " -quiet don't warn about duplicates\n"
761 " -Dname[=value], -Uname, -Idirectory passed to preprocessor\n"
763 "A - or no input filename represents stdin.\n",
764 ProgramName, cpp_program ? cpp_program : "", BACKUP_SUFFIX);
769 * The following is a hack until XrmParseCommand is ready. It determines
770 * whether or not the given string is an abbreviation of the arg.
774 isabbreviation(const char *arg, const char *s, int minslen)
780 if (!strcmp (arg, s)) return (True);
782 arglen = strlen (arg);
785 /* too long or too short */
786 if (slen >= arglen || slen < minslen) return (False);
789 if (strncmp (arg, s, slen) == 0) return (True);
796 addstring(String *arg, const char *s)
798 if(arg->used + strlen(s) + 1 >= arg->room) {
800 arg->val = realloc(arg->val, arg->room + CHUNK_SIZE);
802 arg->val = malloc(arg->room + CHUNK_SIZE);
804 fatal("%s: Not enough memory\n", ProgramName);
805 arg->room += CHUNK_SIZE;
811 arg->used += strlen(s);
815 addescapedstring(String *arg, const char *s)
819 for (c = copy; *s && c < ©[sizeof(copy)-1]; s++) {
821 case '"': case '\'': case '`':
830 addstring (arg, copy);
834 addtokstring(String *arg, const char *s)
838 for (c = copy; *s && c < ©[sizeof(copy)-1]; s++) {
839 if (!isalpha(*s) && !isdigit(*s) && *s != '_')
845 addstring (arg, copy);
850 main(int argc, char *argv[])
853 char *displayname = NULL;
854 int whichResources = RALL;
859 ProgramName = argv[0];
861 defines.room = defines.used = includes.room = includes.used = 0;
863 /* initialize the includes String struct */
864 addstring(&includes, "");
866 /* Pick the default cpp to use. This needs to be done before
867 * we parse the command line in order to honor -nocpp which sets
870 if (cpp_program == NULL) {
871 int number_of_elements
872 = (sizeof cpp_locations) / (sizeof cpp_locations[0]);
875 for (j = 0; j < number_of_elements; j++) {
877 /* cut off arguments */
878 dup = strdup(cpp_locations[j]);
879 end = strchr(dup,' ');
882 if (access(dup, X_OK) == 0) {
883 cpp_program = cpp_locations[j];
891 /* needs to be replaced with XrmParseCommand */
893 for (i = 1; i < argc; i++) {
897 if (arg[1] == '\0') {
900 } else if (isabbreviation ("-help", arg, 2)) {
903 } else if (isabbreviation ("-version", arg, 2)) {
904 printf("%s\n", PACKAGE_STRING);
906 } else if (isabbreviation ("-display", arg, 2)) {
907 if (++i >= argc) Syntax ();
908 displayname = argv[i];
910 } else if (isabbreviation ("-geometry", arg, 3)) {
911 if (++i >= argc) Syntax ();
912 /* ignore geometry */
914 } else if (isabbreviation ("-cpp", arg, 2)) {
915 if (++i >= argc) Syntax ();
916 cpp_program = argv[i];
918 } else if (!strcmp ("-n", arg)) {
921 } else if (isabbreviation ("-nocpp", arg, 3)) {
924 } else if (isabbreviation ("-query", arg, 2)) {
927 } else if (isabbreviation ("-load", arg, 2)) {
930 } else if (isabbreviation ("-merge", arg, 2)) {
933 } else if (isabbreviation ("-override", arg, 2)) {
936 } else if (isabbreviation ("-symbols", arg, 3)) {
939 } else if (isabbreviation ("-remove", arg, 4)) {
942 } else if (isabbreviation ("-edit", arg, 2)) {
943 if (++i >= argc) Syntax ();
947 } else if (isabbreviation ("-backup", arg, 2)) {
948 if (++i >= argc) Syntax ();
949 backup_suffix = argv[i];
951 } else if (isabbreviation ("-all", arg, 2)) {
952 whichResources = RALL;
954 } else if (isabbreviation ("-global", arg, 3)) {
955 whichResources = RGLOBAL;
957 } else if (isabbreviation ("-screen", arg, 3)) {
958 whichResources = RSCREEN;
960 } else if (!strcmp ("-screens", arg)) {
961 whichResources = RSCREENS;
963 } else if (isabbreviation ("-retain", arg, 4)) {
966 } else if (isabbreviation ("-quiet", arg, 2)) {
969 } else if (arg[1] == 'I') {
970 addstring(&includes, " ");
971 addescapedstring(&includes, arg);
973 } else if (arg[1] == 'U' || arg[1] == 'D') {
974 if (num_cmd_defines < MAX_CMD_DEFINES) {
975 cmd_defines[num_cmd_defines++] = arg;
977 fatal("%s: Too many -U/-D arguments\n", ProgramName);
980 } else if (!strcmp ("-undef", arg)) {
981 if (num_cmd_defines < MAX_CMD_DEFINES) {
982 cmd_defines[num_cmd_defines++] = "-undef";
984 fatal("%s: Too many cpp arguments\n", ProgramName);
989 } else if (arg[0] == '=')
996 while ((i = open("/dev/null", O_RDONLY)) < 3)
997 ; /* make sure later freopen won't clobber things */
1001 if (!(dpy = XOpenDisplay (displayname)))
1002 fatal("%s: Can't open display '%s'\n", ProgramName,
1003 XDisplayName (displayname));
1005 if (whichResources == RALL && ScreenCount(dpy) == 1)
1006 whichResources = RGLOBAL;
1010 (oper == OPLOAD || oper == OPMERGE || oper == OPOVERRIDE)) {
1011 need_real_defines = True;
1013 strcpy(tmpname2, "xrdbD_XXXXXX");
1014 strcpy(tmpname3, "\\temp\\xrdbD_XXXXXX");
1017 { char *tmpdir=getenv("TMP");
1018 if (!tmpdir) tmpdir="/";
1019 sprintf(tmpname2, "%s/xrdbD_XXXXXX",tmpdir);
1022 strcpy(tmpname2, "/tmp/xrdbD_XXXXXX");
1025 (void) mktemp(tmpname2);
1033 (oper == OPLOAD || oper == OPMERGE || oper == OPOVERRIDE) &&
1034 (whichResources == RALL || whichResources == RSCREENS)
1037 char inputbuf[1024];
1039 strcpy(tmpname, "\\temp\\xrdb_XXXXXX");
1042 { char *tmpdir=getenv("TMP");
1043 if (!tmpdir) tmpdir="/";
1044 sprintf(tmpname, "%s/xrdb_XXXXXX",tmpdir);
1047 strcpy(tmpname, "/tmp/xrdb_XXXXXX");
1050 #ifndef HAVE_MKSTEMP
1051 (void) mktemp(tmpname);
1053 fp = fopen(filename, "w");
1056 int fd = mkstemp(tmpname);
1058 fp = fdopen(fd, "w");
1060 #endif /* MKSTEMP */
1062 fatal("%s: Failed to open temp file: %s\n", ProgramName,
1064 while (fgets(inputbuf, sizeof(inputbuf), stdin) != NULL)
1065 fputs(inputbuf, fp);
1069 DoDisplayDefines(dpy, &defines, displayname);
1070 defines_base = defines.used;
1071 need_newline = (oper == OPQUERY || oper == OPSYMBOLS ||
1072 (dont_execute && oper != OPREMOVE));
1073 InitBuffer(&buffer);
1074 if (whichResources == RGLOBAL)
1075 Process(DefaultScreen(dpy), False, True);
1076 else if (whichResources == RSCREEN)
1077 Process(DefaultScreen(dpy), True, True);
1078 else if (whichResources == RSCREENS ||
1079 (oper != OPLOAD && oper != OPMERGE && oper != OPOVERRIDE)) {
1080 if (whichResources == RALL && oper != OPSYMBOLS) {
1082 printf("! screen-independent resources\n");
1083 Process(0, False, True);
1087 for (i = 0; i < ScreenCount(dpy); i++) {
1089 if (oper == OPSYMBOLS)
1090 printf("# screen %d symbols\n", i);
1092 printf("! screen %d resources\n", i);
1093 printf("#if SCREEN_NUM == %d\n", i);
1096 Process(i, True, True);
1098 if (oper != OPSYMBOLS)
1100 if (i+1 != ScreenCount(dpy))
1108 dbs = malloc(ScreenCount(dpy) * sizeof(Entries));
1109 for (i = 0; i < ScreenCount(dpy); i++) {
1110 Process(i, True, False);
1113 InitEntries(&newDB);
1114 if (oper == OPMERGE || oper == OPOVERRIDE)
1115 GetEntriesString(&newDB, XResourceManagerString(dpy));
1116 ShuffleEntries(&newDB, dbs, ScreenCount(dpy));
1118 printf("! screen-independent resources\n");
1119 ReProcess(0, False);
1122 for (i = 0; i < ScreenCount(dpy); i++) {
1125 printf("! screen %d resources\n", i);
1126 printf("#if SCREEN_NUM == %d\n", i);
1131 if (i+1 != ScreenCount(dpy))
1140 XSetCloseDownMode(dpy, RetainPermanent);
1147 FormatEntries(Buffer *b, Entries *entries)
1154 if (oper == OPMERGE)
1155 qsort(entries->entry, entries->used, sizeof(Entry),
1157 for (i = 0; i < entries->used; i++) {
1158 if (entries->entry[i].usable)
1159 AppendEntryToBuffer(b, &entries->entry[i]);
1164 StoreProperty(Display *display, Window root, Atom res_prop)
1166 int len = buffer.used;
1167 int mode = PropModeReplace;
1168 unsigned char *buf = (unsigned char *)buffer.buff;
1169 int max = (XMaxRequestSize(display) << 2) - 28;
1172 XGrabServer(display);
1174 XChangeProperty(display, root, res_prop, XA_STRING, 8, mode, buf, max);
1177 mode = PropModeAppend;
1178 } while (len > max);
1180 XChangeProperty(display, root, res_prop, XA_STRING, 8, mode, buf, len);
1181 if (mode != PropModeReplace)
1182 XUngrabServer(display);
1186 Process(int scrno, Bool doScreen, Bool execute)
1191 FILE *input, *output;
1194 defines.val[defines_base] = '\0';
1195 defines.used = defines_base;
1197 InitEntries(&newDB);
1198 DoScreenDefines(dpy, scrno, &defines);
1199 DoCmdDefines(&defines);
1201 xdefs = XScreenResourceString (ScreenOfDisplay(dpy, scrno));
1202 root = RootWindow(dpy, scrno);
1203 res_prop = XInternAtom(dpy, SCREEN_RESOURCES, False);
1205 xdefs = XResourceManagerString (dpy);
1206 root = RootWindow(dpy, 0);
1207 res_prop = XA_RESOURCE_MANAGER;
1209 if (oper == OPSYMBOLS) {
1210 printf ("%s\n", defines.val);
1211 } else if (oper == OPQUERY) {
1213 printf ("%s", xdefs); /* fputs broken in SunOS 4.0 */
1214 } else if (oper == OPREMOVE) {
1216 XDeleteProperty(dpy, root, res_prop);
1217 } else if (oper == OPEDIT) {
1218 char template[100], old[100];
1220 input = fopen(editFile, "r");
1221 snprintf(template, sizeof(template), "%sXXXXXX", editFile);
1222 #ifndef HAVE_MKSTEMP
1223 (void) mktemp(template);
1224 output = fopen(template, "w");
1227 int fd = mkstemp(template);
1228 output = fdopen(fd, "w");
1232 fatal("%s: can't open temporary file '%s'\n", ProgramName, template);
1233 GetEntriesString(&newDB, xdefs);
1234 EditFile(&newDB, input, output);
1238 snprintf(old, sizeof(old), "%s%s", editFile, backup_suffix);
1239 if (dont_execute) { /* then write to standard out */
1243 output = fopen (template, "r");
1245 while ((n = fread (buf, 1, sizeof buf, output)) > 0) {
1246 fwrite (buf, 1, n, stdout);
1252 rename (editFile, old);
1253 if (rename (template, editFile))
1254 fatal("%s: can't rename file '%s' to '%s'\n", ProgramName,
1255 template, editFile);
1258 const char *cpp_addflags = "";
1260 if (oper == OPMERGE || oper == OPOVERRIDE)
1261 GetEntriesString(&newDB, xdefs);
1263 /* Add -P flag only if using cpp, not another preprocessor */
1265 const char *cp = strstr(cpp_program, "cpp");
1267 if (cp && ((cp[3] == '\0') || cp[3] == ' '))
1268 cpp_addflags = "-P";
1271 if (need_real_defines) {
1273 if (!(input = fopen(tmpname2, "w")))
1274 fatal("%s: can't open file '%s'\n", ProgramName, tmpname2);
1275 fputs(defines.val, input);
1276 fprintf(input, "\n#include \"%s\"\n", filename);
1278 (void) mktemp(tmpname3);
1279 if (asprintf(&cmd, "%s %s %s %s > %s", cpp_program, cpp_addflags,
1280 includes.val, tmpname2, tmpname3) == -1)
1281 fatal("%s: Out of memory\n", ProgramName);
1282 if (system(cmd) < 0)
1283 fatal("%s: cannot run '%s'\n", ProgramName, cmd);
1285 if (!(input = fopen(tmpname3, "r")))
1286 fatal("%s: can't open file '%s'\n", ProgramName, tmpname3);
1288 if (!freopen(tmpname2, "w+", stdin))
1289 fatal("%s: can't open file '%s'\n", ProgramName, tmpname2);
1290 fputs(defines.val, stdin);
1291 fprintf(stdin, "\n#include \"%s\"\n", filename);
1294 if (asprintf(&cmd, "%s %s %s", cpp_program, cpp_addflags,
1295 includes.val) == -1)
1296 fatal("%s: Out of memory\n", ProgramName);
1297 if (!(input = popen(cmd, "r")))
1298 fatal("%s: cannot run '%s'\n", ProgramName, cmd);
1304 if (!freopen (filename, "r", stdin))
1305 fatal("%s: can't open file '%s'\n", ProgramName, filename);
1309 (void) mktemp(tmpname3);
1310 if (asprintf(&cmd, "%s %s %s %s %s > %s", cpp_program,
1311 cpp_addflags, includes.val, defines.val,
1312 filename ? filename : "", tmpname3) == -1)
1313 fatal("%s: Out of memory\n", ProgramName);
1314 if (system(cmd) < 0)
1315 fatal("%s: cannot run '%s'\n", ProgramName, cmd);
1317 if (!(input = fopen(tmpname3, "r")))
1318 fatal("%s: can't open file '%s'\n", ProgramName, tmpname3);
1320 if (asprintf(&cmd, "%s %s %s %s %s", cpp_program,
1321 cpp_addflags, includes.val, defines.val,
1322 filename ? filename : "") == -1)
1323 fatal("%s: Out of memory\n", ProgramName);
1324 if (!(input = popen(cmd, "r")))
1325 fatal("%s: cannot run '%s'\n", ProgramName, cmd);
1334 ReadFile(&buffer, input);
1343 if (need_real_defines) {
1346 if (tmpname3[strlen(tmpname3) - 1] != 'X')
1351 GetEntries(&newDB, &buffer, 0);
1353 FormatEntries(&buffer, &newDB);
1355 if (buffer.used > 0) {
1356 fwrite (buffer.buff, 1, buffer.used, stdout);
1357 if (buffer.buff[buffer.used - 1] != '\n') putchar ('\n');
1359 } else if (buffer.used > 1 || !doScreen)
1360 StoreProperty (dpy, root, res_prop);
1362 XDeleteProperty (dpy, root, res_prop);
1366 FreeEntries(&newDB);
1367 if (doScreen && xdefs)
1372 ShuffleEntries(Entries *db, Entries *dbs, int num)
1375 register int i, j, k;
1377 char *curtag, *curvalue;
1379 hits = malloc(num * sizeof(int));
1381 for (i = 0; i < cur.used; i++) {
1382 curtag = cur.entry[i].tag;
1383 curvalue = cur.entry[i].value;
1384 for (j = 1; j < num; j++) {
1386 for (k = 0; k < cmp.used; k++) {
1387 if (cmp.entry[k].usable &&
1388 !strcmp(curtag, cmp.entry[k].tag) &&
1389 !strcmp(curvalue, cmp.entry[k].value))
1399 AddEntry(db, &cur.entry[i]);
1401 for (j = 0; j < num; j++)
1402 dbs[j].entry[hits[j]].usable = False;
1409 ReProcess(int scrno, Bool doScreen)
1414 FormatEntries(&buffer, &newDB);
1416 root = RootWindow(dpy, scrno);
1417 res_prop = XInternAtom(dpy, SCREEN_RESOURCES, False);
1419 root = RootWindow(dpy, 0);
1420 res_prop = XA_RESOURCE_MANAGER;
1423 if (buffer.used > 0) {
1424 fwrite (buffer.buff, 1, buffer.used, stdout);
1425 if (buffer.buff[buffer.used - 1] != '\n') putchar ('\n');
1428 if (buffer.used > 1 || !doScreen)
1429 StoreProperty (dpy, root, res_prop);
1431 XDeleteProperty (dpy, root, res_prop);
1433 FreeEntries(&newDB);
1437 fatal(const char *msg, ...)
1442 perror(ProgramName);
1443 va_start(args, msg);
1444 vfprintf(stderr, msg, args);