A couple more unsigned char changes to silence compiler warnings
[rsync/rsync.git] / popt / poptconfig.c
1 /** \ingroup popt
2  * \file popt/poptconfig.c
3  */
4
5 /* (C) 1998-2000 Red Hat, Inc. -- Licensing details are in the COPYING
6    file accompanying popt source distributions, available from 
7    ftp://ftp.rpm.org/pub/rpm/dist. */
8
9 #include "system.h"
10 #include "poptint.h"
11
12 /*@-compmempass@*/      /* FIX: item->option.longName kept, not dependent. */
13 static void configLine(poptContext con, unsigned char * line)
14         /*@modifies con @*/
15 {
16     /*@-type@*/
17     int nameLength = strlen(con->appName);
18     /*@=type@*/
19     const char * entryType;
20     const char * opt;
21     poptItem item = (poptItem) alloca(sizeof(*item));
22     int i, j;
23     
24     memset(item, 0, sizeof(*item));
25
26     /*@-type@*/
27     if (strncmp(line, con->appName, nameLength)) return;
28     /*@=type@*/
29
30     line += nameLength;
31     if (*line == '\0' || !isspace(*line)) return;
32
33     while (*line != '\0' && isspace(*line)) line++;
34     entryType = line;
35     while (*line == '\0' || !isspace(*line)) line++;
36     *line++ = '\0';
37
38     while (*line != '\0' && isspace(*line)) line++;
39     if (*line == '\0') return;
40     opt = line;
41     while (*line == '\0' || !isspace(*line)) line++;
42     *line++ = '\0';
43
44     while (*line != '\0' && isspace(*line)) line++;
45     if (*line == '\0') return;
46
47     /*@-temptrans@*/ /* FIX: line alias is saved */
48     if (opt[0] == '-' && opt[1] == '-')
49         item->option.longName = opt + 2;
50     else if (opt[0] == '-' && opt[2] == '\0')
51         item->option.shortName = opt[1];
52     /*@=temptrans@*/
53
54     if (poptParseArgvString(line, &item->argc, &item->argv)) return;
55
56     /*@-modobserver@*/
57     item->option.argInfo = POPT_ARGFLAG_DOC_HIDDEN;
58     for (i = 0, j = 0; i < item->argc; i++, j++) {
59         const char * f;
60         if (!strncmp(item->argv[i], "--POPTdesc=", sizeof("--POPTdesc=")-1)) {
61             f = item->argv[i] + sizeof("--POPTdesc=");
62             if (f[0] == '$' && f[1] == '"') f++;
63             item->option.descrip = f;
64             item->option.argInfo &= ~POPT_ARGFLAG_DOC_HIDDEN;
65             j--;
66         } else
67         if (!strncmp(item->argv[i], "--POPTargs=", sizeof("--POPTargs=")-1)) {
68             f = item->argv[i] + sizeof("--POPTargs=");
69             if (f[0] == '$' && f[1] == '"') f++;
70             item->option.argDescrip = f;
71             item->option.argInfo &= ~POPT_ARGFLAG_DOC_HIDDEN;
72             item->option.argInfo |= POPT_ARG_STRING;
73             j--;
74         } else
75         if (j != i)
76             item->argv[j] = item->argv[i];
77     }
78     if (j != i) {
79         item->argv[j] = NULL;
80         item->argc = j;
81     }
82     /*@=modobserver@*/
83         
84     /*@-nullstate@*/ /* FIX: item->argv[] may be NULL */
85     if (!strcmp(entryType, "alias"))
86         (void) poptAddItem(con, item, 0);
87     else if (!strcmp(entryType, "exec"))
88         (void) poptAddItem(con, item, 1);
89     /*@=nullstate@*/
90 }
91 /*@=compmempass@*/
92
93 int poptReadConfigFile(poptContext con, const char * fn)
94 {
95     const unsigned char * file, * chptr, * end;
96     unsigned char * buf;
97 /*@dependent@*/ unsigned char * dst;
98     int fd, rc;
99     off_t fileLength;
100
101     fd = open(fn, O_RDONLY);
102     if (fd < 0)
103         return (errno == ENOENT ? 0 : POPT_ERROR_ERRNO);
104
105     fileLength = lseek(fd, 0, SEEK_END);
106     if (fileLength == -1 || lseek(fd, 0, 0) == -1) {
107         rc = errno;
108         (void) close(fd);
109         /*@-mods@*/
110         errno = rc;
111         /*@=mods@*/
112         return POPT_ERROR_ERRNO;
113     }
114
115     file = alloca(fileLength + 1);
116     if (read(fd, (char *)file, fileLength) != fileLength) {
117         rc = errno;
118         (void) close(fd);
119         /*@-mods@*/
120         errno = rc;
121         /*@=mods@*/
122         return POPT_ERROR_ERRNO;
123     }
124     if (close(fd) == -1)
125         return POPT_ERROR_ERRNO;
126
127     dst = buf = alloca(fileLength + 1);
128
129     chptr = file;
130     end = (file + fileLength);
131     /*@-infloops@*/     /* LCL: can't detect chptr++ */
132     while (chptr < end) {
133         switch (*chptr) {
134           case '\n':
135             *dst = '\0';
136             dst = buf;
137             while (*dst && isspace(*dst)) dst++;
138             if (*dst && *dst != '#')
139                 configLine(con, dst);
140             chptr++;
141             /*@switchbreak@*/ break;
142           case '\\':
143             *dst++ = *chptr++;
144             if (chptr < end) {
145                 if (*chptr == '\n') 
146                     dst--, chptr++;     
147                     /* \ at the end of a line does not insert a \n */
148                 else
149                     *dst++ = *chptr++;
150             }
151             /*@switchbreak@*/ break;
152           default:
153             *dst++ = *chptr++;
154             /*@switchbreak@*/ break;
155         }
156     }
157     /*@=infloops@*/
158
159     return 0;
160 }
161
162 int poptReadDefaultConfig(poptContext con, /*@unused@*/ UNUSED(int useEnv))
163 {
164     char * fn, * home;
165     int rc;
166
167     /*@-type@*/
168     if (!con->appName) return 0;
169     /*@=type@*/
170
171     rc = poptReadConfigFile(con, "/etc/popt");
172     if (rc) return rc;
173     if (getuid() != geteuid()) return 0;
174
175     if ((home = getenv("HOME"))) {
176         fn = alloca(strlen(home) + 20);
177         strcpy(fn, home);
178         strcat(fn, "/.popt");
179         rc = poptReadConfigFile(con, fn);
180         if (rc) return rc;
181     }
182
183     return 0;
184 }