Rob Landley | 187649d | 2016-02-10 23:06:12 -0600 | [diff] [blame] | 1 | //#include "toys.h" |
Rob Landley | 86cafe1 | 2014-01-03 18:23:09 -0600 | [diff] [blame] | 2 | |
Mike Frysinger | bef3a51 | 2016-02-29 13:13:38 -0600 | [diff] [blame] | 3 | #include <ctype.h> |
Rob Landley | 187649d | 2016-02-10 23:06:12 -0600 | [diff] [blame] | 4 | #include <stdio.h> |
| 5 | #include <string.h> |
| 6 | #include <stdlib.h> |
| 7 | #include <sys/types.h> |
| 8 | #include <sys/stat.h> |
| 9 | #include <unistd.h> |
| 10 | #include <regex.h> |
| 11 | #include <inttypes.h> |
| 12 | #include <termios.h> |
| 13 | #include <poll.h> |
Rob Landley | 3879cd9 | 2016-02-25 17:16:32 -0600 | [diff] [blame] | 14 | #include <sys/socket.h> |
Rob Landley | 187649d | 2016-02-10 23:06:12 -0600 | [diff] [blame] | 15 | struct statvfs {int i;}; |
| 16 | #include "lib/portability.h" |
| 17 | #include "lib/lib.h" |
| 18 | |
| 19 | // Humor toys.h (lie through our teeth, C's linker doesn't care). |
| 20 | char toys[4096], libbuf[4096], toybuf[4096]; |
Rob Landley | e5354ca | 2015-09-11 16:35:14 -0500 | [diff] [blame] | 21 | void show_help(FILE *out) {;} |
Rob Landley | 86cafe1 | 2014-01-03 18:23:09 -0600 | [diff] [blame] | 22 | void toy_exec(char *argv[]) {;} |
Rob Landley | 187649d | 2016-02-10 23:06:12 -0600 | [diff] [blame] | 23 | void toy_init(void *which, char *argv[]) {;} |
Rob Landley | 86cafe1 | 2014-01-03 18:23:09 -0600 | [diff] [blame] | 24 | |
| 25 | // Parse config files into data structures. |
| 26 | |
| 27 | struct symbol { |
| 28 | struct symbol *next; |
Rob Landley | c049bca | 2014-01-20 17:26:50 -0600 | [diff] [blame] | 29 | int enabled, help_indent; |
Rob Landley | 86cafe1 | 2014-01-03 18:23:09 -0600 | [diff] [blame] | 30 | char *name, *depends; |
| 31 | struct double_list *help; |
| 32 | } *sym; |
| 33 | |
Rob Landley | 187649d | 2016-02-10 23:06:12 -0600 | [diff] [blame] | 34 | // remove leading spaces |
Rob Landley | c049bca | 2014-01-20 17:26:50 -0600 | [diff] [blame] | 35 | char *trim(char *s) |
| 36 | { |
| 37 | while (isspace(*s)) s++; |
| 38 | |
| 39 | return s; |
| 40 | } |
| 41 | |
Rob Landley | 187649d | 2016-02-10 23:06:12 -0600 | [diff] [blame] | 42 | // if line starts with name (as whole word) return pointer after it, else NULL |
Rob Landley | 86cafe1 | 2014-01-03 18:23:09 -0600 | [diff] [blame] | 43 | char *keyword(char *name, char *line) |
| 44 | { |
| 45 | int len = strlen(name); |
| 46 | |
Rob Landley | c049bca | 2014-01-20 17:26:50 -0600 | [diff] [blame] | 47 | line = trim(line); |
Rob Landley | 86cafe1 | 2014-01-03 18:23:09 -0600 | [diff] [blame] | 48 | if (strncmp(name, line, len)) return 0; |
| 49 | line += len; |
| 50 | if (*line && !isspace(*line)) return 0; |
Rob Landley | c049bca | 2014-01-20 17:26:50 -0600 | [diff] [blame] | 51 | line = trim(line); |
Rob Landley | 86cafe1 | 2014-01-03 18:23:09 -0600 | [diff] [blame] | 52 | |
| 53 | return line; |
| 54 | } |
| 55 | |
Rob Landley | 187649d | 2016-02-10 23:06:12 -0600 | [diff] [blame] | 56 | // dlist_pop() freeing wrapper structure for you. |
Rob Landley | c049bca | 2014-01-20 17:26:50 -0600 | [diff] [blame] | 57 | char *dlist_zap(struct double_list **help) |
| 58 | { |
| 59 | struct double_list *dd = dlist_pop(help); |
| 60 | char *s = dd->data; |
| 61 | |
| 62 | free(dd); |
Rob Landley | 0432050 | 2014-01-29 23:47:53 -0600 | [diff] [blame] | 63 | |
Rob Landley | c049bca | 2014-01-20 17:26:50 -0600 | [diff] [blame] | 64 | return s; |
| 65 | } |
| 66 | |
Rob Landley | 0432050 | 2014-01-29 23:47:53 -0600 | [diff] [blame] | 67 | int zap_blank_lines(struct double_list **help) |
Rob Landley | c049bca | 2014-01-20 17:26:50 -0600 | [diff] [blame] | 68 | { |
Rob Landley | 0432050 | 2014-01-29 23:47:53 -0600 | [diff] [blame] | 69 | int got = 0; |
| 70 | |
| 71 | while (*help) { |
| 72 | char *s; |
| 73 | |
| 74 | s = trim((*help)->data); |
Rob Landley | c049bca | 2014-01-20 17:26:50 -0600 | [diff] [blame] | 75 | |
| 76 | if (*s) break; |
Rob Landley | 0432050 | 2014-01-29 23:47:53 -0600 | [diff] [blame] | 77 | got++; |
Rob Landley | c049bca | 2014-01-20 17:26:50 -0600 | [diff] [blame] | 78 | free(dlist_zap(help)); |
| 79 | } |
Rob Landley | 0432050 | 2014-01-29 23:47:53 -0600 | [diff] [blame] | 80 | |
| 81 | return got; |
| 82 | } |
| 83 | |
| 84 | // Collect "-a blah" description lines following a blank line (or start). |
| 85 | // Returns array of removed lines with *len entries (0 for none). |
| 86 | |
| 87 | // Moves *help to new start of text (in case dash lines were at beginning). |
| 88 | // Sets *from to where dash lines removed from (in case they weren't). |
| 89 | // Discards blank lines before and after dashlines. |
| 90 | |
| 91 | // If no prefix, *help NULL. If no postfix, *from == *help |
| 92 | // if no dashlines returned *from == *help. |
| 93 | |
| 94 | char **grab_dashlines(struct double_list **help, struct double_list **from, |
| 95 | int *len) |
| 96 | { |
| 97 | struct double_list *dd; |
| 98 | char *s, **list; |
| 99 | int count = 0; |
| 100 | |
| 101 | *len = 0; |
| 102 | zap_blank_lines(help); |
| 103 | *from = *help; |
| 104 | |
| 105 | // Find start of dash block. Must be at start or after blank line. |
| 106 | for (;;) { |
| 107 | s = trim((*from)->data); |
| 108 | if (*s == '-' && s[1] != '-' && !count) break; |
| 109 | |
| 110 | if (!*s) count = 0; |
| 111 | else count++; |
| 112 | |
| 113 | *from = (*from)->next; |
| 114 | if (*from == *help) return 0; |
| 115 | } |
| 116 | |
| 117 | // If there was whitespace before this, zap it. This can't take out *help |
| 118 | // because zap_blank_lines skipped blank lines, and we had to have at least |
| 119 | // one non-blank line (a dash line) to get this far. |
| 120 | while (!*trim((*from)->prev->data)) { |
| 121 | *from = (*from)->prev; |
| 122 | free(dlist_zap(from)); |
| 123 | } |
| 124 | |
| 125 | // Count number of dashlines, copy out to array, zap trailing whitespace |
| 126 | // If *help was at start of dashblock, move it with *from |
| 127 | count = 0; |
| 128 | dd = *from; |
| 129 | if (*help == *from) *help = 0; |
| 130 | for (;;) { |
| 131 | if (*trim(dd->data) != '-') break; |
| 132 | count++; |
| 133 | if (*from == (dd = dd->next)) break; |
| 134 | } |
| 135 | |
| 136 | list = xmalloc(sizeof(char *)*count); |
| 137 | *len = count; |
| 138 | while (count) list[--count] = dlist_zap(from); |
| 139 | |
| 140 | return list; |
Rob Landley | c049bca | 2014-01-20 17:26:50 -0600 | [diff] [blame] | 141 | } |
| 142 | |
Rob Landley | 86cafe1 | 2014-01-03 18:23:09 -0600 | [diff] [blame] | 143 | void parse(char *filename) |
| 144 | { |
| 145 | FILE *fp = xfopen(filename, "r"); |
| 146 | struct symbol *new = 0; |
Rob Landley | 86cafe1 | 2014-01-03 18:23:09 -0600 | [diff] [blame] | 147 | |
| 148 | for (;;) { |
| 149 | char *s, *line = NULL; |
| 150 | size_t len; |
| 151 | |
| 152 | // Read line, trim whitespace at right edge. |
| 153 | if (getline(&line, &len, fp) < 1) break; |
| 154 | s = line+strlen(line); |
| 155 | while (--s >= line) { |
| 156 | if (!isspace(*s)) break; |
| 157 | *s = 0; |
| 158 | } |
| 159 | |
| 160 | // source or config keyword at left edge? |
| 161 | if (*line && !isspace(*line)) { |
Rob Landley | 86cafe1 | 2014-01-03 18:23:09 -0600 | [diff] [blame] | 162 | if ((s = keyword("config", line))) { |
| 163 | new = xzalloc(sizeof(struct symbol)); |
| 164 | new->next = sym; |
| 165 | new->name = s; |
| 166 | sym = new; |
| 167 | } else if ((s = keyword("source", line))) parse(s); |
| 168 | |
| 169 | continue; |
| 170 | } |
| 171 | if (!new) continue; |
| 172 | |
Rob Landley | c049bca | 2014-01-20 17:26:50 -0600 | [diff] [blame] | 173 | if (sym && sym->help_indent) { |
| 174 | dlist_add(&(new->help), line); |
| 175 | if (sym->help_indent < 0) { |
| 176 | sym->help_indent = 0; |
| 177 | while (isspace(line[sym->help_indent])) sym->help_indent++; |
| 178 | } |
| 179 | } |
Rob Landley | 86cafe1 | 2014-01-03 18:23:09 -0600 | [diff] [blame] | 180 | else if ((s = keyword("depends", line)) && (s = keyword("on", s))) |
| 181 | new->depends = s; |
Rob Landley | c049bca | 2014-01-20 17:26:50 -0600 | [diff] [blame] | 182 | else if (keyword("help", line)) sym->help_indent = -1; |
Rob Landley | 86cafe1 | 2014-01-03 18:23:09 -0600 | [diff] [blame] | 183 | } |
| 184 | |
| 185 | fclose(fp); |
| 186 | } |
| 187 | |
Rob Landley | c049bca | 2014-01-20 17:26:50 -0600 | [diff] [blame] | 188 | int charsort(void *a, void *b) |
| 189 | { |
| 190 | char *aa = a, *bb = b; |
| 191 | |
| 192 | if (*aa < *bb) return -1; |
| 193 | if (*aa > *bb) return 1; |
| 194 | return 0; |
| 195 | } |
| 196 | |
Rob Landley | 0432050 | 2014-01-29 23:47:53 -0600 | [diff] [blame] | 197 | int dashsort(char **a, char **b) |
Rob Landley | c049bca | 2014-01-20 17:26:50 -0600 | [diff] [blame] | 198 | { |
Rob Landley | 0432050 | 2014-01-29 23:47:53 -0600 | [diff] [blame] | 199 | char *aa = *a, *bb = *b; |
Rob Landley | c049bca | 2014-01-20 17:26:50 -0600 | [diff] [blame] | 200 | |
| 201 | if (aa[1] < bb[1]) return -1; |
| 202 | if (aa[1] > bb[1]) return 1; |
| 203 | return 0; |
| 204 | } |
| 205 | |
Rob Landley | 0432050 | 2014-01-29 23:47:53 -0600 | [diff] [blame] | 206 | int dashlinesort(char **a, char **b) |
| 207 | { |
| 208 | return strcmp(*a, *b); |
| 209 | } |
| 210 | |
Rob Landley | 86cafe1 | 2014-01-03 18:23:09 -0600 | [diff] [blame] | 211 | int main(int argc, char *argv[]) |
| 212 | { |
| 213 | FILE *fp; |
Rob Landley | 86cafe1 | 2014-01-03 18:23:09 -0600 | [diff] [blame] | 214 | |
| 215 | if (argc != 3) { |
| 216 | fprintf(stderr, "usage: config2help Config.in .config\n"); |
| 217 | exit(1); |
| 218 | } |
| 219 | |
| 220 | // Read Config.in |
| 221 | parse(argv[1]); |
| 222 | |
| 223 | // read .config |
| 224 | fp = xfopen(argv[2], "r"); |
| 225 | for (;;) { |
| 226 | char *line = NULL; |
| 227 | size_t len; |
| 228 | |
| 229 | if (getline(&line, &len, fp) < 1) break; |
| 230 | if (!strncmp("CONFIG_", line, 7)) { |
Rob Landley | 2ded833 | 2014-01-15 09:38:31 -0600 | [diff] [blame] | 231 | struct symbol *try; |
| 232 | char *s = line+7; |
| 233 | |
Rob Landley | 86cafe1 | 2014-01-03 18:23:09 -0600 | [diff] [blame] | 234 | for (try=sym; try; try=try->next) { |
| 235 | len = strlen(try->name); |
| 236 | if (!strncmp(try->name, s, len) && s[len]=='=' && s[len+1]=='y') { |
| 237 | try->enabled++; |
| 238 | break; |
| 239 | } |
| 240 | } |
| 241 | } |
| 242 | } |
| 243 | |
Rob Landley | 2ded833 | 2014-01-15 09:38:31 -0600 | [diff] [blame] | 244 | // Collate help according to usage, depends, and .config |
| 245 | |
| 246 | // Loop through each entry, finding duplicate enabled "usage:" names |
Rob Landley | 0432050 | 2014-01-29 23:47:53 -0600 | [diff] [blame] | 247 | // This is in reverse order, so last entry gets collated with previous |
| 248 | // entry until we run out of matching pairs. |
Rob Landley | 2ded833 | 2014-01-15 09:38:31 -0600 | [diff] [blame] | 249 | for (;;) { |
| 250 | struct symbol *throw = 0, *catch; |
Rob Landley | c049bca | 2014-01-20 17:26:50 -0600 | [diff] [blame] | 251 | char *this, *that, *cusage, *tusage, *name; |
Rob Landley | 2ded833 | 2014-01-15 09:38:31 -0600 | [diff] [blame] | 252 | int len; |
| 253 | |
| 254 | // find a usage: name and collate all enabled entries with that name |
| 255 | for (catch = sym; catch; catch = catch->next) { |
| 256 | if (catch->enabled != 1) continue; |
Rob Landley | c049bca | 2014-01-20 17:26:50 -0600 | [diff] [blame] | 257 | if (catch->help && (that = keyword("usage:", catch->help->data))) { |
Rob Landley | 0432050 | 2014-01-29 23:47:53 -0600 | [diff] [blame] | 258 | struct double_list *cfrom, *tfrom, *anchor; |
| 259 | char *try, **cdashlines, **tdashlines; |
| 260 | int clen, tlen; |
Rob Landley | 2ded833 | 2014-01-15 09:38:31 -0600 | [diff] [blame] | 261 | |
Rob Landley | 0432050 | 2014-01-29 23:47:53 -0600 | [diff] [blame] | 262 | // Align usage: lines, finding a matching pair so we can suck help |
| 263 | // text out of throw into catch, copying from this to that |
Rob Landley | c049bca | 2014-01-20 17:26:50 -0600 | [diff] [blame] | 264 | if (!throw) name = that; |
| 265 | else if (strncmp(name, that, len) || !isspace(that[len])) continue; |
| 266 | catch->enabled++; |
| 267 | while (!isspace(*that) && *that) that++; |
| 268 | if (!throw) len = that-name; |
| 269 | that = trim(that); |
Rob Landley | 2ded833 | 2014-01-15 09:38:31 -0600 | [diff] [blame] | 270 | if (!throw) { |
| 271 | throw = catch; |
Rob Landley | c049bca | 2014-01-20 17:26:50 -0600 | [diff] [blame] | 272 | this = that; |
Rob Landley | 2ded833 | 2014-01-15 09:38:31 -0600 | [diff] [blame] | 273 | |
| 274 | continue; |
| 275 | } |
| 276 | |
Rob Landley | 0432050 | 2014-01-29 23:47:53 -0600 | [diff] [blame] | 277 | // Grab option description lines to collate from catch and throw |
Rob Landley | c049bca | 2014-01-20 17:26:50 -0600 | [diff] [blame] | 278 | tusage = dlist_zap(&throw->help); |
Rob Landley | 0432050 | 2014-01-29 23:47:53 -0600 | [diff] [blame] | 279 | tdashlines = grab_dashlines(&throw->help, &tfrom, &tlen); |
| 280 | cusage = dlist_zap(&catch->help); |
| 281 | cdashlines = grab_dashlines(&catch->help, &cfrom, &clen); |
| 282 | anchor = catch->help; |
Rob Landley | 2ded833 | 2014-01-15 09:38:31 -0600 | [diff] [blame] | 283 | |
Rob Landley | 0432050 | 2014-01-29 23:47:53 -0600 | [diff] [blame] | 284 | // If we've got both, collate and alphebetize |
| 285 | if (cdashlines && tdashlines) { |
| 286 | char **new = xmalloc(sizeof(char *)*(clen+tlen)); |
Rob Landley | c049bca | 2014-01-20 17:26:50 -0600 | [diff] [blame] | 287 | |
Rob Landley | 0432050 | 2014-01-29 23:47:53 -0600 | [diff] [blame] | 288 | memcpy(new, cdashlines, sizeof(char *)*clen); |
| 289 | memcpy(new+clen, tdashlines, sizeof(char *)*tlen); |
| 290 | free(cdashlines); |
| 291 | free(tdashlines); |
| 292 | qsort(new, clen+tlen, sizeof(char *), (void *)dashlinesort); |
| 293 | cdashlines = new; |
| 294 | |
| 295 | // If just one, make sure it's in catch. |
| 296 | } else if (tdashlines) cdashlines = tdashlines; |
| 297 | |
| 298 | // If throw had a prefix, insert it before dashlines, with a |
| 299 | // blank line if catch had a prefix. |
| 300 | if (tfrom && tfrom != throw->help) { |
| 301 | if (throw->help || catch->help) dlist_add(&cfrom, strdup("")); |
| 302 | else { |
| 303 | dlist_add(&cfrom, 0); |
| 304 | anchor = cfrom->prev; |
| 305 | } |
| 306 | while (throw->help && throw->help != tfrom) |
| 307 | dlist_add(&cfrom, dlist_zap(&throw->help)); |
| 308 | if (cfrom && cfrom->prev->data && *trim(cfrom->prev->data)) |
| 309 | dlist_add(&cfrom, strdup("")); |
| 310 | } |
| 311 | if (!anchor) { |
| 312 | dlist_add(&cfrom, 0); |
| 313 | anchor = cfrom->prev; |
| 314 | } |
| 315 | |
| 316 | // Splice sorted lines back in place |
| 317 | if (cdashlines) { |
| 318 | tlen += clen; |
| 319 | |
| 320 | for (clen = 0; clen < tlen; clen++) |
| 321 | dlist_add(&cfrom, cdashlines[clen]); |
| 322 | } |
| 323 | |
| 324 | // If there were no dashlines, text would be considered prefix, so |
| 325 | // the list is definitely no longer empty, so discard placeholder. |
| 326 | if (!anchor->data) dlist_zap(&anchor); |
| 327 | |
| 328 | // zap whitespace at end of catch help text |
| 329 | while (!*trim(anchor->prev->data)) { |
| 330 | anchor = anchor->prev; |
| 331 | free(dlist_zap(&anchor)); |
| 332 | } |
| 333 | |
| 334 | // Append trailing lines. |
| 335 | while (tfrom) dlist_add(&anchor, dlist_zap(&tfrom)); |
| 336 | |
| 337 | // Collate first [-abc] option block in usage: lines |
Rob Landley | c049bca | 2014-01-20 17:26:50 -0600 | [diff] [blame] | 338 | try = 0; |
| 339 | if (*this == '[' && this[1] == '-' && this[2] != '-' && |
| 340 | *that == '[' && that[1] == '-' && that[2] != '-') |
| 341 | { |
| 342 | char *from = this+2, *to = that+2; |
| 343 | int ff = strcspn(from, " ]"), tt = strcspn(to, " ]"); |
| 344 | |
| 345 | if (from[ff] == ']' && to[tt] == ']') { |
| 346 | try = xmprintf("[-%.*s%.*s] ", ff, from, tt, to); |
| 347 | qsort(try+2, ff+tt, 1, (void *)charsort); |
| 348 | this = trim(this+ff+3); |
| 349 | that = trim(that+tt+3); |
| 350 | } |
| 351 | } |
| 352 | |
Rob Landley | 0432050 | 2014-01-29 23:47:53 -0600 | [diff] [blame] | 353 | // The list is definitely no longer empty, so discard placeholder. |
| 354 | if (!anchor->data) dlist_zap(&anchor); |
| 355 | |
Rob Landley | c049bca | 2014-01-20 17:26:50 -0600 | [diff] [blame] | 356 | // Add new collated line (and whitespace). |
Rob Landley | 0432050 | 2014-01-29 23:47:53 -0600 | [diff] [blame] | 357 | dlist_add(&anchor, xmprintf("%*cusage: %.*s %s%s%s%s", |
Rob Landley | c049bca | 2014-01-20 17:26:50 -0600 | [diff] [blame] | 358 | catch->help_indent, ' ', len, name, try ? try : "", |
| 359 | this, *this ? " " : "", that)); |
Rob Landley | 0432050 | 2014-01-29 23:47:53 -0600 | [diff] [blame] | 360 | free(try); |
| 361 | dlist_add(&anchor, strdup("")); |
Rob Landley | c049bca | 2014-01-20 17:26:50 -0600 | [diff] [blame] | 362 | free(cusage); |
| 363 | free(tusage); |
Rob Landley | 2ded833 | 2014-01-15 09:38:31 -0600 | [diff] [blame] | 364 | throw->enabled = 0; |
Rob Landley | 0432050 | 2014-01-29 23:47:53 -0600 | [diff] [blame] | 365 | throw = catch; |
| 366 | throw->help = anchor->prev->prev; |
Rob Landley | 2ded833 | 2014-01-15 09:38:31 -0600 | [diff] [blame] | 367 | |
Rob Landley | 2ded833 | 2014-01-15 09:38:31 -0600 | [diff] [blame] | 368 | throw = catch; |
Rob Landley | c049bca | 2014-01-20 17:26:50 -0600 | [diff] [blame] | 369 | this = throw->help->data + throw->help_indent + 8 + len; |
Rob Landley | 2ded833 | 2014-01-15 09:38:31 -0600 | [diff] [blame] | 370 | } |
| 371 | } |
| 372 | |
| 373 | // Did we find one? |
| 374 | |
| 375 | if (!throw) break; |
Rob Landley | 2ded833 | 2014-01-15 09:38:31 -0600 | [diff] [blame] | 376 | } |
| 377 | |
Rob Landley | 86cafe1 | 2014-01-03 18:23:09 -0600 | [diff] [blame] | 378 | // Print out help #defines |
| 379 | while (sym) { |
| 380 | struct double_list *dd; |
| 381 | |
| 382 | if (sym->help) { |
Rob Landley | c049bca | 2014-01-20 17:26:50 -0600 | [diff] [blame] | 383 | int i; |
Rob Landley | 2ded833 | 2014-01-15 09:38:31 -0600 | [diff] [blame] | 384 | char *s = xstrdup(sym->name); |
Rob Landley | 86cafe1 | 2014-01-03 18:23:09 -0600 | [diff] [blame] | 385 | |
Rob Landley | 86cafe1 | 2014-01-03 18:23:09 -0600 | [diff] [blame] | 386 | for (i = 0; s[i]; i++) s[i] = tolower(s[i]); |
Rob Landley | 187649d | 2016-02-10 23:06:12 -0600 | [diff] [blame] | 387 | printf("#define HELP_%s \"", s); |
Rob Landley | 86cafe1 | 2014-01-03 18:23:09 -0600 | [diff] [blame] | 388 | free(s); |
| 389 | |
Rob Landley | 86cafe1 | 2014-01-03 18:23:09 -0600 | [diff] [blame] | 390 | dd = sym->help; |
Rob Landley | 86cafe1 | 2014-01-03 18:23:09 -0600 | [diff] [blame] | 391 | for (;;) { |
Rob Landley | c049bca | 2014-01-20 17:26:50 -0600 | [diff] [blame] | 392 | i = sym->help_indent; |
Rob Landley | 86cafe1 | 2014-01-03 18:23:09 -0600 | [diff] [blame] | 393 | |
| 394 | // Trim leading whitespace |
| 395 | s = dd->data; |
| 396 | while (isspace(*s) && i) { |
| 397 | s++; |
| 398 | i--; |
| 399 | } |
| 400 | for (i=0; s[i]; i++) { |
| 401 | if (s[i] == '"' || s[i] == '\\') putchar('\\'); |
| 402 | putchar(s[i]); |
| 403 | } |
Rob Landley | 2ded833 | 2014-01-15 09:38:31 -0600 | [diff] [blame] | 404 | putchar('\\'); |
| 405 | putchar('n'); |
Rob Landley | 86cafe1 | 2014-01-03 18:23:09 -0600 | [diff] [blame] | 406 | dd = dd->next; |
| 407 | if (dd == sym->help) break; |
| 408 | } |
Rob Landley | e6314da | 2014-04-07 12:53:24 -0500 | [diff] [blame] | 409 | printf("\"\n\n"); |
Rob Landley | 86cafe1 | 2014-01-03 18:23:09 -0600 | [diff] [blame] | 410 | } |
| 411 | sym = sym->next; |
| 412 | } |
Rob Landley | 1fb3ae7 | 2014-02-16 11:09:23 -0600 | [diff] [blame] | 413 | |
| 414 | return 0; |
Rob Landley | 86cafe1 | 2014-01-03 18:23:09 -0600 | [diff] [blame] | 415 | } |