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