|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T a
Length: 15294 (0x3bbe) Types: TextFile Names: »ap_1adr.c«
└─⟦2d1937cfd⟧ Bits:30007241 EUUGD22: P.P 5.0 └─⟦dc59850a2⟧ »EurOpenD22/pp5.0/pp-5.tar.Z« └─⟦e5a54fb17⟧ └─⟦this⟧ »pp-5.0/Lib/addr/ap_1adr.c«
/* ap_1adr.c: parse one address - the heart of the parser */ # ifndef lint static char Rcsid[] = "@(#)$Header: /cs/research/pp/hubris/pp-beta/Lib/addr/RCS/ap_1adr.c,v 5.0 90/09/20 16:03:29 pp Exp Locker: pp $"; # endif /* * $Header: /cs/research/pp/hubris/pp-beta/Lib/addr/RCS/ap_1adr.c,v 5.0 90/09/20 16:03:29 pp Exp Locker: pp $ * * $Log: ap_1adr.c,v $ * Revision 5.0 90/09/20 16:03:29 pp * rcsforce : 5.0 public release * */ /* ADDRESS PARSER, as per: "Standard for the Format of ARPA Network Text Messages", D. Crocker, J. Vittal, K. Pogran & D. Henderson, in ARPANET PROTOCOL HANDBOOK, E. Feinler & J. Postel (eds), NIC-7104-REV-1, Network Information Center, SRI International: Menlo Park, Ca. (1978) (NTIS AD-A0038901). and "Standard for the Format of Arpa Internet Text Messages", Revised by D. Crocker, RFC #822, in INTERNET PROTOCOL TRANSITION WORKBOOK, Feinler & J. Postel (eds), Network Information Center, SRI International: Menlo Park, Ca. (March 1982). A parsed address is normalized to have routing references placed into rfc822-type positioning. History: Fall 1977 Bruce Borden: Initial Design & Coding Summer 1979 Dave Crocker: Completed it & fixed bugs Major reorganization & re-labeling Minor changes to semantics Documentation Sept 81 Andy Knutsen case STPREND -> STPHRSE, to allow comments afterwards Sept 81 Dave Crocker generalized the use of STPHRSE, so that STOKEND occurs only on comma or eof. changed again, to cycle only accepting comments Nov 82 Dave Crocker Converted to accept 822 syntax, while trying also to juggle 733... Aug 83 Steve Kille Fix to STEPER This module is the real parser, tho it is intended to be co-routined with a caller who has something specific to do with ap_1adr's output. This is organized so as to make some attempt at limiting core consumption. Fullparse(), however, simply causes a full parse tree to be built up in core. The implementation deviates somewhat from the above specification. Deviations and the use of the package are discussed in the companion documentation. The parser's behavior is fairly straightforward. A singly-linked flat list of labelled (lexical) nodes is built up. Ap_1adr() is used to get the next "address segment", which consists of all of the lexical nodes up to the end of the next host-phrase (i.e., usually that means up to the next comma, semi-colon, or right-angle bracket). The caller is responsible for initializing state variables, via ap_init(), and linking together or using ap_1adr's output segments. Note that ap_1adr does NOT interpret address text to cause re-directed file input. The caller must do that. Ap_pshfil() and ap_popfil() can be used to save and restore the parse state and acquire the named file. The provision for this stacking, given the co-routining, is the reason state information is chained through global variables, rather than being saved on local (stack) variables. The amount of input processed on a single call may seem strange. The idea is to try to guess the most common use of the routine. This is presumed to be for address checking, in which acquisition of the MBOX and DOMAIN text are most important, with the rest actually being thrown away. It is, of course, possible for the core-limiting heuristic to lose if a ridiculous number of groups and personal lists are specified in a particular way. I am assuming that won't happen. \f */ #include "util.h" #include "ap.h" #include "ap_lex.h" #define STDOMAIN 0 #define STDTYPE 1 #define STEBAD 2 #define STECMNT 3 #define STEDOMAIN 4 #define STEDONE 5 /* Returned when addresses were NOT found */ #define STEDTYPE 6 #define STEGRP 7 #define STEOK 8 /* Returned when addresses were found */ #define STEPER 9 #define STINIT 10 #define STITER 11 #define STPHRSE 12 #define STSTPER 13 int ap_intype = AP_PARSE_733; /* default to RFC #733 input */ int ap_outtype = AP_PARSE_822; /* default to RFC #822 output */ /* with little endian domains */ int ap_grplev = 0; /* Group nesting depth */ int ap_perlev = 0; /* <> nesting depth */ int ap_routing; /* parsing a route */ #ifdef AP_DEBUG extern AP_ptr ap_sqinsert (); extern char *strdup(); char ap_debug=TRUE; /* True if in debug mode */ char *statnam[] = { "Domain", "DTypNam", "BadEnd", "CmntEnd", "DomainE", "DoneEnd", "DTypeE", "GrpEnd", "OKEnd", "PersEnd", "Init", "Iterate", "Phrase", "Persstrt", }; char *typtab[] = { "Nil", "Comment", "DataType", "Domain", "DomainLit", "Word", "GpEnd", "GpName", "GpStart", "Mailbox", "PersonEnd", "PersonName", "PersonStart" }; #endif /*\f */ /* --------------------- Begin Routines -------------------------------- */ int ap_1adr () { struct ap_node base_node; AP_ptr ap_sp = NULLAP, /* Saved ap node ptr */ ap_noname, r822_ptr = NULLAP, r733_prefptr; int got_822, noname; char buf[LINESIZE]; register int state; ap_routing = DONE; ap_noname = NULL; ap_ninit (&base_node); ap_sqinsert (&base_node, AP_PTR_MORE, ap_pstrt); for (state = STINIT, got_822 = FALSE, noname = FALSE, r733_prefptr = NULLAP; ; ) { #ifdef AP_DEBUG if (ap_debug) PP_DBG (("=>%d (%s)", state, (state >= 0 && state <= 13) ? statnam[state] : "BOGUS!")); #endif switch (state) { case STITER: /* -- Iteration to get real address -- */ ap_palloc (); state = STINIT; /* just drop on through -- */ case STINIT: /* -- start of parse; empty node -- */ ap_sp = ap_pcur; switch (ap_lex (buf)) { case LV_WORD: ap_pfill (AP_GENERIC_WORD, buf); if (noname == TRUE) { /* no name before so copy buf into ap_noname */ ap_noname->ap_obvalue = (buf == NULLCP) ? NULLCP : strdup(buf); ap_noname = NULL; noname = FALSE; } state = STPHRSE; break; case LV_AT: if (!got_822) { got_822 = TRUE; r822_ptr = ap_pcur; } ap_routing = OK; #ifdef AP_DEBUG if (ap_debug) PP_DBG (("(routing)")); #endif state = STDOMAIN; break; case LV_COLON: /* -- data type start -- */ state = STDTYPE; break; case LV_SEMI: /* -- group list end -- */ state = STEGRP; break; case LV_GRTR: /* -- personal list end -- */ state = STEPER; break; case LV_LESS: /* -- allow one angle-bracket, here -- */ ap_pfill (AP_GENERIC_WORD, ""); noname = TRUE; ap_noname = ap_pcur; state = STSTPER; break; case LV_FROM: /* -- file source -- */ ap_pfill (AP_DATA_TYPE, "Include"); state = STITER; break; case LV_COMMENT: ap_pfill (AP_COMMENT, buf); state = STITER; break; case LV_COMMA: /* -- ignore null addresses -- */ break; case LV_EOD: if (ap_perlev != 0 || ap_grplev != 0) state = STEBAD; else state = STEDONE; break; default: state = STEBAD; break; } continue; /* --------------------------- Ending --------------------------------- */ case STECMNT: /* -- accept comments until end -- */ switch (ap_lex (buf)) { case LV_COMMENT: /* -- just cycle, accepting comments -- */ /* ap_pfill (AP_COMMENT, buf);*/ ap_pappend(AP_COMMENT, buf); break; case LV_COMMA: state = STEOK; break; case LV_SEMI: /* -- group list end -- */ state = STEGRP; break; case LV_EOD: state = STEOK; break; default: state = STEBAD; break; } continue; case STEDONE: /* -- end clean; no empty nodes? -- */ ap_7to8 (r733_prefptr, r822_ptr); return (DONE); case STEOK: /* -- end clean -- */ ap_7to8 (r733_prefptr, r822_ptr); return (OK); case STEBAD: /* -- end error -- */ ap_clear(); /* Experimental, DPK, 7 Aug 84 */ return (NOTOK); /* ----------------------- Gather a phrase ------------------------------ */ case STPHRSE: /* -- phrase continuation; empty node -- */ switch (ap_lex (buf)) { case LV_WORD: /* -- append word to phrase, maybe -- */ ap_pappend (AP_GENERIC_WORD, buf); break; case LV_AT: /* -- mailbox (name) end -- */ if (!got_822) r822_ptr = ap_pcur; ap_sqtfix (ap_sp, ap_pcur, AP_MAILBOX); ap_palloc (); state = STDOMAIN; break; case LV_LESS: /* -- person name end -- */ state = STSTPER; break; case LV_COLON: /* -- group name end -- */ if (ap_grplev++ >= 1 && ap_intype == AP_PARSE_822) { /* -- may not be nested -- */ #ifdef AP_DEBUG if (ap_debug) PP_DBG (("(intype=%d,ap_grplev=%d)", ap_intype, ap_grplev)); #endif state = STEBAD; break; } ap_sqtfix (ap_sp, ap_pcur, AP_GROUP_START); ap_sp -> ap_obtype = AP_GROUP_NAME; state = STITER; break; case LV_SEMI: ap_sqtfix (ap_sp, ap_pcur, AP_MAILBOX); ap_sp -> ap_obtype = AP_MAILBOX; state = STEGRP; break; case LV_GRTR: state = STEPER; break; case LV_COMMA: ap_sqtfix (ap_sp, ap_pcur, AP_MAILBOX); state = STEOK; break; case LV_EOD: ap_sqtfix (ap_sp, ap_pcur, AP_MAILBOX); state = STEOK; break; case LV_COMMENT: ap_pappend (AP_COMMENT, buf); break; default: state = STEBAD; break; } continue; /* ------------------------- Address lists ---------------------------- */ case STSTPER: /* -- personal address list; no empty node -- */ if (ap_perlev++ > 0 && ap_intype == AP_PARSE_822) { /* -- may not be nested -- */ #ifdef AP_DEBUG if (ap_debug) PP_DBG (("(intype=%d,ap_perlev=%d)", ap_intype, ap_perlev)); #endif state = STEBAD; break; } ap_routing = OK; ap_sqtfix (ap_sp, ap_pcur, AP_PERSON_START); ap_sp -> ap_obtype = AP_PERSON_NAME; state = STITER; continue; case STEPER: if (--ap_perlev < 0) { #ifdef AP_DEBUG if (ap_debug) PP_DBG (("(ap_perlev=%d)", ap_perlev)); #endif state = STEBAD; break; } ap_pappend (AP_PERSON_END, NULLCP); ap_palloc (); /* SEK add storage */ state = STECMNT; /* allow comments, etc */ continue; case STEGRP: if (--ap_grplev < 0) { #ifdef AP_DEBUG if (ap_debug) PP_DBG (("(ap_grplev=%d)", ap_grplev)); #endif state = STEBAD; break; } ap_pappend (AP_GROUP_END, NULLCP); state = STECMNT; continue; /* -------------------------- Data type ---------------------------------- */ case STDTYPE: /* -- data type name; empty node -- */ if (ap_intype == AP_PARSE_822) { /* -- data types not legal in 822 -- */ #ifdef AP_DEBUG if (ap_debug) PP_DBG (("(intype=%d)", ap_intype)); #endif state = STEBAD; break; } if (ap_lex (buf) != LV_WORD) { state = STEBAD; continue; } ap_pfill (AP_DATA_TYPE, buf); state = STEDTYPE; /* -- Just drop on through -- */ case STEDTYPE: /* -- data type name end; empty node -- */ state = (ap_lex (buf) == LV_COLON) ? STITER : STEBAD; continue; /* --------------------------- domain ----------------------------------- */ case STDOMAIN: /* -- domain/host; no empty parse node -- */ switch (ap_lex (buf)) { default: state = STEBAD; continue; case LV_COMMENT: ap_pappend (AP_COMMENT, buf); continue; case LV_DLIT: ap_pappend (AP_DOMAIN_LITERAL, buf); state = STEDOMAIN; continue; case LV_WORD: ap_pfill (AP_DOMAIN, buf); state = STEDOMAIN; } /* -- just drop on through -- */ case STEDOMAIN: /* -- domain end; no empty parse node -- */ switch (ap_lex (buf)) { case LV_AT: /* -- sequence of HOST's => @ separation -- */ if (r733_prefptr == NULLAP) r733_prefptr = ap_pcur; ap_palloc (); /* -- node which points to first routing ref -- */ state = STDOMAIN; break; case LV_SEMI: state = STEGRP; break; case LV_GRTR: state = STEPER; break; case LV_COMMA: if (ap_routing != DONE) state = STITER; else state = STEOK; break; case LV_EOD: if (ap_routing != DONE) state = STEBAD; else state = STEOK; break; case LV_COMMENT: ap_pappend (AP_COMMENT, buf); break; case LV_COLON: if (ap_routing != DONE) { ap_routing = DONE; state = STITER; continue; } /* else drop on through */ default: state = STEBAD; break; } continue; } } } /* ------------------------------------------------------------------------ */ void ap_7to8 (r733_prefptr, r822_ptr) AP_ptr r733_prefptr, r822_ptr; { AP_ptr routbase; AP_ptr ap; char *perneeded; PP_DBG (("Lib/addr/ap_7to8()")); /* -- don't have to move it to 822 style -- */ if (r733_prefptr == NULLAP) return; if (ap_pstrt -> ap_obtype == AP_MAILBOX) { perneeded = strdup (r822_ptr -> ap_obvalue); ap_pappend (AP_PERSON_END, NULLCP); } else perneeded = NULLCP; /* -- move the sequence to newroute -- */ routbase = ap_alloc (); while (r733_prefptr -> ap_ptrtype != AP_PTR_NIL && r733_prefptr -> ap_ptrtype != AP_PTR_NXT && r733_prefptr -> ap_next != NULLAP) { switch (r733_prefptr -> ap_next -> ap_obtype) { default: /* -- only move domain info -- */ goto endit; case AP_COMMENT: if (routbase -> ap_next != NULLAP) { /* -- try to append, not prepend, cmnts -- */ PP_DBG (("comment appended'%s'", r733_prefptr->ap_next->ap_obvalue)); ap_move (routbase -> ap_next, r733_prefptr); continue; } /* else drop on through */ case AP_DOMAIN_LITERAL: case AP_DOMAIN: PP_DBG (("val='%s'", r733_prefptr -> ap_next -> ap_obvalue)); ap_move (routbase, r733_prefptr); continue; } } endit: /* treatment here depends on whether we have an 822 route already. Note that 822 pointer is NOT easy, as an easy pointer was too hard! There is a need to copy first part of route to r822_ptr */ if (r822_ptr -> ap_obtype != AP_DOMAIN && r822_ptr -> ap_obtype != AP_DOMAIN_LITERAL) { ap_insert (r822_ptr, AP_PTR_MORE, ap_new (r822_ptr -> ap_obtype, r822_ptr -> ap_obvalue)); free (r822_ptr -> ap_obvalue); ap_fllnode (r822_ptr, routbase -> ap_next -> ap_obtype, routbase -> ap_next -> ap_obvalue); ap_sqinsert (r822_ptr, AP_PTR_MORE, routbase -> ap_next -> ap_next); /* -- add it before local-part -- */ ap_free (routbase); ap_free (routbase -> ap_next); } else { ap = r822_ptr; while (ap -> ap_next -> ap_obtype == AP_DOMAIN || ap -> ap_next -> ap_obtype == AP_DOMAIN_LITERAL) ap = ap -> ap_next; ap_sqinsert (ap, AP_PTR_MORE, routbase -> ap_next); } /* -- need to kludge person name -- */ if (perneeded != 0) { ap_insert (r822_ptr, AP_PTR_MORE, ap_new (r822_ptr -> ap_obtype, r822_ptr -> ap_obvalue)); free (r822_ptr -> ap_obvalue); ap_fllnode (r822_ptr, AP_PERSON_NAME, perneeded); free (perneeded); } }