Compare commits

..

242 Commits
v4.2 ... v4.3

Author SHA1 Message Date
Benno Schulenberg
b8987a1e40 po: update translations and regenerate POT file and PO files 2019-06-18 10:33:21 +02:00
Benno Schulenberg
895d2b8e9c bump version numbers and add a news item for the 4.3 release 2019-06-18 10:04:16 +02:00
Benno Schulenberg
47068c3770 build: fix compilation when configured with --disable-color 2019-06-17 09:59:15 +02:00
Benno Schulenberg
345cf5accc files: don't close a newly-created buffer when it is the only one
This fixes https://savannah.gnu.org/bugs/?56504.
Reported-by: Liu Hao <lh_mouse@126.com>

Bug existed since commit 7e422402 from two weeks ago.
2019-06-16 19:12:52 +02:00
Benno Schulenberg
c7ca60b046 tweaks: don't check the user's nanorc file for accessibility twice
Also, condense some alternatives into a single 'if'.
2019-06-16 17:53:44 +02:00
Benno Schulenberg
01e4f85f29 tweaks: remove a check that is no longer relevant
Since commit 7028adf2 from three days ago, also the color commands of
syntaxes that are defined in a main nanorc will get parsed during a
second pass, so it is perfectly possible to extend such syntaxes
later on in the same (or another) nanorc file.
2019-06-16 11:02:03 +02:00
Benno Schulenberg
6bfbb2bcd9 tweaks: remove two more unneeded assignments
'opensyntax' is relevant only during the first pass through all the
nanorc files (intros_only == TRUE) when it is checked that syntax
commands are grouped properly and not mixed with others.  And
'lastcolor' is relevant only during the second pass of a specific
syntax, because only then the color commands are actually parsed.
2019-06-16 10:41:53 +02:00
Benno Schulenberg
d82c753ba4 rcfile: at terminating points, verify that a defined syntax is not empty
Whenever, in an rcfile, a command is encountered that is not part of a
syntax definition, a currently open syntax should be closed, but only
after checking that the syntax contains at least one color command.

This fixes https://savannah.gnu.org/bugs/?56501.

Bug existed since version 2.3.3.
2019-06-15 19:42:31 +02:00
Benno Schulenberg
0af9ce926b rcfile: close off a syntax when a non-syntax command is encountered
The 'color' commands of a syntax definition should not be allowed to
be interspersed with other, non-syntax commands.

This fixes https://savannah.gnu.org/bugs/?56498.

Bug existed since before version 2.6.0.
2019-06-15 15:07:57 +02:00
Benno Schulenberg
4e14a8a977 tweaks: remove two unneeded assignments, and improve a comment
Also reshuffle a line, for esthetics.
2019-06-15 14:35:53 +02:00
Benno Schulenberg
accd17c249 tweaks: remove four unneeded pre-processor directives
The parse_next_word() function is not being used by the history code
anymore since commit ecd18c16, more than two years ago.
2019-06-15 14:17:13 +02:00
Benno Schulenberg
e8eb30cad6 tweaks: just mark four rcfile errors for translation, like the others
The messages get translated when they get stored in the linked list.
This is to economize on the number of actual calls of gettext().
2019-06-15 14:13:20 +02:00
Benno Schulenberg
36bd68f3ab tweaks: rename a function, to better suit what it does 2019-06-15 14:07:57 +02:00
Benno Schulenberg
03692363a2 tweaks: move a syntax check to a better place, to reduce duplication 2019-06-15 13:04:01 +02:00
Benno Schulenberg
0e94575c6b rcfile: check for missing color commands only when a syntax is still open
This fixes https://savannah.gnu.org/bugs/?56497.

Bug existed since commit 7028adf2 from two days ago.
2019-06-15 12:17:33 +02:00
Benno Schulenberg
27cc3117e2 tweaks: rename two parameters, for more contrast, and elide another
Also rename a function.
2019-06-14 10:56:49 +02:00
Benno Schulenberg
19f71632c8 tweaks: remove an unneeded "closing" of a syntax after extending it
As 'extendsyntax' commands are no longer interpreted immediately when
the rcfiles are read, there is no need to set 'opensyntax' to FALSE
after interpreting such a command -- for a single syntax they are all
interpreted in a row.
2019-06-14 10:56:49 +02:00
Benno Schulenberg
e3f18e7a6c tweaks: rename two variables, and frob some comments
Also reshuffle the newline stripping, as it's pointless for lines
that are skipped.
2019-06-14 10:56:49 +02:00
Benno Schulenberg
b55923f5ec tweaks: reshuffle some lines, to group things more sensibly 2019-06-14 10:56:49 +02:00
Benno Schulenberg
7028adf211 rcfile: fully read each included file, so all its syntaxes are seen
An included file can contain multiple syntaxes.  If reading would stop
as soon as a command different from 'syntax' and 'header' and 'magic'
is found, any later syntaxes would not be seen.  So each nanorc file
needs to be fully scanned -- it's just the interpretation of all the
color commands that we want to delay until the syntax gets actually
used.

This fixes https://savannah.gnu.org/bugs/?56478.

Bug existed since commit cba9d8d0 from a month ago.
2019-06-14 10:49:30 +02:00
Benno Schulenberg
d7df7c694a tweaks: elide a pre-processor #else clause, by using braces instead 2019-06-13 15:47:29 +02:00
Benno Schulenberg
ce69d5be88 tweaks: condense two comments, and normalize the whitespace of a label 2019-06-12 11:10:27 +02:00
Benno Schulenberg
3da4240229 tweaks: rename a variable, to fit a little better 2019-06-12 11:03:03 +02:00
Benno Schulenberg
43caf7bb7b tweaks: avoid an unneeded, extra stat() for temporary files 2019-06-12 10:48:03 +02:00
Benno Schulenberg
e8e30e5197 tweaks: elide an unneeded, duplicate stat() for the FIFO check 2019-06-12 10:34:53 +02:00
Benno Schulenberg
189de5ee78 files: suppress feedback when writing an emergency or temporary file
This fixes https://savannah.gnu.org/bugs/?56474.

Bug existed since commit 47770bd3 from two weeks ago.
2019-06-12 09:51:14 +02:00
Benno Schulenberg
c57d040e99 tweaks: don't bother calling mblen() in a non-UTF-8 build
There is no need, because in non-UTF-8 encodings nano treats
each single byte as one character anyway.
2019-06-11 19:48:03 +02:00
Benno Schulenberg
0adb15c7a1 display: properly show all characters in a non-UTF-8 build
Also, don't use mblen() directly, to not get stuck when it returns -1,
which it will when running a non-UTF-8 build in a UTF-8 locale.

This fixes https://savannah.gnu.org/bugs/?56472.

Bug existed since commit cd094822 from yesterday.
2019-06-11 19:07:34 +02:00
Benno Schulenberg
1e48df388e build: avoid a warning when using --disable-utf8 2019-06-11 14:24:30 +02:00
Benno Schulenberg
d477775871 build: avoid a warning on FreeBSD, OpenBSD, and Alpine 2019-06-11 12:29:32 +02:00
Benno Schulenberg
ed40fd8031 tweaks: reorder some code, to further optimize display_string() for ASCII
The majority of characters in the files that get edited with nano will
be single-byte printable ASCII characters, so their case should come
first in the main loop of display_string().
2019-06-11 12:08:28 +02:00
Benno Schulenberg
5c4b0b38f4 chars: redo the speedup for plain ASCII from three commits ago
It was lost in the elision of length_of_char() two commits ago.
2019-06-11 11:10:53 +02:00
Benno Schulenberg
bd331b0198 tweaks: reshuffle some lines and frob some comments 2019-06-10 20:07:10 +02:00
Benno Schulenberg
cd09482231 tweaks: elide a function that is an amalgam of three others
In addition, the function was used just once, had a weird return value,
and now some more code can be excluded from a non-UTF8 build.

Make use of the fact that any single-byte character always occupies
just one column, and call the costly mbtowc() and wcwidth() only for
characters that actually are multibyte.
2019-06-10 19:43:50 +02:00
Benno Schulenberg
c5955d14ce chars: speed up the determination of length and width for plain ASCII 2019-06-10 17:22:41 +02:00
Benno Schulenberg
7d38379919 tweaks: rename two parameters, away from single letters 2019-06-10 12:36:16 +02:00
Benno Schulenberg
45bf18f8fe tweaks: rename three variables, to get rid of a suffix or an underscore
Also drop an unneeded cast.
2019-06-10 12:34:24 +02:00
Benno Schulenberg
787dca6724 tweaks: elide an unneeded variable 2019-06-10 12:06:12 +02:00
Benno Schulenberg
15e36956b5 tweaks: avoid parsing a character twice
Let mbtowc() do all the work, and thus also elide a variable.
2019-06-10 12:01:10 +02:00
Benno Schulenberg
967f581860 tweaks: adjust some whitespace and rewrap a few lines
And remove two unneeded casts.
2019-06-09 20:03:44 +02:00
Benno Schulenberg
1075de1222 tweaks: rename two functions, to get rid of the "mb" abbreviation
Also, for me "move" is about moving the cursor.  But these functions
are about moving an index in a text, which is more general.
2019-06-09 19:37:56 +02:00
Benno Schulenberg
3457039cee tweaks: rename a variable, to get out of the way of the next commit 2019-06-09 19:31:01 +02:00
Benno Schulenberg
ca77254968 tweaks: use a slightly faster function where appropriate
Also, correct a call of move_mbright() to use the intended format.
2019-06-09 19:22:24 +02:00
Benno Schulenberg
710a600f22 chars: speed up case-insensitive searching by roughly one percent
It is less of a speedup than I was hoping for, though.
2019-06-09 19:13:25 +02:00
Benno Schulenberg
843eef65b8 tweaks: put some timing code back into the search function 2019-06-09 18:48:52 +02:00
Benno Schulenberg
781c7a7a5f chars: create a dedicated function for getting the length of a character
Instead of calling in twenty places parse_mbchar(pointer, NULL, NULL),
use a simpler and faster char_length(pointer).  This saves pushing two
unneeded parameters onto the stack, avoids two needless ifs, and elides
an intermediate variable.

Its main purpose will follow in a later commit: to speed up searching.
2019-06-09 18:38:46 +02:00
Benno Schulenberg
aa205f58ca tweaks: rename a bunch of variables, to become identical to others 2019-06-09 17:07:02 +02:00
Benno Schulenberg
3bf04afa6d tweaks: specifically refer to the manual of GNU grep for more regex info 2019-06-09 12:30:35 +02:00
Benno Schulenberg
71236e145d tweaks: rename two variables, away from a single letter
And adjust the indentation after the previous change.
2019-06-09 11:08:34 +02:00
Benno Schulenberg
7be76af418 tweaks: speed up the counting of characters in mbstrlen()
This function is used in get_totsize(), so speed is important.

There is no reason why the length of the string must limited to a
certain size -- that is just a leftover from the function merge in
commit ba2e6f43 from a year ago.
2019-06-09 11:04:52 +02:00
Benno Schulenberg
fb17929fab tweaks: use FALSE for booleans instead of zero
Also adjust some indentation and reduce the scope of a variable.
2019-06-09 10:41:14 +02:00
Benno Schulenberg
fea1901592 docs: remove "--" from the default value of 'quotestr'
Adjust the documentation to the removal of "--" in the previous commit.
2019-06-08 17:48:44 +02:00
Benno Schulenberg
33fea90bcd justify: remove "--" from the quoting regex, to avoid false paragraphs
The use of a double dash (for an option name or as sentence separator)
is too common to allow it to be seen always as a comment introducer.
Users of Lua and Postgres will have to redefine 'quotestr' themselves
if they want to be able to rewrap block comments with ^J.

The other characters that were added in commit c5a72103 (!, %, and ;)
are less problematic because they tend to be glued to the end of words,
so they are unlikely to appear at the start of a line.

This fixes https://savannah.gnu.org/bugs/?56462,
and fixes https://savannah.gnu.org/bugs/?56461.

Bug existed since version 4.0, commit c5a72103.
2019-06-08 16:47:08 +02:00
Benno Schulenberg
f03c87c300 tweaks: squeeze excess spaces out of a line in situ
There is no need to make a copy of the line, because if there are some
bytes that are moved, they are always moved toward the left -- the line
can only shrink, never expand.
2019-06-08 16:17:59 +02:00
Benno Schulenberg
45b1a38b82 tweaks: factor out a fragment of code that is repeated three times 2019-06-08 14:17:41 +02:00
Benno Schulenberg
c3bf17a801 tweaks: improve a handful of comments 2019-06-08 14:00:24 +02:00
Benno Schulenberg
8582e4a6b9 tweaks: don't bother keeping track of whether a squeezed line has shrunk
When squeezing excess spaces from a line has proved unsuccessful, we
have already copied all of its data, so it hardly makes a difference
whether we free the old or the new data.  Choose to free always the
old data, so that we can simplify things.
2019-06-08 14:00:03 +02:00
Benno Schulenberg
9b34d0a4fb tweaks: rename two variables, to be unique 2019-06-08 10:10:31 +02:00
Benno Schulenberg
26d16ab9d1 tweaks: rename a variable, to better suit its counterpart 2019-06-08 10:05:32 +02:00
Benno Schulenberg
6ca8518428 tweaks: make better use of two variables, and reshuffle two comments 2019-06-08 10:03:15 +02:00
Benno Schulenberg
f2c61c4b9a docs: mention the default value for 'errorcolor' 2019-06-07 11:24:51 +02:00
Benno Schulenberg
c4e04eb682 docs: show double quotes where they are needed
Instead of saying that string parameters should be enclosed in
double quotes, just show the quotes in the relevant commands.

Also, rename the parameters, to better fit the subsequent description.
2019-06-07 11:15:02 +02:00
Benno Schulenberg
0b257fe558 tweaks: sort three translator names better 2019-06-06 15:22:02 +02:00
Benno Schulenberg
941637615b docs: clarify that in nano regexes are extended regular expressions
And add a concise summary of the most important special characters.

This addresses https://savannah.gnu.org/bugs/?56438.
2019-06-06 15:16:56 +02:00
Benno Schulenberg
378aa8bc41 docs: slightly reword the notice about the changed defaults since 4.0 2019-06-05 19:40:15 +02:00
Benno Schulenberg
157098ee75 gnulib: update to its current upstream state 2019-06-05 16:45:27 +02:00
Benno Schulenberg
8d4e171d3c tweaks: improve a couple of comments 2019-06-05 16:23:34 +02:00
Benno Schulenberg
6f1e5912a9 tweaks: stop allocating and freeing a holder struct for every cut/paste
This "holder" information is needed for every cut and paste and other
block operation.  Instead of allocating and freeing it for every such
operation, just have the six elements as static variables.  This saves
a little churn, and saves having to declare a type that is used just
once.  Plus, the access to these variables will be a little quicker.
2019-06-05 16:10:07 +02:00
Benno Schulenberg
28a6d9f300 tweaks: rename four elements of the holder struct, for more contrast 2019-06-05 15:32:50 +02:00
Benno Schulenberg
f92606491c speller: when something goes wrong with 'sort', do not blame 'spell'
That is, check the exit status of 'sort' before the one of 'spell'.
2019-06-05 15:07:33 +02:00
Benno Schulenberg
260588af1e speller: be more concise and to the point when something goes wrong 2019-06-05 14:57:24 +02:00
Benno Schulenberg
cdc9482d8f tweaks: rename three variables, to use full words instead of abbrevs 2019-06-05 14:50:01 +02:00
Benno Schulenberg
7c1b649eb8 tweaks: rename a function and its parameters, to be more fitting
Also, reshuffle their order, and improve or adjust some comments.
And change the type of 'pairnum' to short, what ncurses uses too.
2019-06-05 13:08:14 +02:00
Brand Huntsman
57b3f83cfe rcfile: compile the color regexes just once
When a syntax gets parsed, store the compiled color regexes right away,
instead of compiling them a second time in color_update().

This addresses https://savannah.gnu.org/bugs/?56432.

Signed-off-by: Brand Huntsman <alpha@qzx.com>
Signed-off-by: Benno Schulenberg <bensberg@telfort.nl>
2019-06-04 19:57:46 +02:00
Benno Schulenberg
edbdcb9b9a docs: add a light warning to the explanation of --nonewlines 2019-06-04 19:54:58 +02:00
Benno Schulenberg
a6978b54f1 docs: say thanks to the Korean translator, and trim a double space 2019-06-04 19:32:52 +02:00
Brand Huntsman
8bc2d18fa9 tweaks: remove an unneeded pre-processor '#else' clause
Commit 1e2e6733 added braces and made the semicolon no longer needed
when libmagic is not used.

Signed-off-by: Brand Huntsman <alpha@qzx.com>
2019-06-04 19:27:34 +02:00
Brand Huntsman
fb10a94f35 startup: prevent a crash when no applicable syntax is found
This fixes https://savannah.gnu.org/bugs/?56434.

