// Parse reference. Assumes string begins with '[' character. // Modify refmap if a reference is encountered. // Return 0 if no reference found, otherwise position of subject // after reference is parsed. public static int ParseReference(Subject subj) { string title; var startPos = subj.Position; // parse label: var lab = ParseReferenceLabel(subj); if (lab == null || lab.Value.Length > Reference.MaximumReferenceLabelLength) { goto INVALID; } if (!Scanner.HasNonWhitespace(lab.Value)) { goto INVALID; } // colon: if (peek_char(subj) == ':') { subj.Position++; } else { goto INVALID; } // parse link url: spnl(subj); var matchlen = Scanner.scan_link_url(subj.Buffer, subj.Position, subj.Length); if (matchlen == 0) { goto INVALID; } var url = subj.Buffer.Substring(subj.Position, matchlen); url = CleanUrl(url); subj.Position += matchlen; // parse optional link_title var beforetitle = subj.Position; spnl(subj); matchlen = Scanner.scan_link_title(subj.Buffer, subj.Position, subj.Length); if (matchlen > 0) { title = subj.Buffer.Substring(subj.Position, matchlen); title = CleanTitle(title); subj.Position += matchlen; } else { subj.Position = beforetitle; title = string.Empty; } // parse final spaces and newline: while (peek_char(subj) == ' ') { subj.Position++; } if (peek_char(subj) == '\n') { subj.Position++; } else if (peek_char(subj) != '\0') { goto INVALID; } // insert reference into refmap AddReference(subj.ReferenceMap, lab.Value, url, title); return(subj.Position); INVALID: subj.Position = startPos; return(0); }
// Parse a link or the link portion of an image, or return a fallback. static Reference ParseLinkDetails(Subject subj) { int n; int sps; int endlabel, starturl, endurl, starttitle, endtitle, endall; string url, title; endlabel = subj.Position; var c = peek_char(subj); if (c == '(' && ((sps = Scanner.scan_spacechars(subj.Buffer, subj.Position + 1, subj.Length)) > -1) && ((n = Scanner.scan_link_url(subj.Buffer, subj.Position + 1 + sps, subj.Length)) > -1)) { // try to parse an explicit link: starturl = subj.Position + 1 + sps; // after ( endurl = starturl + n; starttitle = endurl + Scanner.scan_spacechars(subj.Buffer, endurl, subj.Length); // ensure there are spaces btw url and title endtitle = (starttitle == endurl) ? starttitle : starttitle + Scanner.scan_link_title(subj.Buffer, starttitle, subj.Length); endall = endtitle + Scanner.scan_spacechars(subj.Buffer, endtitle, subj.Length); if (endall < subj.Length && subj.Buffer[endall] == ')') { subj.Position = endall + 1; url = subj.Buffer.Substring(starturl, endurl - starturl); url = CleanUrl(url); title = subj.Buffer.Substring(starttitle, endtitle - starttitle); title = CleanTitle(title); return(new Reference() { Title = title, Url = url }); } } else if (c == '[' || c == ' ' || c == '\n') { var label = ParseReferenceLabel(subj); if (label != null) { if (label.Value.Length == 0) { return(Reference.SelfReference); } var details = LookupReference(subj.ReferenceMap, label.Value); if (details != null) { return(details); } // rollback the subject but return InvalidReference so that the caller knows not to // parse 'foo' from [foo][bar]. subj.Position = endlabel; return(Reference.InvalidReference); } } // rollback the subject position because didn't match anything. subj.Position = endlabel; return(null); }