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