Signed-off-by: Brand Huntsman <alpha@qzx.com>
2019-06-04 12:42:24 +02:00
Benno Schulenberg
9b30bb15cc tweaks: adjust the indentation after the previous change
And reshuffle two declarations.
2019-06-03 15:51:07 +02:00
Benno Schulenberg
a1669e1bfd rcfile: disallow extending a syntax that is defined in a main nanorc
The /etc/nanorc file should not define any syntax directly (and
preferably not include any either, to not slow startup down with
syntaxes the user is never going to use), and if the ~/.nanorc file
defines a syntax directly, there is no need to use 'extendsyntax':
the command can be added to the syntax itself -- it would be better
even: it keeps things together.
2019-06-03 15:42:06 +02:00
Benno Schulenberg
3d6eca3f26 tweaks: reshuffle some lines, to put the most likely candidate first 2019-06-03 15:04:00 +02:00
Benno Schulenberg
c025a60ce9 tweaks: rename a function and a variable, for contrast and variety 2019-06-03 15:01:28 +02:00
Benno Schulenberg
5e1f90d8fa tweaks: don't bother to free the content of 'extendsyntax' commands
Extending a syntax will be rather rare, so the amount of memory it
takes up will be minimal.  It's not worth the trouble to free this
memory -- it only takes time.  Plus: we don't bother to free the
memory of a syntax that gets fully redefined either.
2019-06-03 14:37:27 +02:00
Benno Schulenberg
7f3ffe8544 tweaks: remove a bit of redundant code
When an included file has just been fully parsed, 'lastcolor' is still
pointing at the last color regex that was added to the list -- no need
to refind the end of this list.
2019-06-03 14:21:17 +02:00
Benno Schulenberg
ea1016efdb feedback: make an error check work also when curses hasn't started yet
Add a temporary boolean for this, because isendwin() returns TRUE
only when curses mode has actually been started with initscr() and
then exited with endwin().
2019-06-03 13:38:21 +02:00
Benno Schulenberg
f63fee79e3 tweaks: merge two functions, as the first is called just once 2019-06-01 11:14:21 +02:00
Benno Schulenberg
2003413989 tweaks: move a function to the file where it is used 2019-06-01 10:52:38 +02:00
Benno Schulenberg
9369af77ce tweaks: elide a function that is used just once 2019-06-01 10:43:50 +02:00
Benno Schulenberg
35d2bc6b38 build: fix compilation on another system
The <signal.h> header file is needed to define 'sig_atomic_t'.
(Don't know why on my main system it compiled fine without it.)
2019-05-31 20:53:00 +02:00
Benno Schulenberg
b52d166afa tweaks: rename a type, to make more sense
The sphere, the holder, is everything *around* the partition;
it was confusing to call this holder type 'partition'.

Also correct and improve some comments.
2019-05-31 19:44:47 +02:00
Benno Schulenberg
3952dcb629 tweaks: rename a variable, reduce its scope, and use it consistently 2019-05-31 19:25:50 +02:00
Benno Schulenberg
7e9dd385f5 tweaks: elide a parameter and a return value
As 'filepart' is a global variable, there is no need to pass it around.
Just use it directly.
2019-05-31 19:00:20 +02:00
Benno Schulenberg
2e81023553 tweaks: rename two variables, and reshuffle their declarations 2019-05-31 17:45:51 +02:00
Benno Schulenberg
b9f994b2c0 tweaks: elide a variable, drop a comment, and remove unneeded braces
There is no need to save, clear, and restore the mark when counting
words, lines and characters, because partitioning and unpartitioning
the buffer does not use the mark nor affect it.
2019-05-31 17:43:40 +02:00
Benno Schulenberg
e98847200e tweaks: reshuffle some lines, to reduce duplication 2019-05-31 17:42:42 +02:00
Benno Schulenberg
a77b21388a build: remove two #includes that don't seem to be needed 2019-05-31 17:16:07 +02:00
Benno Schulenberg
58ca5fb0f3 build: move an #include to where it is needed 2019-05-31 17:14:28 +02:00
Benno Schulenberg
844214b4a0 tweaks: rename two variables, to not be abbreviations
Also reshuffle two declarations.
2019-05-31 12:54:20 +02:00
Benno Schulenberg
f9dfca7d5a tweaks: rename a variable, to be shorter 2019-05-31 12:46:15 +02:00
Benno Schulenberg
fe40e8867d tweaks: rename a struct element, to be distinct
And to match the style of its sisters.
2019-05-31 12:25:15 +02:00
Benno Schulenberg
923a90cba0 tweaks: rename a type, for more contrast 2019-05-31 12:18:30 +02:00
Benno Schulenberg
5817e83e33 tweaks: be more sparing in redrawing things when exiting from help viewer
That is: don't redraw the title bar twice, don't redraw the bottom bars
twice, nor unnecessarily redraw the whole screen.
2019-05-31 10:28:23 +02:00
Benno Schulenberg
122cabd3ba tweaks: elide another parameter, and rename the function to match 2019-05-31 09:33:28 +02:00
Benno Schulenberg
c5d157dd9d tweaks: close a buffer differently and elide a parameter 2019-05-31 09:15:12 +02:00
Benno Schulenberg
3a65c0d192 feedback: when the last line is empty, don't include it in the count
Now M-D will report 0 lines instead of 1 line for an empty buffer, and
will match the output of 'wc --lines' as long the file is a POSIX file.

This fixes https://savannah.gnu.org/bugs/?56054.

Bug existed since before version 2.1.10.
2019-05-30 19:51:25 +02:00
Benno Schulenberg
e1c011c9a1 tweaks: rename a variable, to match the style of its brothers 2019-05-30 19:34:57 +02:00
Benno Schulenberg
477ff49f66 feedback: don't try to represent keys outside of the seven-bit range
This fixes https://savannah.gnu.org/bugs/?56415.
2019-05-30 19:06:06 +02:00
Benno Schulenberg
85eb9b9a53 tweaks: use a cheaper way to switch between buffers where possible
For this one quick switch back and forth there is no need to report
anything on the status bar nor to update colors and such.  In this
case, those things are just a waste of time.
2019-05-30 17:42:37 +02:00
Benno Schulenberg
484523b3bb tweaks: drop two checks that were made redundant by the previous commit 2019-05-30 17:18:30 +02:00
Benno Schulenberg
5a48edc9ae tweaks: reshuffle some code to the one place that needs it
The extra things that close_buffer() did are only needed and useful
when manually closing a buffer, so move them there.  The other three
calls of close_buffer() only need to get rid of the current buffer
(making the preceding buffer the new current one) and nothing else.
2019-05-30 17:09:49 +02:00
Benno Schulenberg
6dc8570d55 tweaks: reshuffle a few things, partly to make two chunks more alike 2019-05-30 16:00:11 +02:00
Benno Schulenberg
7e422402d5 tweaks: change a function to void, to make things more direct 2019-05-29 20:02:50 +02:00
Benno Schulenberg
5f03c20ea0 tweaks: switch to the preceding buffer in a cheaper way (when in help)
When a help-text buffer is closed while exiting from the help viewer,
the rest of the exit code takes care that the preceding buffer gets
displayed properly.  And when a help-text buffer is closed because a
SIGWINCH occurred, doing anything for the preceding buffer is a waste
of time because a new help-text buffer will be opened and displayed
instantly.
2019-05-29 19:48:42 +02:00
Benno Schulenberg
71574e7a6f tweaks: reshuffle some closing and switching to a better place
And rename the function and elide a parameter besides.
2019-05-29 19:48:42 +02:00
Benno Schulenberg
821445d284 tweaks: drop some checks that were made redundant by the previous commit
And move one to a better place.
2019-05-29 19:48:42 +02:00
Benno Schulenberg
3eab405e7b help: write the text directly into a new buffer, without using a tempfile
This avoids the substantial overhead of first writing and then reading a
temporary file, and in the bargain removes two possible failure points.

This fulfills https://savannah.gnu.org/bugs/?56371.
2019-05-29 19:48:42 +02:00
Benno Schulenberg
423ed031b4 help: don't cycle through the buffers for every resizing step
Closing a buffer automatically switches to the next buffer.  But for
the help-text buffer this is not the desired behavior, so each closing
needs to be followed by a switch to the preceding buffer.

This fixes https://savannah.gnu.org/bugs/?56411.
2019-05-29 12:33:59 +02:00
Benno Schulenberg
57390cff04 tweaks: exclude another bug check from the tiny version 2019-05-29 11:24:25 +02:00
Benno Schulenberg
4e637cd1c7 tweaks: delete a now-unused function 2019-05-28 17:41:28 +02:00
Benno Schulenberg
add1159675 tweaks: don't bother checking the return value of wait()
It is not done for the external spell checker either.
2019-05-28 17:39:19 +02:00
Benno Schulenberg
dbdf38cce5 tweaks: consistently report failures to fork (and the like) as errors 2019-05-28 17:36:32 +02:00
Benno Schulenberg
47770bd321 feedback: treat statusline() being called outside of curses mode as a bug 2019-05-28 17:19:34 +02:00
Benno Schulenberg
d656b0d3b9 feedback: show an appropriate message when reading a file was cut short 2019-05-28 17:06:07 +02:00
Benno Schulenberg
d9deaf9f2f tweaks: reduce the scope of a variable, and let the compiler zero it
Also, rename the variable, to have a unique name.
2019-05-28 14:09:54 +02:00
Benno Schulenberg
b75563b88e tweaks: use a symbol instead of zero to refer to standard input 2019-05-28 12:31:16 +02:00
Benno Schulenberg
33e1bf1435 startup: remove the now-unneeded workaround for a SIGWINCH during input
The previous commit makes that the terminal's state is only resaved
when standard input is actually reconnected to the terminal, and
leaves it unchanged otherwise.  Apparently this is enough to fix
https://savannah.gnu.org/bugs/?56394.
2019-05-28 12:19:49 +02:00
Benno Schulenberg
d946f38a2b files: when needed, reconnect the keyboard and reenter curses mode
When after reading a file we are not in curses mode, it means we have
read data from standard input, either from the keyboard or from a pipe.
In the latter case, we first need to reconnect standard input to the tty.
And in both cases, we then need to reenter curses mode before being able
to display the number of lines that were read (or an error message).

So, move the reconnecting code from scoop_stdin() to its own function,
and call this function from read_file() when needed.

This fixes https://savannah.gnu.org/bugs/?56310.

Bug existed since version 2.1.8 when reading from stdin was introduced.
2019-05-28 11:28:23 +02:00
Benno Schulenberg
b53dffaeed startup: resave the terminal's state only when there were no signals
For some reason a SIGWINCH or SIGINT "corrupts" the current state of
the terminal, and magically validates the state that was saved first.

This fixes https://savannah.gnu.org/bugs/?56394 properly.
2019-05-27 19:35:46 +02:00
Benno Schulenberg
6dcfcd11ce tweaks: rename two functions, to better describe what they do 2019-05-27 17:24:35 +02:00
Benno Schulenberg
f21b094dad tweaks: condense a couple of comments, and reshuffle a line 2019-05-27 17:21:05 +02:00
Benno Schulenberg
a521ac4ae7 tweaks: exclude a bug check from the tiny version 2019-05-27 10:11:22 +02:00
Benno Schulenberg
d972c17050 build: exclude the ability to open a FIFO from the tiny version 2019-05-27 09:55:24 +02:00
Benno Schulenberg
f6e182ca72 tweaks: check in a single place for files that should not be opened 2019-05-27 09:42:41 +02:00
Benno Schulenberg
6a83bb7508 tweaks: delete a leftover 2019-05-27 09:33:36 +02:00
Benno Schulenberg
728498fde5 files: don't say "Error...: Success" when aborting after resizing
For some reason 'errno' is not EINTR but zero when a SIGINT is
produced after a SIGWINCH.
2019-05-26 19:49:23 +02:00
Brand Huntsman
05f34bbfaf files: block SIGWINCH while opening a FIFO for reading or writing
This fixes https://savannah.gnu.org/bugs/?56354.
Reported-by: Brand Huntsman <alpha@qzx.com>

Signed-off-by: Brand Huntsman <alpha@qzx.com>
2019-05-26 19:40:33 +02:00
Benno Schulenberg
b7e2da7434 files: don't save the state of the terminal a second time
The user will understand that changing the state of the terminal
while inputting data into nano is not the same as changing this
state before nano has started or after nano has exited.

This fixes https://savannah.gnu.org/bugs/?56394.

Bug existed since version 2.4.2.
2019-05-26 19:16:40 +02:00
Benno Schulenberg
8e2d03b92c build: fix compilation when configured with --enable-tiny 2019-05-26 14:48:14 +02:00
Benno Schulenberg
308a094d8d feedback: show a more fitting message when opening a FIFO is interrupted 2019-05-26 14:17:35 +02:00
Benno Schulenberg
5757aa8a0c tweaks: reuse the install and restore functions for a signal handler 2019-05-26 13:57:29 +02:00
Benno Schulenberg
8c5b67379f tweaks: factor out the installing and restoring of the ^C signal handler
So that these two functions can be used elsewhere too.
2019-05-26 13:55:59 +02:00
Benno Schulenberg
b2926eb675 tweaks: include the enabling of SIGINT into the tiny version
Either this enabling is not needed at all when the original terminal
state has been restored, or it will be needed in the tiny version too.

Also condense some comments.
2019-05-26 13:49:38 +02:00
Benno Schulenberg
ea11709564 files: allow to abort the reading of slow files with Ctrl+C
This addresses https://savannah.gnu.org/bugs/?44907.

Original-patch-by: Martin van Zijl <martin.vanzijl@gmail.com>
2019-05-26 13:34:38 +02:00
Benno Schulenberg
8550c6bd93 files: allow to interrupt the opening of a FIFO for writing with Ctrl+C 2019-05-26 11:45:51 +02:00
Benno Schulenberg
65560a583c tweaks: rename a parameter and a variable, to be more distinct 2019-05-24 19:27:04 +02:00
Benno Schulenberg
35a791dee5 tweaks: remove two unneeded checks for NULL
If the rest of nano is correct, then these checks are superfluous and
only slow the loops down.  But if there is some incorrect code, then
let nano crash on dereferencing NULL so we can find and fix the bug.
2019-05-24 19:17:01 +02:00
Benno Schulenberg
98ffb19746 tweaks: stop checking for a NULL result from line_from_number()
No one ever reported seeing the message that was removed in commit
c039aaad one month ago, so most likely the code is correct and nano
never calls line_from_number() with a non-existent line number.
2019-05-24 19:08:29 +02:00
Benno Schulenberg
93edd12099 tweaks: rename a function, to be clearer and to stop using an old abbrev 2019-05-24 18:56:34 +02:00
Benno Schulenberg
9a475bf2d3 speller: don't crash when the spell-checked tempfile cannot be opened
This addresses https://savannah.gnu.org/bugs/?56361.
2019-05-24 17:31:35 +02:00
Benno Schulenberg
b512e253b6 tweaks: drop an unneeded parameter from open_file()
The 'quiet' parameter is only used when opening a help-text tempfile
or a spell-checked tempfile, and these files necessarily exist, so
'quiet' will never be checked for them.  But in the weird case that
the help-text tempfile could not be opened, it is not a problem that
"New File" gets printed to the status bar because nano will crash
shortly afterwards.  And when the spell-checked tempfile could not
be opened, a "Not Found" message is appropriate, but nano will crash
in this case too.
2019-05-24 13:00:00 +02:00
Benno Schulenberg
137c4467ef speller: ensure that a Shift-selected region is retained
For both an integrated and an external spell check, fake the Shift key
being held so that (when the cursor is moved by a changed length of a
word) a Shift-selected region is not unexpectedly cancelled.

This fixes https://savannah.gnu.org/bugs/?56365.
2019-05-24 12:30:07 +02:00
Benno Schulenberg
4cacb626a0 files: allow to interrupt the opening of a FIFO with Ctrl+C
With-help-from: Brand Huntsman <alpha@qzx.com>
2019-05-24 10:51:56 +02:00
Benno Schulenberg
e3e81879b1 tweaks: condense the setup of the two signal handlers for Ctrl+C
Don't bother checking for an error from sigaction(), because the only
things it could error out for is when it is passed an invalid signal
(which SIGINT isn't) or oldaction/newaction would point to memory that
is outside of nano's control (which is obviously not the case).

Also, the setup of signal handlers during startup does not check for
errors, so why do it here?
2019-05-24 10:48:03 +02:00
Benno Schulenberg
acd23551c3 help: don't check for confinement when opening a temporary help-text file
This fixes https://savannah.gnu.org/bugs/?56369.
2019-05-23 12:43:31 +02:00
Benno Schulenberg
2f1691079e usage: make the --help output independent from the terminal's tab size
Use printf's ability to align things (instead of trying to do it
ourselves and failing when the tab size of the terminal is not 8.)

Suggested-by: Vincent Huisman <site.gentoobugzilla@dataghost.com>

This fixes https://savannah.gnu.org/bugs/?56372.
Reported-by: Vincent Huisman <site.gentoobugzilla@dataghost.com>
2019-05-22 19:55:25 +02:00
Benno Schulenberg
12bf3bfce4 feedback: don't clear off possible error messages after a spell check
If functions deeper down would put up some message on the status bar,
it should not be cleared.  The chance that messages from a spell-check
program stay onscreen is minute: the edit window is fully refreshed,
the status bar is fully drawn, and the help lines (if there are any)
are redrawn.  Only the title bar is not refreshed, but the chance that
an error message has spilled onto the top row...  And anyway, the
spell checker should not print any error messages at all.
2019-05-21 19:42:44 +02:00
Benno Schulenberg
d7555d071f tweaks: adjust a comment and drop two others, and reshuffle two lines 2019-05-21 19:42:08 +02:00
Benno Schulenberg
9596f7de9d tweaks: delete a now-unused function 2019-05-21 18:56:35 +02:00
Benno Schulenberg
20635b40f4 tweaks: merge two very similar functions into a single one 2019-05-21 18:56:13 +02:00
Benno Schulenberg
1128a40d42 tweaks: remove an unneeded setting and unsetting of a flag
This twiddling was made superfluous by commit faa0eb99 from a year ago.
2019-05-21 18:55:34 +02:00
Benno Schulenberg
1e2e6733df tweaks: add a pair of braces, to silence a compiler warning
Also, put an 'else' on the same line as the preceding closing brace.
2019-05-21 17:25:45 +02:00
Benno Schulenberg
2669d3623d tweaks: set a boolean directly, instead of using a function call 2019-05-21 12:15:37 +02:00
Benno Schulenberg
22fc16b2d0 tweaks: add a missing forward declaration of make_new_buffer()
Reported-by: Brand Huntsman <alpha@qzx.com>
2019-05-20 11:53:22 +02:00
Benno Schulenberg
372e858ec8 docs: note David as author of undoable indenting and undoable justifying 2019-05-20 10:55:03 +02:00
Benno Schulenberg
da8c74a44f docs: note Brand as the author of the delayed syntax parsing 2019-05-20 10:45:33 +02:00
Brand Huntsman
cba9d8d05e rcfile: fully parse a syntax file only when needed
When parsing an included syntax file, stop reading when a command other
than 'syntax', 'header' or 'magic' is encountered.  The syntax file is
fully parsed the first time that a file needs it.  Each 'extendsyntax'
command is stored for unloaded syntaxes and applied after the syntax
is loaded.

Closing a buffer does not unload the syntax, even if no longer used by
another buffer.

This addresses https://savannah.gnu.org/bugs/?54928.

Signed-off-by: Brand Huntsman <alpha@qzx.com>
2019-05-20 10:25:47 +02:00
Brand Huntsman
0e29c2a24a rcfile: store errors and display them when nano terminates
This is needed to implement the demand loading of syntax files, as any
errors that these files may contain would otherwise overwrite things on
the screen and the messages wouldn't be on the terminal when nano exits.

It also allows nano to start up on a Linux console when there are errors.

Signed-off-by: Brand Huntsman <alpha@qzx.com>
2019-05-20 10:25:47 +02:00
Benno Schulenberg
9e182722cc feedback: print helpful message only when data comes from keyboard
When the data is fed to nano through a pipe, it is pointless to print
this message as it can be seen only after nano has exited.

This addresses https://savannah.gnu.org/bugs/?56348.
2019-05-19 19:49:47 +02:00
Benno Schulenberg
4f1eb5fdd4 tweaks: remove the two remaining handfuls of asserts
They are just clutter -- no one runs a debug build for any length
of time.
2019-05-19 18:58:02 +02:00
Benno Schulenberg
53352d0b26 files: try matching a syntax after scooping data from standard input
The blank filename should not give any match, but maybe the header line
or the magic finds a fitting syntax.

This fixes https://savannah.gnu.org/bugs/?56344.
2019-05-19 17:48:08 +02:00
Benno Schulenberg
1d3a4df3b3 browser: don't show a mistaken message when exiting from help viewer
This fixes https://savannah.gnu.org/bugs/?56346.

Bug existed since version 3.0, commit 8d6b205e.
2019-05-18 19:59:54 +02:00
Benno Schulenberg
afbaf8ae2d files: give feedback while waiting for a FIFO to open up 2019-05-18 19:14:32 +02:00
Benno Schulenberg
1b2018e921 files: check for writability by the access bits, not by trying to append
Trying to append does not work on a fifo, and we'd like to be able to
open a fifo again.  Also, the append test causes a close event for the
given file at the moment of opening it, which makes using 'inotify' for
waiting for this file to be closed useless.

Commit f8f90272 added the append test, but the original request
(https://lists.gnu.org/archive/html/info-nano/2009-05/msg00000.html
by Damien Joldersma) asked only for a warning when the user did not
have enough privileges to write to the file.

So, drop the append test and just check the access bits.

This fixes https://bugs.debian.org/583196
and fixes https://savannah.gnu.org/bugs/?29312.
2019-05-18 19:13:42 +02:00
Benno Schulenberg
26642a39c3 files: allow a given file to be a special file but not a directory
The original requests (https://bugs.debian.org/551717 by Paul Wise,
and https://savannah.gnu.org/bugs/?45383 by Mike Frysinger) asked
only that specifying a directory instead of a file name should not
open a new buffer.  But commit 98ffb642 excluded everything that was
not a normal file.  This avoids a hang when the user accidentally
tries to open a pipe or a socket, but also prevents any user from
doing so on purpose.  And opening a fifo can be useful when wanting
to handle sensitive data that shouldn't be stored on disk.

This prepares the fix for https://bugs.debian.org/583196.
2019-05-18 17:24:13 +02:00
Benno Schulenberg
8723375443 tweaks: remove a superfluous and ineffective assignment
This assignment became superfluous two years ago, by David's revamping
of read_file() in commit 86f7bc18.
2019-05-18 17:21:54 +02:00
Benno Schulenberg
82aea04c79 bindings: at a Yes-No prompt, accept also ^Y for "Yes"
For symmetry with ^N for "No".

Suggested-by: Brand Huntsman <alpha@qzx.com>
2019-05-17 11:39:40 +02:00
Benno Schulenberg
341601e1a2 bindings: at a Yes-No prompt, accept also ^N and ^Q for "No"
When wanting to exit after having modified a buffer by mistake, I don't
want to politely answer a question by typing precisely an unmodified N,
I want to give a command: ^N, meaning *No!*.  Or seen another way: I
don't want to be obliged to let go of the Ctrl key before typing N.

When at startup --tempfile was used, the user can discard a modified
buffer with ^O ^Q.  It would be nice when (without --tempfile) ^X ^Q
would work too.
2019-05-17 11:31:59 +02:00
Benno Schulenberg
368f1a1c9d tweaks: elide a function that is called in just one place
Since commit b5f15cb5 from a year ago, there remains just one call
of initialize_buffer_text().
2019-05-16 16:16:52 +02:00
Benno Schulenberg
527c6c1ca0 tweaks: reshuffle a few lines, to be more straightforward 2019-05-16 16:04:12 +02:00
Benno Schulenberg
a9e8f88e77 tweaks: enforce the miminum amount of scrolling in a simpler way
This improves the fix for https://savannah.gnu.org/bugs/?56317.
2019-05-16 16:00:42 +02:00
Benno Schulenberg
0cbf1f4027 help: don't show Alt+Left and Alt+Right when running on a Linux console
On a VT, <Alt+Left> and <Alt+Right> switch between VTs and nano
does not receive those keystrokes.
2019-05-13 13:01:10 +02:00
Benno Schulenberg
96baa70cc8 tweaks: reshuffle a couple of lines and adjust a few comments
Also, compute the required space for the keystrokes more tightly:
most of those characters are plain ASCII, so that means 17 bytes
for 17 cells, and at most one of those characters is a three-byte
arrow, which means 2 bytes extra.  Adding the two newlines at the
end, the needed room besides the description is 21 bytes.
2019-05-13 12:25:39 +02:00
Benno Schulenberg
b18e2129ce bindings: bind the Alt+arrow keystrokes also in non-UTF-8 locales
Fall back to using the words "Left", "Right", "Up", and "Down",
instead of graphical arrows.

This fixes https://savannah.gnu.org/bugs/?56313.

Bug was left to exist since the Alt+arrow keys were introduced,
in version 2.8.7, commit 1cc030f7.
2019-05-13 11:35:15 +02:00
Benno Schulenberg
e26cbdd6cd help: make the column for the first keystroke a little wider
To make room for the "M-Right" that is coming in the next commit --
seven characters are needed instead of six.
2019-05-13 11:07:21 +02:00
Benno Schulenberg
0ebfd54e17 softwrap: use smooth scrolling when softwrapping is toggled on
If the cursor is near the bottom row when softwrap gets switched on, the
screen should scroll just the amount needed to keep the cursor onscreen.

This fixes https://savannah.gnu.org/bugs/?56317.

Bug existed since softwrapping was introduced in version 2.1.11.
2019-05-13 10:25:12 +02:00
Benno Schulenberg
8f1cd50f1e syntax: python: avoid miscoloring stuff between two empty strings
The quotes of an empty string ('' or "") should be colored just like
those of a non-empty string, because otherwise the text *between* two
empty strings on the same line gets colored.

Add an extra rule to discolor triple quotes again to not make them
look like valid by themselves.

Also, remove six superfluous backslashes.

This addresses https://savannah.gnu.org/patch/?9801.
Reported-by: Ryan Westlund <rlwestlund@gmail.com>
2019-05-11 19:05:45 +02:00
Benno Schulenberg
4fb9f298c9 tweaks: adjust some indentation after the previous change
Also reshuffle some arguments.
2019-05-08 19:35:42 +02:00
Benno Schulenberg
c338d86843 tweaks: rename some single-letter variables to the same significant word
And simply elide one of those variables.
2019-05-08 19:35:03 +02:00
Benno Schulenberg
247dd8f052 tweaks: rename a variable, reshuffle declarations, and drop an assert 2019-05-08 15:34:06 +02:00
Benno Schulenberg
71d0847b19 tweaks: merge two functions, as the one is used only by the other 2019-05-08 15:25:11 +02:00
Benno Schulenberg
c55d144748 tweaks: drop most of the remaining debugging code, and some timing code 2019-05-08 15:23:36 +02:00
Benno Schulenberg
da91a44f9e tweaks: reshuffle two #ifdefs, to avoid an unpaired brace 2019-05-08 13:56:02 +02:00
Benno Schulenberg
02d3a2c0fb tweaks: remove some unneeded braces, and reshuffle for more symmetry 2019-05-06 11:20:31 +02:00
Benno Schulenberg
5764619655 search: stay in the Search menu when trying to Replace in view mode
This fixes https://savannah.gnu.org/bugs/?56274.

Bug existed since version 3.1, commit 6cd53e7f.
2019-05-06 11:08:22 +02:00
Benno Schulenberg
3c959fd038 tweaks: drop a useless tidying-up call, as spelling does not use regexes
The integrated spell checker does not use regular expressions, and
'refresh_needed' is set to TRUE anyway, so the tidy_up_after_search()
call there is effectively a no-op.
2019-05-06 10:57:45 +02:00
Benno Schulenberg
f0bc94fd02 tweaks: move the tyding-up-after-a-search to a single exit point 2019-05-06 10:29:45 +02:00
Benno Schulenberg
8720cfcce9 tweaks: rename two more functions, to be simpler too 2019-05-04 11:21:45 +02:00
Benno Schulenberg
954c4d03ac tweaks: rename two functions, to be simpler 2019-05-04 11:21:45 +02:00
Benno Schulenberg
edf6995be4 zapping: use the 'keep_cutbuffer' logic to keep undo items apart
The 'keep_cutbuffer' variable becomes FALSE whenever there is cursor
movement or there was a marked region.  Use this variable to simplify
the condition for creating a new ZAP undo item.  But then typing the
'zap' shortcut should not cause the variable to be set to FALSE.

This fixes the first part of https://savannah.gnu.org/bugs/?56261.

Bug existed since zapping was introduced, in version 3.2.
2019-05-04 11:18:51 +02:00
Benno Schulenberg
b50d5758ef zapping: disjoin a zap command from earlier ones when the mark is set
This fixes the third part of https://savannah.gnu.org/bugs/?56261.

Bug existed since zapping was introduced, in version 3.2.
2019-05-03 12:58:17 +02:00
Benno Schulenberg
6c4d0d87f0 tweaks: remove a condition that has become superfluous
After the previous change, a copy command will break a chain of cut
commands, so there is no need any more to verify that the line number
hasn't changed.
2019-05-03 12:41:49 +02:00
Benno Schulenberg
a962bceca6 copying: let a copy command break a chain of cut or zap commands
This fixes the second part of https://savannah.gnu.org/bugs/?56261.

Bug existed since zapping was introduced, in version 3.2.
2019-05-03 12:33:42 +02:00
Benno Schulenberg
e0c5c589ad tweaks: remove a superfluous condition, in three places
When 'last_action' has a specific value, then necessarily there must
exist a corresponding current undo item.

(The condition is already absent in do_deletion(), for the BACK and DEL
undo items, and it works fine there.)
2019-05-03 12:18:04 +02:00
Benno Schulenberg
dfe87540c6 syntax: po: colorize also escaped hex and octal codes 2019-05-03 12:12:44 +02:00
Benno Schulenberg
6c4f228f6f tweaks: invert two conditions, in order to elide an extra variable 2019-05-02 14:34:05 +02:00
Benno Schulenberg
fe06ae5f48 tweaks: normalize the indentation after the previous two changes 2019-05-02 14:27:35 +02:00
Benno Schulenberg
07289f437f tweaks: invert a condition, in order to return earlier 2019-05-02 14:12:23 +02:00
Benno Schulenberg
99d155d80f tweaks: reshuffle an assignment, to be able to return earlier 2019-05-02 14:10:23 +02:00
Benno Schulenberg
3346c5395e tweaks: place a function better, and reduce some comments to a single one 2019-05-02 10:17:10 +02:00
Benno Schulenberg
083218aca5 tweaks: rename two parameters, to differentiate them from function names 2019-05-02 10:17:04 +02:00
Benno Schulenberg
fd3b3bc1d6 cutting: clear the cutbuffer when the previous operation was copying
The cut and copy operations (^K and M-6) are different operations and
one should not add to the cutbuffer created by the other.

This fixes https://savannah.gnu.org/bugs/?56251.

Bug existed since version 3.0, commit 71f85937.
2019-05-02 09:27:37 +02:00
Benno Schulenberg
9bc6bc83c0 tweaks: rename two variables, for more contrast 2019-05-01 19:14:06 +02:00
Benno Schulenberg
d4468b2def tweaks: condense a comment and reshuffle a couple of lines 2019-05-01 19:10:56 +02:00
Benno Schulenberg
404a6862cd tweaks: really don't bother renumbering the lines in the cutbuffer
The lines from the cutbuffer will be renumbered when it matters: when
they get pasted.

The only place that used the numbering of (a copy of) the cutbuffer
(the updating of an undo item) already iterates through its lines.
Just add a counter there instead of making use of the line numbers.
2019-05-01 13:09:22 +02:00
Benno Schulenberg
85fc41470b tweaks: stop passing 'cutbuffer' and 'cutbottom' back and forth
All extractions are done into the cutbuffer, so it is pointless to pass
'cutbuffer' and 'cutbottom' in and back out as parameters all the time.
Just use those global variables directly.

Also, rename the function as there is no longer a buffer among its
parameters.
2019-05-01 11:33:37 +02:00
Benno Schulenberg
2b9dd6c574 tweaks: don't bother saving and restoring 'cutbottom' all the time
The 'cutbottom' variable is only ever used when cutting or copying
consecutive lines: for appending the current line to the already
existing lines in the cutbuffer.  As soon as some other operation
is performed, 'cutbottom' becomes irrelevant, it could be set to
anything, it doesn't matter: the pasting of the cutbuffer does not
use the value of 'cutbottom', nor does any other operation.
2019-05-01 11:19:14 +02:00
Benno Schulenberg
9e44a53be7 copying: scroll just one line when M-6 is pressed on the bottom row
This fixes https://savannah.gnu.org/bugs/?56249.

Bug existed since version 2.6.0, commit 318ed6b1.
2019-04-30 19:31:44 +02:00
Benno Schulenberg
0c561f0325 copying: make M-6 do nothing when at end of buffer 2019-04-30 19:03:18 +02:00
Benno Schulenberg
e5831f81bb tweaks: rename two variables, to be less cryptic 2019-04-30 18:41:05 +02:00
Benno Schulenberg
fa21986ecf oops: apparently the line numbers in the cutbuffer do matter
The line numbers don't matter for the cutbuffer itself, but they matter
for the copy of the cutbuffer that is stored in an undo item.

This reverts commit 14140d52 from two hours ago.

This fixes https://savannah.gnu.org/bugs/?56245.
2019-04-30 12:49:57 +02:00
Benno Schulenberg
772137cabe tweaks: rename a variable, to fit a bit better 2019-04-30 12:24:56 +02:00
Benno Schulenberg
4c53e2f56b tweaks: elide two unneeded variables
After extracting a line or region, the current line is always the one
where renumbering should start.  And when ingrafting a buffer, it is
always the first ingrafted line where renumbering should start.  The
'top_save' variable was indirectly getting set to those lines.

Also, renumber immediately after unpartitioning the file buffer, before
doing anything else.
2019-04-30 12:20:41 +02:00
Benno Schulenberg
14140d5249 tweaks: don't bother renumbering the lines in the cutbuffer
The numbering of the lines in the cutbuffer is irrelevant.  These lines
will be renumbered when it matters: when they get pasted.
2019-04-30 10:55:15 +02:00
Benno Schulenberg
17aa9371b5 tweaks: rename a function, to better indicate what it does 2019-04-30 10:27:10 +02:00
Benno Schulenberg
208995e4a7 tweaks: move a bit of timing code to where it will be needed 2019-04-30 10:15:46 +02:00
Benno Schulenberg
b503670750 tweaks: rename a variable, to match another with the same meaning
Also, remove a redundant condition.
2019-04-30 10:15:11 +02:00
Benno Schulenberg
7c08e8ea69 cutting: ignore the mark when a word is deleted
Just like for deleting a word to the left, the mark should be ignored
also when deleting a word to the right.

This fixes https://savannah.gnu.org/bugs/?56241.
2019-04-30 09:53:10 +02:00
Benno Schulenberg
542426f1f1 tweaks: add a warning for something that shouldn't occur 2019-04-30 09:44:47 +02:00
Benno Schulenberg
6319a86178 tweaks: improve some comments, reshuffle a line, and rename a variable 2019-04-29 11:08:21 +02:00
Benno Schulenberg
9888e67b20 tweaks: rename two variables, for more contrast with the partition stuff 2019-04-29 09:45:41 +02:00
Benno Schulenberg
8fe19e344f tweaks: use a more direct call when a single linestruct is deleted 2019-04-28 17:20:08 +02:00
Benno Schulenberg
896cfcef95 tweaks: when OR'ing, put the most likely condition first
Also, slightly reword a comment, adjust some whitespace, and use
a more direct comparison for equality.
2019-04-28 15:53:33 +02:00
Benno Schulenberg
d54180ad8b tweaks: reduce a bit of mark-adjusting code to its essence
It doesn't matter whether the grafted text contains a newline or not.

It only matters whether the mark was before or after the cursor.  When
it was after the cursor, the mark needs to be set to the bottom line of
the grafted text and its x coordinate needs adjustment; and when it was
before the cursor, the mark just needs to be set to the top line of the
grafted text.
2019-04-28 12:18:24 +02:00
Benno Schulenberg
065afe6e0f tweaks: reshuffle a bit of code, to be less intertwined 2019-04-28 11:54:23 +02:00
Benno Schulenberg
37eccd3117 tweaks: rename a function, to be more fitting
Also, adjust some whitespace, for esthetics.
2019-04-28 11:01:51 +02:00
Benno Schulenberg
b9dd572a67 tweaks: set a boolean directly, instead of using a function call 2019-04-28 10:40:37 +02:00
Benno Schulenberg
3fe17e0355 docs: adjust the wording of the README to be factually correct
That is: don't say that nano doesn't change the file contents by default.

Also, correct the style of the preceding paragraph.
2019-04-28 10:35:27 +02:00
Benno Schulenberg
6e3a3964ce tweaks: adjust the indentation after the previous change
Also, condense a couple of comments.
2019-04-27 17:17:06 +02:00
Benno Schulenberg
18eb7e6d21 tweaks: elide an unneeded 'if' and 'break' 2019-04-27 17:10:10 +02:00
Benno Schulenberg
e84a790b5d tweaks: rename a variable, to better indicate it contains two characters
Also rename a function, to differentiate it more from do_find_bracket().
2019-04-27 17:01:34 +02:00
Benno Schulenberg
20d9070aa1 tweaks: move an assignment that is useful only when searching forward 2019-04-27 16:31:57 +02:00
Benno Schulenberg
482b2814b4 tweaks: step away one character from the current bracket, not one byte 2019-04-27 14:41:53 +02:00
71 changed files with 23585 additions and 22853 deletions

View File

@@ -14,7 +14,9 @@ David Lawrence Ramsey <pooka109@gmail.com>
* Former stable series maintainer. Multiple buffer support,
operating dir (-o) option, bug fixes for display routines,
wrapping code, spelling fixes, constantshow mode, parts of
UTF-8 support, softwrap overhaul, and various other fixes.
UTF-8 support, softwrap overhaul, undoable (un)indentations,
undoable justifications, justifiable regions, and numerous
other fixes.
Jordi Mallach <jordi@gnu.org>
* Debian package maintainer, fellow bug squasher.
@@ -67,3 +69,6 @@ Rishabh Dave <rishabhddave@gmail.com>
Marco Diego Aurélio Mesquita <marcodiegomesquita@gmail.com>
* Filtering text through an external command.
Brand Huntsman <alpha@qzx.com>
* The delayed parsing of syntax files.

249
ChangeLog
View File

@@ -1,3 +1,252 @@
Changes between v4.2 and v4.3:
------------------------------
Benno Schulenberg (235):
bindings: at a Yes-No prompt, accept also ^N and ^Q for "No"
bindings: at a Yes-No prompt, accept also ^Y for "Yes"
bindings: bind the Alt+arrow keystrokes also in non-UTF-8 locales
browser: don't show a mistaken message when exiting from help viewer
build: avoid a warning on FreeBSD, OpenBSD, and Alpine
build: avoid a warning when using --disable-utf8
build: exclude the ability to open a FIFO from the tiny version
build: fix compilation on another system
build: fix compilation when configured with --disable-color
build: fix compilation when configured with --enable-tiny
build: move an #include to where it is needed
build: remove two #includes that don't seem to be needed
bump version numbers and add a news item for the 4.3 release
chars: create a dedicated function for getting the length of a character
chars: redo the speedup for plain ASCII from three commits ago
chars: speed up case-insensitive searching by roughly one percent
chars: speed up the determination of length and width for plain ASCII
copying: let a copy command break a chain of cut or zap commands
copying: make M-6 do nothing when at end of buffer
copying: scroll just one line when M-6 is pressed on the bottom row
cutting: clear the cutbuffer when the previous operation was copying
cutting: ignore the mark when a word is deleted
display: properly show all characters in a non-UTF-8 build
docs: add a light warning to the explanation of --nonewlines
docs: adjust the wording of the README to be factually correct
docs: clarify that in nano regexes are extended regular expressions
docs: mention the default value for 'errorcolor'
docs: note Brand as the author of the delayed syntax parsing
docs: note David as author of undoable indenting and undoable justifying
docs: remove "--" from the default value of 'quotestr'
docs: say thanks to the Korean translator, and trim a double space
docs: show double quotes where they are needed
docs: slightly reword the notice about the changed defaults since 4.0
feedback: don't clear off possible error messages after a spell check
feedback: don't try to represent keys outside of the seven-bit range
feedback: make an error check work also when curses hasn't started yet
feedback: print helpful message only when data comes from keyboard
feedback: show a more fitting message when opening a FIFO is interrupted
feedback: show an appropriate message when reading a file was cut short
feedback: treat statusline() being called outside of curses mode as a bug
feedback: when the last line is empty, don't include it in the count
files: allow a given file to be a special file but not a directory
files: allow to abort the reading of slow files with Ctrl+C
files: allow to interrupt the opening of a FIFO for writing with Ctrl+C
files: allow to interrupt the opening of a FIFO with Ctrl+C
files: check for writability by the access bits, not by trying to append
files: don't close a newly-created buffer when it is the only one
files: don't save the state of the terminal a second time
files: don't say "Error...: Success" when aborting after resizing
files: give feedback while waiting for a FIFO to open up
files: suppress feedback when writing an emergency or temporary file
files: try matching a syntax after scooping data from standard input
files: when needed, reconnect the keyboard and reenter curses mode
gnulib: update to its current upstream state
help: don't check for confinement when opening a temporary help-text file
help: don't cycle through the buffers for every resizing step
help: don't show Alt+Left and Alt+Right when running on a Linux console
help: make the column for the first keystroke a little wider
help: write the text directly into a new buffer, without using a tempfile
justify: remove "--" from the quoting regex, to avoid false paragraphs
oops: apparently the line numbers in the cutbuffer do matter
rcfile: at terminating points, verify that a defined syntax is not empty
rcfile: check for missing color commands only when a syntax is still open
rcfile: close off a syntax when a non-syntax command is encountered
rcfile: disallow extending a syntax that is defined in a main nanorc
rcfile: fully read each included file, so all its syntaxes are seen
search: stay in the Search menu when trying to Replace in view mode
softwrap: use smooth scrolling when softwrapping is toggled on
speller: be more concise and to the point when something goes wrong
speller: don't crash when the spell-checked tempfile cannot be opened
speller: ensure that a Shift-selected region is retained
speller: when something goes wrong with 'sort', do not blame 'spell'
startup: remove the now-unneeded workaround for a SIGWINCH during input
startup: resave the terminal's state only when there were no signals
syntax: po: colorize also escaped hex and octal codes
syntax: python: avoid miscoloring stuff between two empty strings
tweaks: add a missing forward declaration of make_new_buffer()
tweaks: add a pair of braces, to silence a compiler warning
tweaks: add a warning for something that shouldn't occur
tweaks: adjust a comment and drop two others, and reshuffle two lines
tweaks: adjust some indentation after the previous change
tweaks: adjust some whitespace and rewrap a few lines
tweaks: adjust the indentation after the previous change
tweaks: adjust the indentation after the previous change
tweaks: avoid an unneeded, extra stat() for temporary files
tweaks: avoid parsing a character twice
tweaks: be more sparing in redrawing things when exiting from help viewer
tweaks: change a function to void, to make things more direct
tweaks: check in a single place for files that should not be opened
tweaks: close a buffer differently and elide a parameter
tweaks: condense a comment and reshuffle a couple of lines
tweaks: condense a couple of comments, and reshuffle a line
tweaks: condense the setup of the two signal handlers for Ctrl+C
tweaks: condense two comments, and normalize the whitespace of a label
tweaks: consistently report failures to fork (and the like) as errors
tweaks: delete a leftover
tweaks: delete a now-unused function
tweaks: delete a now-unused function
tweaks: don't bother calling mblen() in a non-UTF-8 build
tweaks: don't bother checking the return value of wait()
tweaks: don't bother keeping track of whether a squeezed line has shrunk
tweaks: don't bother renumbering the lines in the cutbuffer
tweaks: don't bother saving and restoring 'cutbottom' all the time
tweaks: don't bother to free the content of 'extendsyntax' commands
tweaks: don't check the user's nanorc file for accessibility twice
tweaks: drop an unneeded parameter from open_file()
tweaks: drop a useless tidying-up call, as spelling does not use regexes
tweaks: drop most of the remaining debugging code, and some timing code
tweaks: drop some checks that were made redundant by the previous commit
tweaks: drop two checks that were made redundant by the previous commit
tweaks: elide a function that is an amalgam of three others
tweaks: elide a function that is called in just one place
tweaks: elide a function that is used just once
tweaks: elide another parameter, and rename the function to match
tweaks: elide an unneeded, duplicate stat() for the FIFO check
tweaks: elide an unneeded 'if' and 'break'
tweaks: elide an unneeded variable
tweaks: elide a parameter and a return value
tweaks: elide a pre-processor #else clause, by using braces instead
tweaks: elide a variable, drop a comment, and remove unneeded braces
tweaks: elide two unneeded variables
tweaks: enforce the miminum amount of scrolling in a simpler way
tweaks: exclude a bug check from the tiny version
tweaks: exclude another bug check from the tiny version
tweaks: factor out a fragment of code that is repeated three times
tweaks: factor out the installing and restoring of the ^C signal handler
tweaks: improve a couple of comments
tweaks: improve a handful of comments
tweaks: improve some comments, reshuffle a line, and rename a variable
tweaks: include the enabling of SIGINT into the tiny version
tweaks: invert a condition, in order to return earlier
tweaks: invert two conditions, in order to elide an extra variable
tweaks: just mark four rcfile errors for translation, like the others
tweaks: make better use of two variables, and reshuffle two comments
tweaks: merge two functions, as the first is called just once
tweaks: merge two functions, as the one is used only by the other
tweaks: merge two very similar functions into a single one
tweaks: move a bit of timing code to where it will be needed
tweaks: move a function to the file where it is used
tweaks: move an assignment that is useful only when searching forward
tweaks: move a syntax check to a better place, to reduce duplication
tweaks: move the tyding-up-after-a-search to a single exit point
tweaks: normalize the indentation after the previous two changes
tweaks: place a function better, and reduce some comments to a single one
tweaks: put some timing code back into the search function
tweaks: really don't bother renumbering the lines in the cutbuffer
tweaks: reduce a bit of mark-adjusting code to its essence
tweaks: reduce the scope of a variable, and let the compiler zero it
tweaks: remove a bit of redundant code
tweaks: remove a check that is no longer relevant
tweaks: remove a condition that has become superfluous
tweaks: remove an unneeded "closing" of a syntax after extending it
tweaks: remove an unneeded setting and unsetting of a flag
tweaks: remove a superfluous and ineffective assignment
tweaks: remove a superfluous condition, in three places
tweaks: remove four unneeded pre-processor directives
tweaks: remove some unneeded braces, and reshuffle for more symmetry
tweaks: remove the two remaining handfuls of asserts
tweaks: remove two more unneeded assignments
tweaks: remove two unneeded assignments, and improve a comment
tweaks: remove two unneeded checks for NULL
tweaks: rename a bunch of variables, to become identical to others
tweaks: rename a function and a variable, for contrast and variety
tweaks: rename a function and its parameters, to be more fitting
tweaks: rename a function, to be clearer and to stop using an old abbrev
tweaks: rename a function, to be more fitting
tweaks: rename a function, to better indicate what it does
tweaks: rename a function, to better suit what it does
tweaks: rename a parameter and a variable, to be more distinct
tweaks: rename a struct element, to be distinct
tweaks: rename a type, for more contrast
tweaks: rename a type, to make more sense
tweaks: rename a variable, reduce its scope, and use it consistently
tweaks: rename a variable, reshuffle declarations, and drop an assert
tweaks: rename a variable, to be shorter
tweaks: rename a variable, to better indicate it contains two characters
tweaks: rename a variable, to better suit its counterpart
tweaks: rename a variable, to fit a bit better
tweaks: rename a variable, to fit a little better
tweaks: rename a variable, to get out of the way of the next commit
tweaks: rename a variable, to match another with the same meaning
tweaks: rename a variable, to match the style of its brothers
tweaks: rename four elements of the holder struct, for more contrast
tweaks: rename some single-letter variables to the same significant word
tweaks: rename three variables, to get rid of a suffix or an underscore
tweaks: rename three variables, to use full words instead of abbrevs
tweaks: rename two functions, to be simpler
tweaks: rename two functions, to better describe what they do
tweaks: rename two functions, to get rid of the "mb" abbreviation
tweaks: rename two more functions, to be simpler too
tweaks: rename two parameters, away from single letters
tweaks: rename two parameters, for more contrast, and elide another
tweaks: rename two parameters, to differentiate them from function names
tweaks: rename two variables, and frob some comments
tweaks: rename two variables, and reshuffle their declarations
tweaks: rename two variables, away from a single letter
tweaks: rename two variables, for more contrast
tweaks: rename two variables, for more contrast with the partition stuff
tweaks: rename two variables, to be less cryptic
tweaks: rename two variables, to be unique
tweaks: rename two variables, to not be abbreviations
tweaks: reorder some code, to further optimize display_string() for ASCII
tweaks: reshuffle a bit of code, to be less intertwined
tweaks: reshuffle a couple of lines and adjust a few comments
tweaks: reshuffle a few lines, to be more straightforward
tweaks: reshuffle a few things, partly to make two chunks more alike
tweaks: reshuffle an assignment, to be able to return earlier
tweaks: reshuffle some closing and switching to a better place
tweaks: reshuffle some code to the one place that needs it
tweaks: reshuffle some lines and frob some comments
tweaks: reshuffle some lines, to group things more sensibly
tweaks: reshuffle some lines, to put the most likely candidate first
tweaks: reshuffle some lines, to reduce duplication
tweaks: reshuffle two #ifdefs, to avoid an unpaired brace
tweaks: reuse the install and restore functions for a signal handler
tweaks: set a boolean directly, instead of using a function call
tweaks: set a boolean directly, instead of using a function call
tweaks: sort three translator names better
tweaks: specifically refer to the manual of GNU grep for more regex info
tweaks: speed up the counting of characters in mbstrlen()
tweaks: squeeze excess spaces out of a line in situ
tweaks: step away one character from the current bracket, not one byte
tweaks: stop allocating and freeing a holder struct for every cut/paste
tweaks: stop checking for a NULL result from line_from_number()
tweaks: stop passing 'cutbuffer' and 'cutbottom' back and forth
tweaks: switch to the preceding buffer in a cheaper way (when in help)
tweaks: use a cheaper way to switch between buffers where possible
tweaks: use a more direct call when a single linestruct is deleted
tweaks: use a slightly faster function where appropriate
tweaks: use a symbol instead of zero to refer to standard input
tweaks: use FALSE for booleans instead of zero
tweaks: when OR'ing, put the most likely condition first
usage: make the --help output independent from the terminal's tab size
zapping: disjoin a zap command from earlier ones when the mark is set
zapping: use the 'keep_cutbuffer' logic to keep undo items apart
Brand Huntsman (6):
files: block SIGWINCH while opening a FIFO for reading or writing
rcfile: compile the color regexes just once
rcfile: fully parse a syntax file only when needed
rcfile: store errors and display them when nano terminates
startup: prevent a crash when no applicable syntax is found
tweaks: remove an unneeded pre-processor '#else' clause
Changes between v4.1 and v4.2:
------------------------------

View File

@@ -2,6 +2,7 @@ Improvements in GNU nano
========================
Since 4.0:
- The ability to both read from and write to a FIFO.
- Automatic hard-wrapping is no longer the default.
- Addition of --guidestripe to draw a helpful vertical bar.
- Meta-Up and Meta-Down scroll the screen linewise.

8
NEWS
View File

@@ -1,3 +1,11 @@
2019.06.18 - GNU nano 4.3 "Musa Kart"
• The ability to read from and write to a FIFO has been regained.
• Startup time is reduced by fully parsing a syntax only when needed.
• Asking for help (^G) when using --operatingdir does not crash.
• The reading of a huge or slow file can be stopped with ^C.
• Cut, zap, and copy operations are undone separately when intermixed.
• M-D reports the correct number of lines (zero for an empty buffer).
2019.04.24 - GNU nano 4.2 "Tax the rich, pay the teachers"
• The integrated spell checker does not crash when 'spell' is missing.
• Option --breaklonglines works also when --ignorercfiles is used.

6
README
View File

@@ -15,10 +15,10 @@ Overview
Nano aimed to solve these problems by: 1) being truly free software
by using the GPL, 2) emulating the functionality of Pico as closely
as is reasonable, and 3) include extra functionality by default.
as is reasonable, and 3) including extra functionality by default.
Nowadays, nano wants to be a generally useful editor, with default
settings that do not change the file contents automatically.
Nowadays, nano wants to be a generally useful editor with sensible
defaults (linewise scrolling, no automatic line breaking).
The nano editor is an official GNU package. For more information on
GNU and the Free Software Foundation, please see https://www.gnu.org/.

9
THANKS
View File

@@ -11,6 +11,7 @@ Mario Blättermann <mario.blaettermann@gmail.com> German
Ricardo Cárdenes Medina <ricardo@conisys.com> Spanish
Antonio Ceballos <aceballos@gmail.com> Spanish
Wei-Lun CHAO <chaoweilun@pcmail.com.tw> Chinese (traditional)
Seong-ho Cho <darkcircle.0426@gmail.com> Korean
Yuri Chornoivan <yurchor@ukr.net> Ukrainian
Marco Colombo <magicdice@inwind.it> Italian
Mihai Cristescu <mihai.cristescu@archlinux.info> Romanian
@@ -22,22 +23,22 @@ Rafael Fontenelle <rffontenelle@gmail.com> Brazilian Portuguese
Pavel Fric <pavelfric@seznam.cz> Czech
Jorge González <aloriel@gmail.com> Spanish
Jean-Philippe Guérard <jean-philippe.guerard@laposte.net> French
Geir Helland <pjallabais@users.sourceforge.net> Norwegian Bokmål
Tedi Heriyanto <tedi_h@gmx.net> Indonesian
Václav Haisman <V.Haisman@sh.cvut.cz> Czech
Takeshi Hamasaki <hmatrjp@users.sourceforge.jp> Japanese
Geir Helland <pjallabais@users.sourceforge.net> Norwegian Bokmål
Tedi Heriyanto <tedi_h@gmx.net> Indonesian
Kjetil Torgrim Homme <kjetilho@linpro.no> Norwegian Nynorsk
Szabolcs Horvath <horvaths@janus.gimsz.sulinet.hu> Hungarian
Jorma Karvonen <karvonen.jorma@gmail.com> Finnish
Mehmet Kececi <mkececi@mehmetkececi.com> Turkish
Mehmet Kececi <mkececi@mehmetkececi.com> Turkish
Gabor Kelemen <kelemeng@gnome.hu> Hungarian
Kalle Kivimaa <kalle.kivimaa@iki.fi> Finnish
Eivind Kjørstad <ekj@vestdata.no> Norwegian Nynorsk
Florian König <floki@bigfoot.com> German
Klemen Košir <klemen913@gmail.com> Slovenian
Wojciech Kotwica <wkotwica@post.pl> Polish
Ask Hjorth Larsen <asklarsen@gmail.com> Danish
Clement Laforet <clem_laf@wanadoo.fr> French
Ask Hjorth Larsen <asklarsen@gmail.com> Danish
LI Daobing <lidaobing@gmail.com> Chinese (simplified)
Jordi Mallach <jordi@gnu.org> Catalan
João Victor Duarte Martins <jvdm@sdf.lonestar.org> Brazilian Portuguese

View File

