1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */ 2 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 7#include "system.h" 8#include "poptint.h" 9 10static void displayArgs(poptContext con, 11 /*@unused@*/ enum poptCallbackReason foo, 12 struct poptOption * key, 13 /*@unused@*/ const char * arg, /*@unused@*/ void * data) { 14 if (key->shortName== '?') 15 poptPrintHelp(con, stdout, 0); 16 else 17 poptPrintUsage(con, stdout, 0); 18 exit(0); 19} 20 21struct poptOption poptHelpOptions[] = { 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 } 26} ; 27 28 29/*@observer@*/ /*@null@*/ static const char * 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 * 45getArgDescrip(const struct poptOption * opt, const char *translation_domain) 46{ 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 52 if (opt->argDescrip) return D_(translation_domain, opt->argDescrip); 53 return POPT_("ARG"); 54} 55 56static void singleOptionHelp(FILE * f, int maxLeftCol, 57 const struct poptOption * opt, 58 const char *translation_domain) { 59 int indentLength = maxLeftCol + 5; 60 int lineLength = 79 - indentLength; 61 const char * help = D_(translation_domain, opt->descrip); 62 int helpLength; 63 const char * ch; 64 char format[10]; 65 char * left; 66 const char * argDescrip = getArgDescrip(opt, translation_domain); 67 68 left = malloc(maxLeftCol + 1); 69 *left = '\0'; 70 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); 87 goto out; 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); 106 107out: 108 free(left); 109} 110 111static int maxArgWidth(const struct poptOption * opt, 112 const char * translation_domain) { 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) { 119 this = maxArgWidth(opt->arg, translation_domain); 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 128 s = getArgDescrip(opt, translation_domain); 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, 141 int left, 142 const char *translation_domain) { 143 const struct poptOption * opt; 144 const char *sub_transdom; 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)) 150 singleOptionHelp(f, left, opt, translation_domain); 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) { 157 sub_transdom = getTableTranslationDomain(opt->arg); 158 if(!sub_transdom) 159 sub_transdom = translation_domain; 160 161 if (opt->descrip) 162 fprintf(f, "\n%s\n", D_(sub_transdom, opt->descrip)); 163 164 singleTableHelp(f, opt->arg, left, sub_transdom); 165 } 166 opt++; 167 } 168} 169 170static int showHelpIntro(poptContext con, FILE * f) { 171 int len = 6; 172 const char * fn; 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 185void poptPrintHelp(poptContext con, FILE * f, /*@unused@*/ int flags) { 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 194 leftColWidth = maxArgWidth(con->options, NULL); 195 singleTableHelp(f, con->options, leftColWidth, NULL); 196} 197 198static int singleOptionUsage(FILE * f, int cursor, 199 const struct poptOption * opt, 200 const char *translation_domain) { 201 int len = 3; 202 char shortStr[2] = { '\0', '\0' }; 203 const char * item = shortStr; 204 const char * argDescrip = getArgDescrip(opt, translation_domain); 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 234static int singleTableUsage(FILE * f, int cursor, const struct poptOption * table, 235 const char *translation_domain) { 236 const struct poptOption * opt; 237 238 opt = table; 239 while (opt->longName || opt->shortName || opt->arg) { 240 if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INTL_DOMAIN) 241 translation_domain = (const char *)opt->arg; 242 else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) 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 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 260 s[0] = '\0'; 261 if (str == NULL) { 262 memset(s, 0, sizeof(s)); 263 str = s; 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 282void poptPrintUsage(poptContext con, FILE * f, /*@unused@*/ int flags) { 283 int cursor; 284 285 cursor = showHelpIntro(con, f); 286 cursor += showShortOptions(con->options, f, NULL); 287 singleTableUsage(f, cursor, con->options, NULL); 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) { 299 if (con->otherHelp) xfree(con->otherHelp); 300 con->otherHelp = xstrdup(text); 301} 302