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