@@ -2,7 +2,7 @@
# Generate configure & friends for GIT users.
gnulib_url="git://git.sv.gnu.org/gnulib.git"
gnulib_hash="91584ed612fa26a505c8fc4c7f6fb19f7413795d"
gnulib_hash="a1beabcb14cde661c36f7a3c7c17b5871704003e"
modules="
futimens

View File

@@ -16,7 +16,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see https://www.gnu.org/licenses/.
AC_INIT([GNU nano], [4.2], [nano-devel@gnu.org], [nano])
AC_INIT([GNU nano], [4.3], [nano-devel@gnu.org], [nano])
AC_CONFIG_SRCDIR([src/nano.c])
AC_CANONICAL_HOST
AM_INIT_AUTOMAKE([1.14])

View File

@@ -85,7 +85,7 @@
<h3><a name="1.3"></a>1.3. Why the name change from TIP?</h3>
<blockquote><p>On January 10, 2000, TIP was officially renamed to nano because of a namespace conflict with another program called 'tip'. The original 'tip' program &quot;establishes a full duplex terminal connection to a remote host&quot;, and was included with many older Unix systems (and newer ones like Solaris). The conflict was not noticed at first because there is no 'tip' utility included with most GNU/Linux distributions (where nano was developed).</p></blockquote>
<h3><a name="1.4"></a>1.4. What is the current version of nano?</h3>
<blockquote><p>The current version of nano <i>should</i> be <b>4.2</b>. Of course, you should always check the <a href="https://nano-editor.org/">nano homepage</a> to see what the latest and greatest version is.</p></blockquote>
<blockquote><p>The current version of nano <i>should</i> be <b>4.3</b>. Of course, you should always check the <a href="https://nano-editor.org/">nano homepage</a> to see what the latest and greatest version is.</p></blockquote>
<h3><a name="1.5"></a>1.5. I want to read the man page without having to download the program!</h3>
<blockquote><p>Jeez, demanding, aren't we? Okay, look <a href="https://nano-editor.org/dist/latest/nano.1.html">here</a>.</p></blockquote>
<hr width="100%">

View File

