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