#include "mwcc_decomp.h" typedef struct _Side { short offset; short width; char buffer[1024]; short bptr; short blen; short indent; short vrow; short vcol; unsigned char atEOL; unsigned char impInd; } Side; short helpExtras; unsigned char showedHelp; Side left; Side right; Side all; char **helptext; static char outLine[256]; static void Help_Output(Side *left, Side *right); static void Help_OutputSingle(Side *all); static void Help_Flush(); static void Side_Init(Side *s, short offset, short width) { memset(s, 0, sizeof(Side)); s->offset = offset; s->width = width; } static void Side_Print(Side *s, const char *format, ...) { char c; char *text; char buffer[1024]; va_list args; va_start(args, format); vsprintf(buffer, format, args); va_end(args); text = buffer; while (*text) { if (s->blen < 1024) { c = *(text++); if (c == '~' && *text == '~') { c = *MAINOPTCHAR; text++; } s->buffer[(s->bptr + s->blen) & 1023] = c; s->blen++; } else { if (s == &left) Help_Output(&left, &right); else Help_OutputSingle(&all); } } } static void Side_NewLine(Side *s) { Side_Print(s, "\n"); } static void Side_Indent(Side *s, short how) { if ((s->width - s->indent - how) > (parseopts.ioCols / 8)) s->indent += how; else if ((s->width - s->indent - 1) > (parseopts.ioCols / 10)) s->indent++; } static void Side_Outdent(Side *s, short how) { if ((s->width - s->indent) < (parseopts.ioCols / 8)) s->indent++; else if (s->indent >= how) s->indent -= how; } static unsigned char isBreaker(char c) { return (c == 10) || (c == 13) || (c == 32) || (c == 9) || (c == 8) || (c == '|'); } static void Side_DumpLine(Side *s) { short col; short len; short afterspace; short eol; short ind; char c; eol = 0; ind = 0; col = s->offset + s->indent; s->vcol = s->indent; len = 0; afterspace = s->width - s->indent; while (s->blen > 0 && s->vcol < s->width && !eol && !ind) { c = s->buffer[s->bptr]; outLine[col + len] = c; s->vcol++; len++; if (isBreaker(c)) { afterspace = len; eol = (c == '\n') || (c == '\r'); eol += (c == '\r'); ind = (c == '\b') || (c == '\t'); ind += (c == '\b'); } s->bptr = (s->bptr + 1) & 1023; s->blen--; } if (s->blen || eol || ind) { s->blen += len - afterspace; s->bptr = (s->bptr - (len - afterspace)) & 1023; if (eol || ind) { len++; afterspace--; } while (len > afterspace) { outLine[col + --len] = ' '; } } s->vcol = 0; s->vrow++; s->atEOL = (eol == 1) || ind || !s->blen; if ((s->atEOL || ind) && s->impInd) { Side_Outdent(s, parseopts.ioCols / 40); s->impInd = 0; } if (ind) { if (ind == 1) Side_Indent(s, parseopts.ioCols / 25); else Side_Outdent(s, parseopts.ioCols / 25); } else if (!s->atEOL && s != &all && !s->impInd) { Side_Indent(s, parseopts.ioCols / 40); s->impInd = 1; } } static void Help_PrintLine() { HPrintF(helptext, "%.*s\n", parseopts.ioCols - 1, outLine); } static void Help_Output(Side *left, Side *right) { while (left->blen || right->blen) { memset(outLine, ' ', parseopts.ioCols); outLine[left->offset + left->width + 1] = '#'; if (left->atEOL && right->atEOL) left->atEOL = right->atEOL = 0; if (!left->atEOL) Side_DumpLine(left); if (!right->atEOL) Side_DumpLine(right); Help_PrintLine(); } } static void Help_OutputSingle(Side *all) { while (all->blen) { memset(outLine, ' ', parseopts.ioCols); if (all->atEOL) all->atEOL = 0; if (!all->atEOL) Side_DumpLine(all); Help_PrintLine(); } } static void Help_Flush() { Help_Output(&left, &right); } static void Help_NewLine() { Side_NewLine(&left); Side_NewLine(&right); } int Help_Option(struct OptionList *lst, struct Option *opt, int subprint, const char *keyword) { char pfbuf[512]; char slflags; int listFlags; Boolean allNoArgs; PARAM_T *lastparam; Boolean print; Boolean printMe; if (!opt->names[0] && !(lst->flags & LISTFLAGS_4)) return 0; if (keyword && keyword[0] && !strstr(opt->names, keyword) && (!opt->help || !strstr(opt->help, keyword))) return 0; if ((opt->avail & OTF_SECRET) && !(parseopts.helpFlags & HELPFLAGS_SECRET)) return 0; if ((opt->avail & OTF_OBSOLETE) && !(parseopts.helpFlags & HELPFLAGS_OBSOLETE)) return 0; if ((opt->avail & OTF_DEPRECATED) && !(parseopts.helpFlags & HELPFLAGS_DEPRECATED)) return 0; if ((opt->avail & OTF_IGNORED) && !(parseopts.helpFlags & HELPFLAGS_IGNORED)) return 0; if ((opt->avail & OTF_MEANINGLESS) && !(parseopts.helpFlags & HELPFLAGS_MEANINGLESS)) return 0; if (!(parseopts.helpFlags & HELPFLAGS_NORMAL) && !(opt->avail & OTF_ALL_HIDDEN_BY_DEFAULT)) return 0; if (opt->help || (opt->avail & OTF8000)) { allNoArgs = 1; lastparam = 0; if (parseopts.helpFlags & HELPFLAGS_SPACES) Help_NewLine(); if ((opt->avail & OTF_GLOBAL) && !subprint) Side_Print(&right, "global; "); if (compat != 1 && (opt->avail & OTF_CASED)) Side_Print(&right, "cased; "); slflags = (subprint == 0) ? SLFLAGS_1 : SLFLAGS_2; switch (opt->avail & OTF_SLFLAGS_MASK) { case OTF_SLFLAGS_8: slflags = slflags | SLFLAGS_8; break; case OTF_SLFLAGS_10: slflags = slflags | SLFLAGS_10; break; case OTF_SLFLAGS_20: slflags = slflags | SLFLAGS_20; break; } if (opt->avail & OTF2) slflags = slflags | SLFLAGS_40; Utils_SpellList(opt->names[0] ? opt->names : "...", pfbuf, slflags); Side_Print(&left, pfbuf); if (opt->avail & OTF_OBSOLETE) Side_Print(&right, "obsolete;\r"); if (opt->avail & OTF_COMPATIBILITY) Side_Print(&right, "compatibility;\r"); if (opt->avail & OTF_IGNORED) Side_Print(&right, "ignored;\r"); listFlags = ((lst->flags & LISTFLAGS_COMPILER) ? OTF_TOOL_COMPILER : 0) | ((lst->flags & LISTFLAGS_LINKER) ? OTF_TOOL_LINKER : 0) | ((lst->flags & LISTFLAGS_DISASSEMBLER) ? OTF_TOOL_DISASSEMBLER : 0); if (!Option_ForThisTool(opt) || Option_AlsoPassedFromThisTool(opt) || listFlags != Option_ThisTool()) { print = 0; printMe = 1; if ((opt->avail & OTF_TOOL_MASK) != (unsigned int) listFlags) print = 1; if (Option_ForThisTool(opt) && Option_AlsoPassedFromThisTool(opt)) printMe = 0; if (print) { char opttool[64] = ""; // stack 0x44 if ((opt->avail & OTF_TOOL_MASK) == (unsigned int) OTF_TOOL_MASK) { strcat(opttool, "all tools"); } else { if (Option_ForTool(opt, OTF_TOOL_COMPILER) && ((Option_ThisTool() != (unsigned int) OTF_TOOL_COMPILER) || printMe)) { strcat(opttool, "this tool"); } if (Option_ForTool(opt, OTF_TOOL_LINKER) && ((Option_ThisTool() != (unsigned int) OTF_TOOL_LINKER) || printMe)) { if (opttool[0]) strcat(opttool, ", "); strcat(opttool, "linker"); } if (Option_ForTool(opt, OTF_TOOL_DISASSEMBLER) && ((Option_ThisTool() != (unsigned int) OTF_TOOL_DISASSEMBLER) || printMe)) { if (opttool[0]) strcat(opttool, ", "); strcat(opttool, "disassembler"); } if (!Option_ForTool(opt, OTF_TOOL_MASK)) strcat(opttool, "another tool"); } if (printMe || !Option_ForThisTool(opt)) { Side_Print(&right, "for %s;\r", opttool); } else if (parseopts.passingArgs) { Side_Print(&right, "passed to %s;\r", opttool); } } } if (opt->avail & OTF_WARNING) Side_Print(&right, "warning:\r"); if (opt->avail & OTF_DEPRECATED) Side_Print(&right, "deprecated;\rinstead use "); else if (opt->avail & OTF_SUBSTITUTED) Side_Print(&right, "substituted with "); if (opt->help) Side_Print(&right, "%s", opt->help); if (opt->param && !(opt->avail & OTF_IGNORED)) { PARAM_T *scan = opt->param; PARAM_T *firstparam = 0; const char *desc; const char *help; const char *defaul; while (scan) { if ((scan->flags & PARAMFLAGS_3) != PARAMFLAGS_1) { if (!firstparam) firstparam = scan; allNoArgs = 0; Param_DescHelp(scan, &desc, &help, &defaul); if (desc) { if (((scan->flags & PARAMFLAGS_3) == PARAMFLAGS_2) && scan->which != PARAMWHICH_Setting && scan->which != PARAMWHICH_IfArg) { if (SEPOPTSTR[0] == ' ') { Side_Print(&left, (scan != firstparam) ? "[," : subprint ? "[=" : " ["); } else { Side_Print(&left, "[%s", (scan != firstparam) ? "," : subprint ? "=" : SEPOPTSTR); } } else { Side_Print(&left, (scan != firstparam) ? "," : subprint ? "=" : ((opt->avail & OTF2) && !strchr(opt->names, '|')) ? "" : SEPOPTSTR); } Side_Print(&left, "%s", desc); if (((scan->flags & PARAMFLAGS_3) == PARAMFLAGS_2) && scan->which != PARAMWHICH_Setting && scan->which != PARAMWHICH_IfArg) { Side_Print(&left, "]"); } if (help) { if ((scan->flags & PARAMFLAGS_3) != PARAMFLAGS_2) Side_Print(&right, "; for '%s', %s", desc, help); else Side_Print(&right, "; if parameter specified, %s", help); } if (defaul && !(opt->avail & OTF2000)) { if (firstparam == scan) Side_Print(&right, "; default is %s", defaul); else Side_Print(&right, ",%s", defaul); } } } lastparam = scan; scan = scan->next; } if (allNoArgs && !(opt->avail & OTF2000)) { PARAM_T *scan = opt->param; Boolean isdefault = scan ? 1 : 0; while (scan && isdefault) { isdefault &= Param_Compare(scan); scan = scan->next; } if (isdefault) Side_Print(&right, "; default"); } } if (opt->avail & OTF_MEANINGLESS) Side_Print(&right, "; meaningless for this target"); if ((opt->avail & OTF8000) && opt->sub) { if (!allNoArgs) { Side_Print( &left, "%s", (opt->avail & OTF10000) ? ((lastparam->flags & PARAMFLAGS_8) ? "[=" : "[,") : ((lastparam->flags & PARAMFLAGS_8) ? "," : "=") ); } else if (!(opt->avail & OTF2)) { if (opt->avail & OTF10000) { if (SEPOPTSTR[0] == ' ') Side_Print(&left, subprint ? "[=" : " ["); else Side_Print(&left, "[%s", subprint ? "=" : SEPOPTSTR); } else { Side_Print(&left, "%c", subprint ? '=' : SEPOPTSTR[0]); } } else { if (opt->avail & OTF10000) { Side_Print(&left, subprint ? "[" : (SEPOPTSTR[0] == ' ') ? " [" : "["); } } Side_Print( &left, "%s%s%s", opt->sub->help ? opt->sub->help : "keyword", (opt->sub->flags & PARAMFLAGS_1) ? "" : "[,...]", (opt->avail & OTF10000) ? "]" : "" ); Side_Print(&left, "\t"); Side_Print(&right, "\t"); Help_Options(opt->sub, 1, ""); Side_Print(&left, "\b"); Side_Print(&right, "\b"); } else { Side_Print(&left, "\n"); Side_Print(&right, "\n"); } } Help_Flush(); return 1; } void Help_Options(struct OptionList *lst, int subprint, const char *keyword) { Option **opts; int toolflags; Boolean show; opts = lst->list; toolflags = 0; if (Option_ThisTool() == (unsigned int) OTF_TOOL_COMPILER) { toolflags |= LISTFLAGS_COMPILER; } else { toolflags |= LISTFLAGS_LINKER; } // review me maybe? if (!subprint && (parseopts.helpFlags & HELPFLAGS_TOOL)) { if ((parseopts.helpFlags & HELPFLAGS_TOOL_BOTH) == HELPFLAGS_TOOL_THIS && (lst->flags & LISTFLAGS_TOOL_MASK) && !(lst->flags & toolflags)) return; if ((parseopts.helpFlags & HELPFLAGS_TOOL_BOTH) == HELPFLAGS_TOOL_OTHER && (((lst->flags & LISTFLAGS_TOOL_MASK) == (unsigned int) toolflags) || ((lst->flags & LISTFLAGS_TOOL_MASK) == (unsigned int) LISTFLAGS_NONE))) return; } if (lst->help && !subprint && opts[0]) { Help_Line('-'); Side_Print(&all, "%s", lst->help); Help_OutputSingle(&all); Help_Line('-'); } while (*opts) { show = 0; if (!(parseopts.helpFlags & HELPFLAGS_TOOL)) { if (((parseopts.helpFlags & HELPFLAGS_TOOL_BOTH) == HELPFLAGS_TOOL_BOTH) && (parseopts.passingArgs ? (Option_ForTool(*opts, OTF_TOOL_LINKER) || Option_ForTool(*opts, OTF_TOOL_DISASSEMBLER)) : 1) && Option_ForThisTool(*opts)) show = 1; } else if ((parseopts.helpFlags & HELPFLAGS_TOOL_BOTH) == HELPFLAGS_TOOL_BOTH) { show = 1; } else if ((parseopts.helpFlags & HELPFLAGS_TOOL_THIS) && Option_ForThisTool(*opts)) { show = 1; } else if ((parseopts.helpFlags & HELPFLAGS_TOOL_OTHER) && !Option_ForThisTool(*opts)) { show = 1; } else if ((parseopts.helpFlags & HELPFLAGS_TOOL_OTHER) && Option_ForTool(*opts, ~Option_ThisTool() & OTF_TOOL_MASK)) { show = 1; } if (show) Help_Option(lst, *opts, subprint, keyword); ++opts; } if (subprint && (parseopts.helpFlags & HELPFLAGS_SPACES)) Help_NewLine(); Help_Flush(); if (!subprint) HPrintF(helptext, "\n"); } void Help_Usage() { Side_Print( &all, "\tGuide to help:\b" "\tWhen an option is specified as '~~xxx | yy[y] | zzz', then either '~~xxx', '~~yy', '~~yyy', or '~~zzz' matches the option.\b" "\tAn option given as '~~[no]xxx' may be given as '~~xxx' or '~~noxxx'; '~~noxxx' reverses the meaning of the option.\b" ); Help_OutputSingle(&all); Side_Print( &all, "\tFor most options, the option and the parameters are separated by a %sspace. When the option's name is '~~xxx+', however, the parameter must directly follow the option, without the '+' (as in '~~xxx45').\b", (compat != 1) ? "" : "colon or " ); Side_Print( &all, "\tA parameter included in brackets '[]' is optional. An ellipsis '...' indicates that the previous type of parameter may be repeated as a list.\b" ); Help_OutputSingle(&all); Side_Print( &all, "\t%s-- \"compatability\" indicates that the option is borrowed from another vendor's tool and may only approximate its counterpart.\r" "-- \"global\" indicates that the option has an effect over the entire command line and is parsed before any other options. When several global options are specified, they are interpreted in order.\r" "-- \"deprecated\" indicates that the option will be eliminated in the future and should not be used any longer. An alternative form is supplied.\r", (compat != 1) ? "-- \"cased\" indicates that the option is case-sensitive. By default, no options are case-sensitive.\r" : ""); Help_OutputSingle(&all); Side_Print( &all, "-- \"ignored\" means the option will be accepted but has no effect on the tool.\r" "-- \"meaningless\" means the option is accepted but probably has no meaning for the target OS.\r" "-- \"obsolete\" means the option was once deprecated and is now gone.\r" "-- \"substituted\" means the option has the same effect as another. This points out a preferred form and prevents confusion when similar options appear in the help.\r" "-- \"default\" in the help text indicates that the given value or variation of an option will be used unless otherwise overridden. \b" ); Help_OutputSingle(&all); Side_Print( &all, "\tThe symbols ',' %s separate options and parameters unconditionally; to include one of these symbols in a parameter or filename, escape it (e.g., as '\\,' in mwcc file.c\\,v).\b\n", (compat != 1) ? "and '='" : ", ':', and '='" ); Help_OutputSingle(&all); if (parseopts.passingArgs && pTool->TYPE == CWDROPINCOMPILERTYPE) Side_Print( &all, "\tThis tool calls the linker (unless a compiler option such as ~~c prevents it) and understands linker options -- use '~~help tool=other' to see them. Options marked \"passed to linker\" are used by the compiler and the linker; options marked \"for linker\" are used only by the linker. When using the compiler and linker separately, you must pass the common options to both.\b\n" ); Help_OutputSingle(&all); } void Help_Null() { Side_Print(&all, "%s [options, filenames...]\n\nExecute '%s %shelp' for more information.", OS_GetFileNamePtr(parseopts.args->argv[0]), OS_GetFileNamePtr(parseopts.args->argv[0]), MAINOPTCHAR ); Help_OutputSingle(&all); } void Help_Init() { short lb; short le; short rb; short re; if (!(helptext = NewHandle(0))) { fprintf(stderr, "\n*** Out of memory\n"); exit(-23); } lb = parseopts.ioCols / 40; le = (parseopts.ioCols / 3) + lb; rb = le + 3 + ((parseopts.ioCols / 60) & ~1); re = parseopts.ioCols - 1; Side_Init(&left, lb, le - lb); Side_Init(&right, rb, re - rb); Side_Init(&all, 0, re); } void Help_Line(char ch) { char line[256]; memset(line, ch, 255); line[255] = 0; HPrintF(helptext, "%.*s\n", parseopts.ioCols - 1, line); } void Help_Term() { ShowTextHandle(0, helptext); DisposeHandle(helptext); }