public inbox for gcc-cvs@sourceware.org help / color / mirror / Atom feed
From: Jason Merrill <jason@gcc.gnu.org> To: gcc-cvs@gcc.gnu.org Subject: [gcc r13-3689] input: add get_source_text_between Date: Fri, 4 Nov 2022 17:07:52 +0000 (GMT) [thread overview] Message-ID: <20221104170807.B79DB3858426@sourceware.org> (raw) https://gcc.gnu.org/g:0386c40eebf1800dc7728ba85f3dbbb9ec4eeb5d commit r13-3689-g0386c40eebf1800dc7728ba85f3dbbb9ec4eeb5d Author: Jeff Chapman II <jchapman@lock3software.com> Date: Thu Nov 3 15:47:47 2022 -0400 input: add get_source_text_between The c++-contracts branch uses this to retrieve the source form of the contract predicate, to be returned by contract_violation::comment(). Co-authored-by: Jason Merrill <jason@redhat.com> gcc/ChangeLog: * input.cc (get_source_text_between): New fn. * input.h (get_source_text_between): Declare. Diff: --- gcc/input.h | 1 + gcc/input.cc | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) diff --git a/gcc/input.h b/gcc/input.h index 11c571d076f..f18769950b5 100644 --- a/gcc/input.h +++ b/gcc/input.h @@ -111,6 +111,7 @@ class char_span }; extern char_span location_get_source_line (const char *file_path, int line); +extern char *get_source_text_between (location_t, location_t); extern bool location_missing_trailing_newline (const char *file_path); diff --git a/gcc/input.cc b/gcc/input.cc index a28abfac5ac..c185bd74c1f 100644 --- a/gcc/input.cc +++ b/gcc/input.cc @@ -949,6 +949,98 @@ location_get_source_line (const char *file_path, int line) return char_span (buffer, len); } +/* Return a NUL-terminated copy of the source text between two locations, or + NULL if the arguments are invalid. The caller is responsible for freeing + the return value. */ + +char * +get_source_text_between (location_t start, location_t end) +{ + expanded_location expstart = + expand_location_to_spelling_point (start, LOCATION_ASPECT_START); + expanded_location expend = + expand_location_to_spelling_point (end, LOCATION_ASPECT_FINISH); + + /* If the locations are in different files or the end comes before the + start, give up and return nothing. */ + if (!expstart.file || !expend.file) + return NULL; + if (strcmp (expstart.file, expend.file) != 0) + return NULL; + if (expstart.line > expend.line) + return NULL; + if (expstart.line == expend.line + && expstart.column > expend.column) + return NULL; + /* These aren't real column numbers, give up. */ + if (expstart.column == 0 || expend.column == 0) + return NULL; + + /* For a single line we need to trim both edges. */ + if (expstart.line == expend.line) + { + char_span line = location_get_source_line (expstart.file, expstart.line); + if (line.length () < 1) + return NULL; + int s = expstart.column - 1; + int len = expend.column - s; + if (line.length () < (size_t)expend.column) + return NULL; + return line.subspan (s, len).xstrdup (); + } + + struct obstack buf_obstack; + obstack_init (&buf_obstack); + + /* Loop through all lines in the range and append each to buf; may trim + parts of the start and end lines off depending on column values. */ + for (int lnum = expstart.line; lnum <= expend.line; ++lnum) + { + char_span line = location_get_source_line (expstart.file, lnum); + if (line.length () < 1 && (lnum != expstart.line && lnum != expend.line)) + continue; + + /* For the first line in the range, only start at expstart.column */ + if (lnum == expstart.line) + { + unsigned off = expstart.column - 1; + if (line.length () < off) + return NULL; + line = line.subspan (off, line.length() - off); + } + /* For the last line, don't go past expend.column */ + else if (lnum == expend.line) + { + if (line.length () < (size_t)expend.column) + return NULL; + line = line.subspan (0, expend.column); + } + + /* Combine spaces at the beginning of later lines. */ + if (lnum > expstart.line) + { + unsigned off; + for (off = 0; off < line.length(); ++off) + if (line[off] != ' ' && line[off] != '\t') + break; + if (off > 0) + { + obstack_1grow (&buf_obstack, ' '); + line = line.subspan (off, line.length() - off); + } + } + + /* This does not include any trailing newlines. */ + obstack_grow (&buf_obstack, line.get_buffer (), line.length ()); + } + + /* NUL-terminate and finish the buf obstack. */ + obstack_1grow (&buf_obstack, 0); + const char *buf = (const char *) obstack_finish (&buf_obstack); + + return xstrdup (buf); +} + /* Determine if FILE_PATH missing a trailing newline on its final line. Only valid to call once all of the file has been loaded, by requesting a line number beyond the end of the file. */
reply other threads:[~2022-11-04 17:07 UTC|newest] Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20221104170807.B79DB3858426@sourceware.org \ --to=jason@gcc.gnu.org \ --cc=gcc-cvs@gcc.gnu.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).