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