From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2122) id B79DB3858426; Fri, 4 Nov 2022 17:07:52 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org B79DB3858426 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1667581687; bh=ihs2m7XTc67B3Z01NtSZ+lNxdLz07J5n9eBi6CsKpMM=; h=From:To:Subject:Date:From; b=Vuqvm7CiKFz0AjZydB0gGynCqYZFuxhophDPVU+mmYDp2hdcDNo4ff/X8KLRCVXYY goUR1pStSDueO5BgkZknZnQy857Qvyc6cb/WdConfCfVdtpP2I9xwFsFbkay0XbYFk tFqqXjc9B8FJ2sx+KrNSfIuClTTsr2vXTh06Jjzg= MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Jason Merrill To: gcc-cvs@gcc.gnu.org Subject: [gcc r13-3689] input: add get_source_text_between X-Act-Checkin: gcc X-Git-Author: Jeff Chapman II X-Git-Refname: refs/heads/master X-Git-Oldrev: 679be32e66428f0ba81d1c1b55f7bd47f01cb295 X-Git-Newrev: 0386c40eebf1800dc7728ba85f3dbbb9ec4eeb5d Message-Id: <20221104170807.B79DB3858426@sourceware.org> Date: Fri, 4 Nov 2022 17:07:52 +0000 (GMT) List-Id: https://gcc.gnu.org/g:0386c40eebf1800dc7728ba85f3dbbb9ec4eeb5d commit r13-3689-g0386c40eebf1800dc7728ba85f3dbbb9ec4eeb5d Author: Jeff Chapman II 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 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. */