@@ -16,7 +16,7 @@
.\" Documentation License along with this program. If not, see
.\" <https://www.gnu.org/licenses/>.
.\"
.TH NANO 1 "version 4.2" "April 2019"
.TH NANO 1 "version 4.3" "June 2019"
.SH NAME
nano \- Nano's ANOther editor, inspired by Pico
@@ -27,8 +27,8 @@ nano \- Nano's ANOther editor, inspired by Pico
.SH NOTICE
Starting with version 4.0, \fBnano\fR no longer hard-wraps an overlong
line by default, uses smooth scrolling by default, and by default makes
use of the line below the title bar.
line by default. It further uses smooth scrolling by default, and by
default includes the line below the title bar into the editing area.
.sp
If you want the old, Pico behavior back, you can use \fB\-\-breaklonglines\fR,
\fB\-\-jumpyscrolling\fR, and \fB\-\-emptyline\fR (or \fB\-bje\fR for short).
@@ -121,7 +121,8 @@ properly, please report a bug. Using this option disables \fBnano\fR's
mouse support.
.TP
.BR \-L ", " \-\-nonewlines
Don't automatically add a newline when a file does not end with one.
Don't automatically add a newline when a text does not end with one.
(This can cause you to save non-POSIX text files.)
.TP
.BR \-M ", " \-\-trimblanks
Snip trailing whitespace from the wrapped line when automatic
@@ -141,7 +142,7 @@ and place it at that position again upon reopening such a file.
.TP
.BR "\-Q ""\fIregex\fB""" ", " "\-\-quotestr=""" \fIregex """
Set the regular expression for matching the quoting part of a line.
The default value is \fB"^([\ \\t]*([!#%:;>|}]|//|\-\-))+"\fP.
The default value is \fB"^([\ \\t]*([!#%:;>|}]|//))+"\fP.
(Note that \fB\\t\fP stands for an actual Tab.)
This makes it possible to rejustify blocks of quoted text when composing
email, and to rewrap blocks of line comments when writing source code.

View File

@@ -8,8 +8,8 @@
@smallbook
@set EDITION 0.5
@set VERSION 4.2
@set UPDATED April 2019
@set VERSION 4.3
@set UPDATED June 2019
@dircategory Editors
@direntry
@@ -23,7 +23,7 @@
@titlepage
@title GNU @command{nano}
@subtitle a small and friendly text editor
@subtitle version 4.2
@subtitle version 4.3
@author Chris Allegretta
@page
@@ -63,7 +63,7 @@ e-mail: @email{chrisa@@asty.org}@*
@node Top
@top
This manual documents the GNU @command{nano} editor, version 4.2.
This manual documents the GNU @command{nano} editor, version 4.3.
@menu
* Introduction::
@@ -97,8 +97,8 @@ as is reasonable while offering a superset of Pico's functionality.
Pico differ.
Starting with version 4.0, @command{nano} no longer hard-wraps an overlong
line by default, uses smooth scrolling by default, and by default makes
use of the line below the title bar.
line by default. It further uses smooth scrolling by default, and by
default includes the line below the title bar into the editing area.
If you want the old, Pico behavior back, you can use the
following options: @option{--breaklonglines},
@@ -214,7 +214,8 @@ mouse support.
@item -L
@itemx --nonewlines
Don't automatically add a newline when a file does not end with one.
Don't automatically add a newline when a text does not end with one.
(This can cause you to save non-POSIX text files.)
@item -M
@itemx --trimblanks
@@ -239,7 +240,7 @@ and place it at that position again upon reopening such a file.
@item -Q "@var{regex}"
@itemx --quotestr="@var{regex}"
Set the regular expression for matching the quoting part of a line.
The default value is @t{"^([@w{ }\t]*([!#%:;>|@}]|//|--))+"}.
The default value is @t{"^([@w{ }\t]*([!#%:;>|@}]|//))+"}.
(Note that @code{\t} stands for a literal Tab character.)
This makes it possible to rejustify blocks of quoted text when composing
email, and to rewrap blocks of line comments when writing source code.
@@ -689,10 +690,8 @@ take an argument are unset by default. So using the @code{unset} command
is only needed when wanting to override a setting of the system's nanorc
file in your own nanorc. Options that take an argument cannot be unset.
Quotes inside string parameters don't have to be escaped with
backslashes. The last double quote in the string will be treated as its
end. For example, for the @code{brackets} option, @t{""')>]@}"} will match
@code{"}, @code{'}, @code{)}, @code{>}, @code{]}, and @code{@}}.
Quotes inside the @var{characters} parameters below should not be escaped.
The last double quote on the line will be seen as the closing quote.
@menu
* Settings::
@@ -740,7 +739,7 @@ function tags, line numbers, and selected text. This can be overridden by
setting the options @code{titlecolor}, @code{statuscolor}, @code{keycolor},
@code{functioncolor}, @code{numbercolor}, and @code{selectedcolor}.
@item set brackets "@var{string}"
@item set brackets "@var{characters}"
Set the characters treated as closing brackets when justifying
paragraphs. This may not include blank characters. Only closing
punctuation (see @code{set punct}), optionally followed by the specified
@@ -765,6 +764,7 @@ Do not use the line below the title bar, leaving it entirely blank.
@item set errorcolor @var{fgcolor},@var{bgcolor}
Use this color combination for the status bar when an error message is displayed.
The default value is @t{brightwhite,red}.
@xref{@code{set functioncolor}} for valid color names.
@item set fill @var{number}
@@ -807,7 +807,7 @@ Display line numbers to the left of the text area.
@item set locking
Enable vim-style lock-files for when editing files.
@item set matchbrackets "@var{string}"
@item set matchbrackets "@var{characters}"
Set the opening and closing brackets that can be found by bracket
searches. This may not include blank characters. The opening set must
come before the closing set, and the two sets must be in the same order.
@@ -831,7 +831,8 @@ Don't convert files from DOS/Mac format.
Don't display the help lists at the bottom of the screen.
@item set nonewlines
Don't automatically add a newline when a file does not end with one.
Don't automatically add a newline when a text does not end with one.
(This can cause you to save non-POSIX text files.)
@item set nopauses
Don't pause between warnings at startup. This means that only
@@ -858,7 +859,7 @@ The cursor position is remembered for the 200 most-recently edited files.
@item set preserve
Preserve the XON and XOFF keys (@kbd{^Q} and @kbd{^S}).
@item set punct "@var{string}"
@item set punct "@var{characters}"
Set the characters treated as closing punctuation when justifying
paragraphs. This may not include blank characters. Only the
specified closing punctuation, optionally followed by closing brackets
@@ -871,7 +872,7 @@ keystroke instead of 25. Note that @option{constantshow} overrides this.
@item set quotestr "@var{regex}"
Set the regular expression for matching the quoting part of a line.
The default value is @t{"^([@w{ }\t]*([!#%:;>|@}]|//|--))+"}.
The default value is @t{"^([@w{ }\t]*([!#%:;>|@}]|//))+"}.
(Note that @code{\t} stands for a literal Tab character.)
This makes it possible to rejustify blocks of quoted text when composing
email, and to rewrap blocks of line comments when writing source code.
@@ -888,7 +889,8 @@ and Delete work properly. You should only use this option when on your
system either Backspace acts like Delete or Delete acts like Backspace.
@item set regexp
Do extended regular expression searches by default.
Do regular-expression searches by default.
Regular expressions in @command{nano} are of the extended type (ERE).
@item set selectedcolor @var{fgcolor},@var{bgcolor}
Use this color combination for selected text.
@@ -957,7 +959,7 @@ This mode allows the user to open also other files for viewing,
unless @option{--restricted} is given on the command line.
@anchor{Whitespace}
@item set whitespace "@var{string}"
@item set whitespace "@var{characters}"
Set the two characters used to indicate the presence of tabs and
spaces. They must be single-column characters. The default pair
for a UTF-8 locale is @t{"»·"}, and for other locales @t{">."}.
@@ -966,7 +968,7 @@ for a UTF-8 locale is @t{"»·"}, and for other locales @t{">."}.
Detect word boundaries differently by treating punctuation
characters as part of a word.
@item set wordchars "@var{string}"
@item set wordchars "@var{characters}"
Specify which other characters (besides the normal alphanumeric ones)
should be considered as parts of words. This overrides the option
@code{wordbounds}.
@@ -987,6 +989,20 @@ powerful enough to fully parse a file. Nevertheless, regular
expressions can do a lot and are easy to make, so they are a
good fit for a small editor like @command{nano}.
All regular expressions in @command{nano} are extended regular expressions
(ERE). This means that @code{.}, @code{?}, @code{*}, @code{+}, @code{^},
@code{$}, and several other characters are special.
The period @code{.} matches any single character,
@code{?} means the preceding item is optional,
@code{*} means the preceding item may be matched zero or more times,
@code{+} means the preceding item must be matched one or more times,
@code{^} matches the beginning of a line, and @code{$} the end,
@code{\<} matches the start of a word, and @code{\>} the end,
and @code{\s} matches a blank.
It also means that lookahead and lookbehind are not possible.
A complete explanation can be found in the manual of GNU grep:
@code{info grep regular}.
A separate syntax can be defined for each kind of file
via the following commands in a nanorc file:

View File

@@ -16,15 +16,15 @@
.\" Documentation License along with this program. If not, see
.\" <https://www.gnu.org/licenses/>.
.\"
.TH NANORC 5 "version 4.2" "April 2019"
.TH NANORC 5 "version 4.3" "June 2019"
.SH NAME
nanorc \- GNU nano's configuration file
.SH NOTICE
Starting with version 4.0, \fBnano\fR no longer hard-wraps an overlong
line by default, uses smooth scrolling by default, and by default makes
use of the line below the title bar.
line by default. It further uses smooth scrolling by default, and by
default includes the line below the title bar into the editing area.
.sp
If you want the old, Pico behavior back, you can use \fBset breaklonglines\fR,
\fBset jumpyscrolling\fR, and \fBset emptyline\fR.
@@ -52,11 +52,8 @@ command is only needed when wanting to override a setting of the system's
\fInanorc\fR file in your own \fInanorc\fR. Options that take an
argument cannot be unset.
.sp
Below, the \fIstring\fR parameters need to be enclosed in double quotes.
Quotes inside these string parameters don't have to be escaped with
backslashes. The last double quote in the string will be treated as its
end. For example, for the \fBbrackets\fP option, "\fB"')>]}\fP" will
match \fB"\fP, \fB'\fP, \fB)\fP, \fB>\fP, \fB]\fP, and \fB}\fP.
Quotes inside the \fIcharacters\fR parameters below should not be escaped.
The last double quote on the line will be seen as the closing quote.
.sp
The supported commands and arguments are:
@@ -94,7 +91,7 @@ function tags, line numbers, and selected text. This can be overridden by
setting the options \fBtitlecolor\fP, \fBstatuscolor\fP, \fBkeycolor\fP,
\fBfunctioncolor\fP, \fBnumbercolor\fP, and \fBselectedcolor\fP.
.TP
.B set brackets "\fIstring\fP"
.BI "set brackets """ characters """
Set the characters treated as closing brackets when justifying
paragraphs. This may not include blank characters. Only closing
punctuation (see \fBset punct\fP), optionally followed by the specified
@@ -118,6 +115,7 @@ Do not use the line below the title bar, leaving it entirely blank.
.TP
.B set errorcolor \fIfgcolor\fR,\fIbgcolor\fR
Use this color combination for the status bar when an error message is displayed.
The default value is \fBbrightwhite,red\fR.
See \fBset titlecolor\fR for valid color names.
.TP
.B set fill \fInumber\fR
@@ -125,7 +123,7 @@ Set the target width for justifying and automatic hard-wrapping at this
\fInumber\fR of columns. If the value is 0 or less, wrapping will occur
at the width of the screen minus \fInumber\fR columns, allowing the wrap
point to vary along with the width of the screen if the screen is resized.
The default value is \-8.
The default value is \fB\-8\fR.
.TP
.B set functioncolor \fIfgcolor\fR,\fIbgcolor\fR
Specify the color combination to use for the function descriptions
@@ -154,7 +152,7 @@ Display line numbers to the left of the text area.
.B set locking
Enable vim-style lock-files for when editing files.
.TP
.B set matchbrackets "\fIstring\fP"
.BI "set matchbrackets """ characters """
Set the opening and closing brackets that can be found by bracket
searches. This may not include blank characters. The opening set must
come before the closing set, and the two sets must be in the same order.
@@ -181,7 +179,8 @@ Don't convert files from DOS/Mac format.
Don't display the two help lines at the bottom of the screen.
.TP
.B set nonewlines
Don't automatically add a newline when a file does not end with one.
Don't automatically add a newline when a text does not end with one.
(This can cause you to save non-POSIX text files.)
.TP
.B set nopauses
Don't pause between warnings at startup. This means that only
@@ -208,7 +207,7 @@ The cursor position is remembered for the 200 most-recently edited files.
.B set preserve
Preserve the XON and XOFF keys (^Q and ^S).
.TP
.B set punct "\fIstring\fP"
.BI "set punct """ characters """
Set the characters treated as closing punctuation when justifying
paragraphs. This may not include blank characters. Only the
specfified closing punctuation, optionally followed by closing brackets
@@ -218,9 +217,9 @@ specfified closing punctuation, optionally followed by closing brackets
Do quick status-bar blanking: status-bar messages will disappear after 1
keystroke instead of 25. The option \fBconstantshow\fR overrides this.
.TP
.B set quotestr "\fIregex\fP"
.BI "set quotestr """ regex """
Set the regular expression for matching the quoting part of a line.
The default value is "\fB^([\ \\t]*([!#%:;>|}]|//|\-\-))+\fP".
The default value is "\fB^([\ \\t]*([!#%:;>|}]|//))+\fP".
(Note that \fB\\t\fR stands for an actual Tab character.)
This makes it possible to rejustify blocks of quoted text when composing
email, and to rewrap blocks of line comments when writing source code.
@@ -237,7 +236,8 @@ and Delete work properly. You should only use this option when on your
system either Backspace acts like Delete or Delete acts like Backspace.
.TP
.B set regexp
Do extended regular expression searches by default.
Do regular-expression searches by default.
Regular expressions in \fBnano\fR are of the extended type (ERE).
.TP
.B set selectedcolor \fIfgcolor\fR,\fIbgcolor\fR
Specify the color combination to use for selected text.
@@ -309,7 +309,7 @@ Disallow file modification: read-only mode.
This mode allows the user to open also other files for viewing,
unless \fB\-\-restricted\fR is given on the command line.
.TP
.B set whitespace "\fIstring\fP"
.BI "set whitespace """ characters """
Set the two characters used to indicate the presence of tabs and
spaces. They must be single-column characters. The default pair
for a UTF-8 locale is "\fB\[Fc]\[md]\fR", and for other locales "\fB>.\fR".
@@ -318,7 +318,7 @@ for a UTF-8 locale is "\fB\[Fc]\[md]\fR", and for other locales "\fB>.\fR".
Detect word boundaries differently by treating punctuation
characters as parts of words.
.TP
.B set wordchars \fIstring\fP
.BI "set wordchars """ characters """
Specify which other characters (besides the normal alphanumeric ones)
should be considered as parts of words. This overrides the option
\fBwordbounds\fR.
@@ -335,6 +335,20 @@ powerful enough to fully parse a file. Nevertheless, regular
expressions can do a lot and are easy to make, so they are a
good fit for a small editor like \fBnano\fR.
.sp
All regular expressions in \fBnano\fR are extended regular expressions (ERE).
This means that \fB.\fR, \fB?\fR, \fB*\fR, \fB+\fR, \fB^\fR, \fB$\fR, and
several other characters are special.
The period \fB.\fR matches any single character,
\fB?\fR means the preceding item is optional,
\fB*\fR means the preceding item may be matched zero or more times,
\fB+\fR means the preceding item must be matched one or more times,
\fB^\fR matches the beginning of a line, and \fB$\fR the end,
\fB\\<\fR matches the start of a word, and \fB\\>\fR the end,
and \fB\\s\fR matches a blank.
It also means that lookahead and lookbehind are not possible.
A complete explanation can be found in the manual page of GNU grep:
\fBman grep\fR.
.sp
For each kind of file a separate syntax can be defined
via the following commands:
.TP

View File

@@ -16,7 +16,7 @@
.\" Documentation License along with this program. If not, see
.\" <https://www.gnu.org/licenses/>.
.\"
.TH RNANO 1 "version 4.2" "April 2019"
.TH RNANO 1 "version 4.3" "June 2019"
.SH NAME
rnano \- a restricted nano

View File

@@ -8,10 +8,8 @@
## For the options that take parameters, the default value is given.
## Other options are unset by default.
##
## Quotes inside string parameters don't have to be escaped with
## backslashes. The last double quote in the string will be treated as
## its end. For example, for the "brackets" option, ""')>]}" will match
## ", ', ), >, ], and }.
## Inside string parameters, quotes should not be escaped. The last
## double quote on the line will be seen as the closing quote.
## Make the 'nextword' function (Ctrl+Right) stop at word ends
## instead of at beginnings.
@@ -127,7 +125,7 @@
## The regular expression that matches quoting characters in email
## or line-comment introducers in source code. The default is:
# set quotestr "^([ ]*([!#%:;>|}]|//|--))+"
# set quotestr "^([ ]*([!#%:;>|}]|//))+"
## Try to work around a mismatching terminfo terminal description.
# set rawsequences
@@ -135,7 +133,8 @@
## Fix Backspace/Delete confusion problem.
# set rebinddelete
## Do extended regular expression searches by default.
## Do regular-expression searches by default.
## Regular expressions are of the extended type (ERE).
# set regexp
## Put the cursor on the highlighted item in the file browser, and show
@@ -239,6 +238,8 @@
## yellow, magenta, cyan. For foreground colors, you may use the
## prefix "bright" to get a stronger highlight.
##
## All regexes (regular expressions) are of the extended type (ERE).
##
## To use multi-line regexes, use the start="regex" end="regex"
## [start="regex" end="regex"...] format.
##
@@ -246,8 +247,6 @@
## color will use a transparent color. If you don't want this, be sure
## to set the background color to black or white.
##
## All regexes should be extended regular expressions.
##
## If you wish, you may put your syntax definitions in separate files.
## You can make use of such files as follows:
##

1166
po/bg.po

File diff suppressed because it is too large Load Diff

1175
po/ca.po

File diff suppressed because it is too large Load Diff

1171
po/cs.po

File diff suppressed because it is too large Load Diff

1382
po/da.po

File diff suppressed because it is too large Load Diff

1182
po/de.po

File diff suppressed because it is too large Load Diff

1174
po/eo.po

File diff suppressed because it is too large Load Diff

1177
po/es.po

File diff suppressed because it is too large Load Diff

1166
po/eu.po

File diff suppressed because it is too large Load Diff

1169
po/fi.po

File diff suppressed because it is too large Load Diff

1174
po/fr.po

File diff suppressed because it is too large Load Diff

1168
po/ga.po

File diff suppressed because it is too large Load Diff

1168
po/gl.po

File diff suppressed because it is too large Load Diff

1179
po/hr.po

File diff suppressed because it is too large Load Diff

1168
po/hu.po

File diff suppressed because it is too large Load Diff

1158
po/id.po

File diff suppressed because it is too large Load Diff

1172
po/it.po

File diff suppressed because it is too large Load Diff

1178
po/ja.po

File diff suppressed because it is too large Load Diff

1170
po/ko.po

File diff suppressed because it is too large Load Diff

1166
po/ms.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1171
po/nb.po

File diff suppressed because it is too large Load Diff

1176
po/nl.po

File diff suppressed because it is too large Load Diff

1158
po/nn.po

File diff suppressed because it is too large Load Diff

1172
po/pl.po

File diff suppressed because it is too large Load Diff

1180
po/pt.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1177
po/ro.po

File diff suppressed because it is too large Load Diff

1166
po/ru.po

File diff suppressed because it is too large Load Diff

1166
po/sl.po

File diff suppressed because it is too large Load Diff

1168
po/sr.po

File diff suppressed because it is too large Load Diff

1437
po/sv.po

File diff suppressed because it is too large Load Diff

1174
po/tr.po

File diff suppressed because it is too large Load Diff

1197
po/uk.po

File diff suppressed because it is too large Load Diff

1170
po/vi.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
#!/bin/bash
VERSION="4.2"
VERSION="4.3"
./configure -C --enable-tiny && make && ./configure -C &&

View File

@@ -77,8 +77,6 @@ char *do_browser(char *path)
present_name = mallocstrcpy(present_name, filelist[selected]);
}
assert(path != NULL && path[strlen(path) - 1] == '/');
if (dir != NULL) {
/* Get the file list, and set longest and width in the process. */
read_the_list(path, dir);
@@ -223,11 +221,9 @@ char *do_browser(char *path)
selected = filelist_len - 1;
} else if (func == goto_dir_void) {
/* Ask for the directory to go to. */
int i = do_prompt(TRUE, FALSE, MGOTODIR, NULL, NULL,
/* TRANSLATORS: This is a prompt. */
browser_refresh, _("Go To Directory"));
if (i < 0) {
if (do_prompt(TRUE, FALSE, MGOTODIR, NULL, NULL,
/* TRANSLATORS: This is a prompt. */
browser_refresh, _("Go To Directory")) < 0) {
statusbar(_("Cancelled"));
continue;
}
@@ -305,13 +301,12 @@ char *do_browser(char *path)
} else if (func == (functionptrtype)implant) {
implant(first_sc_for(MBROWSER, func)->expansion);
#endif
} else if (func == do_exit) {
/* Exit from the file browser. */
break;
#ifndef NANO_TINY
} else if (kbinput == KEY_WINCH) {
;
; /* Nothing to do. */
#endif
} else if (func == do_exit) {
break;
} else
unbound_key(kbinput);
@@ -394,8 +389,6 @@ void read_the_list(const char *path, DIR *dir)
const struct dirent *nextdir;
size_t i = 0, path_len = strlen(path);
assert(path != NULL && path[strlen(path) - 1] == '/' && dir != NULL);
longest = 0;
/* Find the length of the longest filename in the current folder. */
@@ -445,8 +438,6 @@ void read_the_list(const char *path, DIR *dir)
* filelist, so record it. */
filelist_len = i;
assert(filelist != NULL);
/* Sort the list of names. */
qsort(filelist, filelist_len, sizeof(char *), diralphasort);

View File

@@ -70,7 +70,7 @@ bool is_alpha_mbchar(const char *c)
wchar_t wc;
if (mbtowc(&wc, c, MAXCHARLEN) < 0)
return 0;
return FALSE;
return iswalpha(wc);
} else
@@ -86,7 +86,7 @@ bool is_alnum_mbchar(const char *c)
wchar_t wc;
if (mbtowc(&wc, c, MAXCHARLEN) < 0)
return 0;
return FALSE;
return iswalnum(wc);
} else
@@ -102,7 +102,7 @@ bool is_blank_mbchar(const char *c)
wchar_t wc;
if (mbtowc(&wc, c, MAXCHARLEN) < 0)
return 0;
return FALSE;
return iswblank(wc);
} else
@@ -139,7 +139,7 @@ bool is_punct_mbchar(const char *c)
wchar_t wc;
if (mbtowc(&wc, c, MAXCHARLEN) < 0)
return 0;
return FALSE;
return iswpunct(wc);
} else
@@ -200,36 +200,6 @@ char control_mbrep(const char *c, bool isdata)
return control_rep(*c);
}
/* Assess how many bytes the given (multibyte) character occupies. Return -1
* if the byte sequence is invalid, and return the number of bytes minus 8
* when it encodes an invalid codepoint. Also, in the second parameter,
* return the number of columns that the character occupies. */
int length_of_char(const char *c, int *width)
{
#ifdef ENABLE_UTF8
if (use_utf8) {
wchar_t wc;
int charlen = mbtowc(&wc, c, MAXCHARLEN);
/* If the sequence is invalid... */
if (charlen < 0)
return -1;
/* If the codepoint is invalid... */
if (!is_valid_unicode(wc))
return charlen - 8;
else {
*width = wcwidth(wc);
/* If the codepoint is unassigned, assume a width of one. */
if (*width < 0)
*width = 1;
return charlen;
}
} else
#endif
return 1;
}
/* This function is equivalent to wcwidth() for multibyte characters. */
int mbwidth(const char *c)
{
@@ -280,6 +250,20 @@ char *make_mbchar(long chr, int *chr_mb_len)
return chr_mb;
}
/* Return the length (in bytes) of the character located at *pointer. */
int char_length(const char *pointer)
{
#ifdef ENABLE_UTF8
/* If possibly a multibyte character, get its length; otherwise, it's 1. */
if ((signed char)*pointer < 0) {
int length = mblen(pointer, MAXCHARLEN);
return (length < 0 ? 1 : length);
} else
#endif
return 1;
}
/* Parse a multibyte character from buf. Return the number of bytes
* used. If chr isn't NULL, store the multibyte character in it. If
* col isn't NULL, add the character's width (in columns) to it. */
@@ -328,11 +312,11 @@ int parse_mbchar(const char *buf, char *chr, size_t *col)
/* Return the index in buf of the beginning of the multibyte character
* before the one at pos. */
size_t move_mbleft(const char *buf, size_t pos)
size_t step_left(const char *buf, size_t pos)
{
#ifdef ENABLE_UTF8
if (use_utf8) {
size_t before, char_len = 0;
size_t before, charlen = 0;
if (pos < 4)
before = 0;
@@ -355,11 +339,11 @@ size_t move_mbleft(const char *buf, size_t pos)
/* Move forward again until we reach the original character,
* so we know the length of its preceding character. */
while (before < pos) {
char_len = parse_mbchar(buf + before, NULL, NULL);
before += char_len;
charlen = char_length(buf + before);
before += charlen;
}
return before - char_len;
return before - charlen;
} else
#endif
return (pos == 0 ? 0 : pos - 1);
@@ -367,9 +351,9 @@ size_t move_mbleft(const char *buf, size_t pos)
/* Return the index in buf of the beginning of the multibyte character
* after the one at pos. */
size_t move_mbright(const char *buf, size_t pos)
size_t step_right(const char *buf, size_t pos)
{
return pos + parse_mbchar(buf + pos, NULL, NULL);
return pos + char_length(buf + pos);
}
/* This function is equivalent to strcasecmp() for multibyte strings. */
@@ -402,8 +386,8 @@ int mbstrncasecmp(const char *s1, const char *s2, size_t n)
return difference;
}
s1 += move_mbright(s1, 0);
s2 += move_mbright(s2, 0);
s1 += char_length(s1);
s2 += char_length(s2);
n--;
}
@@ -424,13 +408,13 @@ char *mbstrcasestr(const char *haystack, const char *needle)
if (mbstrncasecmp(haystack, needle, needle_len) == 0)
return (char *)haystack;
haystack += move_mbright(haystack, 0);
haystack += char_length(haystack);
}
return NULL;
} else
#endif
return (char *) strcasestr(haystack, needle);
return (char *)strcasestr(haystack, needle);
}
/* This function is equivalent to strstr(), except in that it scans the
@@ -496,7 +480,7 @@ char *mbrevstrcasestr(const char *haystack, const char *needle,
if (pointer == haystack)
return NULL;
pointer = haystack + move_mbleft(haystack, pointer - haystack);
pointer = haystack + step_left(haystack, pointer - haystack);
}
} else
#endif
@@ -504,70 +488,61 @@ char *mbrevstrcasestr(const char *haystack, const char *needle,
}
/* Count the number of (multibyte) characters in the given string. */
size_t mbstrlen(const char *s)
size_t mbstrlen(const char *pointer)
{
size_t maxlen = (size_t)-1;
size_t count = 0;
while (*pointer != '\0') {
#ifdef ENABLE_UTF8
if (use_utf8) {
size_t n = 0;
if ((signed char)*pointer < 0) {
int length = mblen(pointer, MAXCHARLEN);
while (*s != '\0' && maxlen > 0) {
if ((signed char)*s < 0) {
int length = mblen(s, MAXCHARLEN);
s += (length < 0 ? 1 : length);
} else
s++;
maxlen--;
n++;
}
return n;
} else
pointer += (length < 0 ? 1 : length);
} else
#endif
return strnlen(s, maxlen);
pointer++;
count++;
}
return count;
}
#if !defined(NANO_TINY) || defined(ENABLE_JUSTIFY)
/* This function is equivalent to strchr() for multibyte strings. */
char *mbstrchr(const char *s, const char *c)
char *mbstrchr(const char *string, const char *chr)
{
#ifdef ENABLE_UTF8
if (use_utf8) {
bool bad_s_mb = FALSE, bad_c_mb = FALSE;
char symbol[MAXCHARLEN];
const char *q = s;
bool bad_s = FALSE, bad_c = FALSE;
wchar_t ws, wc;
if (mbtowc(&wc, c, MAXCHARLEN) < 0) {
wc = (unsigned char)*c;
bad_c_mb = TRUE;
if (mbtowc(&wc, chr, MAXCHARLEN) < 0) {
wc = (unsigned char)*chr;
bad_c = TRUE;
}
while (*s != '\0') {
int sym_len = parse_mbchar(s, symbol, NULL);
while (*string != '\0') {
int symlen = mbtowc(&ws, string, MAXCHARLEN);
if (mbtowc(&ws, symbol, sym_len) < 0) {
ws = (unsigned char)*s;
bad_s_mb = TRUE;
if (symlen < 0) {
ws = (unsigned char)*string;
bad_s = TRUE;
}
if (bad_s_mb == bad_c_mb && ws == wc)
if (ws == wc && bad_s == bad_c)
break;
s += sym_len;
q += sym_len;
string += symlen;
}
if (*s == '\0')
q = NULL;
if (*string == '\0')
return NULL;
return (char *)q;
return (char *)string;
} else
#endif
return (char *) strchr(s, *c);
return strchr(string, *chr);
}
#endif /* !NANO_TINY || ENABLE_JUSTIFY */
@@ -580,7 +555,7 @@ char *mbstrpbrk(const char *string, const char *accept)
if (mbstrchr(accept, string) != NULL)
return (char *)string;
string += move_mbright(string, 0);
string += char_length(string);
}
return NULL;
@@ -593,7 +568,7 @@ char *mbrevstrpbrk(const char *head, const char *accept, const char *pointer)
if (*pointer == '\0') {
if (pointer == head)
return NULL;
pointer = head + move_mbleft(head, pointer - head);
pointer = head + step_left(head, pointer - head);
}
while (TRUE) {
@@ -604,7 +579,7 @@ char *mbrevstrpbrk(const char *head, const char *accept, const char *pointer)
if (pointer == head)
return NULL;
pointer = head + move_mbleft(head, pointer - head);
pointer = head + step_left(head, pointer - head);
}
}
#endif /* !NANO_TINY */

View File

@@ -39,11 +39,34 @@
#define A_BANDAID A_NORMAL
#endif
/* Assign pair numbers for the colors in the given syntax, giving identical
* color pairs the same number. */
void set_syntax_colorpairs(syntaxtype *sint)
{
int new_number = NUMBER_OF_ELEMENTS + 1;
colortype *ink;
for (ink = sint->color; ink != NULL; ink = ink->next) {
const colortype *beforenow = sint->color;
while (beforenow != ink && (beforenow->fg != ink->fg ||
beforenow->bg != ink->bg))
beforenow = beforenow->next;
if (beforenow != ink)
ink->pairnum = beforenow->pairnum;
else
ink->pairnum = new_number++;
ink->attributes |= COLOR_PAIR(ink->pairnum) | A_BANDAID;
}
}
/* Initialize the colors for nano's interface, and assign pair numbers
* for the colors in each syntax. */
* for the colors in each loaded syntax. */
void set_colorpairs(void)
{
const syntaxtype *sint;
syntaxtype *sint;
bool using_defaults = FALSE;
size_t i;
@@ -82,27 +105,10 @@ void set_colorpairs(void)
free(color_combo[i]);
}
/* For each syntax, go through its list of colors and assign each
* its pair number, giving identical color pairs the same number. */
for (sint = syntaxes; sint != NULL; sint = sint->next) {
colortype *ink;
int new_number = NUMBER_OF_ELEMENTS + 1;
for (ink = sint->color; ink != NULL; ink = ink->next) {
const colortype *beforenow = sint->color;
while (beforenow != ink && (beforenow->fg != ink->fg ||
beforenow->bg != ink->bg))
beforenow = beforenow->next;
if (beforenow != ink)
ink->pairnum = beforenow->pairnum;
else
ink->pairnum = new_number++;
ink->attributes |= COLOR_PAIR(ink->pairnum) | A_BANDAID;
}
}
/* For each loaded syntax, assign pair numbers to color combinations. */
for (sint = syntaxes; sint != NULL; sint = sint->next)
if (sint->filename == NULL)
set_syntax_colorpairs(sint);
}
/* Initialize the color information. */
@@ -163,7 +169,6 @@ bool found_in_list(regexlisttype *head, const char *shibboleth)
void color_update(void)
{
syntaxtype *sint = NULL;
colortype *ink;
/* If the rcfiles were not read, or contained no syntaxes, get out. */
if (syntaxes == NULL)
@@ -267,22 +272,14 @@ void color_update(void)
}
}
/* When the syntax isn't loaded yet, parse it and initialize its colors. */
if (sint != NULL && sint->filename != NULL) {
parse_one_include(sint->filename, sint);
set_syntax_colorpairs(sint);
}
openfile->syntax = sint;
openfile->colorstrings = (sint == NULL ? NULL : sint->color);
/* If a syntax was found, compile its specified regexes (which have
* already been checked for validity when they were read in). */
for (ink = openfile->colorstrings; ink != NULL; ink = ink->next) {
if (ink->start == NULL) {
ink->start = (regex_t *)nmalloc(sizeof(regex_t));
regcomp(ink->start, ink->start_regex, ink->rex_flags);
}
if (ink->end_regex != NULL && ink->end == NULL) {
ink->end = (regex_t *)nmalloc(sizeof(regex_t));
regcomp(ink->end, ink->end_regex, ink->rex_flags);
}
}
}
/* Determine whether the matches of multiline regexes are still the same,
@@ -334,12 +331,10 @@ void check_the_multis(linestruct *line)
/* Allocate (for one line) the cache space for multiline color regexes. */
void alloc_multidata_if_needed(linestruct *fileptr)
{
int i;
if (fileptr->multidata == NULL) {
fileptr->multidata = (short *)nmalloc(openfile->syntax->nmultis * sizeof(short));
for (i = 0; i < openfile->syntax->nmultis; i++)
for (int i = 0; i < openfile->syntax->nmultis; i++)
fileptr->multidata[i] = -1;
}
}
@@ -355,10 +350,6 @@ void precalc_multicolorinfo(void)
if (openfile->colorstrings == NULL || ISSET(NO_COLOR_SYNTAX))
return;
#ifdef DEBUG
fprintf(stderr, "Precalculating the multiline color info...\n");
#endif
for (ink = openfile->colorstrings; ink != NULL; ink = ink->next) {
/* If this is not a multi-line regex, skip it. */
if (ink->end == NULL)
@@ -380,14 +371,14 @@ void precalc_multicolorinfo(void)
/* When the line contains a start match, look for an end, and if
* found, mark all the lines that are affected. */
while (regexec(ink->start, line->data + index, 1,
&startmatch, (index == 0) ? 0 : REG_NOTBOL) == 0) {
&startmatch, (index == 0) ? 0 : REG_NOTBOL) == 0) {
/* Begin looking for an end match after the start match. */
index += startmatch.rm_eo;
/* If there is an end match on this line, mark the line, but
* continue looking for other starts after it. */
if (regexec(ink->end, line->data + index, 1,
&endmatch, (index == 0) ? 0 : REG_NOTBOL) == 0) {
&endmatch, (index == 0) ? 0 : REG_NOTBOL) == 0) {
line->multidata[ink->id] = CSTARTENDHERE;
index += endmatch.rm_eo;
/* If both start and end are mere anchors, step ahead. */
@@ -396,7 +387,7 @@ void precalc_multicolorinfo(void)
/* When at end-of-line, we're done. */
if (line->data[index] == '\0')
break;
index = move_mbright(line->data, index);
index = step_right(line->data, index);
}
continue;
}

165
src/cut.c
View File

@@ -35,10 +35,8 @@ void do_deletion(undo_type action)
/* When in the middle of a line, delete the current character. */
if (openfile->current->data[openfile->current_x] != '\0') {
int char_len = parse_mbchar(openfile->current->data +
openfile->current_x, NULL, NULL);
size_t line_len = strlen(openfile->current->data +
openfile->current_x);
int charlen = char_length(openfile->current->data + openfile->current_x);
size_t line_len = strlen(openfile->current->data + openfile->current_x);
#ifndef NANO_TINY
/* If the type of action changed or the cursor moved to a different
* line, create a new undo item, otherwise update the existing item. */
@@ -53,13 +51,13 @@ void do_deletion(undo_type action)
#endif
/* Move the remainder of the line "in", over the current character. */
charmove(&openfile->current->data[openfile->current_x],
&openfile->current->data[openfile->current_x + char_len],
line_len - char_len + 1);
&openfile->current->data[openfile->current_x + charlen],
line_len - charlen + 1);
#ifndef NANO_TINY
/* Adjust the mark if it is after the cursor on the current line. */
if (openfile->mark == openfile->current &&
openfile->mark_x > openfile->current_x)
openfile->mark_x -= char_len;
openfile->mark_x -= charlen;
#endif
/* Otherwise, when not at end of buffer, join this line with the next. */
} else if (openfile->current != openfile->filebot) {
@@ -91,7 +89,7 @@ void do_deletion(undo_type action)
}
#endif
unlink_node(joining);
renumber(openfile->current);
renumber_from(openfile->current);
/* Two lines were joined, so we need to refresh the screen. */
refresh_needed = TRUE;
@@ -148,12 +146,10 @@ void chop_word(bool forward)
/* Remember the current cursor position. */
linestruct *is_current = openfile->current;
size_t is_current_x = openfile->current_x;
/* Remember where the cutbuffer is and then make it seem blank. */
/* Remember where the cutbuffer is, then make it seem blank. */
linestruct *is_cutbuffer = cutbuffer;
linestruct *is_cutbottom = cutbottom;
cutbuffer = NULL;
cutbottom = NULL;
/* Move the cursor to a word start, to the left or to the right.
* If that word is on another line and the cursor was not already
@@ -186,12 +182,11 @@ void chop_word(bool forward)
openfile->current_x = is_current_x;
/* Now kill the marked region and a word is gone. */
do_cut_text_void();
cut_text();
/* Discard the cut word and restore the cutbuffer. */
free_lines(cutbuffer);
cutbuffer = is_cutbuffer;
cutbottom = is_cutbottom;
}
/* Delete a word leftward. */
@@ -203,6 +198,8 @@ void chop_previous_word(void)
/* Delete a word rightward. */
void chop_next_word(void)
{
openfile->mark = NULL;
if (is_cuttable(openfile->current_x > 0))
chop_word(FORWARD);
}
@@ -215,28 +212,15 @@ void cut_line(void)
* head of this line to the head of the next line into the cutbuffer;
* otherwise, move all of the text of this line into the cutbuffer. */
if (openfile->current != openfile->filebot)
extract_buffer(&cutbuffer, &cutbottom, openfile->current, 0,
openfile->current->next, 0);
extract(openfile->current, 0, openfile->current->next, 0);
else
extract_buffer(&cutbuffer, &cutbottom, openfile->current, 0,
extract(openfile->current, 0,
openfile->current, strlen(openfile->current->data));
openfile->placewewant = 0;
}
#ifndef NANO_TINY
/* Move all marked text from the current buffer into the cutbuffer. */
void cut_marked(bool *right_side_up)
{
linestruct *top, *bot;
size_t top_x, bot_x;
mark_order((const linestruct **)&top, &top_x,
(const linestruct **)&bot, &bot_x, right_side_up);
extract_buffer(&cutbuffer, &cutbottom, top, top_x, bot, bot_x);
openfile->placewewant = xplustabs();
}
/* Move all text from the cursor position until the end of this line into
* the cutbuffer. But when already at the end of a line, then move this
* "newline" to the cutbuffer. */
@@ -248,35 +232,48 @@ void cut_to_eol(void)
* the cutbuffer. Otherwise, when not at the end of the buffer,
* move the line separation into the cutbuffer. */
if (openfile->current_x < data_len)
extract_buffer(&cutbuffer, &cutbottom, openfile->current,
openfile->current_x, openfile->current, data_len);
extract(openfile->current, openfile->current_x,
openfile->current, data_len);
else if (openfile->current != openfile->filebot) {
extract_buffer(&cutbuffer, &cutbottom, openfile->current,
openfile->current_x, openfile->current->next, 0);
extract(openfile->current, openfile->current_x,
openfile->current->next, 0);
openfile->placewewant = xplustabs();
}
}
/* Move all marked text from the current buffer into the cutbuffer. */
void cut_marked(bool *right_side_up)
{
linestruct *top, *bot;
size_t top_x, bot_x;
get_region((const linestruct **)&top, &top_x,
(const linestruct **)&bot, &bot_x, right_side_up);
extract(top, top_x, bot, bot_x);
openfile->placewewant = xplustabs();
}
/* Move all text from the cursor position to end-of-file into the cutbuffer. */
void cut_to_eof(void)
{
extract_buffer(&cutbuffer, &cutbottom,
openfile->current, openfile->current_x,
extract(openfile->current, openfile->current_x,
openfile->filebot, strlen(openfile->filebot->data));
}
#endif /* !NANO_TINY */
/* Move text from the current buffer into the cutbuffer. If
* copy_text is TRUE, copy the text back into the buffer afterward.
* If cut_till_eof is TRUE, move all text from the current cursor
* copying is TRUE, copy the text back into the buffer afterward.
* If until_eof is TRUE, move all text from the current cursor
* position to the end of the file into the cutbuffer. If append
* is TRUE (when zapping), always append the cut to the cutbuffer. */
void do_cut_text(bool copy_text, bool marked, bool cut_till_eof, bool append)
void do_cut_text(bool copying, bool marked, bool until_eof, bool append)
{
#ifndef NANO_TINY
linestruct *cb_save = NULL;
linestruct *was_bottom = NULL;
/* The current end of the cutbuffer, before we add text to it. */
size_t cb_save_len = 0;
size_t botlen = 0;
/* The length of the string at the current end of the cutbuffer,
* before we add text to it. */
bool using_magicline = !ISSET(NO_NEWLINES);
@@ -284,51 +281,52 @@ void do_cut_text(bool copy_text, bool marked, bool cut_till_eof, bool append)
bool right_side_up = TRUE;
/* There *is* no region, *or* it is marked forward. */
#endif
static bool precedent = FALSE;
/* Whether the previous operation was a copying operation. */
/* If cuts were not continuous, or when cutting a region, clear the slate. */
if (!append && (!keep_cutbuffer || marked || cut_till_eof)) {
if ((!keep_cutbuffer || marked || until_eof || copying != precedent) &&
!append) {
free_lines(cutbuffer);
cutbuffer = NULL;
/* After a line cut, future line cuts should add to the cutbuffer. */
keep_cutbuffer = !marked && !cut_till_eof;
}
/* After a line operation, future ones should add to the cutbuffer. */
keep_cutbuffer = !marked && !until_eof;
precedent = copying;
#ifndef NANO_TINY
if (copy_text) {
if (copying) {
/* If the cutbuffer isn't empty, remember where it currently ends. */
if (cutbuffer != NULL) {
cb_save = cutbottom;
cb_save_len = strlen(cutbottom->data);
was_bottom = cutbottom;
botlen = strlen(cutbottom->data);
}
/* Don't add a magic line when moving text to the cutbuffer. */
SET(NO_NEWLINES);
}
if (cut_till_eof) {
/* Move all text up to the end of the file into the cutbuffer. */
/* Now move the relevant piece of text into the cutbuffer. */
if (until_eof)
cut_to_eof();
} else if (openfile->mark) {
/* Move the marked text to the cutbuffer, and turn the mark off. */
else if (openfile->mark) {
cut_marked(&right_side_up);
openfile->mark = NULL;
} else if (ISSET(CUT_FROM_CURSOR))
/* Move all text up to the end of the line into the cutbuffer. */
cut_to_eol();
else
#endif
/* Move the entire line into the cutbuffer. */
cut_line();
#ifndef NANO_TINY
if (copy_text) {
/* Copy the text that is in the cutbuffer (starting at its saved end,
* if there is one) back into the current buffer. This effectively
* uncuts the text we just cut. */
if (copying) {
/* Copy the text that was put into the cutbuffer back into the current
* file buffer, so that in the end nothing has been deleted. */
if (cutbuffer != NULL) {
if (cb_save != NULL) {
cb_save->data += cb_save_len;
copy_from_buffer(cb_save);
cb_save->data -= cb_save_len;
if (was_bottom != NULL) {
was_bottom->data += botlen;
copy_from_buffer(was_bottom);
was_bottom->data -= botlen;
} else
copy_from_buffer(cutbuffer);
@@ -341,9 +339,9 @@ void do_cut_text(bool copy_text, bool marked, bool cut_till_eof, bool append)
if (using_magicline)
UNSET(NO_NEWLINES);
} else
#endif /* !NANO_TINY */
#endif
set_modified();
set_modified();
refresh_needed = TRUE;
}
@@ -372,7 +370,7 @@ bool is_cuttable(bool test_cliff)
}
/* Move text from the current buffer into the cutbuffer. */
void do_cut_text_void(void)
void cut_text(void)
{
#ifndef NANO_TINY
if (!is_cuttable(ISSET(CUT_FROM_CURSOR) && openfile->mark == NULL))
@@ -380,11 +378,13 @@ void do_cut_text_void(void)
/* Only add a new undo item when the current item is not a CUT or when
* the current cut is not contiguous with the previous cutting. */
if (openfile->last_action != CUT || openfile->current_undo == NULL ||
openfile->current_undo->mark_begin_lineno != openfile->current->lineno ||
!keep_cutbuffer)
if (openfile->last_action != CUT || !keep_cutbuffer) {
keep_cutbuffer = FALSE;
add_undo(CUT);
}
do_cut_text(FALSE, openfile->mark != NULL, FALSE, FALSE);
update_undo(CUT);
#else
if (is_cuttable(FALSE))
@@ -396,9 +396,8 @@ void do_cut_text_void(void)
/* Move text from the current buffer into the cutbuffer, and copy it
* back into the buffer afterward. If the mark is set or the cursor
* was moved, blow away previous contents of the cutbuffer. */
void do_copy_text(void)
void copy_text(void)
{
static linestruct *next_contiguous_line = NULL;
bool mark_is_set = (openfile->mark != NULL);
/* Remember the current viewport and cursor position. */
@@ -407,25 +406,26 @@ void do_copy_text(void)
ssize_t is_current_lineno = openfile->current->lineno;
size_t is_current_x = openfile->current_x;
if (mark_is_set || openfile->current != next_contiguous_line)
keep_cutbuffer = FALSE;
/* If there is nothing to copy, don't even try. */
if (openfile->current->next == NULL && openfile->current->data[0] == '\0')
return;
do_cut_text(TRUE, mark_is_set, FALSE, FALSE);
/* If the mark was set, blow away the cutbuffer on the next copy. */
next_contiguous_line = (mark_is_set ? NULL : openfile->current);
/* If the mark was set, restore the viewport and cursor position. */
if (mark_is_set) {
openfile->edittop = fsfromline(is_edittop_lineno);
openfile->edittop = line_from_number(is_edittop_lineno);
openfile->firstcolumn = is_firstcolumn;
openfile->current = fsfromline(is_current_lineno);
openfile->current = line_from_number(is_current_lineno);
openfile->current_x = is_current_x;
}
} else
focusing = FALSE;
openfile->last_action = OTHER;
}
/* Cut from the current cursor position to the end of the file. */
void do_cut_till_eof(void)
void cut_till_eof(void)
{
if ((openfile->current == openfile->filebot && openfile->current->data[0] == '\0') ||
(!ISSET(NO_NEWLINES) && openfile->current->next == openfile->filebot &&
@@ -444,33 +444,28 @@ void zap_text(void)
{
/* Remember the current cutbuffer so it can be restored after the zap. */
linestruct *was_cutbuffer = cutbuffer;
linestruct *was_cutbottom = cutbottom;
if (!is_cuttable(ISSET(CUT_FROM_CURSOR) && openfile->mark == NULL))
return;
/* Add a new undo item only when the current item is not a ZAP or when
* the current zap is not contiguous with the previous zapping. */
if (openfile->last_action != ZAP || openfile->current_undo == NULL ||
openfile->current_undo->mark_begin_lineno != openfile->current->lineno ||
openfile->current_undo->xflags & (MARK_WAS_SET|WAS_MARKED_FORWARD))
if (openfile->last_action != ZAP || !keep_cutbuffer)
add_undo(ZAP);
/* Use the cutbuffer from the ZAP undo item, so the cut can be undone. */
cutbuffer = openfile->current_undo->cutbuffer;
cutbottom = openfile->current_undo->cutbottom;
do_cut_text(FALSE, openfile->mark != NULL, FALSE, TRUE);
update_undo(ZAP);
cutbuffer = was_cutbuffer;
cutbottom = was_cutbottom;
}
#endif /* !NANO_TINY */
/* Copy text from the cutbuffer into the current buffer. */
void do_uncut_text(void)
void paste_text(void)
{
ssize_t was_lineno = openfile->current->lineno;
/* The line number where we started the paste. */

View File

@@ -88,11 +88,19 @@ void make_new_buffer(void)
openfile->filename = mallocstrcpy(NULL, "");
initialize_buffer_text();
openfile->filetop = make_new_node(NULL);
openfile->filetop->data = mallocstrcpy(NULL, "");
openfile->filebot = openfile->filetop;
openfile->current = openfile->filetop;
openfile->current_x = 0;
openfile->placewewant = 0;
openfile->current_y = 0;
openfile->edittop = openfile->filetop;
openfile->firstcolumn = 0;
openfile->totsize = 0;
openfile->modified = FALSE;
#ifdef ENABLE_WRAPPING
openfile->spillage_line = NULL;
@@ -116,21 +124,6 @@ void make_new_buffer(void)
#endif
}
/* Initialize the text and pointers of the current openfile struct. */
void initialize_buffer_text(void)
{
openfile->filetop = make_new_node(NULL);
openfile->filetop->data = mallocstrcpy(NULL, "");
openfile->filebot = openfile->filetop;
openfile->edittop = openfile->filetop;
openfile->current = openfile->filetop;
openfile->firstcolumn = 0;
openfile->current_x = 0;
openfile->totsize = 0;
}
/* Mark the current file as modified if it isn't already, and then
* update the titlebar to display the file's new status. */
void set_modified(void)
@@ -273,7 +266,7 @@ int write_lockfile(const char *lockfilename, const char *origfilename, bool modi
goto free_the_data;
}
openfile->lock_filename = (char *) lockfilename;
openfile->lock_filename = (char *)lockfilename;
free(lockdata);
return 1;
@@ -302,8 +295,8 @@ int delete_lockfile(const char *lockfilename)
* creating the lockfile but we should continue to load the file. */
int do_lockfile(const char *filename)
{
char *namecopy = (char *) mallocstrcpy(NULL, filename);
char *secondcopy = (char *) mallocstrcpy(NULL, filename);
char *namecopy = mallocstrcpy(NULL, filename);
char *secondcopy = mallocstrcpy(NULL, filename);
size_t locknamesize = strlen(filename) + strlen(locking_prefix)
+ strlen(locking_suffix) + 3;
char *lockfilename = charalloc(locknamesize);
@@ -418,6 +411,7 @@ bool open_buffer(const char *filename, bool new_buffer)
{
char *realname;
/* The filename after tilde expansion. */
struct stat fileinfo;
FILE *f;
int rc;
/* rc == -2 means that we have a new file. -1 means that the
@@ -436,20 +430,25 @@ bool open_buffer(const char *filename, bool new_buffer)
realname = real_dir_from_tilde(filename);
/* When the specified filename is not empty, and the corresponding
* file exists, verify that it is a normal file. */
if (*filename != '\0') {
struct stat fileinfo;
if (stat(realname, &fileinfo) == 0 && !(S_ISREG(fileinfo.st_mode) ||
(ISSET(NOREAD_MODE) && S_ISFIFO(fileinfo.st_mode)))) {
if (S_ISDIR(fileinfo.st_mode))
statusline(ALERT, _("\"%s\" is a directory"), realname);
else
statusline(ALERT, _("\"%s\" is not a normal file"), realname);
/* Don't try to open directories, character files, or block files. */
if (*filename != '\0' && stat(realname, &fileinfo) == 0) {
if (S_ISDIR(fileinfo.st_mode)) {
statusline(ALERT, _("\"%s\" is a directory"), realname);
free(realname);
return FALSE;
}
if (S_ISCHR(fileinfo.st_mode) || S_ISBLK(fileinfo.st_mode)) {
statusline(ALERT, _("\"%s\" is a device file"), realname);
free(realname);
return FALSE;
}
#ifdef NANO_TINY
if (S_ISFIFO(fileinfo.st_mode)) {
statusline(ALERT, _("\"%s\" is a FIFO"), realname);
free(realname);
return FALSE;
}
#endif
}
/* If we're going to load into a new buffer, first create the new
@@ -457,13 +456,14 @@ bool open_buffer(const char *filename, bool new_buffer)
if (new_buffer) {
make_new_buffer();
if (!inhelp && has_valid_path(realname)) {
if (has_valid_path(realname)) {
#ifndef NANO_TINY
if (ISSET(LOCKING) && filename[0] != '\0') {
/* When not overriding an existing lock, discard the buffer. */
if (do_lockfile(realname) < 0) {
#ifdef ENABLE_MULTIBUFFER
close_buffer();
if (openfile != openfile->next)
close_buffer();
#endif
free(realname);
return FALSE;
@@ -476,12 +476,17 @@ bool open_buffer(const char *filename, bool new_buffer)
/* If the filename isn't blank, and we are not in NOREAD_MODE,
* open the file. Otherwise, treat it as a new file. */
rc = (filename[0] != '\0' && !ISSET(NOREAD_MODE)) ?
open_file(realname, new_buffer, inhelp, &f) : -2;
open_file(realname, new_buffer, &f) : -2;
/* If we have a non-new file, read it in. Then, if the buffer has
* no stat, update the stat, if applicable. */
if (rc > 0) {
install_handler_for_Ctrl_C();
read_file(f, rc, realname, !new_buffer);
restore_handler_for_Ctrl_C();
#ifndef NANO_TINY
if (openfile->current_stat == NULL)
stat_with_alloc(realname, &openfile->current_stat);
@@ -508,90 +513,51 @@ bool open_buffer(const char *filename, bool new_buffer)
}
#ifdef ENABLE_SPELLER
/* Open the specified file, and if that succeeds, blow away the text of
* the current buffer and read the file contents into its place. */
void replace_buffer(const char *filename)
/* Open the specified file, and if that succeeds, remove the text of the marked
* region or of the entire buffer and read the file contents into its place. */
bool replace_buffer(const char *filename, undo_type action, bool marked)
{
FILE *f;
int descriptor;
linestruct *was_cutbuffer = cutbuffer;
int descriptor;
FILE *f;
/* Open the file quietly. */
descriptor = open_file(filename, FALSE, TRUE, &f);
descriptor = open_file(filename, FALSE, &f);
/* If opening failed, forget it. */
if (descriptor < 0)
return;
return FALSE;
#ifndef NANO_TINY
add_undo(COUPLE_BEGIN);
openfile->undotop->strdata = mallocstrcpy(NULL, _("spelling correction"));
#endif
/* Throw away the text of the file. */
/* When nothing is marked, start at the top of the buffer. */
if (!marked) {
openfile->current = openfile->filetop;
openfile->current_x = 0;
}
/* Throw away the marked region or the whole buffer. */
cutbuffer = NULL;
openfile->current = openfile->filetop;
openfile->current_x = 0;
#ifndef NANO_TINY
add_undo(CUT_TO_EOF);
add_undo(action);
#endif
do_cut_text(FALSE, FALSE, TRUE, FALSE);
do_cut_text(FALSE, marked, !marked, FALSE);
#ifndef NANO_TINY
update_undo(CUT_TO_EOF);
update_undo(action);
#endif
free_lines(cutbuffer);
cutbuffer = was_cutbuffer;
/* Insert the processed file into its place. */
/* Insert the spell-checked file into the cleared area. */
read_file(f, descriptor, filename, TRUE);
#ifndef NANO_TINY
add_undo(COUPLE_END);
openfile->undotop->strdata = mallocstrcpy(NULL, _("spelling correction"));
#endif
return TRUE;
}
#ifndef NANO_TINY
/* Open the specified file, and if that succeeds, blow away the text of
* the current buffer covered by the mark and read the file
* contents into its place. */
void replace_marked_buffer(const char *filename)
{
FILE *f;
int descriptor;
bool using_magicline = !ISSET(NO_NEWLINES);
linestruct *was_cutbuffer = cutbuffer;
descriptor = open_file(filename, FALSE, TRUE, &f);
if (descriptor < 0)
return;
/* Don't add a magic line when replacing text in the buffer. */
SET(NO_NEWLINES);
add_undo(COUPLE_BEGIN);
openfile->undotop->strdata = mallocstrcpy(NULL, _("spelling correction"));
/* Throw away the text under the mark. */
cutbuffer = NULL;
add_undo(CUT);
do_cut_text(FALSE, TRUE, FALSE, FALSE);
update_undo(CUT);
free_lines(cutbuffer);
cutbuffer = was_cutbuffer;
/* Insert the processed file where the marked text was. */
read_file(f, descriptor, filename, TRUE);
/* Restore the magic-line behavior now that we're done fiddling. */
if (using_magicline)
UNSET(NO_NEWLINES);
add_undo(COUPLE_END);
openfile->undotop->strdata = mallocstrcpy(NULL, _("spelling correction"));
}
#endif /* !NANO_TINY */
#endif /* ENABLE_SPELLER */
/* Update the titlebar and the multiline cache to match the current buffer. */
@@ -633,19 +599,15 @@ void mention_name_and_linecount(void)
_("New Buffer") : tail(openfile->filename), count);
}
/* Switch to a neighbouring file buffer; to the next if to_next is TRUE;
* otherwise, to the previous one. */
void switch_to_adjacent_buffer(bool to_next)
/* Update title bar and such after switching to another buffer.*/
void redecorate_after_switch(void)
{
/* If only one file buffer is open, say so and get out. */
/* If only one file buffer is open, there is nothing to update. */
if (openfile == openfile->next) {
statusbar(_("No more open file buffers"));
return;
}
/* Switch to the next or previous file buffer. */
openfile = to_next ? openfile->next : openfile->prev;
#ifndef NANO_TINY
/* When not in softwrap mode, make sure firstcolumn is zero. It might
* be nonzero if we had softwrap mode on while in this buffer, and then
@@ -657,9 +619,6 @@ void switch_to_adjacent_buffer(bool to_next)
/* Update titlebar and multiline info to match the current buffer. */
prepare_for_display();
if (inhelp)
return;
/* Ensure that the main loop will redraw the help lines. */
currmenu = MMOST;
@@ -673,78 +632,46 @@ void switch_to_adjacent_buffer(bool to_next)
/* Switch to the previous entry in the list of open files. */
void switch_to_prev_buffer(void)
{
switch_to_adjacent_buffer(BACKWARD);
openfile = openfile->prev;
redecorate_after_switch();
}
/* Switch to the next entry in the list of open files. */
void switch_to_next_buffer(void)
{
switch_to_adjacent_buffer(FORWARD);
openfile = openfile->next;
redecorate_after_switch();
}
/* Delete an entry from the circular list of open files, and switch to the
* one after it. Return FALSE if just one buffer is open, otherwise TRUE. */
bool close_buffer(void)
/* Remove the current buffer from the circular list of buffers. */
void close_buffer(void)
{
if (openfile == openfile->next)
return FALSE;
openfilestruct *orphan = openfile;
#ifdef ENABLE_HISTORIES
if (ISSET(POSITIONLOG))
update_poshistory(openfile->filename,
openfile->current->lineno, xplustabs() + 1);
if (orphan == startfile)
startfile = startfile->next;
orphan->prev->next = orphan->next;
orphan->next->prev = orphan->prev;
free(orphan->filename);
free_lines(orphan->filetop);
#ifndef NANO_TINY
free(orphan->current_stat);
free(orphan->lock_filename);
/* Free the undo stack. */
discard_until(NULL, orphan, TRUE);
#endif
switch_to_next_buffer();
openfile = orphan->prev;
free(orphan);
/* Delete the old file buffer, and adjust the count in the top bar. */
unlink_opennode(openfile->prev);
if (!inhelp)
titlebar(NULL);
/* If now just one buffer remains open, show "Exit" in the help lines. */
/* When just one buffer remains open, show "Exit" in the help lines. */
if (openfile == openfile->next)
exitfunc->desc = exit_tag;
return TRUE;
}
#endif /* ENABLE_MULTIBUFFER */
/* Do a quick permissions check by verifying whether the file is appendable.
* Err on the side of permissiveness (reporting TRUE when it might be wrong)
* to not fluster users editing on odd filesystems by printing incorrect
* warnings. */
int is_file_writable(const char *filename)
{
char *full_filename;
struct stat fileinfo;
int fd;
FILE *f;
bool result = TRUE;
if (ISSET(VIEW_MODE))
return TRUE;
full_filename = get_full_path(filename);
/* If the absolute path is unusable, use the given relative one. */
if (full_filename == NULL || stat(full_filename, &fileinfo) == -1)
full_filename = mallocstrcpy(NULL, filename);
if ((fd = open(full_filename, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR |
S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) == -1)
result = FALSE;
else if ((f = fdopen(fd, "a")) == NULL) {
result = FALSE;
close(fd);
} else
fclose(f);
free(full_filename);
return result;
}
/* Encode any NUL bytes in the given line of text, which is of length buf_len,
* and return a dynamically allocated copy of the resultant string. */
char *encode_data(char *buf, size_t buf_len)
@@ -781,6 +708,8 @@ void read_file(FILE *f, int fd, const char *filename, bool undoable)
int input_int;
/* The current value we read from the file, whether an input
* character or EOF. */
int errornumber;
/* The error code, in case an error occurred during reading. */
bool writable = TRUE;
/* Whether the file is writable (in case we care). */
#ifndef NANO_TINY
@@ -810,8 +739,16 @@ void read_file(FILE *f, int fd, const char *filename, bool undoable)
* of locking it for each single byte that we read from it. */
flockfile(f);
control_C_was_pressed = FALSE;
/* Read the entire file into the new buffer. */
while ((input_int = getc_unlocked(f)) != EOF) {
if (control_C_was_pressed) {
statusline(ALERT, _("Interrupted"));
break;
}
input = (char)input_int;
/* If it's a *nix file ("\n") or a DOS file ("\r\n"), and file
@@ -878,6 +815,8 @@ void read_file(FILE *f, int fd, const char *filename, bool undoable)
#endif
}
errornumber = errno;
/* We are done with the file, unlock it. */
funlockfile(f);
@@ -885,13 +824,22 @@ void read_file(FILE *f, int fd, const char *filename, bool undoable)
block_sigwinch(FALSE);
#endif
/* Perhaps this could use some better handling. */
if (ferror(f))
nperror(filename);
/* When reading from stdin, restore the terminal and reenter curses mode. */
if (isendwin()) {
if (!isatty(STANDARD_INPUT))
reconnect_and_store_state();
terminal_init();
doupdate();
}
/* If there was a real error during the reading, let the user know. */
if (ferror(f) && errornumber != EINTR && errornumber != 0)
statusline(ALERT, strerror(errornumber));
fclose(f);
if (fd > 0 && !undoable) {
close(fd);
writable = is_file_writable(filename);
writable = (ISSET(VIEW_MODE) || access(filename, W_OK) == 0);
}
/* If the file ended with newline, or it was entirely empty, make the
@@ -935,10 +883,6 @@ void read_file(FILE *f, int fd, const char *filename, bool undoable)
/* Set the desired x position at the end of what was inserted. */
openfile->placewewant = xplustabs();
/* If we've read a help file, don't give any feedback. */
if (inhelp)
return;
if (!writable)
statusline(ALERT, _("File '%s' is unwritable"), filename);
#ifndef NANO_TINY
@@ -980,7 +924,7 @@ void read_file(FILE *f, int fd, const char *filename, bool undoable)
* "New File" if newfie is TRUE, and say "File not found" otherwise.
* Return -2 if we say "New File", -1 if the file isn't opened, and the
* obtained fd otherwise. *f is set to the opened file. */
int open_file(const char *filename, bool newfie, bool quiet, FILE **f)
int open_file(const char *filename, bool newfie, FILE **f)
{
struct stat fileinfo, fileinfo2;
int fd;
@@ -994,8 +938,7 @@ int open_file(const char *filename, bool newfie, bool quiet, FILE **f)
if (stat(full_filename, &fileinfo) == -1) {
if (newfie) {
if (!quiet)
statusbar(_("New File"));
statusbar(_("New File"));
free(full_filename);
return -2;
}
@@ -1005,30 +948,37 @@ int open_file(const char *filename, bool newfie, bool quiet, FILE **f)
return -1;
}
/* Don't open directories, character files, or block files. */
if (S_ISDIR(fileinfo.st_mode) || S_ISCHR(fileinfo.st_mode) ||
S_ISBLK(fileinfo.st_mode)) {
statusline(ALERT, S_ISDIR(fileinfo.st_mode) ?
_("\"%s\" is a directory") :
_("\"%s\" is a device file"), filename);
free(full_filename);
return -1;
}
#ifndef NANO_TINY
if (S_ISFIFO(fileinfo.st_mode))
statusbar(_("Reading from FIFO..."));
block_sigwinch(TRUE);
install_handler_for_Ctrl_C();
#endif
/* Try opening the file. */
fd = open(full_filename, O_RDONLY);
if (fd == -1)
statusline(ALERT, _("Error reading %s: %s"), filename, strerror(errno));
else {
#ifndef NANO_TINY
restore_handler_for_Ctrl_C();
block_sigwinch(FALSE);
#endif
if (fd == -1) {
if (errno == EINTR || errno == 0)
statusline(ALERT, _("Interrupted"));
else
statusline(ALERT, _("Error reading %s: %s"), filename, strerror(errno));
} else {
/* The file is A-OK. Associate a stream with it. */
*f = fdopen(fd, "rb");
if (*f == NULL) {
statusline(ALERT, _("Error reading %s: %s"), filename, strerror(errno));
close(fd);
} else if (!inhelp)
statusbar(_("Reading File"));
fd = -1;
} else
statusbar(_("Reading..."));
}
free(full_filename);
@@ -1076,7 +1026,7 @@ char *get_next_filename(const char *name, const char *suffix)
* the MULTIBUFFER flag is set. */
void do_insertfile(void)
{
int i;
int response;
const char *msg;
char *given = mallocstrcpy(NULL, "");
/* The last answer the user typed at the statusbar prompt. */
@@ -1121,30 +1071,30 @@ void do_insertfile(void)
present_path = mallocstrcpy(present_path, "./");
i = do_prompt(TRUE, TRUE,
response = do_prompt(TRUE, TRUE,
#ifndef NANO_TINY
execute ? MEXTCMD :
execute ? MEXTCMD :
#endif
MINSERTFILE, given,
MINSERTFILE, given,
#ifndef NANO_TINY
execute ? &execute_history :
execute ? &execute_history :
#endif
NULL, edit_refresh, msg,
NULL, edit_refresh, msg,
#ifdef ENABLE_OPERATINGDIR
operating_dir != NULL ? operating_dir :
operating_dir != NULL ? operating_dir :
#endif
"./");
"./");
/* If we're in multibuffer mode and the filename or command is
* blank, open a new buffer instead of canceling. */
if (i == -1 || (i == -2 && !ISSET(MULTIBUFFER))) {
if (response == -1 || (response == -2 && !ISSET(MULTIBUFFER))) {
statusbar(_("Cancelled"));
break;
} else {
ssize_t was_current_lineno = openfile->current->lineno;
size_t was_current_x = openfile->current_x;
#if !defined(NANO_TINY) || defined(ENABLE_BROWSER) || defined(ENABLE_MULTIBUFFER)
functionptrtype func = func_from_key(&i);
functionptrtype func = func_from_key(&response);
#endif
given = mallocstrcpy(given, answer);
@@ -1178,7 +1128,7 @@ void do_insertfile(void)
free(answer);
answer = chosen;
i = 0;
response = 0;
}
#endif
#ifndef NANO_TINY
@@ -1189,7 +1139,7 @@ void do_insertfile(void)
}
#endif
/* If we don't have a file yet, go back to the prompt. */
if (i != 0 && (!ISSET(MULTIBUFFER) || i != -2))
if (response != 0 && (!ISSET(MULTIBUFFER) || response != -2))
continue;
#ifndef NANO_TINY
@@ -1339,8 +1289,6 @@ char *get_full_path(const char *origpath)
/* If we didn't find one, then make sure the answer is in the format
* "d_here/d_there". */
if (last_slash == NULL) {
assert(!path_only);
d_there_file = d_there;
d_there = d_here;
} else {
@@ -1559,8 +1507,6 @@ int copy_file(FILE *inn, FILE *out, bool close_out)
size_t charsread;
int (*flush_out_fnc)(FILE *) = (close_out) ? fclose : fflush;
assert(inn != NULL && out != NULL && inn != out);
do {
charsread = fread(buf, sizeof(char), BUFSIZ, inn);
if (charsread == 0 && ferror(inn)) {
@@ -1609,10 +1555,8 @@ bool write_file(const char *name, FILE *f_open, bool tmp,
mode_t original_umask = 0;
/* Our umask, from when nano started. */
#ifndef NANO_TINY
bool realexists;
/* The result of stat(). TRUE if the file exists, FALSE
* otherwise. If name is a link that points nowhere, realexists
* is FALSE. */
bool isactualfile = FALSE;
/* TRUE when the file is non-temporary and exists, FALSE otherwise. */
#endif
struct stat st;
/* The status fields filled in by stat(). */
@@ -1646,21 +1590,20 @@ bool write_file(const char *name, FILE *f_open, bool tmp,
#ifndef NANO_TINY
/* Check whether the file (at the end of the symlink) exists. */
realexists = (stat(realname, &st) != -1);
if (!tmp)
isactualfile = (stat(realname, &st) != -1);
/* If we haven't stat()d this file before (say, the user just
* specified it interactively), stat and save the value now,
* or else we will chase null pointers when we do modtime checks,
* preserve file times, and so on, during backup. */
if (openfile->current_stat == NULL && !tmp && realexists)
/* If we haven't stat()d this file before (say, the user just specified
* it interactively), stat and save the value now, or else we will chase
* null pointers when we do modtime checks and such during backup. */
if (openfile->current_stat == NULL && isactualfile)
stat_with_alloc(realname, &openfile->current_stat);
/* We backup only if the backup toggle is set, the file isn't
* temporary, and the file already exists. Furthermore, if we
* aren't appending, prepending, or writing a selection, we backup
* only if the file has not been modified by someone else since nano
* opened it. */
if (ISSET(BACKUP_FILE) && !tmp && realexists && openfile->current_stat &&
/* We back up only if the backup toggle is set, and the file exists and
* isn't temporary. Furthermore, if we aren't appending, prepending, or
* writing a selection, we back up only if the file has not been modified
* by someone else since nano opened it. */
if (ISSET(BACKUP_FILE) && isactualfile && openfile->current_stat &&
(method != OVERWRITE || openfile->mark ||
openfile->current_stat->st_mtime == st.st_mtime)) {
static struct timespec filetime[2];
@@ -1787,10 +1730,6 @@ bool write_file(const char *name, FILE *f_open, bool tmp,
goto cleanup_and_exit;
}
#ifdef DEBUG
fprintf(stderr, "Backing up %s to %s\n", realname, backupname);
#endif
/* Copy the file. */
if (copy_file(f, backup_file, FALSE) != 0) {
fclose(backup_file);
@@ -1813,7 +1752,7 @@ bool write_file(const char *name, FILE *f_open, bool tmp,
free(backupname);
}
skip_backup:
skip_backup:
#endif /* !NANO_TINY */
if (f_open == NULL) {
@@ -1873,21 +1812,35 @@ bool write_file(const char *name, FILE *f_open, bool tmp,
goto cleanup_and_exit;
}
}
if (S_ISFIFO(st.st_mode))
statusbar(_("Writing to FIFO..."));
#endif /* !NANO_TINY */
if (f_open == NULL) {
#ifndef NANO_TINY
block_sigwinch(TRUE);
install_handler_for_Ctrl_C();
#endif
/* Now open the file in place. Use O_EXCL if tmp is TRUE. This
* is copied from joe, because wiggy says so *shrug*. */
fd = open(realname, O_WRONLY | O_CREAT | ((method == APPEND) ?
O_APPEND : (tmp ? O_EXCL : O_TRUNC)), S_IRUSR |
S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
#ifndef NANO_TINY
restore_handler_for_Ctrl_C();
block_sigwinch(FALSE);
#endif
/* Set the umask back to the user's original value. */
umask(original_umask);
/* If we couldn't open the file, give up. */
if (fd == -1) {
statusline(ALERT, _("Error writing %s: %s"), realname,
if (errno == EINTR || errno == 0)
statusline(ALERT, _("Interrupted"));
else
statusline(ALERT, _("Error writing %s: %s"), realname,
strerror(errno));
if (tempname != NULL)
unlink(tempname);
@@ -1904,6 +1857,9 @@ bool write_file(const char *name, FILE *f_open, bool tmp,
}
}
if (!tmp)
statusbar(_("Writing..."));
while (fileptr != NULL) {
size_t data_len = strlen(fileptr->data), size;
@@ -2058,9 +2014,9 @@ bool write_marked_file(const char *name, FILE *f_open, bool tmp,
size_t top_x, bot_x;
/* Partition the buffer so that it contains only the marked text. */
mark_order((const linestruct **)&top, &top_x,
get_region((const linestruct **)&top, &top_x,
(const linestruct **)&bot, &bot_x, NULL);
filepart = partition_buffer(top, top_x, bot, bot_x);
partition_buffer(top, top_x, bot, bot_x);
/* If we are using a magic line, and the last line of the partition
* isn't blank, then add a newline at the end of the buffer. */
@@ -2075,7 +2031,7 @@ bool write_marked_file(const char *name, FILE *f_open, bool tmp,
remove_magicline();
/* Unpartition the buffer so that it contains all the text again. */
unpartition_buffer(&filepart);
unpartition_buffer();
return retval;
}
@@ -2463,8 +2419,6 @@ char **username_tab_completion(const char *buf, size_t *num_matches,
const struct passwd *userdata;
#endif
assert(buf != NULL && num_matches != NULL && buf_len > 0);
*num_matches = 0;
#ifdef HAVE_PWD_H
@@ -2529,8 +2483,6 @@ char **cwd_tab_completion(const char *buf, bool allow_files,
dirname = mallocstrcpy(NULL, present_path);
}
assert(dirname[strlen(dirname) - 1] == '/');
dir = opendir(dirname);
if (dir == NULL) {
@@ -2594,9 +2546,6 @@ char *input_tab(char *buf, bool allow_files, size_t *place,
size_t num_matches = 0, buf_len;
char **matches = NULL;
assert(buf != NULL && place != NULL && *place <= strlen(buf) &&
lastwastab != NULL && refresh_func != NULL && listed != NULL);
*listed = FALSE;
/* If the word starts with `~' and there is no slash in the word,
@@ -2653,14 +2602,9 @@ char *input_tab(char *buf, bool allow_files, size_t *place,
glued = charalloc(strlen(present_path) + strlen(mzero) + 1);
sprintf(glued, "%s%s", present_path, mzero);
assert(common_len >= *place);
if (num_matches == 1 && (is_dir(mzero) || is_dir(glued))) {
if (num_matches == 1 && (is_dir(mzero) || is_dir(glued)))
mzero[common_len++] = '/';
assert(common_len > *place);
}
if (num_matches > 1 && (common_len != *place || !*lastwastab))
beep();

View File

@@ -31,10 +31,8 @@ volatile sig_atomic_t the_window_resized = FALSE;
/* Set to TRUE by the handler whenever a SIGWINCH occurs. */
#endif
#ifdef __linux__
bool on_a_vt;
/* Whether we're running on a Linux VT or on something else. */
#endif
bool on_a_vt = FALSE;
/* Whether we're running on a Linux console (a VT). */
bool meta_key;
/* Whether the current keystroke is a Meta key. */
@@ -46,6 +44,11 @@ bool focusing = TRUE;
bool as_an_at = TRUE;
/* Whether a 0x0A byte should be shown as a ^@ instead of a ^J. */
bool control_C_was_pressed = FALSE;
/* Whether Ctrl+C was pressed (when a keyboard interrupt is enabled). */
bool started_curses = FALSE;
bool suppress_cursorpos = FALSE;
/* Should we skip constant position display for current keystroke? */
@@ -123,8 +126,6 @@ linestruct *cutbottom = NULL;
bool keep_cutbuffer = FALSE;
/* Whether to add to the cutbuffer instead of clearing it first. */
partition *filepart = NULL;
/* The "partition" where we store a portion of the current file. */
openfilestruct *openfile = NULL;
/* The list of all open file buffers. */
#ifdef ENABLE_MULTIBUFFER
@@ -378,10 +379,6 @@ void add_to_funcs(void (*func)(void), int menus, const char *desc, const char *h
f->help = help;
f->blank_after = blank_after;
#endif
#ifdef DEBUG
fprintf(stderr, "Added func %ld (%s) for menus %x\n", (long)func, f->desc, menus);
#endif
}
/* Add a key combo to the shortcut list. */
@@ -413,10 +410,6 @@ void add_to_sclist(int menus, const char *scstring, const int keycode,
assign_keyinfo(s, scstring, keycode);
tailsc = s;
#ifdef DEBUG
fprintf(stderr, "Setting keycode to %d for shortcut \"%s\" in menus %x\n", s->keycode, scstring, s->menus);
#endif
}
/* Return the first shortcut in the list of shortcuts that
@@ -429,9 +422,6 @@ const keystruct *first_sc_for(int menu, void (*func)(void))
if ((s->menus & menu) && s->func == func)
return s;
#ifdef DEBUG
fprintf(stderr, "Whoops, returning null given func %ld in menu %x\n", (long)func, menu);
#endif
return NULL;
}
@@ -506,22 +496,6 @@ int keycode_from_string(const char *keystring)
return -1;
}
#ifdef DEBUG
void print_sclist(void)
{
keystruct *s;
const funcstruct *f;
for (s = sclist; s != NULL; s = s->next) {
f = sctofunc(s);
if (f)
fprintf(stderr, "Shortcut \"%s\", function: %s, menus %x\n", s->keystr, f->desc, f->menus);
else
fprintf(stderr, "Hmm, didn't find a func for \"%s\"\n", s->keystr);
}
}
#endif
/* These two tags are used elsewhere too, so they are global. */
/* TRANSLATORS: Try to keep the next two strings at most 10 characters. */
const char *exit_tag = N_("Exit");
@@ -722,23 +696,20 @@ void shortcut_init(void)
N_("Write Out"), WITHORSANS(writeout_gist), TOGETHER, NOVIEW);
#ifdef ENABLE_JUSTIFY
if (!ISSET(RESTRICTED)) {
#else
/* If we can't replace Insert with Justify, show Insert anyway, to
* keep the help items nicely paired also in restricted mode. */
if (TRUE) {
/* In restricted mode, replace Insert with Justify, when possible;
* otherwise, show Insert anyway, to keep the help items paired. */
if (!ISSET(RESTRICTED))
#endif
add_to_funcs(do_insertfile_void, MMAIN,
N_("Read File"), WITHORSANS(readfile_gist), BLANKAFTER,
/* We allow inserting files in view mode if multibuffer mode
* is switched on, so that we can view multiple files. */
* is available, so that the user can view multiple files. */
CAN_OPEN_OTHER_BUFFER);
} else {
#ifdef ENABLE_JUSTIFY
else
add_to_funcs(do_justify_void, MMAIN,
N_("Justify"), WITHORSANS(justify_gist), BLANKAFTER, NOVIEW);
#endif
}
#ifdef ENABLE_HELP
/* The description ("x") and blank_after (0) are irrelevant,
@@ -761,10 +732,10 @@ void shortcut_init(void)
N_("Refresh"), WITHORSANS(browserrefresh_gist), BLANKAFTER, VIEW);
#endif
add_to_funcs(do_cut_text_void, MMAIN,
add_to_funcs(cut_text, MMAIN,
N_("Cut Text"), WITHORSANS(cut_gist), TOGETHER, NOVIEW);
add_to_funcs(do_uncut_text, MMAIN,
add_to_funcs(paste_text, MMAIN,
N_("Paste Text"), WITHORSANS(uncut_gist), BLANKAFTER, NOVIEW);
if (!ISSET(RESTRICTED)) {
@@ -797,7 +768,7 @@ void shortcut_init(void)
add_to_funcs(do_mark, MMAIN,
N_("Mark Text"), WITHORSANS(mark_gist), TOGETHER, VIEW);
add_to_funcs(do_copy_text, MMAIN,
add_to_funcs(copy_text, MMAIN,
N_("Copy Text"), WITHORSANS(copy_gist), BLANKAFTER, NOVIEW);
#endif
@@ -952,7 +923,7 @@ void shortcut_init(void)
N_("Chop Left"), WITHORSANS(chopwordleft_gist), TOGETHER, NOVIEW);
add_to_funcs(chop_next_word, MMAIN,
N_("Chop Right"), WITHORSANS(chopwordright_gist), TOGETHER, NOVIEW);
add_to_funcs(do_cut_till_eof, MMAIN,
add_to_funcs(cut_till_eof, MMAIN,
N_("CutTillEnd"), WITHORSANS(cuttilleof_gist), BLANKAFTER, NOVIEW);
#endif
@@ -1114,8 +1085,8 @@ void shortcut_init(void)
add_to_sclist(MMAIN|MHELP|MBROWSER, "^W", 0, do_search_forward, 0);
add_to_sclist(MMAIN, "^\\", 0, do_replace, 0);
add_to_sclist(MMAIN, "M-R", 0, do_replace, 0);
add_to_sclist(MMOST, "^K", 0, do_cut_text_void, 0);
add_to_sclist(MMOST, "^U", 0, do_uncut_text, 0);
add_to_sclist(MMOST, "^K", 0, cut_text, 0);
add_to_sclist(MMOST, "^U", 0, paste_text, 0);
#ifdef ENABLE_JUSTIFY
add_to_sclist(MMAIN, "^J", 0, do_justify_void, 0);
#endif
@@ -1146,8 +1117,8 @@ void shortcut_init(void)
add_to_sclist(MMAIN, "M-A", 0, do_mark, 0);
add_to_sclist(MMAIN, "^6", 0, do_mark, 0);
add_to_sclist(MMAIN, "^^", 0, do_mark, 0);
add_to_sclist(MMAIN, "M-6", 0, do_copy_text, 0);
add_to_sclist(MMAIN, "M-^", 0, do_copy_text, 0);
add_to_sclist(MMAIN, "M-6", 0, copy_text, 0);
add_to_sclist(MMAIN, "M-^", 0, copy_text, 0);
add_to_sclist(MMAIN, "M-}", 0, do_indent, 0);
add_to_sclist(MMAIN, "Tab", TAB_CODE, do_indent, 0);
add_to_sclist(MMAIN, "M-{", 0, do_unindent, 0);
@@ -1174,11 +1145,11 @@ void shortcut_init(void)
add_to_sclist(MMOST|MHELP|MBROWSER, "\xE2\x96\xb6", KEY_RIGHT, do_right, 0);
add_to_sclist(MSOME, "^\xE2\x97\x80", CONTROL_LEFT, do_prev_word_void, 0);
add_to_sclist(MSOME, "^\xE2\x96\xb6", CONTROL_RIGHT, do_next_word_void, 0);
#ifndef NANO_TINY
#ifdef ENABLE_MULTIBUFFER
add_to_sclist(MMAIN, "M-\xE2\x97\x80", ALT_LEFT, switch_to_prev_buffer, 0);
add_to_sclist(MMAIN, "M-\xE2\x96\xb6", ALT_RIGHT, switch_to_next_buffer, 0);
#endif
#if !defined(NANO_TINY) && defined(ENABLE_MULTIBUFFER)
if (!on_a_vt) {
add_to_sclist(MMAIN, "M-\xE2\x97\x80", ALT_LEFT, switch_to_prev_buffer, 0);
add_to_sclist(MMAIN, "M-\xE2\x96\xb6", ALT_RIGHT, switch_to_next_buffer, 0);
}
#endif
} else
#endif
@@ -1187,6 +1158,12 @@ void shortcut_init(void)
add_to_sclist(MMOST|MHELP|MBROWSER, "Right", KEY_RIGHT, do_right, 0);
add_to_sclist(MSOME, "^Left", CONTROL_LEFT, do_prev_word_void, 0);
add_to_sclist(MSOME, "^Right", CONTROL_RIGHT, do_next_word_void, 0);
#ifdef ENABLE_MULTIBUFFER
if (!on_a_vt) {
add_to_sclist(MMAIN, "M-Left", ALT_LEFT, switch_to_prev_buffer, 0);
add_to_sclist(MMAIN, "M-Right", ALT_RIGHT, switch_to_next_buffer, 0);
}
#endif
}
#ifdef NANO_TINY
add_to_sclist(MMAIN, "M-B", 0, do_prev_word_void, 0);
@@ -1224,10 +1201,16 @@ void shortcut_init(void)
add_to_sclist(MMAIN, "M-)", 0, do_para_end_void, 0);
add_to_sclist(MMAIN, "M-0", 0, do_para_end_void, 0);
#endif
#if !defined(NANO_TINY) && defined(ENABLE_UTF8)
#ifndef NANO_TINY
#ifdef ENABLE_UTF8
if (using_utf8()) {
add_to_sclist(MMAIN|MHELP, "M-\xE2\x96\xb2", ALT_UP, do_scroll_up, 0);
add_to_sclist(MMAIN|MHELP, "M-\xE2\x96\xbc", ALT_DOWN, do_scroll_down, 0);
} else
#endif
{
add_to_sclist(MMAIN|MHELP, "M-Up", ALT_UP, do_scroll_up, 0);
add_to_sclist(MMAIN|MHELP, "M-Down", ALT_DOWN, do_scroll_down, 0);
}
#endif
#if !defined(NANO_TINY) || defined(ENABLE_HELP)
@@ -1244,7 +1227,7 @@ void shortcut_init(void)
#endif
add_to_sclist(MMOST, "M-V", 0, do_verbatim_input, 0);
#ifndef NANO_TINY
add_to_sclist(MMAIN, "M-T", 0, do_cut_till_eof, 0);
add_to_sclist(MMAIN, "M-T", 0, cut_till_eof, 0);
add_to_sclist(MMAIN, "M-D", 0, do_wordlinechar_count, 0);
#endif
#ifdef ENABLE_JUSTIFY
@@ -1383,26 +1366,12 @@ void shortcut_init(void)
add_to_sclist(MMAIN|MHELP|MBROWSER, "F6", 0, do_search_forward, 0);
add_to_sclist(MMAIN|MHELP|MBROWSER|MLINTER, "F7", 0, do_page_up, 0);
add_to_sclist(MMAIN|MHELP|MBROWSER|MLINTER, "F8", 0, do_page_down, 0);
add_to_sclist(MMOST, "F9", 0, do_cut_text_void, 0);
add_to_sclist(MMOST, "F10", 0, do_uncut_text, 0);
add_to_sclist(MMOST, "F9", 0, cut_text, 0);
add_to_sclist(MMOST, "F10", 0, paste_text, 0);
add_to_sclist(MMAIN, "F11", 0, do_cursorpos_void, 0);
#ifdef ENABLE_SPELLER
add_to_sclist(MMAIN, "F12", 0, do_spell, 0);
#endif
#ifdef DEBUG
print_sclist();
#endif
}
const funcstruct *sctofunc(const keystruct *s)
{
funcstruct *f = allfuncs;
while (f != NULL && f->func != s->func)
f = f->next;
return f;
}
#ifndef NANO_TINY
@@ -1483,14 +1452,14 @@ keystruct *strtosc(const char *input)
else if (!strcasecmp(input, "replace"))
s->func = do_replace;
else if (!strcasecmp(input, "cut"))
s->func = do_cut_text_void;
s->func = cut_text;
else if (!strcasecmp(input, "paste"))
s->func = do_uncut_text;
s->func = paste_text;
#ifndef NANO_TINY
else if (!strcasecmp(input, "cutrestoffile"))
s->func = do_cut_till_eof;
s->func = cut_till_eof;
else if (!strcasecmp(input, "copy"))
s->func = do_copy_text;
s->func = copy_text;
else if (!strcasecmp(input, "zap"))
s->func = zap_text;
else if (!strcasecmp(input, "mark"))

View File

@@ -39,45 +39,42 @@ static char *end_of_intro = NULL;
static size_t location;
/* The offset (in bytes) of the topleft of the shown help text. */
char *tempfilename = NULL;
/* Name of the temporary file used for wrapping the help text. */
/* Hard-wrap the help text, write it to the existing temporary file, and
* read that file into a new buffer. */
void wrap_the_help_text(bool redisplaying)
/* Hard-wrap the concatenated help text, and write it into a new buffer. */
void wrap_help_text_into_buffer()
{
size_t sum = 0;
const char *ptr = start_of_body;
FILE *tempfile = fopen(tempfilename, "w+b");
/* If re-opening the temporary file failed, give up. */
if (tempfile == NULL) {
statusline(ALERT, _("Error writing temp file: %s"), strerror(errno));
return;
}
make_new_buffer();
/* Write the body of the help_text into the temporary file. */
/* Copy the help text into the just-created new buffer. */
while (*ptr != '\0') {
int length = help_line_len(ptr);
char *oneline = nmalloc(length + 1);
snprintf(oneline, length + 1, "%s", ptr);
free(openfile->current->data);
openfile->current->data = oneline;
fwrite(ptr, sizeof(char), length, tempfile);
ptr += length;
/* Hard-wrap the lines in the help text. */
if (*ptr != '\n')
fwrite("\n", sizeof(char), 1, tempfile);
else while (*ptr == '\n')
fwrite(ptr++, sizeof(char), 1, tempfile);
ptr--;
/* Create a new line, and then one more for each extra \n. */
do {
openfile->current->next = make_new_node(openfile->current);
openfile->current = openfile->current->next;
openfile->current->data = mallocstrcpy(NULL, "");
} while (*(++ptr) == '\n');
}
fclose(tempfile);
openfile->filebot = openfile->current;
openfile->current = openfile->filetop;
if (redisplaying)
close_buffer();
open_buffer(tempfilename, TRUE);
remove_magicline();
#ifdef ENABLE_COLOR
color_update();
#endif
prepare_for_display();
/* Move to the position in the file where we were before. */
@@ -112,20 +109,9 @@ void do_help(void)
/* A storage place for the current flag settings. */
linestruct *line;
int length;
FILE *fp;
blank_statusbar();
/* Get a temporary file for the help text. If it fails, give up. */
tempfilename = safe_tempfile(&fp);
if (tempfilename == NULL) {
statusline(ALERT, _("Error writing temp file: %s"), strerror(errno));
free(saved_answer);
return;
}
fclose(fp);
/* Save the settings of all flags. */
memcpy(stash, flags, sizeof(flags));
@@ -175,7 +161,7 @@ void do_help(void)
while (*start_of_body == '\n')
start_of_body++;
wrap_the_help_text(FALSE);
wrap_help_text_into_buffer();
edit_refresh();
while (TRUE) {
@@ -210,19 +196,16 @@ void do_help(void)
} else if (func == (functionptrtype)implant) {
implant(first_sc_for(MHELP, func)->expansion);
#endif
#ifndef NANO_TINY
} else if (kbinput == KEY_WINCH) {
; /* Nothing to do. */
#endif
#ifdef ENABLE_MOUSE
} else if (kbinput == KEY_MOUSE) {
int dummy_row, dummy_col;
get_mouseinput(&dummy_row, &dummy_col, TRUE);
#endif
#ifndef NANO_TINY
} else if (kbinput == KEY_WINCH) {
; /* Nothing to do. */
#endif
} else if (func == do_exit) {
/* Exit from the help viewer. */
close_buffer();
curs_set(0);
break;
} else
unbound_key(kbinput);
@@ -240,6 +223,9 @@ void do_help(void)
}
}
/* Discard the help-text buffer. */
close_buffer();
/* Restore the settings of all flags. */
memcpy(flags, stash, sizeof(flags));
@@ -250,35 +236,33 @@ void do_help(void)
tabsize = was_tabsize;
#ifdef ENABLE_COLOR
syntaxstr = was_syntax;
have_palette = FALSE;
#endif
/* Switch back to the buffer we were invoked from. */
switch_to_prev_buffer();
free(title);
title = NULL;
free(answer);
answer = saved_answer;
free(help_text);
inhelp = FALSE;
curs_set(0);
refresh_needed = TRUE;
if (ISSET(NO_HELP)) {
currmenu = oldmenu;
window_init();
} else
} else {
wipe_statusbar();
bottombars(oldmenu);
free(title);
title = NULL;
inhelp = FALSE;
}
#ifdef ENABLE_BROWSER
if (oldmenu == MBROWSER || oldmenu == MWHEREISFILE || oldmenu == MGOTODIR)
browser_refresh();
else
#endif
total_refresh();
free(answer);
answer = saved_answer;
remove(tempfilename);
free(tempfilename);
free(help_text);
titlebar(NULL);
}
/* Allocate space for the help text for the current menu, and concatenate
@@ -464,22 +448,22 @@ void help_init(void)
allocsize += strlen(htx[2]);
/* Calculate the length of the shortcut help text. Each entry has
* one or two keys, which fill 16 columns, plus translated text,
* one or two keys, which fill 17 cells, plus translated text,
* plus one or two \n's. */
for (f = allfuncs; f != NULL; f = f->next)
if (f->menus & currmenu)
allocsize += (16 * MAXCHARLEN) + strlen(_(f->help)) + 2;
allocsize += strlen(_(f->help)) + 21;
#ifndef NANO_TINY
/* If we're on the main list, we also count the toggle help text.
* Each entry has "M-%c\t\t", five chars which fill 16 columns,
* plus a space, plus translated text, plus one or two '\n's. */
* Each entry has "M-%c\t\t ", six chars which fill 17 cells, plus
* two translated texts, plus a space, plus one or two '\n's. */
if (currmenu == MMAIN) {
size_t endis_len = strlen(_("enable/disable"));
size_t onoff_len = strlen(_("enable/disable"));
for (s = sclist; s != NULL; s = s->next)
if (s->func == do_toggle_void)
allocsize += strlen(_(flagtostr(s->toggle))) + endis_len + 8;
allocsize += strlen(_(flagtostr(s->toggle))) + onoff_len + 9;
}
#endif
@@ -493,40 +477,39 @@ void help_init(void)
if (htx[2] != NULL)
strcat(help_text, htx[2]);
ptr = help_text + strlen(help_text);
/* Remember this end-of-introduction, start-of-shortcuts. */
end_of_intro = ptr;
end_of_intro = help_text + strlen(help_text);
ptr = end_of_intro;
/* Now add our shortcut info. */
/* Now add the shortcuts and their descriptions. */
for (f = allfuncs; f != NULL; f = f->next) {
int tally = 0;
if ((f->menus & currmenu) == 0)
continue;
/* Let's simply show the first two shortcuts from the list. */
/* Show the first two shortcuts (if any) for each function. */
for (s = sclist; s != NULL; s = s->next) {
if ((s->menus & currmenu) && s->func == f->func) {
/* Make the first column narrower (6) than the second (10),
* but allow it to spill into the second, for "M-Space". */
/* Make the first column 7 cells wide and the second 10. */
if (++tally == 1) {
sprintf(ptr, "%s ", s->keystr);
sprintf(ptr, "%s ", s->keystr);
/* Unicode arrows take three bytes instead of one. */
ptr += (strstr(s->keystr, "\xE2") != NULL ? 8 : 6);
ptr += (strstr(s->keystr, "\xE2") != NULL ? 9 : 7);
} else {
ptr += sprintf(ptr, "(%s)\t", s->keystr);
sprintf(ptr, "(%s) ", s->keystr);
ptr += (strstr(s->keystr, "\xE2") != NULL ? 12 : 10);
break;
}
}
}
if (tally == 0)
ptr += sprintf(ptr, "\t\t");
ptr += sprintf(ptr, "\t\t ");
else if (tally == 1)
ptr += 10;
/* The shortcut's help text. */
/* The shortcut's description. */
ptr += sprintf(ptr, "%s\n", _(f->help));
if (f->blank_after)
@@ -547,7 +530,7 @@ void help_init(void)
counter++;
for (s = sclist; s != NULL; s = s->next)
if (s->toggle && s->ordinal == counter) {
ptr += sprintf(ptr, "%s\t\t%s %s\n", (s->menus == MMAIN ? s->keystr : ""),
ptr += sprintf(ptr, "%s\t\t %s %s\n", (s->menus == MMAIN ? s->keystr : ""),
_(flagtostr(s->toggle)), _("enable/disable"));
if (s->toggle == NO_COLOR_SYNTAX || s->toggle == TABS_TO_SPACES)
ptr += sprintf(ptr, "\n");
@@ -607,7 +590,7 @@ size_t help_line_len(const char *ptr)
/* Get the length of the entire line up to a null or a newline. */
while (*(ptr + length) != '\0' && *(ptr + length) != '\n')
length = move_mbright(ptr, length);
length = step_right(ptr, length);
/* If the entire line will just fit the screen, don't wrap it. */
if (wideness(ptr, length) <= wrapping_point + 1)

View File

@@ -119,7 +119,7 @@ void update_history(linestruct **item, const char *text)
*htop = after;
unlink_node(thesame);
renumber(after);
renumber_from(after);
}
/* If the history is full, delete the oldest item (the one at the
@@ -129,7 +129,7 @@ void update_history(linestruct **item, const char *text)
*htop = (*htop)->next;
unlink_node(oldest);
renumber(*htop);
renumber_from(*htop);
}
/* Store the fresh string in the last item, then create a new item. */
@@ -528,7 +528,7 @@ void update_poshistory(char *filename, ssize_t lineno, ssize_t xpos)
poshiststruct *posptr, *theone, *posprev = NULL;
char *fullpath = get_full_path(filename);
if (fullpath == NULL || fullpath[strlen(fullpath) - 1] == '/' || inhelp) {
if (fullpath == NULL || fullpath[strlen(fullpath) - 1] == '/') {
free(fullpath);
return;
}

View File

@@ -278,7 +278,7 @@ void do_prev_word(bool allow_punct)
}
/* Step back one character. */
openfile->current_x = move_mbleft(openfile->current->data,
openfile->current_x = step_left(openfile->current->data,
openfile->current_x);
if (is_word_mbchar(openfile->current->data + openfile->current_x,
@@ -296,7 +296,7 @@ void do_prev_word(bool allow_punct)
if (step_forward)
/* Move one character forward again to sit on the start of the word. */
openfile->current_x = move_mbright(openfile->current->data,
openfile->current_x = step_right(openfile->current->data,
openfile->current_x);
}
@@ -324,7 +324,7 @@ bool do_next_word(bool after_ends, bool allow_punct)
seen_space = TRUE;
} else {
/* Step forward one character. */
openfile->current_x = move_mbright(openfile->current->data,
openfile->current_x = step_right(openfile->current->data,
openfile->current_x);
}
@@ -570,7 +570,7 @@ void do_left(void)
linestruct *was_current = openfile->current;
if (openfile->current_x > 0)
openfile->current_x = move_mbleft(openfile->current->data,
openfile->current_x = step_left(openfile->current->data,
openfile->current_x);
else if (openfile->current != openfile->filetop) {
openfile->current = openfile->current->prev;
@@ -586,7 +586,7 @@ void do_right(void)
linestruct *was_current = openfile->current;
if (openfile->current->data[openfile->current_x] != '\0')
openfile->current_x = move_mbright(openfile->current->data,
openfile->current_x = step_right(openfile->current->data,
openfile->current_x);
else if (openfile->current != openfile->filebot) {
openfile->current = openfile->current->next;

File diff suppressed because it is too large Load Diff

View File

@@ -113,14 +113,11 @@
#define N_(string) gettext_noop(string)
/* Mark a string that will be sent to gettext() later. */
#include <stddef.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <regex.h>
#include <signal.h>
#include <assert.h>
#include <stdlib.h>
#include <sys/stat.h>
/* If we aren't using an ncurses with mouse support, exclude any
* mouse routines, as they are useless then. */
@@ -147,6 +144,8 @@
#define BAD_COLOR -2
#endif
#define STANDARD_INPUT 0
/* Enumeration types. */
typedef enum {
NIX_FILE, DOS_FILE, MAC_FILE
@@ -188,21 +187,14 @@ typedef struct colortype {
/* This syntax's foreground color. */
short bg;
/* This syntax's background color. */
int pairnum;
/* The color pair number used for this foreground color and
* background color. */
short pairnum;
/* The pair number for this foreground/background color combination. */
int attributes;
/* Pair number and brightness composed into ready-to-use attributes. */
int rex_flags;
/* The regex compilation flags (with or without REG_ICASE). */
char *start_regex;
/* The start (or all) of the regex string. */
regex_t *start;
/* The compiled start (or all) of the regex string. */
char *end_regex;
/* The end (if any) of the regex string. */
/* The compiled regular expression for 'start=', or the only one. */
regex_t *end;
/* The compiled end (if any) of the regex string. */
/* The compiled regular expression for 'end=', if any. */
struct colortype *next;
/* Next set of colors. */
int id;
@@ -216,9 +208,26 @@ typedef struct regexlisttype {
/* The next regex. */
} regexlisttype;
typedef struct augmentstruct {
char *filename;
/* The file where the syntax is extended. */
ssize_t lineno;
/* The number of the line of the extendsyntax command. */
char *data;
/* The text of the line. */
struct augmentstruct *next;
/* Next node. */
} augmentstruct;
typedef struct syntaxtype {
char *name;
/* The name of this syntax. */
char *filename;
/* File where the syntax is defined, or NULL if not an included file. */
size_t lineno;
/* The line number where the 'syntax' command was found. */
struct augmentstruct *augmentations;
/* List of extendsyntax commands to apply when loaded. */
regexlisttype *extensions;
/* The list of extensions that this syntax applies to. */
regexlisttype *headers;
@@ -285,24 +294,6 @@ typedef struct linestruct {
#endif
} linestruct;
typedef struct partition {
linestruct *filetop;
/* The top line of this portion of the file. */
linestruct *top_prev;
/* The line before the top line of this portion of the file. */
char *top_data;
/* The text before the beginning of the top line of this portion
* of the file. */
linestruct *filebot;
/* The bottom line of this portion of the file. */
linestruct *bot_next;
/* The line after the bottom line of this portion of the
* file. */
char *bot_data;
/* The text after the end of the bottom line of this portion of
* the file. */
} partition;
#ifndef NANO_TINY
typedef struct undo_group {
ssize_t top_line;
@@ -330,12 +321,8 @@ typedef struct undo {
/* Some flag data we need. */
undo_group *grouping;
/* Undo info specific to groups of lines. */
/* Cut-specific stuff we need. */
linestruct *cutbuffer;
/* Copy of the cutbuffer. */
linestruct *cutbottom;
/* Copy of cutbottom. */
ssize_t mark_begin_lineno;
/* Mostly the line number of the current line; sometimes something else. */
size_t mark_begin_x;

View File

@@ -150,8 +150,8 @@ int do_statusbar_input(bool *finished)
else if (ISSET(RESTRICTED) && currmenu == MWRITEFILE &&
openfile->filename[0] != '\0' &&
(shortcut->func == do_verbatim_input ||
shortcut->func == do_cut_text_void ||
shortcut->func == do_uncut_text ||
shortcut->func == cut_text ||
shortcut->func == paste_text ||
shortcut->func == do_delete ||
shortcut->func == do_backspace))
;
@@ -161,13 +161,13 @@ int do_statusbar_input(bool *finished)
#endif
else if (shortcut->func == do_verbatim_input)
do_statusbar_verbatim_input();
else if (shortcut->func == do_cut_text_void)
else if (shortcut->func == cut_text)
do_statusbar_cut_text();
else if (shortcut->func == do_delete)
do_statusbar_delete();
else if (shortcut->func == do_backspace)
do_statusbar_backspace();
else if (shortcut->func == do_uncut_text) {
else if (shortcut->func == paste_text) {
if (cutbuffer != NULL)
do_statusbar_uncut_text();
} else {
@@ -190,7 +190,7 @@ void do_statusbar_output(int *the_input, size_t input_len,
{
char *output = charalloc(input_len + 1);
char onechar[MAXCHARLEN];
size_t char_len, i, j = 0;
size_t charlen, i, j = 0;
/* Copy the typed stuff so it can be treated. */
for (i = 0; i < input_len; i++)
@@ -203,21 +203,21 @@ void do_statusbar_output(int *the_input, size_t input_len,
output[j] = '\n';
/* Interpret the next multibyte character. */
char_len = parse_mbchar(output + j, onechar, NULL);
charlen = parse_mbchar(output + j, onechar, NULL);
j += char_len;
j += charlen;
/* When filtering, skip any ASCII control character. */
if (filtering && is_ascii_cntrl_char(*(output + j - char_len)))
if (filtering && is_ascii_cntrl_char(*(output + j - charlen)))
continue;
/* Insert the typed character into the existing answer string. */
answer = charealloc(answer, strlen(answer) + char_len + 1);
charmove(answer + typing_x + char_len, answer + typing_x,
answer = charealloc(answer, strlen(answer) + charlen + 1);
charmove(answer + typing_x + charlen, answer + typing_x,
strlen(answer) - typing_x + 1);
strncpy(answer + typing_x, onechar, char_len);
strncpy(answer + typing_x, onechar, charlen);
typing_x += char_len;
typing_x += charlen;
}
free(output);
@@ -239,24 +239,24 @@ void do_statusbar_end(void)
void do_statusbar_left(void)
{
if (typing_x > 0)
typing_x = move_mbleft(answer, typing_x);
typing_x = step_left(answer, typing_x);
}
/* Move right one character. */
void do_statusbar_right(void)
{
if (answer[typing_x] != '\0')
typing_x = move_mbright(answer, typing_x);
typing_x = step_right(answer, typing_x);
}
/* Delete one character. */
void do_statusbar_delete(void)
{
if (answer[typing_x] != '\0') {
int char_len = parse_mbchar(answer + typing_x, NULL, NULL);
int charlen = char_length(answer + typing_x);
charmove(answer + typing_x, answer + typing_x + char_len,
strlen(answer) - typing_x - char_len + 1);
charmove(answer + typing_x, answer + typing_x + charlen,
strlen(answer) - typing_x - charlen + 1);
}
}
@@ -264,7 +264,7 @@ void do_statusbar_delete(void)
void do_statusbar_backspace(void)
{
if (typing_x > 0) {
typing_x = move_mbleft(answer, typing_x);
typing_x = step_left(answer, typing_x);
do_statusbar_delete();
}
}
@@ -288,7 +288,7 @@ void do_statusbar_next_word(void)
/* Move forward until we reach either the end or the start of a word,
* depending on whether the AFTER_ENDS flag is set or not. */
while (answer[typing_x] != '\0') {
typing_x = move_mbright(answer, typing_x);
typing_x = step_right(answer, typing_x);
if (ISSET(AFTER_ENDS)) {
/* If this is a word character, continue; else it's a separator,
@@ -315,7 +315,7 @@ void do_statusbar_prev_word(void)
/* Move backward until we pass over the start of a word. */
while (typing_x != 0) {
typing_x = move_mbleft(answer, typing_x);
typing_x = step_left(answer, typing_x);
if (is_word_mbchar(answer + typing_x, FALSE))
seen_a_word = TRUE;
@@ -328,7 +328,7 @@ void do_statusbar_prev_word(void)
if (step_forward)
/* Move one character forward again to sit on the start of the word. */
typing_x = move_mbright(answer, typing_x);
typing_x = step_right(answer, typing_x);
}
#endif /* !NANO_TINY */
@@ -738,6 +738,12 @@ int do_yesno_prompt(bool all, const char *msg)
choice = 2;
else if (func_from_key(&kbinput) == do_cancel)
choice = -1;
/* Interpret ^N and ^Q as "No", to allow exiting in anger. */
else if (kbinput == '\x0E' || kbinput == '\x11')
choice = 0;
/* And interpret ^Y as "Yes". */
else if (kbinput == '\x19')
choice = 1;
#ifdef ENABLE_MOUSE
else if (kbinput == KEY_MOUSE) {
int mouse_x, mouse_y;

View File

@@ -29,9 +29,7 @@
extern volatile sig_atomic_t the_window_resized;
#endif
#ifdef __linux__
extern bool on_a_vt;
#endif
extern bool meta_key;
extern bool shift_held;
@@ -40,8 +38,12 @@ extern bool focusing;
extern bool as_an_at;
extern bool control_C_was_pressed;
extern bool suppress_cursorpos;
extern bool started_curses;
extern message_type lastmessage;
extern linestruct *pletion_line;
@@ -96,7 +98,6 @@ extern linestruct *cutbuffer;
extern linestruct *cutbottom;
extern bool keep_cutbuffer;
extern partition *filepart;
extern openfilestruct *openfile;
#ifdef ENABLE_MULTIBUFFER
extern openfilestruct *startfile;
@@ -209,12 +210,12 @@ bool is_ascii_cntrl_char(int c);
bool is_cntrl_mbchar(const char *c);
bool is_word_mbchar(const char *c, bool allow_punct);
char control_mbrep(const char *c, bool isdata);
int length_of_char(const char *c, int *width);
int mbwidth(const char *c);
char *make_mbchar(long chr, int *chr_mb_len);
int char_length(const char *pointer);
int parse_mbchar(const char *buf, char *chr, size_t *col);
size_t move_mbleft(const char *buf, size_t pos);
size_t move_mbright(const char *buf, size_t pos);
size_t step_left(const char *buf, size_t pos);
size_t step_right(const char *buf, size_t pos);
int mbstrcasecmp(const char *s1, const char *s2);
int mbstrncasecmp(const char *s1, const char *s2, size_t n);
char *mbstrcasestr(const char *haystack, const char *needle);
@@ -254,35 +255,32 @@ void chop_previous_word(void);
void chop_next_word(void);
void cut_marked(bool *right_side_up);
#endif
void do_cut_text(bool copy_text, bool marked, bool cut_till_eof, bool append);
void do_cut_text(bool copying, bool marked, bool until_eof, bool append);
bool is_cuttable(bool test_cliff);
void do_cut_text_void(void);
void cut_text(void);
#ifndef NANO_TINY
void do_copy_text(void);
void do_cut_till_eof(void);
void copy_text(void);
void cut_till_eof(void);
void zap_text(void);
#endif
void do_uncut_text(void);
void paste_text(void);
/* Most functions in files.c. */
void initialize_buffer_text(void);
void make_new_buffer(void);
void set_modified(void);
bool open_buffer(const char *filename, bool new_buffer);
#ifdef ENABLE_SPELLER
void replace_buffer(const char *filename);
#ifndef NANO_TINY
void replace_marked_buffer(const char *filename);
#endif
bool replace_buffer(const char *filename, undo_type action, bool marked);
#endif
void prepare_for_display(void);
#ifdef ENABLE_MULTIBUFFER
void mention_name_and_linecount(void);
void switch_to_prev_buffer(void);
void switch_to_next_buffer(void);
bool close_buffer(void);
void close_buffer(void);
#endif
void read_file(FILE *f, int fd, const char *filename, bool undoable);
int open_file(const char *filename, bool newfie, bool quiet, FILE **f);
int open_file(const char *filename, bool newfie, FILE **f);
char *get_next_filename(const char *name, const char *suffix);
void do_insertfile_void(void);
char *get_full_path(const char *origpath);
@@ -322,9 +320,7 @@ int the_code_for(void (*func)(void), int defaultval);
functionptrtype func_from_key(int *kbinput);
int keycode_from_string(const char *keystring);
void assign_keyinfo(keystruct *s, const char *keystring, const int keycode);
void print_sclist(void);
void shortcut_init(void);
const funcstruct *sctofunc(const keystruct *s);
const char *flagtostr(int flag);
#ifdef ENABLE_NANORC
keystruct *strtosc(const char *input);
@@ -334,7 +330,7 @@ char *menu_to_name(int menu);
/* All functions in help.c. */
#ifdef ENABLE_HELP
void wrap_the_help_text(bool redisplaying);
void wrap_help_text_into_buffer();
void do_help(void);
void help_init(void);
functionptrtype parse_help_input(int *kbinput);
@@ -397,18 +393,13 @@ void unlink_node(linestruct *fileptr);
void delete_node(linestruct *fileptr);
linestruct *copy_buffer(const linestruct *src);
void free_lines(linestruct *src);
void renumber(linestruct *line);
partition *partition_buffer(linestruct *top, size_t top_x,
void renumber_from(linestruct *line);
void partition_buffer(linestruct *top, size_t top_x,
linestruct *bot, size_t bot_x);
void unpartition_buffer(partition **p);
void extract_buffer(linestruct **file_top, linestruct **file_bot,
linestruct *top, size_t top_x, linestruct *bot, size_t bot_x);
void unpartition_buffer();
void extract(linestruct *top, size_t top_x, linestruct *bot, size_t bot_x);
void ingraft_buffer(linestruct *somebuffer);
void copy_from_buffer(linestruct *somebuffer);
#ifdef ENABLE_MULTIBUFFER
void unlink_opennode(openfilestruct *fileptr);
void delete_opennode(openfilestruct *fileptr);
#endif
void print_view_warning(void);
void show_restricted_warning(void);
#ifndef ENABLE_HELP
@@ -420,6 +411,9 @@ void emergency_save(const char *die_filename, struct stat *die_stat);
void window_init(void);
void do_exit(void);
void close_and_go(void);
void install_handler_for_Ctrl_C(void);
void restore_handler_for_Ctrl_C(void);
void reconnect_and_store_state(void);
RETSIGTYPE handle_hupterm(int signal);
#ifndef DEBUG
RETSIGTYPE handle_crash(int signal);
@@ -433,8 +427,9 @@ void block_sigwinch(bool blockit);
RETSIGTYPE handle_sigwinch(int signal);
void regenerate_screen(void);
void do_toggle(int flag);
void enable_signals(void);
#endif
void disable_kb_interrupt(void);
void enable_kb_interrupt(void);
void disable_flow_control(void);
void enable_flow_control(void);
void terminal_init(void);
@@ -470,15 +465,17 @@ int do_yesno_prompt(bool all, const char *msg);
/* Most functions in rcfile.c. */
#ifdef ENABLE_NANORC
void display_rcfile_errors();
#ifdef ENABLE_COLOR
void parse_one_include(char *file, syntaxtype *syntax);
void grab_and_store(const char *kind, char *ptr, regexlisttype **storage);
bool parse_syntax_commands(char *keyword, char *ptr);
#endif
void parse_rcfile(FILE *rcstream, bool syntax_only);
void parse_rcfile(FILE *rcstream, bool just_syntax, bool intros_only);
void do_rcfiles(void);
#endif /* ENABLE_NANORC */
/* Most functions in search.c. */
void tidy_up_after_search(void);
int findnextstr(const char *needle, bool whole_word_only, int modus,
size_t *match_len, bool skipone, const linestruct *begin, size_t begin_x);
void do_search(void);
@@ -571,7 +568,6 @@ bool is_separate_word(size_t position, size_t length, const char *buf);
#endif
const char *strstrwrapper(const char *haystack, const char *needle,
const char *start);
void nperror(const char *s);
void *nmalloc(size_t howmuch);
void *nrealloc(void *ptr, size_t howmuch);
char *mallocstrncpy(char *dest, const char *src, size_t n);
@@ -587,13 +583,13 @@ void new_magicline(void);
void remove_magicline(void);
#endif
#ifndef NANO_TINY
void mark_order(const linestruct **top, size_t *top_x,
void get_region(const linestruct **top, size_t *top_x,
const linestruct **bot, size_t *bot_x, bool *right_side_up);
void get_range(const linestruct **top, const linestruct **bot);
#endif
size_t get_totsize(const linestruct *begin, const linestruct *end);
#ifndef NANO_TINY
linestruct *fsfromline(ssize_t lineno);
linestruct *line_from_number(ssize_t lineno);
#endif
/* Most functions in winio.c. */

View File

@@ -3,6 +3,7 @@
* *
* Copyright (C) 2001-2011, 2013-2019 Free Software Foundation, Inc. *
* Copyright (C) 2014 Mike Frysinger *
* Copyright (C) 2019 Brand Huntsman *
* Copyright (C) 2014-2019 Benno Schulenberg *
* *
* GNU nano is free software: you can redistribute it and/or modify *
@@ -140,30 +141,54 @@ static bool opensyntax = FALSE;
* or when a new syntax command is seen, this bool becomes FALSE. */
static syntaxtype *live_syntax;
/* The syntax that is currently being parsed. */
static bool seen_color_command = FALSE;
/* Whether a syntax definition contains any color commands. */
static colortype *lastcolor = NULL;
/* The end of the color list for the current syntax. */
#endif
/* Report an error in an rcfile, printing it to stderr. */
void rcfile_error(const char *msg, ...)
static linestruct *errors_head = NULL;
static linestruct *errors_tail = NULL;
/* Beginning and end of a list of errors in rcfiles, if any. */
/* Send the gathered error messages (if any) to the terminal. */
void display_rcfile_errors()
{
for (linestruct *error = errors_head; error != NULL; error = error->next)
fprintf(stderr, "%s\n", error->data);
}
#define MAXSIZE (PATH_MAX + 200)
/* Store the given error message in a linked list, to be printed upon exit. */
void jot_error(const char *msg, ...)
{
linestruct *error = make_new_node(errors_tail);
char textbuf[MAXSIZE];
int length = 0;
va_list ap;
if (errors_head == NULL)
errors_head = error;
else
errors_tail->next = error;
errors_tail = error;
if (rcfile_with_errors == NULL)
rcfile_with_errors = strdup(nanorc);
if (lineno > 0)
fprintf(stderr, _("Error in %s on line %zu: "), nanorc, lineno);
length = snprintf(textbuf, MAXSIZE, _("Error in %s on line %zu: "),
nanorc, lineno);
va_start(ap, msg);
vfprintf(stderr, _(msg), ap);
length += vsnprintf(textbuf + length, MAXSIZE - length, _(msg), ap);
va_end(ap);
fprintf(stderr, "\n");
error->data = nmalloc(length + 1);
sprintf(error->data, "%s", textbuf);
}
#endif /* ENABLE_NANORC */
#if defined(ENABLE_NANORC) || defined(ENABLE_HISTORIES)
/* Parse the next word from the string, null-terminate it, and return
* a pointer to the first character after the null terminator. The
* returned pointer will point to '\0' if we hit the end of the line. */
@@ -183,9 +208,7 @@ char *parse_next_word(char *ptr)
return ptr;
}
#endif /* ENABLE_NANORC || ENABLE_HISTORIES */
#ifdef ENABLE_NANORC
/* Parse an argument, with optional quotes, after a keyword that takes
* one. If the next word starts with a ", we say that it ends with the
* last " of the line. Otherwise, we interpret it as usual, so that the
@@ -204,7 +227,7 @@ char *parse_argument(char *ptr)
}
if (last_quote == NULL) {
rcfile_error(N_("Argument '%s' has an unterminated \""), ptr_save);
jot_error(N_("Argument '%s' has an unterminated \""), ptr_save);
return NULL;
}
@@ -229,7 +252,7 @@ char *parse_next_regex(char *ptr)
ptr++;
if (*ptr == '\0') {
rcfile_error(N_("Regex strings must begin and end with a \" character"));
jot_error(N_("Regex strings must begin and end with a \" character"));
return NULL;
}
@@ -242,38 +265,41 @@ char *parse_next_regex(char *ptr)
return ptr;
}
/* Compile the regular expression regex to see if it's valid. Return
* TRUE if it is, and FALSE otherwise. */
bool nregcomp(const char *regex, int compile_flags)
/* Compile the given regular expression and store the result in packed (when
* this pointer is not NULL). Return TRUE when the expression is valid. */
bool compile(const char *expression, int rex_flags, regex_t **packed)
{
regex_t preg;
int rc = regcomp(&preg, regex, compile_flags);
regex_t *compiled = nmalloc(sizeof(regex_t));
int outcome = regcomp(compiled, expression, rex_flags);
if (rc != 0) {
size_t len = regerror(rc, &preg, NULL, 0);
char *str = charalloc(len);
if (outcome != 0) {
size_t length = regerror(outcome, compiled, NULL, 0);
char *message = charalloc(length);
regerror(rc, &preg, str, len);
rcfile_error(N_("Bad regex \"%s\": %s"), regex, str);
free(str);
regerror(outcome, compiled, message, length);
jot_error(N_("Bad regex \"%s\": %s"), expression, message);
free(message);
}
regfree(&preg);
return (rc == 0);
if (packed == NULL || outcome != 0) {
regfree(compiled);
free(compiled);
} else
*packed = compiled;
return (outcome == 0);
}
/* Parse the next syntax name and its possible extension regexes from the
* line at ptr, and add it to the global linked list of color syntaxes. */
void parse_syntax(char *ptr)
void begin_new_syntax(char *ptr)
{
char *nameptr = ptr;
opensyntax = FALSE;
/* Check that the syntax name is not empty. */
if (*ptr == '\0' || (*ptr == '"' &&
(*(ptr + 1) == '\0' || *(ptr + 1) == '"'))) {
rcfile_error(N_("Missing syntax name"));
jot_error(N_("Missing syntax name"));
return;
}
@@ -281,7 +307,7 @@ void parse_syntax(char *ptr)
/* Check that quotes around the name are either paired or absent. */
if ((*nameptr == '\x22') ^ (nameptr[strlen(nameptr) - 1] == '\x22')) {
rcfile_error(N_("Unpaired quote in syntax name"));
jot_error(N_("Unpaired quote in syntax name"));
return;
}
@@ -293,13 +319,16 @@ void parse_syntax(char *ptr)
/* Redefining the "none" syntax is not allowed. */
if (strcmp(nameptr, "none") == 0) {
rcfile_error(N_("The \"none\" syntax is reserved"));
jot_error(N_("The \"none\" syntax is reserved"));
return;
}
/* Initialize a new syntax struct. */
live_syntax = (syntaxtype *)nmalloc(sizeof(syntaxtype));
live_syntax->name = mallocstrcpy(NULL, nameptr);
live_syntax->filename = strdup(nanorc);
live_syntax->lineno = lineno;
live_syntax->augmentations = NULL;
live_syntax->extensions = NULL;
live_syntax->headers = NULL;
live_syntax->magics = NULL;
@@ -308,7 +337,6 @@ void parse_syntax(char *ptr)
live_syntax->comment = mallocstrcpy(NULL, GENERAL_COMMENT_CHARACTER);
#endif
live_syntax->color = NULL;
lastcolor = NULL;
live_syntax->nmultis = 0;
/* Hook the new syntax in at the top of the list. */
@@ -316,10 +344,11 @@ void parse_syntax(char *ptr)
syntaxes = live_syntax;
opensyntax = TRUE;
seen_color_command = FALSE;
/* The default syntax should have no associated extensions. */
if (strcmp(live_syntax->name, "default") == 0 && *ptr != '\0') {
rcfile_error(N_("The \"default\" syntax does not accept extensions"));
jot_error(N_("The \"default\" syntax does not accept extensions"));
return;
}
@@ -329,6 +358,17 @@ void parse_syntax(char *ptr)
}
#endif /* ENABLE_COLOR */
/* Verify that a syntax definition contains at least one color command. */
void check_for_nonempty_syntax(void)
{
#ifdef ENABLE_COLOR
if (opensyntax && !seen_color_command)
jot_error(N_("Syntax \"%s\" has no color commands"), live_syntax->name);
opensyntax = FALSE;
#endif
}
/* Return TRUE when the given function is present in almost all menus. */
bool is_universal(void (*func)(void))
{
@@ -338,7 +378,7 @@ bool is_universal(void (*func)(void))
func == do_prev_word_void || func == do_next_word_void ||
#endif
func == do_delete || func == do_backspace ||
func == do_cut_text_void || func == do_uncut_text ||
func == cut_text || func == paste_text ||
func == do_tab || func == do_enter || func == do_verbatim_input);
}
@@ -350,8 +390,10 @@ void parse_binding(char *ptr, bool dobind)
int menu, mask = 0;
funcstruct *f;
check_for_nonempty_syntax();
if (*ptr == '\0') {
rcfile_error(N_("Missing key name"));
jot_error(N_("Missing key name"));
return;
}
@@ -360,7 +402,7 @@ void parse_binding(char *ptr, bool dobind)
keycopy = mallocstrcpy(NULL, keyptr);
if (strlen(keycopy) < 2) {
rcfile_error(N_("Key name is too short"));
jot_error(N_("Key name is too short"));
goto free_things;
}
@@ -371,7 +413,7 @@ void parse_binding(char *ptr, bool dobind)
if (strlen(keycopy) > 2)
keycopy[2] = toupper((unsigned char)keycopy[2]);
else {
rcfile_error(N_("Key name is too short"));
jot_error(N_("Key name is too short"));
goto free_things;
}
}
@@ -381,10 +423,10 @@ void parse_binding(char *ptr, bool dobind)
if (!strcasecmp(keycopy, "Ins") || !strcasecmp(keycopy, "Del"))
keycopy[1] = tolower((unsigned char)keycopy[1]);
else if (keycopy[0] != '^' && keycopy[0] != 'M' && keycopy[0] != 'F') {
rcfile_error(N_("Key name must begin with \"^\", \"M\", or \"F\""));
jot_error(N_("Key name must begin with \"^\", \"M\", or \"F\""));
goto free_things;
} else if (keycode_from_string(keycopy) < 0) {
rcfile_error(N_("Key name %s is invalid"), keycopy);
jot_error(N_("Key name %s is invalid"), keycopy);
goto free_things;
}
@@ -393,7 +435,7 @@ void parse_binding(char *ptr, bool dobind)
ptr = parse_argument(ptr);
if (funcptr[0] == '\0') {
rcfile_error(N_("Must specify a function to bind the key to"));
jot_error(N_("Must specify a function to bind the key to"));
goto free_things;
} else if (ptr == NULL)
goto free_things;
@@ -404,7 +446,8 @@ void parse_binding(char *ptr, bool dobind)
if (menuptr[0] == '\0') {
/* TRANSLATORS: Do not translate the word "all". */
rcfile_error(N_("Must specify a menu (or \"all\") in which to bind/unbind the key"));
jot_error(N_("Must specify a menu (or \"all\") "
"in which to bind/unbind the key"));
goto free_things;
}
@@ -422,14 +465,14 @@ void parse_binding(char *ptr, bool dobind)
newsc = strtosc(funcptr);
if (newsc == NULL) {
rcfile_error(N_("Cannot map name \"%s\" to a function"), funcptr);
jot_error(N_("Cannot map name \"%s\" to a function"), funcptr);
goto free_things;
}
}
menu = name_to_menu(menuptr);
if (menu < 1) {
rcfile_error(N_("Cannot map name \"%s\" to a menu"), menuptr);
jot_error(N_("Cannot map name \"%s\" to a menu"), menuptr);
goto free_things;
}
@@ -462,7 +505,7 @@ void parse_binding(char *ptr, bool dobind)
if (!menu) {
if (!ISSET(RESTRICTED) && !ISSET(VIEW_MODE))
rcfile_error(N_("Function '%s' does not exist in menu '%s'"),
jot_error(N_("Function '%s' does not exist in menu '%s'"),
funcptr, menuptr);
goto free_things;
}
@@ -473,7 +516,7 @@ void parse_binding(char *ptr, bool dobind)
/* Disallow rebinding ^[ and frequent escape-sequence starter "Esc [". */
if ((!newsc->meta && newsc->keycode == ESC_CODE) ||
(newsc->meta && newsc->keycode == '[')) {
rcfile_error(N_("Keystroke %s may not be rebound"), keycopy);
jot_error(N_("Keystroke %s may not be rebound"), keycopy);
free_things:
free(keycopy);
free(newsc);
@@ -506,8 +549,8 @@ bool is_good_file(char *file)
/* If the thing exists, it may be neither a directory nor a device. */
if (stat(file, &rcinfo) != -1 && (S_ISDIR(rcinfo.st_mode) ||
S_ISCHR(rcinfo.st_mode) || S_ISBLK(rcinfo.st_mode))) {
rcfile_error(S_ISDIR(rcinfo.st_mode) ? _("\"%s\" is a directory") :
_("\"%s\" is a device file"), file);
jot_error(S_ISDIR(rcinfo.st_mode) ? N_("\"%s\" is a directory") :
N_("\"%s\" is a device file"), file);
return FALSE;
} else
return TRUE;
@@ -515,8 +558,9 @@ bool is_good_file(char *file)
#ifdef ENABLE_COLOR
/* Read and parse one included syntax file. */
static void parse_one_include(char *file)
void parse_one_include(char *file, syntaxtype *syntax)
{
augmentstruct *extra;
FILE *rcstream;
/* Don't open directories, character files, or block files. */
@@ -527,7 +571,7 @@ static void parse_one_include(char *file)
rcstream = fopen(file, "rb");
if (rcstream == NULL) {
rcfile_error(_("Error reading %s: %s"), file, strerror(errno));
jot_error(N_("Error reading %s: %s"), file, strerror(errno));
return;
}
@@ -536,7 +580,36 @@ static void parse_one_include(char *file)
nanorc = file;
lineno = 0;
parse_rcfile(rcstream, TRUE);
/* If this is the first pass, parse only the prologue. */
if (syntax == NULL) {
parse_rcfile(rcstream, TRUE, TRUE);
return;
}
live_syntax = syntax;
lastcolor = NULL;
/* Fully parse the given syntax (as it is about to be used). */
parse_rcfile(rcstream, TRUE, FALSE);
extra = syntax->augmentations;
/* Apply any stored extendsyntax commands. */
while (extra != NULL) {
char *keyword = extra->data;
char *therest = parse_next_word(extra->data);
nanorc = extra->filename;
lineno = extra->lineno;
if (!parse_syntax_commands(keyword, therest))
jot_error(N_("Command \"%s\" not understood"), keyword);
extra = extra->next;
}
free(syntax->filename);
syntax->filename = NULL;
}
/* Expand globs in the passed name, and parse the resultant files. */
@@ -561,9 +634,9 @@ void parse_includes(char *ptr)
* report an error if it's something other than zero matches. */
if (result == 0) {
for (size_t i = 0; i < files.gl_pathc; ++i)
parse_one_include(files.gl_pathv[i]);
parse_one_include(files.gl_pathv[i], NULL);
} else if (result != GLOB_NOMATCH)
rcfile_error(_("Error expanding %s: %s"), pattern, strerror(errno));
jot_error(N_("Error expanding %s: %s"), pattern, strerror(errno));
globfree(&files);
free(expanded);
@@ -603,7 +676,7 @@ short color_to_short(const char *colorname, bool *bright)
else if (strcasecmp(colorname, "normal") == 0)
return USE_THE_DEFAULT;
rcfile_error(N_("Color \"%s\" not understood"), colorname);
jot_error(N_("Color \"%s\" not understood"), colorname);
return BAD_COLOR;
}
@@ -619,7 +692,7 @@ bool parse_color_names(char *combostr, short *fg, short *bg, int *attributes)
if (comma != NULL) {
*bg = color_to_short(comma + 1, &bright);
if (bright) {
rcfile_error(N_("A background color cannot be bright"));
jot_error(N_("A background color cannot be bright"));
return FALSE;
}
if (*bg == BAD_COLOR)
@@ -650,14 +723,8 @@ void parse_colors(char *ptr, int rex_flags)
int attributes;
char *item;
if (!opensyntax) {
rcfile_error(N_("A '%s' command requires a preceding 'syntax' command"),
"color");
return;
}
if (*ptr == '\0') {
rcfile_error(N_("Missing color name"));
jot_error(N_("Missing color name"));
return;
}
@@ -667,7 +734,7 @@ void parse_colors(char *ptr, int rex_flags)
return;
if (*ptr == '\0') {
rcfile_error(N_("Missing regex string after '%s' command"), "color");
jot_error(N_("Missing regex string after '%s' command"), "color");
return;
}
@@ -687,7 +754,7 @@ void parse_colors(char *ptr, int rex_flags)
}
if (*ptr != '"') {
rcfile_error(N_("Regex strings must begin and end with a \" character"));
jot_error(N_("Regex strings must begin and end with a \" character"));
ptr = parse_next_regex(ptr);
continue;
}
@@ -698,27 +765,21 @@ void parse_colors(char *ptr, int rex_flags)
break;
if (*item == '\0') {
rcfile_error(N_("Empty regex string"));
jot_error(N_("Empty regex string"));
goodstart = FALSE;
} else
goodstart = nregcomp(item, rex_flags);
/* If the starting regex is valid, initialize a new color struct,
* and hook it in at the tail of the linked list. */
if (goodstart) {
} else {
newcolor = (colortype *)nmalloc(sizeof(colortype));
goodstart = compile(item, rex_flags, &newcolor->start);
}
/* If the start regex is valid, fill in the rest of the data, and
* hook the new color struct in at the tail of the linked list. */
if (goodstart) {
newcolor->fg = fg;
newcolor->bg = bg;
newcolor->attributes = attributes;
newcolor->rex_flags = rex_flags;
newcolor->start_regex = mallocstrcpy(NULL, item);
newcolor->start = NULL;
newcolor->end_regex = NULL;
newcolor->end = NULL;
newcolor->next = NULL;
if (lastcolor == NULL)
@@ -727,19 +788,20 @@ void parse_colors(char *ptr, int rex_flags)
lastcolor->next = newcolor;
lastcolor = newcolor;
}
} else
free(newcolor);
if (!expectend)
continue;
if (ptr == NULL || strncasecmp(ptr, "end=", 4) != 0) {
rcfile_error(N_("\"start=\" requires a corresponding \"end=\""));
jot_error(N_("\"start=\" requires a corresponding \"end=\""));
return;
}
ptr += 4;
if (*ptr != '"') {
rcfile_error(N_("Regex strings must begin and end with a \" character"));
jot_error(N_("Regex strings must begin and end with a \" character"));
continue;
}
@@ -749,18 +811,16 @@ void parse_colors(char *ptr, int rex_flags)
break;
if (*item == '\0') {
rcfile_error(N_("Empty regex string"));
jot_error(N_("Empty regex string"));
continue;
}
/* If the start regex was invalid, skip past the end regex
* to stay in sync. */
/* If the start regex was invalid, the end regex cannot be saved. */
if (!goodstart)
continue;
/* If it's valid, save the ending regex string. */
if (nregcomp(item, rex_flags))
newcolor->end_regex = mallocstrcpy(NULL, item);
/* Save the compiled ending regex (when it's valid). */
compile(item, rex_flags, &newcolor->end);
/* Lame way to skip another static counter. */
newcolor->id = live_syntax->nmultis;
@@ -790,20 +850,18 @@ void grab_and_store(const char *kind, char *ptr, regexlisttype **storage)
regexlisttype *lastthing;
if (!opensyntax) {
rcfile_error(
N_("A '%s' command requires a preceding 'syntax' command"), kind);
jot_error(N_("A '%s' command requires a preceding 'syntax' command"), kind);
return;
}
/* The default syntax doesn't take any file matching stuff. */
if (strcmp(live_syntax->name, "default") == 0 && *ptr != '\0') {
rcfile_error(
N_("The \"default\" syntax does not accept '%s' regexes"), kind);
jot_error(N_("The \"default\" syntax does not accept '%s' regexes"), kind);
return;
}
if (*ptr == '\0') {
rcfile_error(N_("Missing regex string after '%s' command"), kind);
jot_error(N_("Missing regex string after '%s' command"), kind);
return;
}
@@ -819,7 +877,7 @@ void grab_and_store(const char *kind, char *ptr, regexlisttype **storage)
regexlisttype *newthing;
if (*ptr != '"') {
rcfile_error(N_("Regex strings must begin and end with a \" character"));
jot_error(N_("Regex strings must begin and end with a \" character"));
return;
}
@@ -829,7 +887,7 @@ void grab_and_store(const char *kind, char *ptr, regexlisttype **storage)
return;
/* If the regex string is malformed, skip it. */
if (!nregcomp(regexstring, NANO_REG_EXTENDED | REG_NOSUB))
if (!compile(regexstring, NANO_REG_EXTENDED | REG_NOSUB, NULL))
continue;
/* Copy the regex into a struct, and hook this in at the end. */
@@ -849,14 +907,8 @@ void grab_and_store(const char *kind, char *ptr, regexlisttype **storage)
/* Gather and store the string after a comment/linter command. */
void pick_up_name(const char *kind, char *ptr, char **storage)
{
if (!opensyntax) {
rcfile_error(
N_("A '%s' command requires a preceding 'syntax' command"), kind);
return;
}
if (*ptr == '\0') {
rcfile_error(N_("Missing argument after '%s'"), kind);
jot_error(N_("Missing argument after '%s'"), kind);
return;
}
@@ -866,7 +918,7 @@ void pick_up_name(const char *kind, char *ptr, char **storage)
while (*look != '"') {
if (--look == ptr) {
rcfile_error(N_("Argument of '%s' lacks closing \""), kind);
jot_error(N_("Argument of '%s' lacks closing \""), kind);
return;
}
}
@@ -877,6 +929,25 @@ void pick_up_name(const char *kind, char *ptr, char **storage)
*storage = mallocstrcpy(*storage, ptr);
}
/* Handle the four syntax-only commands. */
bool parse_syntax_commands(char *keyword, char *ptr)
{
if (strcasecmp(keyword, "color") == 0)
parse_colors(ptr, NANO_REG_EXTENDED);
else if (strcasecmp(keyword, "icolor") == 0)
parse_colors(ptr, NANO_REG_EXTENDED | REG_ICASE);
else if (strcasecmp(keyword, "comment") == 0) {
#ifdef ENABLE_COMMENT
pick_up_name("comment", ptr, &live_syntax->comment);
#endif
} else if (strcasecmp(keyword, "linter") == 0)
pick_up_name("linter", ptr, &live_syntax->linter);
else
return FALSE;
return TRUE;
}
#endif /* ENABLE_COLOR */
/* Verify that the user has not unmapped every shortcut for a
@@ -908,25 +979,31 @@ static void check_vitals_mapped(void)
}
/* Parse the rcfile, once it has been opened successfully at rcstream,
* and close it afterwards. If syntax_only is TRUE, allow the file to
* and close it afterwards. If just_syntax is TRUE, allow the file to
* to contain only color syntax commands. */
void parse_rcfile(FILE *rcstream, bool syntax_only)
void parse_rcfile(FILE *rcstream, bool just_syntax, bool intros_only)
{
char *buf = NULL;
char *buffer = NULL;
ssize_t len;
size_t n = 0;
size_t size = 0;
while ((len = getline(&buf, &n, rcstream)) > 0) {
while ((len = getline(&buffer, &size, rcstream)) > 0) {
char *ptr, *keyword, *option;
int set = 0;
size_t i;
/* Ignore the newline. */
if (buf[len - 1] == '\n')
buf[len - 1] = '\0';
lineno++;
ptr = buf;
#ifdef ENABLE_COLOR
/* If doing a full parse, skip to after the 'syntax' command. */
if (just_syntax && !intros_only && lineno <= live_syntax->lineno)
continue;
#endif
/* Strip the terminating newline, if any. */
if (buffer[len - 1] == '\n')
buffer[len - 1] = '\0';
ptr = buffer;
while (isblank((unsigned char)*ptr))
ptr++;
@@ -940,9 +1017,12 @@ void parse_rcfile(FILE *rcstream, bool syntax_only)
#ifdef ENABLE_COLOR
/* Handle extending first... */
if (strcasecmp(keyword, "extendsyntax") == 0 && !syntax_only) {
syntaxtype *sint;
if (!just_syntax && strcasecmp(keyword, "extendsyntax") == 0) {
augmentstruct *newitem, *extra;
char *syntaxname = ptr;
syntaxtype *sint;
check_for_nonempty_syntax();
ptr = parse_next_word(ptr);
@@ -951,60 +1031,67 @@ void parse_rcfile(FILE *rcstream, bool syntax_only)
break;
if (sint == NULL) {
rcfile_error(N_("Could not find syntax \"%s\" to extend"),
syntaxname);
opensyntax = FALSE;
jot_error(N_("Could not find syntax \"%s\" to extend"), syntaxname);
continue;
}
live_syntax = sint;
opensyntax = TRUE;
newitem = nmalloc(sizeof(augmentstruct));;
/* Refind the tail of the color list for this syntax. */
lastcolor = sint->color;
if (lastcolor != NULL)
while (lastcolor->next != NULL)
lastcolor = lastcolor->next;
/* Store the content of an 'extendsyntax', for later parsing. */
newitem->filename = strdup(nanorc);
newitem->lineno = lineno;
newitem->data = strdup(ptr);
newitem->next = NULL;
keyword = ptr;
ptr = parse_next_word(ptr);
if (sint->augmentations != NULL) {
extra = sint->augmentations;
while (extra->next != NULL)
extra = extra->next;
extra->next = newitem;
} else
sint->augmentations = newitem;
continue;
}
/* Try to parse the keyword. */
if (strcasecmp(keyword, "syntax") == 0) {
if (opensyntax && lastcolor == NULL)
rcfile_error(N_("Syntax \"%s\" has no color commands"),
live_syntax->name);
parse_syntax(ptr);
}
else if (strcasecmp(keyword, "header") == 0)
grab_and_store("header", ptr, &live_syntax->headers);
else if (strcasecmp(keyword, "magic") == 0)
if (intros_only) {
check_for_nonempty_syntax();
begin_new_syntax(ptr);
} else
break;
} else if (strcasecmp(keyword, "header") == 0) {
if (intros_only)
grab_and_store("header", ptr, &live_syntax->headers);
} else if (strcasecmp(keyword, "magic") == 0) {
#ifdef HAVE_LIBMAGIC
grab_and_store("magic", ptr, &live_syntax->magics);
#else
;
if (intros_only)
grab_and_store("magic", ptr, &live_syntax->magics);
#endif
else if (strcasecmp(keyword, "comment") == 0)
#ifdef ENABLE_COMMENT
pick_up_name("comment", ptr, &live_syntax->comment);
#else
;
#endif
else if (strcasecmp(keyword, "color") == 0)
parse_colors(ptr, NANO_REG_EXTENDED);
else if (strcasecmp(keyword, "icolor") == 0)
parse_colors(ptr, NANO_REG_EXTENDED | REG_ICASE);
else if (strcasecmp(keyword, "linter") == 0)
pick_up_name("linter", ptr, &live_syntax->linter);
else if (syntax_only && (strcasecmp(keyword, "set") == 0 ||
} else if (just_syntax && (strcasecmp(keyword, "set") == 0 ||
strcasecmp(keyword, "unset") == 0 ||
strcasecmp(keyword, "bind") == 0 ||
strcasecmp(keyword, "unbind") == 0 ||
strcasecmp(keyword, "include") == 0 ||
strcasecmp(keyword, "extendsyntax") == 0))
rcfile_error(N_("Command \"%s\" not allowed in included file"),
keyword);
strcasecmp(keyword, "extendsyntax") == 0)) {
if (intros_only)
jot_error(N_("Command \"%s\" not allowed in included file"),
keyword);
else
break;
} else if (intros_only && (strcasecmp(keyword, "color") == 0 ||
strcasecmp(keyword, "icolor") == 0 ||
strcasecmp(keyword, "comment") == 0 ||
strcasecmp(keyword, "linter") == 0)) {
if (!opensyntax)
jot_error(N_("A '%s' command requires a preceding "
"'syntax' command"), keyword);
if (strcasestr("icolor", keyword))
seen_color_command = TRUE;
continue;
} else if (parse_syntax_commands(keyword, ptr))
;
else if (strcasecmp(keyword, "include") == 0)
parse_includes(ptr);
else
@@ -1017,56 +1104,50 @@ void parse_rcfile(FILE *rcstream, bool syntax_only)
parse_binding(ptr, TRUE);
else if (strcasecmp(keyword, "unbind") == 0)
parse_binding(ptr, FALSE);
else
rcfile_error(N_("Command \"%s\" not understood"), keyword);
#ifdef ENABLE_COLOR
/* If a syntax was extended, it stops at the end of the command. */
if (live_syntax != syntaxes)
opensyntax = FALSE;
#endif
else if (intros_only)
jot_error(N_("Command \"%s\" not understood"), keyword);
if (set == 0)
continue;
check_for_nonempty_syntax();
if (*ptr == '\0') {
rcfile_error(N_("Missing option"));
jot_error(N_("Missing option"));
continue;
}
option = ptr;
ptr = parse_next_word(ptr);
/* Find the just read name among the existing options. */
/* Find the just parsed option name among the existing names. */
for (i = 0; rcopts[i].name != NULL; i++) {
if (strcasecmp(option, rcopts[i].name) == 0)
break;
}
if (rcopts[i].name == NULL) {
rcfile_error(N_("Unknown option \"%s\""), option);
jot_error(N_("Unknown option \"%s\""), option);
continue;
}
/* First handle unsetting. */
if (set == -1) {
if (rcopts[i].flag != 0)
UNSET(rcopts[i].flag);
/* If the option has a flag, set it or unset it, as requested. */
if (rcopts[i].flag) {
if (set == 1)
SET(rcopts[i].flag);
else
rcfile_error(N_("Cannot unset option \"%s\""), rcopts[i].name);
UNSET(rcopts[i].flag);
continue;
}
/* If the option has a flag, it doesn't take an argument. */
if (rcopts[i].flag != 0) {
SET(rcopts[i].flag);
/* An option that takes an argument cannot be unset. */
if (set == -1) {
jot_error(N_("Cannot unset option \"%s\""), rcopts[i].name);
continue;
}
/* The option doesn't have a flag, so it takes an argument. */
if (*ptr == '\0') {
rcfile_error(N_("Option \"%s\" requires an argument"),
rcopts[i].name);
jot_error(N_("Option \"%s\" requires an argument"), rcopts[i].name);
continue;
}
@@ -1080,7 +1161,7 @@ void parse_rcfile(FILE *rcstream, bool syntax_only)
#ifdef ENABLE_UTF8
/* When in a UTF-8 locale, ignore arguments with invalid sequences. */
if (using_utf8() && mbstowcs(NULL, option, 0) == (size_t)-1) {
rcfile_error(N_("Argument is not a valid multibyte string"));
jot_error(N_("Argument is not a valid multibyte string"));
continue;
}
#endif
@@ -1111,8 +1192,7 @@ void parse_rcfile(FILE *rcstream, bool syntax_only)
#ifdef ENABLED_WRAPORJUSTIFY
if (strcasecmp(rcopts[i].name, "fill") == 0) {
if (!parse_num(option, &fill)) {
rcfile_error(N_("Requested fill size \"%s\" is invalid"),
option);
jot_error(N_("Requested fill size \"%s\" is invalid"), option);
fill = -COLUMNS_FROM_EOL;
}
free(option);
@@ -1121,40 +1201,40 @@ void parse_rcfile(FILE *rcstream, bool syntax_only)
#ifndef NANO_TINY
if (strcasecmp(rcopts[i].name, "guidestripe") == 0) {
if (!parse_num(option, &stripe_column) || stripe_column <= 0) {
rcfile_error(N_("Guide column \"%s\" is invalid"), option);
jot_error(N_("Guide column \"%s\" is invalid"), option);
stripe_column = 0;
}
free(option);
} else if (strcasecmp(rcopts[i].name, "matchbrackets") == 0) {
if (has_blank_char(option)) {
rcfile_error(N_("Non-blank characters required"));
jot_error(N_("Non-blank characters required"));
free(option);
} else if (mbstrlen(option) % 2 != 0) {
rcfile_error(N_("Even number of characters required"));
jot_error(N_("Even number of characters required"));
free(option);
} else
matchbrackets = option;
} else if (strcasecmp(rcopts[i].name, "whitespace") == 0) {
if (mbstrlen(option) != 2 || breadth(option) != 2) {
rcfile_error(N_("Two single-column characters required"));
jot_error(N_("Two single-column characters required"));
free(option);
} else {
whitespace = option;
whitelen[0] = parse_mbchar(whitespace, NULL, NULL);
whitelen[1] = parse_mbchar(whitespace + whitelen[0], NULL, NULL);
whitelen[0] = char_length(whitespace);
whitelen[1] = char_length(whitespace + whitelen[0]);
}
} else
#endif
#ifdef ENABLE_JUSTIFY
if (strcasecmp(rcopts[i].name, "punct") == 0) {
if (has_blank_char(option)) {
rcfile_error(N_("Non-blank characters required"));
jot_error(N_("Non-blank characters required"));
free(option);
} else
punct = option;
} else if (strcasecmp(rcopts[i].name, "brackets") == 0) {
if (has_blank_char(option)) {
rcfile_error(N_("Non-blank characters required"));
jot_error(N_("Non-blank characters required"));
free(option);
} else
brackets = option;
@@ -1177,24 +1257,18 @@ void parse_rcfile(FILE *rcstream, bool syntax_only)
#endif
if (strcasecmp(rcopts[i].name, "tabsize") == 0) {
if (!parse_num(option, &tabsize) || tabsize <= 0) {
rcfile_error(N_("Requested tab size \"%s\" is invalid"),
option);
jot_error(N_("Requested tab size \"%s\" is invalid"), option);
tabsize = -1;
}
free(option);
}
}
#ifdef ENABLE_COLOR
if (opensyntax && lastcolor == NULL)
rcfile_error(N_("Syntax \"%s\" has no color commands"),
live_syntax->name);
if (intros_only)
check_for_nonempty_syntax();
opensyntax = FALSE;
#endif
free(buf);
fclose(rcstream);
free(buffer);
lineno = 0;
return;
@@ -1203,20 +1277,14 @@ void parse_rcfile(FILE *rcstream, bool syntax_only)
/* Read and interpret one of the two nanorc files. */
void parse_one_nanorc(void)
{
FILE *rcstream;
/* Don't try to open directories nor devices. */
if (!is_good_file(nanorc))
return;
rcstream = fopen(nanorc, "rb");
FILE *rcstream = fopen(nanorc, "rb");
/* If opening the file succeeded, parse it. Otherwise, only
* complain if the file actually exists. */
if (rcstream != NULL)
parse_rcfile(rcstream, FALSE);
parse_rcfile(rcstream, FALSE, TRUE);
else if (errno != ENOENT)
rcfile_error(N_("Error reading %s: %s"), nanorc, strerror(errno));
jot_error(N_("Error reading %s: %s"), nanorc, strerror(errno));
}
bool have_nanorc(const char *path, char *name)
@@ -1235,36 +1303,25 @@ void do_rcfiles(void)
{
const char *xdgconfdir;
/* First process the system-wide nanorc, if there is one. */
/* First process the system-wide nanorc, if it exists and is suitable. */
nanorc = mallocstrcpy(nanorc, SYSCONFDIR "/nanorc");
parse_one_nanorc();
if (is_good_file(nanorc))
parse_one_nanorc();
get_homedir();
xdgconfdir = getenv("XDG_CONFIG_HOME");
/* Now try the to find a nanorc file in the user's home directory or in
* the XDG configuration directories, and process the first one found. */
if (have_nanorc(homedir, "/" HOME_RC_NAME))
parse_one_nanorc();
else if (have_nanorc(xdgconfdir, "/nano/" RCFILE_NAME))
parse_one_nanorc();
else if (have_nanorc(homedir, "/.config/nano/" RCFILE_NAME))
if (have_nanorc(homedir, "/" HOME_RC_NAME) ||
have_nanorc(xdgconfdir, "/nano/" RCFILE_NAME) ||
have_nanorc(homedir, "/.config/nano/" RCFILE_NAME))
parse_one_nanorc();
else if (homedir == NULL && xdgconfdir == NULL)
rcfile_error(N_("I can't find my home directory! Wah!"));
jot_error(N_("I can't find my home directory! Wah!"));
check_vitals_mapped();
#ifdef __linux__
/* On a Linux console, don't start nano when there are rcfile errors,
* because otherwise these error messages get wiped. */
if (on_a_vt && rcfile_with_errors) {
fprintf(stderr, _("If needed, use nano with the -I option "
"to adjust your nanorc settings.\n"));
exit(1);
}
#endif
free(nanorc);
}

View File

@@ -22,9 +22,6 @@
#include "proto.h"
#include <string.h>
#ifdef DEBUG
#include <time.h>
#endif
static bool came_full_circle = FALSE;
/* Have we reached the starting line again while searching? */
@@ -96,15 +93,16 @@ void search_init(bool replacing, bool keep_the_answer)
while (TRUE) {
functionptrtype func;
/* Ask the user what to search for (or replace). */
int i = do_prompt(FALSE, FALSE,
int response = do_prompt(FALSE, FALSE,
inhelp ? MFINDINHELP : (replacing ? MREPLACE : MWHEREIS),
answer, &search_history,
answer, &search_history, edit_refresh,
/* TRANSLATORS: This is the main search prompt. */
edit_refresh, "%s%s%s%s%s%s", _("Search"),
/* TRANSLATORS: The next four modify the search prompt. */
"%s%s%s%s%s%s", _("Search"),
/* TRANSLATORS: The next five modify the search prompt. */
ISSET(CASE_SENSITIVE) ? _(" [Case Sensitive]") : "",
ISSET(USE_REGEXP) ? _(" [Regexp]") : "",
ISSET(BACKWARDS_SEARCH) ? _(" [Backwards]") : "", replacing ?
ISSET(BACKWARDS_SEARCH) ? _(" [Backwards]") : "",
replacing ?
#ifndef NANO_TINY
openfile->mark ? _(" (to replace) in selection") :
#endif
@@ -112,15 +110,13 @@ void search_init(bool replacing, bool keep_the_answer)
/* If the search was cancelled, or we have a blank answer and
* nothing was searched for yet during this session, get out. */
if (i == -1 || (i == -2 && *last_search == '\0')) {
if (response == -1 || (response == -2 && *last_search == '\0')) {
statusbar(_("Cancelled"));
tidy_up_after_search();
free(thedefault);
return;
break;
}
/* If Enter was pressed, prepare to do a replace or a search. */
if (i == 0 || i == -2) {
if (response == 0 || response == -2) {
/* If an actual answer was typed, remember it. */
if (*answer != '\0') {
last_search = mallocstrcpy(last_search, answer);
@@ -139,38 +135,35 @@ void search_init(bool replacing, bool keep_the_answer)
go_looking();
}
tidy_up_after_search();
free(thedefault);
return;
break;
}
func = func_from_key(&i);
func = func_from_key(&response);
/* If we're here, one of the five toggles was pressed, or
* a shortcut was executed. */
if (func == case_sens_void) {
if (func == case_sens_void)
TOGGLE(CASE_SENSITIVE);
} else if (func == backwards_void) {
else if (func == backwards_void)
TOGGLE(BACKWARDS_SEARCH);
} else if (func == regexp_void) {
else if (func == regexp_void)
TOGGLE(USE_REGEXP);
} else if (func == flip_replace) {
else if (func == flip_replace) {
if (ISSET(VIEW_MODE)) {
print_view_warning();
tidy_up_after_search();
free(thedefault);
return;
}
replacing = !replacing;
} else {
if (func == flip_goto)
do_gotolinecolumn(openfile->current->lineno,
openfile->placewewant + 1, TRUE, TRUE);
tidy_up_after_search();
free(thedefault);
return;
}
napms(600);
} else
replacing = !replacing;
} else if (func == flip_goto) {
do_gotolinecolumn(openfile->current->lineno,
openfile->placewewant + 1, TRUE, TRUE);
break;
} else
break;
}
tidy_up_after_search();
free(thedefault);
}
/* Look for needle, starting at (current, current_x). begin is the line
@@ -230,10 +223,10 @@ int findnextstr(const char *needle, bool whole_word_only, int modus,
if (skipone) {
skipone = FALSE;
if (ISSET(BACKWARDS_SEARCH) && from != line->data) {
from = line->data + move_mbleft(line->data, from - line->data);
from = line->data + step_left(line->data, from - line->data);
found = strstrwrapper(line->data, needle, from);
} else if (!ISSET(BACKWARDS_SEARCH) && *from != '\0') {
from += move_mbright(from, 0);
from += char_length(from);
found = strstrwrapper(line->data, needle, from);
}
} else
@@ -248,7 +241,7 @@ int findnextstr(const char *needle, bool whole_word_only, int modus,
* if it's not, continue looking in the rest of the line. */
if (whole_word_only && !is_separate_word(found - line->data,
found_len, line->data)) {
from = found + move_mbright(found, 0);
from = found + char_length(found);
continue;
}
#endif
@@ -402,7 +395,10 @@ void go_looking(void)
{
linestruct *was_current = openfile->current;
size_t was_current_x = openfile->current_x;
#ifdef DEBUG
//#define TIMEIT 12
#ifdef TIMEIT
#include <time.h>
clock_t start = clock();
#endif
@@ -419,7 +415,7 @@ void go_looking(void)
else if (didfind == 0)
not_found_msg(last_search);
#ifdef DEBUG
#ifdef TIMEIT
statusline(HUSH, "Took: %.2f", (double)(clock() - start) / CLOCKS_PER_SEC);
#endif
@@ -472,21 +468,20 @@ int replace_regexp(char *string, bool create)
/* Return a copy of the current line with one needle replaced. */
char *replace_line(const char *needle)
{
char *copy;
size_t new_size = strlen(openfile->current->data) + 1;
size_t match_len;
size_t new_line_size = strlen(openfile->current->data) + 1;
char *copy;
/* First adjust the size of the new line for the change. */
if (ISSET(USE_REGEXP)) {
match_len = regmatches[0].rm_eo - regmatches[0].rm_so;
new_line_size += replace_regexp(NULL, FALSE) - match_len;
new_size += replace_regexp(NULL, FALSE) - match_len;
} else {
match_len = strlen(needle);
new_line_size += strlen(answer) - match_len;
new_size += strlen(answer) - match_len;
}
/* Create the buffer. */
copy = charalloc(new_line_size);
copy = charalloc(new_size);
/* Copy the head of the original line. */
strncpy(copy, openfile->current->data, openfile->current_x);
@@ -497,8 +492,6 @@ char *replace_line(const char *needle)
else
strcpy(copy + openfile->current_x, answer);
assert(openfile->current_x + match_len <= strlen(openfile->current->data));
/* Copy the tail of the original line. */
strcat(copy, openfile->current->data + openfile->current_x + match_len);
@@ -529,8 +522,8 @@ ssize_t do_replace_loop(const char *needle, bool whole_word_only,
/* If the mark is on, frame the region, and turn the mark off. */
if (openfile->mark) {
mark_order((const linestruct **)&top, &top_x,
(const linestruct **)&bot, &bot_x, &right_side_up);
get_region((const linestruct **)&top, &top_x,
(const linestruct **)&bot, &bot_x, &right_side_up);
openfile->mark = NULL;
modus = INREGION;
@@ -704,22 +697,22 @@ void ask_for_replacement(void)
linestruct *edittop_save, *begin;
size_t firstcolumn_save, begin_x;
ssize_t numreplaced;
int i = do_prompt(FALSE, FALSE, MREPLACEWITH, NULL, &replace_history,
/* TRANSLATORS: This is a prompt. */
edit_refresh, _("Replace with"));
int response = do_prompt(FALSE, FALSE, MREPLACEWITH, NULL,
/* TRANSLATORS: This is a prompt. */
&replace_history, edit_refresh, _("Replace with"));
#ifdef ENABLE_HISTORIES
/* If the replace string is not "", add it to the replace history list. */
if (i == 0)
if (response == 0)
update_history(&replace_history, answer);
#endif
/* When cancelled, or when a function was run, get out. */
if (i == -1 || i > 0) {
if (i == -1)
statusbar(_("Cancelled"));
if (response == -1) {
statusbar(_("Cancelled"));
return;
} else if (response > 0)
return;
}
/* Save where we are. */
edittop_save = openfile->edittop;
@@ -762,18 +755,18 @@ void do_gotolinecolumn(ssize_t line, ssize_t column, bool use_answer,
{
if (interactive) {
/* Ask for the line and column. */
int i = do_prompt(FALSE, FALSE, MGOTOLINE,
use_answer ? answer : NULL, NULL,
/* TRANSLATORS: This is a prompt. */
edit_refresh, _("Enter line number, column number"));
int response = do_prompt(FALSE, FALSE, MGOTOLINE,
use_answer ? answer : NULL, NULL, edit_refresh,
/* TRANSLATORS: This is a prompt. */
_("Enter line number, column number"));
/* If the user cancelled or gave a blank answer, get out. */
if (i < 0) {
if (response < 0) {
statusbar(_("Cancelled"));
return;
}
if (func_from_key(&i) == flip_goto) {
if (func_from_key(&response) == flip_goto) {
UNSET(BACKWARDS_SEARCH);
/* Retain what the user typed so far and switch to searching. */
search_init(FALSE, TRUE);
@@ -781,7 +774,7 @@ void do_gotolinecolumn(ssize_t line, ssize_t column, bool use_answer,
}
/* If a function was executed, we're done here. */
if (i > 0)
if (response > 0)
return;
/* Try to extract one or two numbers from the user's response. */
@@ -858,36 +851,36 @@ void do_gotolinecolumn(ssize_t line, ssize_t column, bool use_answer,
void do_gotolinecolumn_void(void)
{
do_gotolinecolumn(openfile->current->lineno,
openfile->placewewant + 1, FALSE, TRUE);
openfile->placewewant + 1, FALSE, TRUE);
}
#ifndef NANO_TINY
/* Search, starting from the current position, for any of the two characters
* in bracket_set. If reverse is TRUE, search backwards, otherwise forwards.
* in bracket_pair. If reverse is TRUE, search backwards, otherwise forwards.
* Return TRUE when one of the brackets was found, and FALSE otherwise. */
bool find_bracket_match(bool reverse, const char *bracket_set)
bool find_a_bracket(bool reverse, const char *bracket_pair)
{
linestruct *line = openfile->current;
const char *pointer = line->data + openfile->current_x;
const char *found = NULL;
const char *pointer, *found;
/* Step away from the current bracket, either backwards or forwards. */
if (reverse) {
if (--pointer < line->data) {
if (openfile->current_x == 0) {
line = line->prev;
if (line == NULL)
return FALSE;
pointer = line->data + strlen(line->data);
}
} else
pointer = line->data + step_left(line->data, openfile->current_x);
} else
++pointer;
pointer = line->data + step_right(line->data, openfile->current_x);
/* Now seek for any of the two brackets, either backwards or forwards. */
while (TRUE) {
if (reverse)
found = mbrevstrpbrk(line->data, bracket_set, pointer);
found = mbrevstrpbrk(line->data, bracket_pair, pointer);
else
found = mbstrpbrk(pointer, bracket_set);
found = mbstrpbrk(pointer, bracket_pair);
if (found)
break;
@@ -928,7 +921,7 @@ void do_find_bracket(void)
/* The location in matchbrackets of the complementing bracket. */
int wanted_ch_len;
/* The length of wanted_ch in bytes. */
char bracket_set[MAXCHARLEN * 2 + 1];
char bracket_pair[MAXCHARLEN * 2 + 1];
/* The pair of characters in ch and wanted_ch. */
size_t halfway = 0;
/* The index in matchbrackets where the closing brackets start. */
@@ -948,7 +941,7 @@ void do_find_bracket(void)
/* Find the halfway point in matchbrackets, where the closing ones start. */
for (size_t i = 0; i < charcount; i++)
halfway += parse_mbchar(matchbrackets + halfway, NULL, NULL);
halfway += char_length(matchbrackets + halfway);
/* When on a closing bracket, we have to search backwards for a matching
* opening bracket; otherwise, forward for a matching closing bracket. */
@@ -959,41 +952,36 @@ void do_find_bracket(void)
wanted_ch = ch;
while (charcount-- > 0) {
if (reverse)
wanted_ch = matchbrackets + move_mbleft(matchbrackets,
wanted_ch - matchbrackets);
wanted_ch = matchbrackets + step_left(matchbrackets,
wanted_ch - matchbrackets);
else
wanted_ch += move_mbright(wanted_ch, 0);
wanted_ch += char_length(wanted_ch);
}
ch_len = parse_mbchar(ch, NULL, NULL);
wanted_ch_len = parse_mbchar(wanted_ch, NULL, NULL);
ch_len = char_length(ch);
wanted_ch_len = char_length(wanted_ch);
/* Fill bracket_set in with the values of ch and wanted_ch. */
strncpy(bracket_set, ch, ch_len);
strncpy(bracket_set + ch_len, wanted_ch, wanted_ch_len);
bracket_set[ch_len + wanted_ch_len] = '\0';
/* Copy the two complementary brackets into a single string. */
strncpy(bracket_pair, ch, ch_len);
strncpy(bracket_pair + ch_len, wanted_ch, wanted_ch_len);
bracket_pair[ch_len + wanted_ch_len] = '\0';
while (TRUE) {
if (find_bracket_match(reverse, bracket_set)) {
/* If we found an identical bracket, increment balance. If we
* found a complementary bracket, decrement it. */
balance += (strncmp(openfile->current->data + openfile->current_x,
ch, ch_len) == 0) ? 1 : -1;
while (find_a_bracket(reverse, bracket_pair)) {
/* Increment/decrement balance for an identical/other bracket. */
balance += (strncmp(openfile->current->data + openfile->current_x,
ch, ch_len) == 0) ? 1 : -1;
/* If balance is zero, we've found a matching bracket. Update
* the screen and get out. */
if (balance == 0) {
edit_redraw(was_current, FLOWING);
break;
}
} else {
/* We didn't find either an opening or closing bracket.
* Indicate this, restore where we were, and get out. */
statusbar(_("No matching bracket"));
openfile->current = was_current;
openfile->current_x = was_current_x;
break;
/* When balance reached zero, we've found the complementary bracket. */
if (balance == 0) {
edit_redraw(was_current, FLOWING);
return;
}
}
statusbar(_("No matching bracket"));
/* Restore the cursor position. */
openfile->current = was_current;
openfile->current_x = was_current_x;
}
#endif /* !NANO_TINY */

View File

@@ -268,7 +268,7 @@ void do_unindent(void)
void handle_indent_action(undo *u, bool undoing, bool add_indent)
{
undo_group *group = u->grouping;
linestruct *line = fsfromline(group->top_line);
linestruct *line = line_from_number(group->top_line);
if (group->next != NULL)
statusline(ALERT, "Multiple groups -- please report a bug");
@@ -297,11 +297,11 @@ void handle_indent_action(undo *u, bool undoing, bool add_indent)
}
#endif /* !NANO_TINY */
/* Test whether the string is empty or consists of only blanks. */
/* Return TRUE when the given string is empty or consists of only blanks. */
bool white_string(const char *s)
{
while (*s != '\0' && (is_blank_mbchar(s) || *s == '\r'))
s += move_mbright(s, 0);
s += char_length(s);
return !*s;
}
@@ -440,7 +440,7 @@ void handle_comment_action(undo *u, bool undoing, bool add_comment)
goto_line_posx(u->lineno, u->begin);
while (group) {
linestruct *f = fsfromline(group->top_line);
linestruct *f = line_from_number(group->top_line);
while (f && f->lineno <= group->bottom_line) {
comment_line(undoing ^ add_comment ?
@@ -490,7 +490,7 @@ void undo_cut(undo *u)
/* Redo a cut, or undo an uncut. */
void redo_cut(undo *u)
{
linestruct *oldcutbuffer = cutbuffer, *oldcutbottom = cutbottom;
linestruct *oldcutbuffer = cutbuffer;
goto_line_posx(u->lineno, u->begin);
@@ -499,16 +499,14 @@ void redo_cut(undo *u)
return;
cutbuffer = NULL;
cutbottom = NULL;
openfile->mark = fsfromline(u->mark_begin_lineno);
openfile->mark = line_from_number(u->mark_begin_lineno);
openfile->mark_x = (u->xflags & WAS_WHOLE_LINE) ? 0 : u->mark_begin_x;
do_cut_text(FALSE, TRUE, FALSE, u->type == ZAP);
free_lines(cutbuffer);
cutbuffer = oldcutbuffer;
cutbottom = oldcutbottom;
}
/* Undo the last thing(s) we did. */
@@ -516,7 +514,7 @@ void do_undo(void)
{
undo *u = openfile->current_undo;
linestruct *f = NULL, *t = NULL;
linestruct *oldcutbuffer, *oldcutbottom;
linestruct *oldcutbuffer;
char *data, *undidmsg = NULL;
size_t from_x, to_x;
@@ -525,11 +523,8 @@ void do_undo(void)
return;
}
if (u->type <= REPLACE) {
f = fsfromline(u->mark_begin_lineno);
if (f == NULL)
return;
}
if (u->type <= REPLACE)
f = line_from_number(u->mark_begin_lineno);
openfile->current_x = u->begin;
switch (u->type) {
@@ -554,7 +549,7 @@ void do_undo(void)
strlen(&u->strdata[from_x]) + 1);
strcat(f->data, &u->strdata[from_x]);
unlink_node(f->next);
renumber(f);
renumber_from(f);
goto_line_posx(u->lineno, to_x);
break;
case BACK:
@@ -584,7 +579,7 @@ void do_undo(void)
free(f->data);
f->data = data;
splice_node(f, t);
renumber(t);
renumber_from(t);
goto_line_posx(u->lineno, u->begin);
break;
case REPLACE:
@@ -622,18 +617,14 @@ void do_undo(void)
case INSERT:
undidmsg = _("insertion");
oldcutbuffer = cutbuffer;
oldcutbottom = cutbottom;
cutbuffer = NULL;
cutbottom = NULL;
openfile->mark = fsfromline(u->mark_begin_lineno);
openfile->mark = line_from_number(u->mark_begin_lineno);
openfile->mark_x = u->mark_begin_x;
goto_line_posx(u->lineno, u->begin);
cut_marked(NULL);
free_lines(u->cutbuffer);
u->cutbuffer = cutbuffer;
u->cutbottom = cutbottom;
cutbuffer = oldcutbuffer;
cutbottom = oldcutbottom;
break;
case COUPLE_BEGIN:
undidmsg = u->strdata;
@@ -701,11 +692,8 @@ void do_redo(void)
while (u->next != openfile->current_undo)
u = u->next;
if (u->type <= REPLACE) {
f = fsfromline(u->mark_begin_lineno);
if (f == NULL)
return;
}
if (u->type <= REPLACE)
f = line_from_number(u->mark_begin_lineno);
switch (u->type) {
case ADD:
@@ -729,7 +717,7 @@ void do_redo(void)
free(f->data);
f->data = data;
splice_node(f, shoveline);
renumber(shoveline);
renumber_from(shoveline);
goto_line_posx(u->lineno + 1, u->mark_begin_x);
break;
case BACK:
@@ -754,7 +742,7 @@ void do_redo(void)
f->data = charealloc(f->data, strlen(f->data) + strlen(u->strdata) + 1);
strcat(f->data, u->strdata);
unlink_node(f->next);
renumber(f);
renumber_from(f);
goto_line_posx(u->mark_begin_lineno, u->mark_begin_x);
break;
case REPLACE:
@@ -903,7 +891,7 @@ void do_enter(void)
/* Insert the newly created line after the current one and renumber. */
splice_node(openfile->current, newnode);
renumber(newnode);
renumber_from(newnode);
/* Put the cursor on the new line, after any automatic whitespace. */
openfile->current = newnode;
@@ -957,20 +945,18 @@ bool execute_command(const char *command)
const char *shellenv;
struct sigaction oldaction, newaction;
/* Original and temporary handlers for SIGINT. */
bool setup_failed = FALSE;
/* Whether setting up the temporary SIGINT handler failed. */
/* Create a pipe to read the command's output from, and, if needed,
* a pipe to feed the command's input through. */
if (pipe(from_fd) == -1 || (should_pipe && pipe(to_fd) == -1)) {
statusbar(_("Could not create pipe"));
statusline(ALERT, _("Could not create pipe"));
return FALSE;
}
/* Check which shell to use. If none is specified, use /bin/sh. */
shellenv = getenv("SHELL");
if (shellenv == NULL)
shellenv = (char *) "/bin/sh";
shellenv = (char *)"/bin/sh";
/* Fork a child process to run the command in. */
if ((pid_of_command = fork()) == 0) {
@@ -999,7 +985,7 @@ bool execute_command(const char *command)
close(from_fd[1]);
if (pid_of_command == -1) {
statusbar(_("Could not fork"));
statusline(ALERT, _("Could not fork"));
close(from_fd[0]);
return FALSE;
}
@@ -1013,7 +999,7 @@ bool execute_command(const char *command)
#ifdef ENABLE_MULTIBUFFER
if (ISSET(MULTIBUFFER)) {
switch_to_prev_buffer();
openfile = openfile->prev;
if (openfile->mark)
do_cut_text(TRUE, TRUE, FALSE, FALSE);
} else
@@ -1042,7 +1028,7 @@ bool execute_command(const char *command)
#ifdef ENABLE_MULTIBUFFER
if (ISSET(MULTIBUFFER))
switch_to_next_buffer();
openfile = openfile->next;
#endif
free_lines(cutbuffer);
cutbuffer = was_cutbuffer;
@@ -1050,19 +1036,12 @@ bool execute_command(const char *command)
/* Re-enable interpretation of the special control keys so that we get
* SIGINT when Ctrl-C is pressed. */
enable_signals();
enable_kb_interrupt();
/* Set things up so that Ctrl-C will terminate the forked process. */
if (sigaction(SIGINT, NULL, &newaction) == -1) {
setup_failed = TRUE;
nperror("sigaction");
} else {
newaction.sa_handler = cancel_the_command;
if (sigaction(SIGINT, &newaction, &oldaction) == -1) {
setup_failed = TRUE;
nperror("sigaction");
}
}
/* Set up a signal handler so that ^C will terminate the forked process. */
newaction.sa_handler = cancel_the_command;
newaction.sa_flags = 0;
sigaction(SIGINT, &newaction, &oldaction);
stream = fdopen(from_fd[0], "rb");
if (stream == NULL)
@@ -1076,14 +1055,12 @@ bool execute_command(const char *command)
}
/* Wait for the external command (and possibly data sender) to terminate. */
if (wait(NULL) == -1)
nperror("wait");
if (should_pipe && (wait(NULL) == -1))
nperror("wait");
wait(NULL);
if (should_pipe)
wait(NULL);
/* If it was changed, restore the handler for SIGINT. */
if (!setup_failed && sigaction(SIGINT, &oldaction, NULL) == -1)
nperror("sigaction");
/* Restore the original handler for SIGINT. */
sigaction(SIGINT, &oldaction, NULL);
/* Restore the terminal to its desired state, and disable
* interpretation of the special control keys again. */
@@ -1141,7 +1118,6 @@ void add_undo(undo_type action)
u->type = action;
u->strdata = NULL;
u->cutbuffer = NULL;
u->cutbottom = NULL;
u->lineno = openfile->current->lineno;
u->begin = openfile->current_x;
u->mark_begin_lineno = openfile->current->lineno;
@@ -1187,12 +1163,12 @@ void add_undo(undo_type action)
* else purposely fall into the line-joining code. */
if (openfile->current->data[openfile->current_x] != '\0') {
char *char_buf = charalloc(MAXCHARLEN + 1);
int char_len = parse_mbchar(&openfile->current->data[u->begin],
int charlen = parse_mbchar(&openfile->current->data[u->begin],
char_buf, NULL);
char_buf[char_len] = '\0';
char_buf[charlen] = '\0';
u->strdata = char_buf;
if (u->type == BACK)
u->mark_begin_x += char_len;
u->mark_begin_x += charlen;
break;
}
case JOIN:
@@ -1297,7 +1273,7 @@ void update_undo(undo_type action)
{
undo *u = openfile->undotop;
char *char_buf;
int char_len;
int charlen;
if (u->type != action)
statusline(ALERT, "Mismatching undo type -- please report a bug");
@@ -1307,10 +1283,10 @@ void update_undo(undo_type action)
switch (u->type) {
case ADD:
char_buf = charalloc(MAXCHARLEN);
char_len = parse_mbchar(&openfile->current->data[u->mark_begin_x],
charlen = parse_mbchar(&openfile->current->data[u->mark_begin_x],
char_buf, NULL);
u->strdata = addstrings(u->strdata, u->strdata ? strlen(u->strdata) : 0,
char_buf, char_len);
char_buf, charlen);
u->mark_begin_lineno = openfile->current->lineno;
u->mark_begin_x = openfile->current_x;
break;
@@ -1321,15 +1297,15 @@ void update_undo(undo_type action)
case BACK:
case DEL:
char_buf = charalloc(MAXCHARLEN);
char_len = parse_mbchar(&openfile->current->data[openfile->current_x],
charlen = parse_mbchar(&openfile->current->data[openfile->current_x],
char_buf, NULL);
if (openfile->current_x == u->begin) {
/* They deleted more: add removed character after earlier stuff. */
u->strdata = addstrings(u->strdata, strlen(u->strdata), char_buf, char_len);
u->strdata = addstrings(u->strdata, strlen(u->strdata), char_buf, charlen);
u->mark_begin_x = openfile->current_x;
} else if (openfile->current_x == u->begin - char_len) {
} else if (openfile->current_x == u->begin - charlen) {
/* They backspaced further: add removed character before earlier. */
u->strdata = addstrings(char_buf, char_len, u->strdata, strlen(u->strdata));
u->strdata = addstrings(char_buf, charlen, u->strdata, strlen(u->strdata));
u->begin = openfile->current_x;
} else {
/* They deleted *elsewhere* on the line: start a new undo item. */
@@ -1362,34 +1338,37 @@ void update_undo(undo_type action)
u->cutbuffer = copy_buffer(cutbuffer);
}
if (u->xflags & MARK_WAS_SET) {
/* If the "marking" operation was from right-->left or
* bottom-->top, then swap the mark points. */
if ((u->lineno == u->mark_begin_lineno && u->begin < u->mark_begin_x)
|| u->lineno < u->mark_begin_lineno) {
ssize_t line = u->lineno;
size_t x_loc = u->begin;
u->begin = u->mark_begin_x;
u->mark_begin_x = x_loc;
/* If the region was marked backwards, swap the end points. */
if (u->lineno < u->mark_begin_lineno ||
(u->lineno == u->mark_begin_lineno &&
u->begin < u->mark_begin_x)) {
ssize_t number = u->lineno;
size_t position = u->begin;
u->lineno = u->mark_begin_lineno;
u->mark_begin_lineno = line;
u->begin = u->mark_begin_x;
u->mark_begin_lineno = number;
u->mark_begin_x = position;
} else
u->xflags |= WAS_MARKED_FORWARD;
} else {
/* Compute the end of the cut for the undo, using our copy. */
u->cutbottom = u->cutbuffer;
while (u->cutbottom->next != NULL)
u->cutbottom = u->cutbottom->next;
u->lineno = u->mark_begin_lineno + u->cutbottom->lineno -
u->cutbuffer->lineno;
linestruct *bottomline = u->cutbuffer;
size_t count = 0;
/* Find the end of the cut for the undo/redo, using our copy. */
while (bottomline->next != NULL) {
bottomline = bottomline->next;
count++;
}
u->lineno = u->mark_begin_lineno + count;
if (ISSET(CUT_FROM_CURSOR) || u->type == CUT_TO_EOF) {
u->begin = strlen(u->cutbottom->data);
u->begin = strlen(bottomline->data);
if (u->lineno == u->mark_begin_lineno)
u->begin += u->mark_begin_x;
} else if (openfile->current == openfile->filebot &&
ISSET(NO_NEWLINES))
u->begin = strlen(u->cutbottom->data);
u->begin = strlen(bottomline->data);
}
break;
case INSERT:
@@ -1434,7 +1413,7 @@ bool do_wrap(void)
return FALSE;
/* Step forward to the character just after the blank. */
wrap_loc += move_mbright(line->data + wrap_loc, 0);
wrap_loc = step_right(line->data, wrap_loc);
/* When now at end-of-line, no need to wrap. */
if (line->data[wrap_loc] == '\0')
@@ -1461,7 +1440,7 @@ bool do_wrap(void)
openfile->current_x = line_len;
/* If the remainder doesn't end in a blank, add a space. */
if (!is_blank_mbchar(remainder + move_mbleft(remainder, rest_length))) {
if (!is_blank_mbchar(remainder + step_left(remainder, rest_length))) {
#ifndef NANO_TINY
add_undo(ADD);
#endif
@@ -1487,14 +1466,14 @@ bool do_wrap(void)
/* When requested, snip trailing blanks off the wrapped line. */
if (ISSET(TRIM_BLANKS)) {
size_t tail_x = move_mbleft(line->data, wrap_loc);
size_t typed_x = move_mbleft(line->data, cursor_x);
size_t tail_x = step_left(line->data, wrap_loc);
size_t typed_x = step_left(line->data, cursor_x);
while ((tail_x != typed_x || cursor_x >= wrap_loc) &&
is_blank_mbchar(line->data + tail_x)) {
openfile->current_x = tail_x;
do_delete();
tail_x = move_mbleft(line->data, tail_x);
tail_x = step_left(line->data, tail_x);
}
}
@@ -1533,7 +1512,7 @@ ssize_t break_line(const char *line, ssize_t goal, bool snap_at_nl)
/* The index of the character we are looking at. */
size_t column = 0;
/* The column position that corresponds with index. */
int char_len = 0;
int charlen = 0;
/* The length of the current character, in bytes. */
/* Find the last blank that does not overshoot the target column. */
@@ -1545,9 +1524,9 @@ ssize_t break_line(const char *line, ssize_t goal, bool snap_at_nl)
break;
}
char_len = parse_mbchar(line, NULL, &column);
line += char_len;
index += char_len;
charlen = parse_mbchar(line, NULL, &column);
line += charlen;
index += charlen;
}
/* If the whole line displays shorter than goal, we're done. */
@@ -1558,7 +1537,7 @@ ssize_t break_line(const char *line, ssize_t goal, bool snap_at_nl)
/* If we're wrapping a help text and no blank was found, or was
* found only as the first character, force a line break. */
if (snap_at_nl && lastblank < 1)
return (index - char_len);
return (index - charlen);
#endif
/* If no blank was found within the goal width, seek one after it. */
@@ -1569,9 +1548,9 @@ ssize_t break_line(const char *line, ssize_t goal, bool snap_at_nl)
else if (lastblank > 0)
return lastblank;
char_len = parse_mbchar(line, NULL, NULL);
line += char_len;
index += char_len;
charlen = char_length(line);
line += charlen;
index += charlen;
}
return -1;
@@ -1579,14 +1558,14 @@ ssize_t break_line(const char *line, ssize_t goal, bool snap_at_nl)
/* Move the pointer back to the last blank, and then step beyond it. */
line = line - index + lastblank;
char_len = parse_mbchar(line, NULL, NULL);
line += char_len;
charlen = char_length(line);
line += charlen;
/* Skip any consecutive blanks after the last blank. */
while (*line != '\0' && is_blank_mbchar(line)) {
lastblank += char_len;
char_len = parse_mbchar(line, NULL, NULL);
line += char_len;
lastblank += charlen;
charlen = char_length(line);
line += charlen;
}
return lastblank;
@@ -1617,90 +1596,65 @@ size_t indent_length(const char *line)
#endif /* !NANO_TINY || ENABLE_JUSTIFY */
#ifdef ENABLE_JUSTIFY
/* Copy a character from one place to another. */
void copy_character(char **from, char **to)
{
int charlen = char_length(*from);
if (*from == *to) {
*from += charlen;
*to += charlen;
} else
while (--charlen >= 0)
*((*to)++) = *((*from)++);
}
/* In the given line, replace any series of blanks with a single space,
* but keep two spaces (if there are two) after any closing punctuation,
* and remove all blanks from the end of the line. Leave the first skip
* number of characters untreated. */
void squeeze(linestruct *line, size_t skip)
{
char *from, *to, *newdata;
size_t shrunk = 0;
int charlen;
newdata = charalloc(strlen(line->data) + 1);
strncpy(newdata, line->data, skip);
from = line->data + skip;
to = newdata + skip;
char *start = line->data + skip;
char *from = start, *to = start;
/* For each character, 1) when a blank, change it to a space, and pass over
* all blanks after it; 2) if it is punctuation, copy it plus a possible
* tailing bracket, and change at most two subsequent blanks to spaces, and
* pass over all blanks after these; 3) leave anything else unchanged. */
while (*from != '\0') {
/* If this character is blank, change it to a space,
* and pass over all blanks after it. */
if (is_blank_mbchar(from)) {
from += parse_mbchar(from, NULL, NULL);
from += char_length(from);
*(to++) = ' ';
while (*from != '\0' && is_blank_mbchar(from)) {
charlen = parse_mbchar(from, NULL, NULL);
from += charlen;
shrunk += charlen;
}
/* If this character is punctuation, then copy it plus a possible
* bracket, and change at most two of subsequent blanks to spaces,
* and pass over all blanks after these. */
while (*from != '\0' && is_blank_mbchar(from))
from += char_length(from);
} else if (mbstrchr(punct, from) != NULL) {
charlen = parse_mbchar(from, NULL, NULL);
copy_character(&from, &to);
while (charlen > 0) {
*(to++) = *(from++);
charlen--;
}
if (*from != '\0' && mbstrchr(brackets, from) != NULL) {
charlen = parse_mbchar(from, NULL, NULL);
while (charlen > 0) {
*(to++) = *(from++);
charlen--;
}
}
if (*from != '\0' && mbstrchr(brackets, from) != NULL)
copy_character(&from, &to);
if (*from != '\0' && is_blank_mbchar(from)) {
from += parse_mbchar(from, NULL, NULL);
from += char_length(from);
*(to++) = ' ';
}
if (*from != '\0' && is_blank_mbchar(from)) {
from += parse_mbchar(from, NULL, NULL);
from += char_length(from);
*(to++) = ' ';
}
while (*from != '\0' && is_blank_mbchar(from)) {
charlen = parse_mbchar(from, NULL, NULL);
from += charlen;
shrunk += charlen;
}
/* Leave unchanged anything that is neither blank nor punctuation. */
} else {
charlen = parse_mbchar(from, NULL, NULL);
while (charlen > 0) {
*(to++) = *(from++);
charlen--;
}
}
while (*from != '\0' && is_blank_mbchar(from))
from += char_length(from);
} else
copy_character(&from, &to);
}
/* If there are spaces at the end of the line, remove them. */
while (to > newdata + skip && *(to - 1) == ' ') {
while (to > start && *(to - 1) == ' ')
to--;
shrunk++;
}
if (shrunk > 0) {
*to = '\0';
free(line->data);
line->data = newdata;
} else
free(newdata);
*to = '\0';
}
/* Return the length of the quote part of the given line. The "quote part"
@@ -1771,14 +1725,12 @@ bool inpar(const linestruct *const line)
return (line->data[quote_len + indent_len] != '\0');
}
/* Determine the beginning, length, and quoting of the first found paragraph.
* Return TRUE if we found a paragraph, and FALSE otherwise. Furthermore,
* return in firstline the first line of the paragraph,
* and in *parlen the length of the paragraph. */
/* Find the first occurring paragraph in the forward direction. Return TRUE
* when a paragraph was found, and FALSE otherwise. Furthermore, return the
* first line and the length (number of lines) of the paragraph. */
bool find_paragraph(linestruct **firstline, size_t *const parlen)
{
linestruct *line = *firstline;
/* The line of the current paragraph we're searching in. */
/* When not currently in a paragraph, move forward to a line that is. */
while (!inpar(line) && line->next != NULL)
@@ -1786,22 +1738,22 @@ bool find_paragraph(linestruct **firstline, size_t *const parlen)
*firstline = line;
/* Move down to the last line of the paragraph. */
/* Move down to the last line of the paragraph (if any). */
do_para_end(&line);
/* When not in a paragraph now, there aren't any paragraphs left. */
if (!inpar(line))
return FALSE;
/* We found a paragraph; determine number of lines. */
/* We found a paragraph; determine its number of lines. */
*parlen = line->lineno - (*firstline)->lineno + 1;
return TRUE;
}
/* Tack all the lines of the paragraph (that starts at *line, and consists of
* par_len lines) together, skipping
* the quoting and indentation on all lines after the first. */
/* Concatenate into a single line all the lines of the paragraph that starts at
* *line and consists of par_len lines, skipping the quoting and indentation on
* all lines after the first. */
void concat_paragraph(linestruct **line, size_t par_len)
{
while (par_len > 1) {
@@ -1926,8 +1878,6 @@ void do_justify(bool full_justify)
/* The bottom x-coordinate of the paragraph we justify. */
linestruct *was_cutbuffer = cutbuffer;
/* The old cutbuffer, so we can justify in the current cutbuffer. */
linestruct *was_cutbottom = cutbottom;
/* The old cutbottom, so we can justify in the current cutbuffer. */
linestruct *jusline;
/* The line that we're justifying in the current cutbuffer. */
@@ -1963,11 +1913,10 @@ void do_justify(bool full_justify)
if (openfile->mark) {
size_t quote_len;
mark_order((const linestruct **)&first_par_line, &top_x,
(const linestruct **)&last_par_line, &bot_x,
&right_side_up);
get_region((const linestruct **)&first_par_line, &top_x,
(const linestruct **)&last_par_line, &bot_x, &right_side_up);
/* Save the coordinates of the mark. */
/* Save the starting point of the marked region. */
was_top_lineno = first_par_line->lineno;
was_top_x = top_x;
@@ -2054,9 +2003,7 @@ void do_justify(bool full_justify)
/* Do the equivalent of a marked cut into an empty cutbuffer. */
cutbuffer = NULL;
cutbottom = NULL;
extract_buffer(&cutbuffer, &cutbottom, first_par_line, top_x,
last_par_line, bot_x);
extract(first_par_line, top_x, last_par_line, bot_x);
#ifndef NANO_TINY
update_undo(CUT);
@@ -2107,8 +2054,6 @@ void do_justify(bool full_justify)
} else
rewrap_paragraph(&line, the_lead, lead_len);
cutbottom = line;
/* If the marked region started after the beginning of a line, insert
* a new line before the new paragraph. But if the region started in
* the middle of the line's leading part, no new line is needed: just
@@ -2131,10 +2076,8 @@ void do_justify(bool full_justify)
* portion, so it will become a full leading part when the justified
* region is "pasted" back. */
if (bot_x > 0 && !ends_at_eol) {
cutbottom->next = make_new_node(cutbottom);
cutbottom->next->data = mallocstrcpy(NULL, the_lead +
needed_bot_extra);
cutbottom = cutbottom->next;
line->next = make_new_node(line);
line->next->data = mallocstrcpy(NULL, the_lead + needed_bot_extra);
}
free(the_lead);
@@ -2172,10 +2115,10 @@ void do_justify(bool full_justify)
/* If we justified marked text, restore mark or cursor position. */
if (openfile->mark) {
if (right_side_up) {
openfile->mark = fsfromline(was_top_lineno);
openfile->mark = line_from_number(was_top_lineno);
openfile->mark_x = was_top_x;
} else {
openfile->current = fsfromline(was_top_lineno);
openfile->current = line_from_number(was_top_lineno);
openfile->current_x = was_top_x;
}
update_undo(COUPLE_END);
@@ -2184,7 +2127,6 @@ void do_justify(bool full_justify)
/* We're done justifying. Restore the old cutbuffer. */
cutbuffer = was_cutbuffer;
cutbottom = was_cutbottom;
/* Show what we justified on the status bar. */
#ifndef NANO_TINY
@@ -2266,8 +2208,8 @@ bool fix_spello(const char *word)
#ifndef NANO_TINY
/* If the mark is on, start at the beginning of the marked region. */
if (openfile->mark) {
mark_order((const linestruct **)&top, &top_x,
(const linestruct **)&bot, &bot_x, &right_side_up);
get_region((const linestruct **)&top, &top_x,
(const linestruct **)&bot, &bot_x, &right_side_up);
/* If the region is marked normally, swap the end points, so that
* (current, current_x) (where searching starts) is at the top. */
if (right_side_up) {
@@ -2516,7 +2458,6 @@ const char *do_int_speller(const char *tempfile_name)
fix_spello(oneword);
free(misspellings);
tidy_up_after_search();
refresh_needed = TRUE;
/* Process the end of the three processes. */
@@ -2524,14 +2465,14 @@ const char *do_int_speller(const char *tempfile_name)
waitpid(pid_sort, &sort_status, 0);
waitpid(pid_uniq, &uniq_status, 0);
if (WIFEXITED(spell_status) == 0 || WEXITSTATUS(spell_status))
return _("Error invoking \"spell\"");
if (WIFEXITED(uniq_status) == 0 || WEXITSTATUS(uniq_status))
return _("Error invoking \"uniq\"");
if (WIFEXITED(sort_status) == 0 || WEXITSTATUS(sort_status))
return _("Error invoking \"sort -f\"");
if (WIFEXITED(uniq_status) == 0 || WEXITSTATUS(uniq_status))
return _("Error invoking \"uniq\"");
if (WIFEXITED(spell_status) == 0 || WEXITSTATUS(spell_status))
return _("Error invoking \"spell\"");
/* When all went okay. */
return NULL;
@@ -2556,6 +2497,7 @@ const char *do_alt_speller(char *tempfile_name)
size_t pww_save = openfile->placewewant;
ssize_t lineno_save = openfile->current->lineno;
bool was_at_eol = (openfile->current->data[openfile->current_x] == '\0');
bool replaced = FALSE;
struct stat spellfileinfo;
time_t timestamp;
pid_t pid_spell;
@@ -2589,11 +2531,9 @@ const char *do_alt_speller(char *tempfile_name)
wait(&alt_spell_status);
block_sigwinch(FALSE);
/* Reenter curses mode. */
doupdate();
/* Restore the terminal to its previous state. */
/* Set the desired terminal state again, and reenter curses mode. */
terminal_init();
doupdate();
if (!WIFEXITED(alt_spell_status) || WEXITSTATUS(alt_spell_status) != 0)
return invocation_error(alt_speller);
@@ -2606,35 +2546,33 @@ const char *do_alt_speller(char *tempfile_name)
#ifndef NANO_TINY
/* Replace the marked text (or entire text) with the corrected text. */
if (openfile->mark) {
linestruct *top, *bot;
size_t top_x, bot_x;
bool right_side_up;
bool upright = (openfile->mark->lineno < openfile->current->lineno ||
(openfile->mark == openfile->current &&
openfile->mark_x < openfile->current_x));
ssize_t was_mark_lineno = openfile->mark->lineno;
mark_order((const linestruct **)&top, &top_x,
(const linestruct **)&bot, &bot_x, &right_side_up);
replace_marked_buffer(tempfile_name);
replaced = replace_buffer(tempfile_name, CUT, TRUE);
/* Adjust the end point of the marked region for any change in
* length of the region's last line. */
if (right_side_up)
if (upright)
current_x_save = openfile->current_x;
else
openfile->mark_x = openfile->current_x;
/* Restore the mark. */
openfile->mark = fsfromline(was_mark_lineno);
openfile->mark = line_from_number(was_mark_lineno);
} else
#endif
replace_buffer(tempfile_name);
replaced = replace_buffer(tempfile_name, CUT_TO_EOF, FALSE);
/* Go back to the old position. */
goto_line_posx(lineno_save, current_x_save);
if (was_at_eol || openfile->current_x > strlen(openfile->current->data))
openfile->current_x = strlen(openfile->current->data);
#ifndef NANO_TINY
update_undo(COUPLE_END);
if (replaced)
update_undo(COUPLE_END);
#endif
openfile->placewewant = pww_save;
adjust_viewport(STATIONARY);
@@ -2695,17 +2633,16 @@ void do_spell(void)
/* Restore the settings of the global flags. */
memcpy(flags, stash, sizeof(flags));
/* If the spell-checker printed any error messages onscreen, make
* sure that they're cleared off. */
total_refresh();
/* Ensure the help lines will be redrawn and a selection is retained. */
currmenu = MMOST;
shift_held = TRUE;
if (result_msg != NULL) {
/* Avoid giving a failure reason of "Success". */
if (errno == 0)
/* Don't display an error message of "Success". */
statusline(ALERT, _("Spell checking failed: %s"), result_msg);
statusline(ALERT, result_msg);
else
statusline(ALERT, _("Spell checking failed: %s: %s"), result_msg,
strerror(errno));
statusline(ALERT, _("%s: %s"), result_msg, strerror(errno));
} else
statusbar(_("Finished checking spelling"));
}
@@ -2754,7 +2691,7 @@ void do_linter(void)
/* Create a pipe up front. */
if (pipe(lint_fd) == -1) {
statusbar(_("Could not create pipe"));
statusline(ALERT, _("Could not create pipe"));
return;
}
@@ -2791,7 +2728,7 @@ void do_linter(void)
/* If the child process was not forked successfully... */
if (pid_lint < 0) {
close(lint_fd[0]);
statusbar(_("Could not fork"));
statusline(ALERT, _("Could not fork"));
return;
}
@@ -2800,7 +2737,7 @@ void do_linter(void)
if (pipesize < 1) {
close(lint_fd[0]);
statusbar(_("Could not get size of pipe buffer"));
statusline(ALERT, _("Could not get size of pipe buffer"));
return;
}
@@ -3061,21 +2998,19 @@ void do_linter(void)
* multibyte characters instead of single-byte characters. */
void do_wordlinechar_count(void)
{
linestruct *was_current = openfile->current;
size_t was_x = openfile->current_x;
size_t words = 0, chars = 0;
ssize_t nlines = 0;
size_t current_x_save = openfile->current_x;
linestruct *current_save = openfile->current;
linestruct *was_mark = openfile->mark;
ssize_t lines = 0;
linestruct *top, *bot;
size_t top_x, bot_x;
/* If the mark is on, partition the buffer so that it
* contains only the marked text, and turn the mark off. */
if (was_mark) {
mark_order((const linestruct **)&top, &top_x,
(const linestruct **)&bot, &bot_x, NULL);
filepart = partition_buffer(top, top_x, bot, bot_x);
openfile->mark = NULL;
if (openfile->mark) {
get_region((const linestruct **)&top, &top_x,
(const linestruct **)&bot, &bot_x, NULL);
partition_buffer(top, top_x, bot, bot_x);
}
/* Start at the top of the file. */
@@ -3092,28 +3027,24 @@ void do_wordlinechar_count(void)
words++;
}
/* Get the total line and character counts, as "wc -l" and "wc -c"
* do, but get the latter in multibyte characters. */
if (was_mark) {
nlines = openfile->filebot->lineno - openfile->filetop->lineno + 1;
chars = get_totsize(openfile->filetop, openfile->filebot);
/* Get the number of lines, similar to what "wc -l" gives. */
lines = openfile->filebot->lineno - openfile->filetop->lineno +
((openfile->filebot->data[0] == '\0') ? 0 : 1);
/* Unpartition the buffer so that it contains all the text
* again, and turn the mark back on. */
unpartition_buffer(&filepart);
openfile->mark = was_mark;
} else {
nlines = openfile->filebot->lineno;
/* Get the number of multibyte characters, similar to "wc -c". */
if (openfile->mark) {
chars = get_totsize(openfile->filetop, openfile->filebot);
unpartition_buffer();
} else
chars = openfile->totsize;
}
/* Restore where we were. */
openfile->current = current_save;
openfile->current_x = current_x_save;
openfile->current = was_current;
openfile->current_x = was_x;
/* Display the total word, line, and character counts on the statusbar. */
statusline(HUSH, _("%sWords: %zu Lines: %zd Chars: %zu"), was_mark ?
_("In Selection: ") : "", words, nlines, chars);
statusline(HUSH, _("%sWords: %zu Lines: %zd Chars: %zu"), openfile->mark ?
_("In Selection: ") : "", words, lines, chars);
}
#endif /* !NANO_TINY */
@@ -3162,7 +3093,7 @@ char *copy_completion(char *text)
/* Find the end of the candidate word to get its length. */
while (is_word_mbchar(&text[length], FALSE))
length = move_mbright(text, length);
length = step_right(text, length);
/* Now copy this candidate to a new string. */
word = charalloc(length + 1);
@@ -3214,11 +3145,11 @@ void complete_a_word(void)
/* Find the start of the fragment that the user typed. */
start_of_shard = openfile->current_x;
while (start_of_shard > 0) {
size_t step_left = move_mbleft(openfile->current->data, start_of_shard);
size_t oneleft = step_left(openfile->current->data, start_of_shard);
if (!is_word_mbchar(&openfile->current->data[step_left], FALSE))
if (!is_word_mbchar(&openfile->current->data[oneleft], FALSE))
break;
start_of_shard = step_left;
start_of_shard = oneleft;
}
/* If there is no word fragment before the cursor, do nothing. */
@@ -3261,7 +3192,7 @@ void complete_a_word(void)
/* If the match is not a separate word, skip it. */
if (i > 0 && is_word_mbchar(&pletion_line->data[
move_mbleft(pletion_line->data, i)], FALSE))
step_left(pletion_line->data, i)], FALSE))
continue;
/* If this match is the shard itself, ignore it. */

View File

@@ -202,7 +202,7 @@ bool is_separate_word(size_t position, size_t length, const char *buf)
size_t word_end = position + length;
/* Get the characters before and after the word, if any. */
parse_mbchar(buf + move_mbleft(buf, position), before, NULL);
parse_mbchar(buf + step_left(buf, position), before, NULL);
parse_mbchar(buf + word_end, after, NULL);
/* If the word starts at the beginning of the line OR the character before
@@ -246,7 +246,7 @@ const char *strstrwrapper(const char *haystack, const char *needle,
/* If this is the last possible match, don't try to advance. */
if (last_find == ceiling)
break;
next_rung = move_mbright(haystack, last_find);
next_rung = step_right(haystack, last_find);
regmatches[0].rm_so = next_rung;
regmatches[0].rm_eo = far_end;
if (regexec(&search_regexp, haystack, 1, regmatches,
@@ -287,17 +287,6 @@ const char *strstrwrapper(const char *haystack, const char *needle,
return mbstrcasestr(start, needle);
}
/* This is a wrapper for the perror() function. The wrapper temporarily
* leaves curses mode, calls perror() (which writes to stderr), and then
* reenters curses mode, updating the screen in the process. Note that
* nperror() causes the window to flicker once. */
void nperror(const char *s)
{
endwin();
perror(s);
doupdate();
}
/* This is a wrapper for the malloc() function that properly handles
* things when we run out of memory. */
void *nmalloc(size_t howmuch)
@@ -442,7 +431,7 @@ void remove_magicline(void)
if (openfile->filebot->data[0] == '\0' &&
openfile->filebot != openfile->filetop) {
openfile->filebot = openfile->filebot->prev;
free_lines(openfile->filebot->next);
delete_node(openfile->filebot->next);
openfile->filebot->next = NULL;
openfile->totsize--;
}
@@ -450,15 +439,15 @@ void remove_magicline(void)
#endif
#ifndef NANO_TINY
/* Set (top, top_x) and (bot, bot_x) to the start and end "coordinates" of
* the marked region. If right_side_up isn't NULL, set it to TRUE when the
* mark is at the top of the marked region, and to FALSE otherwise. */
void mark_order(const linestruct **top, size_t *top_x,
const linestruct **bot, size_t *bot_x, bool *right_side_up)
/* Return in (top, top_x) and (bot, bot_x) the start and end "coordinates"
* of the marked region. If right_side_up isn't NULL, set it to TRUE when
* the mark is at the top of the marked region, and to FALSE otherwise. */
void get_region(const linestruct **top, size_t *top_x,
const linestruct **bot, size_t *bot_x, bool *right_side_up)
{
if ((openfile->current->lineno == openfile->mark->lineno &&
openfile->current_x > openfile->mark_x) ||
openfile->current->lineno > openfile->mark->lineno) {
if (openfile->mark->lineno < openfile->current->lineno ||
(openfile->mark == openfile->current &&
openfile->mark_x < openfile->current_x)) {
*top = openfile->mark;
*top_x = openfile->mark_x;
*bot = openfile->current;
@@ -486,7 +475,7 @@ void get_range(const linestruct **top, const linestruct **bot)
} else {
size_t top_x, bot_x;
mark_order(top, &top_x, bot, &bot_x, NULL);
get_region(top, &top_x, bot, &bot_x, NULL);
if (bot_x == 0 && *bot != *top && !also_the_last)
*bot = (*bot)->prev;
@@ -495,22 +484,19 @@ void get_range(const linestruct **top, const linestruct **bot)
}
}
/* Given a line number, return a pointer to the corresponding struct. */
linestruct *fsfromline(ssize_t lineno)
/* Return a pointer to the line that has the given line number. */
linestruct *line_from_number(ssize_t number)
{
linestruct *f = openfile->current;
linestruct *line = openfile->current;
if (lineno <= openfile->current->lineno)
while (f->lineno != lineno && f->prev != NULL)
f = f->prev;
if (line->lineno > number)
while (line->lineno != number)
line = line->prev;
else
while (f->lineno != lineno && f->next != NULL)
f = f->next;
while (line->lineno != number)
line = line->next;
if (f->lineno == lineno)
return f;
else
return NULL;
return line;
}
#endif /* !NANO_TINY */

View File

@@ -27,6 +27,9 @@
#include <sys/ioctl.h>
#endif
#include <string.h>
#ifdef ENABLE_UTF8
#include <wchar.h>
#endif
#ifdef REVISION
#define BRANDING REVISION
@@ -1903,7 +1906,7 @@ char *display_string(const char *buf, size_t column, size_t span,
if (start_col < column) {
converted[index++] = control_mbrep(buf, isdata);
column++;
buf += parse_mbchar(buf, NULL, NULL);
buf += char_length(buf);
}
}
#ifdef ENABLE_UTF8
@@ -1916,21 +1919,30 @@ char *display_string(const char *buf, size_t column, size_t span,
/* Display the right half of a two-column character as ']'. */
converted[index++] = ']';
column++;
buf += parse_mbchar(buf, NULL, NULL);
buf += char_length(buf);
}
#endif
}
while (*buf != '\0' && (column < beyond || mbwidth(buf) == 0)) {
int charlength, charwidth = 1;
#ifdef ENABLE_UTF8
#define ISO8859_CHAR FALSE
#else
#define ISO8859_CHAR ((unsigned char)*buf > 0x9F)
#endif
while (*buf != '\0' && (column < beyond || mbwidth(buf) == 0)) {
/* A plain printable ASCII character is one byte, one column. */
if (((signed char)*buf > 0x20 && *buf != DEL_CODE) || ISO8859_CHAR) {
converted[index++] = *(buf++);
column++;
continue;
}
/* Show a space as a visible character, or as a space. */
if (*buf == ' ') {
/* Show a space as a visible character, or as a space. */
#ifndef NANO_TINY
if (ISSET(WHITESPACE_DISPLAY)) {
int i = whitelen[0];
while (i < whitelen[0] + whitelen[1])
for (int i = whitelen[0]; i < whitelen[0] + whitelen[1];)
converted[index++] = whitespace[i++];
} else
#endif
@@ -1938,15 +1950,15 @@ char *display_string(const char *buf, size_t column, size_t span,
column++;
buf++;
continue;
} else if (*buf == '\t') {
/* Show a tab as a visible character, or as as a space. */
}
/* Show a tab as a visible character plus spaces, or as just spaces. */
if (*buf == '\t') {
#ifndef NANO_TINY
if (ISSET(WHITESPACE_DISPLAY) && (index > 0 || !isdata ||
!ISSET(SOFTWRAP) || column % tabsize == 0 ||
column == start_col)) {
int i = 0;
while (i < whitelen[0])
for (int i = 0; i < whitelen[0];)
converted[index++] = whitespace[i++];
} else
#endif
@@ -1961,47 +1973,54 @@ char *display_string(const char *buf, size_t column, size_t span,
continue;
}
charlength = length_of_char(buf, &charwidth);
/* If buf contains a control character, represent it. */
/* Represent a control character with a leading caret. */
if (is_cntrl_mbchar(buf)) {
converted[index++] = '^';
converted[index++] = control_mbrep(buf, isdata);
buf += char_length(buf);
column += 2;
buf += charlength;
continue;
}
/* If buf contains a valid non-control character, simply copy it. */
if (charlength > 0) {
for (; charlength > 0; charlength--)
converted[index++] = *(buf++);
#ifdef ENABLE_UTF8
int charlength, charwidth;
wchar_t wc;
/* Convert a multibyte character to a single code. */
charlength = mbtowc(&wc, buf, MAXCHARLEN);
/* Represent an invalid character with the Replacement Character. */
if (charlength < 0 || !is_valid_unicode(wc)) {
converted[index++] = '\xEF';
converted[index++] = '\xBF';
converted[index++] = '\xBD';
buf += (charlength > 0 ? charlength : 1);
column++;
continue;
}
/* For any valid character, just copy its bytes. */
for (; charlength > 0; charlength--)
converted[index++] = *(buf++);
/* Determine whether the character occupies one or two columns. */
charwidth = wcwidth(wc);
/* If the codepoint is unassigned, assume a width of one. */
column += (charwidth < 0 ? 1 : charwidth);
column += charwidth;
#ifdef USING_OLD_NCURSES
if (charwidth > 1)
seen_wide = TRUE;
if (charwidth > 1)
seen_wide = TRUE;
#endif
continue;
}
/* Represent an invalid starter byte with the Replacement Character. */
converted[index++] = '\xEF';
converted[index++] = '\xBF';
converted[index++] = '\xBD';
column++;
buf++;
/* For invalid codepoints, skip extra bytes. */
if (charlength < -1)
buf += charlength + 7;
#endif /* ENABLE_UTF8 */
}
/* If there is more text than can be shown, make room for the ">". */
if (column > beyond || (*buf != '\0' && (isprompt ||
(isdata && !ISSET(SOFTWRAP))))) {
do {
index = move_mbleft(converted, index);
index = step_left(converted, index);
} while (mbwidth(converted + index) == 0);
#ifdef ENABLE_UTF8
@@ -2211,16 +2230,15 @@ void statusline(message_type importance, const char *msg, ...)
(lastmessage == MILD && importance == HUSH))
return;
va_start(ap, msg);
/* Curses mode is turned off. If we use wmove() now, it will muck
* up the terminal settings. So we just use vfprintf(). */
if (isendwin()) {
fprintf(stderr, "\n");
vfprintf(stderr, msg, ap);
va_end(ap);
#ifndef NANO_TINY
/* Curses mode shouldn't be off when trying to write to the status bar. */
if (!started_curses || isendwin()) {
fprintf(stderr, "Out of curses -- please report a bug\n");
lastmessage = HUSH;
napms(1400);
return;
}
#endif
/* If the ALERT status has been reset, reset the counter. */
if (lastmessage == HUSH)
@@ -2248,6 +2266,7 @@ void statusline(message_type importance, const char *msg, ...)
/* Construct the message out of all the arguments. */
compound = charalloc(MAXCHARLEN * (COLS + 1));
va_start(ap, msg);
vsnprintf(compound, MAXCHARLEN * (COLS + 1), msg, ap);
va_end(ap);
message = display_string(compound, 0, COLS, FALSE, FALSE);
@@ -2494,8 +2513,7 @@ void edit_draw(linestruct *fileptr, const char *converted,
/* If the match is of length zero, skip it. */
if (match.rm_so == match.rm_eo) {
index = move_mbright(fileptr->data,
index + match.rm_eo);
index = step_right(fileptr->data, index + match.rm_eo);
continue;
}
@@ -2517,8 +2535,7 @@ void edit_draw(linestruct *fileptr, const char *converted,
paintlen = actual_x(thetext, wideness(fileptr->data,
match.rm_eo) - from_col - start_col);
mvwaddnstr(edit, row, margin + start_col,
thetext, paintlen);
mvwaddnstr(edit, row, margin + start_col, thetext, paintlen);
}
goto tail_of_loop;
}
@@ -2581,7 +2598,7 @@ void edit_draw(linestruct *fileptr, const char *converted,
endmatch.rm_so == endmatch.rm_eo) {
if (start_line->data[index] == '\0')
break;
index = move_mbright(start_line->data, index);
index = step_right(start_line->data, index);
}
/* If there is no later start on this line, next step. */
if (regexec(varnish->start, start_line->data + index,
@@ -2663,7 +2680,7 @@ void edit_draw(linestruct *fileptr, const char *converted,
endmatch.rm_so == endmatch.rm_eo) {
if (fileptr->data[index] == '\0')
break;
index = move_mbright(fileptr->data, index);
index = step_right(fileptr->data, index);
}
continue;
}
@@ -2739,7 +2756,7 @@ void edit_draw(linestruct *fileptr, const char *converted,
int paintlen = -1;
/* The number of characters to paint. Negative means "all". */
mark_order(&top, &top_x, &bot, &bot_x, NULL);
get_region(&top, &top_x, &bot, &bot_x, NULL);
if (top->lineno < fileptr->lineno || top_x < from_x)
top_x = from_x;
@@ -3375,9 +3392,10 @@ void total_refresh(void)
if (currmenu != MBROWSER && currmenu != MWHEREISFILE && currmenu != MGOTODIR)
titlebar(title);
#ifdef ENABLE_HELP
if (inhelp)
wrap_the_help_text(TRUE);
else
if (inhelp) {
close_buffer();
wrap_help_text_into_buffer();
} else
#endif
if (currmenu != MBROWSER && currmenu != MWHEREISFILE && currmenu != MGOTODIR)
edit_refresh();

View File

@@ -22,7 +22,7 @@ color yellow " (no-)?[-[:alpha:]]+-format(,|$)"
color brightmagenta "%([1-9]\$)?[a-z]*"
# Quotes and escaped characters.
color yellow "\""
color cyan "\\[abcefnrtv"\]"
color cyan "\\([abcefnrtv"\]|x[0-9abcdefABCDEF]{2}|[0-7]{3})"
# Reminders.
color brightwhite,yellow "(FIXME|TODO|XXX)"
# Obsolete strings.

View File

@@ -22,14 +22,15 @@ color brightcyan "\<(exec|print)([[:blank:]]|$)"
# Special values.
color brightmagenta "\<(False|None|True)\>"
# Single-quoted strings.
color brightgreen "'([^'\]|\\.)+'"
color brightgreen ""([^"\]|\\.)+""
# Mono-quoted strings.
color brightgreen "'([^'\]|\\.)*'|'''"
color brightgreen ""([^"\]|\\.)*"|""""
color normal "'''|""""
# Comments.
color brightred "(^|[[:blank:]])#.*"
# Triple-quoted strings.
color brightgreen start="'''([^'),]|$)" end="(^|[^(\])'''"
color brightgreen start="\"\"\"([^"),]|$)" end="(^|[^(\])\"\"\""
color brightgreen start=""""([^"),]|$)" end="(^|[^(\])""""
# Reminders.
color brightwhite,yellow "(FIXME|TODO|XXX)"