1*2775Sraf /*
2*2775Sraf * CDDL HEADER START
3*2775Sraf *
4*2775Sraf * The contents of this file are subject to the terms of the
5*2775Sraf * Common Development and Distribution License, Version 1.0 only
6*2775Sraf * (the "License"). You may not use this file except in compliance
7*2775Sraf * with the License.
8*2775Sraf *
9*2775Sraf * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*2775Sraf * or http://www.opensolaris.org/os/licensing.
11*2775Sraf * See the License for the specific language governing permissions
12*2775Sraf * and limitations under the License.
13*2775Sraf *
14*2775Sraf * When distributing Covered Code, include this CDDL HEADER in each
15*2775Sraf * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*2775Sraf * If applicable, add the following below this CDDL HEADER, with the
17*2775Sraf * fields enclosed by brackets "[]" replaced with your own identifying
18*2775Sraf * information: Portions Copyright [yyyy] [name of copyright owner]
19*2775Sraf *
20*2775Sraf * CDDL HEADER END
21*2775Sraf */
22*2775Sraf /*
23*2775Sraf * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24*2775Sraf * Use is subject to license terms.
25*2775Sraf */
26*2775Sraf
27*2775Sraf #pragma ident "%Z%%M% %I% %E% SMI"
28*2775Sraf
29*2775Sraf #include <stdio.h>
30*2775Sraf #include <ctype.h>
31*2775Sraf #include <stdlib.h>
32*2775Sraf #include <unistd.h>
33*2775Sraf #include <string.h>
34*2775Sraf #include <dlfcn.h>
35*2775Sraf #include <dirent.h>
36*2775Sraf #include <libgen.h>
37*2775Sraf #include <sys/param.h>
38*2775Sraf #include <errno.h>
39*2775Sraf
40*2775Sraf #include "parser.h"
41*2775Sraf #include "errlog.h"
42*2775Sraf
43*2775Sraf static char const *ARCH_I386 = "i386";
44*2775Sraf static char const *ARCH_SPARC = "sparc";
45*2775Sraf static char const *ARCH_SPARCV9 = "sparcv9";
46*2775Sraf static char const *ARCH_IA64 = "ia64";
47*2775Sraf static char const *ARCH_AMD64 = "amd64";
48*2775Sraf static char const *ARCH_ALL = "all";
49*2775Sraf
50*2775Sraf static int dofiles(const Translator_info *);
51*2775Sraf static int read_spec(const Translator_info *, char *);
52*2775Sraf
53*2775Sraf static int Curlineno;
54*2775Sraf
55*2775Sraf xlator_keyword_t *keywordlist;
56*2775Sraf
57*2775Sraf /*
58*2775Sraf * frontend entry point
59*2775Sraf * returns the number of errors encountered
60*2775Sraf */
61*2775Sraf int
frontend(const Translator_info * T_info)62*2775Sraf frontend(const Translator_info *T_info)
63*2775Sraf {
64*2775Sraf int retval, i = 0, errors = 0;
65*2775Sraf
66*2775Sraf keywordlist = xlator_init(T_info);
67*2775Sraf if (keywordlist == NULL) {
68*2775Sraf errlog(ERROR, "Error: Unable to get keywordlist\n");
69*2775Sraf return (1);
70*2775Sraf }
71*2775Sraf
72*2775Sraf if (T_info->ti_verbosity >= STATUS) {
73*2775Sraf errlog(STATUS, "interesting keywords:\n");
74*2775Sraf while (keywordlist[i].key != NULL) {
75*2775Sraf errlog(STATUS, "\t%s\n", keywordlist[i].key);
76*2775Sraf ++i;
77*2775Sraf };
78*2775Sraf }
79*2775Sraf
80*2775Sraf retval = xlator_startlib(T_info->ti_liblist);
81*2775Sraf switch (retval) {
82*2775Sraf case XLATOR_SKIP:
83*2775Sraf if (T_info->ti_verbosity >= STATUS)
84*2775Sraf errlog(STATUS, "Skipping %s\n", T_info->ti_liblist);
85*2775Sraf retval = 0;
86*2775Sraf break;
87*2775Sraf
88*2775Sraf case XLATOR_NONFATAL:
89*2775Sraf ++errors;
90*2775Sraf retval = 0;
91*2775Sraf break;
92*2775Sraf
93*2775Sraf case XLATOR_SUCCESS:
94*2775Sraf retval = dofiles(T_info);
95*2775Sraf errors += retval;
96*2775Sraf if ((retval = xlator_endlib()) != XLATOR_SUCCESS)
97*2775Sraf ++errors;
98*2775Sraf retval = 0;
99*2775Sraf break;
100*2775Sraf
101*2775Sraf default:
102*2775Sraf errlog(ERROR | FATAL,
103*2775Sraf "Error: Invalid return code from xlator_startlib()\n");
104*2775Sraf exit(1);
105*2775Sraf }
106*2775Sraf
107*2775Sraf if ((retval = xlator_end()) != XLATOR_SUCCESS)
108*2775Sraf ++errors;
109*2775Sraf
110*2775Sraf return (errors);
111*2775Sraf }
112*2775Sraf
113*2775Sraf /*
114*2775Sraf * dofiles(const Translator_info *T_info);
115*2775Sraf * iterate through files specified in the command line and process
116*2775Sraf * them one by one
117*2775Sraf * requires spec files to have a ".spec" suffix
118*2775Sraf * returns the number of errors;
119*2775Sraf */
120*2775Sraf static int
dofiles(const Translator_info * T_info)121*2775Sraf dofiles(const Translator_info *T_info)
122*2775Sraf {
123*2775Sraf int nfiles, flen, findex, retval = 0, errors = 0;
124*2775Sraf
125*2775Sraf nfiles = T_info->ti_nfiles;
126*2775Sraf
127*2775Sraf for (findex = 0; findex < nfiles; ++findex) {
128*2775Sraf flen = strlen(filelist[findex]);
129*2775Sraf if ((flen <= 5) ||
130*2775Sraf strcmp(&filelist[findex][flen-5], ".spec") != 0) {
131*2775Sraf errlog(ERROR,
132*2775Sraf "Error: File specified does not have the "
133*2775Sraf ".spec extension: %s\n", filelist[findex]);
134*2775Sraf ++errors;
135*2775Sraf continue;
136*2775Sraf };
137*2775Sraf retval = read_spec(T_info, filelist[findex]);
138*2775Sraf errors += retval;
139*2775Sraf }
140*2775Sraf return (errors);
141*2775Sraf }
142*2775Sraf
143*2775Sraf /*
144*2775Sraf * read_spec -
145*2775Sraf * Given a filename, this function will reads the spec file to
146*2775Sraf * recognize keywords which it passes along with the corresponding
147*2775Sraf * value to the back-end translator to process. The following
148*2775Sraf * back-end interfaces are called:
149*2775Sraf * xlator_startfile
150*2775Sraf * xlator_start_if
151*2775Sraf * xlator_take_kvpair
152*2775Sraf * xlator_end_if
153*2775Sraf * xlator_endfile
154*2775Sraf */
155*2775Sraf static int
read_spec(const Translator_info * T_info,char * spec_filename)156*2775Sraf read_spec(const Translator_info *T_info, char *spec_filename)
157*2775Sraf {
158*2775Sraf FILE *spec_fp;
159*2775Sraf Meta_info meta_info;
160*2775Sraf char key[BUFSIZ], *value = NULL, *p = NULL;
161*2775Sraf char *buf2 = NULL;
162*2775Sraf int retval = 0, errors = 0, ki = 0; /* keyword indicator */
163*2775Sraf int start_if_fail = 0, skip_if = 0;
164*2775Sraf int extends_err = 0;
165*2775Sraf
166*2775Sraf meta_info.mi_ext_cnt = 0; /* All info is non-extends */
167*2775Sraf meta_info.mi_flags = 0;
168*2775Sraf
169*2775Sraf retval = xlator_startfile(spec_filename);
170*2775Sraf
171*2775Sraf switch (retval) {
172*2775Sraf case XLATOR_SKIP:
173*2775Sraf if (T_info->ti_verbosity >= WARNING)
174*2775Sraf errlog(WARNING, "Warning: Skipping %s\n",
175*2775Sraf spec_filename);
176*2775Sraf return (errors);
177*2775Sraf
178*2775Sraf case XLATOR_NONFATAL:
179*2775Sraf errlog(ERROR, "Error in xlator_startfile\n");
180*2775Sraf ++errors;
181*2775Sraf return (errors);
182*2775Sraf
183*2775Sraf case XLATOR_SUCCESS:
184*2775Sraf break;
185*2775Sraf
186*2775Sraf default:
187*2775Sraf errlog(ERROR,
188*2775Sraf "Error: Invalid return code from xlator_startfile()\n");
189*2775Sraf ++errors;
190*2775Sraf return (errors);
191*2775Sraf };
192*2775Sraf
193*2775Sraf /* file processing */
194*2775Sraf spec_fp = fopen(spec_filename, "r");
195*2775Sraf if (spec_fp == NULL) {
196*2775Sraf errlog(ERROR, "Error: Unable to open spec file %s: %s\n",
197*2775Sraf spec_filename, strerror(errno));
198*2775Sraf ++errors;
199*2775Sraf return (errors);
200*2775Sraf }
201*2775Sraf
202*2775Sraf (void) strncpy(meta_info.mi_filename, spec_filename, BUFSIZ);
203*2775Sraf meta_info.mi_line_number = 0;
204*2775Sraf Curlineno = meta_info.mi_line_number;
205*2775Sraf while (meta_info.mi_nlines = readline(&buf2, spec_fp)) {
206*2775Sraf meta_info.mi_line_number += meta_info.mi_nlines;
207*2775Sraf Curlineno = meta_info.mi_line_number;
208*2775Sraf if (!non_empty(buf2)) {
209*2775Sraf free(buf2);
210*2775Sraf buf2 = NULL;
211*2775Sraf continue;
212*2775Sraf }
213*2775Sraf p = realloc(value, sizeof (char)*(strlen(buf2)+1));
214*2775Sraf if (p == NULL) {
215*2775Sraf errlog(ERROR | FATAL,
216*2775Sraf "Error: Unable to allocate memory for "
217*2775Sraf "value: %d\n", errno);
218*2775Sraf }
219*2775Sraf value = p;
220*2775Sraf split(buf2, key, value);
221*2775Sraf ki = interesting_keyword(keywordlist, key);
222*2775Sraf switch (ki) {
223*2775Sraf case XLATOR_KW_FUNC: /* Function keyword */
224*2775Sraf case XLATOR_KW_DATA: /* Data keyword */
225*2775Sraf meta_info.mi_extended = 0;
226*2775Sraf retval = xlator_start_if(meta_info, ki, value);
227*2775Sraf switch (retval) {
228*2775Sraf case XLATOR_FATAL: /* FATAL ERROR */
229*2775Sraf if (T_info->ti_verbosity >= STATUS) {
230*2775Sraf errlog(STATUS,
231*2775Sraf "Error in xlator_start_if: ");
232*2775Sraf }
233*2775Sraf ++errors;
234*2775Sraf return (errors);
235*2775Sraf case XLATOR_NONFATAL: /* NON-FATAL ERROR */
236*2775Sraf if (T_info->ti_verbosity >= STATUS)
237*2775Sraf errlog(STATUS,
238*2775Sraf "Error in xlator_start_if\n");
239*2775Sraf ++errors;
240*2775Sraf start_if_fail = 1;
241*2775Sraf break;
242*2775Sraf case XLATOR_SUCCESS: /* OK */
243*2775Sraf start_if_fail = 0;
244*2775Sraf extends_err = check4extends(spec_filename,
245*2775Sraf value, T_info->ti_archtoken, spec_fp);
246*2775Sraf switch (extends_err) {
247*2775Sraf case -1: /* Error */
248*2775Sraf errlog(ERROR, "\"%s\", line %d: "
249*2775Sraf "Error occurred while "
250*2775Sraf "checking for extends clause\n",
251*2775Sraf spec_filename, Curlineno);
252*2775Sraf ++errors;
253*2775Sraf /*FALLTHRU*/
254*2775Sraf case 0: /* No Extends */
255*2775Sraf break;
256*2775Sraf case 1: /* Extends */
257*2775Sraf meta_info.mi_extended = 1;
258*2775Sraf extends_err = do_extends(meta_info,
259*2775Sraf T_info, value);
260*2775Sraf if (extends_err) {
261*2775Sraf errors += extends_err;
262*2775Sraf }
263*2775Sraf break;
264*2775Sraf default: /* Programmer Error */
265*2775Sraf errlog(ERROR | FATAL,
266*2775Sraf "Error: invalid return from "
267*2775Sraf "check4extends %d\n", extends_err);
268*2775Sraf }
269*2775Sraf break;
270*2775Sraf case XLATOR_SKIP: /* SKIP */
271*2775Sraf if (T_info->ti_verbosity >= WARNING)
272*2775Sraf errlog(WARNING, "Warning: Skipping "
273*2775Sraf "interface %s\n", value);
274*2775Sraf skip_if = 1;
275*2775Sraf start_if_fail = 0;
276*2775Sraf break;
277*2775Sraf default:
278*2775Sraf /* Invalid Return */
279*2775Sraf errlog(ERROR | FATAL,
280*2775Sraf "Error: Invalid return code "
281*2775Sraf "from xlator_start_if (): %d\n", retval);
282*2775Sraf }
283*2775Sraf break;
284*2775Sraf case XLATOR_KW_END: /* END keyword */
285*2775Sraf if (start_if_fail == 0 && skip_if == 0) {
286*2775Sraf retval = xlator_end_if(meta_info, value);
287*2775Sraf if (retval)
288*2775Sraf ++errors;
289*2775Sraf }
290*2775Sraf skip_if = 0;
291*2775Sraf break;
292*2775Sraf case XLATOR_KW_NOTFOUND:
293*2775Sraf if (T_info->ti_verbosity >= TRACING)
294*2775Sraf errlog(TRACING, "uninteresting keyword: %s\n",
295*2775Sraf key);
296*2775Sraf break;
297*2775Sraf default:
298*2775Sraf if (skip_if == 0 && start_if_fail == 0) {
299*2775Sraf retval = xlator_take_kvpair(meta_info,
300*2775Sraf ki, value);
301*2775Sraf if (retval) {
302*2775Sraf if (T_info->ti_verbosity >= STATUS)
303*2775Sraf errlog(STATUS, "Error in "
304*2775Sraf "xlator_take_kvpair\n");
305*2775Sraf ++errors;
306*2775Sraf }
307*2775Sraf }
308*2775Sraf }
309*2775Sraf free(buf2);
310*2775Sraf buf2 = NULL;
311*2775Sraf }
312*2775Sraf
313*2775Sraf if ((retval = xlator_endfile()) != XLATOR_SUCCESS) {
314*2775Sraf if (T_info->ti_verbosity >= STATUS)
315*2775Sraf errlog(STATUS, "Error in xlator_endfile\n");
316*2775Sraf ++errors;
317*2775Sraf }
318*2775Sraf free(p);
319*2775Sraf (void) fclose(spec_fp);
320*2775Sraf return (errors);
321*2775Sraf }
322*2775Sraf
323*2775Sraf /*
324*2775Sraf * interesting_keyword(char **keywordlist, const char *key) {
325*2775Sraf * returns the token associated with key if key is found in keywordlist
326*2775Sraf * returns XLATOR_KW_NOTFOUND if key is NOT found in keywordlist
327*2775Sraf * "Function" and "End" are always interesting, return XLATOR_KW_FUNC
328*2775Sraf * and XLATOR_KW_DATA respectively;
329*2775Sraf * "End" is always interesting, return XLATOR_KW_END;
330*2775Sraf *
331*2775Sraf */
332*2775Sraf int
interesting_keyword(xlator_keyword_t * keywordlist,const char * key)333*2775Sraf interesting_keyword(xlator_keyword_t *keywordlist, const char *key)
334*2775Sraf {
335*2775Sraf int i = 0;
336*2775Sraf
337*2775Sraf if (strcasecmp(key, "data") == 0) {
338*2775Sraf return (XLATOR_KW_DATA);
339*2775Sraf }
340*2775Sraf if (strcasecmp(key, "function") == 0) {
341*2775Sraf return (XLATOR_KW_FUNC);
342*2775Sraf }
343*2775Sraf
344*2775Sraf if (strcasecmp(key, "end") == 0)
345*2775Sraf return (XLATOR_KW_END);
346*2775Sraf
347*2775Sraf while (keywordlist[i].key != NULL) {
348*2775Sraf if (strcasecmp(keywordlist[i].key, key) == 0)
349*2775Sraf return (keywordlist[i].token);
350*2775Sraf ++i;
351*2775Sraf }
352*2775Sraf return (XLATOR_KW_NOTFOUND);
353*2775Sraf }
354*2775Sraf
355*2775Sraf /*
356*2775Sraf * line_to_buf(char *dest, const char *src) {
357*2775Sraf * appends src to dest, dynamically increasing the size of dest.
358*2775Sraf * replaces the trailing '\' continuation character with a space.
359*2775Sraf *
360*2775Sraf * if src is continuation of dest, dest != NULL, and
361*2775Sraf * the last character in dest before the newline must be a `\'
362*2775Sraf * if src is not continuation of dest, then dest must be NULL
363*2775Sraf */
364*2775Sraf char *
line_to_buf(char * dest,const char * src)365*2775Sraf line_to_buf(char *dest, const char *src)
366*2775Sraf {
367*2775Sraf int slen = strlen(src);
368*2775Sraf int dlen;
369*2775Sraf
370*2775Sraf if (dest == NULL) {
371*2775Sraf /* We're being called for the first time */
372*2775Sraf dest = malloc(sizeof (char) * (slen + 1));
373*2775Sraf if (dest == NULL) {
374*2775Sraf errlog(ERROR | FATAL,
375*2775Sraf "Error: Unable to allocate memory for dest\n");
376*2775Sraf }
377*2775Sraf (void) strcpy(dest, src);
378*2775Sraf return (dest);
379*2775Sraf }
380*2775Sraf
381*2775Sraf dlen = strlen(dest);
382*2775Sraf
383*2775Sraf dest = realloc(dest, (size_t)(sizeof (char) * (dlen+slen+1)));
384*2775Sraf if (dest == NULL) {
385*2775Sraf errlog(ERROR | FATAL,
386*2775Sraf "Error: Unable to allocate memory for dest\n");
387*2775Sraf }
388*2775Sraf
389*2775Sraf if (dlen > 1) {
390*2775Sraf /*
391*2775Sraf * remove continuation character
392*2775Sraf * we replace the '\' from the previous line with a space
393*2775Sraf */
394*2775Sraf if (dest[dlen-2] == '\\') {
395*2775Sraf dest[dlen-2] = ' ';
396*2775Sraf }
397*2775Sraf }
398*2775Sraf
399*2775Sraf /* join the two strings */
400*2775Sraf (void) strcat(dest, src);
401*2775Sraf
402*2775Sraf return (dest);
403*2775Sraf }
404*2775Sraf
405*2775Sraf /*
406*2775Sraf * non_empty(const char *str)
407*2775Sraf * assumes str is non null
408*2775Sraf * checks if str is a non empty string
409*2775Sraf * returns 1 if string contains non whitespace
410*2775Sraf * returns 0 if string contains only whitespace
411*2775Sraf */
412*2775Sraf int
non_empty(const char * str)413*2775Sraf non_empty(const char *str)
414*2775Sraf {
415*2775Sraf while (*str != '\0') {
416*2775Sraf if (!isspace(*str))
417*2775Sraf return (1);
418*2775Sraf ++str;
419*2775Sraf };
420*2775Sraf return (0);
421*2775Sraf }
422*2775Sraf
423*2775Sraf /*
424*2775Sraf * split(const char *line, char *key, char *value);
425*2775Sraf * splits the line into keyword (key) and value pair
426*2775Sraf */
427*2775Sraf void
split(const char * line,char * key,char * value)428*2775Sraf split(const char *line, char *key, char *value)
429*2775Sraf {
430*2775Sraf char *p;
431*2775Sraf
432*2775Sraf p = (char *)line;
433*2775Sraf
434*2775Sraf /* skip leading whitespace */
435*2775Sraf while (isspace(*p)&& *p != '\0')
436*2775Sraf ++p;
437*2775Sraf
438*2775Sraf /* copy keyword from line into key */
439*2775Sraf while (!isspace(*p) && *p != '\0')
440*2775Sraf *key++ = *p++;
441*2775Sraf
442*2775Sraf *key = '\0';
443*2775Sraf
444*2775Sraf /* skip whitespace */
445*2775Sraf while (isspace(*p) && *p != '\0')
446*2775Sraf p++;
447*2775Sraf
448*2775Sraf (void) strcpy(value, p);
449*2775Sraf
450*2775Sraf }
451*2775Sraf
452*2775Sraf /*
453*2775Sraf * check4extends(char *filename, char *value, int arch, FILE *fp)
454*2775Sraf * if no arch keyword is found or there is a MATCHING arch keyword
455*2775Sraf * returns 1 if value is of the form "data|function name extends"
456*2775Sraf * -1 for error
457*2775Sraf * 0 no other keyword after the function name
458*2775Sraf * else
459*2775Sraf * return 0
460*2775Sraf *
461*2775Sraf * filename is used only for error reporting
462*2775Sraf */
463*2775Sraf int
check4extends(const char * filename,const char * value,int arch,FILE * fp)464*2775Sraf check4extends(const char *filename, const char *value, int arch, FILE *fp)
465*2775Sraf {
466*2775Sraf char fun[BUFSIZ];
467*2775Sraf char extends[BUFSIZ];
468*2775Sraf int n;
469*2775Sraf
470*2775Sraf if (arch_match(fp, arch)) {
471*2775Sraf split(value, fun, extends);
472*2775Sraf n = strlen(extends);
473*2775Sraf if (extends[n-1] == '\n')
474*2775Sraf extends[n-1] = '\0';
475*2775Sraf if (strncasecmp("extends", extends, 7) == 0) {
476*2775Sraf return (1);
477*2775Sraf } else {
478*2775Sraf if (*extends != '\0') {
479*2775Sraf errlog(ERROR, "\"%s\", line %d: Error: "
480*2775Sraf "Trailing garbage after function name\n",
481*2775Sraf filename, Curlineno);
482*2775Sraf return (-1);
483*2775Sraf }
484*2775Sraf }
485*2775Sraf }
486*2775Sraf return (0);
487*2775Sraf }
488*2775Sraf
489*2775Sraf /*
490*2775Sraf * remcomment (char *buf)
491*2775Sraf * replace comments with single whitespace
492*2775Sraf */
493*2775Sraf /* XXX: There is currently no way to escape a comment character */
494*2775Sraf void
remcomment(char const * buf)495*2775Sraf remcomment(char const *buf)
496*2775Sraf {
497*2775Sraf char *p;
498*2775Sraf p = strchr(buf, '#');
499*2775Sraf if (p) {
500*2775Sraf *p = ' ';
501*2775Sraf *(p+1) = '\0';
502*2775Sraf }
503*2775Sraf }
504*2775Sraf
505*2775Sraf /*
506*2775Sraf * arch_strtoi()
507*2775Sraf *
508*2775Sraf * input: string
509*2775Sraf * return: XLATOR_I386 if string == ARCH_I386
510*2775Sraf * XLATOR_SPARC if string == ARCH_SPARC
511*2775Sraf * XLATOR_SPARCV9 if string == ARCH_SPARCV9
512*2775Sraf * XLATOR_IA64 if string == ARCH_IA64
513*2775Sraf * XLATOR_AMD64 if string == ARCH_AMD64
514*2775Sraf * XLATOR_ALLARCH if string == ARCH_ALL
515*2775Sraf * 0 if outside the known set {i386, sparc, sparcv9, ia64, amd64}.
516*2775Sraf */
517*2775Sraf int
arch_strtoi(const char * arch_str)518*2775Sraf arch_strtoi(const char *arch_str)
519*2775Sraf {
520*2775Sraf if (arch_str != NULL) {
521*2775Sraf if (strcmp(arch_str, ARCH_I386) == 0)
522*2775Sraf return (XLATOR_I386);
523*2775Sraf else if (strcmp(arch_str, ARCH_SPARC) == 0)
524*2775Sraf return (XLATOR_SPARC);
525*2775Sraf else if (strcmp(arch_str, ARCH_SPARCV9) == 0)
526*2775Sraf return (XLATOR_SPARCV9);
527*2775Sraf else if (strcmp(arch_str, ARCH_IA64) == 0)
528*2775Sraf return (XLATOR_IA64);
529*2775Sraf else if (strcmp(arch_str, ARCH_AMD64) == 0)
530*2775Sraf return (XLATOR_AMD64);
531*2775Sraf else if (strcmp(arch_str, ARCH_ALL) == 0)
532*2775Sraf return (XLATOR_ALLARCH);
533*2775Sraf } else {
534*2775Sraf errlog(ERROR, "\"%s\", line %d: Error: "
535*2775Sraf "arch keyword with no value");
536*2775Sraf }
537*2775Sraf return (0);
538*2775Sraf }
539*2775Sraf
540*2775Sraf int
readline(char ** buffer,FILE * fp)541*2775Sraf readline(char **buffer, FILE *fp)
542*2775Sraf {
543*2775Sraf int nlines = 0;
544*2775Sraf int len;
545*2775Sraf char buf[BUFSIZ];
546*2775Sraf
547*2775Sraf if (fgets(buf, BUFSIZ, fp)) {
548*2775Sraf nlines++;
549*2775Sraf /* replace comments with single whitespace */
550*2775Sraf remcomment(buf);
551*2775Sraf
552*2775Sraf /* get complete line */
553*2775Sraf *buffer = line_to_buf(*buffer, buf); /* append buf to buffer */
554*2775Sraf len = strlen(buf);
555*2775Sraf if (len > 1) {
556*2775Sraf /* handle continuation lines */
557*2775Sraf while (buf[len-2] == '\\') {
558*2775Sraf if (!fgets(buf, BUFSIZ, fp)) {
559*2775Sraf *buffer = line_to_buf(*buffer, buf);
560*2775Sraf break;
561*2775Sraf }
562*2775Sraf nlines++;
563*2775Sraf len = strlen(buf);
564*2775Sraf *buffer = line_to_buf(*buffer, buf);
565*2775Sraf }
566*2775Sraf } /* end of 'get complete line' */
567*2775Sraf }
568*2775Sraf return (nlines);
569*2775Sraf }
570