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