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