xrdb.c revision e3e77a2a
1/* 2 * xrdb - X resource manager database utility 3 * 4 */ 5 6/* 7 * COPYRIGHT 1987, 1991 8 * DIGITAL EQUIPMENT CORPORATION 9 * MAYNARD, MASSACHUSETTS 10 * MASSACHUSETTS INSTITUTE OF TECHNOLOGY 11 * CAMBRIDGE, MASSACHUSETTS 12 * ALL RIGHTS RESERVED. 13 * 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. 18 * 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 21 * SET FORTH ABOVE. 22 * 23 * 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. 31 */ 32 33/* 34 * this program is used to load, or dump the resource manager database 35 * in the server. 36 * 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 40 */ 41 42#ifdef HAVE_CONFIG_H 43#include <config.h> 44#endif 45 46#include <X11/Xlib.h> 47#include <X11/Xutil.h> 48#include <X11/Xatom.h> 49#include <X11/Xos.h> 50#include <X11/Xmu/SysUtil.h> 51#include <stdio.h> 52#include <ctype.h> 53#include <errno.h> 54#include <stdlib.h> 55#include <stdarg.h> 56#include <stdint.h> 57 58#ifdef NEED_SYS_PARAM_H 59# include <sys/param.h> /* defines MAXHOSTNAMELEN on BSD & Linux */ 60#endif 61 62#ifdef NEED_NETDB_H 63# include <netdb.h> /* defines MAXHOSTNAMELEN on Solaris */ 64#endif 65 66#define SCREEN_RESOURCES "SCREEN_RESOURCES" 67 68#ifndef CPP 69#define CPP "/usr/lib/cpp" 70#endif /* CPP */ 71 72#define INIT_BUFFER_SIZE 10000 73#define INIT_ENTRY_SIZE 500 74 75#define RALL 0 76#define RGLOBAL 1 77#define RSCREEN 2 78#define RSCREENS 3 79 80#define OPSYMBOLS 0 81#define OPQUERY 1 82#define OPREMOVE 2 83#define OPEDIT 3 84#define OPLOAD 4 85#define OPMERGE 5 86#define OPOVERRIDE 6 87 88#define BACKUP_SUFFIX ".bak" /* for editing */ 89 90typedef struct _Entry { 91 char *tag, *value; 92 int lineno; 93 Bool usable; 94} Entry; 95 96typedef struct _Buffer { 97 char *buff; 98 size_t room, used; 99} Buffer; 100 101typedef struct _Entries { 102 Entry *entry; 103 size_t room, used; 104} Entries; 105 106/* dynamically allocated strings */ 107#define CHUNK_SIZE 4096 108typedef struct _String { 109 char *val; 110 size_t room, used; 111} String; 112 113static char *ProgramName; 114static Bool quiet = False; 115static char tmpname[32]; 116static char *filename = NULL; 117#ifdef PATHETICCPP 118static Bool need_real_defines = False; 119static char tmpname2[32]; 120#endif 121#ifdef WIN32 122static char tmpname3[32]; 123#endif 124static int oper = OPLOAD; 125static char *editFile = NULL; 126static const char *cpp_program = NULL; 127static const char * const cpp_locations[] = { CPP }; 128static const char *backup_suffix = BACKUP_SUFFIX; 129static Bool dont_execute = False; 130static Bool show_cpp = False; 131static String defines; 132static size_t defines_base; 133#define MAX_CMD_DEFINES 512 134static char *cmd_defines[MAX_CMD_DEFINES]; 135static int num_cmd_defines = 0; 136static String includes; 137static Display *dpy; 138static Buffer buffer; 139static Entries newDB; 140 141static void fatal(const char *, ...) 142 _X_ATTRIBUTE_PRINTF(1, 2)_X_NORETURN _X_COLD; 143static void addstring(String *arg, const char *s); 144static void addescapedstring(String *arg, const char *s); 145static void addtokstring(String *arg, const char *s); 146static void FormatEntries(Buffer *b, Entries * entries); 147static void StoreProperty(Display *display, Window root, Atom res_prop); 148static void Process(int scrno, Bool doScreen, Bool execute); 149static void ShuffleEntries(Entries *db, Entries *dbs, unsigned int num); 150static void ReProcess(int scrno, Bool doScreen); 151 152#ifndef HAVE_ASPRINTF 153/* sprintf variant found in newer libc's which allocates string to print to */ 154static int _X_ATTRIBUTE_PRINTF(2, 3) 155asprintf(char **ret, const char *format, ...) 156{ 157 char buf[256]; 158 int len; 159 va_list ap; 160 161 va_start(ap, format); 162 len = vsnprintf(buf, sizeof(buf), format, ap); 163 va_end(ap); 164 165 if (len < 0) 166 return -1; 167 168 if (len < sizeof(buf)) { 169 *ret = strdup(buf); 170 } 171 else { 172 *ret = malloc(len + 1); /* snprintf doesn't count trailing '\0' */ 173 if (*ret != NULL) { 174 va_start(ap, format); 175 len = vsnprintf(*ret, len + 1, format, ap); 176 va_end(ap); 177 if (len < 0) { 178 free(*ret); 179 *ret = NULL; 180 } 181 } 182 } 183 184 if (*ret == NULL) 185 return -1; 186 187 return len; 188} 189#endif /* HAVE_ASPRINTF */ 190 191#ifndef HAVE_REALLOCARRAY 192/* overflow checking realloc API from OpenBSD libc */ 193static inline void * 194reallocarray(void *optr, size_t n, size_t s) 195{ 196 if (n > 0 && (SIZE_MAX / n) < s) 197 return NULL; 198 return realloc(optr, n * s); 199} 200#endif 201 202# define mallocarray(n, s) reallocarray(NULL, n, s) 203 204static void 205InitBuffer(Buffer *b) 206{ 207 b->room = INIT_BUFFER_SIZE; 208 b->used = 0; 209 b->buff = mallocarray(INIT_BUFFER_SIZE, sizeof(char)); 210 if (b->buff == NULL) 211 fatal("%s: Can't allocate memory in %s\n", ProgramName, __func__); 212} 213 214#ifdef notyet 215static void 216FreeBuffer(Buffer *b) 217{ 218 free(b->buff); 219} 220#endif 221 222static void 223AppendToBuffer(Buffer *b, const char *str, size_t len) 224{ 225 while (b->used + len > b->room) { 226 b->buff = reallocarray(b->buff, b->room, 2 * sizeof(char)); 227 if (b->buff == NULL) 228 fatal("%s: Can't allocate memory in %s\n", ProgramName, __func__); 229 b->room *= 2; 230 } 231 strncpy(b->buff + b->used, str, len); 232 b->used += len; 233} 234 235static void 236InitEntries(Entries *e) 237{ 238 e->room = INIT_ENTRY_SIZE; 239 e->used = 0; 240 e->entry = mallocarray(INIT_ENTRY_SIZE, sizeof(Entry)); 241 if (e->entry == NULL) 242 fatal("%s: Can't allocate memory in %s\n", ProgramName, __func__); 243 244} 245 246static void 247FreeEntries(Entries *e) 248{ 249 size_t i; 250 251 for (i = 0; i < e->used; i++) { 252 if (e->entry[i].usable) { 253 free(e->entry[i].tag); 254 free(e->entry[i].value); 255 } 256 } 257 free(e->entry); 258} 259 260static void 261AddEntry(Entries *e, Entry *entry) 262{ 263 size_t n; 264 265 for (n = 0; n < e->used; n++) { 266 if (!strcmp(e->entry[n].tag, entry->tag)) { 267 /* overwrite old entry */ 268 if (e->entry[n].lineno && !quiet) { 269 fprintf(stderr, 270 "%s: \"%s\" on line %d overrides entry on line %d\n", 271 ProgramName, entry->tag, entry->lineno, 272 e->entry[n].lineno); 273 } 274 free(e->entry[n].tag); 275 free(e->entry[n].value); 276 entry->usable = True; 277 e->entry[n] = *entry; 278 return; /* ok to leave, now there's only one of each tag in db */ 279 } 280 } 281 282 if (e->used == e->room) { 283 e->entry = reallocarray(e->entry, e->room, 2 * sizeof(Entry)); 284 if (e->entry == NULL) 285 fatal("%s: Can't allocate memory in %s\n", ProgramName, __func__); 286 e->room *= 2; 287 } 288 entry->usable = True; 289 e->entry[e->used++] = *entry; 290} 291 292static int 293CompareEntries(const void *e1, const void *e2) 294{ 295 return strcmp(((const Entry *) e1)->tag, ((const Entry *) e2)->tag); 296} 297 298static void 299AppendEntryToBuffer(Buffer *b, Entry *entry) 300{ 301 AppendToBuffer(b, entry->tag, strlen(entry->tag)); 302 AppendToBuffer(b, ":\t", 2); 303 AppendToBuffer(b, entry->value, strlen(entry->value)); 304 AppendToBuffer(b, "\n", 1); 305} 306 307/* 308 * Return the position of the first unescaped occurrence of dest in string. 309 * If lines is non-null, return the number of newlines skipped over. 310 */ 311static const char * 312FindFirst(const char *string, char dest, int *lines) 313{ 314 if (lines) 315 *lines = 0; 316 for (;;) { 317 if (*string == '\0') 318 return NULL; 319 if (*string == '\\') { 320 if (*++string == '\0') 321 return NULL; 322 } 323 else if (*string == dest) 324 return string; 325 if (*string == '\n' && lines) 326 (*lines)++; 327 string++; 328 } 329} 330 331static void 332GetEntries(Entries *entries, Buffer *buff, int bequiet) 333{ 334 const char *line, *colon, *temp, *str; 335 Entry entry; 336 size_t length; 337 int lineno = 0; 338 int lines_skipped; 339 340 str = buff->buff; 341 if (!str) 342 return; 343 for (; str < buff->buff + buff->used; 344 str = line + 1, lineno += lines_skipped) { 345 line = FindFirst(str, '\n', &lines_skipped); 346 lineno++; 347 if (!line) 348 line = buff->buff + buff->used; 349 if (*str == '!') 350 continue; 351 if (*str == '\n') 352 continue; 353 if (!bequiet && *str == '#') { 354 int dummy; 355 356 if (sscanf(str, "# %d", &dummy) == 1 || 357 sscanf(str, "# line %d", &dummy) == 1) 358 lineno = dummy - 1; 359 continue; 360 } 361 for (temp = str; 362 *temp && *temp != '\n' && isascii(*temp) && isspace(*temp); 363 temp++); 364 if (!*temp || *temp == '\n') 365 continue; 366 367 colon = FindFirst(str, ':', NULL); 368 if (!colon || colon > line) { 369 if (!bequiet && !quiet) 370 fprintf(stderr, 371 "%s: colon missing on line %d, ignoring line\n", 372 ProgramName, lineno); 373 continue; 374 } 375 376 /* strip leading and trailing blanks from name and store result */ 377 while (*str == ' ' || *str == '\t') 378 str++; 379 length = colon - str; 380 while (length && (str[length - 1] == ' ' || str[length - 1] == '\t')) 381 length--; 382 entry.tag = malloc(length + 1); 383 strncpy(entry.tag, str, length); 384 entry.tag[length] = '\0'; 385 386 /* strip leading and trailing blanks from value and store result */ 387 colon++; 388 while (*colon == ' ' || *colon == '\t') 389 colon++; 390 length = line - colon; 391 entry.value = malloc(length + 1); 392 strncpy(entry.value, colon, length); 393 entry.value[length] = '\0'; 394 entry.lineno = bequiet ? 0 : lineno; 395 396 AddEntry(entries, &entry); 397 } 398} 399 400static void 401GetEntriesString(Entries *entries, char *str) 402{ 403 Buffer buff; 404 405 if (str && *str) { 406 buff.buff = str; 407 buff.used = strlen(str); 408 GetEntries(entries, &buff, 1); 409 } 410} 411 412static void 413ReadFile(Buffer *b, FILE *input) 414{ 415 char buf[BUFSIZ + 1]; 416 size_t bytes; 417 418 b->used = 0; 419 while (!feof(input) && (bytes = fread(buf, 1, BUFSIZ, input)) > 0) { 420#ifdef WIN32 421 char *p; 422 423 buf[bytes] = '\0'; 424 for (p = buf; p = strchr(p, '\r');) { 425 if (p[-1] == '\\' && p[1] == '\n') { 426 bytes -= 3; 427 strcpy(p - 1, p + 2); 428 } 429 } 430#endif 431 AppendToBuffer(b, buf, bytes); 432 if (show_cpp) 433 fwrite(buf, 1, bytes, stdout); 434 } 435 AppendToBuffer(b, "", 1); 436} 437 438static void 439AddDef(String *buff, const char *title, const char *value) 440{ 441#ifdef PATHETICCPP 442 if (need_real_defines) { 443 addstring(buff, "\n#define "); 444 addtokstring(buff, title); 445 if (value && (value[0] != '\0')) { 446 addstring(buff, " "); 447 addstring(buff, value); 448 } 449 return; 450 } 451#endif 452 if (buff->used) { 453 if (oper == OPSYMBOLS) 454 addstring(buff, "\n-D"); 455 else 456 addstring(buff, " -D"); 457 } 458 else 459 addstring(buff, "-D"); 460 addtokstring(buff, title); 461 if (value && (value[0] != '\0')) { 462 addstring(buff, "="); 463 addescapedstring(buff, value); 464 } 465} 466 467static void 468AddSimpleDef(String *buff, const char *title) 469{ 470 AddDef(buff, title, (char *) NULL); 471} 472 473static void 474AddDefQ(String *buff, const char *title, const char *value) 475{ 476#ifdef PATHETICCPP 477 if (need_real_defines) 478 AddDef(buff, title, value); 479 else 480#endif 481 if (value && (value[0] != '\0')) { 482 AddSimpleDef(buff, title); 483 addstring(buff, "=\""); 484 addescapedstring(buff, value); 485 addstring(buff, "\""); 486 } 487 else 488 AddDef(buff, title, NULL); 489} 490 491static void 492AddNum(String *buff, const char *title, int value) 493{ 494 char num[20]; 495 496 snprintf(num, sizeof(num), "%d", value); 497 AddDef(buff, title, num); 498} 499 500static void 501AddDefTok(String *buff, const char *prefix, char *title) 502{ 503 char name[512]; 504 505 snprintf(name, sizeof(name), "%s%s", prefix, title); 506 AddSimpleDef(buff, name); 507} 508 509static void 510AddDefHostname(String *buff, const char *title, const char *value) 511{ 512 char *s; 513 char name[512]; 514 char c; 515 516 strncpy(name, value, sizeof(name) - 1); 517 name[sizeof(name) - 1] = '\0'; 518 for (s = name; (c = *s); s++) { 519 if (!isalpha(c) && !isdigit(c) && 520 c != '_' && c != '.' && c != ':' && c != '-') 521 *s = '_'; 522 } 523 AddDef(buff, title, name); 524} 525 526static void 527AddUndef(String *buff, const char *title) 528{ 529#ifdef PATHETICCPP 530 if (need_real_defines) { 531 addstring(buff, "\n#undef "); 532 addstring(buff, title); 533 return; 534 } 535#endif 536 if (buff->used) { 537 if (oper == OPSYMBOLS) 538 addstring(buff, "\n-U"); 539 else 540 addstring(buff, " -U"); 541 } 542 else 543 addstring(buff, "-U"); 544 addtokstring(buff, title); 545} 546 547static void 548DoCmdDefines(String *buff) 549{ 550 int i; 551 char *arg, *val; 552 553 for (i = 0; i < num_cmd_defines; i++) { 554 arg = cmd_defines[i]; 555 if (arg[1] == 'D') { 556 val = strchr(arg, '='); 557 if (val) { 558 *val = '\0'; 559 AddDefQ(buff, arg + 2, val + 1); 560 *val = '='; 561 } 562 else 563 AddSimpleDef(buff, arg + 2); 564 } 565 else if (arg[1] == 'U') { 566 AddUndef(buff, arg + 2); 567 } 568 else if (!strcmp(arg, "-undef") && oper != OPSYMBOLS) { 569 addstring(buff, " -undef"); 570 } 571 } 572} 573 574static int 575Resolution(int pixels, int mm) 576{ 577 if (mm == 0) 578 return 0; 579 else 580 return ((pixels * 100000 / mm) + 50) / 100; 581} 582 583static void 584DoDisplayDefines(Display *display, String *defs, char *host) 585{ 586#ifndef MAXHOSTNAMELEN 587#define MAXHOSTNAMELEN 255 588#endif 589 char client[MAXHOSTNAMELEN], server[MAXHOSTNAMELEN], *colon; 590 char **extnames; 591 int n; 592 593 XmuGetHostname(client, MAXHOSTNAMELEN); 594 strncpy(server, XDisplayName(host), sizeof(server)); 595 server[sizeof(server) - 1] = '\0'; 596 /* search for final colon to skip over any embedded colons in IPv6 597 numeric address forms */ 598 colon = strrchr(server, ':'); 599 n = 0; 600 if (colon) { 601 /* remove extra colon if there are exactly two, since it indicates 602 DECnet. Three colons is an IPv6 address ending in :: though. */ 603 if ((colon > server) && (*(colon - 1) == ':') && 604 (((colon - 1) == server) || (*(colon - 2) != ':'))) { 605 *(colon - 1) = ':'; 606 } 607 *colon++ = '\0'; 608 sscanf(colon, "%d", &n); 609 } 610 if (!*server || !strcmp(server, "unix") || !strcmp(server, "localhost")) 611 strcpy(server, client); 612 AddDefHostname(defs, "HOST", server); /* R3 compatibility */ 613 AddDefHostname(defs, "SERVERHOST", server); 614 AddDefTok(defs, "SRVR_", server); 615 AddNum(defs, "DISPLAY_NUM", n); 616 AddDefHostname(defs, "CLIENTHOST", client); 617 AddDefTok(defs, "CLNT_", client); 618 AddNum(defs, "VERSION", ProtocolVersion(display)); 619 AddNum(defs, "REVISION", ProtocolRevision(display)); 620 AddDefQ(defs, "VENDOR", ServerVendor(display)); 621 AddDefTok(defs, "VNDR_", ServerVendor(display)); 622 AddNum(defs, "RELEASE", VendorRelease(display)); 623 AddNum(defs, "NUM_SCREENS", ScreenCount(display)); 624 extnames = XListExtensions(display, &n); 625 while (--n >= 0) 626 AddDefTok(defs, "EXT_", extnames[n]); 627 XFreeExtensionList(extnames); 628} 629 630static const char *ClassNames[] = { 631 "StaticGray", 632 "GrayScale", 633 "StaticColor", 634 "PseudoColor", 635 "TrueColor", 636 "DirectColor" 637}; 638 639#define NUM_CLASS_NAMES (int)(sizeof(ClassNames) / sizeof(ClassNames[0])) 640 641static void 642DoScreenDefines(Display *display, int scrno, String *defs) 643{ 644 Screen *screen; 645 Visual *visual; 646 XVisualInfo vinfo, *vinfos; 647 int nv, i, j; 648 char name[50]; 649 650 screen = ScreenOfDisplay(display, scrno); 651 visual = DefaultVisualOfScreen(screen); 652 vinfo.screen = scrno; 653 vinfos = XGetVisualInfo(display, VisualScreenMask, &vinfo, &nv); 654 AddNum(defs, "SCREEN_NUM", scrno); 655 AddNum(defs, "WIDTH", screen->width); 656 AddNum(defs, "HEIGHT", screen->height); 657 AddNum(defs, "X_RESOLUTION", Resolution(screen->width, screen->mwidth)); 658 AddNum(defs, "Y_RESOLUTION", Resolution(screen->height, screen->mheight)); 659 AddNum(defs, "PLANES", DisplayPlanes(display, scrno)); 660 AddNum(defs, "BITS_PER_RGB", visual->bits_per_rgb); 661 if (visual->class >= 0 && visual->class < NUM_CLASS_NAMES) { 662 AddDefQ(defs, "CLASS", ClassNames[visual->class]); 663 snprintf(name, sizeof(name), "CLASS_%s", ClassNames[visual->class]); 664 AddNum(defs, name, (int) visual->visualid); 665 } 666 else { 667 fprintf(stderr, 668 "%s: unknown visual type %d for default visual id 0x%lx\n", 669 ProgramName, visual->class, visual->visualid); 670 } 671 switch (visual->class) { 672 case StaticColor: 673 case PseudoColor: 674 case TrueColor: 675 case DirectColor: 676 AddSimpleDef(defs, "COLOR"); 677 break; 678 } 679 for (i = 0; i < nv; i++) { 680 for (j = i; --j >= 0;) { 681 if (vinfos[j].class == vinfos[i].class && 682 vinfos[j].depth == vinfos[i].depth) 683 break; 684 } 685 if (j < 0) { 686 if (vinfos[i].class >= 0 && vinfos[i].class < NUM_CLASS_NAMES) { 687 snprintf(name, sizeof(name), "CLASS_%s_%d", 688 ClassNames[vinfos[i].class], vinfos[i].depth); 689 AddNum(defs, name, (int) vinfos[i].visualid); 690 } 691 else { 692 fprintf(stderr, 693 "%s: unknown visual type %d for visual id 0x%lx\n", 694 ProgramName, vinfos[i].class, vinfos[i].visualid); 695 } 696 } 697 } 698 XFree(vinfos); 699} 700 701static Entry * 702FindEntry(Entries *db, Buffer *b) 703{ 704 size_t i; 705 register Entry *e; 706 Entries phoney; 707 Entry entry; 708 709 entry.usable = False; 710 entry.tag = NULL; 711 entry.value = NULL; 712 phoney.used = 0; 713 phoney.room = 1; 714 phoney.entry = &entry; 715 GetEntries(&phoney, b, 1); 716 if (phoney.used < 1) 717 return NULL; 718 for (i = 0; i < db->used; i++) { 719 e = &db->entry[i]; 720 if (!e->usable) 721 continue; 722 if (strcmp(e->tag, entry.tag)) 723 continue; 724 e->usable = False; 725 if (strcmp(e->value, entry.value)) 726 return e; 727 return NULL; 728 } 729 return NULL; 730} 731 732static void 733EditFile(Entries *new, FILE *in, FILE *out) 734{ 735 Buffer b; 736 char buff[BUFSIZ]; 737 register Entry *e; 738 register char *c; 739 size_t i; 740 741 InitBuffer(&b); 742 while (in) { 743 b.used = 0; 744 while (1) { 745 buff[0] = '\0'; 746 if (!fgets(buff, BUFSIZ, in)) 747 goto cleanup; 748 AppendToBuffer(&b, buff, strlen(buff)); 749 c = &b.buff[b.used - 1]; 750 if ((*(c--) == '\n') && (b.used == 1 || *c != '\\')) 751 break; 752 } 753 if ((e = FindEntry(new, &b))) 754 fprintf(out, "%s:\t%s\n", e->tag, e->value); 755 else 756 fwrite(b.buff, 1, b.used, out); 757 } 758 cleanup: 759 for (i = 0; i < new->used; i++) { 760 e = &new->entry[i]; 761 if (e->usable) 762 fprintf(out, "%s:\t%s\n", e->tag, e->value); 763 } 764} 765 766static void _X_NORETURN _X_COLD 767Syntax(const char *errmsg) 768{ 769 if (errmsg != NULL) 770 fprintf(stderr, "%s: %s\n", ProgramName, errmsg); 771 772 fprintf(stderr, 773 "usage: %s [-options ...] [filename]\n\n" 774 "where options include:\n" 775 " -help print this help message\n" 776 " -version print the program version\n" 777 " -display host:dpy display to use\n" 778 " -all do all resources [default]\n" 779 " -global do screen-independent resources\n" 780 " -screen do screen-specific resources for one screen\n" 781 " -screens do screen-specific resources for all screens\n" 782 " -n show but don't do changes\n" 783 " -cpp filename preprocessor to use [%s]\n" 784 " -nocpp do not use a preprocessor\n" 785 " -E show preprocessor command & processed input file\n" 786 " -query query resources\n" 787 " -load load resources from file [default]\n" 788 " -override add in resources from file\n" 789 " -merge merge resources from file & sort\n" 790 " -edit filename edit resources into file\n" 791 " -backup string backup suffix for -edit [%s]\n" 792 " -symbols show preprocessor symbols\n" 793 " -remove remove resources\n" 794 " -retain avoid server reset (avoid using this)\n" 795 " -quiet don't warn about duplicates\n" 796 " -Dname[=value], -Uname, -Idirectory passed to preprocessor\n" 797 "\n" 798 "A - or no input filename represents stdin.\n", 799 ProgramName, cpp_program ? cpp_program : "", BACKUP_SUFFIX); 800 exit(1); 801} 802 803/* 804 * The following is a hack until XrmParseCommand is ready. It determines 805 * whether or not the given string is an abbreviation of the arg. 806 */ 807 808static Bool 809isabbreviation(const char *arg, const char *s, size_t minslen) 810{ 811 size_t arglen; 812 size_t slen; 813 814 /* exact match */ 815 if (!strcmp(arg, s)) 816 return (True); 817 818 arglen = strlen(arg); 819 slen = strlen(s); 820 821 /* too long or too short */ 822 if (slen >= arglen || slen < minslen) 823 return (False); 824 825 /* abbreviation */ 826 if (strncmp(arg, s, slen) == 0) 827 return (True); 828 829 /* bad */ 830 return (False); 831} 832 833static void 834addstring(String *arg, const char *s) 835{ 836 if (arg->used + strlen(s) + 1 >= arg->room) { 837 if (arg->val) 838 arg->val = realloc(arg->val, arg->room + CHUNK_SIZE); 839 else 840 arg->val = malloc(arg->room + CHUNK_SIZE); 841 if (arg->val == NULL) 842 fatal("%s: Not enough memory\n", ProgramName); 843 arg->room += CHUNK_SIZE; 844 } 845 if (arg->used) 846 strcat(arg->val, s); 847 else 848 strcpy(arg->val, s); 849 arg->used += strlen(s); 850} 851 852static void 853addescapedstring(String *arg, const char *s) 854{ 855 char copy[512], *c; 856 857 for (c = copy; *s && c < ©[sizeof(copy) - 1]; s++) { 858 switch (*s) { 859 case '"': 860 case '\'': 861 case '`': 862 case '$': 863 case '\\': 864 *c++ = '_'; 865 break; 866 default: 867 *c++ = *s; 868 } 869 } 870 *c = 0; 871 addstring(arg, copy); 872} 873 874static void 875addtokstring(String *arg, const char *s) 876{ 877 char copy[512], *c; 878 879 for (c = copy; *s && c < ©[sizeof(copy) - 1]; s++) { 880 if (!isalpha(*s) && !isdigit(*s) && *s != '_') 881 *c++ = '_'; 882 else 883 *c++ = *s; 884 } 885 *c = 0; 886 addstring(arg, copy); 887} 888 889 890int 891main(int argc, char *argv[]) 892{ 893 int i; 894 char *displayname = NULL; 895 int whichResources = RALL; 896 int retainProp = 0; 897 FILE *fp = NULL; 898 Bool need_newline; 899 900 ProgramName = argv[0]; 901 902 defines.room = defines.used = includes.room = includes.used = 0; 903 904 /* initialize the includes String struct */ 905 addstring(&includes, ""); 906 907 /* Pick the default cpp to use. This needs to be done before 908 * we parse the command line in order to honor -nocpp which sets 909 * it back to NULL. 910 */ 911 if (cpp_program == NULL) { 912 int number_of_elements 913 = (sizeof cpp_locations) / (sizeof cpp_locations[0]); 914 int j; 915 916 for (j = 0; j < number_of_elements; j++) { 917 char *end, *dup; 918 919 /* cut off arguments */ 920 dup = strdup(cpp_locations[j]); 921 end = strchr(dup, ' '); 922 if (end) 923 *end = '\0'; 924 if (access(dup, X_OK) == 0) { 925 cpp_program = cpp_locations[j]; 926 free(dup); 927 break; 928 } 929 free(dup); 930 } 931 } 932 933 /* needs to be replaced with XrmParseCommand */ 934 935 for (i = 1; i < argc; i++) { 936 char *arg = argv[i]; 937 938 if (arg[0] == '-') { 939 if (arg[1] == '\0') { 940 filename = NULL; 941 continue; 942 } 943 else if (isabbreviation("-help", arg, 2)) { 944 Syntax(NULL); 945 /* doesn't return */ 946 } 947 else if (isabbreviation("-version", arg, 2)) { 948 printf("%s\n", PACKAGE_STRING); 949 exit(0); 950 } 951 else if (isabbreviation("-display", arg, 2)) { 952 if (++i >= argc) 953 Syntax("-display requires an argument"); 954 displayname = argv[i]; 955 continue; 956 } 957 else if (isabbreviation("-geometry", arg, 3)) { 958 if (++i >= argc) 959 Syntax("-geometry requires an argument"); 960 /* ignore geometry */ 961 continue; 962 } 963 else if (isabbreviation("-cpp", arg, 2)) { 964 if (++i >= argc) 965 Syntax("-cpp requires an argument"); 966 cpp_program = argv[i]; 967 continue; 968 } 969 else if (!strcmp("-E", arg)) { 970 show_cpp = True; 971 continue; 972 } 973 else if (!strcmp("-n", arg)) { 974 dont_execute = True; 975 continue; 976 } 977 else if (isabbreviation("-nocpp", arg, 3)) { 978 cpp_program = NULL; 979 continue; 980 } 981 else if (isabbreviation("-query", arg, 2)) { 982 oper = OPQUERY; 983 continue; 984 } 985 else if (isabbreviation("-load", arg, 2)) { 986 oper = OPLOAD; 987 continue; 988 } 989 else if (isabbreviation("-merge", arg, 2)) { 990 oper = OPMERGE; 991 continue; 992 } 993 else if (isabbreviation("-override", arg, 2)) { 994 oper = OPOVERRIDE; 995 continue; 996 } 997 else if (isabbreviation("-symbols", arg, 3)) { 998 oper = OPSYMBOLS; 999 continue; 1000 } 1001 else if (isabbreviation("-remove", arg, 4)) { 1002 oper = OPREMOVE; 1003 continue; 1004 } 1005 else if (isabbreviation("-edit", arg, 2)) { 1006 if (++i >= argc) 1007 Syntax("-edit requires an argument"); 1008 oper = OPEDIT; 1009 editFile = argv[i]; 1010 continue; 1011 } 1012 else if (isabbreviation("-backup", arg, 2)) { 1013 if (++i >= argc) 1014 Syntax("-backup requires an argument"); 1015 backup_suffix = argv[i]; 1016 continue; 1017 } 1018 else if (isabbreviation("-all", arg, 2)) { 1019 whichResources = RALL; 1020 continue; 1021 } 1022 else if (isabbreviation("-global", arg, 3)) { 1023 whichResources = RGLOBAL; 1024 continue; 1025 } 1026 else if (isabbreviation("-screen", arg, 3)) { 1027 whichResources = RSCREEN; 1028 continue; 1029 } 1030 else if (!strcmp("-screens", arg)) { 1031 whichResources = RSCREENS; 1032 continue; 1033 } 1034 else if (isabbreviation("-retain", arg, 4)) { 1035 retainProp = 1; 1036 continue; 1037 } 1038 else if (isabbreviation("-quiet", arg, 2)) { 1039 quiet = True; 1040 continue; 1041 } 1042 else if (arg[1] == 'I') { 1043 addstring(&includes, " "); 1044 addescapedstring(&includes, arg); 1045 continue; 1046 } 1047 else if (arg[1] == 'U' || arg[1] == 'D') { 1048 if (num_cmd_defines < MAX_CMD_DEFINES) { 1049 cmd_defines[num_cmd_defines++] = arg; 1050 } 1051 else { 1052 fatal("%s: Too many -U/-D arguments\n", ProgramName); 1053 } 1054 continue; 1055 } 1056 else if (!strcmp("-undef", arg)) { 1057 if (num_cmd_defines < MAX_CMD_DEFINES) { 1058 cmd_defines[num_cmd_defines++] = "-undef"; 1059 } 1060 else { 1061 fatal("%s: Too many cpp arguments\n", ProgramName); 1062 } 1063 continue; 1064 } 1065 fprintf(stderr, "%s: unrecognized argument '%s'\n", 1066 ProgramName, arg); 1067 Syntax(NULL); 1068 } 1069 else if (arg[0] == '=') 1070 continue; 1071 else 1072 filename = arg; 1073 } /* end for */ 1074 1075#ifndef WIN32 1076 while ((i = open("/dev/null", O_RDONLY)) < 3) 1077 ; /* make sure later freopen won't clobber things */ 1078 (void) close(i); 1079#endif 1080 /* Open display */ 1081 if (!(dpy = XOpenDisplay(displayname))) 1082 fatal("%s: Can't open display '%s'\n", ProgramName, 1083 XDisplayName(displayname)); 1084 1085 if (whichResources == RALL && ScreenCount(dpy) == 1) 1086 whichResources = RGLOBAL; 1087 1088#ifdef PATHETICCPP 1089 if (cpp_program && 1090 (oper == OPLOAD || oper == OPMERGE || oper == OPOVERRIDE)) { 1091 need_real_defines = True; 1092#ifdef WIN32 1093 strcpy(tmpname2, "xrdbD_XXXXXX"); 1094 strcpy(tmpname3, "\\temp\\xrdbD_XXXXXX"); 1095#else 1096 strcpy(tmpname2, "/tmp/xrdbD_XXXXXX"); 1097#endif 1098 (void) mktemp(tmpname2); 1099 } 1100#endif 1101 1102 if (!filename && 1103#ifdef PATHETICCPP 1104 need_real_defines 1105#else 1106 (oper == OPLOAD || oper == OPMERGE || oper == OPOVERRIDE) && 1107 (whichResources == RALL || whichResources == RSCREENS) 1108#endif 1109 ) { 1110 char inputbuf[1024]; 1111 1112#ifdef WIN32 1113 strcpy(tmpname, "\\temp\\xrdb_XXXXXX"); 1114#else 1115 strcpy(tmpname, "/tmp/xrdb_XXXXXX"); 1116#endif 1117#ifndef HAVE_MKSTEMP 1118 (void) mktemp(tmpname); 1119 filename = tmpname; 1120 fp = fopen(filename, "w"); 1121#else 1122 { 1123 int fd = mkstemp(tmpname); 1124 1125 filename = tmpname; 1126 fp = fdopen(fd, "w"); 1127 } 1128#endif /* MKSTEMP */ 1129 if (!fp) 1130 fatal("%s: Failed to open temp file: %s\n", ProgramName, filename); 1131 while (fgets(inputbuf, sizeof(inputbuf), stdin) != NULL) 1132 fputs(inputbuf, fp); 1133 fclose(fp); 1134 } 1135 1136 DoDisplayDefines(dpy, &defines, displayname); 1137 defines_base = defines.used; 1138 need_newline = (oper == OPQUERY || oper == OPSYMBOLS || 1139 (dont_execute && oper != OPREMOVE)); 1140 InitBuffer(&buffer); 1141 if (whichResources == RGLOBAL) 1142 Process(DefaultScreen(dpy), False, True); 1143 else if (whichResources == RSCREEN) 1144 Process(DefaultScreen(dpy), True, True); 1145 else if (whichResources == RSCREENS || 1146 (oper != OPLOAD && oper != OPMERGE && oper != OPOVERRIDE)) { 1147 if (whichResources == RALL && oper != OPSYMBOLS) { 1148 if (need_newline) 1149 printf("! screen-independent resources\n"); 1150 Process(0, False, True); 1151 if (need_newline) 1152 printf("\n"); 1153 } 1154 for (i = 0; i < ScreenCount(dpy); i++) { 1155 if (need_newline) { 1156 if (oper == OPSYMBOLS) 1157 printf("# screen %d symbols\n", i); 1158 else { 1159 printf("! screen %d resources\n", i); 1160 printf("#if SCREEN_NUM == %d\n", i); 1161 } 1162 } 1163 Process(i, True, True); 1164 if (need_newline) { 1165 if (oper != OPSYMBOLS) 1166 printf("#endif\n"); 1167 if (i + 1 != ScreenCount(dpy)) 1168 printf("\n"); 1169 } 1170 } 1171 } 1172 else { 1173 Entries *dbs; 1174 1175 dbs = mallocarray(ScreenCount(dpy), sizeof(Entries)); 1176 if (dbs == NULL) 1177 fatal("%s: Can't allocate memory in %s\n", ProgramName, __func__); 1178 for (i = 0; i < ScreenCount(dpy); i++) { 1179 Process(i, True, False); 1180 dbs[i] = newDB; 1181 } 1182 InitEntries(&newDB); 1183 if (oper == OPMERGE || oper == OPOVERRIDE) 1184 GetEntriesString(&newDB, XResourceManagerString(dpy)); 1185 ShuffleEntries(&newDB, dbs, (unsigned) ScreenCount(dpy)); 1186 if (need_newline) 1187 printf("! screen-independent resources\n"); 1188 ReProcess(0, False); 1189 if (need_newline) 1190 printf("\n"); 1191 for (i = 0; i < ScreenCount(dpy); i++) { 1192 newDB = dbs[i]; 1193 if (need_newline) { 1194 printf("! screen %d resources\n", i); 1195 printf("#if SCREEN_NUM == %d\n", i); 1196 } 1197 ReProcess(i, True); 1198 if (need_newline) { 1199 printf("#endif\n"); 1200 if (i + 1 != ScreenCount(dpy)) 1201 printf("\n"); 1202 } 1203 } 1204 } 1205 1206 if (fp) 1207 unlink(filename); 1208 if (retainProp) 1209 XSetCloseDownMode(dpy, RetainPermanent); 1210 XCloseDisplay(dpy); 1211 exit(0); 1212} 1213 1214 1215static void 1216FormatEntries(Buffer *b, Entries *entries) 1217{ 1218 size_t i; 1219 1220 b->used = 0; 1221 if (!entries->used) 1222 return; 1223 if (oper == OPMERGE) 1224 qsort(entries->entry, entries->used, sizeof(Entry), CompareEntries); 1225 for (i = 0; i < entries->used; i++) { 1226 if (entries->entry[i].usable) 1227 AppendEntryToBuffer(b, &entries->entry[i]); 1228 } 1229} 1230 1231static void 1232StoreProperty(Display *display, Window root, Atom res_prop) 1233{ 1234 size_t len = buffer.used; 1235 int mode = PropModeReplace; 1236 unsigned char *buf = (unsigned char *) buffer.buff; 1237 size_t max = ((unsigned) XMaxRequestSize(display) << 2) - 28; 1238 1239 if (len > max) { 1240 XGrabServer(display); 1241 do { 1242 XChangeProperty(display, root, res_prop, XA_STRING, 8, mode, buf, 1243 (int) max); 1244 buf += max; 1245 len -= max; 1246 mode = PropModeAppend; 1247 } while (len > max); 1248 } 1249 XChangeProperty(display, root, res_prop, XA_STRING, 8, mode, buf, 1250 (int) len); 1251 if (mode != PropModeReplace) 1252 XUngrabServer(display); 1253} 1254 1255static void 1256Process(int scrno, Bool doScreen, Bool execute) 1257{ 1258 char *xdefs; 1259 Window root; 1260 Atom res_prop; 1261 FILE *input, *output; 1262 char *cmd; 1263 1264 defines.val[defines_base] = '\0'; 1265 defines.used = defines_base; 1266 buffer.used = 0; 1267 InitEntries(&newDB); 1268 DoScreenDefines(dpy, scrno, &defines); 1269 DoCmdDefines(&defines); 1270 if (doScreen) { 1271 xdefs = XScreenResourceString(ScreenOfDisplay(dpy, scrno)); 1272 root = RootWindow(dpy, scrno); 1273 res_prop = XInternAtom(dpy, SCREEN_RESOURCES, False); 1274 } 1275 else { 1276 xdefs = XResourceManagerString(dpy); 1277 root = RootWindow(dpy, 0); 1278 res_prop = XA_RESOURCE_MANAGER; 1279 } 1280 if (oper == OPSYMBOLS) { 1281 printf("%s\n", defines.val); 1282 } 1283 else if (oper == OPQUERY) { 1284 if (xdefs) 1285 printf("%s", xdefs); /* fputs broken in SunOS 4.0 */ 1286 } 1287 else if (oper == OPREMOVE) { 1288 if (xdefs) 1289 XDeleteProperty(dpy, root, res_prop); 1290 } 1291 else if (oper == OPEDIT) { 1292 char template[100], old[100]; 1293 1294 input = fopen(editFile, "r"); 1295 snprintf(template, sizeof(template), "%sXXXXXX", editFile); 1296#ifndef HAVE_MKSTEMP 1297 (void) mktemp(template); 1298 output = fopen(template, "w"); 1299#else 1300 { 1301 int fd = mkstemp(template); 1302 1303 output = fd != -1 ? fdopen(fd, "w") : NULL; 1304 } 1305#endif 1306 if (!output) 1307 fatal("%s: can't open temporary file '%s'\n", ProgramName, 1308 template); 1309 GetEntriesString(&newDB, xdefs); 1310 EditFile(&newDB, input, output); 1311 if (input) 1312 fclose(input); 1313 fclose(output); 1314 snprintf(old, sizeof(old), "%s%s", editFile, backup_suffix); 1315 if (dont_execute) { /* then write to standard out */ 1316 char buf[BUFSIZ]; 1317 size_t n; 1318 1319 output = fopen(template, "r"); 1320 if (output) { 1321 while ((n = fread(buf, 1, sizeof buf, output)) > 0) { 1322 fwrite(buf, 1, n, stdout); 1323 } 1324 fclose(output); 1325 } 1326 unlink(template); 1327 } 1328 else { 1329 rename(editFile, old); 1330 if (rename(template, editFile)) 1331 fatal("%s: can't rename file '%s' to '%s'\n", ProgramName, 1332 template, editFile); 1333 } 1334 } 1335 else { 1336 const char *cpp_addflags = ""; 1337 1338 if (oper == OPMERGE || oper == OPOVERRIDE) 1339 GetEntriesString(&newDB, xdefs); 1340 1341 /* Add -P flag only if using cpp, not another preprocessor */ 1342 if (cpp_program) { 1343 const char *cp = strstr(cpp_program, "cpp"); 1344 1345 if (cp && ((cp[3] == '\0') || cp[3] == ' ')) 1346 cpp_addflags = "-P"; 1347 } 1348#ifdef PATHETICCPP 1349 if (need_real_defines) { 1350#ifdef WIN32 1351 if (!(input = fopen(tmpname2, "w"))) 1352 fatal("%s: can't open file '%s'\n", ProgramName, tmpname2); 1353 fputs(defines.val, input); 1354 fprintf(input, "\n#include \"%s\"\n", filename); 1355 fclose(input); 1356 (void) mktemp(tmpname3); 1357 if (asprintf(&cmd, "%s %s %s %s > %s", cpp_program, cpp_addflags, 1358 includes.val, tmpname2, tmpname3) == -1) 1359 fatal("%s: Out of memory\n", ProgramName); 1360 if (show_cpp) 1361 puts(cmd); 1362 if (system(cmd) < 0) 1363 fatal("%s: cannot run '%s'\n", ProgramName, cmd); 1364 free(cmd); 1365 if (!(input = fopen(tmpname3, "r"))) 1366 fatal("%s: can't open file '%s'\n", ProgramName, tmpname3); 1367#else 1368 if (!freopen(tmpname2, "w+", stdin)) 1369 fatal("%s: can't open file '%s'\n", ProgramName, tmpname2); 1370 fputs(defines.val, stdin); 1371 fprintf(stdin, "\n#include \"%s\"\n", filename); 1372 fflush(stdin); 1373 fseek(stdin, 0, SEEK_SET); 1374 if (asprintf(&cmd, "%s %s %s", cpp_program, cpp_addflags, 1375 includes.val) == -1) 1376 fatal("%s: Out of memory\n", ProgramName); 1377 if (show_cpp) 1378 puts(cmd); 1379 if (!(input = popen(cmd, "r"))) 1380 fatal("%s: cannot run '%s'\n", ProgramName, cmd); 1381 free(cmd); 1382#endif 1383 } 1384 else { 1385#endif 1386 if (filename) { 1387 if (!freopen(filename, "r", stdin)) 1388 fatal("%s: can't open file '%s'\n", ProgramName, filename); 1389 } 1390 if (cpp_program) { 1391#ifdef WIN32 1392 (void) mktemp(tmpname3); 1393 if (asprintf(&cmd, "%s %s %s %s %s > %s", cpp_program, 1394 cpp_addflags, includes.val, defines.val, 1395 filename ? filename : "", tmpname3) == -1) 1396 fatal("%s: Out of memory\n", ProgramName); 1397 if (show_cpp) 1398 puts(cmd); 1399 if (system(cmd) < 0) 1400 fatal("%s: cannot run '%s'\n", ProgramName, cmd); 1401 free(cmd); 1402 if (!(input = fopen(tmpname3, "r"))) 1403 fatal("%s: can't open file '%s'\n", ProgramName, tmpname3); 1404#else 1405 if (asprintf(&cmd, "%s %s %s %s %s", cpp_program, 1406 cpp_addflags, includes.val, defines.val, 1407 filename ? filename : "") == -1) 1408 fatal("%s: Out of memory\n", ProgramName); 1409 if (show_cpp) 1410 puts(cmd); 1411 if (!(input = popen(cmd, "r"))) 1412 fatal("%s: cannot run '%s'\n", ProgramName, cmd); 1413 free(cmd); 1414#endif 1415 } 1416 else { 1417 input = stdin; 1418 } 1419#ifdef PATHETICCPP 1420 } 1421#endif 1422 ReadFile(&buffer, input); 1423 if (cpp_program) { 1424#ifdef WIN32 1425 fclose(input); 1426#else 1427 pclose(input); 1428#endif 1429 } 1430#ifdef PATHETICCPP 1431 if (need_real_defines) { 1432 unlink(tmpname2); 1433#ifdef WIN32 1434 if (tmpname3[strlen(tmpname3) - 1] != 'X') 1435 unlink(tmpname3); 1436#endif 1437 } 1438#endif 1439 GetEntries(&newDB, &buffer, 0); 1440 if (execute) { 1441 FormatEntries(&buffer, &newDB); 1442 if (dont_execute) { 1443 if (buffer.used > 0) { 1444 fwrite(buffer.buff, 1, buffer.used, stdout); 1445 if (buffer.buff[buffer.used - 1] != '\n') 1446 putchar('\n'); 1447 } 1448 } 1449 else if (buffer.used > 1 || !doScreen) 1450 StoreProperty(dpy, root, res_prop); 1451 else 1452 XDeleteProperty(dpy, root, res_prop); 1453 } 1454 } 1455 if (execute) 1456 FreeEntries(&newDB); 1457 if (doScreen && xdefs) 1458 XFree(xdefs); 1459} 1460 1461static void 1462ShuffleEntries(Entries *db, Entries *dbs, unsigned int num) 1463{ 1464 unsigned int *hits; 1465 unsigned int i, j, k; 1466 Entries cur, cmp; 1467 char *curtag, *curvalue; 1468 1469 hits = mallocarray(num, sizeof(int)); 1470 if (hits == NULL) 1471 fatal("%s: Can't allocate memory in %s\n", ProgramName, __func__); 1472 cur = dbs[0]; 1473 for (i = 0; i < cur.used; i++) { 1474 curtag = cur.entry[i].tag; 1475 curvalue = cur.entry[i].value; 1476 for (j = 1; j < num; j++) { 1477 cmp = dbs[j]; 1478 for (k = 0; k < cmp.used; k++) { 1479 if (cmp.entry[k].usable && 1480 !strcmp(curtag, cmp.entry[k].tag) && 1481 !strcmp(curvalue, cmp.entry[k].value)) { 1482 hits[j] = k; 1483 break; 1484 } 1485 } 1486 if (k == cmp.used) 1487 break; 1488 } 1489 if (j == num) { 1490 AddEntry(db, &cur.entry[i]); 1491 hits[0] = i; 1492 for (j = 0; j < num; j++) 1493 dbs[j].entry[hits[j]].usable = False; 1494 } 1495 } 1496 free(hits); 1497} 1498 1499static void 1500ReProcess(int scrno, Bool doScreen) 1501{ 1502 Window root; 1503 Atom res_prop; 1504 1505 FormatEntries(&buffer, &newDB); 1506 if (doScreen) { 1507 root = RootWindow(dpy, scrno); 1508 res_prop = XInternAtom(dpy, SCREEN_RESOURCES, False); 1509 } 1510 else { 1511 root = RootWindow(dpy, 0); 1512 res_prop = XA_RESOURCE_MANAGER; 1513 } 1514 if (dont_execute) { 1515 if (buffer.used > 0) { 1516 fwrite(buffer.buff, 1, buffer.used, stdout); 1517 if (buffer.buff[buffer.used - 1] != '\n') 1518 putchar('\n'); 1519 } 1520 } 1521 else { 1522 if (buffer.used > 1 || !doScreen) 1523 StoreProperty(dpy, root, res_prop); 1524 else 1525 XDeleteProperty(dpy, root, res_prop); 1526 } 1527 FreeEntries(&newDB); 1528} 1529 1530static void 1531fatal(const char *msg, ...) 1532{ 1533 va_list args; 1534 1535 if (errno != 0) 1536 perror(ProgramName); 1537 va_start(args, msg); 1538 vfprintf(stderr, msg, args); 1539 va_end(args); 1540 exit(1); 1541} 1542