📄 input.c
字号:
while (iscmd(c));
unget(in, c, &cpos);
}
/*
* Now match the command against the list of available
* ones.
*/
ret.type = tok_cmd;
ret.text = ustrdup(rs.text);
match_kw(&ret);
sfree(rs.text);
return ret;
} else if (c == '{')
{ /* tok_lbrace */
ret.type = tok_lbrace;
return ret;
} else if (c == '}')
{ /* tok_rbrace */
ret.type = tok_rbrace;
return ret;
} else
{ /* tok_word */
/*
* Read a word: the longest possible contiguous sequence of
* things other than whitespace, backslash, braces and
* hyphen. A hyphen terminates the word but is returned as
* part of it; everything else is pushed back for the next
* token. The `aux' field contains TRUE if the word ends in
* a hyphen.
*/
ret.aux = FALSE; /* assumed for now */
while (1)
{
if (iswhite(c) || c == '{' || c == '}' || c == '\\' || c == EOF)
{
/* Put back the character that caused termination */
unget(in, c, &cpos);
break;
} else
{
rdadd(&rs, (wchar_t)c);
if (c == '-')
{
ret.aux = TRUE;
break; /* hyphen terminates word */
}
}
c = get(in, &cpos);
}
ret.type = tok_word;
ret.text = ustrdup(rs.text);
sfree(rs.text);
return ret;
}
}
/*
* Determine whether the next input character is an open brace (for
* telling code paragraphs from paragraphs which merely start with
* code).
*/
int isbrace(input * in)
{
int c;
filepos cpos;
c = get(in, &cpos);
unget(in, c, &cpos);
return (c == '{');
}
/*
* Read the rest of a line that starts `\c'. Including nothing at
* all (tok_word with empty text).
*/
token get_codepar_token(input * in)
{
int c;
token ret;
rdstring rs = { 0, 0, NULL };
filepos cpos;
ret.type = tok_word;
c = get(in, &cpos); /* expect (and discard) one space */
ret.pos = cpos;
if (c == ' ')
{
c = get(in, &cpos);
ret.pos = cpos;
}
while (!isnl(c) && c != EOF)
{
int c2 = c;
c = get(in, &cpos);
/* Discard \r just before \n. */
if (c2 != 13 || !isnl(c))
rdadd(&rs, (wchar_t)c2);
}
unget(in, c, &cpos);
ret.text = ustrdup(rs.text);
sfree(rs.text);
return ret;
}
/*
* Adds a new word to a linked list
*/
static word *addword(word newword, word *** hptrptr)
{
word *mnewword;
if (!hptrptr)
return NULL;
mnewword = mknew(word);
*mnewword = newword; /* structure copy */
mnewword->next = NULL;
**hptrptr = mnewword;
*hptrptr = &mnewword->next;
return mnewword;
}
/*
* Adds a new paragraph to a linked list
*/
static paragraph *addpara(paragraph newpara, paragraph *** hptrptr)
{
paragraph *mnewpara = mknew(paragraph);
*mnewpara = newpara; /* structure copy */
mnewpara->next = NULL;
**hptrptr = mnewpara;
*hptrptr = &mnewpara->next;
return mnewpara;
}
/*
* Destructor before token is reassigned; should catch most memory
* leaks
*/
#define dtor(t) ( sfree(t.text) )
/*
* Reads a single file (ie until get() returns EOF)
*/
static void read_file(paragraph *** ret, input * in, indexdata * idx)
{
token t;
paragraph par;
word wd, **whptr, **idximplicit;
tree234 *macros;
wchar_t utext[2], *wdtext;
int style, spcstyle;
int already;
int iswhite, seenwhite;
int type;
struct stack_item {
enum {
stack_nop = 0, /* do nothing (for error recovery) */
stack_ualt = 1, /* \u alternative */
stack_style = 2, /* \e, \c, \cw */
stack_idx = 4, /* \I, \i, \ii */
stack_hyper = 8, /* \W */
stack_quote = 16, /* \q */
} type;
word **whptr; /* to restore from \u alternatives */
word **idximplicit; /* to restore from \u alternatives */
} *sitem;
stack parsestk;
word *indexword=NULL, *uword=NULL, *iword=NULL;
word *idxwordlist;
rdstring indexstr;
int index_downcase=0, index_visible=0, indexing=0;
const rdstring nullrs = { 0, 0, NULL };
wchar_t uchr;
t.text = NULL;
macros = newtree234(macrocmp);
already = FALSE;
/*
* Loop on each paragraph.
*/
while (1)
{
int start_cmd = c__invalid;
par.words = NULL;
par.keyword = NULL;
whptr = &par.words;
/*
* Get a token.
*/
if (!already)
{
dtor(t), t = get_token(in);
}
already = FALSE;
if (t.type == tok_eof)
break;
/*
* Parse code paragraphs separately.
*/
if (t.type == tok_cmd && t.cmd == c_c && !isbrace(in))
{
par.type = para_Code;
par.fpos = t.pos;
while (1)
{
dtor(t), t = get_codepar_token(in);
wd.type = word_WeakCode;
wd.breaks = FALSE; /* shouldn't need this... */
wd.text = ustrdup(t.text);
wd.alt = NULL;
wd.fpos = t.pos;
addword(wd, &whptr);
dtor(t), t = get_token(in);
if (t.type == tok_white)
{
/*
* The newline after a code-paragraph line
*/
dtor(t), t = get_token(in);
}
if (t.type == tok_eop || t.type == tok_eof)
break;
else if (t.type != tok_cmd || t.cmd != c_c)
{
error(err_brokencodepara, &t.pos);
addpara(par, ret);
while (t.type != tok_eop) /* error recovery: */
dtor(t), t = get_token(in); /* eat rest of paragraph */
goto codeparabroken; /* ick, but such is life */
}
}
addpara(par, ret);
codeparabroken:
continue;
}
while (t.type == tok_cmd && macrolookup(macros, in, t.text, &t.pos))
{
dtor(t), t = get_token(in);
}
/*
* This token begins a paragraph. See if it's one of the
* special commands that define a paragraph type.
*
* (note that \# is special in a way, and \nocite takes no
* text)
*/
par.type = para_Normal;
if (t.type == tok_cmd)
{
int needkw=0;
int is_macro = FALSE;
par.fpos = t.pos;
switch (t.cmd)
{
default:
needkw = -1;
break;
case c__invalid:
error(err_badparatype, t.text, &t.pos);
needkw = 4;
break;
case c__comment:
if (isbrace(in))
break; /* `\#{': isn't a comment para */
do
{
dtor(t), t = get_token(in);
}
while (t.type != tok_eop && t.type != tok_eof);
continue; /* next paragraph */
/*
* `needkw' values:
*
* 1 -- exactly one keyword
* 2 -- at least one keyword
* 4 -- any number of keywords including zero
* 8 -- at least one keyword and then nothing else
* 16 -- nothing at all! no keywords, no body
* 32 -- no keywords at all
*/
case c_A:
needkw = 2;
par.type = para_Appendix;
break;
case c_B:
needkw = 2;
par.type = para_Biblio;
break;
case c_BR:
needkw = 1;
par.type = para_BR;
start_cmd = c_BR;
break;
case c_C:
needkw = 2;
par.type = para_Chapter;
break;
case c_H:
needkw = 2;
par.type = para_Heading;
par.aux = 0;
break;
case c_IM:
needkw = 2;
par.type = para_IM;
start_cmd = c_IM;
break;
case c_S:
needkw = 2;
par.type = para_Subsect;
par.aux = t.aux;
break;
case c_U:
needkw = 32;
par.type = para_UnnumberedChapter;
break;
/* For \b and \n the keyword is optional */
case c_b:
needkw = 4;
par.type = para_Bullet;
break;
case c_n:
needkw = 4;
par.type = para_NumberedList;
break;
case c_cfg:
needkw = 8;
par.type = para_Config;
start_cmd = c_cfg;
break;
case c_copyright:
needkw = 32;
par.type = para_Copyright;
break;
case c_define:
is_macro = TRUE;
needkw = 1;
break;
/* For \nocite the keyword is _everything_ */
case c_nocite:
needkw = 8;
par.type = para_NoCite;
break;
case c_preamble:
needkw = 32;
par.type = para_Preamble;
break;
case c_rule:
needkw = 16;
par.type = para_Rule;
break;
case c_title:
needkw = 32;
par.type = para_Title;
break;
case c_versionid:
needkw = 32;
par.type = para_VersionID;
break;
}
if (needkw > 0)
{
rdstring rs = { 0, 0, NULL };
int nkeys = 0;
filepos fp;
/* Get keywords. */
dtor(t), t = get_token(in);
fp = t.pos;
while (t.type == tok_lbrace)
{
/* This is a keyword. */
nkeys++;
/* FIXME: there will be bugs if anyone specifies an
* empty keyword (\foo{}), so trap this case. */
while (dtor(t), t = get_token(in),
t.type == tok_word ||
t.type == tok_white ||
(t.type == tok_cmd && t.cmd == c__nbsp) ||
(t.type == tok_cmd && t.cmd == c__escaped))
{
if (t.type == tok_white ||
(t.type == tok_cmd && t.cmd == c__nbsp))
rdadd(&rs, ' ');
else
rdadds(&rs, t.text);
}
if (t.type != tok_rbrace)
{
error(err_kwunclosed, &t.pos);
continue;
}
rdadd(&rs, 0); /* add string terminator */
dtor(t), t = get_token(in); /* eat right brace */
}
rdadd(&rs, 0); /* add string terminator */
/* See whether we have the right number of keywords. */
if ((needkw & 48) && nkeys > 0)
error(err_kwillegal, &fp);
if ((needkw & 11) && nkeys == 0)
error(err_kwexpected, &fp);
if ((needkw & 5) && nkeys > 1)
error(err_kwtoomany, &fp);
if (is_macro)
{
/*
* Macro definition. Get the rest of the line
* as a code-paragraph token, repeatedly until
* there's nothing more left of it. Separate
* with newlines.
*/
rdstring macrotext = { 0, 0, NULL };
while (1)
{
dtor(t), t = get_codepar_token(in);
if (macrotext.pos > 0)
rdadd(¯otext, L'\n');
rdadds(¯otext, t.text);
dtor(t), t = get_token(in);
if (t.type == tok_eop)
break;
}
macrodef(macros, rs.text, macrotext.text, fp);
continue; /* next paragraph */
}
par.keyword = rdtrim(&rs);
/* Move to EOP in case of needkw==8 or 16 (no body) */
if (needkw & 24)
{
/* We allow whitespace even when we expect no para body */
while (t.type == tok_white)
dtor(t), t = get_token(in);
if (t.type != tok_eop && t.type != tok_eof &&
(start_cmd == c__invalid ||
t.type != tok_cmd || t.cmd != start_cmd))
{
error(err_bodyillegal, &t.pos);
/* Error recovery: eat the rest of the paragraph */
while (t.type != tok_eop && t.type != tok_eof &&
(start_cmd == c__invalid ||
t.type != tok_cmd || t.cmd != start_cmd))
dtor(t), t = get_token(in);
}
if (t.type == tok_cmd)
already = TRUE; /* inhibit get_token at top of loop */
addpara(par, ret);
continue; /* next paragraph */
}
}
}
/*
* Now read the actual paragraph, word by word, adding to
* the paragraph list.
*
* Mid-paragraph commands:
*
* \K \k
* \c \cw
* \e
* \i \ii
* \I
* \u
* \W
* \date
* \\ \{ \}
*/
parsestk = stk_new();
style = word_Normal;
spcstyle = word_WhiteSpace;
indexing = FALSE;
seenwhite = TRUE;
while (t.type != tok_eop && t.type != tok_eof)
{
iswhite = FALSE;
already = FALSE;
/* Handle implicit paragraph breaks after \IM, \BR etc */
if (start_cmd != c__invalid &&
t.type == tok_cmd && t.cmd == start_cmd)
{
already = TRUE; /* inhibit get_token at top of loop */
break;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -