func readRune(r io.RuneScanner) int { rune, _, err := r.ReadRune() if err != nil { return -1 } return rune }
// like in.ReadRune() but ignore all leading whitespace. func ReadChar(in io.RuneScanner) (r rune, size int, err error) { r, size, err = in.ReadRune() for unicode.IsSpace(r) && err == nil { r, size, err = in.ReadRune() } return }
// ParseDelimited returns the string // up to the first unescaped delimiter, // raw newline (rune 0xA), // or the end of input. // A delimiter preceeded by \ is escaped and is non-terminating. // The letter n preceeded by \ is a newline literal. func parseDelimited(delim rune, rs io.RuneScanner) (string, error) { var s string var esc bool for { switch r, _, err := rs.ReadRune(); { case err == io.EOF: return s, nil case err != nil: return "", err case esc && r == delim: s += string(delim) esc = false case r == delim || r == '\n': return s, nil case !esc && r == '\\': esc = true case esc && r == 'n': s += "\n" esc = false default: if esc { s += "\\" } s += string(r) esc = false } } }
// readSDElement reads an SD-ELEMENT as defined by RFC-5424 // // SD-ELEMENT = "[" SD-ID *(SP SD-PARAM) "]" // SD-PARAM = PARAM-NAME "=" %d34 PARAM-VALUE %d34 // SD-ID = SD-NAME // PARAM-NAME = SD-NAME // PARAM-VALUE = UTF-8-STRING ; characters '"', '\' and ']' MUST be escaped. // SD-NAME = 1*32PRINTUSASCII except '=', SP, ']', %d34 (") func readSDElement(r io.RuneScanner) (element StructuredData, err error) { ch, _, err := r.ReadRune() if err != nil { return element, err // hard to reach without underlying IO error } if ch != '[' { return element, BadFormat("StructuredData[]") // unreachable } element.ID, err = readSdID(r) if err != nil { return element, err } for { ch, _, err := r.ReadRune() if err != nil { return element, err } else if ch == ']' { return element, nil } else if ch == ' ' { param, err := readSdParam(r) if err != nil { return element, err } element.Parameters = append(element.Parameters, *param) } else { return element, BadFormat("StructuredData[]") } } }
// readStructuredData reads a STRUCTURED-DATA (as defined in RFC-5424) // from `r` and assigns the StructuredData member. // // STRUCTURED-DATA = NILVALUE / 1*SD-ELEMENT // SD-ELEMENT = "[" SD-ID *(SP SD-PARAM) "]" // SD-PARAM = PARAM-NAME "=" %d34 PARAM-VALUE %d34 // SD-ID = SD-NAME // PARAM-NAME = SD-NAME // PARAM-VALUE = UTF-8-STRING ; characters '"', '\' and ']' MUST be escaped. // SD-NAME = 1*32PRINTUSASCII except '=', SP, ']', %d34 (") func (m *Message) readStructuredData(r io.RuneScanner) (err error) { m.StructuredData = []StructuredData{} ch, _, err := r.ReadRune() if err != nil { return err } if ch == '-' { return nil } r.UnreadRune() for { ch, _, err := r.ReadRune() if err == io.EOF { return nil } else if err != nil { return err // hard to reach without underlying IO error } else if ch == ' ' { r.UnreadRune() return nil } else if ch == '[' { r.UnreadRune() sde, err := readSDElement(r) if err != nil { return err } m.StructuredData = append(m.StructuredData, sde) } else { return BadFormat("StructuredData") } } }
// readPriority reads the PRI as defined in RFC-5424 and assigns Severity and // Facility accordingly. func (m *Message) readPriority(r io.RuneScanner) error { ch, _, err := r.ReadRune() if err != nil { return err } if ch != '<' { return BadFormat("Priority") } rv := &bytes.Buffer{} for { ch, _, err := r.ReadRune() if err != nil { return err } if unicode.IsDigit(ch) { rv.WriteRune(ch) continue } if ch != '>' { return BadFormat("Priority") } // We have a complete integer expression priority, err := strconv.ParseInt(string(rv.Bytes()), 10, 32) if err != nil { return BadFormat("Priority") } m.Priority = int(priority) return nil } }
// ParseNumber parses and returns a positive integer. // Leading spaces are ignored. // If EOF is reached before any digits are encountered, 1 is returned. func parseNumber(rs io.RuneScanner) (int, error) { if err := skipSpace(rs); err != nil { return 0, err } var s string for { switch r, _, err := rs.ReadRune(); { case err == io.EOF: break case err != nil: return 0, err case unicode.IsDigit(r): s += string(r) continue default: if err := rs.UnreadRune(); err != nil { return 0, err } } if len(s) == 0 { return 1, nil } return strconv.Atoi(s) } }
func parseCmd(rs io.RuneScanner) (string, error) { if err := skipSpace(rs); err != nil { return "", err } var esc bool var cmd string for { switch r, _, err := rs.ReadRune(); { case err == io.EOF: return cmd, nil case err != nil: return "", nil case r == '\n': return cmd, nil case r == '\\': esc = true case esc && r == 'n': cmd += "\n" esc = false default: if esc { cmd += "\\" } cmd += string(r) esc = false } } }
// readSpace reads a single space func readSpace(r io.RuneScanner) error { ch, _, err := r.ReadRune() if err != nil { return err } if ch != ' ' { return BadFormat("expected space") } return nil }
// readVersion reads the version string fails if it isn't `1` func (m *Message) readVersion(r io.RuneScanner) error { ch, _, err := r.ReadRune() if err != nil { return err } if ch != '1' { return BadFormat("Version") } return nil }
func chompBOM(r io.RuneScanner) (err error) { for { c, _, err := r.ReadRune() if err != nil { return err } if c != BOM { r.UnreadRune() return nil } } }
func chompWhitespace(r io.RuneScanner) (err error) { for { c, _, err := r.ReadRune() if err != nil { return err } if !unicode.IsSpace(c) { r.UnreadRune() return nil } } }
func skipSingleNewline(rs io.RuneScanner) error { // Eat a single trailing newline. switch r, _, err := rs.ReadRune(); { case err == io.EOF: return nil case err != nil: return err case r == '\n': return nil default: return rs.UnreadRune() } }
func (d *Dec) scan(r io.RuneScanner) error { d.coef.hi = 0 d.coef.lo = 0 d.scale = 0 ch, _, err := r.ReadRune() if err != nil { return err } var neg bool switch ch { case '-': neg = true case '+': default: r.UnreadRune() } var dec bool for { ch, _, err = r.ReadRune() if err == io.EOF { goto ExitLoop } if err != nil { return err } switch { case ch == '.': if dec { r.UnreadRune() goto ExitLoop } dec = true case ch >= '0' && ch <= '9': d.coef.Mul(&d.coef, intTen) var z Int128 z.SetInt64(int64(ch - '0')) d.coef.Add(&d.coef, &z) if dec { d.scale++ } default: r.UnreadRune() goto ExitLoop } } ExitLoop: if neg { d.Neg(d) } return nil }
func parseMarkRune(rs io.RuneScanner) (rune, error) { for { switch r, _, err := rs.ReadRune(); { case err == io.EOF: return '.', nil case err != nil: return 0, err case unicode.IsSpace(r): continue default: return r, nil } } }
// readSdParam reads a PARAM-NAME as defined by RFC-5424 // SD-PARAM = PARAM-NAME "=" %d34 PARAM-VALUE %d34 // PARAM-NAME = SD-NAME // SD-NAME = 1*32PRINTUSASCII except '=', SP, ']', %d34 (") func readSdParamName(r io.RuneScanner) (string, error) { rv := &bytes.Buffer{} for { ch, _, err := r.ReadRune() if err != nil { return "", err } if ch == '=' { r.UnreadRune() return string(rv.Bytes()), nil } rv.WriteRune(ch) } }
func readNumber(b int, r io.RuneScanner) interface{} { s := string(b) for { rune := readRune(r) if rune == -1 || isWhiteSpace(rune) || rune == ')' { r.UnreadRune() return s } s = s + string(rune) } return matchNumer(s) }
func stringReader(flag int, r io.RuneScanner) interface{} { var s string = "" for { rune, _, err := r.ReadRune() if err != nil { panic("err") } if rune == '"' { return s } s = s + string(rune) } return s }
func parseNegation(r io.RuneScanner, glob *globImpl) error { for { char, _, err := r.ReadRune() if err != nil { return err } else if char == '!' { glob.negated = !glob.negated } else { r.UnreadRune() return nil } } }
// SkipSpace consumes and ignores non-newline whitespace. // Terminates if a newline is encountered. // The terminating newline remains consumed. func skipSpace(rs io.RuneScanner) error { for { switch r, _, err := rs.ReadRune(); { case err == io.EOF: return nil case err != nil: return err case r != '\n' && unicode.IsSpace(r): continue default: return rs.UnreadRune() } } }
func scanDigits(rs io.RuneScanner) (string, error) { var s string for { switch r, _, err := rs.ReadRune(); { case err == io.EOF: return s, nil case err != nil: return "", err case !unicode.IsDigit(r): return s, rs.UnreadRune() default: s += string(r) } } }
func parseMarkAddr(rs io.RuneScanner) (SimpleAddress, error) { for { switch r, _, err := rs.ReadRune(); { case err == io.EOF: return nil, errors.New("bad mark: EOF") case err != nil: return nil, err case !unicode.IsSpace(r) || r == '\n': if !isMarkRune(r) { return nil, errors.New("bad mark: " + string(r)) } return Mark(r), nil } } }
func parseText(rs io.RuneScanner) (string, error) { for { switch r, _, err := rs.ReadRune(); { case err == io.EOF: return "", nil case err != nil: return "", err case r == '\n': return parseLines(rs) case unicode.IsSpace(r): continue default: return parseDelimited(r, rs) } } }
func parseLines(rs io.RuneScanner) (string, error) { var s string var nl bool for { switch r, _, err := rs.ReadRune(); { case err == io.EOF: return s, nil case err != nil: return "", err case nl && r == '.': return s, nil default: s += string(r) nl = r == '\n' } } }
// ScanBareIdent reads bare identifier from a rune reader. func ScanBareIdent(r io.RuneScanner) string { // Read every ident character into the buffer. // Non-ident characters and EOF will cause the loop to exit. var buf bytes.Buffer for { ch, _, err := r.ReadRune() if err != nil { break } else if !isIdentChar(ch) { r.UnreadRune() break } else { _, _ = buf.WriteRune(ch) } } return buf.String() }
// readWord reads `r` until it encounters a space (0x20) func readWord(r io.RuneScanner) (string, error) { rv := &bytes.Buffer{} for { ch, _, err := r.ReadRune() if err != nil { return "", err } else if ch != ' ' { rv.WriteRune(ch) } else { r.UnreadRune() rvString := string(rv.Bytes()) if rvString == "-" { rvString = "" } return rvString, nil } } }
// readSdParam reads an SD-PARAM as defined by RFC-5424 // SD-PARAM = PARAM-NAME "=" %d34 PARAM-VALUE %d34 // SD-ID = SD-NAME // PARAM-NAME = SD-NAME // PARAM-VALUE = UTF-8-STRING ; characters '"', '\' and ']' MUST be escaped. // SD-NAME = 1*32PRINTUSASCII except '=', SP, ']', %d34 (") func readSdParam(r io.RuneScanner) (sdp *SDParam, err error) { sdp = &SDParam{} sdp.Name, err = readSdParamName(r) if err != nil { return nil, err } ch, _, err := r.ReadRune() if err != nil { return nil, err // hard to reach } if ch != '=' { return nil, BadFormat("StructuredData[].Parameters") // not reachable } sdp.Value, err = readSdParamValue(r) if err != nil { return nil, err } return sdp, nil }
func ReadList(in io.RuneScanner) Sexper { ch, _, _ := ReadChar(in) chstr := string(ch) switch chstr { case ")": return NIL case ".": list := ReadList(in) if list == NIL || fn_cdr(list) != NIL { panic(ERROR_DOT) } return fn_car(list) default: in.UnreadRune() scar := ReadSexp(in) scdr := ReadList(in) return List{scar, scdr} } }
// scanEscapeCommand scans to the end of the current escape sequence. The scanner // must be positioned at an escape rune (esc or the unicode CSI). func scanEscapeCommand(s io.RuneScanner) (Command, error) { csi := false esc, _, err := s.ReadRune() if err != nil { return nil, err } if esc != escape && esc != monogramCsi { panic(fmt.Errorf("not positioned at beginning of escape sequence, saw: %v", esc)) } if esc == monogramCsi { csi = true } var args bytes.Buffer quote := false for i := 0; ; i++ { r, _, err := s.ReadRune() if err != nil { return nil, err } if i == 0 && r == '[' { csi = true continue } if !csi { return escapeCommand{r, ""}, nil } else if quote == false && unicode.Is(csEnd, r) { return escapeCommand{r, args.String()}, nil } if r == '"' { quote = !quote } // Otherwise, we're still in the args, and this rune is one of those args. if _, err := args.WriteRune(r); err != nil { panic(err) // WriteRune cannot return an error from bytes.Buffer. } } }
func ReadSexp(in io.RuneScanner) Sexper { ch, _, _ := ReadChar(in) switch string(ch) { case "\"": return ReadString(in) case "(": return ReadList(in) case "'": return fn_cons(Atom{"quote"}, fn_cons(ReadSexp(in), NIL)) case ")": panic("unexcepted ')' found") default: in.UnreadRune() if unicode.IsDigit(ch) { return ReadNumber(in) } else { return ReadAtom(in) } } }