home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / X / mit / clients / xrdb / xrdb.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-21  |  25.4 KB  |  1,062 lines

  1. /*
  2.  * xrdb - X resource manager database utility
  3.  *
  4.  * $XConsortium: xrdb.c,v 11.51 92/03/10 12:10:34 keith Exp $
  5.  */
  6.  
  7. /*
  8.  *              COPYRIGHT 1987, 1991
  9.  *           DIGITAL EQUIPMENT CORPORATION
  10.  *               MAYNARD, MASSACHUSETTS
  11.  *           MASSACHUSETTS INSTITUTE OF TECHNOLOGY
  12.  *               CAMBRIDGE, MASSACHUSETTS
  13.  *            ALL RIGHTS RESERVED.
  14.  *
  15.  * THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE AND
  16.  * SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT CORPORATION.
  17.  * DIGITAL MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR
  18.  * ANY PURPOSE.  IT IS SUPPLIED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
  19.  *
  20.  * IF THE SOFTWARE IS MODIFIED IN A MANNER CREATING DERIVATIVE COPYRIGHT RIGHTS,
  21.  * APPROPRIATE LEGENDS MAY BE PLACED ON THE DERIVATIVE WORK IN ADDITION TO THAT
  22.  * SET FORTH ABOVE.
  23.  *
  24.  *
  25.  * Permission to use, copy, modify, and distribute this software and its
  26.  * documentation for any purpose and without fee is hereby granted, provided
  27.  * that the above copyright notice appear in all copies and that both that
  28.  * copyright notice and this permission notice appear in supporting
  29.  * documentation, and that the name of Digital Equipment Corporation not be
  30.  * used in advertising or publicity pertaining to distribution of the software
  31.  * without specific, written prior permission.
  32.  */
  33.  
  34. /*
  35.  * this program is used to load, or dump the resource manager database
  36.  * in the server.
  37.  *
  38.  * Original Author: Jim Gettys, August 28, 1987
  39.  * Extensively Modified: Phil Karlton, January 5, 1987
  40.  * Modified a Bunch More: Bob Scheifler, February, 1991
  41.  */
  42.  
  43. #include <X11/Xlib.h>
  44. #include <X11/Xatom.h>
  45. #include <X11/Xos.h>
  46. #include <stdio.h>
  47. #include <ctype.h>
  48. #include <errno.h>
  49.  
  50. #define SCREEN_RESOURCES "SCREEN_RESOURCES"
  51.  
  52. #ifndef CPP
  53. #define CPP "/usr/lib/cpp"
  54. #endif /* CPP */
  55.  
  56. char *ProgramName;
  57. static Bool quiet = False;
  58.  
  59. #define RESOURCE_PROPERTY_NAME "RESOURCE_MANAGER"
  60. #define BACKUP_SUFFIX ".bak"        /* for editting */
  61.  
  62. #ifndef sgi
  63. extern FILE *popen();
  64. #endif
  65.  
  66. typedef struct _Entry {
  67.     char *tag, *value;
  68.     int lineno;
  69.     Bool usable;
  70. } Entry;
  71. typedef struct _Buffer {
  72.     char *buff;
  73.     int  room, used;
  74. } Buffer;
  75. typedef struct _Entries {
  76.     Entry *entry;
  77.     int   room, used;
  78. } Entries;
  79.  
  80. #define INIT_BUFFER_SIZE 10000
  81. #define INIT_ENTRY_SIZE 500
  82.  
  83. #if defined(USG) && !defined(CRAY) && !defined(MOTOROLA)
  84. int rename (from, to)
  85.     char *from, *to;
  86. {
  87.     (void) unlink (to);
  88.     if (link (from, to) == 0) {
  89.         unlink (from);
  90.         return 0;
  91.     } else {
  92.         return -1;
  93.     }
  94. }
  95. #endif
  96.  
  97. void InitBuffer(b)
  98.     Buffer *b;
  99. {
  100.     b->room = INIT_BUFFER_SIZE;
  101.     b->used = 0;
  102.     b->buff = (char *)malloc(INIT_BUFFER_SIZE*sizeof(char));
  103. }
  104.  
  105. void FreeBuffer(b)
  106.     Buffer *b;
  107. {
  108.     free(b->buff);
  109. }
  110.  
  111. void AppendToBuffer(b, str, len)
  112.     register Buffer *b;
  113.     char *str;
  114.     register int len;
  115. {
  116.     while (b->used + len > b->room) {
  117.     b->buff = (char *)realloc(b->buff, 2*b->room*(sizeof(char)));
  118.     b->room *= 2;
  119.     }
  120.     strncpy(b->buff + b->used, str, len);
  121.     b->used += len;
  122. }
  123.  
  124. void InitEntries(e)
  125.     Entries *e;
  126. {
  127.     e->room = INIT_ENTRY_SIZE;
  128.     e->used = 0;
  129.     e->entry = (Entry *)malloc(INIT_ENTRY_SIZE*sizeof(Entry));
  130. }
  131.  
  132. void FreeEntries(e)
  133.     Entries *e;
  134. {
  135.     register int i;
  136.  
  137.     for (i = 0; i < e->used; i++) {
  138.     if (e->entry[i].usable) {
  139.         free(e->entry[i].tag);
  140.         free(e->entry[i].value);
  141.     }
  142.     }
  143.     free((char *)e->entry);
  144. }
  145.  
  146. void AddEntry(e, entry)
  147.     register Entries *e;
  148.     Entry *entry;
  149. {
  150.     register int n;
  151.  
  152.     for (n = 0; n < e->used; n++) {
  153.     if (!strcmp(e->entry[n].tag, entry->tag)) {
  154.         /* overwrite old entry */
  155.         if (!quiet) {
  156.         fprintf (stderr, 
  157.              "%s:  \"%s\" on line %d overrides entry on line %d\n",
  158.              ProgramName, entry->tag, entry->lineno, 
  159.              e->entry[n].lineno);
  160.         }
  161.         e->entry[n] = *entry;
  162.         return ;  /* ok to leave, now there's only one of each tag in db */
  163.     }
  164.     }
  165.  
  166.     if (e->used == e->room) {
  167.     e->entry = (Entry *)realloc((char *)e->entry,
  168.                     2*e->room*(sizeof(Entry)));
  169.     e->room *= 2;
  170.     }
  171.     entry->usable = True;
  172.     e->entry[e->used++] = *entry;
  173. }
  174.  
  175.  
  176. int CompareEntries(e1, e2)
  177.     Entry *e1, *e2;
  178. {
  179.     return strcmp(e1->tag, e2->tag);
  180. }
  181.  
  182. void AppendEntryToBuffer(buffer, entry)
  183.     register Buffer *buffer;
  184.     Entry *entry;
  185. {
  186.     AppendToBuffer(buffer, entry->tag, strlen(entry->tag));
  187.     AppendToBuffer(buffer, ":\t", 2);
  188.     AppendToBuffer(buffer, entry->value, strlen(entry->value));
  189.     AppendToBuffer(buffer, "\n", 1);
  190. }
  191.  
  192. /*
  193.  * Return the position of the first unescaped occurrence of dest in string.
  194.  * If lines is non-null, return the number of newlines skipped over.
  195.  */
  196. char *FindFirst(string, dest, lines)
  197.     register char *string;
  198.     register char dest;
  199.     register int *lines;    /* RETURN */
  200. {
  201.     if (lines)
  202.     *lines = 0;
  203.     for (;;) {
  204.     if (*string == '\0')
  205.         return NULL;
  206.     if (*string == '\\') {
  207.         if (*++string == '\0')
  208.         return NULL;
  209.     } else if (*string == dest)
  210.         return string;
  211.     if (*string == '\n'  &&  lines)
  212.         (*lines)++;
  213.     string++;
  214.     }
  215. }
  216.  
  217. void GetEntries(entries, buff, dosort)
  218.     register Entries *entries;
  219.     Buffer *buff;
  220.     int dosort;
  221. {
  222.     register char *line, *colon, *temp, *str;
  223.     Entry entry;
  224.     register int length;
  225.     int lineno = 0;
  226.     int lines_skipped;
  227.  
  228.     str = buff->buff;
  229.     if (!str) return;
  230.     for ( ; str < buff->buff + buff->used;
  231.       str = line + 1, lineno += lines_skipped) {
  232.     line = FindFirst(str, '\n', &lines_skipped);
  233.     lineno++;
  234.     if (!line)
  235.         break; 
  236.     if (*str == '!')
  237.         continue;
  238.     if (*str == '\n')
  239.         continue;
  240.     if (*str == '#') {
  241.         int dummy;
  242.         if (sscanf (str, "# %d", &dummy) == 1) lineno = dummy - 1;
  243.         continue;
  244.     }
  245.     for (temp = str; 
  246.          *temp && *temp != '\n' && isascii(*temp) && isspace(*temp); 
  247.          temp++) ;
  248.     if (!*temp || *temp == '\n') continue;
  249.  
  250.     colon = FindFirst(str, ':', NULL);
  251.     if (!colon)
  252.         break;
  253.     if (colon > line) {
  254.         line[0] = '\0';
  255.         fprintf (stderr, 
  256.              "%s:  colon missing on line %d, ignoring entry \"%s\"\n",
  257.              ProgramName, lineno, str);
  258.         continue;
  259.     }
  260.  
  261.     /* strip leading and trailing blanks from name and store result */
  262.     while (*str == ' ' || *str == '\t')
  263.         str++;
  264.     length = colon - str;
  265.     while (length && (str[length-1] == ' ' || str[length-1] == '\t'))
  266.         length--;
  267.     temp = (char *)malloc(length + 1);
  268.     strncpy(temp, str, length);
  269.     temp[length] = '\0';
  270.     entry.tag = temp;
  271.  
  272.     /* strip leading and trailing blanks from value and store result */
  273.     colon++;
  274.     while (*colon == ' ' || *colon == '\t')
  275.         colon++;
  276.     length = line - colon;
  277.     temp = (char *)malloc(length + 1);
  278.     strncpy(temp, colon, length);
  279.     temp[length] = '\0';
  280.     entry.value = temp;
  281.     entry.lineno = lineno;
  282.  
  283.     AddEntry(entries, &entry);
  284.     }
  285.     if (dosort && (entries->used > 0))
  286.     qsort(entries->entry, entries->used, sizeof(Entry), CompareEntries);
  287. }
  288.  
  289. int MergeEntries(buffer, new, old)
  290.     Entries *new, *old;
  291.     Buffer *buffer;
  292. {
  293.     int n, o, cmp;
  294.  
  295.     n = o = 0;
  296.     while ((n < new->used) && (o < old->used)) {
  297.     cmp = strcmp(new->entry[n].tag, old->entry[o].tag);
  298.     if (cmp > 0)
  299.         AppendEntryToBuffer(buffer, &old->entry[o++]);
  300.     else {
  301.         AppendEntryToBuffer(buffer, &new->entry[n++]);
  302.         if (cmp == 0)
  303.         o++;
  304.     }
  305.     }
  306.     while (n < new->used)
  307.     AppendEntryToBuffer(buffer, &new->entry[n++]);
  308.     while (o < old->used)
  309.     AppendEntryToBuffer(buffer, &old->entry[o++]);
  310.     AppendToBuffer(buffer, "", 1);
  311. }
  312.  
  313. void ReadFile(buffer, input)
  314.     register Buffer *buffer;
  315.     FILE *input;
  316. {
  317.          char    buf[BUFSIZ];
  318.     register int    bytes;
  319.  
  320.     buffer->used = 0;
  321.     while (!feof(input) && (bytes = fread(buf, 1, BUFSIZ, input)) > 0) {
  322.     AppendToBuffer(buffer, buf, bytes);
  323.     }
  324.     AppendToBuffer(buffer, "", 1);
  325. }
  326.  
  327. AddDef(buff, title, value)
  328.     char *buff, *title, *value;
  329. {
  330.     strcat(buff, " -D");
  331.     strcat(buff, title);
  332.     if (value && (value[0] != '\0')) {
  333.     strcat(buff, "=");
  334.     strcat(buff, value);
  335.     }
  336. }
  337.  
  338. AddDefQ(buff, title, value)
  339.     char *buff, *title, *value;
  340. {
  341.     strcat(buff, " -D");
  342.     strcat(buff, title);
  343.     if (value && (value[0] != '\0')) {
  344.     strcat(buff, "=\"");
  345.     strcat(buff, value);
  346.     strcat(buff, "\"");
  347.     }
  348. }
  349.  
  350. AddNum(buff, title, value)
  351.     char *buff, *title;
  352.     int value;
  353. {
  354.     char num[20];
  355.     sprintf(num, "%d", value);
  356.     AddDef(buff, title, num);
  357. }
  358.  
  359. AddSimpleDef(buff, title)
  360.     char *buff, *title;
  361. {
  362.     strcat(buff, " -D");
  363.     strcat(buff, title);
  364. }
  365.  
  366. int Resolution(pixels, mm)
  367.     int pixels, mm;
  368. {
  369.     return ((pixels * 100000 / mm) + 50) / 100;
  370. }
  371.  
  372.  
  373. void
  374. DoDisplayDefines(display, defs, host)
  375.     Display *display;
  376.     register char *defs;
  377.     char *host;
  378. {
  379. #define MAXHOSTNAME 255
  380.     char client[MAXHOSTNAME], server[MAXHOSTNAME], *colon;
  381.     
  382.     XmuGetHostname(client, MAXHOSTNAME);
  383.     strcpy(server, XDisplayName(host));
  384.     colon = index(server, ':');
  385.     if (colon)
  386.     *colon = '\0';
  387.     if (server[0] == '\0')    /* must be connected to :0 */
  388.     strcpy(server, client);
  389.     AddDef(defs, "HOST", server); /* R3 compatibility */
  390.     AddDef(defs, "SERVERHOST", server);
  391.     AddDef(defs, "CLIENTHOST", client);
  392.     AddNum(defs, "VERSION", ProtocolVersion(display));
  393.     AddNum(defs, "REVISION", ProtocolRevision(display));
  394.     AddDefQ(defs, "VENDOR", ServerVendor(display));
  395.     AddNum(defs, "RELEASE", VendorRelease(display));
  396. }
  397.  
  398. /*
  399.  * It would probably be best to enumerate all of the screens/visuals
  400.  * rather than just using the defaults. However, most of the current
  401.  * servers only have one screen/visual.
  402.  */
  403. void
  404. DoScreenDefines(display, scrno, defs)
  405.     Display *display;
  406.     int scrno;
  407.     register char *defs;
  408. {
  409.     Screen *screen;
  410.     Visual *visual;
  411.     
  412.     screen = ScreenOfDisplay(display, scrno);
  413.     visual = DefaultVisualOfScreen(screen);
  414.     AddNum(defs, "WIDTH", screen->width);
  415.     AddNum(defs, "HEIGHT", screen->height);
  416.     AddNum(defs, "X_RESOLUTION", Resolution(screen->width,screen->mwidth));
  417.     AddNum(defs, "Y_RESOLUTION", Resolution(screen->height,screen->mheight));
  418.     AddNum(defs, "PLANES", DisplayPlanes(display, scrno));
  419.     AddNum(defs, "BITS_PER_RGB", visual->bits_per_rgb);
  420.     switch(visual->class) {
  421.     case StaticGray:
  422.         AddDef(defs, "CLASS", "StaticGray");
  423.         break;
  424.     case GrayScale:
  425.         AddDef(defs, "CLASS", "GrayScale");
  426.         break;
  427.     case StaticColor:
  428.         AddDef(defs, "CLASS", "StaticColor");
  429.         AddSimpleDef(defs, "COLOR");
  430.         break;
  431.     case PseudoColor:
  432.         AddDef(defs, "CLASS", "PseudoColor");
  433.         AddSimpleDef(defs, "COLOR");
  434.         break;
  435.     case TrueColor:
  436.         AddDef(defs, "CLASS", "TrueColor");
  437.         AddSimpleDef(defs, "COLOR");
  438.         break;
  439.     case DirectColor:
  440.         AddDef(defs, "CLASS", "DirectColor");
  441.         AddSimpleDef(defs, "COLOR");
  442.         break;
  443.     default:
  444.         fatal("%s: unexpected visual class=%d\n",
  445.           ProgramName, visual->class);
  446.     }
  447. }
  448.  
  449. Entry *FindEntry(db, b)
  450.     register Entries *db;
  451.     Buffer *b;
  452. {
  453.     int i;
  454.     register Entry *e;
  455.     Entries phoney;
  456.     Entry entry;
  457.  
  458.     entry.usable = False;
  459.     entry.tag = NULL;
  460.     entry.value = NULL;
  461.     phoney.used = 0;
  462.     phoney.room = 1;
  463.     phoney.entry = &entry;
  464.     GetEntries(&phoney, b, 0);
  465.     if (phoney.used < 1)
  466.     return NULL;
  467.     for (i = 0; i < db->used; i++) {
  468.     e = &db->entry[i];
  469.     if (!e->usable)
  470.         continue;
  471.     if (strcmp(e->tag, entry.tag))
  472.         continue;
  473.     e->usable = False;
  474.     if (strcmp(e->value, entry.value))
  475.         return e;
  476.     return NULL;
  477.     }
  478.     return NULL;
  479. }
  480.  
  481. void EditFile(new, in, out)
  482.     register Entries *new;
  483.     FILE *in, *out;
  484. {
  485.     Buffer b;
  486.     char buff[BUFSIZ];
  487.     register Entry *e;
  488.     register char *c;
  489.     int i;
  490.  
  491.     InitBuffer(&b);
  492.     for (;;) {
  493.     b.used = 0;
  494.     while (1) {
  495.         buff[0] ='\0';
  496.         if (!fgets(buff, BUFSIZ, in))
  497.         goto cleanup;
  498.         AppendToBuffer(&b, buff, strlen(buff));
  499.         c = &b.buff[b.used - 1];
  500.         if ((*(c--) == '\n') && (b.used == 1 || *c != '\\'))
  501.         break;
  502.     }
  503.     if (e = FindEntry(new, &b))
  504.         fprintf(out, "%s:\t%s\n", e->tag, e->value);
  505.     else
  506.         fwrite(b.buff, 1, b.used, out);
  507.     }
  508. cleanup:
  509.     for (i = 0; i < new->used; i++) {
  510.     e = &new->entry[i];
  511.     if (e->usable)
  512.         fprintf(out, "%s:\t%s\n", e->tag, e->value);
  513.     }
  514. }
  515.  
  516. void Syntax ()
  517. {
  518.     fprintf (stderr, 
  519.          "usage:  %s [-options ...] [filename]\n\n",
  520.          ProgramName);
  521.     fprintf (stderr, 
  522.          "where options include:\n");
  523.     fprintf (stderr, 
  524.          " -display host:dpy   display to use\n");
  525.     fprintf (stderr, 
  526.          " -all                do all resources [default]\n");
  527.     fprintf (stderr, 
  528.          " -global             do screen-independent resources\n");
  529.     fprintf (stderr, 
  530.          " -screen             do screen-specific resources for one screen\n");
  531.     fprintf (stderr, 
  532.          " -screens            do screen-specific resources for all screens\n");
  533.     fprintf (stderr,
  534.          " -n                  show but don't do changes\n");
  535.     fprintf (stderr, 
  536.          " -cpp filename       preprocessor to use [%s]\n",
  537.          CPP);
  538.     fprintf (stderr, 
  539.          " -nocpp              do not use a preprocessor\n");
  540.     fprintf (stderr, 
  541.          " -query              query resources\n");
  542.     fprintf (stderr,
  543.          " -load               load resources from file [default]\n");
  544.     fprintf (stderr, 
  545.          " -merge              merge resources from file\n");
  546.     fprintf (stderr, 
  547.          " -edit filename      edit resources into file\n");
  548.     fprintf (stderr, 
  549.          " -backup string      backup suffix for -edit [%s]\n",
  550.          BACKUP_SUFFIX);
  551.     fprintf (stderr, 
  552.          " -symbols            show preprocessor symbols\n");
  553.     fprintf (stderr, 
  554.          " -remove             remove resources\n");
  555.     fprintf (stderr, 
  556.          " -retain             avoid server reset (avoid using this)\n");
  557.     fprintf (stderr,
  558.          " -quiet              don't warn about duplicates\n");
  559.     fprintf (stderr, 
  560.          " -Dname[=value], -Uname, -Idirectory    %s\n",
  561.          "passed to preprocessor");
  562.     fprintf (stderr, 
  563.          "\n");
  564.     fprintf (stderr,
  565.          "A - or no input filename represents stdin.\n");  
  566.     exit (1);
  567. }
  568.  
  569. /*
  570.  * The following is a hack until XrmParseCommand is ready.  It determines
  571.  * whether or not the given string is an abbreviation of the arg.
  572.  */
  573.  
  574. static Bool isabbreviation (arg, s, minslen)
  575.     char *arg;
  576.     char *s;
  577.     int minslen;
  578. {
  579.     int arglen;
  580.     int slen;
  581.  
  582.     /* exact match */
  583.     if (!strcmp (arg, s)) return (True);
  584.  
  585.     arglen = strlen (arg);
  586.     slen = strlen (s);
  587.  
  588.     /* too long or too short */
  589.     if (slen >= arglen || slen < minslen) return (False);
  590.  
  591.     /* abbreviation */
  592.     if (strncmp (arg, s, slen) == 0) return (True);
  593.  
  594.     /* bad */
  595.     return (False);
  596. }
  597.  
  598. #define RALL 0
  599. #define RGLOBAL 1
  600. #define RSCREEN 2
  601. #define RSCREENS 3
  602.  
  603. #define OPSYMBOLS 0
  604. #define OPQUERY 1
  605. #define OPREMOVE 2
  606. #define OPEDIT 3
  607. #define OPLOAD 4
  608. #define OPMERGE 5
  609.  
  610. char tmpname[32];
  611. char *filename = NULL;
  612. int oper = OPLOAD;
  613. char *editFile = NULL;
  614. char *cpp_program = CPP;
  615. char *backup_suffix = BACKUP_SUFFIX;
  616. Bool dont_execute = False;
  617. char defines[BUFSIZ];
  618. int defines_base;
  619. Display *dpy;
  620. Buffer buffer;
  621. Entries newDB;
  622.  
  623. main (argc, argv)
  624.     int argc;
  625.     char **argv;
  626. {
  627.     int i;
  628.     char *displayname = NULL;
  629.     int whichResources = RALL;
  630.     int retainProp = 0;
  631.     FILE *fp = NULL;
  632.     Bool need_newline;
  633.  
  634.     ProgramName = argv[0];
  635.  
  636.     defines[0] = '\0';
  637.  
  638.     /* needs to be replaced with XrmParseCommand */
  639.  
  640.     for (i = 1; i < argc; i++) {
  641.     char *arg = argv[i];
  642.  
  643.     if (arg[0] == '-') {
  644.         if (arg[1] == '\0') {
  645.         filename = NULL;
  646.         continue;
  647.         } else if (isabbreviation ("-help", arg, 2)) {
  648.         Syntax ();
  649.         /* doesn't return */
  650.         } else if (isabbreviation ("-display", arg, 2)) {
  651.         if (++i >= argc) Syntax ();
  652.         displayname = argv[i];
  653.         continue;
  654.         } else if (isabbreviation ("-geometry", arg, 3)) {
  655.         if (++i >= argc) Syntax ();
  656.         /* ignore geometry */
  657.         continue;
  658.         } else if (isabbreviation ("-cpp", arg, 2)) {
  659.         if (++i >= argc) Syntax ();
  660.         cpp_program = argv[i];
  661.         continue;
  662.         } else if (!strcmp ("-n", arg)) {
  663.         dont_execute = True;
  664.         continue;
  665.         } else if (isabbreviation ("-nocpp", arg, 3)) {
  666.         cpp_program = NULL;
  667.         continue;
  668.         } else if (isabbreviation ("-query", arg, 2)) {
  669.         oper = OPQUERY;
  670.         continue;
  671.         } else if (isabbreviation ("-load", arg, 2)) {
  672.         oper = OPLOAD;
  673.         continue;
  674.         } else if (isabbreviation ("-merge", arg, 2)) {
  675.         oper = OPMERGE;
  676.         continue;
  677.         } else if (isabbreviation ("-symbols", arg, 3)) {
  678.         oper = OPSYMBOLS;
  679.         continue;
  680.         } else if (isabbreviation ("-remove", arg, 4)) {
  681.         oper = OPREMOVE;
  682.         continue;
  683.         } else if (isabbreviation ("-edit", arg, 2)) {
  684.         if (++i >= argc) Syntax ();
  685.         oper = OPEDIT;
  686.         editFile = argv[i];
  687.         continue;
  688.         } else if (isabbreviation ("-backup", arg, 2)) {
  689.         if (++i >= argc) Syntax ();
  690.         backup_suffix = argv[i];
  691.         continue;
  692.         } else if (isabbreviation ("-all", arg, 2)) {
  693.         whichResources = RALL;
  694.         continue;
  695.         } else if (isabbreviation ("-global", arg, 3)) {
  696.         whichResources = RGLOBAL;
  697.         continue;
  698.         } else if (isabbreviation ("-screen", arg, 3)) {
  699.         whichResources = RSCREEN;
  700.         continue;
  701.         } else if (!strcmp ("-screens", arg)) {
  702.         whichResources = RSCREENS;
  703.         continue;
  704.         } else if (isabbreviation ("-retain", arg, 4)) {
  705.         retainProp = 1;
  706.         continue;
  707.         } else if (isabbreviation ("-quiet", arg, 2)) {
  708.         quiet = True;
  709.         continue;
  710.         } else if (arg[1] == 'I' || arg[1] == 'U' || arg[1] == 'D') {
  711.         strcat(defines, " \"");
  712.         strcat(defines, arg);
  713.         strcat(defines, "\"");
  714.         continue;
  715.         }
  716.         Syntax ();
  717.     } else if (arg[0] == '=') 
  718.         continue;
  719.     else
  720.         filename = arg;
  721.     }                            /* end for */
  722.  
  723.     /* Open display  */
  724.     if (!(dpy = XOpenDisplay (displayname)))
  725.     fatal("%s: Can't open display '%s'\n", ProgramName,
  726.          XDisplayName (displayname));
  727.  
  728.     if (whichResources == RALL && ScreenCount(dpy) == 1)
  729.     whichResources = RGLOBAL;
  730.     DoDisplayDefines(dpy, defines, displayname);
  731.     defines_base = strlen(defines);
  732.  
  733.     if (!filename &&
  734.     (oper == OPLOAD || oper == OPMERGE) &&
  735.     (whichResources == RALL || whichResources == RSCREENS)) {
  736.     strcpy(tmpname, "/tmp/xrdb_XXXXXX");
  737.     (void) mktemp(tmpname);
  738.     filename = tmpname;
  739.     fp = fopen(filename, "w");
  740.     if (!fp)
  741.         fatal("%s: Failed to open temp file: %s\n", ProgramName,
  742.           filename);
  743.     while ((i = getc(stdin)) != EOF)
  744.         putc(i, fp);
  745.     fclose(fp);
  746.     }
  747.     
  748.     need_newline = (oper == OPQUERY || oper == OPSYMBOLS ||
  749.             (dont_execute && oper != OPREMOVE));
  750.     InitBuffer(&buffer);
  751.     if (whichResources == RGLOBAL)
  752.     Process(DefaultScreen(dpy), False, True);
  753.     else if (whichResources == RSCREEN)
  754.     Process(DefaultScreen(dpy), True, True);
  755.     else if (whichResources == RSCREENS ||
  756.          (oper != OPLOAD && oper != OPMERGE)) {
  757.     if (whichResources == RALL && oper != OPSYMBOLS) {
  758.         if (need_newline)
  759.         printf("! screen-independent resources\n");
  760.         Process(0, False, True);
  761.         if (need_newline)
  762.         printf("\n");
  763.     }
  764.     for (i = 0; i < ScreenCount(dpy); i++) {
  765.         if (need_newline) {
  766.         if (oper == OPSYMBOLS)
  767.             printf("# screen %d symbols\n", i);
  768.         else
  769.             printf("! screen %d resources\n", i);
  770.         }
  771.         Process(i, True, True);
  772.         if (need_newline && i+1 != ScreenCount(dpy))
  773.         printf("\n");
  774.     }
  775.     }
  776.     else {
  777.     Entries *dbs;
  778.  
  779.     dbs = (Entries *)malloc(ScreenCount(dpy) * sizeof(Entries));
  780.     for (i = 0; i < ScreenCount(dpy); i++) {
  781.         Process(i, True, False);
  782.         dbs[i] = newDB;
  783.     }
  784.     InitEntries(&newDB);
  785.     ShuffleEntries(&newDB, dbs, ScreenCount(dpy));
  786.     if (need_newline)
  787.         printf("! screen-independent resources\n");
  788.     ReProcess(0, False);
  789.     if (need_newline)
  790.         printf("\n");
  791.     for (i = 0; i < ScreenCount(dpy); i++) {
  792.         newDB = dbs[i];
  793.         if (need_newline)
  794.         printf("! screen %d resources\n", i);
  795.         ReProcess(i, True);
  796.         if (need_newline && i+1 != ScreenCount(dpy))
  797.         printf("\n");
  798.     }
  799.     }
  800.  
  801.     if (fp)
  802.     unlink(filename);
  803.     if (retainProp)
  804.     XSetCloseDownMode(dpy, RetainPermanent);
  805.     XCloseDisplay(dpy);
  806.     exit (0);
  807. }
  808.  
  809. StoreProperty(dpy, root, res_prop)
  810.     Display *dpy;
  811.     Window root;
  812.     Atom res_prop;
  813. {
  814.     int len = buffer.used;
  815.     int mode = PropModeReplace;
  816.     unsigned char *buf = (unsigned char *)buffer.buff;
  817.     int max = (XMaxRequestSize(dpy) << 2) - 28;
  818.  
  819.     if (len > max) {
  820.     XGrabServer(dpy);
  821.     do {
  822.         XChangeProperty(dpy, root, res_prop, XA_STRING, 8, mode, buf, max);
  823.         buf += max;
  824.         len -= max;
  825.         mode = PropModeAppend;
  826.     } while (len > max);
  827.     }
  828.     XChangeProperty(dpy, root, res_prop, XA_STRING, 8, mode, buf, len);
  829.     if (mode != PropModeReplace)
  830.     XUngrabServer(dpy);
  831. }
  832.  
  833. Process(scrno, doScreen, execute)
  834.     int scrno;
  835.     Bool doScreen;
  836.     Bool execute;
  837. {
  838.     char *xdefs;
  839.     Window root;
  840.     Atom res_prop;
  841.     FILE *input, *output;
  842.     char cmd[BUFSIZ];
  843.     Entries oldDB;
  844.  
  845.     defines[defines_base] = '\0';
  846.     buffer.used = 0;
  847.     InitEntries(&newDB);
  848.     InitEntries(&oldDB);
  849.     DoScreenDefines(dpy, scrno, defines);
  850.     if (doScreen) {
  851.     xdefs = XScreenResourceString (ScreenOfDisplay(dpy, scrno));
  852.     root = RootWindow(dpy, scrno);
  853.     res_prop = XInternAtom(dpy, SCREEN_RESOURCES, False);
  854.     } else {
  855.     xdefs = XResourceManagerString (dpy);
  856.     root = RootWindow(dpy, 0);
  857.     res_prop = XA_RESOURCE_MANAGER;
  858.     }
  859.     if (oper == OPSYMBOLS) {
  860.     printf ("%s\n", defines);
  861.     } else if (oper == OPQUERY) {
  862.     if (xdefs)
  863.         printf ("%s", xdefs);    /* fputs broken in SunOS 4.0 */
  864.     } else if (oper == OPREMOVE) {
  865.     if (xdefs)
  866.         XDeleteProperty(dpy, root, res_prop);
  867.     } else if (oper == OPEDIT) {
  868.     char template[100], old[100];
  869.     char *saveBuff;
  870.  
  871.     input = fopen(editFile, "r");
  872.     if (!input) {
  873.         input = fopen (editFile, "w");
  874.         if (!input) {
  875.         fatal ("%s:  unable to create file '%s' for editing\n",
  876.                ProgramName, editFile);
  877.         /* doesn't return */
  878.         }
  879.         (void) fclose (input);
  880.         input = fopen (editFile, "r");
  881.         if (!input) {
  882.         fatal ("%s:  unable to open file '%s' for editing\n",
  883.                ProgramName, editFile);
  884.         /* doesn't return */
  885.         }
  886.     }
  887.     strcpy(template, editFile);
  888.     strcat(template, "XXXXXX");
  889.     (void) mktemp(template);
  890.     output = fopen(template, "w");
  891.     if (!output)
  892.         fatal("%s: can't open temporary file '%s'\n", ProgramName, template);
  893.     saveBuff = buffer.buff;
  894.     buffer.used = (xdefs ? strlen(xdefs) : 0);
  895.     buffer.buff = xdefs;
  896.     buffer.room = buffer.used;
  897.     GetEntries(&newDB, &buffer, 0);
  898.     buffer.buff = saveBuff;
  899.     EditFile(&newDB, input, output);
  900.     fclose(input);
  901.     fclose(output);
  902.     strcpy(old, editFile);
  903.     strcat(old, backup_suffix);
  904.     if (dont_execute) {        /* then write to standard out */
  905.         char buf[BUFSIZ];
  906.         int n;
  907.  
  908.         output = fopen (template, "r");
  909.         if (output) {
  910.         while ((n = fread (buf, 1, sizeof buf, output)) > 0) {
  911.             fwrite (buf, 1, n, stdout);
  912.         }
  913.         fclose (output);
  914.         }
  915.         unlink (template);
  916.     } else {
  917.         rename (editFile, old);
  918.         rename (template, editFile);
  919.     }
  920.     } else {
  921.     if (filename) {
  922.         if (!freopen (filename, "r", stdin))
  923.         fatal("%s: can't open file '%s'\n", ProgramName, filename);
  924.     }
  925.     if (cpp_program) {
  926.         sprintf(cmd, "%s %s", cpp_program, defines);
  927.         if (!(input = popen(cmd, "r")))
  928.         fatal("%s: cannot run '%s'\n", ProgramName, cmd);
  929.     } else {
  930.         input = stdin;
  931.     }
  932.     ReadFile(&buffer, input);
  933.     if (cpp_program)
  934.         pclose(input);
  935.     GetEntries(&newDB, &buffer, oper == OPMERGE);
  936.     if (oper == OPMERGE && xdefs) {
  937.         char *saveBuff = buffer.buff;
  938.         buffer.used = strlen(xdefs);
  939.         buffer.buff = xdefs;
  940.         GetEntries(&oldDB, &buffer, 1);
  941.         buffer.buff = saveBuff;
  942.     } else
  943.         oldDB.used = 0;
  944.     buffer.used = 0;
  945.     MergeEntries(&buffer, &newDB, &oldDB);
  946.     if (dont_execute && execute) {
  947.         if (buffer.used > 0) {
  948.         fwrite (buffer.buff, 1, buffer.used, stdout);
  949.         if (buffer.buff[buffer.used - 1] != '\n') putchar ('\n');
  950.         }
  951.     } else if (execute) {
  952.         if (buffer.used > 1 || !doScreen)
  953.         StoreProperty (dpy, root, res_prop);
  954.         else
  955.         XDeleteProperty (dpy, root, res_prop);
  956.     }
  957.     }
  958.     if (execute)
  959.     FreeEntries(&newDB);
  960.     FreeEntries(&oldDB);
  961.     if (doScreen && xdefs)
  962.     XFree(xdefs);
  963. }
  964.  
  965. ShuffleEntries(db, dbs, num)
  966.     Entries *db;
  967.     Entries *dbs;
  968.     int num;
  969. {
  970.     int *hits;
  971.     register int i, j, k;
  972.     Entries cur, cmp;
  973.     char *curtag, *curvalue;
  974.  
  975.     hits = (int *)malloc(num * sizeof(int));
  976.     cur = dbs[0];
  977.     for (i = 0; i < cur.used; i++) {
  978.     curtag = cur.entry[i].tag;
  979.     curvalue = cur.entry[i].value;
  980.     for (j = 1; j < num; j++) {
  981.         cmp = dbs[j];
  982.         for (k = 0; k < cmp.used; k++) {
  983.         if (cmp.entry[k].usable &&
  984.             !strcmp(curtag, cmp.entry[k].tag) &&
  985.             !strcmp(curvalue, cmp.entry[k].value))
  986.         {
  987.             hits[j] = k;
  988.             break;
  989.         }
  990.         }
  991.         if (k == cmp.used)
  992.         break;
  993.     }
  994.     if (j == num) {
  995.         AddEntry(db, &cur.entry[i]);
  996.         hits[0] = i;
  997.         for (j = 0; j < num; j++)
  998.         dbs[j].entry[hits[j]].usable = False;
  999.     }
  1000.     }
  1001.     free((char *)hits);
  1002. }
  1003.  
  1004. ReProcess(scrno, doScreen)
  1005.     int scrno;
  1006.     Bool doScreen;
  1007. {
  1008.     Window root;
  1009.     Atom res_prop;
  1010.     register int i;
  1011.  
  1012.     if (!doScreen && oper == OPMERGE && XResourceManagerString(dpy)) {
  1013.     char *saveBuff = buffer.buff;
  1014.     Entries oldDB;
  1015.     InitEntries(&oldDB);
  1016.     buffer.buff = XResourceManagerString(dpy);
  1017.     buffer.used = strlen(buffer.buff);
  1018.     GetEntries(&oldDB, &buffer, 1);
  1019.     buffer.buff = saveBuff;
  1020.     buffer.used = 0;
  1021.     MergeEntries(&buffer, &newDB, &oldDB);
  1022.     FreeEntries(&oldDB);
  1023.     } else {
  1024.     buffer.used = 0;
  1025.     for (i = 0; i < newDB.used; i++) {
  1026.         if (newDB.entry[i].usable)
  1027.         AppendEntryToBuffer(&buffer, &newDB.entry[i]);
  1028.     }
  1029.     }
  1030.     if (doScreen) {
  1031.     root = RootWindow(dpy, scrno);
  1032.     res_prop = XInternAtom(dpy, SCREEN_RESOURCES, False);
  1033.     } else {
  1034.     root = RootWindow(dpy, 0);
  1035.     res_prop = XA_RESOURCE_MANAGER;
  1036.     }
  1037.     if (dont_execute) {
  1038.     if (buffer.used > 0) {
  1039.         fwrite (buffer.buff, 1, buffer.used, stdout);
  1040.         if (buffer.buff[buffer.used - 1] != '\n') putchar ('\n');
  1041.     }
  1042.     } else {
  1043.     if (buffer.used > 1 || !doScreen)
  1044.         StoreProperty (dpy, root, res_prop);
  1045.     else
  1046.         XDeleteProperty (dpy, root, res_prop);
  1047.     }
  1048.     FreeEntries(&newDB);
  1049. }
  1050.  
  1051. fatal(msg, prog, x1, x2, x3, x4, x5)
  1052.     char *msg, *prog;
  1053.     int x1, x2, x3, x4, x5;
  1054. {
  1055.     extern int errno;
  1056.  
  1057.     if (errno)
  1058.     perror(prog);
  1059.     (void) fprintf(stderr, msg, prog, x1, x2, x3, x4, x5);
  1060.     exit(1);
  1061. }
  1062.