Doc.
[rsync/rsync.git] / popt-1.2 / popthelp.c
1 /* (C) 1998 Red Hat Software, Inc. -- Licensing details are in the COPYING
2    file accompanying popt source distributions, available from 
3    ftp://ftp.redhat.com/pub/code/popt */
4
5 #ifdef HAVE_CONFIG_H
6 #include "config.h"
7 #endif
8
9 #include <ctype.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13
14 #include "popt.h"
15 #include "poptint.h"
16
17 static void displayArgs(poptContext con, enum poptCallbackReason foo, 
18                         struct poptOption * key, 
19                         const char * arg, void * data) {
20     if (key->shortName== '?')
21         poptPrintHelp(con, stderr, 0);
22     else
23         poptPrintUsage(con, stderr, 0);
24     exit(0);
25 }
26
27 struct poptOption poptHelpOptions[] = {
28     { NULL, '\0', POPT_ARG_CALLBACK, &displayArgs, '\0', NULL },
29     { "help", '?', 0, NULL, '?', N_("Show this help message") },
30     { "usage", '\0', 0, NULL, 'u', N_("Display brief usage message") },
31     { NULL, '\0', 0, NULL, 0 }
32 } ;
33
34 static const char * getArgDescrip(const struct poptOption * opt) {
35     if (!(opt->argInfo & POPT_ARG_MASK)) return NULL;
36
37     if (opt == (poptHelpOptions + 1) || opt == (poptHelpOptions + 2))
38         if (opt->argDescrip) return POPT_(opt->argDescrip);
39
40     if (opt->argDescrip) return _(opt->argDescrip);
41     return POPT_("ARG");
42 }
43
44 static void singleOptionHelp(FILE * f, int maxLeftCol, 
45                              const struct poptOption * opt) {
46     int indentLength = maxLeftCol + 5;
47     int lineLength = 79 - indentLength;
48     const char * help = _(opt->descrip);
49     int helpLength;
50     const char * ch;
51     char format[10];
52     char * left = alloca(maxLeftCol + 1);
53     const char * argDescrip = getArgDescrip(opt);
54
55     *left = '\0';
56     if (opt->longName && opt->shortName)
57         sprintf(left, "-%c, --%s", opt->shortName, opt->longName);
58     else if (opt->shortName) 
59         sprintf(left, "-%c", opt->shortName);
60     else if (opt->longName)
61         sprintf(left, "--%s", opt->longName);
62     if (!*left) return ;
63     if (argDescrip) {
64         strcat(left, "=");
65         strcat(left, argDescrip);
66     }
67
68     if (help)
69         fprintf(f,"  %-*s   ", maxLeftCol, left);
70     else {
71         fprintf(f,"  %s\n", left); 
72         return;
73     }
74
75     helpLength = strlen(help);
76     while (helpLength > lineLength) {
77         ch = help + lineLength - 1;
78         while (ch > help && !isspace(*ch)) ch--;
79         if (ch == help) break;          /* give up */
80         while (ch > (help + 1) && isspace(*ch)) ch--;
81         ch++;
82
83         sprintf(format, "%%.%ds\n%%%ds", (int) (ch - help), indentLength);
84         fprintf(f, format, help, " ");
85         help = ch;
86         while (isspace(*help) && *help) help++;
87         helpLength = strlen(help);
88     }
89
90     if (helpLength) fprintf(f, "%s\n", help);
91 }
92
93 static int maxArgWidth(const struct poptOption * opt) {
94     int max = 0;
95     int this;
96     const char * s;
97     
98     while (opt->longName || opt->shortName || opt->arg) {
99         if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
100             this = maxArgWidth(opt->arg);
101             if (this > max) max = this;
102         } else if (!(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
103             this = opt->shortName ? 2 : 0;
104             if (opt->longName) {
105                 if (this) this += 2;
106                 this += strlen(opt->longName) + 2;
107             }
108
109             s = getArgDescrip(opt);
110             if (s)
111                 this += strlen(s) + 1;
112             if (this > max) max = this;
113         }
114
115         opt++;
116     }
117     
118     return max;
119 }
120
121 static void singleTableHelp(FILE * f, const struct poptOption * table, 
122                             int left) {
123     const struct poptOption * opt;
124
125     opt = table;
126     while (opt->longName || opt->shortName || opt->arg) {
127         if ((opt->longName || opt->shortName) && 
128             !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN))
129             singleOptionHelp(f, left, opt);
130         opt++;
131     }
132
133     opt = table;
134     while (opt->longName || opt->shortName || opt->arg) {
135         if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
136             if (opt->descrip)
137                 fprintf(f, "\n%s\n", _(opt->descrip));
138             singleTableHelp(f, opt->arg, left);
139         }
140         opt++;
141     }
142 }
143
144 static int showHelpIntro(poptContext con, FILE * f) {
145     int len = 6;
146     char * fn;
147
148     fprintf(f, POPT_("Usage:"));
149     if (!(con->flags & POPT_CONTEXT_KEEP_FIRST)) {
150         fn = con->optionStack->argv[0];
151         if (strchr(fn, '/')) fn = strchr(fn, '/') + 1;
152         fprintf(f, " %s", fn);
153         len += strlen(fn) + 1;
154     }
155
156     return len;
157 }
158
159 void poptPrintHelp(poptContext con, FILE * f, int flags) {
160     int leftColWidth;
161
162     showHelpIntro(con, f);
163     if (con->otherHelp)
164         fprintf(f, " %s\n", con->otherHelp);
165     else
166         fprintf(f, " %s\n", POPT_("[OPTION...]"));
167
168     leftColWidth = maxArgWidth(con->options);
169     singleTableHelp(f, con->options, leftColWidth);
170 }
171
172 static int singleOptionUsage(FILE * f, int cursor, 
173                               const struct poptOption * opt) {
174     int len = 3;
175     char shortStr[2];
176     const char * item = shortStr;
177     const char * argDescrip = getArgDescrip(opt);
178
179     if (opt->shortName) {
180         if (!(opt->argInfo & POPT_ARG_MASK)) 
181             return cursor;      /* we did these already */
182         len++;
183         *shortStr = opt->shortName;
184         shortStr[1] = '\0';
185     } else if (opt->longName) {
186         len += 1 + strlen(opt->longName);
187         item = opt->longName;
188     }
189
190     if (len == 3) return cursor;
191
192     if (argDescrip) 
193         len += strlen(argDescrip) + 1;
194
195     if ((cursor + len) > 79) {
196         fprintf(f, "\n       ");
197         cursor = 7;
198     } 
199
200     fprintf(f, " [-%s%s%s%s]", opt->shortName ? "" : "-", item,
201             argDescrip ? (opt->shortName ? " " : "=") : "",
202             argDescrip ? argDescrip : "");
203
204     return cursor + len + 1;
205 }
206
207 int singleTableUsage(FILE * f, int cursor, const struct poptOption * table) {
208     const struct poptOption * opt;
209     
210     opt = table;
211     while (opt->longName || opt->shortName || opt->arg) {
212         if ((opt->longName || opt->shortName) && 
213             !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN))
214             cursor = singleOptionUsage(f, cursor, opt);
215         else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) 
216             cursor = singleTableUsage(f, cursor, opt->arg);
217         opt++;
218     }
219
220     return cursor;
221 }
222
223 static int showShortOptions(const struct poptOption * opt, FILE * f, 
224                             char * str) {
225     char s[300];                /* this is larger then the ascii set, so
226                                    it should do just fine */
227
228     if (!str) {
229         str = s;
230         memset(str, 0, sizeof(str));
231     }
232
233     while (opt->longName || opt->shortName || opt->arg) {
234         if (opt->shortName && !(opt->argInfo & POPT_ARG_MASK))
235             str[strlen(str)] = opt->shortName;
236         else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE)
237             showShortOptions(opt->arg, f, str);
238
239         opt++;
240     } 
241
242     if (s != str || !*s)
243         return 0;
244
245     fprintf(f, " [-%s]", s);
246     return strlen(s) + 4;
247 }
248
249 void poptPrintUsage(poptContext con, FILE * f, int flags) {
250     int cursor;
251
252     cursor = showHelpIntro(con, f);
253     cursor += showShortOptions(con->options, f, NULL);
254     singleTableUsage(f, cursor, con->options);
255
256     if (con->otherHelp) {
257         cursor += strlen(con->otherHelp) + 1;
258         if (cursor > 79) fprintf(f, "\n       ");
259         fprintf(f, " %s", con->otherHelp);
260     }
261
262     fprintf(f, "\n");
263 }
264
265 void poptSetOtherOptionHelp(poptContext con, const char * text) {
266     if (con->otherHelp) free(con->otherHelp);
267     con->otherHelp = strdup(text);
268 }