Bug Summary

File:xrdb.c
Location:line 790, column 2
Description:Null pointer passed as an argument to a 'nonnull' parameter

Annotated Source Code

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