mirror of https://git.wuffs.org/MWCC
562 lines
20 KiB
C
562 lines
20 KiB
C
#include "parser.h"
|
|
|
|
typedef struct _Side {
|
|
short offset;
|
|
short width;
|
|
char buffer[1024];
|
|
short bptr;
|
|
short blen;
|
|
short indent;
|
|
short vrow;
|
|
short vcol;
|
|
Boolean atEOL;
|
|
Boolean impInd;
|
|
} Side;
|
|
|
|
short helpExtras;
|
|
Boolean 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(void);
|
|
|
|
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(void) {
|
|
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(void) {
|
|
Help_Output(&left, &right);
|
|
}
|
|
|
|
static void Help_NewLine(void) {
|
|
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 & OTF_HAS_SUB_OPTIONS)) {
|
|
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 & OTF_STICKY)
|
|
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 & OTF_STICKY) && !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 & OTF_HIDE_DEFAULT)) {
|
|
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 & OTF_HIDE_DEFAULT)) {
|
|
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 & OTF_HAS_SUB_OPTIONS) && opt->sub) {
|
|
if (!allNoArgs) {
|
|
Side_Print(
|
|
&left,
|
|
"%s",
|
|
(opt->avail & OTF_SUB_OPTIONS_OPTIONAL) ? ((lastparam->flags & PARAMFLAGS_8) ? "[=" : "[,") : ((lastparam->flags & PARAMFLAGS_8) ? "=" : ",")
|
|
);
|
|
} else if (!(opt->avail & OTF_STICKY)) {
|
|
if (opt->avail & OTF_SUB_OPTIONS_OPTIONAL) {
|
|
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 & OTF_SUB_OPTIONS_OPTIONAL) {
|
|
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 & OTF_SUB_OPTIONS_OPTIONAL) ? "]" : ""
|
|
);
|
|
|
|
Side_Print(&left, "\t");
|
|
Side_Print(&right, "\t");
|
|
Help_Options(opt->sub, 1, "");
|
|
Side_Print(&right, "\b");
|
|
Side_Print(&left, "\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() == 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(void) {
|
|
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(void) {
|
|
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(void) {
|
|
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(void) {
|
|
ShowTextHandle(0, helptext);
|
|
DisposeHandle(helptext);
|
|
}
|