51fe026181bffdf95eeba48eb8174e41621fcd8d
[exim.git] / src / src / buildconfig.c
1 /* $Cambridge: exim/src/src/buildconfig.c,v 1.15 2009/11/16 19:50:36 nm4 Exp $ */
2
3 /*************************************************
4 *     Exim - an Internet mail transport agent    *
5 *************************************************/
6
7 /* Copyright (c) University of Cambridge 1995 - 2009 */
8 /* See the file NOTICE for conditions of use and distribution. */
9
10
11 /*************************************************
12 *       Build configuration header for Exim      *
13 *************************************************/
14
15 /* This auxiliary program builds the file config.h by the following
16 process:
17
18 First, it determines the size of off_t and time_t variables, and generates
19 macro code to define OFF_T_FMT and TIME_T_FMT as suitable formats, if they are
20 not already defined in the system-specific header file.
21
22 Then it reads Makefile, looking for certain OS-specific definitions which it
23 uses to define some specific macros. Finally, it reads the defaults file
24 config.h.defaults.
25
26 The defaults file contains normal C #define statements for various macros; if
27 the name of a macro is found in the environment, the environment value replaces
28 the default. If the default #define does not contain any value, then that macro
29 is not copied to the created file unless there is some value in the
30 environment.
31
32 This program is compiled and run as part of the Make process and is not
33 normally called independently. */
34
35
36 #include <ctype.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <sys/types.h>
41 #include <pwd.h>
42 #include <grp.h>
43
44 typedef struct {
45   char *name;
46   int *flag;
47 } have_item;
48
49 typedef struct {
50   char *name;
51   char *data;
52 } save_item;
53
54 static char *db_opts[] = { "", "USE_DB", "USE_GDBM", "USE_TDB" };
55
56 static int have_ipv6 = 0;
57 static int have_iconv = 0;
58
59 static char errno_quota[256];
60 static char ostype[256];
61 static char cc[256];
62
63 /* If any entry is an initial substring of another, the longer one must
64 appear first. */
65
66 static have_item have_list[] = {
67   { "HAVE_IPV6",      &have_ipv6 },
68   { "HAVE_ICONV",     &have_iconv },
69   { NULL, NULL}
70 };
71
72 static save_item save_list[] = {
73   { "ERRNO_QUOTA",    errno_quota },
74   { "OSTYPE",         ostype },
75   { "CC",             cc },
76   { NULL, NULL}
77 };
78
79
80 /* Subroutine to check a string for precisely one instance of "%s". If not,
81 bomb out. */
82
83 void
84 check_percent_ess(char *value, char *name)
85 {
86 int OK = 0;
87 char *p = strstr(value, "%s");
88 if (p != NULL) OK = strstr(p+2, "%s") == NULL;
89 if (!OK)
90   {
91   printf("\n*** \"%s\" (%s) must contain precisely one occurrence of\n"
92     "*** \"%%s\". Please review your build-time configuration.\n\n/", value,
93     name);
94   exit(1);
95   }
96 }
97
98
99 /* Main program */
100
101 int
102 main(int argc, char **argv)
103 {
104 off_t test_off_t = 0;
105 time_t test_time_t = 0;
106 FILE *base;
107 FILE *new;
108 int last_initial = 'A';
109 int linecount = 0;
110 int have_auth = 0;
111 int in_local_makefile = 0;
112 int use_which_db = 0;
113 int use_which_db_in_local_makefile = 0;
114 int support_crypteq = 0;
115 char buffer[1024];
116
117 if (argc != 1)
118   {
119   printf("*** Buildconfig: called with incorrect arguments\n");
120   exit(1);
121   }
122
123 new = fopen("config.h", "wb");
124 if (new == NULL)
125   {
126   printf("*** Buildconfig: failed to open config.h for output\n");
127   exit(1);
128   }
129
130 printf("Building configuration file config.h\n");
131
132 fprintf(new, "/*************************************************\n");
133 fprintf(new, "*           Configuration header for Exim        *\n");
134 fprintf(new, "*************************************************/\n\n");
135
136 fprintf(new, "/* This file was automatically generated from Makefile and "
137   "config.h.defaults,\n");
138 fprintf(new, "using values specified in the configuration file Local/Makefile.\n");
139 fprintf(new, "Do not edit it. Instead, edit Local/Makefile and "
140   "rerun make. */\n\n");
141
142 /* First, deal with the printing format for off_t variables. We assume that if
143 the size of off_t is greater than 4, "%lld" will be available as a format for
144 printing long long variables, and there will be support for the long long type.
145 This assumption is known to be OK for the common operating systems. */
146
147 fprintf(new, "#ifndef OFF_T_FMT\n");
148 if (sizeof(test_off_t) > 4)
149   {
150   fprintf(new, "#define OFF_T_FMT  \"%%lld\"\n");
151   fprintf(new, "#define LONGLONG_T long long int\n");
152   }
153 else
154   {
155   fprintf(new, "#define OFF_T_FMT  \"%%ld\"\n");
156   fprintf(new, "#define LONGLONG_T long int\n");
157   }
158 fprintf(new, "#endif\n\n");
159
160 /* Now do the same thing for time_t variables. If the length is greater than
161 4, we want to assume long long support (even if off_t was less than 4). If the
162 length is 4 or less, we can leave LONGLONG_T to whatever was defined above for
163 off_t. */
164
165 fprintf(new, "#ifndef TIME_T_FMT\n");
166 if (sizeof(test_time_t) > 4)
167   {
168   fprintf(new, "#define TIME_T_FMT  \"%%lld\"\n");
169   fprintf(new, "#undef  LONGLONG_T\n");
170   fprintf(new, "#define LONGLONG_T long long int\n");
171   }
172 else
173   {
174   fprintf(new, "#define TIME_T_FMT  \"%%ld\"\n");
175   }
176 fprintf(new, "#endif\n\n");
177
178 /* Now search the makefile for certain settings */
179
180 base = fopen("Makefile", "rb");
181 if (base == NULL)
182   {
183   printf("*** Buildconfig: failed to open Makefile\n");
184   (void)fclose(new);
185   exit(1);
186   }
187
188 errno_quota[0] = 0;    /* no over-riding value set */
189 ostype[0] = 0;         /* just in case */
190 cc[0] = 0;
191
192 while (fgets(buffer, sizeof(buffer), base) != NULL)
193   {
194   int i;
195   have_item *h;
196   save_item *s;
197   char *p = buffer + (int)strlen(buffer);
198   linecount++;
199   while (p > buffer && isspace((unsigned char)p[-1])) p--;
200   *p = 0;
201   p = buffer;
202   while (isspace((unsigned char)*p)) p++;
203
204   /* Notice when we hit the user's makefile */
205
206   if (strcmp(p, "# From Local/Makefile") == 0)
207     {
208     in_local_makefile = 1;
209     continue;
210     }
211
212   /* Remember the last DB option setting. If we hit two in the user's
213   Makefile, complain. */
214
215   for (i = 1; i < sizeof(db_opts)/sizeof(char *); i++)
216     {
217     int len = (int)strlen(db_opts[i]);
218     if (strncmp(p, db_opts[i], len) == 0 && (p[len] == ' ' || p[len] == '='))
219       {
220       if (in_local_makefile)
221         {
222         if (use_which_db_in_local_makefile)
223           {
224           printf("*** Only one of USE_DB, USE_GDBM, or USE_TDB should be "
225             "defined in Local/Makefile\n");
226           exit(1);
227           }
228         use_which_db_in_local_makefile = 1;
229         }
230       use_which_db = i;
231       break;
232       }
233     }
234   if (i < sizeof(db_opts)/sizeof(char *)) continue;
235
236   /* Items where we just save a boolean */
237
238   for (h = have_list; h->name != NULL; h++)
239     {
240     int len = (int)strlen(h->name);
241     if (strncmp(p, h->name, len) == 0)
242       {
243       p += len;
244       while (isspace((unsigned char)*p)) p++;
245       if (*p++ != '=')
246         {
247         printf("*** Buildconfig: syntax error in Makefile line %d\n", linecount);
248         exit(1);
249         }
250       while (isspace((unsigned char)*p)) p++;
251       if (strcmp(p, "YES") == 0 || strcmp(p, "yes") == 0) *(h->flag) = 1;
252         else *(h->flag) = 0;   /* Must reset in case multiple instances */
253       break;
254       }
255     }
256
257   if (h->name != NULL) continue;
258
259   /* Items where we save the complete string */
260
261   for (s = save_list; s->name != NULL; s++)
262     {
263     int len = (int)strlen(s->name);
264     if (strncmp(p, s->name, len) == 0)
265       {
266       p += len;
267       while (isspace((unsigned char)*p)) p++;
268       if (*p++ != '=')
269         {
270         printf("*** Buildconfig: syntax error in Makefile line %d\n", linecount);
271         exit(1);
272         }
273       while (isspace((unsigned char)*p)) p++;
274       strcpy(s->data, p);
275       }
276     }
277   }
278
279 fprintf(new, "#define HAVE_IPV6             %s\n",
280   have_ipv6? "TRUE" : "FALSE");
281
282 fprintf(new, "#define HAVE_ICONV            %s\n",
283   have_iconv? "TRUE" : "FALSE");
284
285 if (errno_quota[0] != 0)
286   fprintf(new, "\n#define ERRNO_QUOTA           %s\n", errno_quota);
287
288 if (strcmp(cc, "gcc") == 0 &&
289     (strstr(ostype, "IRIX") != NULL || strstr(ostype, "AIX") != NULL))
290   {
291   fprintf(new, "\n/* This switch includes the code to fix the inet_ntoa() */");
292   fprintf(new, "\n/* bug when using gcc on an IRIX or AIX system. */");
293   fprintf(new, "\n#define USE_INET_NTOA_FIX");
294   }
295
296 fprintf(new, "\n");
297 (void)fclose(base);
298
299
300 /* Now handle the macros listed in the defaults */
301
302 base = fopen("../src/config.h.defaults", "rb");
303 if (base == NULL)
304   {
305   printf("*** Buildconfig: failed to open ../src/config.h.defaults\n");
306   (void)fclose(new);
307   exit(1);
308   }
309
310 while (fgets(buffer, sizeof(buffer), base) != NULL)
311   {
312   int i;
313   char name[256];
314   char *value;
315   char *p = buffer;
316   char *q = name;
317
318   while (*p == ' ' || *p == '\t') p++;
319
320   if (strncmp(p, "#define ", 8) != 0) continue;
321
322   p += 8;
323   while (*p == ' ' || *p == '\t') p++;
324
325   if (*p < last_initial) fprintf(new, "\n");
326   last_initial = *p;
327
328   while (*p && (isalnum((unsigned char)*p) || *p == '_')) *q++ = *p++;
329   *q = 0;
330
331   /* USE_DB, USE_GDBM, and USE_TDB are special cases. We want to have only
332   one of them set. The scan of the Makefile has saved which was the last one
333   encountered. */
334
335   for (i = 1; i < sizeof(db_opts)/sizeof(char *); i++)
336     {
337     if (strcmp(name, db_opts[i]) == 0)
338       {
339       if (use_which_db == i)
340         fprintf(new, "#define %s %.*syes\n", db_opts[i],
341           21 - (int)strlen(db_opts[i]), "                         ");
342       else
343         fprintf(new, "/* %s not set */\n", name);
344       break;
345       }
346     }
347   if (i < sizeof(db_opts)/sizeof(char *)) continue;
348
349   /* EXIM_USER is a special case. We look in the environment for EXIM_USER or
350   EXIM_UID (the latter for backward compatibility with Exim 3). If the value is
351   not numeric, we look up the user, and default the GID if found. Otherwise,
352   EXIM_GROUP or EXIM_GID must be in the environment. */
353
354   if (strcmp(name, "EXIM_UID") == 0)
355     {
356     uid_t uid = 0;
357     gid_t gid = 0;
358     int gid_set = 0;
359     char *username = NULL;
360     char *groupname = NULL;
361     char *s;
362     char *user = getenv("EXIM_USER");
363     char *group = getenv("EXIM_GROUP");
364
365     if (user == NULL) user = getenv("EXIM_UID");
366     if (group == NULL) group = getenv("EXIM_GID");
367
368     if (user == NULL)
369       {
370       printf("\n*** EXIM_USER has not been defined in any of the Makefiles in "
371         "the\n    \"Local\" directory. Please review your build-time "
372         "configuration.\n\n");
373       return 1;
374       }
375
376     while (isspace((unsigned char)(*user))) user++;
377     if (*user == 0)
378       {
379       printf("\n*** EXIM_USER is defined as an empty string in one of the "
380         "files\n    in the \"Local\" directory. Please review your build-time"
381         "\n    configuration.\n\n");
382       return 1;
383       }
384
385     for (s = user; *s != 0; s++)
386       {
387       if (iscntrl((unsigned char)(*s)))
388         {
389         printf("\n*** EXIM_USER contains the control character 0x%02X in one "
390           "of the files\n    in the \"Local\" directory. Please review your "
391           "build-time\n    configuration.\n\n", *s);
392         return 1;
393         }
394       }
395
396     /* Numeric uid given */
397
398     if (user[strspn(user, "0123456789")] == 0)
399       {
400       uid = (uid_t)atoi(user);
401       }
402
403     /* User name given. Normally, we look up the uid right away. However,
404     people building binary distributions sometimes want to retain the name till
405     runtime. This is supported if the name begins "ref:". */
406
407     else if (strncmp(user, "ref:", 4) == 0)
408       {
409       user += 4;
410       while (isspace(*user)) user++;
411       username = user;
412       gid_set = 1;
413       }
414
415     else
416       {
417       struct passwd *pw = getpwnam(user);
418       if (pw == NULL)
419         {
420         printf("\n*** User \"%s\" (specified in one of the Makefiles) does not "
421           "exist.\n    Please review your build-time configuration.\n\n",
422           user);
423         return 1;
424         }
425
426       uid = pw->pw_uid;
427       gid = pw->pw_gid;
428       gid_set = 1;
429       }
430
431     /* Use explicit group if set. */
432
433     if (group != NULL)
434       {
435       while (isspace((unsigned char)(*group))) group++;
436       if (*group == 0)
437         {
438         printf("\n*** EXIM_GROUP is defined as an empty string in one of "
439           "the files in the\n    \"Local\" directory. ");
440         if (gid_set)
441           {
442           printf("If you want the Exim group to be taken from the\n    "
443             "password data for the Exim user, just remove the EXIM_GROUP "
444             "setting.\n    Otherwise, p");
445           }
446         else printf("EXIM_USER is defined numerically, so there is no"
447           "\n    default for EXIM_GROUP and you must set it explicitly.\n    P");
448         printf("lease review your build-time configuration.\n\n");
449         return 1;
450         }
451
452       for (s = group; *s != 0; s++)
453         {
454         if (iscntrl((unsigned char)(*s)))
455           {
456           printf("\n*** EXIM_GROUP contains the control character 0x%02X in one "
457             "of the files\n    in the \"Local\" directory. Please review your "
458             "build-time\n    configuration.\n\n", *s);
459           return 1;
460           }
461         }
462
463       /* Group name given. This may be by reference or to be looked up now,
464       as for user. */
465
466       if (strncmp(group, "ref:", 4) == 0)
467         {
468         group += 4;
469         while (isspace(*group)) group++;
470         groupname = group;
471         }
472
473       else if (username != NULL)
474         {
475         groupname = group;
476         }
477
478       else if (group[strspn(group, "0123456789")] == 0)
479         {
480         gid = (gid_t)atoi(group);
481         }
482
483       else
484         {
485         struct group *gr = getgrnam(group);
486         if (gr == NULL)
487           {
488           printf("\n*** Group \"%s\" (specified in one of the Makefiles) does "
489             "not exist.\n   Please review your build-time configuration.\n\n",
490             group);
491           return 1;
492           }
493         gid = gr->gr_gid;
494         }
495       }
496
497     /* Else trouble unless found in passwd file with user */
498
499     else if (!gid_set)
500       {
501       printf("\n*** No group set for Exim. Please review your build-time "
502         "configuration.\n\n");
503       return 1;
504       }
505
506     /* Output user and group names or uid/gid. When names are set, uid/gid
507     are set to zero but will be replaced at runtime. */
508
509     if (username != NULL)
510       fprintf(new, "#define EXIM_USERNAME         \"%s\"\n", username);
511     if (groupname != NULL)
512       fprintf(new, "#define EXIM_GROUPNAME        \"%s\"\n", groupname);
513
514     fprintf(new, "#define EXIM_UID              %d\n", (int)uid);
515     fprintf(new, "#define EXIM_GID              %d\n", (int)gid);
516     continue;
517     }
518
519   /* CONFIGURE_OWNER and CONFIGURE_GROUP are special cases. We look in the
520   environment for first. If the value is not numeric, we look up the user or
521   group. A lot of this code is similar to that for EXIM_USER, but it's easier
522   to keep it separate. */
523
524   if (strcmp(name, "CONFIGURE_OWNER") == 0 ||
525       strcmp(name, "CONFIGURE_GROUP") == 0)
526     {
527     int isgroup = name[10] == 'G';
528     uid_t uid = 0;
529     gid_t gid = 0;
530     char *s;
531     char *username = NULL;
532     char *user = getenv(name);
533
534     if (user == NULL) user = "";
535     while (isspace((unsigned char)(*user))) user++;
536     if (*user == 0)
537       {
538       fprintf(new, "/* %s not set */\n", name);
539       continue;
540       }
541
542     for (s = user; *s != 0; s++)
543       {
544       if (iscntrl((unsigned char)(*s)))
545         {
546         printf("\n*** %s contains the control character 0x%02X in "
547           "one of the files\n    in the \"Local\" directory. Please review "
548           "your build-time\n    configuration.\n\n", name, *s);
549         return 1;
550         }
551       }
552
553     /* Numeric uid given */
554
555     if (user[strspn(user, "0123456789")] == 0)
556       {
557       if (isgroup)
558         gid = (gid_t)atoi(user);
559       else
560         uid = (uid_t)atoi(user);
561       }
562
563     /* Name given. Normally, we look up the uid or gid right away. However,
564     people building binary distributions sometimes want to retain the name till
565     runtime. This is supported if the name begins "ref:". */
566
567     else if (strncmp(user, "ref:", 4) == 0)
568       {
569       user += 4;
570       while (isspace(*user)) user++;
571       username = user;
572       }
573
574     else if (isgroup)
575       {
576       struct group *gr = getgrnam(user);
577       if (gr == NULL)
578         {
579         printf("\n*** Group \"%s\" (specified in one of the Makefiles) does not "
580           "exist.\n    Please review your build-time configuration.\n\n",
581           user);
582         return 1;
583         }
584       gid = gr->gr_gid;
585       }
586
587     else
588       {
589       struct passwd *pw = getpwnam(user);
590       if (pw == NULL)
591         {
592         printf("\n*** User \"%s\" (specified in one of the Makefiles) does not "
593           "exist.\n    Please review your build-time configuration.\n\n",
594           user);
595         return 1;
596         }
597       uid = pw->pw_uid;
598       }
599
600     /* Output user and group names or uid/gid. When names are set, uid/gid
601     are set to zero but will be replaced at runtime. */
602
603     if (username != NULL)
604       {
605       if (isgroup)
606         fprintf(new, "#define CONFIGURE_GROUPNAME         \"%s\"\n", username);
607       else
608         fprintf(new, "#define CONFIGURE_OWNERNAME         \"%s\"\n", username);
609       }
610
611     if (isgroup)
612       fprintf(new, "#define CONFIGURE_GROUP              %d\n", (int)gid);
613     else
614       fprintf(new, "#define CONFIGURE_OWNER              %d\n", (int)uid);
615     continue;
616     }
617
618   /* FIXED_NEVER_USERS is another special case. Look up the uid values and
619   create suitable initialization data for a vector. */
620
621   if (strcmp(name, "FIXED_NEVER_USERS") == 0)
622     {
623     char *list = getenv("FIXED_NEVER_USERS");
624     if (list == NULL)
625       {
626       fprintf(new, "#define FIXED_NEVER_USERS     0\n");
627       }
628     else
629       {
630       int count = 1;
631       int i, j;
632       uid_t *vector;
633       char *p = list;
634       while (*p != 0) if (*p++ == ':') count++;
635
636       vector = malloc((count+1) * sizeof(uid_t));
637       vector[0] = (uid_t)count;
638
639       for (i = 1, j = 0; i <= count; list++, i++)
640         {
641         char name[64];
642
643         p = list;
644         while (*list != 0 && *list != ':') list++;
645         strncpy(name, p, list-p);
646         name[list-p] = 0;
647
648         if (name[0] == 0)
649           {
650           continue;
651           }
652         else if (name[strspn(name, "0123456789")] == 0)
653           {
654           vector[j++] = (uid_t)atoi(name);
655           }
656         else
657           {
658           struct passwd *pw = getpwnam(name);
659           if (pw == NULL)
660             {
661             printf("\n*** User \"%s\" (specified for FIXED_NEVER_USERS in one of the Makefiles) does not "
662               "exist.\n    Please review your build-time configuration.\n\n",
663               name);
664             return 1;
665             }
666           vector[j++] = pw->pw_uid;
667           }
668         }
669       fprintf(new, "#define FIXED_NEVER_USERS     %d", j);
670       for (i = 0; i < j; i++) fprintf(new, ", %d", (unsigned int)vector[i]);
671       fprintf(new, "\n");
672       }
673     continue;
674     }
675
676   /* WITH_CONTENT_SCAN is another special case: it must be set if either it or
677   WITH_OLD_DEMIME is set. */
678
679   if (strcmp(name, "WITH_CONTENT_SCAN") == 0)
680     {
681     char *wcs = getenv("WITH_CONTENT_SCAN");
682     char *wod = getenv("WITH_OLD_DEMIME");
683     char *dcc = getenv("EXPERIMENTAL_DCC");
684     if (wcs != NULL || wod != NULL || dcc != NULL)
685       fprintf(new, "#define WITH_CONTENT_SCAN     yes\n");
686     else fprintf(new, "/* WITH_CONTENT_SCAN not set */\n");
687     continue;
688     }
689
690   /* Otherwise, check whether a value exists in the environment. Remember if
691   it is an AUTH setting or SUPPORT_CRYPTEQ. */
692
693   if ((value = getenv(name)) != NULL)
694     {
695     int len;
696     len = 21 - (int)strlen(name);
697
698     if (strncmp(name, "AUTH_", 5) == 0) have_auth = 1;
699     if (strncmp(name, "SUPPORT_CRYPTEQ", 15) == 0) support_crypteq = 1;
700
701     /* The text value of LDAP_LIB_TYPE refers to a macro that gets set. */
702
703     if (strcmp(name, "LDAP_LIB_TYPE") == 0)
704       {
705       if (strcmp(value, "NETSCAPE") == 0 ||
706           strcmp(value, "UMICHIGAN") == 0 ||
707           strcmp(value, "OPENLDAP1") == 0 ||
708           strcmp(value, "OPENLDAP2") == 0 ||
709           strcmp(value, "SOLARIS") == 0 ||
710           strcmp(value, "SOLARIS7") == 0)              /* Compatibility */
711         {
712         fprintf(new, "#define LDAP_LIB_%s\n", value);
713         }
714       else
715         {
716         printf("\n*** LDAP_LIB_TYPE=%s is not a recognized LDAP library type."
717           "\n*** Please review your build-time configuration.\n\n", value);
718         return 1;
719         }
720       }
721
722     else if (strcmp(name, "RADIUS_LIB_TYPE") == 0)
723       {
724       if (strcmp(value, "RADIUSCLIENT") == 0 ||
725           strcmp(value, "RADIUSCLIENTNEW") == 0 ||
726           strcmp(value, "RADLIB") == 0)
727         {
728         fprintf(new, "#define RADIUS_LIB_%s\n", value);
729         }
730       else
731         {
732         printf("\n*** RADIUS_LIB_TYPE=%s is not a recognized RADIUS library type."
733           "\n*** Please review your build-time configuration.\n\n", value);
734         return 1;
735         }
736       }
737
738     /* Other macros get set to the environment value. */
739
740     else
741       {
742       fprintf(new, "#define %s ", name);
743       while(len-- > 0) fputc(' ', new);
744
745       /* LOG_FILE_PATH is now messy because it can be a path containing %s or
746       it can be "syslog" or ":syslog" or "syslog:path" or even "path:syslog". */
747
748       if (strcmp(name, "LOG_FILE_PATH") == 0)
749         {
750         char *ss = value;
751         for(;;)
752           {
753           char *pp;
754           char *sss = strchr(ss, ':');
755           if (sss != NULL)
756             {
757             strncpy(buffer, ss, sss-ss);
758             buffer[sss-ss] = 0;  /* For empty case */
759             }
760           else strcpy(buffer, ss);
761           pp = buffer + (int)strlen(buffer);
762           while (pp > buffer && isspace((unsigned char)pp[-1])) pp--;
763           *pp = 0;
764           if (buffer[0] != 0 && strcmp(buffer, "syslog") != 0)
765             check_percent_ess(buffer, name);
766           if (sss == NULL) break;
767           ss = sss + 1;
768           while (isspace((unsigned char)*ss)) ss++;
769           }
770         fprintf(new, "\"%s\"\n", value);
771         }
772
773       /* Timezone values and HEADERS_CHARSET get quoted */
774
775       else if (strcmp(name, "TIMEZONE_DEFAULT") == 0||
776                strcmp(name, "HEADERS_CHARSET") == 0)
777         fprintf(new, "\"%s\"\n", value);
778
779       /* For others, quote any paths and don't quote anything else */
780
781       else
782         {
783         if (value[0] == '/') fprintf(new, "\"%s\"\n", value);
784           else fprintf(new, "%s\n", value);
785         }
786       }
787     }
788
789   /* Value not defined in the environment; use the default */
790
791   else
792     {
793     char *t = p;
794     while (*p == ' ' || *p == '\t') p++;
795     if (*p != '\n') fputs(buffer, new); else
796       {
797       *t = 0;
798       if (strcmp(name, "BIN_DIRECTORY")   == 0 ||
799           strcmp(name, "CONFIGURE_FILE")  == 0)
800         {
801         printf("\n*** %s has not been defined in any of the Makefiles in the\n"
802           "    \"Local\" directory. "
803           "Please review your build-time configuration.\n\n", name);
804         return 1;
805         }
806
807       if (strcmp(name, "TIMEZONE_DEFAULT") == 0)
808         {
809         char *tz = getenv("TZ");
810         fprintf(new, "#define TIMEZONE_DEFAULT      ");
811         if (tz == NULL) fprintf(new, "NULL\n"); else
812           fprintf(new, "\"%s\"\n", tz);
813         }
814
815       else fprintf(new, "/* %s not set */\n", name);
816       }
817     }
818   }
819
820 (void)fclose(base);
821
822 /* If any AUTH macros were defined, ensure that SUPPORT_CRYPTEQ is also
823 defined. */
824
825 if (have_auth)
826   {
827   if (!support_crypteq) fprintf(new, "/* Force SUPPORT_CRYPTEQ for AUTH */\n"
828     "#define SUPPORT_CRYPTEQ\n");
829   }
830
831 /* End off */
832
833 fprintf(new, "\n/* End of config.h */\n");
834 (void)fclose(new);
835 return 0;
836 }
837
838 /* End of buildconfig.c */