Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dtksh / ksh93 / src / lib / libast / port / astconf.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $XConsortium: astconf.c /main/2 1996/05/08 19:56:20 drk $ */
24 /***************************************************************
25 *                                                              *
26 *                      AT&T - PROPRIETARY                      *
27 *                                                              *
28 *         THIS IS PROPRIETARY SOURCE CODE LICENSED BY          *
29 *                          AT&T CORP.                          *
30 *                                                              *
31 *                Copyright (c) 1995 AT&T Corp.                 *
32 *                     All Rights Reserved                      *
33 *                                                              *
34 *           This software is licensed by AT&T Corp.            *
35 *       under the terms and conditions of the license in       *
36 *       http://www.research.att.com/orgs/ssr/book/reuse        *
37 *                                                              *
38 *               This software was created by the               *
39 *           Software Engineering Research Department           *
40 *                    AT&T Bell Laboratories                    *
41 *                                                              *
42 *               For further information contact                *
43 *                     gsf@research.att.com                     *
44 *                                                              *
45 ***************************************************************/
46
47 /* : : generated by proto : : */
48
49 #if !defined(__PROTO__)
50 #if defined(__STDC__) || defined(__cplusplus) || defined(_proto) || defined(c_plusplus)
51 #if defined(__cplusplus)
52 #define __MANGLE__      "C"
53 #else
54 #define __MANGLE__
55 #endif
56 #define __STDARG__
57 #define __PROTO__(x)    x
58 #define __OTORP__(x)
59 #define __PARAM__(n,o)  n
60 #if !defined(__STDC__) && !defined(__cplusplus)
61 #if !defined(c_plusplus)
62 #define const
63 #endif
64 #define signed
65 #define void            int
66 #define volatile
67 #define __V_            char
68 #else
69 #define __V_            void
70 #endif
71 #else
72 #define __PROTO__(x)    ()
73 #define __OTORP__(x)    x
74 #define __PARAM__(n,o)  o
75 #define __MANGLE__
76 #define __V_            char
77 #define const
78 #define signed
79 #define void            int
80 #define volatile
81 #endif
82 #if defined(__cplusplus) || defined(c_plusplus)
83 #define __VARARG__      ...
84 #else
85 #define __VARARG__
86 #endif
87 #if defined(__STDARG__)
88 #define __VA_START__(p,a)       va_start(p,a)
89 #else
90 #define __VA_START__(p,a)       va_start(p)
91 #endif
92 #endif
93 static const char id[] = "\n@(#)getconf (AT&T Bell Laboratories) 07/17/95\0\n";
94
95 static const char lib[] = "";
96
97 #define ID              "getconf"
98
99 #include <ast.h>
100 #include <error.h>
101 #include <stk.h>
102 #include <fs3d.h>
103 #include <ctype.h>
104
105 #include "conftab.h"
106 #include "univlib.h"
107
108 #define CONF_ERROR      (CONF_USER<<0)
109
110 #define OP_fs_3d        1
111 #define OP_path_resolve 2
112 #define OP_universe     3
113
114 #define MAXVAL          16
115
116 #if MAXVAL <= UNIV_SIZE
117 #undef  MAXVAL
118 #define MAXVAL          (UNIV_SIZE+1)
119 #endif
120
121 typedef struct Feature
122 {
123         struct Feature* next;
124         const char*     name;
125         char            value[MAXVAL];
126         short           length;
127         short           standard;
128         short           op;
129 } Feature_t;
130
131 typedef struct
132 {
133         Conf_t*         conf;
134         const char*     name;
135         const char*     error;
136         short           flags;
137         short           call;
138         short           standard;
139         short           section;
140 } Lookup_t;
141
142 static Feature_t        dynamic[] =
143 {
144 { &dynamic[1],  "FS_3D",        "",     5,      CONF_AST, OP_fs_3d      },
145 { &dynamic[2],  "PATH_RESOLVE", "",     12,     CONF_AST, OP_path_resolve },
146 { 0,            "UNIVERSE",     "",     8,      CONF_AST, OP_universe   },
147 { 0 }
148 };
149
150 static Feature_t*       features = dynamic;
151
152 static Ast_confdisc_t   notify;
153
154 /*
155  * synthesize state for fp
156  * value==0 just does lookup
157  * otherwise state is set to value
158  */
159
160 static char*
161 synthesize __PARAM__((register Feature_t* fp, const char* path, const char* value), (fp, path, value)) __OTORP__(register Feature_t* fp; const char* path; const char* value;){
162         register char*          s;
163         register char*          d;
164         register char*          v;
165         register int            n;
166
167         static char*            data;
168         static char*            last;
169
170         static const char       state[] = "_AST_FEATURES";
171
172         if (!fp)
173                 return(data);
174         if (!data)
175         {
176                 n = sizeof(state) + 3 * MAXVAL;
177                 if (s = getenv(state))
178                         n += strlen(s);
179                 n = roundof(n, 32);
180                 if (!(data = newof(0, char, n, 0)))
181                         return(0);
182                 last = data + n - 1;
183                 strcpy(data, state);
184                 data += sizeof(state) - 1;
185                 *data++ = '=';
186                 if (s) strcpy(data, s);
187         }
188         s = (char*)fp->name;
189         n = fp->length;
190         d = data;
191         for (;;)
192         {
193                 while (isspace(*d)) d++;
194                 if (!*d) break;
195                 if (strneq(d, s, n) && isspace(d[n]))
196                 {
197                         if (!value)
198                         {
199                                 d += n + 1;
200                                 while (*d && !isspace(*d)) d++;
201                                 while (isspace(*d)) d++;
202                                 s = d;
203                                 while (*s && !isspace(*s)) s++;
204                                 n = s - d;
205                                 value = (const char*)d;
206                                 goto ok;
207                         }
208                         s = d + n + 1;
209                         while (*s && !isspace(*s)) s++;
210                         while (isspace(*s)) s++;
211                         v = s;
212                         while (*s && !isspace(*s)) s++;
213                         n = s - v;
214                         if (strneq(v, value, n))
215                                 goto ok;
216                         while (isspace(*s)) s++;
217                         if (*s) while (*d = *s++) d++;
218                         else if (d != data) d--;
219                         break;
220                 }
221                 while (*d && !isspace(*d)) d++;
222                 while (isspace(*d)) d++;
223                 while (*d && !isspace(*d)) d++;
224                 while (isspace(*d)) d++;
225                 while (*d && !isspace(*d)) d++;
226         }
227         if (!value)
228         {
229                 fp->value[0] = 0;
230                 return(0);
231         }
232         if (!value[0])
233                 value = "0";
234         if (!path || !path[0] || path[0] == '/' && !path[1])
235                 path = "-";
236         n += strlen(path) + strlen(value) + 3;
237         if (d + n >= last)
238         {
239                 int     c;
240                 int     i;
241
242                 i = d - data;
243                 data -= sizeof(state);
244                 c = n + last - data + 3 * MAXVAL;
245                 c = roundof(c, 32);
246                 if (!(data = newof(data, char, c, 0)))
247                         return(0);
248                 last = data + c - 1;
249                 data += sizeof(state);
250                 d = data + i;
251         }
252         s = (char*)fp->name;
253         if (d != data)
254                 *d++ = ' ';
255         while (*d = *s++) d++;
256         *d++ = ' ';
257         s = (char*)path;
258         while (*d = *s++) d++;
259         *d++ = ' ';
260         s = (char*)value;
261         while (*d = *s++) d++;
262         setenviron(data - sizeof(state));
263         n = s - (char*)value - 1;
264  ok:
265         if (n >= sizeof(fp->value))
266                 n = sizeof(fp->value) - 1;
267         else if (n == 1 && (*value == '0' || *value == '-'))
268                 n = 0;
269         strncpy(fp->value, value, n);
270         fp->value[n] = 0;
271         return(fp->value);
272 }
273
274 /*
275  * initialize the value for fp
276  * if command!=0 then it is checked for on $PATH
277  * synthesize(fp,path,succeed) called on success
278  * otherwise synthesize(fp,path,fail) called
279  */
280
281 static void
282 initialize __PARAM__((register Feature_t* fp, const char* path, const char* command, const char* succeed, const char* fail), (fp, path, command, succeed, fail)) __OTORP__(register Feature_t* fp; const char* path; const char* command; const char* succeed; const char* fail;){
283         register char*  p;
284         register int    ok = 1;
285
286         if (fp->op != OP_path_resolve || !fs3d(FS3D_TEST))
287         {
288                 if (fp->op == OP_universe)
289                         ok = streq(_UNIV_DEFAULT, "att");
290                 if (p = getenv("PATH"))
291                 {
292                         register int    r = 1;
293                         register char*  d = p;
294                         int             offset = stktell(stkstd);
295
296                         for (;;)
297                         {
298                                 switch (*p++)
299                                 {
300                                 case 0:
301                                         break;
302                                 case ':':
303                                         if (command && (fp->op != OP_universe || !ok))
304                                         {
305                                                 if (r = p - d - 1)
306                                                 {
307                                                         sfwrite(stkstd, d, r);
308                                                         sfputc(stkstd, '/');
309                                                         sfputr(stkstd, command, 0);
310                                                         stkseek(stkstd, offset);
311                                                         if (!access(stkptr(stkstd, offset), X_OK))
312                                                         {
313                                                                 ok = 1;
314                                                                 if (fp->op != OP_universe)
315                                                                         break;
316                                                         }
317                                                 }
318                                                 d = p;
319                                         }
320                                         r = 1;
321                                         continue;
322                                 case '/':
323                                         if (r)
324                                         {
325                                                 r = 0;
326                                                 if (fp->op == OP_universe)
327                                                 {
328                                                         if (strneq(p, "bin:", 4) || strneq(p, "usr/bin:", 8))
329                                                                 break;
330                                                 }
331                                                 else if (fp->op == OP_path_resolve)
332                                                         if (strneq(p, "ast/bin:", 8))
333                                                                 break;
334                                         }
335                                         if (fp->op == OP_universe)
336                                         {
337                                                 if (strneq(p, "5bin", 4))
338                                                 {
339                                                         ok = 1;
340                                                         break;
341                                                 }
342                                                 if (strneq(p, "bsd", 3) || strneq(p, "ucb", 3))
343                                                 {
344                                                         ok = 0;
345                                                         break;
346                                                 }
347                                         }
348                                         continue;
349                                 default:
350                                         r = 0;
351                                         continue;
352                                 }
353                                 break;
354                         }
355                 }
356         }
357         synthesize(fp, path, ok ? succeed : fail);
358 }
359
360 /*
361  * value==0 get feature name
362  * value!=0 set feature name
363  * 0 returned if error or not defined; otherwise previous value
364  */
365
366 static char*
367 feature __PARAM__((const char* name, const char* path, const char* value), (name, path, value)) __OTORP__(const char* name; const char* path; const char* value;){
368         register Feature_t*     fp;
369         register int            n;
370
371         if (value)
372         {
373                 if (streq(value, "-") || streq(value, "0"))
374                         value = "";
375                 if (notify && !(*notify)(name, path, value))
376                         return(0);
377         }
378         for (fp = features; fp && !streq(fp->name, name); fp = fp->next);
379         if (!fp)
380         {
381                 if (!value)
382                         return(0);
383                 n = strlen(name);
384                 if (!(fp = newof(0, Feature_t, 1, n + 1)))
385                         return(0);
386                 fp->name = (const char*)fp + sizeof(Feature_t);
387                 strcpy((char*)fp->name, name);
388                 fp->length = n;
389                 fp->next = features;
390                 features = fp;
391         }
392         switch (fp->op)
393         {
394
395         case OP_fs_3d:
396                 fp->value[0] = fs3d(value ? value[0] ? FS3D_ON : FS3D_OFF : FS3D_TEST) ? '1' : 0;
397                 break;
398
399         case OP_path_resolve:
400                 if (!synthesize(fp, path, value))
401                         initialize(fp, path, "hostinfo", "logical", "physical");
402                 break;
403
404         case OP_universe:
405 #if _lib_universe
406                 if (getuniverse(fp->value) < 0)
407                         strcpy(fp->value, "att");
408                 if (value)
409                         setuniverse(value);
410 #else
411 #ifdef UNIV_MAX
412                 n = 0;
413                 if (value)
414                 {
415                         while (n < univ_max && !streq(value, univ_name[n])
416                                 n++;
417                         if (n >= univ_max)
418                                 return(0);
419                 }
420 #ifdef ATT_UNIV
421                 n = setuniverse(n + 1);
422                 if (!value && n > 0)
423                         setuniverse(n);
424 #else
425                 n = universe(value ? n + 1 : U_GET);
426 #endif
427                 if (n <= 0 || n >= univ_max)
428                         n = 1;
429                 strcpy(fp->value, univ_name[n - 1]);
430 #else
431                 if (!synthesize(fp, path, value))
432                         initialize(fp, path, "echo", "att", "ucb");
433 #endif
434 #endif
435                 break;
436
437         default:
438                 synthesize(fp, path, value);
439                 break;
440
441         }
442         return(fp->value);
443 }
444
445 /*
446  * binary search for name in conf[]
447  */
448
449 static int
450 lookup __PARAM__((register Lookup_t* look, const char* name), (look, name)) __OTORP__(register Lookup_t* look; const char* name;){
451         register Conf_t*        mid = (Conf_t*)conf;
452         register Conf_t*        lo = mid;
453         register Conf_t*        hi = mid + conf_elements;
454         register int            v;
455         register int            c;
456         const char*             oldname = name;
457         const Prefix_t*         p;
458
459         look->flags = 0;
460         look->call = -1;
461         look->standard = -1;
462         look->section = -1;
463         while (*name == '_')
464                 name++;
465         for (p = prefix; p < &prefix[prefix_elements]; p++)
466                 if (strneq(name, p->name, p->length) && ((c = name[p->length] == '_') || isdigit(name[p->length]) && name[p->length + 1] == '_'))
467                 {
468                         if ((look->call = p->call) < 0)
469                         {
470                                 look->flags |= CONF_MINMAX;
471                                 look->standard = p->standard;
472                         }
473                         name += p->length + c;
474                         if (isdigit(name[0]) && name[1] == '_')
475                         {
476                                 look->section = name[0] - '0';
477                                 name += 2;
478                         }
479                         else look->section = 1;
480                         break;
481                 }
482         look->name = name;
483         c = *((unsigned char*)name);
484         while (lo <= hi)
485         {
486                 mid = lo + (hi - lo) / 2;
487                 if (!(v = c - *((unsigned char*)mid->name)) && !(v = strcmp(name, mid->name)))
488                 {
489                         lo = (Conf_t*)conf;
490                         hi = lo + conf_elements - 1;
491                         if (look->standard >= 0 && look->standard != mid->standard) do
492                         {
493                                 if (look->standard > mid->standard)
494                                 {
495                                         if (mid >= hi)
496                                                 goto badstandard;
497                                         mid++;
498                                 }
499                                 else if (mid <= lo)
500                                         goto badstandard;
501                                 else mid--;
502                                 if (!streq(name, mid->name))
503                                         goto badstandard;
504                         } while (look->standard != mid->standard);
505                         if (look->section >= 0 && look->section != mid->section) do
506                         {
507                                 if (look->section > mid->section)
508                                 {
509                                         if (mid >= hi)
510                                                 goto badsection;
511                                         mid++;
512                                 }
513                                 else if (mid <= lo)
514                                         goto badsection;
515                                 else mid--;
516                                 if (!streq(name, mid->name))
517                                         goto badsection;
518                         } while (look->section != mid->section);
519                         if (look->call >= 0 && look->call != mid->call)
520                                 goto badcall;
521                         look->conf = mid;
522                         return(1);
523                 }
524                 else if (v > 0)
525                         lo = mid + 1;
526                 else hi = mid - 1;
527         }
528         look->error = 0;
529         return(0);
530  badcall:
531         look->error = "call";
532         return(0);
533  badstandard:
534         look->error = "standard";
535         return(0);
536  badsection:
537         look->error = "section";
538         return(0);
539 }
540
541 /*
542  * print value line for p
543  * if !name then value prefixed by "p->name="
544  * if (flags & CONF_MINMAX) then default minmax value used
545  */
546
547 static char*
548 print __PARAM__((Sfio_t* sp, register Lookup_t* look, const char* name, const char* path), (sp, look, name, path)) __OTORP__(Sfio_t* sp; register Lookup_t* look; const char* name; const char* path;){
549         register Conf_t*        p = look->conf;
550         register int            flags = look->flags|CONF_DEFINED;
551         char*                   call;
552         int                     offset;
553         long                    v;
554         int                     olderrno;
555         char                    buf[PATH_MAX];
556
557         if (!name && p->call != CONF_confstr && (p->flags & (CONF_FEATURE|CONF_LIMIT)) && (p->flags & (CONF_LIMIT|CONF_PREFIXED)) != CONF_LIMIT)
558         {
559                 flags |= CONF_PREFIXED;
560                 if (p->flags & CONF_DEFINED)
561                         flags |= CONF_MINMAX;
562         }
563         olderrno = errno;
564         errno = 0;
565         switch ((flags & CONF_MINMAX) && (p->flags & CONF_DEFINED) ? 0 : p->call)
566         {
567         case 0:
568                 if (p->flags & CONF_DEFINED)
569                         v = p->value;
570                 else
571                 {
572                         flags &= ~CONF_DEFINED;
573                         v = -1;
574                 }
575                 break;
576         case CONF_confstr:
577                 call = "confstr";
578                 if (!(v = confstr(p->op, buf, sizeof(buf))))
579                 {
580                         v = -1;
581                         errno = EINVAL;
582                 }
583                 break;
584         case CONF_pathconf:
585                 call = "pathconf";
586                 v = pathconf(path, p->op);
587                 break;
588         case CONF_sysconf:
589                 call = "sysconf";
590                 v = sysconf(p->op);
591                 break;
592         default:
593                 call = "synthesis";
594                 errno = EINVAL;
595                 v = -1;
596                 break;
597         }
598         if (v == -1)
599         {
600                 if (!errno)
601                 {
602                         if ((p->flags & CONF_FEATURE) || !(p->flags & (CONF_LIMIT|CONF_MINMAX)))
603                                 flags &= ~CONF_DEFINED;
604                 }
605                 else if (!(flags & CONF_PREFIXED))
606                 {
607                         if (!sp)
608                         {
609                                 liberror(lib, ERROR_SYSTEM|2, "%s: %s error", p->name, call);
610                                 return("");
611                         }
612                         flags &= ~CONF_DEFINED;
613                         flags |= CONF_ERROR;
614                 }
615                 else flags &= ~CONF_DEFINED;
616         }
617         errno = olderrno;
618         if (sp) offset = -1;
619         else
620         {
621                 sp = stkstd;
622                 offset = stktell(sp);
623         }
624         if (!(flags & CONF_PREFIXED))
625         {
626                 if (!name)
627                         sfprintf(sp, "%s=", p->name);
628                 if (flags & CONF_ERROR)
629                         sfprintf(sp, "error");
630                 else if (p->call == CONF_confstr)
631                         sfprintf(sp, "%s", buf);
632                 else if (v != -1)
633                         sfprintf(sp, "%ld", v);
634                 else if (flags & CONF_DEFINED)
635                         sfprintf(sp, "%lu", v);
636                 else sfprintf(sp, "undefined");
637                 if (!name)
638                         sfprintf(sp, "\n");
639         }
640         if (!name && p->call != CONF_confstr && (p->flags & (CONF_FEATURE|CONF_MINMAX)))
641         {
642                 if (p->flags & CONF_UNDERSCORE)
643                         sfprintf(sp, "_");
644                 sfprintf(sp, "%s", prefix[p->standard].name);
645                 if (p->section > 1)
646                         sfprintf(sp, "%d", p->section);
647                 sfprintf(sp, "_%s=", p->name);
648                 if (p->flags & CONF_DEFINED)
649                 {
650                         if ((v = p->value) == -1 && ((p->flags & CONF_FEATURE) || !(p->flags & (CONF_LIMIT|CONF_MINMAX))))
651                                 flags &= ~CONF_DEFINED;
652                         else flags |= CONF_DEFINED;
653                 }
654                 if (v != -1)
655                         sfprintf(sp, "%ld", v);
656                 else if (flags & CONF_DEFINED)
657                         sfprintf(sp, "%lu", v);
658                 else sfprintf(sp, "undefined");
659                 sfprintf(sp, "\n");
660         }
661         if (offset >= 0)
662         {
663                 sfputc(sp, 0);
664                 stkseek(stkstd, offset);
665                 return(stkptr(sp, offset));
666         }
667         return("");
668 }
669
670 /*
671  * value==0 gets value for name
672  * value!=0 sets value for name and returns previous value
673  * path==0 implies path=="/"
674  *
675  * settable return values are in permanent store
676  * non-settable return values are on stkstd
677  *
678  *      if (!strcmp(astconf("PATH_RESOLVE", NiL, NiL), "logical"))
679  *              our_way();
680  *
681  *      universe = astconf("UNIVERSE", NiL, "att");
682  *      astconf("UNIVERSE", NiL, universe);
683  */
684
685 char*
686 astconf __PARAM__((const char* name, const char* path, const char* value), (name, path, value)) __OTORP__(const char* name; const char* path; const char* value;){
687         register char*  s;
688         Lookup_t        look;
689
690         if (!path)
691                 path = "/";
692         if (lookup(&look, name))
693         {
694                 if (value)
695                 {
696                         liberror(lib, 2, "%s: cannot set value", name);
697                         errno = EINVAL;
698                         return("");
699                 }
700                 return(print(NiL, &look, name, path));
701         }
702         if (look.error)
703                 liberror(lib, 2, "%s: invalid %s prefix", name, look.error);
704         else if ((look.standard < 0 || look.standard == CONF_AST) && look.call <= 0 && look.section <= 1 && (s = feature(look.name, path, value)))
705                 return(s);
706         else liberror(lib, 2, "%s: invalid symbol", name);
707         return("");
708 }
709
710 /*
711  * set discipline function to be called when features change
712  * old discipline function returned
713  */
714
715 Ast_confdisc_t
716 astconfdisc __PARAM__((Ast_confdisc_t new_notify), (new_notify)) __OTORP__(Ast_confdisc_t new_notify;){
717         Ast_confdisc_t  old_notify = notify;
718
719         notify = new_notify;
720         return(old_notify);
721 }
722
723 /*
724  * list all name=value entries on sp
725  * path==0 implies path=="/"
726  * flags==0 lists all values
727  * flags&R_OK lists readonly values
728  * flags&W_OK lists writeable values
729  * flags&X_OK lists writeable values in inputable form
730  */
731
732 void
733 astconflist __PARAM__((Sfio_t* sp, const char* path, int flags), (sp, path, flags)) __OTORP__(Sfio_t* sp; const char* path; int flags;){
734         char*           s;
735         Feature_t*      fp;
736         Lookup_t        look;
737         int             olderrno;
738
739         if (!path)
740                 path = "/";
741         else if (access(path, F_OK))
742         {
743                 liberror(lib, 2, "%s: not found", path);
744                 return;
745         }
746         olderrno = errno;
747         look.flags = 0;
748         if (!flags)
749                 flags = R_OK|W_OK;
750         else if (flags & X_OK)
751                 flags = W_OK|X_OK;
752         if (flags & R_OK)
753                 for (look.conf = (Conf_t*)conf; look.conf < (Conf_t*)&conf[conf_elements]; look.conf++)
754                         print(sp, &look, NiL, path);
755         if (flags & W_OK)
756                 for (fp = features; fp; fp = fp->next)
757                 {
758 #if HUH950401 /* don't get prefix happy */
759                         if (fp->standard >= 0)
760                                 sfprintf(sp, "_%s_", prefix[fp->standard].name);
761 #endif
762                         if (!*(s = feature(fp->name, path, NiL)))
763                                 s = "0";
764                         if (flags & X_OK) sfprintf(sp, "%s %s - %s\n", ID, fp->name, s); 
765                         else sfprintf(sp, "%s=%s\n", fp->name, s);
766                 }
767         errno = olderrno;
768 }