📄 input.cc
字号:
if (s == 0) return new small_temp_iterator(s, 0); else { int n = strlen(s); if (n <= small_temp_iterator::SIZE) return new small_temp_iterator(s, n); else return new temp_iterator(s, n); }}// this is used when macros are interpolated using the .macro_name notationstruct arg_list { macro mac; arg_list *next; arg_list(const macro &); ~arg_list();};arg_list::arg_list(const macro &m) : mac(m), next(0){}arg_list::~arg_list(){}class macro_iterator : public string_iterator { arg_list *args; int argc;public: macro_iterator(symbol, macro &); macro_iterator(); ~macro_iterator(); int has_args() { return 1; } input_iterator *get_arg(int i); int nargs() { return argc; } void add_arg(const macro &m); void shift(int n);};input_iterator *macro_iterator::get_arg(int i){ if (i == 0) return make_temp_iterator(nm.contents()); if (i > 0 && i <= argc) { arg_list *p = args; for (int j = 1; j < i; j++) { assert(p != 0); p = p->next; } return new string_iterator(p->mac); } else return 0;}void macro_iterator::add_arg(const macro &m){ for (arg_list **p = &args; *p; p = &((*p)->next)) ; *p = new arg_list(m); ++argc;}void macro_iterator::shift(int n){ while (n > 0 && argc > 0) { arg_list *tem = args; args = args->next; delete tem; --argc; --n; }}// This gets used by eg .if '\?xxx\?''.int operator==(const macro &m1, const macro &m2){ if (m1.length != m2.length) return 0; string_iterator iter1(m1); string_iterator iter2(m2); int n = m1.length; while (--n >= 0) { node *nd1 = 0; int c1 = iter1.get(&nd1); assert(c1 != EOF); node *nd2 = 0; int c2 = iter2.get(&nd2); assert(c2 != EOF); if (c1 != c2) { if (c1 == 0) delete nd1; else if (c2 == 0) delete nd2; return 0; } if (c1 == 0) { assert(nd1 != 0); assert(nd2 != 0); int are_same = nd1->type() == nd2->type() && nd1->same(nd2); delete nd1; delete nd2; if (!are_same) return 0; } } return 1;}static void interpolate_macro(symbol nm){ request_or_macro *p = (request_or_macro *)request_dictionary.lookup(nm); if (p == 0) { int warned = 0; const char *s = nm.contents(); if (strlen(s) > 2) { request_or_macro *r; char buf[3]; buf[0] = s[0]; buf[1] = s[1]; buf[2] = '\0'; r = (request_or_macro *)request_dictionary.lookup(symbol(buf)); if (r) { macro *m = r->to_macro(); if (!m || !m->empty()) warned = warning(WARN_SPACE, "space required between `%1' and argument", buf); } } if (!warned) { warning(WARN_MAC, "`%1' not defined", nm.contents()); p = new macro; request_dictionary.define(nm, p); } } if (p) p->invoke(nm); else { skip_line(); return; }}static void decode_args(macro_iterator *mi){ if (!tok.newline() && !tok.eof()) { node *n; int c = get_copy(&n); for (;;) { while (c == ' ') c = get_copy(&n); if (c == '\n' || c == EOF) break; macro arg; int quote_input_level = 0; if (c == '\"') { quote_input_level = input_stack::get_level(); c = get_copy(&n); } while (c != EOF && c != '\n' && !(c == ' ' && quote_input_level == 0)) { if (quote_input_level > 0 && c == '\"' && (compatible_flag || input_stack::get_level() == quote_input_level)) { c = get_copy(&n); if (c == '"') { arg.append(c); c = get_copy(&n); } else break; } else { if (c == 0) arg.append(n); else arg.append(c); c = get_copy(&n); } } mi->add_arg(arg); } }}void macro::invoke(symbol nm){ macro_iterator *mi = new macro_iterator(nm, *this); decode_args(mi); input_stack::push(mi); tok.next();}macro *macro::to_macro(){ return this;}int macro::empty(){ return length == 0;}macro_iterator::macro_iterator(symbol s, macro &m): string_iterator(m, "macro", s), args(0), argc(0){}macro_iterator::macro_iterator() : args(0), argc(0){}macro_iterator::~macro_iterator(){ while (args != 0) { arg_list *tem = args; args = args->next; delete tem; }}void read_request(){ macro_iterator *mi = new macro_iterator; int had_prompt = 0; if (!tok.newline() && !tok.eof()) { int c = get_copy(NULL); while (c == ' ') c = get_copy(NULL); while (c != EOF && c != '\n' && c != ' ') { if (!illegal_input_char(c)) { fputc(c, stderr); had_prompt = 1; } c = get_copy(NULL); } if (c == ' ') { tok.make_space(); decode_args(mi); } } fputc(had_prompt ? ':' : '\007', stderr); fflush(stderr); input_stack::push(mi); macro mac; int nl = 0; int c; while ((c = getchar()) != EOF) { if (illegal_input_char(c)) warning(WARN_INPUT, "illegal input character code %1", int(c)); else { if (c == '\n') { if (nl) break; else nl = 1; } else nl = 0; mac.append(c); } } input_stack::push(new string_iterator(mac)); tok.next();}void do_define_string(int append){ symbol nm; node *n; int c; nm = get_name(1); if (nm.is_null()) { skip_line(); return; } if (tok.newline()) c = '\n'; else if (tok.tab()) c = '\t'; else if (!tok.space()) { error("bad string definition"); skip_line(); return; } else c = get_copy(&n); while (c == ' ') c = get_copy(&n); if (c == '"') c = get_copy(&n); macro mac; request_or_macro *rm = (request_or_macro *)request_dictionary.lookup(nm); macro *mm = rm ? rm->to_macro() : 0; if (append && mm) mac = *mm; while (c != '\n' && c != EOF) { if (c == 0) mac.append(n); else mac.append((unsigned char)c); c = get_copy(&n); } if (!mm) { mm = new macro; request_dictionary.define(nm, mm); } *mm = mac; tok.next();}void define_string(){ do_define_string(0);}void append_string(){ do_define_string(1);}void define_character(){ node *n; int c; tok.skip(); charinfo *ci = tok.get_char(1); if (ci == 0) { skip_line(); return; } tok.next(); if (tok.newline()) c = '\n'; else if (tok.tab()) c = '\t'; else if (!tok.space()) { error("bad character definition"); skip_line(); return; } else c = get_copy(&n); while (c == ' ' || c == '\t') c = get_copy(&n); if (c == '"') c = get_copy(&n); macro *m = new macro; while (c != '\n' && c != EOF) { if (c == 0) m->append(n); else m->append((unsigned char)c); c = get_copy(&n); } m = ci->set_macro(m); if (m) delete m; tok.next();}static void remove_character(){ tok.skip(); while (!tok.newline() && !tok.eof()) { if (!tok.space() && !tok.tab()) { charinfo *ci = tok.get_char(1); if (!ci) break; macro *m = ci->set_macro(0); if (m) delete m; } tok.next(); } skip_line();} static void interpolate_string(symbol nm){ request_or_macro *p = lookup_request(nm); macro *m = p->to_macro(); if (!m) error("you can only invoke a string using \\*"); else { string_iterator *si = new string_iterator(*m, "string", nm); input_stack::push(si); }}/* This class is used for the implementation of \$@. It is used foreach of the closing double quotes. It artificially increases theinput level by 2, so that the closing double quote will appear to havethe same input level as the opening quote. */class end_quote_iterator : public input_iterator { unsigned char buf[1];public: end_quote_iterator(); ~end_quote_iterator() { } int internal_level() { return 2; }};end_quote_iterator::end_quote_iterator(){ buf[0] = '"'; ptr = buf; eptr = buf + 1;}static void interpolate_arg(symbol nm){ const char *s = nm.contents(); if (!s || *s == '\0') error("missing argument name"); else if (s[1] == 0 && csdigit(s[0])) input_stack::push(input_stack::get_arg(s[0] - '0')); else if (s[0] == '*' && s[1] == '\0') { for (int i = input_stack::nargs(); i > 0; i--) { input_stack::push(input_stack::get_arg(i)); if (i != 1) input_stack::push(make_temp_iterator(" ")); } } else if (s[0] == '@' && s[1] == '\0') { for (int i = input_stack::nargs(); i > 0; i--) { input_stack::push(new end_quote_iterator); input_stack::push(input_stack::get_arg(i)); input_stack::push(make_temp_iterator(i == 1 ? "\"" : " \"")); } } else { for (const char *p = s; *p && csdigit(*p); p++) ; if (*p) error("bad argument name `%1'", s); else input_stack::push(input_stack::get_arg(atoi(s))); }}void handle_first_page_transition(){ push_token(tok); topdiv->begin_page();}// We push back a token by wrapping it up in a token_node, and// wrapping that up in a string_iterator.static void push_token(const token &t){ macro m; m.append(new token_node(t)); input_stack::push(new string_iterator(m));}void push_page_ejector(){ static char buf[2] = { PAGE_EJECTOR, '\0' }; input_stack::push(make_temp_iterator(buf));}void handle_initial_request(unsigned char code){ char buf[2]; buf[0] = code; buf[1] = '\0'; macro mac; mac.append(new token_node(tok)); input_stack::push(new string_iterator(mac)); input_stack::push(make_temp_iterator(buf)); topdiv->begin_page(); tok.next();}void handle_initial_title(){ handle_initial_request(TITLE_REQUEST);}int trap_sprung_flag = 0;int postpone_traps_flag = 0;symbol postponed_trap;void spring_trap(symbol nm){ assert(!nm.is_null()); trap_sprung_flag = 1; if (postpone_traps_flag) { postponed_trap = nm; return; } static char buf[2] = { BEGIN_TRAP, 0 }; static char buf2[2] = { END_TRAP, '\0' }; input_stack::push(make_temp_iterator(buf2)); request_or_macro *p = lookup_request(nm); macro *m = p->to_macro(); if (m) input_stack::push(new string_iterator(*m, "trap-invoked macro", nm)); else error("you can't invoke a request with a trap"); input_stack::push(make_temp_iterator(buf));}void postpone_traps(){ postpone_traps_flag = 1;}int unpostpone_traps(){ postpone_traps_flag = 0; if (!postponed_trap.is_null()) { spring_trap(postponed_trap); postponed_trap = NULL_SYMBOL; return 1; } else return 0;}// this should be local to define_macro, but cfront 1.2 doesn't support thatstatic symbol dot_symbol(".");enum define_mode { DEFINE_NORMAL, DEFINE_APPEND, DEFINE_IGNORE };void do_define_macro(define_mode mode){ symbol nm; if (mode == DEFINE_NORMAL || mode == DEFINE_APPEND) { nm = get_name(1); if (nm.is_null()) { skip_line(); return; } } symbol term = get_name(); // the request that terminates the definition if (term.is_null()) term = dot_symbol; while (!tok.newline() && !tok.eof()) tok.next(); const char *start_filename; int start_lineno; int have_start_location = input_stack::get_location(0, &start_filename, &start_lineno); node *n; // doing this here makes the line numbers come out right int c = get_copy(&n, 1); macro mac; macro *mm = 0; if (mode == DEFINE_NORMAL || mode == DEFINE_APPEND) { request_or_macro *rm = (request_or_macro *)request_dictionary.lookup(nm); if (rm) mm = rm->to_macro(); if (mm && mode == DEFINE_APPEND) mac = *mm; } int bol = 1; for (;;) { while (c == ESCAPE_NEWLINE) { if (mode == DEFINE_NORMAL || mode == DEFINE_APPEND) mac.append(c); c = get_copy(&n, 1); } if (bol && c == '.') { const char *s = term.contents(); int d; // see if it matches term for (int i = 0; s[i] != 0; i++) { d = get_copy(&n); if ((unsigned char)s[i] != d) break; } if (s[i] == 0 && ((i == 2 && compatible_flag) || (d = get_copy(&n)) == ' ' || d == '\n')) { // we found it if (d == '\n') tok.make_newline(); else tok.make_space(); if (mode == DEFINE_APPEND || mode == DEFINE_NORMAL) { if (!mm) { mm = new macro; request_dictionary.define(nm, mm); } *mm = mac; } if (term != dot_symbol) interpolate_macro(term); else skip_line(); return; } if (mode == DEFINE_APPEND || mode == DEFINE_NORMAL) { mac.append(c); for (int j = 0; j < i; j++) mac.append(s[j]); } c = d; } if (c == EOF) { if (mode == DEFINE_NORMAL || mode == DEFINE_APPEND) { if (have_start_location) error_with_file_and_line(start_filename, start_lineno, "end of file while defining macro `%1'", nm.contents()); else error("end of file while defining macro `%1'", nm.contents()); } else { if (have_start_location) error_with_file_and_line(start_filename, start_lineno, "end of file while ignoring input lines"); else error("end of file while ignoring input lines"); } tok.next(); return; } if (mode == DEFINE_NORMAL || mode == DEFINE_APPEND) { if (c == 0) mac.append(n); else mac.append(c); } bol = (c == '\n'); c = get_copy(&n, 1); }}void define_macro(){ do_define_macro(DEFINE_NORMAL);}void append_macro(){ do_define_macro(DEFINE_APPEND);}void ignore(){ do_define_macro(DEFINE_IGNORE);}void remove_macro(){ for (;;) { symbol s = get_name(); if (s.is_null()) break; request_dictionary.remove(s); } skip_line();}vo
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -