Index: vendor/nvi/2.2.0-05ed8b9/CMakeLists.txt =================================================================== --- vendor/nvi/2.2.0-05ed8b9/CMakeLists.txt (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/CMakeLists.txt (revision 366308) @@ -0,0 +1,210 @@ +cmake_minimum_required(VERSION 3.9) + +get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(is_multi_config) + set(CMAKE_CONFIGURATION_TYPES Debug Release CACHE STRING + "Semicolon separated list of supported configuration types") + mark_as_advanced(CMAKE_CONFIGURATION_TYPES) +elseif(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_C_FLAGS) + message(WARNING "No CMAKE_BUILD_TYPE is selected") +endif() + +project(nvi2 C) + +include(CheckIncludeFiles) +include(CheckFunctionExists) +include(CheckStructHasMember) +include(CheckCSourceCompiles) + +mark_as_advanced(CMAKE_INSTALL_PREFIX) + +option(USE_WIDECHAR "Enable wide character support" ON) +option(USE_ICONV "Enable iconv support" ON) + +add_compile_options(-fcolor-diagnostics) +add_compile_options($<$:-Wall>) +add_compile_options($<$:-Wno-parentheses>) +add_compile_options($<$:-Wno-uninitialized>) +add_compile_options($<$:-Wmissing-prototypes>) +add_compile_options($<$:-Wsystem-headers>) +add_compile_options($<$:-Wuninitialized>) +add_compile_options($<$:-Wno-dangling-else>) +add_compile_options(-Wstack-protector -fstack-protector) +add_compile_options(-Wstrict-aliasing -fstrict-aliasing) + +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +set(MAIN_PROTOS + cl/extern.h common/extern.h ex/extern.h vi/extern.h + common/options_def.h ex/ex_def.h ex/version.h) + +set(CL_SRCS + cl/cl_funcs.c cl/cl_main.c cl/cl_read.c cl/cl_screen.c cl/cl_term.c) + +set(COMMON_SRCS + common/conv.c common/cut.c common/delete.c common/encoding.c common/exf.c + common/key.c common/line.c common/log.c common/main.c common/mark.c + common/msg.c common/options.c common/options_f.c common/put.c + common/recover.c common/screen.c common/search.c common/seq.c + common/util.c) + +set(EX_SRCS + ex/ex.c ex/ex_abbrev.c ex/ex_append.c ex/ex_args.c ex/ex_argv.c ex/ex_at.c + ex/ex_bang.c ex/ex_cd.c ex/ex_cmd.c ex/ex_cscope.c ex/ex_delete.c + ex/ex_display.c ex/ex_edit.c ex/ex_equal.c ex/ex_file.c ex/ex_filter.c + ex/ex_global.c ex/ex_init.c ex/ex_join.c ex/ex_map.c ex/ex_mark.c + ex/ex_mkexrc.c ex/ex_move.c ex/ex_open.c ex/ex_preserve.c ex/ex_print.c + ex/ex_put.c ex/ex_quit.c ex/ex_read.c ex/ex_screen.c ex/ex_script.c + ex/ex_set.c ex/ex_shell.c ex/ex_shift.c ex/ex_source.c ex/ex_stop.c + ex/ex_subst.c ex/ex_tag.c ex/ex_txt.c ex/ex_undo.c ex/ex_usage.c + ex/ex_util.c ex/ex_version.c ex/ex_visual.c ex/ex_write.c ex/ex_yank.c + ex/ex_z.c) + +set(VI_SRCS + vi/getc.c vi/v_at.c vi/v_ch.c vi/v_cmd.c vi/v_delete.c vi/v_ex.c + vi/v_increment.c vi/v_init.c vi/v_itxt.c vi/v_left.c vi/v_mark.c + vi/v_match.c vi/v_paragraph.c vi/v_put.c vi/v_redraw.c vi/v_replace.c + vi/v_right.c vi/v_screen.c vi/v_scroll.c vi/v_search.c vi/v_section.c + vi/v_sentence.c vi/v_status.c vi/v_txt.c vi/v_ulcase.c vi/v_undo.c + vi/v_util.c vi/v_word.c vi/v_xchar.c vi/v_yank.c vi/v_z.c vi/v_zexit.c + vi/vi.c vi/vs_line.c vi/vs_msg.c vi/vs_refresh.c vi/vs_relative.c + vi/vs_smap.c vi/vs_split.c) + +set(REGEX_SRCS + regex/regcomp.c regex/regerror.c regex/regexec.c regex/regfree.c) + +# commands to generate the public headers +set(extract_protos sed -n 's/^ \\* PUBLIC: \\\(.*\\\)/\\1/p') +set(extract_version sed -n + 's/^.*version \\\([^\)]*\)\\\).*/\#define VI_VERSION \\\"\\1\\\"/p') + +add_custom_command(OUTPUT cl/extern.h + COMMAND ${extract_protos} ${CL_SRCS} > cl/extern.h + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + DEPENDS ${CL_SRCS}) +add_custom_command(OUTPUT common/extern.h + COMMAND ${extract_protos} ${COMMON_SRCS} > common/extern.h + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + DEPENDS ${COMMON_SRCS}) +add_custom_command(OUTPUT ex/extern.h + COMMAND ${extract_protos} ${EX_SRCS} > ex/extern.h + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + DEPENDS ${EX_SRCS}) +add_custom_command(OUTPUT vi/extern.h + COMMAND ${extract_protos} ${VI_SRCS} > vi/extern.h + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + DEPENDS ${VI_SRCS}) +add_custom_command(OUTPUT common/options_def.h + COMMAND awk -f common/options.awk + common/options.c > common/options_def.h + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + DEPENDS common/options.c) +add_custom_command(OUTPUT ex/ex_def.h + COMMAND awk -f ex/ex.awk ex/ex_cmd.c > ex/ex_def.h + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + DEPENDS ex/ex_cmd.c) +add_custom_command(OUTPUT ex/version.h + COMMAND ${extract_version} README > ex/version.h + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + DEPENDS README) + +add_executable(nvi) +target_sources(nvi PRIVATE ${MAIN_PROTOS} ${CL_SRCS} ${COMMON_SRCS} + ${EX_SRCS} ${VI_SRCS}) +target_compile_definitions(nvi PRIVATE $<$:DEBUG> + $<$:COMLOG>) + +check_function_exists(openpty UTIL_IN_LIBC) +if(NOT UTIL_IN_LIBC) + find_library(UTIL_LIBRARY util) + target_link_libraries(nvi PRIVATE ${UTIL_LIBRARY}) +endif() + +check_function_exists(__b64_ntop RESOLV_IN_LIBC) +if(NOT RESOLV_IN_LIBC) + find_library(RESOLV_LIBRARY resolv) + target_link_libraries(nvi PRIVATE ${RESOLV_LIBRARY}) +endif() + +if(USE_WIDECHAR) + find_library(CURSES_LIBRARY NAMES ncursesw cursesw curses HINTS /usr/lib) + find_library(TERMINFO_LIBRARY NAMES tinfow terminfo HINTS /usr/lib) + + # link to the wchar_t awared BSD libregex.a + add_library(regex STATIC) + target_sources(regex PRIVATE ${REGEX_SRCS}) + target_include_directories(regex PUBLIC regex) + target_compile_definitions(regex PUBLIC __REGEX_PRIVATE) + target_link_libraries(nvi PRIVATE regex) +else() + find_library(CURSES_LIBRARY NAMES ncurses curses HINTS /usr/lib) + find_library(TERMINFO_LIBRARY NAMES tinfo terminfo HINTS /usr/lib) + target_compile_options(nvi PRIVATE -Wno-pointer-sign) +endif() + +target_link_libraries(nvi PRIVATE ${CURSES_LIBRARY} ${TERMINFO_LIBRARY}) + +if(USE_ICONV) + check_function_exists(iconv ICONV_IN_LIBC) + if(NOT ICONV_IN_LIBC) + find_path(ICONV_INCLUDE_DIR iconv.h) + find_library(ICONV_LIBRARY iconv) + endif() + + # detect the prototype of iconv(3) + set(CMAKE_C_FLAGS_BACKUP "${CMAKE_C_FLAGS}") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror") + set(CMAKE_REQUIRED_INCLUDES "${ICONV_INCLUDE_DIR}") + set(CMAKE_REQUIRED_LIBRARIES "${ICONV_LIBRARY}") + check_c_source_compiles(" + #include + int main() { + iconv_t conv = 0; + char* in = 0; + size_t ilen = 0; + char* out = 0; + size_t olen = 0; + iconv(conv, &in, &ilen, &out, &olen); + return 0; + } + " ICONV_TRADITIONAL) + set(CMAKE_REQUIRED_INCLUDES) + set(CMAKE_REQUIRED_LIBRARIES) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS_BACKUP}") + + target_include_directories(nvi PRIVATE ${ICONV_INCLUDE_DIR}) + target_link_libraries(nvi PRIVATE ${ICONV_LIBRARY}) +endif() + +check_function_exists(getprogname GETPROGNAME_IN_LIBC) +check_function_exists(strlcpy STRLCPY_IN_LIBC) +if(NOT GETPROGNAME_IN_LIBC OR NOT STRLCPY_IN_LIBC) + find_package(PkgConfig REQUIRED) + pkg_check_modules(LIBBSD libbsd-overlay) + add_definitions(${LIBBSD_CFLAGS}) + target_link_libraries(nvi PRIVATE ${LIBBSD_LIBRARIES}) +endif() + +check_function_exists(dbopen DBOPEN_IN_LIBC) +if(NOT DBOPEN_IN_LIBC) + target_link_libraries(nvi PRIVATE db1) +endif() + +check_include_files(libutil.h HAVE_LIBUTIL_H) +check_include_files(ncurses.h HAVE_NCURSES_H) +check_include_files(ncursesw/ncurses.h HAVE_NCURSESW_NCURSES_H) +check_include_files(pty.h HAVE_PTY_H) +check_include_files(term.h HAVE_TERM_H) +check_struct_has_member("struct dirent" d_namlen dirent.h HAVE_DIRENT_D_NAMLEN LANGUAGE C) + +configure_file(files/config.h.in config.h) + +set(vi_cv_path_preserve /var/tmp/vi.recover/) +if(APPLE) + set(vi_cv_path_msgcat /usr/local/share/vi/catalog/) +else() + set(vi_cv_path_msgcat /usr/share/vi/catalog/) +endif() + +configure_file(files/pathnames.h.in pathnames.h) +configure_file(files/recover.in recover @ONLY) Property changes on: vendor/nvi/2.2.0-05ed8b9/CMakeLists.txt ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/catalog/dump.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/catalog/dump.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/catalog/dump.c (revision 366308) @@ -0,0 +1,97 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +static void +parse(FILE *fp) +{ + int ch, s1, s2, s3; + +#define TESTD(s) do { \ + if ((s = getc(fp)) == EOF) \ + return; \ + if (!isdigit(s)) \ + continue; \ +} while (0) +#define TESTP do { \ + if ((ch = getc(fp)) == EOF) \ + return; \ + if (ch != '|') \ + continue; \ +} while (0) +#define MOVEC(t) do { \ + do { \ + if ((ch = getc(fp)) == EOF) \ + return; \ + } while (ch != (t)); \ +} while (0) + for (;;) { + MOVEC('"'); + TESTD(s1); + TESTD(s2); + TESTD(s3); + TESTP; + putchar('"'); + putchar(s1); + putchar(s2); + putchar(s3); + putchar('|'); + for (;;) { /* dump to end quote. */ + if ((ch = getc(fp)) == EOF) + return; + putchar(ch); + if (ch == '"') + break; + if (ch == '\\') { + if ((ch = getc(fp)) == EOF) + return; + putchar(ch); + } + } + putchar('\n'); + } +} + +int +main(int argc, char *argv[]) +{ + FILE *fp; + + for (; *argv != NULL; ++argv) { + if ((fp = fopen(*argv, "r")) == NULL) { + perror(*argv); + return (1); + } + parse(fp); + (void)fclose(fp); + } + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/catalog/dump.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/catalog/Makefile =================================================================== --- vendor/nvi/2.2.0-05ed8b9/catalog/Makefile (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/catalog/Makefile (revision 366308) @@ -0,0 +1,77 @@ +CAT= dutch english french german polish ru_RU.KOI8-R spanish \ + swedish tr_TR.ISO8859-9 tr_TR.UTF-8 uk_UA.KOI8-U zh_CN.GB2312 +FILES= ../cl/*.c ../common/*.c ../ex/*.c ../vi/*.c + +all: dump ${CAT} + +${CAT}: english.base + @echo "... $@"; \ + rm -f $@; \ + sort -u $@.base | \ + awk '{ \ + if ($$1 == 1) { \ + print "\nMESSAGE NUMBER 1 IS NOT LEGAL"; \ + exit 1; \ + } \ + if (++nline > $$1) { \ + print "DUPLICATE MESSAGE NUMBER " $$1; \ + exit 1; \ + } \ + print $0; \ + }' | \ + sed -e '1s/^/$$set 1~$$quote "~/; 1y/~/\n/' | \ + gencat $@ /dev/stdin; \ + chmod 444 $@; \ + if grep DUPLICATE $@ > /dev/null; then \ + grep DUPLICATE $@; \ + fi; \ + if grep 'NOT LEGAL' $@ > /dev/null; then \ + grep 'NOT LEGAL' $@; \ + fi + +CHK= dutch.check english.check french.check german.check \ + polish.check ru_RU.KOI8-R.check spanish.check swedish.check \ + tr_TR.ISO8859-9.check tr_TR.UTF-8.check uk_UA.KOI8-U.check \ + zh_CN.GB2312.check +check: ${CHK} +${CHK}: ${CAT} + @echo "... $@"; \ + f=`basename $@ .check`; \ + (echo "Unused message id's (this is okay):"; \ + awk '{ \ + while (++nline < $$1) \ + printf "%03d\n", nline; \ + }' < $$f.base; \ + echo =========================; \ + echo "MISSING ERROR MESSAGES (Please add!):"; \ + awk '{print $$1}' < $$f.base | sort -u > __ck1; \ + awk '{print $$1}' < english.base | sort -u > __ck2; \ + comm -13 __ck1 __ck2; \ + echo =========================; \ + echo "Extra error messages (just delete them):"; \ + comm -23 __ck1 __ck2; \ + echo =========================; \ + echo "MESSAGES WITH THE SAME MESSAGE ID's (FIX!):"; \ + for j in \ + `sed '/^$$/d' < $$f.base | sort -u | \ + awk '{print $$1}' | uniq -d`; do \ + egrep $$j $$f.base; \ + done; \ + echo =========================; \ + echo "Duplicate messages, both id and message (this is okay):"; \ + sed '/^$$/d' < $$f.base | sort | uniq -c | \ + awk '$$1 != 1 { print $$0 }' | sort -n; \ + echo =========================) > $@ + +english.base: dump ${FILES} #Makefile + ./dump ${FILES} |\ + sed -e '/|/!d' \ + -e 's/|/ "/' \ + -e 's/^"//' |\ + sort -nu > $@ + +dump: dump.c + ${CC} -O -o dump dump.c + +clean: + rm -f dump dump.o ${CAT} english.base *.check __ck1 __ck2 Property changes on: vendor/nvi/2.2.0-05ed8b9/catalog/Makefile ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/catalog/README =================================================================== --- vendor/nvi/2.2.0-05ed8b9/catalog/README (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/catalog/README (revision 366308) @@ -0,0 +1,125 @@ +Generally, all non-system error and informational messages in nvi are +catalog messages, i.e. they can be tailored to a specific langauge. +Command strings, usage strings, system errors and other 'known text' +are not. + +Message catalogs in nvi are fairly simple. Every catalog message +consists of two parts -- an initial number followed by a pipe (`|') +character, followed by the English text for the message. For example: + + msgq(sp, M_ERR, "001|This is an error message"); + +would be a typical message. + +When the msgq() routine is called, if the user has specified a message +catalog and the format string (the third argument) has a leading number, +then it is converted to a record number, and that record is retrieved +from the message catalog and used as a replacement format string. If +the record can't be retrieved for any reason, the English text is displayed +instead. + +Each message format string MUST map into the English format string, i.e. +it can't display more or different arguments than the English one. + +For example: + + msgq(sp, M_ERR, "002|Error: %d %x", arg1, arg2); + +is a format string that displays two arguments. + +Arguments to the msgq function are required to contain ONLY printable +characters. No further translation is done by the msgq routine before +displaying the message on the screen. For example, in the msgq call: + + msgq(sp, M_ERR, "003|File: %s", file_name); + +"file_name" must contain only printable characters. The routine +msg_print() returns a printable version of a string; the third argument +indicates whether the string needs to be freed. For example: + + char *p; + int nf; + + p = msg_print(sp, file_name, &nf); + msgq(sp, M_ERR, "003|File: %s", p); + if (nf) + FREE_SPACE(sp, p, 0); + +makes sure that "file_name" is printable before calling the msgq +routine. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +The message catalogs themselves are maintained in two files. The first +is the "base file" which contains two fields, a record number and the +message itself. All base files are named using the convention +".base", e.g. the English one is "english.base". For +example: + + 002 "Line length overflow" + 003 "unable to delete line %lu" + 004 "unable to append to line %lu" + 005 "unable to insert at line %lu" + 006 "unable to store line %lu" + 007 "unable to get last line" + +are the first few lines of the current english.base file. + +Before this file being converted to the second file, the POSIX formatted +message catalog file, by gencat(1), two lines: + + $set 1 + $quote " + +will be inserted before the base text to setup the set_id and the quote +character. So the double-quote needs to be escaped by a backslash to be +included in a message; same as the backslash itself. + +These files are named for their language, e.g. "english". However, a +locale(1) name is also recommended. + +To create a new catalog for nvi: + +Copy the file english.base to a file that you can modify , e.g. "cp +english.base german.base". For each of the messages in the file, +replace the message with the string that you want to use. If you have +doubts about the meaning of a message, just email me. + +A latest english.base can be created from source by running the command +"make english" in the catalog/ directory. + +Once you've translated all of the strings, then add your catalog to the +"CAT=" line of the Makefile, and run the command "make catalog". This +will create the second (and corresponding) file for each file named +.base. + +Don't worry about missing line numbers, i.e. base files that look like: + + 005 Message number 5. + 007 Message number 7. + +This simply means that a message was deleted during the course of nvi's +development. It will be taken care of automatically when you create +the second form of the file. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +If you add new messages to the nvi sources, you can check your work by +doing "make english; make check". The "make check" target lists unused +message numbers, duplicate message numbers, and duplicate messages. +Unused message numbers are only useful if you are condensing messages. +Duplicate message numbers are a serious problem and have to be fixed. +Duplicate messages are only interesting if a message appears often enough +that it's worth creating a routine so that the string is only need in +a single place. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +To select a catalog when running nvi, set the "msgcat" option. If the +value of this option ends with a '/', it is treated as the name of a +directory that contains a message catalog "$LC_MESSAGES", which is set +through the LC_MESSAGES environment variable but returned by setlocale(3). +Check the output of locale(1) to validate such a value. If the option +doesn't end in a '/', the option is treated as the full path name of the +message catalog to use. + +If any messages are missing from the catalog, the backup text (English) +is used instead. Property changes on: vendor/nvi/2.2.0-05ed8b9/catalog/README ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/catalog/tr_TR.ISO8859-9.base =================================================================== --- vendor/nvi/2.2.0-05ed8b9/catalog/tr_TR.ISO8859-9.base (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/catalog/tr_TR.ISO8859-9.base (revision 366308) @@ -0,0 +1,304 @@ +002 "Satýr uzunluðu taþýmý" +003 "%lu numaralý satýr silinemiyor" +004 "%lu numaralý satýra iliþtirilemiyor" +005 "%lu numaralý satýrda ekleme yapýlamýyor" +006 "%lu numaralý satýr kaydedilemiyor" +007 "Son satýr alýnamýyor" +008 "Hata: %lu numaralý satýr okunamýyor" +009 "Günlük dosyasý" +010 "Günlükleme gerçekleþtirilmiyor, geri alma olanaklý deðil" +011 "Geri alýnacak bir deðiþiklik yok" +012 "Günlükleme gerçekleþtirilmiyor, geri alma olanaklý deðil" +013 "Günlükleme gerçekleþtirilmiyor, ileri sarma olanaklý deðil" +014 "Yinelenecek bir deðiþiklik yok" +015 "%s/%d: Günlük kayýt hatasý" +016 "Vi'nin standart girdisi ve çýktýsý bir uçbirim olmalý" +017 "Ým %s: Ayarlanmamýþ" +018 "Ým %s: Satýr silinmiþ" +019 "Ým %s: Ýmleç konumu artýk yok" +020 "Hata: " +021 "yeni dosya +022 "adý deðiþti" +023 "deðiþtirildi" +024 "deðiþtirilmedi" +025 "KÝLÝDÝ AÇILDI" +026 "saltokunur" +027 "satýr %lu/%lu [%ld%%]" +028 "boþ dosya" +029 "%lu. satýr" +030 "%s dosyasý bir ileti kataloðu deðil" +031 "Öntanýmlý %s seçeneði ayarlanamadý" +032 "Kullaným: %s" +033 "set: %s seçeneði yok: 'set all' tüm seçenek deðerlerini verir" +034 "set: [no]%s seçeneði bir deðer almaz" +035 "set: %s seçeneði bir Boole deðeri deðil" +036 "set: %s seçeneði: %s" +037 "set: %s seçeneði: %s: Deðer taþýmý" +038 "set: %s seçeneði: %s izin verilmeyen bir sayý" +039 "set: %s seçeneði bir Boole deðeri deðil" +040 "Ekran sütun sayýsý çok küçük, þundan daha az: %d" +041 "Ekran sütun sayýsý çok büyük, þundan daha çok: %d" +042 "Ekran satýr sayýsý çok küçük, þundan daha az: %d" +043 "Ekran satýr sayýsý çok büyük, þundan daha çok: %d" +044 "Lisp seçeneði eklenmemiþ" +045 "Ýletiler kapatýlmamýþ: %s" +046 "Ýletiler açýlmamýþ: %s" +047 "%s seçeneði iki karakterli öbekler biçiminde olmalý" +053 "Baþlangýç arabelleði boþ" +054 "%s arabelleði boþ" +056 "Oturum baþarýsýz olursa deðiþiklikler kurtarýlamaz" +057 "Dosya, kurtarma için kopyalanýyor..." +058 "Koruma baþarýsýz oldu: %s" +059 "Oturum baþarýsýz olursa deðiþiklikler kurtarýlamaz" +060 "Dosya yedeklemesi baþarýsýz oldu: %s" +061 "Dosya, kurtarma için kopyalanýyor..." +062 "%u kullanýcýsý üzerine bilgi bulunamadý" +063 "Kurtarma dosyasý kilitlenemiyor" +065 "Kurtarma dosyasý" +066 "%s: Hatalý oluþturulmuþ kurtarma dosyasý" +067 "%s: Hatalý oluþturulmuþ kurtarma dosyasý" +068 "Kurtarýlacak %s adýnda sizce okunabilir bir dosya yok" +069 "Bu dosyanýn kurtarabileceðiniz eski sürümleri var" +070 "Kurtarabileceðiniz baþka dosyalar var" +071 "E-posta gönderilmedi: %s" +072 "Dosya boþ, aranacak bir þey yok" +073 "Dizgi bulunamadan dosyanýn sonuna eriþildi" +074 "Arama dizgisi yok" +075 "Dizgi bulunamadý" +076 "Dizgi bulunamadan dosyanýn baþýna eriþildi" +077 "Arama tamamlandý" +078 "Aranýyor..." +079 "Yazdýrýlamaz karakter bulunmadý" +080 "Bilinmeyen komut adý" +082 "%s: Komut ex kipinde kullanýlamaz" +083 "Sayým sýfýr olmayabilir" +084 "%s: Hatalý satýr belirtimi" +085 "Ýç sözdizim tablo hatasý (%s: %s)" +086 "Kullaným: %s" +087 "%s: Geçici arabellek salýverilmedi" +088 "Bayrak göreli konumu birinci satýrdan önceye" +089 "Bayrak göreli konumu dosya sonunu geçiyor" +090 "Erimli @, dosya/ekran deðiþtiðinde çalýþýr" +091 "Global/v komutu dosya/ekran deðiþtiðinde çalýþýr" +092 "Ex komutu baþarýsýz: Sýradaki komutlar çýkarýldý" +093 "Ex komutu baþarýsýz: Eþlemlenen düðmeler çýkarýldý" +094 "Ýkinci adres ilkinden daha küçük" +095 "Bir im adý saðlanmadý" +096 "\\ sonrasýnda / veya ? gelmiyor" +097 "Bir satýr numarasýna yapýlan baþvuru sayýsý sýfýrdan az" +098 "Bilinmeyen komut: %s" +099 "Adres deðeri taþýmý" +100 "Adres deðeri alttaþýmý" +101 "Ýzin verilmeyen adres birleþimi" +102 "Ýzin verilmeyen adres: Dosyada yalnýzca %lu satýr var" +103 "Ýzin verilmeyen adres: Dosya boþ" +104 "%s komutu bir 0 adresine izin vermiyor" +105 "Görüntülenecek kýsaltma yok" +106 "Kýsaltmalar bir \"sözcük\" karakteri ile bitmelidir" +107 "Kýsaltmalar sekme veya boþluk içeremez" +108 "Kýsaltmalar sonu dýþýnda sözcük/sözcük olmayan karakterleri karýþtýramaz" +109 "\"%s\" bir kýsaltma deðil" +110 "Vi komutu baþarýsýz: Eþlemlenen düðmeler çýkarýldý" +111 "Düzenlenecek baþka dosya yok" +112 "Öncesinde düzenlenecek baþka dosya yok" +113 "Öncesinde geri sarýlacak dosyalar yok" +114 "Görüntülenecek dosya yok" +115 "Öncesinde \"!\" ögesinin yerine geçecek bir komut yok" +116 "%% yerine geçecek bir dosya adý yok" +117 "# yerine geçecek bir dosya adý yok" +118 "Hata: execl: %s" +119 "Girdi/Çýktý hatasý: %s" +120 "Dosya son tam yazýmdan bu yana deðiþtirilmiþ; yazýn veya yok saymak için ! kullanýn" +121 "Ev dizini konumu bulunamýyor" +122 "Yeni þimdiki dizin: %s" +123 "Görüntülenecek kesilmiþ arabellek yok" +124 "%s komutu bir global veya v komutunun parçasý olarak kullanýlamaz" +128 "%s: kaynak alýnmýyor: Ýyesi siz veya kök deðil" +129 "%s: kaynak alýnmýyor: Ýyesi siz deðilsiniz" +130 "%s: kaynak alýnmýyor: Ýyesi dýþýnda baþka bir kullanýcý tarafýndan yazýlabilir" +131 "Uç uca eklenecek bir satýr yok" +132 "Girdi eþlem girdisi yok" +133 "Komut eþlem girdisi yok" +134 "%s yeniden eþlemlenemeyebilir" +135 "\"%s\" þu anda eþlemlenmemiþ" +136 "Ým adlarý tek bir karakter olmalýdýr" +137 "%s mevcut, yazýlmamýþ; yok saymak için ! kullanýn" +138 "Yeni exrc dosyasý: %s" +139 "Hedef satýrý taþýma erimi içinde" +140 "'open' komutu 'open' seçeneðinin ayarlý olmasýný gerektirir" +141 "'open' komutu henüz eklenmemiþ" +142 "Bu dosyanýn korunmasý olanaklý deðil" +143 "Dosya korundu" +144 "%s: Çok fazla dosya adýna geniþletilmiþ" +145 "Yalnýzca sýradan dosyalar ve adlandýrýlmýþ veri yollarý okunabilir" +146 "%s: Okuma kilidi kullanýlabilir deðildi" +147 "Okunuyor..." +148 "%s: %lu satýr, %lu karakter" +149 "Görüntülenecek arkaplan ekraný yok" +150 "'script' komutu yalnýzca vi kipinde kullanýlabilir" +151 "Çalýþtýrýlacak komut yok" +152 "'shiftwidth' seçeneði 0 olarak ayarlanmýþ" +153 "Sayým taþýmý" +154 "Sayým alttaþýmý" +155 "Düzenli ifade belirtilmiþ; r bayraðý anlamsýz" +156 "#, l ve p bayraklarý vi kipinde c bayraðý ile birlikte kullanýlamaz" +157 "Eþleþme bulunamadý" +158 "Önceden bir etiket girilmemiþ" +159 "Etiket yýðýnýnda %s sayýsýndan az girdi; :display t[ags] kullanýn" +160 "Etiket yýðýnýnda dönülecek bir %s dosyasý yok; :display t[ags] kullanýn" +161 "Sürdürmek için Enter'a basýn:" +162 "%s: Etiket bulunamadý" +163 "%s: %s içinde hasar görmüþ etiket" +164 "%s: Etiketin satýr numarasý dosya sonunu geçmiþ" +165 "Etiket yýðýný boþ" +166 "%s: Arama dizgisi bulunamadý" +167 "%d dosya daha düzenlenecek" +168 "%s arabelleði boþ" +169 "Deðiþikliði onayla? [n]" +170 "Yarýda kesildi" +171 "Öncesinde çalýþtýrýlacak arabellek yok" +172 "Öncesinde düzenli ifade yok" +173 "%s komutu bir dosyanýn halihazýrda okunmuþ olmasýný gerektirir" +174 "Kullaným: %s" +175 "'visual' komutu 'open' seçeneðinin ayarlanmýþ olmasýný gerektirir" +177 "Boþ dosya" +178 "Öncesinde F, f, T veya t aramasý yok" +179 "%s bulunamadý" +180 "Düzenlenecek dosya yok" +181 "Ýmleç bir sayýda deðil" +182 "Ortaya çýkan sayý çok büyük" +183 "Ortaya çýkan sayý çok küçük" +184 "Bu satýrda eþleþen karakter yok" +185 "Eþleþen karakter bulunamadý" +186 "Deðiþtirilecek karakter yok" +187 "Geçilecek baþka ekran yok" +188 "Arama dizgisinden, satýr ofsetinden ve/veya 'z' komutundan sonraki karakterler" +189 "Öncesinde arama dizgisi yok" +190 "Arama baþlanan konumda tamamlandý" +191 "Kýsaltma geniþleme sýnýrýný aþtý: Karakterler çýkarýldý" +192 "Ýzin verilmeyen karakter; giriþ için týrnak içine alýn" +193 "Halihazýrda eklemenin baþýnda" +194 "Silinecek baþka karakter yok" +195 "Hareket dosya sonunu geçti" +196 "Hareket satýr sonunu geçti" +197 "Ýmleç hareket ettirilmedi" +198 "Halihazýrda dosyanýn baþýnda" +199 "Hareket dosyanýn baþýný geçti" +200 "Halihazýrda ilk sütunda" +201 "Arabellekler komuttan önce belirtilmeli" +202 "Halihazýrda dosya sonunda" +203 "Halihazýrda satýr sonunda" +204 "%s bir vi komutu deðil" +205 "Kullaným: %s" +206 "Silinecek karakter yok" +207 "Q komutu ex uçbirim arabirimini gerektirir" +208 "Yinelenecek komut yok" +209 "Dosya boþ" +210 "%s bir hareket komutu olarak kullanýlamaz" +211 "Halihazýrda komut kipi içinde" +212 "Ýmleç bir sözcükte deðil" +214 "'windows' seçeneði deðeri çok büyük, en çok %u olabilir" +215 "Ýliþtir" +216 "Deðiþiklik yap" +217 "Komut" +218 "Ekle" +219 "Deðiþtir" +220 "Hareket ekran sonunu geçti" +221 "Hareket ekran baþýný geçti" +222 "Ekran bölünebilmesi için %d satýrdan daha geniþ olmalýdýr" +223 "Arkaplan ekraný yok" +224 "Arkaplanda %s dosyasýný düzenleyen bir ekran yok" +225 "Açýk olan tek ekranýnýzý arkaplana alamazsýnýz" +226 "Ekran yalnýzca %d satýra küçültülebilir" +227 "Ekran küçülemez" +228 "Ekran büyüyemez" +230 "Bu ekran askýya alýnamaz" +231 "Yarýda kesildi: Eþlemlenen düðmeler çýkarýldý" +232 "vi: Geçici arabellek salýverilmedi" +233 "Bu uçbirimde %s düðmesi yok" +234 "Yalnýzca bir arabellek belirtilebilir" +235 "Sayý þundan daha büyük: %lu" +236 "Yarýda kesildi" +237 "Geçici dosya oluþturulamýyor" +238 "Uyarý: %s sýradan bir dosya deðil" +239 "%s halihazýrda kilitlenmiþ, oturum saltokunur" +240 "%s: Kaldýr" +241 "%s: Kapat" +242 "%s: Kaldýr" +243 "%s: Kaldýr" +244 "Saltokunur dosya, yazýlmadý; yok saymak için ! kullanýn" +245 "Saltokunur dosya, yazýlmadý" +246 "%s mevcut, yazýlmadý; yok saymak için ! kullanýn" +247 "%s mevcut, yazýlmadý" +248 "Kýsmi dosya, yazýlmadý; yok saymak için ! kullanýn" +249 "Kýsmi dosya, yazýlmadý" +250 "%s: Dosya bu kopyadan daha önce deðiþtirilmiþ; yok saymak için ! kullanýn" +251 "%s: Dosya bu kopyadan daha önce deðiþtirilmiþ" +252 "%s: Yazým korumasý kullanýlabilir deðildi" +253 "Yazýlýyor..." +254 "%s: UYARI: DOSYA KIRPILMIÞ" +255 "Halihazýrda bu grubun ilk etiketinde" +256 "%s: Yeni dosya: %lu satýr, %lu karakter" +257 "%s: %lu satýr, %lu karakter" +258 "%s çok fazla dosya adýna geniþletilmiþ" +259 "%s: Sýradan bir dosya deðil" +260 "%s: Ýyesi siz deðilsiniz" +261 "%s: Ýyesi dýþýnda baþka bir kullanýcý tarafýndan da eriþilebilir" +262 "Dosya son tam yazýmdan bu yana deðiþtirilmiþ; yazýn veya yok saymak için ! kullanýn" +263 "Dosya son tam yazýmdan bu yana deðiþtirilmiþ; yazýn veya yok saymak için :edit! kullanýn" +264 "Dosya son tam yazýmdan bu yana deðiþtirilmiþ; yazýn veya yok saymak için ! kullanýn" +265 "Dosya geçici; çýkarsanýz deðiþiklikler atýlacaktýr" +266 "Dosya saltokunur, deðiþiklikler kendiliðinden yazýlmaz" +267 "Günlük yeniden baþlatýldý" +268 "Onayla? [ynq]" +269 "Sürdürmek için herhangi bir düðmeye basýn: " +270 "Sürdürmek için herhangi bir düðmeye basýn [ex komutu girmek için :]: " +271 "Sürdürmek için herhangi bir düðmeye basýn [çýkýþ için q]: " +272 "Bu biçim %s ex uçbirim arabirimini gerektirir" +273 "ex girdisi kipine giriliyor" +274 "Komut baþarýsýz, henüz bir dosya okunmadý." +275 " sürdür?" +276 "Beklenmedik karakter olayý" +277 "Beklenmedik dosya sonu olayý" +278 "Sorgu eþleþmesi bulunamadý" +279 "Beklenmedik yarýda kesme olayý" +281 "Beklenmedik yeniden boyama olayý" +282 "Halihazýrda bu grubun son etiketinde" +283 "%s komutu ex uçbirim arabirimini gerektirir" +284 "Bu biçim %s 'secure edit' seçeneði ayarlandýðýnda desteklenmez" +285 "Beklenmedik dizi olayý" +286 "Beklenmedik zaman aþýmý olayý" +288 "Bölünebilmesi için ekran %d sütundan daha geniþ olmalýdýr" +289 "Kabuk geniþletmeleri 'secure edit' seçeneði ayarlandýðýnda desteklenmez" +290 "%s komutu 'secure edit' seçeneði ayarlandýðýnda desteklenmez" +291 "set: %s seçeneði kapatýlamaz" +292 "Ekran çok küçük." +293 "eklendi" +294 "deðiþtirildi" +295 "silindi" +296 "uç uca eklendi" +297 "taþýndý" +298 "kaydýrýldý" +299 "kopyalandý" +300 "satýr" +301 "satýr" +303 "Dosya son yazýmdan bu yana deðiþtirilmiþ." +304 "Kabuk geniþletmesi baþarýsýz" +305 "Bir '%s' düzenleme seçeneði belirtilmedi" +307 "Çalýþtýrýlacak ex komutu yok" +308 "Bir komut çalýþtýrmak için , çýkmak için :q girin" +309 "Yardým için \"cscope help\" kullanýn" +310 "Çalýþan bir cscope baðlantýsý yok" +311 "%s: Bilinmeyen arama türü: Þunlardan bir tanesini kullanýn: %s" +312 "%d: Böyle bir cscope oturumu yok" +313 "set: %s seçeneði hiçbir zaman açýlamaz" +314 "set: %s seçeneði hiçbir zaman 0 olarak ayarlanamaz" +315 "%s: Ýliþtirildi: %lu satýr, %lu karakter" +316 "Beklenmedik yeniden boyutlandýrma olayý" +317 "Düzenlenecek %d dosya var" +319 "%d ekran arkaplana alýndý; onlarý listelemek için :display kullanýn" +320 "Bilinmeyen imleç konumu" +321 "Dosya kodlama dönüþtürmesi desteklenmiyor" +322 "Girdi kodlama dönüþtürmesi desteklenmiyor" +323 "Geçersiz girdi. Kýrpýldý." +324 "%d numaralý satýrda dönüþtürme hatasý" Index: vendor/nvi/2.2.0-05ed8b9/catalog/tr_TR.ISO8859-9.owner =================================================================== --- vendor/nvi/2.2.0-05ed8b9/catalog/tr_TR.ISO8859-9.owner (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/catalog/tr_TR.ISO8859-9.owner (revision 366308) @@ -0,0 +1 @@ +Emir SARI Index: vendor/nvi/2.2.0-05ed8b9/catalog/tr_TR.UTF-8.base =================================================================== --- vendor/nvi/2.2.0-05ed8b9/catalog/tr_TR.UTF-8.base (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/catalog/tr_TR.UTF-8.base (revision 366308) @@ -0,0 +1,304 @@ +002 "Satır uzunluÄŸu taşımı" +003 "%lu numaralı satır silinemiyor" +004 "%lu numaralı satıra iliÅŸtirilemiyor" +005 "%lu numaralı satırda ekleme yapılamıyor" +006 "%lu numaralı satır kaydedilemiyor" +007 "Son satır alınamıyor" +008 "Hata: %lu numaralı satır okunamıyor" +009 "Günlük dosyası" +010 "Günlükleme gerçekleÅŸtirilmiyor, geri alma olanaklı deÄŸil" +011 "Geri alınacak bir deÄŸiÅŸiklik yok" +012 "Günlükleme gerçekleÅŸtirilmiyor, geri alma olanaklı deÄŸil" +013 "Günlükleme gerçekleÅŸtirilmiyor, ileri sarma olanaklı deÄŸil" +014 "Yinelenecek bir deÄŸiÅŸiklik yok" +015 "%s/%d: Günlük kayıt hatası" +016 "Vi'nin standart girdisi ve çıktısı bir uçbirim olmalı" +017 "Ä°m %s: Ayarlanmamış" +018 "Ä°m %s: Satır silinmiÅŸ" +019 "Ä°m %s: Ä°mleç konumu artık yok" +020 "Hata: " +021 "yeni dosya +022 "adı deÄŸiÅŸti" +023 "deÄŸiÅŸtirildi" +024 "deÄŸiÅŸtirilmedi" +025 "KÄ°LÄ°DÄ° AÇILDI" +026 "saltokunur" +027 "satır %lu/%lu [%ld%%]" +028 "boÅŸ dosya" +029 "%lu. satır" +030 "%s dosyası bir ileti kataloÄŸu deÄŸil" +031 "Öntanımlı %s seçeneÄŸi ayarlanamadı" +032 "Kullanım: %s" +033 "set: %s seçeneÄŸi yok: 'set all' tüm seçenek deÄŸerlerini verir" +034 "set: [no]%s seçeneÄŸi bir deÄŸer almaz" +035 "set: %s seçeneÄŸi bir Boole deÄŸeri deÄŸil" +036 "set: %s seçeneÄŸi: %s" +037 "set: %s seçeneÄŸi: %s: DeÄŸer taşımı" +038 "set: %s seçeneÄŸi: %s izin verilmeyen bir sayı" +039 "set: %s seçeneÄŸi bir Boole deÄŸeri deÄŸil" +040 "Ekran sütun sayısı çok küçük, ÅŸundan daha az: %d" +041 "Ekran sütun sayısı çok büyük, ÅŸundan daha çok: %d" +042 "Ekran satır sayısı çok küçük, ÅŸundan daha az: %d" +043 "Ekran satır sayısı çok büyük, ÅŸundan daha çok: %d" +044 "Lisp seçeneÄŸi eklenmemiÅŸ" +045 "Ä°letiler kapatılmamış: %s" +046 "Ä°letiler açılmamış: %s" +047 "%s seçeneÄŸi iki karakterli öbekler biçiminde olmalı" +053 "BaÅŸlangıç arabelleÄŸi boÅŸ" +054 "%s arabelleÄŸi boÅŸ" +056 "Oturum baÅŸarısız olursa deÄŸiÅŸiklikler kurtarılamaz" +057 "Dosya, kurtarma için kopyalanıyor..." +058 "Koruma baÅŸarısız oldu: %s" +059 "Oturum baÅŸarısız olursa deÄŸiÅŸiklikler kurtarılamaz" +060 "Dosya yedeklemesi baÅŸarısız oldu: %s" +061 "Dosya, kurtarma için kopyalanıyor..." +062 "%u kullanıcısı üzerine bilgi bulunamadı" +063 "Kurtarma dosyası kilitlenemiyor" +065 "Kurtarma dosyası" +066 "%s: Hatalı oluÅŸturulmuÅŸ kurtarma dosyası" +067 "%s: Hatalı oluÅŸturulmuÅŸ kurtarma dosyası" +068 "Kurtarılacak %s adında sizce okunabilir bir dosya yok" +069 "Bu dosyanın kurtarabileceÄŸiniz eski sürümleri var" +070 "KurtarabileceÄŸiniz baÅŸka dosyalar var" +071 "E-posta gönderilmedi: %s" +072 "Dosya boÅŸ, aranacak bir ÅŸey yok" +073 "Dizgi bulunamadan dosyanın sonuna eriÅŸildi" +074 "Arama dizgisi yok" +075 "Dizgi bulunamadı" +076 "Dizgi bulunamadan dosyanın başına eriÅŸildi" +077 "Arama tamamlandı" +078 "Aranıyor..." +079 "Yazdırılamaz karakter bulunmadı" +080 "Bilinmeyen komut adı" +082 "%s: Komut ex kipinde kullanılamaz" +083 "Sayım sıfır olmayabilir" +084 "%s: Hatalı satır belirtimi" +085 "İç sözdizim tablo hatası (%s: %s)" +086 "Kullanım: %s" +087 "%s: Geçici arabellek salıverilmedi" +088 "Bayrak göreli konumu birinci satırdan önceye" +089 "Bayrak göreli konumu dosya sonunu geçiyor" +090 "Erimli @, dosya/ekran deÄŸiÅŸtiÄŸinde çalışır" +091 "Global/v komutu dosya/ekran deÄŸiÅŸtiÄŸinde çalışır" +092 "Ex komutu baÅŸarısız: Sıradaki komutlar çıkarıldı" +093 "Ex komutu baÅŸarısız: EÅŸlemlenen düğmeler çıkarıldı" +094 "Ä°kinci adres ilkinden daha küçük" +095 "Bir im adı saÄŸlanmadı" +096 "\\ sonrasında / veya ? gelmiyor" +097 "Bir satır numarasına yapılan baÅŸvuru sayısı sıfırdan az" +098 "Bilinmeyen komut: %s" +099 "Adres deÄŸeri taşımı" +100 "Adres deÄŸeri alttaşımı" +101 "Ä°zin verilmeyen adres birleÅŸimi" +102 "Ä°zin verilmeyen adres: Dosyada yalnızca %lu satır var" +103 "Ä°zin verilmeyen adres: Dosya boÅŸ" +104 "%s komutu bir 0 adresine izin vermiyor" +105 "Görüntülenecek kısaltma yok" +106 "Kısaltmalar bir \"sözcük\" karakteri ile bitmelidir" +107 "Kısaltmalar sekme veya boÅŸluk içeremez" +108 "Kısaltmalar sonu dışında sözcük/sözcük olmayan karakterleri karıştıramaz" +109 "\"%s\" bir kısaltma deÄŸil" +110 "Vi komutu baÅŸarısız: EÅŸlemlenen düğmeler çıkarıldı" +111 "Düzenlenecek baÅŸka dosya yok" +112 "Öncesinde düzenlenecek baÅŸka dosya yok" +113 "Öncesinde geri sarılacak dosyalar yok" +114 "Görüntülenecek dosya yok" +115 "Öncesinde \"!\" ögesinin yerine geçecek bir komut yok" +116 "%% yerine geçecek bir dosya adı yok" +117 "# yerine geçecek bir dosya adı yok" +118 "Hata: execl: %s" +119 "Girdi/Çıktı hatası: %s" +120 "Dosya son tam yazımdan bu yana deÄŸiÅŸtirilmiÅŸ; yazın veya yok saymak için ! kullanın" +121 "Ev dizini konumu bulunamıyor" +122 "Yeni ÅŸimdiki dizin: %s" +123 "Görüntülenecek kesilmiÅŸ arabellek yok" +124 "%s komutu bir global veya v komutunun parçası olarak kullanılamaz" +128 "%s: kaynak alınmıyor: Ä°yesi siz veya kök deÄŸil" +129 "%s: kaynak alınmıyor: Ä°yesi siz deÄŸilsiniz" +130 "%s: kaynak alınmıyor: Ä°yesi dışında baÅŸka bir kullanıcı tarafından yazılabilir" +131 "Uç uca eklenecek bir satır yok" +132 "Girdi eÅŸlem girdisi yok" +133 "Komut eÅŸlem girdisi yok" +134 "%s yeniden eÅŸlemlenemeyebilir" +135 "\"%s\" ÅŸu anda eÅŸlemlenmemiÅŸ" +136 "Ä°m adları tek bir karakter olmalıdır" +137 "%s mevcut, yazılmamış; yok saymak için ! kullanın" +138 "Yeni exrc dosyası: %s" +139 "Hedef satırı taşıma erimi içinde" +140 "'open' komutu 'open' seçeneÄŸinin ayarlı olmasını gerektirir" +141 "'open' komutu henüz eklenmemiÅŸ" +142 "Bu dosyanın korunması olanaklı deÄŸil" +143 "Dosya korundu" +144 "%s: Çok fazla dosya adına geniÅŸletilmiÅŸ" +145 "Yalnızca sıradan dosyalar ve adlandırılmış veri yolları okunabilir" +146 "%s: Okuma kilidi kullanılabilir deÄŸildi" +147 "Okunuyor..." +148 "%s: %lu satır, %lu karakter" +149 "Görüntülenecek arkaplan ekranı yok" +150 "'script' komutu yalnızca vi kipinde kullanılabilir" +151 "Çalıştırılacak komut yok" +152 "'shiftwidth' seçeneÄŸi 0 olarak ayarlanmış" +153 "Sayım taşımı" +154 "Sayım alttaşımı" +155 "Düzenli ifade belirtilmiÅŸ; r bayrağı anlamsız" +156 "#, l ve p bayrakları vi kipinde c bayrağı ile birlikte kullanılamaz" +157 "EÅŸleÅŸme bulunamadı" +158 "Önceden bir etiket girilmemiÅŸ" +159 "Etiket yığınında %s sayısından az girdi; :display t[ags] kullanın" +160 "Etiket yığınında dönülecek bir %s dosyası yok; :display t[ags] kullanın" +161 "Sürdürmek için Enter'a basın:" +162 "%s: Etiket bulunamadı" +163 "%s: %s içinde hasar görmüş etiket" +164 "%s: Etiketin satır numarası dosya sonunu geçmiÅŸ" +165 "Etiket yığını boÅŸ" +166 "%s: Arama dizgisi bulunamadı" +167 "%d dosya daha düzenlenecek" +168 "%s arabelleÄŸi boÅŸ" +169 "DeÄŸiÅŸikliÄŸi onayla? [n]" +170 "Yarıda kesildi" +171 "Öncesinde çalıştırılacak arabellek yok" +172 "Öncesinde düzenli ifade yok" +173 "%s komutu bir dosyanın halihazırda okunmuÅŸ olmasını gerektirir" +174 "Kullanım: %s" +175 "'visual' komutu 'open' seçeneÄŸinin ayarlanmış olmasını gerektirir" +177 "BoÅŸ dosya" +178 "Öncesinde F, f, T veya t araması yok" +179 "%s bulunamadı" +180 "Düzenlenecek dosya yok" +181 "Ä°mleç bir sayıda deÄŸil" +182 "Ortaya çıkan sayı çok büyük" +183 "Ortaya çıkan sayı çok küçük" +184 "Bu satırda eÅŸleÅŸen karakter yok" +185 "EÅŸleÅŸen karakter bulunamadı" +186 "DeÄŸiÅŸtirilecek karakter yok" +187 "Geçilecek baÅŸka ekran yok" +188 "Arama dizgisinden, satır ofsetinden ve/veya 'z' komutundan sonraki karakterler" +189 "Öncesinde arama dizgisi yok" +190 "Arama baÅŸlanan konumda tamamlandı" +191 "Kısaltma geniÅŸleme sınırını aÅŸtı: Karakterler çıkarıldı" +192 "Ä°zin verilmeyen karakter; giriÅŸ için tırnak içine alın" +193 "Halihazırda eklemenin başında" +194 "Silinecek baÅŸka karakter yok" +195 "Hareket dosya sonunu geçti" +196 "Hareket satır sonunu geçti" +197 "Ä°mleç hareket ettirilmedi" +198 "Halihazırda dosyanın başında" +199 "Hareket dosyanın başını geçti" +200 "Halihazırda ilk sütunda" +201 "Arabellekler komuttan önce belirtilmeli" +202 "Halihazırda dosya sonunda" +203 "Halihazırda satır sonunda" +204 "%s bir vi komutu deÄŸil" +205 "Kullanım: %s" +206 "Silinecek karakter yok" +207 "Q komutu ex uçbirim arabirimini gerektirir" +208 "Yinelenecek komut yok" +209 "Dosya boÅŸ" +210 "%s bir hareket komutu olarak kullanılamaz" +211 "Halihazırda komut kipi içinde" +212 "Ä°mleç bir sözcükte deÄŸil" +214 "'windows' seçeneÄŸi deÄŸeri çok büyük, en çok %u olabilir" +215 "Ä°liÅŸtir" +216 "DeÄŸiÅŸiklik yap" +217 "Komut" +218 "Ekle" +219 "DeÄŸiÅŸtir" +220 "Hareket ekran sonunu geçti" +221 "Hareket ekran başını geçti" +222 "Ekran bölünebilmesi için %d satırdan daha geniÅŸ olmalıdır" +223 "Arkaplan ekranı yok" +224 "Arkaplanda %s dosyasını düzenleyen bir ekran yok" +225 "Açık olan tek ekranınızı arkaplana alamazsınız" +226 "Ekran yalnızca %d satıra küçültülebilir" +227 "Ekran küçülemez" +228 "Ekran büyüyemez" +230 "Bu ekran askıya alınamaz" +231 "Yarıda kesildi: EÅŸlemlenen düğmeler çıkarıldı" +232 "vi: Geçici arabellek salıverilmedi" +233 "Bu uçbirimde %s düğmesi yok" +234 "Yalnızca bir arabellek belirtilebilir" +235 "Sayı ÅŸundan daha büyük: %lu" +236 "Yarıda kesildi" +237 "Geçici dosya oluÅŸturulamıyor" +238 "Uyarı: %s sıradan bir dosya deÄŸil" +239 "%s halihazırda kilitlenmiÅŸ, oturum saltokunur" +240 "%s: Kaldır" +241 "%s: Kapat" +242 "%s: Kaldır" +243 "%s: Kaldır" +244 "Saltokunur dosya, yazılmadı; yok saymak için ! kullanın" +245 "Saltokunur dosya, yazılmadı" +246 "%s mevcut, yazılmadı; yok saymak için ! kullanın" +247 "%s mevcut, yazılmadı" +248 "Kısmi dosya, yazılmadı; yok saymak için ! kullanın" +249 "Kısmi dosya, yazılmadı" +250 "%s: Dosya bu kopyadan daha önce deÄŸiÅŸtirilmiÅŸ; yok saymak için ! kullanın" +251 "%s: Dosya bu kopyadan daha önce deÄŸiÅŸtirilmiÅŸ" +252 "%s: Yazım koruması kullanılabilir deÄŸildi" +253 "Yazılıyor..." +254 "%s: UYARI: DOSYA KIRPILMIÅž" +255 "Halihazırda bu grubun ilk etiketinde" +256 "%s: Yeni dosya: %lu satır, %lu karakter" +257 "%s: %lu satır, %lu karakter" +258 "%s çok fazla dosya adına geniÅŸletilmiÅŸ" +259 "%s: Sıradan bir dosya deÄŸil" +260 "%s: Ä°yesi siz deÄŸilsiniz" +261 "%s: Ä°yesi dışında baÅŸka bir kullanıcı tarafından da eriÅŸilebilir" +262 "Dosya son tam yazımdan bu yana deÄŸiÅŸtirilmiÅŸ; yazın veya yok saymak için ! kullanın" +263 "Dosya son tam yazımdan bu yana deÄŸiÅŸtirilmiÅŸ; yazın veya yok saymak için :edit! kullanın" +264 "Dosya son tam yazımdan bu yana deÄŸiÅŸtirilmiÅŸ; yazın veya yok saymak için ! kullanın" +265 "Dosya geçici; çıkarsanız deÄŸiÅŸiklikler atılacaktır" +266 "Dosya saltokunur, deÄŸiÅŸiklikler kendiliÄŸinden yazılmaz" +267 "Günlük yeniden baÅŸlatıldı" +268 "Onayla? [ynq]" +269 "Sürdürmek için herhangi bir düğmeye basın: " +270 "Sürdürmek için herhangi bir düğmeye basın [ex komutu girmek için :]: " +271 "Sürdürmek için herhangi bir düğmeye basın [çıkış için q]: " +272 "Bu biçim %s ex uçbirim arabirimini gerektirir" +273 "ex girdisi kipine giriliyor" +274 "Komut baÅŸarısız, henüz bir dosya okunmadı." +275 " sürdür?" +276 "Beklenmedik karakter olayı" +277 "Beklenmedik dosya sonu olayı" +278 "Sorgu eÅŸleÅŸmesi bulunamadı" +279 "Beklenmedik yarıda kesme olayı" +281 "Beklenmedik yeniden boyama olayı" +282 "Halihazırda bu grubun son etiketinde" +283 "%s komutu ex uçbirim arabirimini gerektirir" +284 "Bu biçim %s 'secure edit' seçeneÄŸi ayarlandığında desteklenmez" +285 "Beklenmedik dizi olayı" +286 "Beklenmedik zaman aşımı olayı" +288 "Bölünebilmesi için ekran %d sütundan daha geniÅŸ olmalıdır" +289 "Kabuk geniÅŸletmeleri 'secure edit' seçeneÄŸi ayarlandığında desteklenmez" +290 "%s komutu 'secure edit' seçeneÄŸi ayarlandığında desteklenmez" +291 "set: %s seçeneÄŸi kapatılamaz" +292 "Ekran çok küçük." +293 "eklendi" +294 "deÄŸiÅŸtirildi" +295 "silindi" +296 "uç uca eklendi" +297 "taşındı" +298 "kaydırıldı" +299 "kopyalandı" +300 "satır" +301 "satır" +303 "Dosya son yazımdan bu yana deÄŸiÅŸtirilmiÅŸ." +304 "Kabuk geniÅŸletmesi baÅŸarısız" +305 "Bir '%s' düzenleme seçeneÄŸi belirtilmedi" +307 "Çalıştırılacak ex komutu yok" +308 "Bir komut çalıştırmak için , çıkmak için :q girin" +309 "Yardım için \"cscope help\" kullanın" +310 "Çalışan bir cscope baÄŸlantısı yok" +311 "%s: Bilinmeyen arama türü: Åžunlardan bir tanesini kullanın: %s" +312 "%d: Böyle bir cscope oturumu yok" +313 "set: %s seçeneÄŸi hiçbir zaman açılamaz" +314 "set: %s seçeneÄŸi hiçbir zaman 0 olarak ayarlanamaz" +315 "%s: Ä°liÅŸtirildi: %lu satır, %lu karakter" +316 "Beklenmedik yeniden boyutlandırma olayı" +317 "Düzenlenecek %d dosya var" +319 "%d ekran arkaplana alındı; onları listelemek için :display kullanın" +320 "Bilinmeyen imleç konumu" +321 "Dosya kodlama dönüştürmesi desteklenmiyor" +322 "Girdi kodlama dönüştürmesi desteklenmiyor" +323 "Geçersiz girdi. Kırpıldı." +324 "%d numaralı satırda dönüştürme hatası" Index: vendor/nvi/2.2.0-05ed8b9/catalog/tr_TR.UTF-8.owner =================================================================== --- vendor/nvi/2.2.0-05ed8b9/catalog/tr_TR.UTF-8.owner (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/catalog/tr_TR.UTF-8.owner (revision 366308) @@ -0,0 +1 @@ +Emir SARI Index: vendor/nvi/2.2.0-05ed8b9/catalog/dutch.base =================================================================== --- vendor/nvi/2.2.0-05ed8b9/catalog/dutch.base (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/catalog/dutch.base (revision 366308) @@ -0,0 +1,306 @@ +002 "regel te lang" +003 "kan regel %lu niet verwijderen" +004 "kan niet toevoegen aan regel %lu" +005 "kan niet invoegen vooraan regel %lu" +006 "kan regel %lu niet opslaan" +007 "kan laatste regel niet lezen" +008 "Fout: kan regel %lu niet vinden" +009 "log bestand" +010 "Er vindt geen logging plaats, kan wijzigingen niet ongedaan maken" +011 "geen wijzigingen om ongedaan te maken" +012 "Er vindt geen logging plaats, kan wijzigingen niet ongedaan maken" +013 "Er vindt geen logging plaats, herhaling niet mogelijk" +014 "geen wijzigingen om te herhalen" +015 "%s/%d: schrijven naar log mislukt" +016 "Vi's standaard invoer en uitvoer moeten aan een terminal gekoppeld zijn" +017 "Merk %s: niet gezet" +018 "Merk %s: de regel is verwijderd" +019 "Merk %s: de cursor positie bestaat niet meer" +020 "Fout: " +021 "nieuw bestand" +022 "naam veranderd" +023 "gewijzigd" +024 "ongewijzigd" +025 "NIET BEVEILIGD" +026 "niet schrijfbaar" +027 "regel %lu uit %lu [%ld%%]" +028 "leeg bestand" +029 "regel %lu" +030 "Het bestand %s is geen message catalog" +031 "Niet in staat om de standaard %s optie in te stellen" +032 "Gebruik: %s" +033 "set: optie %s onbekend: 'set all' laat alle opties zien" +034 "set: [no]%s optie kan geen waarde hebben" +035 "set: %s optie moet een waarde hebben" +036 "set: %s optie: %s" +037 "set: %s optie: %s: getal is te groot" +038 "set: %s optie: %s is een ongeldige waarde" +039 "set: %s optie moet een waarde hebben" +040 "Te weinig kolommen op het scherm, minder dan %d" +041 "Aantal kolommen te groot, meer dan %d" +042 "Te weinig regels op het scherm, minder dan %d" +043 "Aantal regels te groot, meer dan %d" +044 "De lisp optie is niet ondersteund" +045 "messages niet uitgeschakeld: %s" +046 "messages niet geactiveerd: %s" +047 "De %s optie moet karakter paren bevatten" +053 "De standaard buffer is leeg" +054 "Buffer %s is leeg" +055 "Bestanden met newlines in de naam kunnen niet hersteld worden" +056 "Wijzigingen kunnen niet ongedaan gemaakt worden als deze sessie mislukt" +057 "Bestand wordt gecopieerd voor herstel..." +058 "Herstel mechanisme werkt niet: %s" +059 "Wijzigingen kunnen niet ongedaan gemaakt worden als deze sessie mislukt" +060 "Kon bestand niet veilig stellen: %s" +061 "Bestand wordt gecopieerd voor herstel..." +062 "Informatie met betrekking tot gebruiker nummer %u niet gevonden" +063 "Kan herstel bestand niet beveiligen" +064 "herstel buffer overgelopen" +065 "herstel bestand" +066 "%s: verminkt herstel bestand" +067 "%s: verminkt herstel bestand" +068 "U heeft geen bestand genaamd %s te herstellen" +069 "U kan eerdere versies van dit bestand herstellen" +070 "U kan nog meer bestanden herstellen" +071 "kan geen email versturen: %s" +072 "Bestand leeg; niets om te doorzoeken" +073 "Einde van het bestand bereikt zonder dat het patroon gevonden is" +074 "Geen vorig zoek patroon" +075 "Patroon niet gevonden" +076 "Begin van het bestand bereikt zonder dat het patroon gevonden is" +077 "Zoek-operatie omgeslagen" +078 "Bezig met zoeken..." +079 "Geen niet-printbaar karakter gevonden" +080 "Onbekend commando" +082 "Commando niet beschikbaar in ex mode" +083 "Aantal mag niet nul zijn" +084 "%s: ongeldige regel aanduiding" +085 "Interne fout in syntax tabel (%s: %s)" +086 "Gebruik: %s" +087 "%s: tijdelijke buffer niet vrijgegeven" +088 "Vlag offset voor regel 1" +089 "Vlag offset voorbij bestands einde" +090 "bestand/scherm veranderd tijdens uitvoeren van @ in een blok" +091 "bestand/scherm veranderd tijdens uitvoeren van globaal/v commando" +092 "Ex commando mislukt: rest van commando(s) genegeerd" +093 "Ex commando mislukt: gemappede toetsen genegeerd" +094 "Het tweede adres is kleiner dan het eerste" +095 "Geen merk naam opgegeven" +096 "\\ niet gevolgd door / of ?" +097 "Referentie aan een regel nummer kleiner dan 0" +098 "Het %s commando is onbekend" +099 "Adres waarde te groot" +100 "Adres waarde te klein" +101 "Ongeldige adres combinatie" +102 "Ongeldig adres: slechts %lu regels in het bestand aanwezig" +103 "Ongeldig adres: het bestand is leeg" +104 "Het %s commando staat het adres 0 niet toe" +105 "Geen afkortingen om weer te geven" +106 "Afkortingen moeten eindigen met een \"woord\" letter" +107 "Afkortingen mogen geen tabulaties of spaties bevatten" +108 "Afkortingen mogen geen woord/niet-woord karakters mengen, behalve aan het einde" +109 "\"%s\" is geen afkorting" +110 "Vi commando mislukt: gemappede toetsen genegeerd" +111 "Dit is het laatste bestand" +112 "Dit is het eerste bestand" +113 "Dit is het eerste bestand" +114 "lijst met bestanden is leeg" +115 "Geen voorgaand commando om \"!\" te vervangen" +116 "Geen bestandsnaam voor %%" +117 "Geen bestandsnaam voor #" +118 "Fout: execl: %s" +119 "I/O fout: %s" +120 "Bestand gewijzigd sinds laatste schrijfactie; schrijf het weg of gebruik ! om het te forceren" +121 "Kan uw home directory niet vinden" +122 "Nieuwe huidige directory: %s" +123 "Geen cut buffers aanwezig" +124 "Het %s commando kan niet gebruikt worden in een globaal of v commando" +125 "%s/%s: niet gelezen: noch U noch root is de eigenaar" +126 "%s/%s: niet gelezen: U bent niet de eigenaar" +127 "%s/%s: niet gelezen: kan gewijzigd worden door andere gebruikers" +128 "%s: niet gelezen: noch U noch root is de eigenaar" +129 "%s: niet gelezen: U bent niet de eigenaar" +130 "%s: niet gelezen: kan gewijzigd worden door andere gebruikers" +131 "Geen volgende regel om samen te voegen" +132 "Geen input map entries" +133 "Geen command map entries" +134 "Het %s karakter kan niet ge-remapped worden" +135 "\"%s\" is niet gemapped" +136 "Merk naam moet een enkel karakter zijn" +137 "%s bestaat al, niet weggeschreven; gebruik ! om het te forceren" +138 "Nieuw .exrc bestand: %s. " +139 "doel regel ligt in het blok" +140 "Het open commando vereist dat de open optie actief is" +141 "Het open commando is nog niet ondersteund" +142 "Kan dit bestand niet veilig stellen" +143 "Bestand veilig gesteld" +144 "%s resulteert in te veel bestandsnamen" +145 "Alleen echte bestanden en named pipes kunnen gelezen worden" +146 "%s: lees beveiliging niet beschikbaar" +147 "Bezig met lezen..." +148 "%s: %lu regels, %lu karakters" +149 "Geen achtergrond schermen aanwezig" +150 "Het script commando is alleen beschikbaar in vi mode" +151 "Geen comando om uit te voeren" +152 "shiftwidth optie op 0 gezet" +153 "Count te groot" +154 "Count te klein" +155 "Reguliere expressie opgegeven; r vlag heeft geen betekenis" +156 "De #, l en p vlaggen kunnen niet gecombineerd worden met de c vlag in vi mode" +157 "Geen match gevonden" +158 "Geen voorafgaande tag aanwezig" +159 "Minder dan %s elementen op de tags stapel; gebruik :display t[ags]" +160 "Geen bestand genaamd %s op de tags stapel; gebruik :display t[ags]" +161 "Kies Enter om door te gaan: " +162 "%s: tag niet gevonden" +163 "%s: verminkte tag in %s" +164 "%s: Het regel nummer van deze tag is voorbij het einde van het bestand" +165 "De tags stapel is leeg" +166 "%s: zoek patroon niet gevonden" +167 "%d andere bestanden te wijzigen" +168 "Buffer %s is leeg" +169 "Bevestig wijziging? [n]" +170 "Onderbroken" +171 "Geen voorafgaande buffer om uit te voeren" +172 "Geen vorige reguliere expressie" +173 "Het %s commando vereist dat er een bestand geladen is" +174 "Gebruik: %s" +175 "Het visual commando vereist dat de open optie actief is" +177 "Leeg bestand" +178 "Geen voorafgaand F, f, T of t zoek commando" +179 "%s niet gevonden" +180 "Geen voorafgaand bestand te bewerken" +181 "Cursor niet op een getal" +182 "Getal wordt te groot" +183 "Getal wordt te klein" +184 "Geen overeenkomstig karakter op deze regel" +185 "Overeenkomstig karakter niet gevonden" +186 "Geen karakters te vervangen" +187 "Geen ander scherm aanwezig" +188 "Karakters achter het zoek patroon, de regel offset, en/of het z commando" +189 "Geen voorafgaand zoek patroon" +190 "Zoekopdracht na omslag teruggekeerd op originele positie" +191 "Afkorting overschrijdt expansie limiet: karakters genegeerd" +192 "Ongeldig karakter; quote to enter" +193 "Reeds aan het begin van de invoer" +194 "Niet meer karakters te verwijderen" +195 "Verplaatsing voorbij het einde van het bestand" +196 "Verplaatsing voorbij het einde van de regel" +197 "Cursor niet verplaatst" +198 "Reeds aan het begin van het bestand" +199 "Verplaatsing voorbij het begin van het bestand" +200 "Reeds in de eerste kolom" +201 "Buffers moeten voor het commando opgegeven worden" +202 "Reeds bij het einde van het bestand" +203 "Reeds bij het einde van de regel" +204 "%s is geen vi commando" +205 "Gebruik: %s" +206 "Geen karakters te verwijderen" +207 "Het Q commando vereist de ex terminal interface" +208 "Geen commando om te herhalen" +209 "Het bestand is leeg" +210 "%s mag niet gebruikt worden als een verplaatsings commando" +211 "Al in commando mode" +212 "Cursor niet in een woord" +214 "Windows optie waarde is te groot, maximum is %u" +215 "Toevoegen" +216 "Veranderen" +217 "Commando" +218 "Invoegen" +219 "Vervangen" +220 "Verplaatsing voorbij het eind van het scherm" +221 "Verplaatsing voorbij het begin van het scherm" +222 "Scherm moet meer dan %d regels hebben om het te kunnen splitsen" +223 "Er zijn geen achtergrond schermen" +224 "Er is geen achtergrond scherm waarin U bestand %s aan het bewerken bent" +225 "U kan uw enige scherm niet in de achtergrond zetten" +226 "Het scherm kan slechts verkleind worden tot %d regels" +227 "Het scherm kan niet kleiner" +228 "Het scherm kan niet groter" +230 "Dit scherm kan niet gesuspend worden" +231 "Onderbroken: gemappede toetsen genegeerd" +232 "vi: tijdelijke buffer niet vrijgegeven" +233 "Deze terminal heeft geen %s toets" +234 "Er kan slechts een buffer opgegeven worden" +235 "Getal groter dan %lu" +236 "Onderbroken" +237 "Aanmaken van tijdelijk bestand is mislukt" +238 "Waarschuwing: %s is geen regulier bestand" +239 "%s is al geopend, bestand is in deze sessie niet schrijfbaar" +240 "%s: verwijdering mislukt" +241 "%s: sluiting mislukt" +242 "%s: verwijdering mislukt" +243 "%s: verwijdering mislukt" +244 "Bestand niet schrijfbaar, niet weggeschreven; gebruik ! om het te forceren" +245 "Bestand niet schrijfbaar, niet weggeschreven" +246 "%s bestaat al, niet weggeschreven; gebruik ! om het te forceren" +247 "%s bestaat al, niet weggeschreven" +248 "Gebruik ! om een incompleet bestand weg te schrijven" +249 "Bestand incompleet, niet weggeschreven" +250 "%s: bestand op disk nieuwer dan deze versie; gebruik ! om het te forceren" +251 "%s: bestand op disk nieuwer dan deze versie" +252 "%s: schrijf beveiliging niet beschikbaar" +253 "Bezig met schrijven..." +254 "%s: WAARSCHUWING: BESTAND INCOMPLEET" +255 "Reeds op de eerste tag van deze groep" +256 "%s: nieuw bestand: %lu regels, %lu karakters" +257 "%s: %lu regels, %lu karakters" +258 "%s resulteert in te veel bestandsnamen" +259 "%s: geen normaal bestand" +260 "%s: U bent niet de eigenaar" +261 "%s: kan gewijzigd worden door andere gebruikers" +262 "Bestand gewijzigd sinds laatste schrijfactie; schrijf het weg of gebruik ! om het te forceren" +263 "Bestand gewijzigd sinds laatste schrijfactie; schrijf het weg of gebruik :edit! om het te forceren" +264 "Bestand gewijzigd sinds laatste schrijfactie; schrijf het weg of gebruik ! om het te forceren" +265 "Tijdelijk bestand; exit negeert wijzigingen" +266 "Bestand niet schrijfbaar, wijzigingen niet automatisch weggeschreven" +267 "log opnieuw gestart" +268 "Bevestig? [ynq]" +269 "Druk op een toets om door te gaan: " +270 "Druk op een toets om door te gaan [: voor meer ex commandos]: " +271 "Druk op een toets om door te gaan [q om te stoppen]: " +272 "Deze vorm van %s vereist de ex terminal interface" +273 "Entering ex input mode." +274 "Commando mislukt, nog geen bestand geladen." +275 " doorgaan?" +276 "Onverwacht character event" +277 "Onverwacht end-of-file event" +278 "Geen match gevonden voor dit patroon" +279 "Onverwacht interrupt event" +280 "Onverwacht quit event" +281 "Onverwacht repaint event" +282 "Reeds op de laatste tag van deze groep" +283 "Het %s command vereist de ex terminal interface" +284 "Deze vorm van %s is niet ondersteund als de secure edit optie actief is" +285 "Onverwacht string event" +286 "Onverwacht timeout event" +287 "Onverwacht write event" +289 "Shell expansies zijn niet ondersteund als de secure edit optie actief is" +290 "Het %s commando is niet ondersteund als de secure edit optie actief is" +291 "set: %s mag niet uitgezet worden" +292 "Scherm te klein." +293 "toegevoegd" +294 "gewijzigd" +295 "verwijderd" +296 "samengevoegd" +297 "verplaatst" +298 "verschoven" +299 "gebufferd" +300 "regel" +301 "regels" +302 "Vi was niet geladen met een Tcl interpreter" +303 "Bestand gewijzigd sinds het de laatste keer weg is geschreven." +304 "Shell expansie mislukt" +305 "Geen %s edit optie opgegeven" +306 "Vi was niet geladen met een Perl interpreter" +307 "Geen ex commando om uit te voeren" +308 "Kies om commando uit te voeren, :q om te stoppen" +309 "Gebruik \"cscope help\" voor uitleg" +310 "Nog geen cscope connectie aanwezig" +311 "%s: onbekend zoek type: gebruik een van %s" +312 "%d: onbekende cscope sessie" +313 "set: de %s optie mag nooit aangezet worden" +314 "set: de %s optie mag nooit op 0 gezet worden" +315 "%s: toegevoegd: %lu regels, %lu karakters" +316 "Onverwacht resize event" +317 "%d bestanden te wijzigen" Property changes on: vendor/nvi/2.2.0-05ed8b9/catalog/dutch.base ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain; charset=iso-8859-1 \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/catalog/french.base =================================================================== --- vendor/nvi/2.2.0-05ed8b9/catalog/french.base (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/catalog/french.base (revision 366308) @@ -0,0 +1,306 @@ +002 "Dépassement de longueur de ligne" +003 "impossible de supprimer la ligne %lu" +004 "impossible d'ajouter à la ligne %lu" +005 "impossible d'insérer devant la ligne %lu" +006 "impossible de stocker la ligne %lu" +007 "impossible d'obtenir la dernière ligne" +008 "Erreur : impossible de récupérer la ligne %lu" +009 "Fichier journal" +010 "Aucune journalisation n'étant effectuée, impossible d'annuler" +011 "Aucune action à annuler" +012 "Aucune journalisation n'étant effectuée, impossible d'annuler" +013 "Aucune journalisation n'étant effectuée, reprise actualisée impossible" +014 "Aucune action à refaire" +015 "%s/%d : Erreur d'écriture de journal" +016 "L'entrée et la sortie Vi standards doivent être un terminal" +017 "Marque %s : non définie" +018 "Marque %s : la ligne a été supprimée" +019 "Marque %s : la position du curseur n'existe plus" +020 "Erreur : " +021 "nouveau fichier" +022 "le nom a changé" +023 "modifié" +024 "non modifié" +025 "DÉVERROUILLÉ" +026 "lecture seule" +027 "ligne %lu de %lu [%ld%%]" +028 "fichier vide" +029 "ligne %lu" +030 "Ce fichier %s n'est pas un catalogue de messages" +031 "Impossible de configurer option %s par défaut" +032 "Utilisation : %s" +033 "Définition : pas d'option %s : 'set all' donne toutes les valeurs optionnelles" +034 "Définition : option [no]%s ne prend pas de valeur" +035 "Définition : l'option %s n'est pas booléenne" +036 "Définition : option %s : %s" +037 "Définition : option %s : %s : Dépassement de valeur" +038 "Définition : option %s : %s n'est pas un nombre valide" +039 "Définition : l'option %s n'est pas booléenne" +040 "Les colonnes de l'écran sont trop petites, inférieures à %d" +041 "Les colonnes de l'écran sont trop grandes, supérieures à %d" +042 "Les lignes de l'écran sont trop courtes, inférieures à %d" +043 "Les lignes de l'écran sont trop longues, supérieures à %d" +044 "L'option lisp n'est pas implémentée" +045 "Les messages ne sont pas désactivés : %s" +046 "Les messages ne sont pas activés : %s" +047 "L'option de %s doit être en groupe de deux caractères" +053 "Le tampon par défaut est vide" +054 "Le tampon %s est vide" +055 "Les fichiers dont le nom contient des caractères de saut de ligne sont irrécupérables" +056 "Impossible de récupérer les modifications si la session échoue" +057 "Copie en cours du fichier pour récupération..." +058 "La préservation a échoué : %s" +059 "Impossible de récupérer les modifications si la session échoue" +060 "La sauvegarde du fichier a échoué : %s" +061 "Copie en cours du fichier pour récupération..." +062 "Les renseignements sur l'identité %u de l'utilisateur sont introuvables" +063 "Impossible de verrouiller le fichier de récupération" +064 "Débordement de tampon du fichier de récupération" +065 "Fichier de récupération" +066 "%s : Fichier de récupération malformé" +067 "%s : Fichier de récupération malformé" +068 "Aucun fichier nommé %s à récupérer, que vous puissiez lire" +069 "Il existe des versions récupérables antérieures à ce fichier" +070 "Vous avez d'autres fichiers à récupérer" +071 "pas d'envoi d'email : %s" +072 "Fichier vide, rien à rechercher" +073 "Fin de fichier atteinte sans trouver le motif" +074 "Pas de motif de recherche précédent" +075 "Motif introuvable" +076 "Début du fichier atteint sans trouver le motif" +077 "La recherche est revenue à son point de départ" +078 "Recherche en cours..." +079 "Caractère non-imprimable introuvable" +080 "Nom de commande inconnu" +082 "%s : Commande non disponible en ex mode" +083 "Le compteur ne peut être zéro" +084 "%s : mauvaise spécification de ligne" +085 "Erreur de tableau de syntaxe interne (%s: %s)" +086 "Utilisation : %s" +087 "%s : tampon temporaire non libéré" +088 "Décalage de drapeau hors de la ligne 1" +089 "Décalage de drapeau hors de la fin du fichier" +090 "@ avec plage, en cours d'exécution quand le fichier/l'écran a changé" +091 "Commande Global/v en cours d'exécution quand le fichier/l'écran a changé" +092 "La commande ex a échoué : commandes en attente abandonnées" +093 "La commande ex a échoué : les touches affectées sont abandonnées" +094 "La deuxième adresse est plus petite que la première" +095 "Aucun nom de marque fourni" +096 "\\ non suivi par / ou ?" +097 "Référence à un numéro de ligne inférieure à 0" +098 "La commande %s est inconnue" +099 "Dépassement de la valeur adresse" +100 "Dépassement négatif de la valeur adresse" +101 "Combinaison d'adresse non valide" +102 "Adresse non valide : il n'y a que %lu lignes dans ce fichier" +103 "Adresse non valide : le fichier est vide" +104 "La commande %s ne permet pas une adresse de 0" +105 "Pas d'abréviations à afficher" +106 "Les abréviations doivent finir par un caractère \"mot\"" +107 "Les abréviations ne peuvent pas contenir de tabulations ni d'espaces" +108 "Les abréviations ne peuvent pas contenir un mélange de caractères mot/non-mot, sauf à la fin" +109 "\"%s\" n'est pas une abréviation" +110 "La commande Vi a échoué : Les touches affectées ont été abandonnées" +111 "Plus de fichiers à éditer" +112 "Pas de fichiers précédents à éditer" +113 "Pas de fichiers précédents à rembobiner" +114 "Pas de liste de fichiers à afficher" +115 "Pas de commande précédente à remplacer \"!\"" +116 "Pas de nom de fichier à substituer à %%" +117 "Pas de nom de fichier à substituer à #" +118 "Erreur : execl : %s" +119 "Erreur E/S : %s" +120 "Fichier modifié depuis la dernière écriture complète ; écrire ou utiliser ! pour outrepasser" +121 "Impossible de trouver l'emplacement du répertoire d'origine" +122 "Nouveau répertoire en cours : %s" +123 "Pas de tampon de coupure à afficher" +124 "La commande %s ne peut pas être utilisée à l'intérieur d'une commande globale ou commande v" +125 "%s/%s : échec de source : ni vous ni le super-utilisateur n'êtes les propriétaires " +126 "%s/%s : échec de source : vous n'êtes pas le propriétaire" +127 "%s/%s : échec de source : peut être écrit par un utilisateur autre que le propriétaire" +128 "%s : échec de source : ni vous ni le super-utilisateur n'êtes les propriétaires" +129 "%s : échec de source : vous n'êtes pas le propriétaire" +130 "%s : échec de source : peut être écrit par un utilisateur autre que le propriétaire" +131 "Pas de lignes suivantes à joindre" +132 "Pas d'entrées de mappage d'entrée" +133 "Pas d'entrées de mappage de commandes" +134 "Le caractère %s ne peut pas être remappé" +135 "\"%s\" n'est pas actuellement mappé" +136 "Les noms de marque ne doivent avoir qu'un caractère" +137 "%s existe, non enregistré; utiliser ! pour outrepasser" +138 "Nouveau fichier exrc : %s" +139 "La ligne de destination est à l'intérieur de la plage à déplacer" +140 "La commande ouverte nécessite que l'option ouverte soit définie" +141 "La commande ouverte n'est pas encore implémentée" +142 "La préservation de ce fichier est impossible" +143 "Fichier préservé" +144 "%s: étendu dans trop de noms de fichiers" +145 "Vous ne pouvez lire que les fichiers standards et les canaux de transmission nommés" +146 "%s: Interdiction de lecture non disponible" +147 "Lecture en cours..." +148 "%s: %lu lignes, %lu caractères" +149 "Pas d'écrans d'arrière-plan à afficher" +150 "La commande script n'est disponible qu'en mode vi" +151 "Pas de commande à exécuter" +152 "Option de largeur de décalage définie sur 0" +153 "Compter dépassement" +154 "Compter dépassement négatif" +155 "Expression standard spécifiée; drapeau r superflu" +156 "Vous ne pouvez pas en mode vi, combiner les drapeaux #, l et p avec le drapeau c" +157 "Aucune correspondance trouvée" +158 "Aucune marque précédente entrée" +159 "Moins de %s entrées dans la pile de marques ; utilisez t[ags]" +160 "Pas de fichier %s vers lequel retourner dans la pile de marques ; utiliser : affichage t[ags]" +161 "Appuyez sur Entrée pour continuer :" +162 "%s : marque introuvable" +163 "%s : marque corrompue en %s" +164 "%s : le numéro de ligne de la marque dépasse la fin du fichier" +165 "La pile de marques est vide" +166 "%s : motif de recherche introuvable" +167 "%d fichiers supplémentaires à éditer" +168 "Le tampon %s est vide +169 "Confirmer les changements ? [n]" +170 "Interrompu" +171 "Pas de tampon précédent à exécuter" +172 "Pas d'expression standard précédente" +173 "La commande %s nécessite qu'un fichier ait déjà été lu en mémoire" +174 "Utilisation : %s" +175 "La commande visual nécessite que l'option open soit définie" +177 "Fichier vide" +178 "Pas de recherche précédente F, f, T ou t" +179 "%s introuvable" +180 "Pas de fichier précédent à éditer" +181 "Le curseur n'est pas dans un nombre" +182 "Le nombre obtenu est trop grand" +183 "Le nombre obtenu est trop petit" +184 "Pas de correspondance de caractère sur cette ligne" +185 "Caractère correspondant introuvable" +186 "Pas de caractères à remplacer" +187 "Pas d'autre écran vers lequel basculer" +188 "Caractères après la chaîne de recherche, décalage de ligne et/ou commande z" +189 "Pas de motif de recherche précédent" +190 "La recherche est revenue à son point de départ" +191 "L'abréviation a dépassé la limite de l'expansion : caractères abandonnés" +192 "Caractère non valide ; guillemet pour saisir" +193 "Déjà au début de l'insertion" +194 "Plus de caractères à effacer" +195 "Déplacement hors de fin de fichier" +196 "Déplacement hors de fin de ligne" +197 "Aucun mouvement de curseur n'a été effectué" +198 "Déjà au début du fichier" +199 "Déplacement hors du début du fichier" +200 "Déjà dans la première colonne" +201 "Les tampons doivent être spécifiés avant la commande" +202 "Déjà à la fin du fichier" +203 "Déjà à la fin de la ligne" +204 "%s n'est pas une commande vi" +205 "Utilisation : %s" +206 "Pas de caractères à supprimer" +207 "La commande Q nécessite une interface terminal ex" +208 "Pas de commande à répéter" +209 "Le fichier est vide" +210 "Vous ne pouvez pas utiliser %s comme commande de déplacement" +211 "Déjà en mode commande" +212 "Le curseur n'est pas dans un mot" +214 "Valeur optionnelle de fenêtre trop grande, maximum est %u" +215 "Ajouter" +216 "Changer" +217 "Commande" +218 "Insérer" +219 "Remplacer" +220 "Déplacement hors de la fin d'écran" +221 "Déplacement hors du début d'écran" +222 "L'écran doit être supérieur à %d lignes pour se fractionner" +223 "Il n'y a pas d'écran d'arrière-plan" +224 "Il n'y a pas d'écran d'arrière-plan qui édite un fichier nommé %s" +225 "Vous ne pouvez pas mettre à l'arrière-plan votre seul écran affiché" +226 "L'écran ne peut être réduit qu'à %d rangs" +227 "L'écran n'est pas auto-réductible" +228 "L'écran n'est pas auto-extensible" +230 "Vous ne pouvez pas mettre cet écran en attente" +231 "Interrompu : les touches affectées ont été abandonnées" +232 "vi : le tampon temporaire n' a pas été libéré" +233 "Ce terminal n'a pas de touche %s" +234 "Vous ne pouvez spécifier qu'un seul tampon" +235 "Nombre supérieur à %lu" +236 "Interrompu" +237 "Impossible de créer un fichier temporaire" +238 "Avertissement : %s n'est pas un fichier standard" +239 "%s déjà verrouillé, session en lecture seule" +240 "%s: supprimer" +241 "%s: fermer" +242 "%s: supprimer" +243 "%s: supprimer" +244 "Fichier en lecture seule, non écrit, utiliser ! pour outrepasser" +245 "Fichier en lecture seule, non écrit" +246 "%s existe, non écrit; utiliser ! pour outrepasser" +247 "%s existe, non écrit" +248 "Fichier partiel, non écrit; utiliser ! pour outrepasser" +249 "Fichier partiel, non écrit" +250 "%s: fichier modifié plus récemment que cet exemplaire; utiliser ! pour outrepasser" +251 "%s: fichier modifié plus récemment que cet exemplaire" +252 "%s: interdiction d'écriture non disponible" +253 "Ecriture en cours..." +254 "%s: AVERTISSEMENT : FICHIER TRONQUÉ" +255 "Première marque de ce groupe déjà atteinte" +256 "%s: nouveau fichier : %lu lignes, %lu caractères" +257 "%s: %lu lignes, %lu caractères" +258 "%s étendue à trop de noms de fichiers" +259 "%s: pas un fichier standard" +260 "%s: ne vous appartient pas" +261 "%s: accessible par un utilisateur autre que son propriétaire" +262 "Fichier modifé depuis la dernière écriture complète ; écrire ou utiliser ! pour outrepasser " +263 "Fichier modifé depuis la dernière écriture complète ; écrire ou utiliser :edit! pour outrepasser" +264 "Fichier modifé depuis la dernière écriture complète ; écrire ou utiliser ! pour outrepasser" +265 "Fichier temporaire ; quitter annulera les modifications" +266 "Fichier en lecture seule ; les modifications ne sont pas écrites automatiquement" +267 "Journal redémarré" +268 "confirmer ? [ynq]" +269 "Appuyez sur n'importe quelle touche pour continuer : " +270 "Appuyez sur n'importe quelle touche pour continuer [: pour entrer plus de commandes ex] : " +271 "Appuyez sur n'importe quelle touche pour continuer [q pour Quitter]: " +272 "Cette forme de %s nécessite l'interface de terminal ex" +273 "Entrée de mode entrée ex." +274 "La commande a échoué, aucun fichier n'a encore été lu." +275 "cont?" +276 "Evénement imprévu de caractère" +277 "Evénement imprévu de fin-de-fichier" +278 "Pas de correspondances pour cette requête" +279 "Evénement imprévu d'interruption" +280 "Evénement quitter imprévu" +281 "Evénement imprévu de rafraîchissement" +282 "La dernière marque de ce groupe a déjà été atteinte" +283 "La commande %s nécessite l'interface de terminal ex" +284 "Cette forme de %s n'est pas reconnue quand l'option d'édition protégée est activée" +285 "Evénement imprévu de chaîne" +286 "Evénement imprévu de délai imparti" +287 "Evénement d'écriture imprévu" +289 "Les expansions du shell ne sont pas reconnues quand l'option d'édition protégée est activée" +290 "La commande %s n'est pas reconnue quand l'option d'édition protégée est activée" +291 "Définition : l'option %s ne peut pas être désactivée" +292 "Affichage trop petit." +293 "ajouté" +294 "changé" +295 "supprimé" +296 "joint" +297 "déplacé" +298 "décalé" +299 "coupé" +300 "ligne" +301 "lignes" +302 "Vi n'a pas été chargé avec un interprétateur Tcl" +303 "Ficher modifié depuis le dernier enregistrement." +304 "L'expansion du shell a échoué" +305 "Pas d'option d'édition %s spécifiée" +306 "Vi n'a pas été chargé avec un interprétateur Perl" +307 "Pas de commande ex à exécuter" +308 "Entrez pour exécuter une commande, :q pour quitter" +309 "Utiliser \"cscope help\" pour obtenir de l'aide" +310 "Aucune connexion cscope n'est lancée" +311 "%s : type de recherche inconnu : utiliser un des %s" +312 "%d : Il n'existe pas de telle session cscope" +313 "Définition : l'option %s ne peut jamais être activée" +314 "Définition : l'option %s ne peut jamais être définie sur 0" +315 "%s: joints : %lu lignes, %lu caractères" +316 "événement imprévu de redimensionnement" +317 "%d fichiers à éditer" Property changes on: vendor/nvi/2.2.0-05ed8b9/catalog/french.base ___________________________________________________________________ Added: fbsd:notbinary ## -0,0 +1 ## +catalog/dutch.base \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain; charset=iso-8859-1 \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/catalog/german.base =================================================================== --- vendor/nvi/2.2.0-05ed8b9/catalog/german.base (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/catalog/german.base (revision 366308) @@ -0,0 +1,306 @@ +002 "Zeilenlängen-Überlauf" +003 "kann Zeile %lu nicht löschen" +004 "kann an Zeile %lu nicht anfügen" +005 "kann in Zeile %lu nicht einfügen" +006 "kann Zeile %lu nicht speichern" +007 "kann letzte Zeile nicht lesen" +008 "Fehler: kann Zeile %lu nicht wiederherstellen" +009 "Protokolldatei" +010 "Keine Protokollierung aktiv, Rückgängigmachen nicht möglich" +011 "Keine Änderungen rückgängig zu machen" +012 "Keine Protokollierung aktiv, Rückgängigmachen nicht möglich" +013 "Keine Protokollierung aktiv, Wiederholung von Änderungen nicht möglich" +014 "Keine Änderungen zu wiederholen" +015 "%s/%d: Protokollschreibfehler" +016 "Vi's Standardein- und -ausgabe muß ein Terminal sein" +017 "Marke %s: nicht gesetzt" +018 "Marke %s: die Zeile wurde gelöscht" +019 "Marke %s: Cursorposition existiert nicht mehr" +020 "Fehler: " +021 "neue Datei" +022 "Name geändert" +023 "geändert" +024 "nicht geändert" +025 "NICHT GELOCKT" +026 "nur zum Lesen" +027 "Zeile %lu von %lu [%ld%%]" +028 "leere Datei" +029 "Zeile %lu" +030 "Die Datei %s ist kein Meldungskatalog" +031 "Setzen der Voreinstellung für %s Option nicht möglich" +032 "Benutzung: %s" +033 "set: keine %s Option: 'set all' zeigt alle Optionen mit Werten an" +034 "set: der [no]%s Option kann kein Wert zugewiesen werden" +035 "set: %s ist keine Boolsche Option" +036 "set: %s Option: %s" +037 "set: %s Option: %s: Werte-Überlauf" +038 "set: %s Option: %s ist eine ungültige Zahl" +039 "set: %s ist keine Boolsche Option" +040 "Bildschirm hat zu wenig Spalten, weniger als %d" +041 "Bildschirm hat zu viele Spalten, mehr als %d" +042 "Bildschirm hat zu wenig Zeilen, weniger als %d" +043 "Bildschirm hat zu viele Zeilen, mehr als %d" +044 "Die lisp-Option ist nicht implementiert" +045 "Meldungen nicht abgeschaltet: %s" +046 "Meldungen nicht eingeschaltet: %s" +047 "Die %s-Option muß Gruppen zu zwei Zeichen enthalten" +053 "Der Standardpuffer ist leer" +054 "Puffer %s ist leer" +055 "Dateien mit newlines im Namen sind nicht wiederherstellbar" +056 "Änderungen nicht wiederherstellbar, falls die Editorsitzung schiefgeht" +057 "kopiere Datei für Wiederherstellung ..." +058 "Rettungsmechanismus funktioniert nicht: %s" +059 "Änderungen nicht wiederherstellbar, falls die Editorsitzung schiefgeht" +060 "Sicherung der Datei gescheitert: %s" +061 "kopiere Datei für Wiederherstellung ..." +062 "Informationen über den Benutzer mit id %u nicht gefunden" +063 "Wiederherstellungsdatei kann nicht gelockt werden" +064 "Puffer der Wiederherstellungsdatei übergelaufen" +065 "Wiederherstellungsdatei" +066 "%s: Wiederherstellungsdatei hat falsches Format" +067 "%s: Wiederherstellungsdatei hat falsches Format" +068 "Keine von Ihnen lesbaren Dateien mit Namen %s zum Wiederherstellen" +069 "Es gibt ältere Versionen dieser Datei von Ihnen zum Wiederherstellen" +070 "Sie haben noch andere Dateien zum Wiederherstellen" +071 "schicke keine email: %s" +072 "Datei leer; nichts zu suchen" +073 "Dateiende erreicht, ohne das Suchmuster zu finden" +074 "Kein altes Suchmuster" +075 "Suchmuster nicht gefunden" +076 "Dateianfang erreicht, ohne das Suchmuster zu finden" +077 "Suche beginnt von vorn" +078 "suche ..." +079 "Keine nichtdruckbaren Zeichen gefunden" +080 "Unbekannter Kommandoname" +082 "%s: Kommando im ex-Modus nicht verfügbar" +083 "Anzahl darf nicht Null sein" +084 "%s: falsche Zeilenangabe" +085 "Interner Syntaxtabellenfehler (%s: %s)" +086 "Benutzung: %s" +087 "%s: temporärer Puffer nicht freigegeben" +088 "Flagoffset vor Zeile 1" +089 "Flagoffset hinter dem Dateiende" +090 "@ mit Bereich lief, als Datei/Anzeige geändert wurde" +091 "globales oder v-Kommando lief, als Datei/Anzeige geändert wurde" +092 "Ex-Kommando mißlungen: restliche Kommandoeingabe ignoriert" +093 "Ex-Kommando mißlungen: umdefinierte Tasten ungültig" +094 "Die zweite Adresse ist kleiner als die erste" +095 "Kein Markenname angegeben" +096 "\\ ohne folgenden / oder ?" +097 "Referenz auf eine negative Zeilennummer" +098 "Das Kommando %s ist unbekannt" +099 "Adreßwert zu groß" +100 "Adreßwert zu klein" +101 "Ungültige Adreßkombination" +102 "Ungültige Adresse: nur %lu Zeilen in der Datei" +103 "Ungültige Adresse: die Datei ist leer" +104 "Das Kommando %s erlaubt keine Adresse 0" +105 "Keine Abkürzungen zum Anzeigen" +106 "Abkürzungen müssen mit einem \"Wort\"-Zeichen enden" +107 "Abkürzungen dürfen keine Tabulator- oder Leerzeichen enthalten" +108 "In Abkürzungen dürfen außer am Ende Wort- und Nicht-Wort-Zeichen nicht gemischt werden" +109 "\"%s\" ist keine Abkürzung" +110 "Vi Kommando mißlungen: umdefinierte Tasten ungültig" +111 "Keine weiteren Dateien zu editieren" +112 "Keine vorhergehenden Dateien zu editieren" +113 "Keine vorhergehenden Dateien für rewind" +114 "Keine Dateiliste zum Anzeigen" +115 "Kein vorhergehendes Kommando, um \"!\" zu ersetzen" +116 "Kein Dateiname für %%" +117 "Kein Dateiname für #" +118 "Fehler: execl: %s" +119 "E/A-Fehler: %s" +120 "Datei wurde seit dem letzten vollständigen Schreiben geändert; schreibe oder verwende ! zum ignorieren" +121 "Kann Homedirectory nicht bestimmen" +122 "Neues aktuelles Directory: %s" +123 "Keine Puffer anzuzeigen" +124 "Das Kommando %s kann nicht als Teil eines global oder v Kommandos verwendet werden" +125 "%s/%s: nicht gelesen: gehört weder Ihnen noch root" +126 "%s/%s: nicht gelesen: gehört nicht Ihnen" +127 "%s/%s: nicht gelesen: anderer Benutzer als Eigentümer hat Schreibrecht" +128 "%s: nicht gelesen: gehört weder Ihnen noch root" +129 "%s: nicht gelesen: gehört nicht Ihnen" +130 "%s: nicht gelesen: anderer Benutzer als Eigentümer hat Schreibrecht" +131 "Keine folgenden Zeilen zum Verbinden" +132 "Kein input-Map Eintrag" +133 "Kein command-Map Eintrag" +134 "Das %s Zeichen kann nicht umgemappt werden" +135 "\"%s\" ist momentan nicht gemappt" +136 "Markennamen müssen einzelne Buchstaben sein" +137 "%s existiert, nicht geschrieben; verwende ! zum Überschreiben" +138 "Neue .exrc Datei: %s. " +139 "Zielzeile ist innerhalb des Verschiebebereichs" +140 "Das open Kommando verlangt, daß die open Option gesetzt ist" +141 "Das open Kommando ist nocht nicht implementiert" +142 "Rettung dieser Datei nicht möglich" +143 "Datei gerettet" +144 "%s wurde in zu viele Dateinamen expandiert" +145 "Nur reguläre Dateien und named pipes können gelesen werden" +146 "%s: Locken zum Lesen war nicht möglich" +147 "lese ..." +148 "%s: %lu Zeilen, %lu Zeichen" +149 "Keine Hintergrundanzeigen vorhanden" +150 "Das script Kommando ist nur im vi Modus verfügbar" +151 "Kein Kommando auszuführen" +152 "shiftwidth Option auf 0 gesetzt" +153 "Anzahl-Überlauf" +154 "Anzahl-Unterlauf" +155 "Regulärer Ausdruck angegeben; r Flag bedeutungslos" +156 "Die #, l und p Flags können im vi Modus nicht mit dem c Flag kombiniert werden" +157 "Keine Übereinstimmung gefunden" +158 "Kein vorhergehender 'tag' angegeben" +159 "Weniger als %s Einträge auf dem 'tag'-Stack; verwende :display t[ags]" +160 "Keine Datei namens %s auf dem 'tag'-Stack; verwende :display t[ags]" +161 "Drücke Enter um fortzufahren: " +162 "%s: 'tag' nicht gefunden" +163 "%s: kaputter 'tag' in %s" +164 "%s: die Zeilennummer des 'tag' ist hinter dem Dateiende" +165 "Der 'tag' Stack ist leer" +166 "%s: Suchmuster nicht gefunden" +167 "%d weitere Dateien zu editieren" +168 "Puffer %s ist leer" +169 "Bestätige Änderung [n]" +170 "Unterbrochen." +171 "Kein vorhergehender Puffer zum Ausführen" +172 "Kein vorhergehender regulärer Ausdruck" +173 "Das Kommando %s verlangt, daß bereits eine Datei eingelesen wurde" +174 "Benutzung: %s" +175 "Das visual Kommando verlangt daß die open Option gesetzt ist" +177 "Leere Datei" +178 "Keine vorhergehende F, f, T oder t Suche" +179 "%s nicht gefunden" +180 "Keine vorhergehende Datei zu editieren" +181 "Cursor nicht auf einer Zahl" +182 "Sich ergebende Zahl ist zu groß" +183 "Sich ergebende Zahl ist zu klein" +184 "Kein korrespondierendes Zeichen in dieser Zeile" +185 "Korrespondierendes Zeichen nicht gefunden" +186 "Keine Zeichen zu ersetzen" +187 "Keine andere Anzeige zum Hinschalten" +188 "Zeichen nach Suchmuster, Zeilenoffset und/oder z Kommando" +189 "Kein altes Suchmuster" +190 "Suche zur ursprünglichen Position zurückgekehrt" +191 "Abkürzung überschreitet Expansionsgrenze: Zeichen weggelassen" +192 "Nicht erlaubtes Zeichen; maskiere zum Eingeben" +193 "Bereits am Anfang der Eingabe" +194 "Keine weiteren Zeichen zu löschen" +195 "Bewegung hinter das Dateiende" +196 "Bewegung hinter das Zeilenende" +197 "Keine Cursorbewegung gemacht" +198 "Bereits am Dateianfang" +199 "Bewegung vor den Dateianfang" +200 "Bereits in der ersten Spalte" +201 "Puffer sollen vor dem Kommando angegeben werden" +202 "Bereits am Dateiende" +203 "Bereits am Zeilenende" +204 "%s ist kein vi Kommando" +205 "Benutzung: %s" +206 "Keine Zeichen zu löschen" +207 "Das Q Kommando benötigt das ex Terminal Interface" +208 "Kein Kommando zu wiederholen" +209 "Die Datei ist leer" +210 "%s kann nicht als Bewegungskommando verwendet werden" +211 "Bereits im Kommando-Modus" +212 " Cursor nicht auf einem Wort" +214 "Wert der Window Option ist zu groß, max ist %u" +215 "Anhängen" +216 "Ändern" +217 "Kommando" +218 "Einfügen" +219 "Ersetzen" +220 "Bewegung hinter das Anzeigenende" +221 "Bewegung vor den Anzeigenanfang" +222 "Anzeige muß für Bildschirmteilung größer als %d sein" +223 "Keine Hintergrundanzeigen vorhanden" +224 "Es gibt keine Hintergrundanzeige, die eine Datei namens %s editiert" +225 "Die einzige dargestellte Anzeige kann nicht in den Hintergrund gebracht werden" +226 "Die Anzeige kann nur auf %d Zeilen verkleinert werden" +227 "Die Anzeige kann nicht verkleinert werden" +228 "Die Anzeige kann nicht vergrößert werden" +230 "Diese Anzeige kann nicht gestopt werden" +231 "Unterbrochen: umdefinierte Tasten ungültig" +232 "vi: temporärer Puffer nicht freigegeben" +233 "Dieses Terminal hat keine %s Taste" +234 "es kann nur ein Puffer angegeben werden" +235 "Zahl größer als %lu" +236 "Unterbrochen" +237 "Nicht möglich, temporäre Datei anzulegen" +238 "Warnung: %s ist keine reguläre Datei" +239 "%s ist bereits gelockt, Editorsitzung schreibgeschützt" +240 "%s: löschen" +241 "%s: schließen" +242 "%s: löschen" +243 "%s: löschen" +244 "Datei nicht schreibbar, nicht geschrieben; verwende ! zum Überschreiben" +245 "Datei nicht schreibbar, nicht geschrieben" +246 "%s existiert, nicht geschrieben; verwende ! zum Überschreiben" +247 "%s existiert, nicht geschrieben" +248 "Teil der Datei, nicht geschrieben; verwende ! zum Überschreiben" +249 "Teil der Datei, nicht geschrieben" +250 "%s: Datei wurde später als diese Kopie verändert; verwende ! zum Überschreiben" +251 "%s: Datei wurde später als diese Kopie verändert" +252 "%s: Locken zum Schreiben war nicht möglich" +253 "schreibe ..." +254 "%s: WARNUNG: DATEI ABGESCHNITTEN" +255 "Bereits am ersten 'tag' dieser Gruppe" +256 "%s: neue Datei: %lu Zeilen, %lu Zeichen" +257 "%s: %lu Zeilen, %lu Zeichen" +258 "%s wurde in zu viele Dateinamen expandiert" +259 "%s: keine reguläre Datei" +260 "%s: gehört nicht Ihnen" +261 "%s: anderer Benutzer als Eigentümer hat Zugriff" +262 "Datei wurde seit dem letzten vollständigen Schreiben geändert; schreibe oder verwende ! zum ignorieren" +263 "Datei wurde seit dem letzten vollständigen Schreiben geändert; schreibe oder verwende :edit! zum ignorieren" +264 "Datei wurde seit dem letzten vollständigen Schreiben geändert; schreibe oder verwende ! zum ignorieren" +265 "Datei ist temporär; beim Verlassen gehen die Änderungen verloren" +266 "Datei ist schreibgeschützt, Änderungen werden nicht automatisch geschrieben" +267 "Portokollierung neu begonnen" +268 "bestätigen [ynq]" +269 "Drücke beliebige Taste um fortzufahren" +270 "Drücke beliebige Taste um fortzufahren [: um weitere Kommandos einzugeben]: " +271 "Drücke beliebige Taste um fortzufahren [q zum Verlassen]: " +272 "Diese Form von %s benötigt das ex Terminal-Interface" +273 "Gehe in ex Eingabe-Modus.\n" +274 "Kommando schiefgelaufen, noch keine Datei eingelesen" +275 " weiter?" +276 "unerwartetes Zeichen - Ereignis" +277 "unerwartetes Dateiende - Ereignis" +278 "Keine Position zum Anspringen gefunden" +279 "unerwartetes Unterbrechungs - Ereignis" +280 "unerwartetes Verlassen - Ereignis" +281 "unerwartetes Wiederherstellungs - Ereignis" +282 "Bereits am letzten 'tag' dieser Gruppe" +283 "Das %s Kommando benötigt das ex Terminal-Interface" +284 "Diese Form von %s wird nicht unterstützt wenn die 'secure edit' - Option gesetzt ist" +285 "unerwartetes Zeichenketten - Ereignis" +286 "unerwartetes timeout - Ereignis" +287 "unerwartetes Schreibe - Ereignis" +289 "Shell Expandierungen nicht unterstützt wenn die 'secure edit' - Option gesetzt ist" +290 "Das %s Kommando wird nicht unterstützt wenn die 'secure edit' - Option gesetzt ist" +291 "set: %s kann nicht ausgeschaltet werden" +292 "Anzeige zu klein." +293 "angefügt" +294 "geändert" +295 "gelöscht" +296 "verbunden" +297 "verschoben" +298 "geschoben" +299 "in Puffer geschrieben" +300 "Zeile" +301 "Zeilen" +302 "Vi wurde nicht mit dem Tcl Interpreter gelinkt" +303 "Datei wurde seit dem letzten Schreiben verändert." +304 "Shell Expansion hat nicht geklappt" +305 "Es ist keine %s Editieroption angegeben" +306 "Vi wurde nicht mit einem Perl Interpreter geladen" +307 "Kein ex Kommando auszuführen" +308 "Drücke um ein Kommando auszuführen, :q zum verlassen" +309 "Verwende \"cscope help\" für Hilestellung" +310 "Keine cscope Verbindung aktiv" +311 "%s: unbekannter Suchtyp: verwende einen aus %s" +312 "%d: keine solche cscope Verbindung" +313 "set: die %s Option kann nicht eingeschaltet werden" +314 "set: die %s Option kann nicht auf 0 gesetzt werden" +315 "%s: angefügt: %lu Zeilen, %lu Zeichen" +316 "unerwartetes Größenveränderungs - Ereignis" +317 "%d Dateien zu edieren" Property changes on: vendor/nvi/2.2.0-05ed8b9/catalog/german.base ___________________________________________________________________ Added: fbsd:notbinary ## -0,0 +1 ## +catalog/dutch.base \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain; charset=iso-8859-1 \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/catalog/german.owner =================================================================== --- vendor/nvi/2.2.0-05ed8b9/catalog/german.owner (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/catalog/german.owner (revision 366308) @@ -0,0 +1,2 @@ +Bernhard Daeubler +Joerg Wunsch Property changes on: vendor/nvi/2.2.0-05ed8b9/catalog/german.owner ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/catalog/polish.base =================================================================== --- vendor/nvi/2.2.0-05ed8b9/catalog/polish.base (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/catalog/polish.base (revision 366308) @@ -0,0 +1,306 @@ +002 "Zbyt d³uga linia" +003 "nie mo¿na usun±æ linii %lu" +004 "nie mo¿na dodaæ do linii %lu" +005 "nie mo¿na wstawiæ w linii %lu" +006 "nie mo¿na zachowaæ linii %lu" +007 "nie mo¿na pobraæ ostatniej linii" +008 "B³±d: nie mo¿na pobraæ linii %lu" +009 "Plik logu" +010 "Brak logowania, anulowanie (undo) niemo¿liwe" +011 "Brak zmian do anulowania" +012 "Brak logowania, anulowanie (undo) niemo¿liwe" +013 "Brak logowania, nie mo¿na przegl±daæ do przodu" +014 "Brak zmian do powtórzenia" +015 "%s/%d: b³±d zapisu do logu" +016 "Standardowe wej¶cie i wyj¶cie vi musi byæ terminalem" +017 "Znacznik %s: nie ustawiony" +018 "Znacznik %s: linia zosta³a usuniêta" +019 "Znacznik %s: pozycja kursora ju¿ nie istnieje" +020 "B³±d: " +021 "nowy plik" +022 "nazwa zosta³a zmieniona" +023 "zmieniony" +024 "nie zmieniony" +025 "ODBLOKOWANY" +026 "tylko do odczytu" +027 "linia %lu z %lu [%ld%%]" +028 "pusty plik" +029 "linia %lu" +030 "Plik %s nie jest katalogiem komunikatów" +031 "Nie mo¿na ustawiæ domy¶lnej opcji %s" +032 "Sposób u¿ycia: %s" +033 "set: brak opcji %s: 'set all' wy¶wietla warto¶ci opcji" +034 "set: opcja no]%s nie pobiera warto¶ci" +035 "set: opcja %s nie jest zmienn± boolowsk±" +036 "set: opcja %s: %s" +037 "set: opcja %s: %s: przepe³nienie" +038 "set: opcja %s: %s nie jest poprawn± liczb±" +039 "set: opcja %s nie jest zmienn± boolowsk±" +040 "Zbyt ma³a liczba kolumn ekranu, mniejsza ni¿ %d" +041 "Zbyt du¿a liczba kolumn, wiêksza ni¿ %d" +042 "Zbyt ma³a liczba wierszy ekranu, mniejsza ni¿ %d" +043 "Zbyt du¿a liczba wierszy ekranu, wiêksza ni¿ %d" +044 "Opcja lisp nie jest zaimplementowana" +045 "komunikaty nie wy³±czone: %s" +046 "komunikaty nie w³±czone: %s" +047 "Opcja %s musi sk³adaæ siê z dwóch grup symboli" +053 "Domy¶lny bufor jest pusty" +054 "Bufor %s jest pusty" +055 "Pliki z symbolem nowego wiersza w nazwie nie mog± byæ odtworzone" +056 "Zmiany nie do odtworzenia, je¶li sesja zostanie przerwana" +057 "Tworzenie kopii zapasowej..." +058 "B³±d podczas zachowywania: %s" +059 "Zmiany nie do odtworzenia, je¶li sesja zostanie przerwana" +060 "B³±d podczas tworzenia kopii zapasowej: %s" +061 "Tworzenie kopii zapasowej..." +062 "Nie znaleziono informacji o u¿ytkowniku numer %u" +063 "Nie mo¿na zablokowaæ kopii zapasowej" +064 "Przepe³nienie bufora kopii zapasowej" +065 "Kopia zapasowa" +066 "%s: b³êdna kopia zapasowa" +067 "%s: b³êdna kopia zapasowa" +068 "Brak plików o nazwie %s, które móg³by¶ odczytaæ, do odzyskania" +069 "Istniej± starsze wersje tego pliku, które mo¿na odzyskaæ" +070 "Istniej± inne pliki, które mo¿na odzyskaæ" +071 "nie wysy³am poczty: %s" +072 "Pusty plik; nie ma czego szukaæ" +073 "Dotarto do koñca pliku bez znalezienia szukanego wzorca" +074 "Brak poprzedniego wzorca poszukiwañ" +075 "Nie znaleziono wzorca" +076 "Dotarto do pocz±tku pliku bez znalezienia szukanego wzorca" +077 "Poszukiwanie od pocz±tku" +078 "Szukam..." +079 "Nie znaleziono niedrukowalnych znaków" +080 "Nieznana nazwa polecenia" +082 "%s: polecenie niedostêpne w trybie edytora ex" +083 "Liczba nie mo¿e byæ zerem" +084 "%s: b³êdny numer linii" +085 "Wewnêtrzny b³±d tablicy sk³adni (%s: %s)" +086 "Sposób u¿ycia: %s" +087 "%s: tymczasowy bufor nie zosta³ zwolniony" +088 "Przesuniêcie przed liniê 1" +089 "Przesuniêcie poza koniec pliku" +090 "@ with range running when the file/screen changed" +091 "Wykonywano polecenie globalne/wizualne podczas zmiany pliku/ekranu" +092 "B³±d polecenie ex: pozosta³e polecenia anulowane" +093 "B³±d polecenia ex: mapowanie klawiszy anulowane" +094 "Drugi adres jest mniejszy od pierwszego" +095 "Nie podano nazwy znacznika" +096 "\\ bez / lub ?" +097 "Odniesienie do linii o numerze mniejszym od 0" +098 "Nieznane polecenie %s" +099 "Przepe³nienie warto¶ci adresu" +100 "Niedomiar warto¶ci adresu" +101 "Niedozwolona kombinacja adresu" +102 "Niedozwolony adres: jest tylko %lu linii w pliku" +103 "Niedozwolony adres: plik jest pusty" +104 "Polecenie %s nie zezwala na u¿ycie adresu 0" +105 "Brak skrótów do wy¶wietlenia" +106 "Skróty musz± siê koñczyæ symbolem \"s³owo\"" +107 "Skróty nie mog± zawieraæ spacji lub tabulacji" +108 "Skróty nie mog± przeplataæ symboli s³owo/nie-s³owo, z wyj±tkiem na koñcu linii" +109 "\"%s\" nie jest skrótem" +110 "B³±d polecenia vi: mapowanie klawiszy odrzucone" +111 "Nie ma wiêcej plików do edycji" +112 "Nie ma poprzednich plików do edycji" +113 "Nie ma poprzednich plików do przewiniêcia wstecz" +114 "Nie ma listy plików do wy¶wietlenia" +115 "Nie ma poprzedniego polecenia do zast±pienia \"!\"" +116 "Nie ma nazwy pliku do zast±pienia %%" +117 "Nie ma nazwy pliku do zast±pienia #" +118 "B³±d: execl: %s" +119 "B³±d I/O: %s" +120 "Plik zmodyfikowany od ostatniego zapisu; zapisz lub u¿yj ! ¿eby wymusiæ" +121 "Nie mozna znale¼æ katalogu domowego (home)" +122 "Nowy katalog bie¿±cy: %s" +123 "Nie ma buforów edycji do wy¶wietlenia" +124 "Polecenie %s nie mo¿e byæ u¿yte jako czê¶æ polecenia globalnego lub wizualnego" +125 "%s/%s: nie wczytany: nie nale¿y do ciebie ani do roota" +126 "%s/%s: nie wczytany: nie nale¿y do ciebie" +127 "%s/%s: nie wczytany: inny u¿ytkownik ni¿ w³a¶ciciel ma prawo do zapisu" +128 "%s: nie wczytany: nie nale¿y do ciebie ani do roota" +129 "%s: nie wczytany: nie nale¿y do ciebie" +130 "%s: nie wczytany: inny uzytkownik ni¿ w³a¶ciciel ma prawo do zapisu" +131 "Brak kolejnych linii do po³±czenia" +132 "Brak pozycji map wej¶ciowych" +133 "Brak pozycji map poleceñ" +134 "Znak %s nie mo¿e byæ przemapowany" +135 "\"%s\" obecnie nie jest mapowany" +136 "Nazwa znacznika musi byæ pojedyñcz± liter±" +137 "%s istnieje, nie zapisany; u¿yj ! ¿eby wymusiæ" +138 "Nowy plik exrc: %s" +139 "Linia docelowa jest wewn±trz przenoszonego obszaru" +140 "Polecenie open wymaga ustawienia opcji open" +141 "Polecenie open jest niezaimplementowane" +142 "Niemo¿liwe jest zachowanie tego pliku" +143 "Plik zachowany" +144 "%s: rozwija siê na zbyt wiele nazw plików" +145 "Tylko zwyk³e pliki i nazwane ³±cza (named pipes) mo¿na czytaæ" +146 "%s: nie mo¿na za³o¿yæ blokady do odczytu" +147 "Czytanie..." +148 "%s: %lu linii, %lu znaków" +149 "Brak ekranów w tle do wy¶wietlenia" +150 "Polecenie script dostêpne jest tylko w trybie vi" +151 "Brak polecenia do wykonania" +152 "Opcja shiftwidth ustawiona na 0" +153 "Przepe³nienie licznika" +154 "Niedomiar licznika" +155 "Podano wyra¿enie regularne; flaga r nie ma znaczenia" +156 "Flagi #, l oraz p nie mog± byæ ³±czone z flag± c w trybie vi" +157 "Nie znaleziono wzorca" +158 "Brak poprzedniego znacznika" +159 "Mniej ni¿ %s na stosie znaczników; u¿yj :display t[ags]" +160 "Brak pliku %s na stosie znaczników do powrotu; u¿yj :display t[ags]" +161 "Naci¶nij Enter: " +162 "%s: znacznik nie znaleziony" +163 "%s: b³êdny znacznik w %s" +164 "%s: numer linii znacznika wykracza poza koniec pliku" +165 "Stos znaczników jest pusty" +166 "%s: nie znaleziono szukanego wzorca" +167 "%d plików jeszcze do edycji" +168 "Bufor %s jest pusty" +169 "Potwierdzasz zmianê? [n]" +170 "Przerwany" +171 "Brak poprzedniego bufora do wykonania" +172 "Brak poprzedniego wyra¿enia regularnego" +173 "Polecenie %s wymaga uprzedniego wczytania pliku" +174 "Sposób u¿ycia: %s" +175 "Polecenie wizualne wymaga ustawienia opcji open" +177 "Pusty plik" +178 "Brak poprzedniego szukania F, f, T lub t" +179 "%s nie znaleziono" +180 "Brak poprzedniego pliku do edycji" +181 "Kursor nie na liczbie" +182 "Liczba wynikowa zbyt du¿a" +183 "Liczba wynikowa zbyt ma³a" +184 "Brak pasuj±cych znaków w tej linii" +185 "Nie znaleziono pasuj±cych znaków" +186 "Brak znaków do zamiany" +187 "Brak innego ekranu do prze³±czenia" +188 "Znaki poza napisem do szukania, przesuniêciem linii i/lub poleceniem z" +189 "Brak poprzedniego wzorca szukania" +190 "Szukanie wróci³o do pierwotnej pozycji" +191 "Skrót przekroczy³ limit rozwiniêcia: czê¶æ znaków odrzucono" +192 "Niedozwolony znak; zacytuj, ¿eby wprowadziæ" +193 "Ju¿ na pocz±tku wstawiania" +194 "Brak kolejnych znaków do usuniêcia" +195 "Przesuniêcie poza koniec pliku" +196 "Przesuniêcie poza koniec linii" +197 "Nie wykonano przesuniêcia kursora" +198 "Ju¿ na pocz±tku pliku" +199 "Przesuniêcie przed pocz±tek pliku" +200 "Ju¿ w pierwszej kolumnie" +201 "Nale¿y podaæ bufory przed poleceniem" +202 "Ju¿ na koñcu pliku" +203 "Ju¿ na koñcu linii" +204 "%s nie jest poleceniem vi" +205 "Sposób u¿ycia: %s" +206 "Brak znaków do usuniêcia" +207 "Polecenie Q wymaga interfejsu terminala ex" +208 "Brak polecenia do powtórzenia" +209 "Plik jest pusty" +210 "%s nie mo¿e byæ u¿yte jako polecenie przesuniêcia" +211 "Ju¿ w trybie poleceñ" +212 "Kursor nie na s³owie" +214 "Warto¶ci opcji okna zbyt du¿e, max to %u" +215 "Do³±cz" +216 "Zmieñ" +217 "Polecenie" +218 "Wstaw" +219 "Zamieñ" +220 "Przesuniêcie poza koniec ekranu" +221 "Przesuniêcie przed pocz±tek ekranu" +222 "Ekran musi mieæ wiêcej ni¿ %d linii, ¿eby go podzieliæ" +223 "Brak ekranów w tle" +224 "Nie ma ekranu w tle z edycj± pliku o nazwie %s" +225 "Nie mo¿na schowaæ w tle jedynego ekranu edycyjnego" +226 "Mo¿na zmniejszyæ ekran tylko do %d wierszy" +227 "Ekran nie mo¿e byæ zmniejszony" +228 "Ekran nie mo¿e byæ zwiêkszony" +230 "Ekran nie mo¿e byæ zawieszony" +231 "Przerwano: odrzucono mapowane klawisze" +232 "vi: nie zwolniono bufora tymczasowego" +233 "Ten terminal nie posiada klawisza %s" +234 "Mo¿na podaæ tylko jeden bufor" +235 "Liczba wiêksza ni¿ %lu" +236 "Przerwano" +237 "Nie mo¿na utworzyæ pliku tymczasowego" +238 "Uwaga: %s nie jest zwyk³ym plikiem" +239 "%s ju¿ zablokowany, sesja tylko do odczytu" +240 "%s: usuñ" +241 "%s: zamknij" +242 "%s: usuñ" +243 "%s: usuñ" +244 "Plik tylko do odczytu, nie zapisany; u¿yj ! ¿eby wymusiæ" +245 "Plik tylko do odczytu, nie zapisany" +246 "%s istnieje, nie zapisany; u¿yj ! ¿eby wymusiæ" +247 "%s istnieje, nie zapisany" +248 "Plik czê¶ciowy, nie zapisany; u¿yj ! ¿eby wymusiæ" +249 "Plik czê¶ciowy, nie zapisany" +250 "%s: plik zmodyfikowany pó¼niej, ni¿ ta kopia; u¿yj ! ¿eby wymusiæ" +251 "%s: plik zmodyfikowany pó¼niej, ni¿ ta kopia" +252 "%s: nie mo¿na zablokowaæ do pisania" +253 "Zapisywanie..." +254 "%s: OSTRZE¯ENIE: PLIK ZOSTA£ OBCIÊTY" +255 "Ju¿ przy pierwszym znaczniku z tej grupy" +256 "%s: nowy plik: %lu linii, %lu znaków" +257 "%s: %lu linii, %lu znaków" +258 "%s rozwija siê na zbyt wiele nazw plików" +259 "%s: nie jest zwyk³ym plikiem" +260 "%s: nie jeste¶ w³a¶cicielem" +261 "%s: dostêpny dla u¿ytkownika innego ni¿ w³a¶ciciel" +262 "Plik zmodyfikowany od ostatniego zapisu; zapisz lub u¿yj ! ¿eby wymusiæ" +263 "Plik zmodyfikowany od ostatniego zapisu; zapisz lub u¿yj :edit! ¿eby wymusiæ" +264 "Plik zmodyfikowany od ostatniego zapisu; zapisz lub u¿yj ! ¿eby wymusiæ" +265 "To jest plik tymczasowy; wyj¶cie anuluje zmiany" +266 "Plik tylko do odczytu, nie ma autozapisu zmian" +267 "Ponownie rozpoczêto logowanie" +268 "potwierdzasz? [ynq]" +269 "Naci¶nij dowolny klawisz: " +270 "Naci¶nij dowolny klawisz [: ¿eby podaæ nastêpne polecenia ex]: " +271 "Naci¶nij dowolny klawisz [q ¿eby zakoñczyæ]: " +272 "Ta forma %s wymaga interfejsu terminala ex" +273 "Wchodzê w tryb wprowadzania ex." +274 "B³±d polecenia, jeszcze nie wczytano pliku." +275 " dalej?" +276 "Nieoczekiwany symbol" +277 "Nieoczekiwany koniec pliku" +278 "Brak wzorców pasuj±cych do zapytania" +279 "Nieoczekiwane przerwanie" +280 "Nieoczekiwane polecenie koniec" +281 "Nieoczekiwane polecenie od¶wie¿enia" +282 "Ju¿ przy ostatnim znaczniku z tej grupy" +283 "Polecenie %s wymaga interfejsu terminala ex" +284 "Ta forma %s jest niedostêpna, kiedy ustawiona jest opcja bezpiecznej edycji" +285 "Nieoczekiwany ci±g znaków" +286 "Nieoczekiwany timeout" +287 "Nieoczekiwane polecenie zapisu" +289 "Rozwiniêcia shella niedostêpne w trybie bezpiecznej edycji" +290 "Polecenie %s jest niedostêpne w trybie bezpiecznej edycji" +291 "set: opcji %s nie mo¿na wy³±czyæ" +292 "Ekran zbyt ma³y." +293 "dodano" +294 "zmieniono" +295 "usuniêto" +296 "po³±czono" +297 "przeniesiono" +298 "przesuniêto" +299 "wczytano" +300 "linia" +301 "linii" +302 "Vi nie zosta³ uruchomiony z interpreterem Tcl" +303 "Plik zmodyfikowany od ostatniego zapisu" +304 "B³±d rozwiniêcia shella" +305 "Brak opcji %s edycji" +306 "Vi nie zosta³ uruchomiony z interpreterem Perl" +307 "Brak polecenia ex do wykonania" +308 "Naci¶nij ¿eby wykonac polecenie, :q ¿eby wyj¶æ" +309 "U¿yj \"cscope help\" w celu uzyskania pomocy" +310 "Brak aktywnych po³±czeñ cscope" +311 "%s: nieznany typ poszukiwañ: u¿yj jednego z %s" +312 "%d: brak takiej sesji cscope" +313 "set: nie mo¿na nigdy w³±czyæ opcji %s" +314 "set: opcja %s nie mo¿e nigdy mieæ warto¶ci 0" +315 "%s: dodano: %lu linii, %lu znaków" +316 "Nieoczekiwane polecenie zmiany rozmiaru" +317 "%d plików do edycji" Property changes on: vendor/nvi/2.2.0-05ed8b9/catalog/polish.base ___________________________________________________________________ Added: fbsd:notbinary ## -0,0 +1 ## +catalog/dutch.base \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain; charset=iso-8859-2 \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/catalog/polish.owner =================================================================== --- vendor/nvi/2.2.0-05ed8b9/catalog/polish.owner (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/catalog/polish.owner (revision 366308) @@ -0,0 +1 @@ +Andrzej Bia³ecki Index: vendor/nvi/2.2.0-05ed8b9/catalog/ru_RU.KOI8-R.base =================================================================== --- vendor/nvi/2.2.0-05ed8b9/catalog/ru_RU.KOI8-R.base (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/catalog/ru_RU.KOI8-R.base (revision 366308) @@ -0,0 +1,311 @@ +002 "ðÅÒÅÐÏÌÎÅÎÉÅ ÚÎÁÞÅÎÉÑ ÄÌÉÎÙ ÓÔÒÏËÉ" +003 "ÎÅ×ÏÚÍÏÖÎÏ ÕÄÁÌÉÔØ ÓÔÒÏËÕ %lu" +004 "ÎÅ×ÏÚÍÏÖÎÏ ÄÏÂÁ×ÉÔØ Ë ÓÔÒÏËÅ %lu" +005 "ÎÅ×ÏÚÍÏÖÎÏ ×ÓÔÁ×ÉÔØ × ÓÔÒÏËÕ %lu" +006 "ÎÅ×ÏÚÍÏÖÎÏ ÓÏÈÒÁÎÉÔØ ÓÔÒÏËÕ %lu" +007 "ÎÅ×ÏÚÍÏÖÎÏ ÄÏÓÔÁÔØ ÐÏÓÌÅÄÎÀÀ ÓÔÒÏËÕ" +008 "ïÛÉÂËÁ: ÎÅ ÕÄÁÌÏÓØ ÐÏÌÕÞÉÔØ ÓÔÒÏËÕ %lu" +009 "æÁÊÌ ÚÁÐÉÓÅÊ" +010 "úÁÐÉÓÉ ÎÅ ×ÅÌÉÓØ, ÎÅ×ÏÚÍÏÖÎÏ ÏÔÍÅÎÉÔØ ÐÏÓÌÅÄÎÀÀ ËÏÍÁÎÄÕ" +011 "îÅÔ ÉÚÍÅÎÅÎÉÊ ÄÌÑ ÏÔÍÅÎÙ" +012 "úÁÐÉÓÉ ÎÅ ×ÅÌÉÓØ, ÎÅ×ÏÚÍÏÖÎÏ ÏÔÍÅÎÉÔØ ÐÏÓÌÅÄÎÀÀ ËÏÍÁÎÄÕ" +013 "úÁÐÉÓÉ ÎÅ ×ÅÌÉÓØ, ÎÅ×ÏÚÍÏÖÎÏ ÐÒÏÓÍÏÔÒÅÔØ ×ÐÅÒÅÄ" +014 "îÅÔ ÉÚÍÅÎÅÎÉÊ ÄÌÑ ÐÅÒÅÄÅÌËÉ" +015 "%s/%d: ÏÛÉÂËÁ ÐÒÉ ÚÁÐÉÓÉ ÐÒÏÔÏËÏÌÁ" +016 "óÔÁÎÄÁÒÔÎÙÊ ××ÏÄ/×Ù×ÏÄ ÄÌÑ VI ÄÏÌÖÅÎ ÂÙÔØ ÔÅÒÍÉÎÁÌ" +017 "ïÔÍÅÔËÁ %s: ÎÅ ÕÓÔÁÎÏ×ÌÅÎÁ" +018 "ïÔÍÅÔËÁ %s: ÓÔÒÏËÁ ÂÙÌÁ ÕÄÁÌÅÎÁ" +019 "ïÔÍÅÔËÁ %s: ÐÏÚÉÃÉÉ ËÕÒÓÏÒÁ ÂÏÌØÛÅ ÎÅ ÓÕÝÅÓÔ×ÕÅÔ" +020 "ïÛÉÂËÁ: " +021 "ÎÏ×ÙÊ ÆÁÊÌ" +022 "ÉÍÑ ÉÚÍÅÎÅÎÏ" +023 "ÍÏÄÉÆÉÃÉÒÏ×ÁÎÏ" +024 "ÎÅ ÍÏÄÉÆÉÃÉÒÏ×ÁÎÏ" +025 "òáúâìïëéòï÷áîï" +026 "ÔÏÌØËÏ ÞÔÅÎÉÅ" +027 "ÓÔÒÏËÁ %lu ÉÚ %lu [%ld%%]" +028 "ÐÕÓÔÏÊ ÆÁÊÌ" +029 "ÓÔÒÏËÁ %lu" +030 "æÁÊÌ %s ÎÅ Ñ×ÌÑÅÔÓÑ ËÁÔÁÌÏÇÏÍ ÓÏÏÂÝÅÎÉÊ" +031 "îÅ×ÏÚÍÏÖÎÏ ÕÓÔÁÎÏ×ÉÔØ ÏÐÃÉÀ %s ÐÏ ÕÍÏÌÞÁÎÉÀ" +032 "éÓÐÏÌØÚÏ×ÁÎÉÅ: %s" +033 "ïÐÃÉÉ %s ÎÅÔ: 'set all' ÐÏËÁÚÙ×ÁÅÔ ×ÓÅ ×ÏÚÍÏÖÎÙÅ ÏÐÃÉÉ" +034 "set: [no]%s ÎÅ ÐÒÉÎÉÍÁÅÔ ÔÁËÏÇÏ ÚÎÁÞÅÎÉÑ" +035 "set: %s ÏÐÃÉÑ ÎÅ Ñ×ÌÑÅÔÓÑ ÌÏÇÉÞÅÓËÏÊ" +036 "set: %s ÏÐÃÉÑ: %s" +037 "set: %s ÏÐÃÉÑ: %s: ÚÎÁÞÅÎÉÅ ÐÅÒÅÐÏÌÎÅÎÉÑ" +038 "set: ÎÅÐÒÁ×ÉÌØÎÏÅ ÚÎÁÞÅÎÉÅ %s" +039 "set: %s ÏÐÃÉÑ ÎÅ Ñ×ÌÑÅÔÓÑ ÌÏÇÉÞÅÓËÏÊ" +040 "ëÏÌÉÞÅÓÔ×Ï ËÏÌÏÎÏË ÜËÒÁÎÁ ÓÌÉÛËÏÍ ÍÁÌÏ, ÍÅÎØÛÅ ÞÅÍ %d" +041 "ëÏÌÉÞÅÓÔ×Ï ËÏÌÏÎÏË ÜËÒÁÎÁ ÓÌÉÛËÏÍ ×ÅÌÉËÏ, ÂÏÌØÛÅ ÞÅÍ %d" +042 "ëÏÌÉÞÅÓÔ×Ï ÓÔÒÏË ÜËÒÁÎÁ ÓÌÉÛËÏÍ ÍÁÌÏ, ÍÅÎØÛÅ ÞÅÍ %d" +043 "ëÏÌÉÞÅÓÔ×Ï ÓÔÒÏË ÜËÒÁÎÁ ÓÌÉÛËÏÍ ×ÅÌÉËÏ, ÂÏÌØÛÅ ÞÅÍ %d" +044 "ïÐÃÉÑ lisp ÏÔÓÕÔÓÔ×ÕÅÔ" +045 "óÏÏÂÝÅÎÉÑ ÎÅ ×ÙËÌÀÞÅÎÙ: %s" +046 "óÏÏÂÝÅÎÉÑ ÎÅ ×ËÌÀÞÅÎÙ: %s" +047 "ïÐÃÉÑ %s ÄÏÌÖÎÁ ÓÏÓÔÏÑÔØ ÉÚ ÇÒÕÐÐ Ó Ä×ÕÍÑ ÓÉÍ×ÏÌÁÍÉ" +053 "óÔÁÒÔÏ×ÙÊ ÂÕÆÅÒ ÐÕÓÔ" +054 "âÕÆÅÒ %s ÐÕÓÔ" +055 "æÁÊÌÙ Ó ÓÉÍ×ÏÌÁÍÉ ÐÅÒÅ×ÏÄÁ ÓÔÒÏËÉ × ÉÍÅÎÉ ÎÅ ÍÏÇÕÔ ÂÙÔØ ×ÏÓÓÔÁÎÏ×ÌÅÎÙ" +056 "éÚÍÅÎÅÎÉÑ ÎÅ ÓÏÈÒÁÎÅÎÙ ÐÒÉ ËÒÁÈÅ ÓÅÓÓÉÉ" +057 "ëÏÐÉÒÏ×ÁÎÉÅ ÆÁÊÌÁ ÄÌÑ ×ÏÓÓÔÁÎÏ×ÌÅÎÉÑ..." +058 "óÏÈÒÁÎÅÎÉÅ ÎÅ ÕÄÁÌÏÓØ: %s" +059 "éÚÍÅÎÅÎÉÑ ÎÅ ÓÏÈÒÁÎÑÀÔÓÑ ÐÒÉ ÏÂÒÙ×Å ÓÅÓÓÉÉ" +060 "óÏÈÒÁÎÅÎÉÅ ËÏÐÉÉ ÆÁÊÌÁ ÎÅ ÕÄÁÌÏÓØ: %s" +061 "ëÏÐÉÒÏ×ÁÎÉÅ ÆÁÊÌÁ ÄÌÑ ×ÏÓÓÔÁÎÏ×ÌÅÎÉÑ..." +062 "éÎÆÏÒÍÁÃÉÉ ÎÁ ÐÏÌØÚÏ×ÁÔÅÌÑ %u ÎÅ ÎÁÊÄÅÎÏ" +063 "îÅ×ÏÚÍÏÖÎÏ ÚÁÝÉÔÉÔØ ÓÐÁÓÅÎÎÙÊ ÆÁÊÌ" +064 "âÕÆÅÒ ×ÏÓÓÔÁÎÏ×ÌÅÎÎÏÇÏ ÆÁÊÌÁ ÐÅÒÅÐÏÌÎÅÎ" +065 "÷ÏÓÓÔÁÎÏ×ÌÅÎÎÙÊ ÆÁÊÌ" +066 "%s: ÎÅ ÄÏ ËÏÎÃÁ ×ÏÓÓÔÁÎÏ×ÌÅÎÎÙÊ ÆÁÊÌ" +067 "%s: ÎÅ ÄÏ ËÏÎÃÁ ×ÏÓÓÔÁÎÏ×ÌÅÎÎÙÊ ÆÁÊÌ" +068 "æÁÊÌÏ× Ó ÉÍÅÎÅÍ %s, ËÏÔÏÒÙÅ ÷Ù ÍÏÖÅÔÅ ÞÉÔÁÔØ, ÎÅ ÓÕÝÅÓÔ×ÕÅÔ" +069 "åÓÔØ ÓÔÁÒÙÅ ×ÅÒÓÉÉ ÆÁÊÌÁ, ËÏÔÏÒÙÅ ÍÏÖÎÏ ×ÏÓÓÔÁÎÏ×ÉÔØ" +070 "óÕÝÅÓÔ×ÕÀÔ ÄÒÕÇÉÅ ÆÁÊÌÙ, ËÏÔÏÒÙÅ ÍÏÖÎÏ ×ÏÓÓÔÁÎÏ×ÉÔØ" +071 "Å-mail ÎÅ ÐÏÓÌÁÎ: %s" +072 "æÁÊÌ ÐÕÓÔ - ÉÓËÁÔØ ÎÅÞÅÇÏ" +073 "äÏÓÔÉÇÎÕÔ ËÏÎÅà ÆÁÊÌÁ ÂÅÚ ÎÁÈÏÖÄÅÎÉÑ ÏÂÒÁÚÃÁ ÐÏÉÓËÁ" +074 "îÅ ÚÁÄÁÎ ÏÂÒÁÚÅà ÐÏÉÓËÁ" +075 "ïÂÒÁÚÅà ÐÏÉÓËÁ ÎÅ ÎÁÊÄÅÎ" +076 "äÏÓÔÕÐÎÏ ÎÁÞÁÌÏ ÆÁÊÌÁ ÂÅÚ ÎÁÈÏÖÄÅÎÉÑ ÏÂÒÁÚÃÁ ÐÏÉÓËÁ" +077 "ðÏÉÓË ÚÁÃÉËÌÅÎ" +078 "ðÏÉÓË..." +079 "îÅÐÅÞÁÔÎÙÈ ÓÉÍ×ÏÌÏ× ÎÅ ÎÁÊÄÅÎÏ" +080 "îÅÉÚ×ÅÓÔÎÁÑ ËÏÍÁÎÄÁ" +082 "%s: ËÏÍÁÎÄÁ ÎÅ ÄÏÓÔÕÐÎÁ × ÒÅÖÉÍÅ ex" +083 "óÞÅÔÞÉË ÎÅ ÍÏÖÅÔ ÂÙÔØ ÎÕÌÅÍ" +084 "%s: ÎÅÐÒÁ×ÉÌØÎÏÅ ÕËÁÚÁÎÉÅ ÓÔÒÏËÉ" +085 "÷ÎÕÔÒÅÎÎÑÑ ÏÛÉÂËÁ × ÓÉÎÔÁËÓÉÓÅ (%s: %s)" +086 "éÓÐÏÌØÚÏ×ÁÎÉÅ: %s" +087 "%s: ×ÒÅÍÅÎÎÙÊ ÂÕÆÅÒ ÎÅ ÉÓÐÏÌØÚÏ×ÁÎ" +088 "íÅÔËÁ ÐÏÓÔÁ×ÌÅÎÁ ÐÅÒÅÄ ÓÔÒÏËÏÊ 1" +089 "íÅÔËÁ ÐÏÓÔÁ×ÌÅÎÁ ÐÏÓÌÅ ËÏÎÃÁ ÆÁÊÌÁ" +090 "@ Ó ÄÉÁÐÁÚÏÎÏÍ ×ÙÐÏÌÎÑÅÔÓÑ ËÏÇÄÁ ÆÁÊÌ/ÜËÒÁÎ ÉÚÍÅÎÅÎÙ" +091 "çÌÏÂÁÌØÎÁÑ/v ËÏÍÁÎÄÁ ×ÙÐÏÌÎÑÅÔÓÑ ËÏÇÄÁ ÆÁÊÌ/ÜËÒÁÎ ÉÚÍÅÎÅÎÙ" +092 "ëÏÍÁÎÄÁ ex ÎÅ ÕÄÁÌÁÓØ: ÐÏÓÌÅÄÕÀÝÉÅ ËÏÍÁÎÄÙ ÚÁÂÙÔÙ" +093 "ëÏÍÁÎÄÁ ex ÎÅ ÕÄÁÌÁÓØ: ÎÁÚÎÁÞÅÎÎÙÅ ËÌÁ×ÉÛÉ ÚÁÂÙÔÙ" +094 "÷ÔÏÒÏÊ ÁÄÒÅÓ ÍÅÎØÛÅ ÞÅÍ ÐÅÒ×ÙÊ" +095 "îÅ ÕËÁÚÁÎÏ ÎÁÚ×ÁÎÉÅ ÏÔÍÅÔËÉ" +096 "\\ ÎÅ ÚÁ×ÅÒÛÁÅÔÓÑ / ÉÌÉ ?" +097 "óÓÙÌËÁ Ë ÓÔÒÏËÅ Ó ÎÏÍÅÒÏÍ ÍÅÎØÛÅ 0" +098 "ëÏÍÁÎÄÁ %s ÎÅÉÚ×ÅÓÔÎÁ" +099 "ðÅÒÅÐÏÌÎÅÎÉÅ ÚÎÁÞÅÎÉÑ ÁÄÒÅÓÁ" +100 "îÅÄÏÂÏÒ ÚÎÁÞÅÎÉÑ ÁÄÒÅÓÁ" +101 "îÅÄÏÐÕÓÔÉÍÁÑ ËÏÍÂÉÎÁÃÉÑ × ÁÄÒÅÓÅ" +102 "îÅÐÒÁ×ÉÌØÎÙÊ ÁÄÒÅÓ: ×ÓÅÇÏ %lu ÓÔÒÏË × ÆÁÊÌÅ" +103 "îÅÐÒÁ×ÉÌØÎÙÊ ÁÄÒÅÓ: ÆÁÊÌ ÐÕÓÔ" +104 "ëÏÍÁÎÄÁ %s ÎÅ ÍÏÖÅÔ ÉÓÐÏÌØÚÏ×ÁÔØ ÁÄÒÅÓ 0" +105 "áÂÂÒÅ×ÉÁÔÕÒÙ ÏÔÓÕÔÓÔ×ÕÀÔ" +106 "áÂÂÒÅ×ÉÁÔÕÒÙ ÄÏÌÖÎÙ ÚÁËÁÎÞÉ×ÁÔØÓÑ ÓÉÍ×ÏÌÏÍ \"ÓÌÏ×\"" +107 "áÂÂÒÅ×ÉÁÔÕÒÙ ÎÅ ÍÏÇÕÔ ÓÏÄÅÒÖÁÔØ ÓÉÍ×ÏÌÙ ÔÁÂÕÌÑÃÉÉ ÉÌÉ ÐÒÏÂÅÌÙ" +108 "áÂÂÒÅ×ÉÁÔÕÒÙ ÎÅ ÍÏÇÕÔ ÓÏÞÅÔÁÔØÓÑ Ó ÓÉÍ×ÏÌÁÍÉ ÓÌÏ×/ÎÅ-ÓÌÏ×, ÚÁ ÉÓËÌÀÞÅÎÉÅÍ ËÏÎÃÁ ÓÔÒÏËÉ" +109 "\"%s\" ÎÅ Ñ×ÌÑÅÔÓÑ ÁÂÂÒÅ×ÉÁÔÕÒÏÊ" +110 "Vi ËÏÍÁÎÄÁ ÎÅ ÕÄÁÌÁÓØ: ÎÁÚÎÁÞÅÎÎÙÅ ËÌÁ×ÉÛÉ ÚÁÂÙÔÙ" +111 "æÁÊÌÏ× ÄÌÑ ÒÅÄÁËÔÉÒÏ×ÁÎÉÑ ÂÏÌØÛÅ ÎÅÔ" +112 "ïÔÓÕÔÓÔ×ÉÅ ÐÒÅÄÙÄÕÝÅÇÏ ÆÁÊÌÁ ÄÌÑ ÒÅÄÁËÔÉÒÏ×ÁÎÉÑ" +113 "ïÔÓÕÔÓÔ×ÉÅ ÐÒÅÄÙÄÕÝÅÇÏ ÆÁÊÌÁ ÄÌÑ ÐÒÏÓÍÏÔÒÁ ÎÁÚÁÄ" +114 "îÅÔ ÆÁÊÌÏ×" +115 "ïÔÓÕÔÓÔ×ÉÅ ÐÒÅÄÙÄÕÝÅÊ ËÏÍÁÎÄÙ ÄÌÑ ÚÁÍÅÎÙ \"!\"" +116 "ïÔÓÕÔÓÔ×ÉÅ ÚÁÍÅÎÙ ÄÌÑ %%" +117 "ïÔÓÕÔÓÔ×ÉÅ ÚÁÍÅÎÙ ÄÌÑ #" +118 "ïÛÉÂËÁ: execl: %s" +119 "ïÛÉÂËÁ ××ÏÄÁ/×Ù×ÏÄÁ: %s" +120 "æÁÊÌ ÉÚÍÅÎÅÎ Ó ÍÏÍÅÎÔÁ ÐÏÓÌÅÄÎÅÊ ÐÏÌÎÏÊ ÚÁÐÉÓÉ: ÉÓÐÏÌØÚÕÊÔÅ ! ÄÌÑ ÏÂÈÏÄÁ" +121 "îÅ×ÏÚÍÏÖÎÏ ÎÁÊÔÉ ÄÏÍÁÛÎÉÊ ËÁÔÁÌÏÇ" +122 "îÏ×ÙÊ ËÁÔÁÌÏÇ: %s" +123 "îÅÔ ×ÙÒÅÚÁÎÎÙÈ ÂÕÆÅÒÏ×" +124 "ëÏÍÁÎÄÁ %s ÎÅ ÍÏÖÅÔ ÂÙÔØ ÉÓÐÏÌØÚÏ×ÁÎÁ ×ÎÕÔÒÉ ÇÌÏÂÁÌØÎÏÊ ÉÌÉ v ËÏÍÁÎÄÙ" +125 "%s/%s: ÎÅ ÏÔËÒÙÔ: ÎÅ ÐÒÉÎÁÄÌÅÖÉÔ ÷ÁÍ ÉÌÉ root-Õ" +126 "%s/%s: ÎÅ ÏÔËÒÙÔ: ÎÅ ÐÒÉÎÁÄÌÅÖÉÔ ÷ÁÍ" +127 "%s/%s: ÎÅ ÏÔËÒÙÔ: ×ÏÚÍÏÖÎÏÓÔØ ÚÁÐÉÓÉ Õ ÐÏÌØÚÏ×ÁÔÅÌÑ, ÎÅ Ñ×ÌÑÀÝÅÇÏÓÑ ×ÌÁÄÅÌØÃÅÍ" +128 "%s: ÎÅ ÓÞÉÔÁÎ: ÎÅ ÐÒÉÎÁÄÌÅÖÉÔ ÷ÁÍ ÉÌÉ root-Õ" +129 "%s: ÎÅ ÓÞÉÔÁÎ: ÎÅ ÐÒÉÎÁÄÌÅÖÉÔ ÷ÁÍ" +130 "%s: ÎÅ ÓÞÉÔÁÎ: ×ÏÚÍÏÖÎÏÓÔØ ÚÁÐÉÓÉ Õ ÐÏÌØÚÏ×ÁÔÅÌÑ, ÎÅ Ñ×ÌÑÀÝÅÇÏÓÑ ×ÌÁÄÅÌØÃÅÍ" +131 "ðÏÓÌÅÄÕÀÝÉÅ ÓÔÒÏËÉ ÏÔÓÕÔÓÔ×ÕÀÔ" +132 "ïÔÓÕÔÓÔ×ÉÅ ÐÁÒÁÍÅÔÒÏ× ××ÏÄÁ" +133 "ïÔÓÕÔÓÔ×ÉÅ ÐÁÒÁÍÅÔÒÏ× ËÏÍÁÎÄÙ" +134 "óÉÍ×ÏÌ %s ÎÅ ÍÏÖÅÔ ÂÙÔØ ÐÅÒÅÎÁÚÎÁÞÅÎ" +135 "\"%s\" ÎÁ ÄÁÎÎÙÊ ÍÏÍÅÎÔ ÎÅ ÎÁÚÎÁÞÅÎ" +136 "éÍÑ ÍÅÔËÉ ÄÏÌÖÎÏ ÂÙÔØ ÏÄÎÉÍ ÓÉÍ×ÏÌÏÍ" +137 "%s ÓÕÝÅÓÔ×ÕÅÔ, ÎÅ ÚÁÐÉÓÁÎ; ÉÓÐÏÌØÚÕÊÔÅ ! ÄÌÑ ÏÂÈÏÄÁ" +138 "îÏ×ÙÊ ÆÁÊÌ exrc: %s" +139 "óÔÒÏËÁ ÐÅÒÅÎÏÓÁ ÎÁÈÏÄÉÔÓÑ ×ÎÕÔÒÉ ÐÁÒÁÍÅÔÒÏ× ÐÅÒÅÎÏÓÁ" +140 "ëÏÍÁÎÄÁ open ÐÏÄÒÁÚÕÍÅ×ÁÅÔ ÕÓÔÁÎÏ×ËÕ ÏÐÃÉÉ open" +141 "ëÏÍÁÎÄÁ open ÎÅ ÒÅÁÌÉÚÏ×ÁÎÁ" +142 "úÁÝÉÔÁ ÆÁÊÌÁ ÎÅ×ÏÚÍÏÖÎÁ" +143 "æÁÊÌ ÚÁÝÉÝÅÎ" +144 "%s ÒÁÓÛÉÒÉÌÓÑ × ÓÌÉÛËÏÍ ÂÏÌØÛÏÅ ËÏÌÉÞÅÓÔ×Ï ÉÍÅÎ ÆÁÊÌÏ×" +145 "ôÏÌØËÏ ÏÂÙÞÎÙÅ ÆÁÊÌÙ ÉÌÉ ÉÍÅÎÏ×ÁÎÎÙÅ ËÁÎÁÌÙ ÍÏÇÕÔ ÂÙÔØ ÐÒÏÞÉÔÁÎÙ" +146 "%s: ÚÁÝÉÔÁ ÎÁ ÞÔÅÎÉÅ ÂÙÌÁ ÎÅÄÏÓÔÕÐÎÁ" +147 "þÔÅÎÉÅ..." +148 "%s: %lu ÓÔÒÏË, %lu ÓÉÍ×ÏÌÏ×" +149 "îÅÔ ÔÅÎÅ×ÙÈ ÏËÏÎ" +150 "ëÏÍÁÎÄÁ script ÉÓÐÏÌØÚÕÅÔÓÑ ÔÏÌØËÏ × ÒÅÖÉÍÅ vi" +151 "îÅÔ ËÏÍÁÎÄÙ ÄÌÑ ÉÓÐÏÌÎÅÎÉÑ" +152 "ïÐÃÉÑ shiftwidth ÕÓÔÁÎÏ×ÌÅÎÁ ÎÁ 0" +153 "ðÅÒÅÐÏÌÎÅÎÉÅ ÓÞÅÔÞÉËÁ" +154 "ãÉËÌ ×ÙÐÏÌÎÅÎ ÎÅ ÄÏ ËÏÎÃÁ" +155 "õËÁÚÁÎÏ ÒÅÇÕÌÑÒÎÏÅ ×ÙÒÁÖÅÎÉÅ: ÆÌÁÇ r ÎÅ ÎÕÖÅÎ" +156 "æÌÁÇÉ #, l É p ÎÅ ÍÏÇÕÔ ÂÙÔØ ÏÂßÅÄÉÎÅÎÙ Ó ÆÌÁÇÏÍ c × ÒÅÖÉÍÅ vi" +157 "óÏ×ÐÁÄÅÎÉÊ ÎÅÔ" +158 "íÅÔËÁ ÏÔÓÕÔÓÔ×ÕÅÔ" +159 "÷ ÓÔÅËÅ ÍÅÔÏË ÚÁÐÉÓÅÊ ÍÅÎØÛÅ, ÞÅÍ %s, ÉÓÐÏÌØÚÕÊÔÅ :display t[ags]" +160 "æÁÊÌÁ Ó ÉÍÅÎÅÍ %s × ÓÔÅËÅ ÍÅÔÏË ÎÅÔ; ÉÓÐÏÌØÚÕÊÔÅ :display t[ags]" +161 "îÁÖÍÉÔÅ Enter ÞÔÏÂÙ ÐÒÏÄÏÌÖÉÔØ: " +162 "%s: ÍÅÔËÁ ÎÅ ÎÁÊÄÅÎÁ" +163 "%s: ÐÌÏÈÁÑ ÍÅÔËÁ × %s" +164 "%s: ÎÏÍÅÒ ÓÔÒÏËÉ ÍÅÔËÉ ×ÙÛÅÌ ÚÁ ËÏÎÅà ÆÁÊÌÁ" +165 "óÔÅË ÍÅÔÏË ÐÕÓÔ" +166 "%s: ÏÂÒÁÚÅà ÐÏÉÓËÁ ÎÅ ÎÁÊÄÅÎ" +167 "ÅÝÅ %d ÆÁÊÌÏ× ÄÌÑ ÒÅÄÁËÔÉÒÏ×ÁÎÉÑ" +168 "âÕÆÅÒ %s ÐÕÓÔ" +169 "ðÏÄÔ×ÅÒÄÉÔØ ÉÚÍÅÎÅÎÉÑ? [n]" +170 "ðÒÅÒ×ÁÎÏ" +171 "ïÔÓÕÔÓÔ×ÉÅ ÂÕÆÅÒÁ ÄÌÑ ÉÓÐÏÌØÚÏ×ÁÎÉÑ" +172 "îÅÔ ÐÒÅÄÙÄÕÝÅÇÏ ÒÅÇÕÌÑÒÎÏÇÏ ×ÙÒÁÖÅÎÉÑ" +173 "ëÏÍÁÎÄÁ %s ÐÏÄÒÁÚÕÍÅ×ÁÅÔ ÎÁÌÉÞÉÅ ÐÒÏÞÔÅÎÎÏÇÏ ÆÁÊÌÁ" +174 "éÓÐÏÌØÚÏ×ÁÎÉÅ: %s" +175 "ëÏÍÁÎÄÁ visual ÐÏÄÒÁÚÕÍÅ×ÁÅÔ ÏÂÑÚÁÔÅÌØÎÕÀ ÕÓÔÁÎÏ×ËÕ ÏÐÃÉÉ open" +177 "ðÕÓÔÏÊ ÆÁÊÌ" +178 "îÅÔ ÐÒÅÄÙÄÕÝÅÇÏ ÐÏÉÓËÁ F, f, T, ÉÌÉ t" +179 "%s ÎÅ ÎÁÊÄÅÎÏ" +180 "îÅÔ ÐÒÅÄÙÄÕÝÅÇÏ ÆÁÊÌÁ ÄÌÑ ÒÅÄÁËÔÉÒÏ×ÁÎÉÑ" +181 "ëÕÒÓÏÒ ÓÔÏÉÔ ÎÅ ÎÁ ÃÉÆÒÅ" +182 "ðÏÌÕÞÅÎÎÏÅ ÞÉÓÌÏ ÓÌÉÛËÏÍ ×ÅÌÉËÏ" +183 "ðÏÌÕÞÅÎÎÏÅ ÞÉÓÌÏ ÓÌÉÛËÏÍ ÍÁÌÏ" +184 "ðÏÄÈÏÄÑÝÅÇÏ ÓÉÍ×ÏÌÁ ÎÅÔ ÎÁ ÜÔÏÊ ÓÔÒÏËÅ" +185 "ðÏÄÈÏÄÑÝÉÊ ÓÉÍ×ÏÌ ÎÅ ÎÁÊÄÅÎ" +186 "îÅÔ ÓÉÍ×ÏÌÏ× ÄÌÑ ÕÄÁÌÅÎÉÑ" +187 "äÒÕÇÏÇÏ ÜËÒÁÎÁ ÎÅ ÓÕÝÅÓÔ×ÕÅÔ" +188 "óÉÍ×ÏÌÙ ÐÏÓÌÅ ÓÔÒÏËÉ ÄÌÑ ÐÏÉÓËÁ, ÓÍÅÝÅÎÉÑ ÓÔÒÏËÉ É/ÉÌÉ ËÏÍÁÎÄÙ z" +189 "ðÒÏÛÌÙÊ ÏÂÒÁÚÅà ÐÏÉÓËÁ ÏÔÓÕÔÓÔ×ÕÅÔ" +190 "ðÏÉÓË ÚÁ×ÅÒÛÉÌÓÑ ÎÁ ÎÁÞÁÌØÎÏÊ ÐÏÚÉÃÉÉ" +191 "áÂÂÒÅ×ÉÁÔÕÒÁ ÐÒÅ×ÙÓÉÌÁ ÌÉÍÉÔ ÒÁÓÛÉÒÅÎÉÑ: ÓÉÍ×ÏÌÙ ÚÁÂÙÔÙ" +192 "óÉÍ×ÏÌ ÎÅÐÒÁ×ÉÌÅÎ; Ë×ÏÔÉÒÕÊÔÅ ÄÌÑ ××ÏÄÁ" +193 "õÖÅ ÎÁ ÎÁÞÁÌÅ ×ÓÔÁ×ËÉ" +194 "îÅÔ ÓÉÍ×ÏÌÏ× ÄÌÑ ÕÄÁÌÅÎÉÑ" +195 "ðÅÒÅÄ×ÉÖÅÎÉÅ ÚÁ ËÏÎÅà ÆÁÊÌÁ" +196 "ðÅÒÅÄ×ÉÖÅÎÉÅ ÚÁ ËÏÎÅà ÓÔÒÏËÉ" +197 "ä×ÉÖÅÎÉÅ ÓÔÒÏËÉ ÎÅ ÓÄÅÌÁÎÏ" +198 "õÖÅ ÎÁ ÎÁÞÁÌÅ ÆÁÊÌÁ" +199 "ä×ÉÖÅÎÉÅ ËÕÒÓÏÒÁ ÚÁ ÎÁÞÁÌÏ ÆÁÊÌÁ" +200 "õÖÅ × ÐÅÒ×ÏÊ ËÏÌÏÎËÅ" +201 "âÕÆÅÒÙ ÄÏÌÖÎÙ ÂÙÔØ ÕËÁÚÁÎÙ ÄÏ ×ÙÐÏÌÎÅÎÉÑ ËÏÍÁÎÄÙ" +202 "õÖÅ ÎÁ ËÏÎÃÅ ÆÁÊÌÁ" +203 "õÖÅ ÎÁ ËÏÎÃÅ ÓÔÒÏËÉ" +204 "%s ÎÅ Ñ×ÌÑÅÔÓÑ ËÏÍÁÎÄÏÊ VI" +205 "éÓÐÏÌØÚÏ×ÁÎÉÅ: %s" +206 "îÅÔ ÓÉÍ×ÏÌÏ× ÄÌÑ ÕÄÁÌÅÎÉÑ" +207 "ëÏÍÁÎÄÁ Q ÔÒÅÂÕÅÔ ex ÉÎÔÅÒÆÅÊÓ ÔÅÒÍÉÎÁÌÁ" +208 "îÅÔ ËÏÍÁÎÄÙ ÄÌÑ ÐÏ×ÔÏÒÁ" +209 "æÁÊÌ ÐÕÓÔ" +210 "ëÏÍÁÎÄÁ %s ÎÅ ÍÏÖÅÔ ÂÙÔØ ÉÓÐÏÌØÚÏ×ÁÎÁ ËÁË ËÏÍÁÎÄÁ ÐÅÒÅÍÅÝÅÎÉÑ" +211 "õÖÅ × ËÏÍÁÎÄÎÏÍ ÒÅÖÉÍÅ" +212 "ëÕÒÓÏÒ ÎÁÈÏÄÉÔÓÑ ÎÅ ÎÁ ÓÌÏ×Å" +214 "úÎÁÞÅÎÉÅ ÏÐÃÉÉ windows ÓÌÉÛËÏÍ ×ÅÌÉËÏ, ÍÁËÓÉÍÁÌØÎÏÅ ÚÎÁÞÅÎÉÅ = %u" +215 "äÏÂÁ×ÉÔØ" +216 "éÚÍÅÎÉÔØ" +217 "ëÏÍÁÎÄÁ" +218 "÷ÓÔÁ×ÉÔØ" +219 "úÁÍÅÎÉÔØ" +220 "ä×ÉÖÅÎÉÅ ËÕÒÓÏÒÁ ÚÁ ËÏÎÅà ÜËÒÁÎÁ" +221 "ä×ÉÖÅÎÉÅ ËÕÒÓÏÒÁ ÚÁ ÎÁÞÁÌÏ ÜËÒÁÎÁ" +222 "äÌÑ ÒÁÚÄÅÌÅÎÉÑ ÜËÒÁÎ ÄÏÌÖÅÎ ÂÙÔØ ÂÏÌØÛÅ ÞÅÍ ÓÔÒÏËÉ %d" +223 "ôÅÎÅ×ÙÈ ÏËÏÎ ÎÅÔ" +224 "îÅ ÓÕÝÅÓÔ×ÕÅÔ ÔÅÎÅ×ÏÇÏ ÏËÎÁ Ó ÒÅÄÁËÔÉÒÏ×ÁÎÉÅÍ ÆÁÊÌÁ %s" +225 "÷Ù ÎÅ ÍÏÖÅÔÅ ÓÄÅÌÁÔØ ÅÄÉÎÓÔ×ÅÎÎÏÅ ÏËÎÏ ÔÅÎÅ×ÙÍ" +226 "üËÒÁÎ ÍÏÖÅÔ ÂÙÔØ ÓÖÁÔ" +227 "üËÒÁÎ ÎÅ ÍÏÖÅÔ ÂÙÔØ ÓÖÁÔ ÔÏÌØËÏ ÄÏ %d ÓÔÒÏË" +228 "üËÒÁÎ ÎÅ ÍÏÖÅÔ ÂÙÔØ ÒÁÓÛÉÒÅÎ" +230 "üÔÏÔ ÜËÒÁÎ ÎÅ ÍÏÖÅÔ ÂÙÔØ ÐÒÉÏÓÔÁÎÏ×ÌÅÎ" +231 "ðÒÅÒ×ÁÎÏ: ÎÁÚÎÁÞÅÎÎÙÅ ËÌÁ×ÉÛÉ ÚÁÂÙÔÙ" +232 "vi: ×ÒÅÍÅÎÎÙÊ ÂÕÆÅÒ ÎÅ ÏÓ×ÏÂÏÖÄÅÎ" +233 "äÁÎÎÙÊ ÔÉÐ ÔÅÒÍÉÎÁÌÁ ÎÅ ÉÍÅÅÔ ËÌÁ×ÉÛÉ %s" +234 "íÏÖÅÔ ÂÙÔØ ÕËÁÚÁÎ ÔÏÌØËÏ ÏÄÉÎ ÂÕÆÅÒ" +235 "þÉÓÌÏ ÂÏÌØÛÅ ÞÅÍ %lu" +236 "ðÒÅÒ×ÁÎÏ" +237 "îÅ×ÏÚÍÏÖÎÏ ÓÏÚÄÁÔØ ×ÒÅÍÅÎÎÙÊ ÆÁÊÌ" +238 "÷ÎÉÍÁÎÉÅ: %s ÓÐÅÃÉÁÌØÎÙÊ ÆÁÊÌ" +239 "%s ÕÖÅ ÚÁÂÌÏËÉÒÏ×ÁÎ, ÄÏÓÔÕÐÅÎ ÔÏÌØËÏ ÎÁ ÞÔÅÎÉÅ" +240 "%s: ÕÄÁÌÅÎ" +241 "%s: ÚÁËÒÙÔ" +242 "%s: ÕÄÁÌÅÎ" +243 "%s: ÕÄÁÌÅÎ" +244 "æÁÊÌ ÔÏÌØËÏ ÄÌÑ ÞÔÅÎÉÑ, ÎÅ ÚÁÐÉÓÁÎ: éÓÐÏÌØÚÕÊÔÅ ! ÄÌÑ ÏÂÈÏÄÁ" +245 "æÁÊÌ ÔÏÌØËÏ ÄÌÑ ÞÔÅÎÉÑ, ÎÅ ÚÁÐÉÓÁÎ" +246 "%s ÓÕÝÅÓÔ×ÕÅÔ, ÎÅ ÚÁÐÉÓÁÎ; ÉÓÐÏÌØÚÕÊÔÅ ! ÄÌÑ ÏÂÈÏÄÁ" +247 "%s ÓÕÝÅÓÔ×ÕÅÔ, ÎÅ ÚÁÐÉÓÁÎ" +248 "éÓÐÏÌØÚÕÊÔÅ ! ÄÌÑ ÞÁÓÔÉÞÎÏÊ ÚÁÐÉÓÉ ÆÁÊÌÁ" +249 "þÁÓÔØ ÆÁÊÌÁ, ÆÁÊÌ ÎÅ ÚÁÐÉÓÁÎ" +250 "%s: æÁÊÌ ÉÚÍÅÎÑÌÓÑ ÐÏÚÄÎÅÅ, ÞÅÍ ÄÁÎÎÁÑ ËÏÐÉÑ: ÉÓÐÏÌØÚÕÊÔÅ ! ÄÌÑ ÏÂÈÏÄÁ" +251 "%s: æÁÊÌ ÉÚÍÅÎÑÌÓÑ ÐÏÚÄÎÅÅ, ÞÅÍ ÄÁÎÎÁÑ ËÏÐÉÑ" +252 "%s: ÚÁÝÉÔÁ ÎÁ ÚÁÐÉÓØ ÂÙÌÁ ÎÅÄÏÓÔÕÐÎÁ" +253 "úÁÐÉÓØ..." +254 "%s: ÷îéíáîéå: æáêì õóåþåî" +255 "õÖÅ ÐÒÉÓÕÔÓÔ×ÕÅÔ × ÐÅÒ×ÏÊ ÍÅÔËÅ ÄÁÎÎÏÊ ÇÒÕÐÐÙ" +256 "%s: ÎÏ×ÙÊ ÆÁÊÌ: %lu ÓÔÒÏË, %lu ÓÉÍ×ÏÌÏ×" +257 "%s: %lu ÓÔÒÏË, %lu ÓÉÍ×ÏÌÏ×" +258 "%s ÒÁÓÛÉÒÉÌÓÑ × ÓÌÉÛËÏÍ ÂÏÌØÛÏÅ ËÏÌÉÞÅÓÔ×Ï ÉÍÅÎ ÆÁÊÌÏ×" +259 "%s: ÓÐÅÃÉÁÌØÎÙÊ ÆÁÊÌ" +260 "%s: ÎÅ ÐÒÉÎÁÄÌÅÖÉÔ ÷ÁÍ" +261 "%s: ÄÏÓÔÕÐÅÎ ÎÅ ÔÏÌØËÏ ÷ÁÍ" +262 "æÁÊÌ ÉÚÍÅÎÅÎ ÓÏ ×ÒÅÍÅÎÉ ÐÏÓÌÅÄÎÅÊ ÚÁÐÉÓÉ: ÓÏÈÒÁÎÉÔÅ ÉÌÉ ÉÓÐÏÌØÚÕÊÔÅ ! ÄÌÑ ÏÂÈÏÄÁ" +263 "æÁÊÌ ÉÚÍÅÎÅÎ ÓÏ ×ÒÅÍÅÎÉ ÐÏÓÌÅÄÎÅÊ ÚÁÐÉÓÉ: ÓÏÈÒÁÎÉÔÅ ÉÌÉ ÉÓÐÏÌØÚÕÊÔÅ :edit ÄÌÑ ÏÂÈÏÄÁ" +264 "æÁÊÌ ÉÚÍÅÎÅÎ ÓÏ ×ÒÅÍÅÎÉ ÐÏÓÌÅÄÎÅÊ ÚÁÐÉÓÉ: ÓÏÈÒÁÎÉÔÅ ÉÌÉ ÉÓÐÏÌØÚÕÊÔÅ ! ÄÌÑ ÏÂÈÏÄÁ" +265 "æÁÊÌ ×ÒÅÍÅÎÎÙÊ: ×ÙÈÏÄ ÓÏÔÒÅÔ ÌÀÂÙÅ ÉÚÍÅÎÅÎÉÑ" +266 "æÁÊÌ ÔÏÌØËÏ ÄÌÑ ÞÔÅÎÉÑ, Á×ÔÏÚÁÐÉÓØ ÎÅ ÓÒÁÂÏÔÁÌÁ" +267 "úÁÐÉÓÉ ÎÁÞÁÔÙ ÚÁÎÏ×Ï" +268 "ÐÏÄÔ×ÅÒÄÉÔØ? [ynq]" +269 "îÁÖÍÉÔÅ ÌÀÂÕÀ ËÌÁ×ÉÛÕ ÞÔÏÂÙ ÐÒÏÄÏÌÖÉÔØ: " +270 "îÁÖÍÉÔÅ ÌÀÂÕÀ ËÌÁ×ÉÛÕ ÞÔÏÂÙ ÐÒÏÄÏÌÖÉÔØ [: ÞÔÏÂÙ ××ÅÓÔÉ ÅÝÅ ex ËÏÍÁÎÄÙ]: " +271 "îÁÖÍÉÔÅ ÌÀÂÕÀ ËÌÁ×ÉÛÕ ÞÔÏÂÙ ÐÒÏÄÏÌÖÉÔØ [q ÞÔÏÂÙ ×ÙÊÔÉ]: " +272 "üÔÁ ÆÏÒÍÁ %s ÔÒÅÂÕÅÔ ex ÉÎÔÅÒÆÅÊÓ ÔÅÒÍÉÎÁÌÁ" +273 "÷ÈÏÄ × ÒÅÖÉÍ ××ÏÄÁ ex." +274 "ëÏÍÁÎÄÁ ÎÅ ÕÄÁÌÁÓØ, ÆÁÊÌ ÅÝÅ ÎÅ ÐÒÏÞÔÅÎ." +275 " ÐÒÏÄ?" +276 "îÅÏÖÉÄÁÎÎÏÅ ÓÉÍ×ÏÌØÎÏÅ ÓÏÂÙÔÉÅ" +277 "îÅÏÖÉÄÁÎÎÏÅ ÓÏÂÙÔÉÅ 'ËÏÎÅà ÆÁÊÌÁ'" +278 "ðÏ ÚÁÐÒÏÓÕ ÓÏ×ÐÁÄÅÎÉÊ ÎÅÔ" +279 "îÅÏÖÉÄÁÎÎÏÅ ÓÏÂÙÔÉÅ ÐÒÅÒÙ×ÁÎÉÑ" +280 "îÅÏÖÉÄÁÎÎÏÅ ÓÏÂÙÔÉÅ ×ÙÈÏÄÁ" +281 "îÅÏÖÉÄÁÎÎÏÅ ÓÏÂÙÔÉÅ ÐÅÒÅÒÉÓÏ×ËÉ" +282 "õÖÅ ÐÒÉÓÕÔÓÔ×ÕÅÔ × ÐÏÓÌÅÄÎÅÊ ÍÅÔËÅ ÄÁÎÎÏÊ ÇÒÕÐÐÙ" +283 "ëÏÍÁÎÄÁ %s ÔÒÅÂÕÅÔ ex ÉÎÔÅÒÆÅÊÓ ÔÅÒÍÉÎÁÌÁ" +284 "üÔÁ ÆÏÒÍÁ %s ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔÓÑ ÐÏËÁ ÕÓÔÁÎÏ×ÌÅÎÁ ÏÐÃÉÑ ÂÅÚÏÐÁÓÎÏÇÏ ÒÅÄÁËÔÉÒÏ×ÁÎÉÑ" +285 "îÅÏÖÉÄÁÎÎÏÅ ÓÔÒÏËÏ×ÏÅ ÓÏÂÙÔÉÅ" +286 "îÅÏÖÉÄÁÎÎÏÅ ÓÏÂÙÔÉÅ ÔÁÊÍÁÕÔÁ" +287 "îÅÏÖÉÄÁÎÎÏÅ ÓÏÂÙÔÉÅ ÚÁÐÉÓÉ" +288 "äÌÑ ÒÁÚÄÅÌÅÎÉÑ ÜËÒÁÎ ÄÏÌÖÅÎ ÂÙÔØ ÂÏÌØÛÅ ÞÅÍ ÓÔÏÌÂÃÙ %d" +289 "Shell ÒÁÓÛÉÒÅÎÉÑ ÎÅ ÐÏÄÄÅÒÖÉ×ÁÀÔÓÑ ÐÏËÁ ÕÓÔÁÎÏ×ÌÅÎÁ ÏÐÃÉÑ ÂÅÚÏÐÁÓÎÏÇÏ ÒÅÄÁËÔÉÒÏ×ÁÎÉÑ" +290 "ëÏÍÁÎÄÁ %s ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔÓÑ ÐÏËÁ ÕÓÔÁÎÏ×ÌÅÎÁ ÏÐÃÉÑ ÂÅÚÏÐÁÓÎÏÇÏ ÒÅÄÁËÔÉÒÏ×ÁÎÉÑ" +291 "set: ÏÐÃÉÑ %s ÎÅ ÍÏÖÅÔ ÂÙÔØ ×ÙËÌÀÞÅÎÁ" +292 "üËÒÁÎ ÓÌÉÛËÏÍ ÍÁÌ" +293 "ÄÏÂÁ×ÌÅÎÏ" +294 "ÉÚÍÅÎÅÎÏ" +295 "ÕÄÁÌÅÎÏ" +296 "ÐÒÉÓÏÅÄÉÎÅÎÏ" +297 "ÐÅÒÅÍÅÝÅÎÏ" +298 "ÓÍÅÝÅÎÏ" +299 "ÓËÏÐÉÒÏ×ÁÎÏ" +300 "ÓÔÒÏËÁ" +301 "ÓÔÒÏËÉ" +303 "æÁÊÌ ÉÚÍÅÎÅÎ Ó ÍÏÍÅÎÔÁ ÐÏÓÌÅÄÎÅÊ ÚÁÐÉÓÉ." +304 "Shell ÒÁÓÛÉÒÅÎÉÅ ÎÅ ÕÄÁÌÏÓØ" +305 "îÅÔ ÕËÁÚÁÎÎÏÊ %s ÏÐÃÉÉ ÒÅÄÁËÔÉÒÏ×ÁÎÉÑ" +307 "îÅÔ ex ËÏÍÁÎÄÙ ÄÌÑ ×ÙÐÏÌÎÅÎÉÑ" +308 "÷×ÅÄÉÔÅ ÄÌÑ ×ÙÐÏÌÎÅÎÉÑ ËÏÍÁÎÄÙ, :q ÞÔÏÂÙ ×ÙÊÔÉ" +309 "éÓÐÏÌØÚÕÊÔÅ \"cscope help\" ÄÌÑ ÐÏÍÏÝÉ" +310 "îÅÔ ÚÁÐÕÝÅÎÎÏÇÏ cscope ÓÏÅÄÉÎÅÎÉÑ" +311 "%s: ÎÅÉÚ×ÅÓÔÎÙÊ ÔÉÐ ÐÏÉÓËÁ: ÉÓÐÏÌØÚÕÊÔÅ ÏÄÉÎ ÉÚ %s" +312 "%d: ÎÅÔ ÔÁËÏÇÏ cscope ÓÅÁÎÓÁ" +313 "set: %s ÏÐÃÉÑ ÎÉËÏÇÄÁ ÎÅ ÍÏÖÅÔ ÂÙÔØ ×ËÌÀÞÅÎÁ" +314 "set: %s ÏÐÃÉÑ ÎÉËÏÇÄÁ ÎÅ ÍÏÖÅÔ ÂÙÔØ ÕÓÔÁÎÏ×ÌÅÎÁ × 0" +315 "%s: ÄÏÂÁ×ÌÅÎÏ: %lu ÓÔÒÏË, %lu ÓÉÍ×ÏÌÏ×" +316 "îÅÏÖÉÄÁÎÎÏÅ ÓÏÂÙÔÉÅ ÉÚÍÅÎÅÎÉÑ ÒÁÚÍÅÒÁ" +317 "%d ÆÁÊÌÏ× ÄÌÑ ÒÅÄÁËÔÉÒÏ×ÁÎÉÑ" +319 "%d ÜËÒÁÎÏ× × ÆÏÎÏ×ÏÍ ÒÅÖÉÍÅ; ÉÓÐÏÌØÚÕÊÔÅ :display ÞÔÏÂÙ ÐÅÒÅÞÉÓÌÉÔØ ÉÈ" +320 "îÅÉÚ×ÅÓÔÎÁÑ ÐÏÚÉÃÉÑ ËÕÒÓÏÒÁ" +321 "ðÒÅÏÂÒÁÚÏ×ÁÎÉÅ ËÏÄÉÒÏ×ËÉ ÆÁÊÌÏ× ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔÓÑ" +322 "ðÒÅÏÂÒÁÚÏ×ÁÎÉÅ ËÏÄÉÒÏ×ËÉ ××ÏÄÁ ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔÓÑ" +323 "îÅ×ÅÒÎÙÊ ××ÏÄ. õÓÅÞÅÎÏ." +324 "ïÛÉÂËÁ ÐÒÅÏÂÒÁÚÏ×ÁÎÉÑ × ÓÔÒÏËÅ %d" Property changes on: vendor/nvi/2.2.0-05ed8b9/catalog/ru_RU.KOI8-R.base ___________________________________________________________________ Added: fbsd:notbinary ## -0,0 +1 ## +catalog/dutch.base \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain; charset=KOI8-R \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/catalog/ru_RU.KOI8-R.owner =================================================================== --- vendor/nvi/2.2.0-05ed8b9/catalog/ru_RU.KOI8-R.owner (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/catalog/ru_RU.KOI8-R.owner (revision 366308) @@ -0,0 +1,3 @@ +Andrey A. Chernov +Dima Ruban +Pavel Timofeev Property changes on: vendor/nvi/2.2.0-05ed8b9/catalog/ru_RU.KOI8-R.owner ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/catalog/spanish.base =================================================================== --- vendor/nvi/2.2.0-05ed8b9/catalog/spanish.base (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/catalog/spanish.base (revision 366308) @@ -0,0 +1,306 @@ +002 "Desbordamiento de longitud de línea" +003 "no se puede borrar la línea %lu" +004 "no se puede añadir la línea %lu" +005 "no se puede insertar en la línea %lu" +006 "no se puede guardar la línea %lu" +007 "no se puede obtener la última línea" +008 "Error: no se puede recuperar la línea %lu" +009 "Archivo de log" +010 "No se realiza log, no se puede deshacer" +011 "No hay cambios para deshacer" +012 "No se realiza log, no se puede deshacer" +013 "No se realiza log, no se puede remontar hacia adelante" +014 "No hay cambios para rehacer" +015 "%s/%d: error de log" +016 "La entrada y salida estándar de Vi debe ser una terminal" +017 "Marcar %s: no determinado" +018 "Marcar %s: se borró la línea" +019 "Marcar %s: la posición del cursor ya no existe" +020 "Error: " +021 "nuevo archivo" +022 "nombre cambiado" +023 "modificado" +024 "no modificado" +025 "DESTRABADO" +026 "lectura solamente" +027 "línea %lu de %lu [%ld%%]" +028 "archivo vacío" +029 "línea %lu" +030 "El archivo %s no es un catálogo de mensajes" +031 "No se puede determinar la opción por omisión %s" +032 "Uso: %s" +033 "determinar: no hay opción %s: 'determinar todo' establece todos los valores de opción" +034 "determinar: [no] hay opción %s no tiene valor" +035 "determinar: opción %s no es booleano" +036 "determinar: opción %s: %s" +037 "determinar: opción %s: %s: desbordamiento de valores" +038 "determinar: opción %s: %s es un número ilegal" +039 "determinar: opción %s no es booleano" +040 "Las columnas en pantalla son demasiado pequeñas, menos de %d" +041 "Las columnas en pantalla son demasiado grandes, más de %d" +042 "Las líneas en pantalla son demasiado pequeñas, menos de %d" +043 "Las líneas en pantalla son demasiado grandes, más de %d" +044 "La opción lisp no está implementada" +045 "mensajes no desconectados: %s" +046 "mensajes no conectados: %s" +047 "La opción de %s debe estar en dos grupos de caracteres" +053 "El buffer por omisión está vacío" +054 "El buffer %s está vacío" +055 "Los archivos con nuevas líneas en el nombre son irrecuperables" +056 "Las modificaciones no pueden recuperarse si la sesión falla" +057 "Copiando archivo para recuperación..." +058 "Preservación fracasada: %s" +059 "Las modificaciones no pueden recuperarse si la sesión falla" +060 "Archivo de respaldo fracasado: %s" +061 "Copiando archivo para recuperación..." +062 "Información sobre identificación del usuario %u no encontrada" +063 "No se puede trabar archivo de recuperación" +064 "Desbordamiento de buffer de archivo de recuperación" +065 "Archivo de recuperación" +066 "%s: archivo de recuperación defectuoso" +067 "%s: archivo de recuperación defectuoso" +068 "No hay archivos denominados %s, que usted pueda leer, para recuperar" +069 "Existen versiones más antiguas de este archivo que usted puede recuperar" +070 "Existen otros archivos que usted puede recuperar" +071 "no envía email: %s" +072 "Archivo vacío; no hay nada para buscar" +073 "Se alcanzó el final del archivo sin encontrar el patrón" +074 "No hay patrón anterior de búsqueda" +075 "No se encontró el patrón" +076 " Se alcanzó el principio del archivo sin encontrar el patrón" +077 "Búsqueda reiniciada" +078 "Buscando..." +079 "No se encontró ningún carácter no imprimible" +080 "Nombre de comando desconocido" +082 "%s: comando no disponible en modalidad ex" +083 "La cuenta no puede ser cero" +084 "%s: mala especificación de línea" +085 "Error interno de tabla de sintaxis (%s: %s)" +086 "Uso: %s" +087 "%s: buffer temporario no liberado" +088 "Desplazamiento de marcador a antes de la línea 1" +089 "Desplazamiento de marcador más allá del final del archivo" +090 "@ con rango que corre cuando se cambia el archivo/la pantalla" +091 "Comando global/v que corre cuando se cambia el archivo/la pantalla" +092 "Comando Ex fracasado: comandos pendientes descartados" +093 "Comando Ex fracasado: teclas mapeadas descartadas" +094 "La segunda dirección es más pequeña que la primera" +095 "No se suministra nombre de marca" +096 "\\ no es seguido por / o ?" +097 "Referencia a un número de línea menor que 0" +098 "El comando %s es desconocido" +099 "Desbordamiento de valor de dirección" +100 "Subdesbordamiento de valor de dirección" +101 "Combinación de dirección ilegal" +102 "Dirección ilegal: sólo %lu líneas en el archivo" +103 "Dirección ilegal: el archivo está vacío" +104 "El comando %s no permite una dirección de 0" +105 "No hay abreviaturas para visualizar" +106 "Las abreviaturas deben terminar con un carácter de \"palabra\" " +107 "Las abreviaturas no pueden contener tabs o espacios" +108 "Las abreviaturas no pueden mezclar caracteres palabra/no-palabra, salvo al final" +109 "\"%s\" no es una abreviatura" +110 "Comando Vi fracasado: teclas mapeadas descartadas" +111 "No hay más archivos para editar" +112 "No hay archivos anteriores para editar" +113 "No hay archivos anteriores para rebobinar" +114 "No hay lista de archivos para visualizar" +115 "No hay un comando anterior para reemplazar a \"!\"" +116 "No hay nombre de archivo para sustituir por %%" +117 "No hay nombre de archivo para sustituir por #" +118 "Error: execl: %s" +119 "Error de E/S: %s" +120 "Archivo modificado desde la última escritura completa; escribir o usar ! para alterar" +121 "No se puede encontrar la ubicación del directorio inicial" +122 "Nuevo directorio actual: %s" +123 "No hay buffers sueltos para visualizar" +124 "El comando %s no puede usarse como parte de un comando global o v" +125 "%s/%s: sin fuente: no le pertenece a usted o a raíz" +126 "%s/%s: sin fuente: no le pertenece a usted" +127 "%s/%s: sin fuente: puede ser escrito por un usuario que no sea el propietario" +128 "%s: sin fuente: no le pertenece a usted o a raíz" +129 "%s: sin fuente: no le pertenece a usted" +130 "%s: sin fuente: puede ser escrito por un usuario que no sea el propietario" +131 "No hay líneas siguientes para unir" +132 "No hay anotaciones de mapa de entrada" +133 "No hay anotaciones de mapa de comando" +134 "El carácter %s no puede remapearse" +135 "\"%s\" no está mapeado actualmente" +136 "Marca de nombres debe ser un sólo carácter" +137 "%s existe, no está escrito; usar ! para alterar" +138 "Nuevo archivo exrc: %s" +139 "La línea de destino se encuentra dentro del rango de movimiento" +140 "El comando abierto requiere que se determine la opción abierta" +141 "El comando abierto no se ha implementado aún" +142 "No es posible preservar este archivo" +143 "Archivo preservado" +144 "%s: expandido a demasiados nombres de archivo" +145 "Sólo pueden leerse los archivos regulares y los conductos nombrados" +146 "%s: traba de lectura no disponible" +147 "Leyendo..." +148 "%s: %lu líneas, %lu caracteres" +149 "No hay pantallas de fondo para mostrar" +150 "El comando de script sólo está disponible en modalidad vi" +151 "No hay comando para ejecutar" +152 "opción de ancho de desplazamiento en 0" +153 "Desbordamiento de cuenta" +154 "Subdesbordamiento de cuenta" +155 "Expresión regular especificada; marcador r no tiene significado" +156 "Los marcadores #, l y p no pueden combinarse con el marcador c en la modalidad vi" +157 "No se encontró coincidencia" +158 "No se ingresó un identificador anterior" +159 "Se encontraron menos de %s anotaciones en la pila de identificadores; usar :visualizar i[dentificadores]" +160 "No hay archivo %s en la pila de identificadores al que se pueda volver; usar :visualizar i[dentificadores]" +161 "Presionar Intro para continuar: " +162 "%s: no se encontró el identificador" +163 "%s: identificador corrompido en %s" +164 "%s: el número de línea del identificador es posterior al final del archivo" +165 "La pila de identificadores está vacía" +166 "%s: patrón de búsqueda no encontrado" +167 "%d archivos más para editar" +168 "El buffer %s está vacío" +169 "¿Confirmar cambio? [n]" +170 "Interrumpido" +171 "No hay buffer anterior para ejecutar" +172 "No hay expresión regular anterior" +173 "El comando %s requiere que se haya leído un archivo" +174 "Uso: %s" +175 "El comando visual requiere que se determine la opción abierta" +177 "Archivo vacío" +178 "No hay búsqueda F, f, T o t anterior" +179 "%s no se encontró" +180 "No hay archivo anterior para editar" +181 "El cursor no está en un número" +182 "El número resultante es demasiado grande" +183 " El número resultante es demasiado pequeño" +184 "No hay carácter coincidente en esta línea" +185 "No se encontró un carácter coincidente" +186 "No hay caracteres para reemplazar" +187 "No hay otra pantalla a la que se pueda pasar" +188 "Caracteres tras de cadena de búsqueda, desplazamiento de línea y/o comando z" +189 "No hay patrón anterior de búsqueda" +190 "Búsqueda vuelve a la posición inicial" +191 "Se superó el límite de expansión de abreviatura: se descartaron caracteres" +192 "Carácter ilegal; mencionar para entrar" +193 "Ya se encuentra al principio de la inserción" +194 "No hay más caracteres para borrar" +195 "Movimiento más allá del final del archivo" +196 "Movimiento más allá del final de la línea" +197 "No hay movimiento del cursor" +198 "Ya se encuentra al principio del archivo" +199 "Movimiento más allá del principio del archivo" +200 "Ya se encuentra en la primera columna" +201 "Los buffers deben especificarse antes del comando" +202 "Ya se encuentra al final del archivo" +203 "Ya se encuentra al final de la línea" +204 "%s no es un comando vi" +205 "Uso: %s" +206 "No hay caracteres para borrar" +207 "El comando Q requiere la interfase de terminal ex" +208 "No hay comando para repetir" +209 "El archivo está vacío" +210 "%s no puede usarse como comando de movimiento" +211 "Ya se encuentra en modalidad de comando" +212 "El cursor no se encuentra en una palabra" +214 "El valor de opción de Windows es demasiado grande, el máx. es %u" +215 "Añadir" +216 "Cambiar" +217 "Comando" +218 "Insertar" +219 "Reemplazar" +220 "El movimiento va más allá del final de la pantalla" +221 "El movimiento va más allá del principio de la pantalla" +222 "La pantalla debe tener más de %d líneas para dividirse" +223 "No hay pantallas de fondo" +224 "No hay pantalla de fondo editando un archivo denominado %s" +225 "No se puede poner fondo a la única pantalla que se visualiza" +226 "La pantalla sólo puede reducirse a %d hileras" +227 "La pantalla no puede reducirse" +228 "La pantalla no puede aumentarse" +230 "Esta pantalla no puede suspenderse" +231 "Interrumpido: teclas mapeadas descartadas" +232 "vi: buffer temporario no liberado" +233 "Esta terminal no tiene tecla %s" +234 "Sólo un buffer puede especificarse" +235 "Número mayor que %lu" +236 "Interrumpido" +237 "No se puede crear archivo temporario" +238 "Advertencia: %s no es un archivo regular" +239 "%s ya se encuentra trabado, la sesión es de lectura solamente" +240 "%s: eliminar" +241 "%s: cerrar" +242 "%s: eliminar" +243 "%s: eliminar" +244 "Archivo de lectura solamente, no escrito; usar ! para alterar" +245 " Archivo de lectura solamente, no escrito" +246 "%s existe, no escrito; usar ! para alterar" +247 "%s existe, no escrito" +248 "Archivo parcial, no escrito; usar ! para alterar" +249 "Archivo parcial, no escrito" +250 "%s: archivo modificado más recientemente que esta copia; usar ! para alterar" +251 "%s: archivo modificado más recientemente que esta copia" +252 "%s: la traba de escritura no estaba disponible" +253 "Escribiendo..." +254 "%s: ADVERTENCIA: ARCHIVO TRUNCADO" +255 "Ya se encuentra en el primer identificador de este grupo" +256 "%s: nuevo archivo: %lu líneas, %lu caracteres" +257 "%s: %lu líneas, %lu caracteres" +258 "%s expandido a demasiados nombres de archivos" +259 "%s: no es un archivo regular" +260 "%s: no le pertenece" +261 "%s: accesible por un usuario que no sea el propietario" +262 "Archivo modificado desde la última escritura completa; escribir o usar ! para alterar" +263 "Archivo modificado desde la última escritura completa; escribir o usar :editar! para alterar" +264 "Archivo modificado desde la última escritura completa; escribir o usar ! para alterar" +265 "El archivo es temporario; al salir se descartarán las modificaciones" +266 "Archivo de lectura solamente, las modificaciones no se autoescriben" +267 "Se reinició el log" +268 "confirmar? [snq]" +269 "Presionar cualquier tecla para continuar: " +270 "Presionar cualquier tecla para continuar [: para ingresar más comandos ex]: " +271 "Presionar cualquier tecla para continuar [q para salir]: " +272 "Esta forma de %s requiere la interfase terminal ex" +273 "Ingresando en la modalidad de entrada ex." +274 "Comando fracasado, no hay archivo leído aun." +275 " cont?" +276 "Evento inesperado de carácter" +277 "Evento inesperado de final de archivo" +278 "No hay coincidencias para consulta" +279 "Evento inesperado de interrupción" +280 "Evento inesperado de salida" +281 "Evento inesperado de repintura" +282 "Ya se encuentra en el último identificador de este grupo" +283 "El comando %s requiere la interfase terminal ex" +284 "Esta forma de %s no se encuentra soportada cuando se determina la opción de edición segura" +285 "Evento inesperado de cadena" +286 "Evento inesperado de tiempo excedido" +287 "Evento inesperado de escritura" +289 "Las expansiones de shell no se encuentran soportadas cuando se determina la opción de edición segura" +290 "El comando %s no se encuentra soportado cuando se determina la opción de edición segura" +291 "determinar: la opción %s puede no estar desconectada" +292 "El monitor es demasiado pequeño." +293 "agregado" +294 "cambiado" +295 "borrado" +296 "unido" +297 "movido" +298 "desplazado" +299 "arrancado" +300 "línea" +301 "líneas" +302 "Vi no se cargó con un intérprete Tcl" +303 "Archivo modificado desde la última escritura." +304 "Expansión de shell fracasada" +305 "No hay opción de edición %s especificada" +306 "Vi no se cargó con un intérprete Perl" +307 "No hay comando ex para ejecutar" +308 "Ingresar para ejecutar un comando, :q para salir" +309 "Usar \"cscope ayuda\" para obtener ayuda" +310 "No hay conexiones cscope corriendo" +311 "%s: tipo de búsqueda desconocido: usar uno de %s" +312 "%d: no existe esta sesión cscope" +313 "determinar: la opción %s no puede conectarse nunca" +314 "determinar: la opción %s no puede determinarse nunca en 0" +315 "%s: añadido: %lu líneas, %lu caracteres" +316 "Evento inesperado de modificación de tamaño" +317 "%d archivos para editar" Property changes on: vendor/nvi/2.2.0-05ed8b9/catalog/spanish.base ___________________________________________________________________ Added: fbsd:notbinary ## -0,0 +1 ## +catalog/dutch.base \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain; charset=iso-8859-1 \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/catalog/swedish.base =================================================================== --- vendor/nvi/2.2.0-05ed8b9/catalog/swedish.base (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/catalog/swedish.base (revision 366308) @@ -0,0 +1,306 @@ +002 "För långa rader" +003 "kan inte ta bort rad %lu" +004 "kan inte lägga till på rad %lu" +005 "kan inte sätta in på rad %lu" +006 "kan inte lagra rad %lu" +007 "kan inte hämta sista raden" +008 "Fel: kan inte hämta rad %lu" +009 "Loggningsfil" +010 "Loggning utförs inte, ångra är inte möjligt" +011 "Inga ändringar att ångra" +012 "Loggning utförs inte, ångra är inte möjligt" +013 "Loggning utförs inte, ångra ångra är inte möjligt" +014 "Inga ändringar att återgöra" +015 "%s/%d: fel vid loggning" +016 "Vi:s standard in och ut måste gå till en terminal" +017 "Markering %s: inte satt" +018 "Markering %s: raden har tagits bort" +019 "Markering %s: markörpositionen finns inte längre" +020 "Fel: " +021 "ny fil" +022 "namnet ändrades" +023 "ändrad" +024 "oförändrad" +025 "OLÅST" +026 "inte skrivbar" +027 "rad %lu av %lu [%ld%%]" +028 "tom fil" +029 "rad %lu" +030 "Filen %s är ingen meddelandekatalog" +031 "Kan inte sätta standardvärde för %s flaggan" +032 "Användning: %s" +033 "set: %s är en okänd flagga: \"set all\" visar alla flaggor" +034 "set: [no]%s flaggan kan inte ges ett värde" +035 "set: %s flaggan är inte boleansk" +036 "set: %s flaggan: %s" +037 "set: %s flaggan: %s: för stort värde" +038 "set: %s flaggan: %s är ett otillåtet tal" +039 "set: %s flaggan är inte boleansk" +040 "Fönsterkolumnerna är för få, mindre än %d" +041 "Fönsterkolumnerna är för många, fler än %d" +042 "Fönsterraderna är för få, mindre än %d" +043 "Fönsterraderna är för många, fler än %d" +044 "Lisp flaggan är inte implementerad" +045 "meddelanden är inte avslagna: %s" +046 "meddelanden är inte påslagna: %s" +047 "%s flaggan måste ges i teckengrupper om två" +053 "Standardbufferten är tom" +054 "Buffer %s är tom" +055 "Filer med radmatning i namnet kan inte återskapas" +056 "Ändringar kan inte återskapas om programmet kraschar" +057 "Kopierar filen för återskapning..." +058 "Säkerhetskopiering misslyckades: %s" +059 "Ändringar kan inte återskapas om programmet kraschar" +060 "Misslyckades att säkerhetskopiera filen: %s" +061 "Kopierar filen för återskapning..." +062 "Kan inte hitta information om användaridentitet %u" +063 "Kan inte låsa återskapningsfilen" +064 "Återskapningsfilens buffer överskriven" +065 "Återskapningsfil" +066 "%s: Återskapningsfilen är korrupt" +067 "%s: Återskapningsfilen är korrupt" +068 "Det finns ingen fil %s, läsbar av dig, att återskapa" +069 "Det finns äldre versioner av denna fil som du kan återskapa" +070 "Det finns andra filer du kan återskapa" +071 "skickar inte email: %s" +072 "Filen är tom; inget att söka i" +073 "Kom till slutet på filen utan att hitta söksträngen" +074 "Ingen tidigare söksträng" +075 "Hittar inte söksträngen" +076 "Kom till början av filen utan att hitta söksträngen" +077 "Sökningen slog runt" +078 "Söker..." +079 "Inga icke skrivbara tecken funna" +080 "Okänt kommandonamn" +082 "%s: kommandot är inte tillgängligt i \"ex\" läge" +083 "Talet får inte vara noll" +084 "%s: Ogiltig radspecifikation" +085 "Fel i intern syntaxtabell (%s: %s)" +086 "Användning: %s" +087 "%s: temporärbuffert inte frisläppt" +088 "Offset är före rad 1" +089 "Offset är efter slutet på filen" +090 "@ med intervall exekverades när filen/fönstret ändrades" +091 "Global/v kommando exekverades när filen/fönstret ändrades" +092 "Ex kommando misslyckades: efterföljande kommandon ignorerade" +093 "Ex kommando misslyckades: omdefinierade tangenter ignorerade" +094 "Den andra adressen är mindre än den första" +095 "Inget namn på markering givet" +096 "\\ följs inte av / eller ?" +097 "Referens till ett radnummer mindre än 0" +098 "%s kommandot är inte känt" +099 "Värdet på adressen är för stort" +100 "Värdet på adressen är för litet" +101 "Otillåten adresskombination" +102 "Otillåten adress: bara %lu rader finns i filen" +103 "Otillåten adress: filen är tom" +104 "%s kommandot tillåter inte en adress som är 0" +105 "Inga förkortningar att visa" +106 "Förkortningar måste sluta med ett \"ord\" tecken" +107 "Förkortningar kan inte innehålla mellanslag eller tab" +108 "Förkortningar kan inte blanda \"ord\"/\"icke ord\" tecken, utom i slutet" +109 "\"%s\" är ingen förkortning" +110 "Vi kommando misslyckades: omdefinierade tangenter ignorerade" +111 "Inga fler filer att editera" +112 "Inga tidigare filer att editera" +113 "Inga tidigare filer att spela tillbaka" +114 "Ingen fillista att visa" +115 "Inget tidigare kommando att ersätta \"!\" med" +116 "Inget filnamn att ersätta %% med" +117 "Inget filnamn att ersätta # med" +118 "Fel: execl: %s" +119 "I/O fel: %s" +120 "Filen ändrad efter sista skrivning; spara eller använd !" +121 "Kan inte hitta hemkatalog" +122 "Ny nuvarande katalog: %s" +123 "Inga \"cut buffers\" att visa" +124 "%s kommandot kan inte används som del i ett \"global\" eller v kommando" +125 "%s/%s: inte läst: varken du eller root är ägare" +126 "%s/%s: inte läst: du är inte ägare" +127 "%s/%s: inte läst: skrivbar av annan än ägaren" +128 "%s: inte läst: varken du eller root är ägare" +129 "%s: inte läst: du är inte ägare" +130 "%s: inte läst: skrivbar av annan än ägaren" +131 "Ingen nästa rad att sätta ihop med" +132 "Det finns inget i inmatningsmappningen" +133 "Det finns inget i kommandomappningen" +134 "%s tecknet kan inte mappas om" +135 "\"%s\" är inte ommappat just nu" +136 "Namn på markeringar måste vara ett tecken långa" +137 "%s finns, inget sparat; använd ! för att spara" +138 "Ny exrc fil: %s" +139 "Målraden ligger inne i området som ska flyttas" +140 "Open kommandot kräver att open flaggan är satt" +141 "Open kommandot är inte implementerat ännu" +142 "Säkerhetskopiering av filen är inte möjligt" +143 "Filen säkerhetskopierad" +144 "%s expanderade till för många filnamn" +145 "Endast vanliga filer och namngivna rör kan läsas" +146 "%s: läslåset är otillgängligt" +147 "Läser..." +148 "%s: %lu rader, %lu tecken" +149 "Inga bakgrundsfönster att visa" +150 "Script kommandot finns bara i \"vi\" läge" +151 "Inget kommando att exekvera" +152 "shiftwidth flaggan satt till 0" +153 "Talet har för stort värde" +154 "Talet har för litet värde" +155 "Reguljärt uttryck är givet; r flaggan är meningslös" +156 "#, l och p flaggorna kan inte kombineras med c flaggan i \"vi\" läge" +157 "Ingen matchande text funnen" +158 "Inget tidigare märke har givits" +159 "Det är färre än %s märken i stacken; använd :display t[ags]" +160 "Det finns ingen fil %s i märkesstacken; använd :display t[ags]" +161 "Tryck Enter för att fortsätta: " +162 "%s: märke inte funnet" +163 "%s: korrupt märke i %s" +164 "%s: märkets radnummer är bortom filslutet" +165 "Märkesstacken är tom" +166 "%s: söksträngen inte funnen" +167 "%d filer till att editera" +168 "Buffert %s är tom" +169 "Bekräfta ändring? [n]" +170 "Avbruten" +171 "Ingen tidigare buffert att exekvera" +172 "Inget tidigare reguljärt uttryck" +173 "%s kommandot kräver att en fil redan lästs in" +174 "Användning: %s" +175 "Visual kommandot kräver att open flaggan är satt" +177 "Tom fil" +178 "Ingen tidigare F, f, T eller t sökning" +179 "%s inte funnen" +180 "Ingen tidigare fil att editera" +181 "Markören är inte i ett tal" +182 "Det resulterande talet är för stort" +183 "Det resulterande talet är för litet" +184 "Inget matchande tecken på denna rad" +185 "Matchande tecken inte funnet" +186 "Det finns inga tecken att ersätta" +187 "Det finns inget fönster att byta till" +188 "Tecken efter söksträng, radoffset och/eller z kommandot" +189 "Ingen tidigare söksträng" +190 "Sökningen slog runt till ursprungliga positionen" +191 "Förkortning överskred expanderingsgränsen: tecken har tagits bort" +192 "Ogiltigt tecken; använd \"quote\" för att sätta in" +193 "Redan i början på insättningen" +194 "Inga fler tecken att ta bort" +195 "Försök att gå bortom slutet på filen" +196 "Försök att gå bortom slutet på raden" +197 "Ingen förflyttning gjord" +198 "Redan i början på filen" +199 "Försök att gå före början på filen" +200 "Redan i första kolumnen" +201 "Buffertar måste anges före kommandot" +202 "Redan i slutet av filen" +203 "Redan på slutet av raden" +204 "%s är inte ett \"vi\" kommando" +205 "Användning: %s" +206 "Inga tecken att ta bort" +207 "Q kommandot kräver \"ex\" i terminalläge" +208 "Inget kommando att repetera" +209 "Filen är tom" +210 "%s kan inte användas som ett förflyttningskommando" +211 "Redan i kommando läge" +212 "Markören är inte i ett ord" +214 "Windows flaggans värde är för stor, största värde är %u" +215 "Lägg till" +216 "Ändra" +217 "Kommando" +218 "Sätt in" +219 "Ersätt" +220 "Förflyttning bortom fönsterslut" +221 "Förflyttning till före fönstrets början" +222 "Fönstret måste vara större än %d rader för delning" +223 "Det finns inga fönster i bakgrunden" +224 "Det finns inget fönster i bakgrunden som editerar filen %s" +225 "Du får inte sätta ditt enda synliga fönster i bakgrunden" +226 "Fönstret kan bara krympa till %d rader" +227 "Fönstret kan inte krympa" +228 "Fönstret kan inte växa" +230 "Detta fönster kan inte pausas" +231 "Avbrutet: omdefinierade tangenter ignorerade" +232 "vi: temporärbuffertar inte frisläppta" +233 "Denna terminal har ingen %s tangent" +234 "Endast en buffert kan anges" +235 "Talet är större än %lu" +236 "Avbrutet" +237 "Kan inte skapa temporär fil" +238 "Warning: %s är inte en normal fil" +239 "%s är redan låst, detta blir en icke skrivbar session" +240 "%s: ta bort" +241 "%s: stäng" +242 "%s: ta bort" +243 "%s: ta bort" +244 "Ej skrivbar fil, filen inte sparad; använd ! för att skriva över" +245 "Ej skrivbar fil, filen inte sparad" +246 "%s finns, ej sparad; använd ! för att utföra operationen" +247 "%s finns, filen inte sparad" +248 "Ofullständig fil, filen inte sparad, använd ! för att skriva över" +249 "Ofullständig fil, filen inte sparad" +250 "%s: filen ändrad efter denna kopia togs; använd ! för att utföra operationen" +251 "%s: filen ändrad efter denna kopia togs" +252 "%s: skrivlåset är otillgängligt" +253 "Skriver..." +254 "%s: VARNING: FILEN TRUNKERAD" +255 "Redan vid första märket i denna grupp" +256 "%s: ny fil: %lu rader, %lu tecken" +257 "%s: %lu rader, %lu tecken" +258 "%s expanderade till för många filnamn" +259 "%s är inte en normal fil" +260 "%s ägs inte av dig" +261 "%s är åtkomstbar av andra än ägaren" +262 "Filen har ändrats efter den sparats; spara eller använd !" +263 "Filen har ändrats efter den sparats; spara eller använd :edit!" +264 "Filen har ändrats efter den sparats; spara eller använd !" +265 "Filen är temporär; exit kastar bort ändringarna" +266 "Ej skrivbar fil, ändringar har inte automatsparats" +267 "Loggningen startar om" +268 "bekräfta? [ynq]" +269 "Tryck på en tangent för att fortsätta: " +270 "Tryck på en tangent för att fortsätta [: för att ge fler kommandon]: " +271 "Tryck på en tangent för att fortsätta [q för att avsluta]: " +272 "Den formen av %s kräver \"ex\" i terminalläge" +273 "Går till \"ex\" inmatningsläge." +274 "Kommandot misslyckades, ingen fil inläst ännu." +275 " forts?" +276 "Oväntad teckenhändelse" +277 "Oväntad filslutshändelse" +278 "Sökningen hittade ingenting" +279 "Oväntad avbrottshändelse" +280 "Oväntad avslutningshändelse" +281 "Oväntad omritningshändelse" +282 "Redan vid sista märket i denna grupp" +283 "%s kommandot kräver \"ex\" i terminalläge" +284 "Den formen av %s är inte tillgänglig när secure edit flaggan är satt" +285 "Oväntad stränghändelse" +286 "Oväntad tidshändelse" +287 "Oväntad skrivhändelse" +289 "Skalexpansion är inte tillgänglig när secure edit flaggan är satt" +290 "%s kommandot är inte tillgänglig när secure edit flaggan är satt" +291 "set: %s kan inte slås av" +292 "Fönstret för litet." +293 "tillagda" +294 "ändrade" +295 "borttagna" +296 "ihopsatta" +297 "flyttade" +298 "flyttade" +299 "inklistrade" +300 "rad" +301 "rader" +302 "Vi har inte länkats med en Tcl tolk" +303 "Filen har ändrats efter den sparats." +304 "Skalexpansion misslyckades" +305 "Ingen %s edit flagga given" +306 "Vi har inte länkats med en Perl tolk" +307 "Inga \"ex\" kommandon att exekvera" +308 "Tryck för att exekvera kommando, :q för att avsluta" +309 "Gör \"cscope help\" för hjälp" +310 "Inga cscope kopplingar körs" +311 "%s: okänd söktyp: använd en av %s" +312 "%d: ingen sådan cscope session" +313 "set: %s flaggan får aldrig slås på" +314 "set: %s flaggan får aldrig sättas till 0" +315 "%s: tillagt: %lu rader, %lu tecken" +316 "Oväntad storleksändring" +317 "%d filer att editera" Property changes on: vendor/nvi/2.2.0-05ed8b9/catalog/swedish.base ___________________________________________________________________ Added: fbsd:notbinary ## -0,0 +1 ## +catalog/dutch.base \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain; charset=iso-8859-1 \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/catalog/uk_UA.KOI8-U.base =================================================================== --- vendor/nvi/2.2.0-05ed8b9/catalog/uk_UA.KOI8-U.base (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/catalog/uk_UA.KOI8-U.base (revision 366308) @@ -0,0 +1,306 @@ +002 "ðÅÒÅÐÏ×ÎÅÎÎÑ ÚÎÁÞÅÎÎÑ ÄÏ×ÖÉÎÉ ÒÑÄËÕ" +003 "ÎÅÍÏÖÌÉ×Ï ÓÔÅÒÔÉ ÒÑÄÏË %lu" +004 "ÎÅÍÏÖÌÉ×Ï ÄÏÄÁÔÉ ÄÏ ÒÑÄËÕ %lu" +005 "ÎÅÍÏÖÌÉ×Ï ×ÓÔÁ×ÉÔÉ × ÒÑÄÏË %lu" +006 "ÎÅÍÏÖÌÉ×Ï ÒÏÚͦÓÔÉÔÉ ÒÑÄÏË %lu" +007 "ÎÅÍÏÖÌÉ×Ï Ä¦ÓÔÁÔÉ ÏÓÔÁÎÎ¦Ê ÒÑÄÏË" +008 "ðÏÍÉÌËÁ: ÎÅÍÏÖÌÉ×Ï ÏÔÒÉÍÁÔÉ ÒÑÄÏË %lu" +009 "æÁÊÌ ÚÁÐÉÓ¦×" +010 "úÁÐÉÓÉ ÎÅ ×ÅÌÉÓÑ, ÎÅÍÏÖÌÉ×Ï ×¦ÄͦÎÉÔÉ ÏÓÔÁÎÎÀ ËÏÍÁÎÄÕ" +011 "îÅÍÁ ÞÏÇÏ ×¦ÄͦÎÑÔÉ" +012 "úÁÐÉÓÉ ÎÅ ×ÅÌÉÓÑ, ÎÅÍÏÖÌÉ×Ï ×¦ÄͦÎÉÔÉ ÏÓÔÁÎÎÀ ËÏÍÁÎÄÕ" +013 "úÁÐÉÓÉ ÎÅ ×ÅÌÉÓÑ, ÎÅÍÏÖÌÉ×Ï ÐÒÏÄÉ×ÉÔÉÓÑ ×ÐÅÒÅÄ" +014 "îÅÍÁ ÞÏÇÏ ÐÏ×ÔÏÒÀ×ÁÔÉ" +015 "%s/%d: ÐÏÍÉÌËÁ ÚÁÐÉÓÕ ÐÒÏÔÏËÏÌÕ" +016 "óÔÁÎÄÁÒÔÎÉÍ ××ÅÄÅÎÎÑÍ/×É×ÅÄÅÎÎÑÍ ÄÌÑ vi ÍÁ¤ ÂÕÔÉ ÔÅÒͦÎÁÌ" +017 "í¦ÔËÁ %s: ÎÅ ×ÓÔÁÎÏ×ÌÅÎÏ" +018 "í¦ÔËÁ %s: ÒÑÄÏË ÓÔÅÒÔÏ" +019 "í¦ÔËÁ %s: ÐÏÚÉæ§ ËÕÒÓÏÒÕ Â¦ÌØÛÅ ÎÅ ¦ÓÎÕ¤" +020 "ðÏÍÉÌËÁ: " +021 "îÏ×ÉÊ ÆÁÊÌ" +022 "IÍ'Ñ ÚͦÎÉÌÏÓØ" +023 "ÚͦÎÅÎÉÊ" +024 "ÎÅ ÚͦÎÅÎÉÊ" +025 "òO3âìOëO÷áîO" +026 "Ô¦ÌØËÉ ÄÌÑ ÞÉÔÁÎÎÑ" +027 "ÒÑÄÏË %lu Ú %lu [%ld%%]" +028 "ÐÕÓÔÉÊ ÆÁÊÌ" +029 "ÒÑÄÏË %lu" +030 "æÁÊÌ %s ÎÅ ¤ ÆÁÊÌÏÍ ÐÏצÄÏÍÌÅÎÎØ" +031 "îÅÍÏÖÌÉ×Ï ×ÓÔÁÎÏ×ÉÔÉ ÏÐæÀ %s ÚÁ ÚÍÏ×ÞÁÎÎÑÍ" +032 "÷ÉËÏÒÉÓÔÁÎÎÑ: %s" +033 "ïÐæ§ %s ÎÅÍÁ¤: 'set all' ÐÏËÁÚÕ¤ ×Ó¦ ÍÏÖÌÉצ ÏÐæ§" +034 "set: [no]%s ÎÅ ÎÁÂÕ×Á¤ ÔÁËÏÇÏ ÚÎÁÞÅÎÎÑ" +035 "set: %s ÏÐÃ¦Ñ ÎÅ ¤ ÌÏǦÞÎÏÀ" +036 "set: ÏÐÃ¦Ñ %s: %s" +037 "set: ÏÐÃ¦Ñ %s: %s: ÐÅÒÅÐÏ×ÎÅÎÎÑ" +038 "set: ÎÅÐÒÁ×ÉÌØÎÅ ÚÎÁÞÅÎÎÑ %s" +039 "set: %s ÏÐÃ¦Ñ ÎÅ ¤ ÌÏǦÞÎÏÀ" +040 "ë¦ÌØ˦ÓÔØ ËÏÌÏÎÏË ÎÁ ÜËÒÁΦ ÎÁÄÔÏ ÍÁÌÁ, ÍÅÎÛÅ Î¦Ö %d" +041 "ë¦ÌØ˦ÓÔØ ËÏÌÏÎÏË ÎÁ ÜËÒÁΦ ÎÁÄÔÏ ×ÅÌÉËÁ, ¦ÌØÛÅ Î¦Ö %d" +042 "ë¦ÌØ˦ÓÔØ ÒÑÄË¦× ÎÁ ÜËÒÁΦ ÎÁÄÔÏ ÍÁÌÁ, ÍÅÎÛÅ Î¦Ö %d" +043 "ë¦ÌØ˦ÓÔØ ÒÑÄË¦× ÎÁ ÜËÒÁΦ ÎÁÄÔÏ ×ÅÌÉËÁ, ¦ÌØÛÅ Î¦Ö %d" +044 "ïÐÃ¦Ñ lisp צÄÓÕÔÎÑ" +045 "ðÏצÄÏÍÌÅÎÎÑ ÎÅ ×ÉÍËÎÅΦ: %s" +046 "ðÏצÄÏÍÌÅÎÎÑ ÎÅ ×צÍËÎÅΦ: %s" +047 "ïÐÃ¦Ñ %s ÐÏ×ÉÎÎÁ ͦÓÔÉÔÉ ÇÒÕÐÉ Ú Ä×ÏÈ ÓÉÍ×Ï̦×" +053 "óÔÁÒÔÏ×ÉÊ ÂÕÆÅÒ ÐÏÒÏÖΦÊ" +054 "âÕÆÅÒ %s ÐÏÒÏÖΦÊ" +055 "îÅÍÏÖÌÉ×Ï ×¦ÄÎÏ×ÉÔÉ ÆÁÊÌ, ÝÏ Í¦ÓÔÉÔØ × ¦ÍÅΦ ÓÉÍ×ÏÌÉ ÐÅÒÅ×ÅÄÅÎÎÑ ËÁÒÅÔËÉ" +056 "úͦÎÉ ÎÅ ÍÏÖÎÁ ÂÕÄŠצÄÎÏ×ÉÔÉ Ð¦ÓÌÑ ËÒÁÈÕ ÓÅÓ¦§" +057 "ëÏЦÀ×ÁÎÎÑ ÆÁÊÌÕ ÄÌÑ ×¦ÄÎÏ×ÌÅÎÎÑ..." +058 "úÂÅÒÅÖÅÎÎÑ ÎÅ ×ÄÁÌÏÓØ: %s" +059 "úͦÎÉ ÎÅ ÍÏÖÎÁ ÂÕÄŠצÄÎÏ×ÉÔÉ Ð¦ÓÌÑ ËÒÁÈÕ ÓÅÓ¦§" +060 "úÂÅÒÅÖÅÎÎÑ ËÏЦ§ ÆÁÊÌÕ ÎÅ ×ÄÁÌÏÓØ: %s" +061 "ëÏЦÀ×ÁÎÎÑ ÆÁÊÌÕ ÄÌÑ ×¦ÄÎÏ×ÌÅÎÎÑ..." +062 "IÎÆÏÒÍÁæÀ ÐÒÏ ËÏÒÉÓÔÕ×ÁÞÁ %u ÎÅ ÚÎÁÊÄÅÎÏ" +063 "úÁÂÌÏËÕ×ÁÔÉ ×¦ÄÎÏ×ÌÅÎÎÉÊ ÆÁÊÌ ÎÅÍÏÖÌÉ×Ï" +064 "âÕÆÅÒ ×¦ÄÎÏ×ÌÅÎÏÇÏ ÆÁÊÌÕ ÐÅÒÅÐÏ×ÎÅÎÏ" +065 "÷¦ÄÎÏ×ÌÅÎÎÉÊ ÆÁÊÌ" +066 "%s: ÆÁÊÌ ×¦ÄÎÏ×ÌÅÎÎÉÊ ÎÅ ÄÏ Ë¦ÎÃÑ" +067 "%s: ÆÁÊÌ ×¦ÄÎÏ×ÌÅÎÎÉÊ ÎÅ ÄÏ Ë¦ÎÃÑ" +068 "îÅ ¦ÓÎÕÀ¤ ÆÁÊÌ¦× Ú ¦ÍÅÎÅÍ %s, Ñ˦ ÷É ÍÏÖÅÔÅ ÐÒÏÞÉÔÁÔÉ" +069 "IÓÎÕÀÔØ ÓÔÁÒ¦ ×ÅÒÓ¦§ ÆÁÊÌÕ, Ñ˦ ÍÏÖÎÁ צÄÎÏ×ÉÔÉ" +070 "IÓÎÕÀÔØ ¦ÎÛ¦ ÆÁÊÌÉ, Ñ˦ ÍÏÖÎÁ צÄÎÏ×ÉÔÉ" +071 "e-mail ΊצĦÓÌÁÎÏ: %s" +072 "æÁÊÌ ÐÕÓÔÉÊ - ÎÅÍÁ ÞÏÇÏ ÛÕËÁÔÉ" +073 "äÏÓÑÎÕÔÏ Ë¦ÎÃÑ ÆÁÊÌÕ ÂÅÚ ÚÎÁÈÏÖÄÅÎÎÑ ÚÒÁÚËÕ ÐÏÛÕËÕ" +074 "îÅ ÚÁÄÁÎÏ ÚÒÁÚÏË ÐÏÛÕËÕ" +075 "úÒÁÚÏË ÐÏÛÕËÕ ÎÅ ÚÎÁÊÄÅÎÏ" +076 "äÏÓÑÎÕÔÏ ÐÏÞÁÔËÕ ÆÁÊÌÕ ÂÅÚ ÚÎÁÈÏÖÄÅÎÎÑ ÚÒÁÚËÕ ÐÏÛÕËÕ" +077 "ðÏÛÕË ÚÁÃÉËÌÅÎÏ" +078 "ðÏÛÕË..." +079 "îÅÐÅÞÁÔÎÉÈ ÓÉÍ×ÏÌ¦× ÎÅ ÚÎÁÊÄÅÎÏ" +080 "îÅצÄÏÍÁ ËÏÍÁÎÄÁ" +082 "%s: ËÏÍÁÎÄÁ ÎÅ ÄÏÓÔÕÐÎÁ × ÒÅÖÉͦ ex" +083 "ì¦ÞÉÌØÎÉË ÎÅ ÍÏÖÅ ÂÕÔÉ ÎÕÌÅÍ" +084 "%s: ÎÅÐÒÁ×ÉÌØÎÅ ×ÉÚÎÁÞÅÎÎÑ ÒÑÄËÕ" +085 "÷ÎÕÔÒ¦ÛÎÑ ÐÏÍÉÌËÁ × ÓÉÎÔÁËÓÉÓ¦ (%s: %s)" +086 "÷ÉËÏÒÉÓÔÁÎÎÑ: %s" +087 "%s: ÔÉÍÞÁÓÏ×ÉÊ ÂÕÆÅÒ ÎÅ ×ÉËÏÒÉÓÔÁÎÏ" +088 "í¦ÔËÕ ÐÏÓÔÁ×ÌÅÎÏ ÐÅÒÅÄ ÐÅÒÛÉÍ ÒÑÄËÏÍ" +089 "í¦ÔËÕ ÐÏÓÔÁ×ÌÅÎÏ Ð¦ÓÌÑ Ë¦ÎÃÑ ÆÁÊÌÕ" +090 "@ Ú Ä¦ÁÐÁÚÏÎÏÍ ÐÒÁÃÀ¤ ËÏÌÉ ÚͦÎÅÎÏ ÆÁÊÌ/צËÎÏ" +091 "ëÏÍÁÎÄÁ Global/v ÐÒÁÃÀ¤ ËÏÌÉ ÚͦÎÅÎÏ ÆÁÊÌ/צËÎÏ" +092 "ëÏÍÁÎÄÁ ex ÎÅ ×ÄÁÌÁÓØ: ÎÁÓÔÕÐΦ ËÏÍÁÎÄÉ Ú'¦ÇÎÏÒÏ×ÁÎÏ" +093 "ëÏÍÁÎÄÁ ex ÎÅ ×ÄÁÌÁÓØ: צÄÏÂÒÁÖÅΦ ËÌÁצۦ Ú'¦ÇÎÏÒÏ×ÁÎÏ" +094 "äÒÕÇÁ ÁÄÒÅÓÁ ÍÅÎÛÅ Î¦Ö ÐÅÒÛÁ" +095 "îÅ ×ËÁÚÁÎÏ ¦Í'Ñ Í¦ÔËÉ" +096 "\\ ÎÅ ÚÁ˦ÎÞÕ¤ÔØÓÑ / ÞÉ ?" +097 "ðÏÓÉÌÁÎÎÑ ÎÁ ÒÑÄÏË Ú ÎÏÍÅÒÏÍ, ÍÅÎÛÉÍ Î¦Ö 0" +098 "ëÏÍÁÎÄÁ %s ÎÅצÄÏÍÁ" +099 "ðÅÒÅÐÏ×ÎÅÎÎÑ Ì¦ÞÉÌØÎÉËÁ ÁÄÒÅÓ" +100 "îÅÄÏÂ¦Ò Ì¦ÞÉÌØÎÉËÁ ÁÄÒÅÓ" +101 "îÅÄÏÐÕÓÔÉÍÁ ËÏͦÎÁÃ¦Ñ × ÁÄÒÅÓ¦" +102 "îÅÐÒÁ×ÉÌØÎÁ ÁÄÒÅÓÁ: ×ÓØÏÇÏ %lu ÒÑÄË¦× Õ ÆÁÊ̦" +103 "îÅÐÒÁ×ÉÌØÎÁ ÁÄÒÅÓÁ: ÆÁÊÌ ÐÕÓÔÉÊ" +104 "ëÏÍÁÎÄÁ %s ÎÅ ÍÏÖÅ ×ÉËÏÒÉÓÔÏ×Õ×ÁÔÉ ÁÄÒÅÓÕ 0" +105 "îÅÍÁ¤ ÁÂÒÅצÁÔÕÒ" +106 "áÂÒÅצÁÔÕÒÉ ÐÏ×ÉÎΦ ÚÁ˦ÎÞÕ×ÁÔÉÓÑ ÓÉÍ×ÏÌÏÍ \"Ó̦×\"" +107 "÷ ÁÂÒÅצÁÔÕÒ¦ ÎÅ ÍÏÖÎÁ ×ÉËÏÒÉÓÔÏ×Õ×ÁÔÉ ÓÉÍ×ÏÌÉ ÔÁÂÕÌÑæ§ ÔÁ ÐÒϦÌÉ" +108 "áÂÒÅצÁÔÕÒÉ ÎÅ ÍÏÖÕÔØ ÚͦÛÕ×ÁÔÉ ÓÉÍ×ÏÌÉ Ó̦×/ÎÅ-Ó̦×, ȦÂÁ ÝÏ × Ë¦Îæ ÒÑÄËÕ" +109 "\"%s\" ÎÅ ÁÂÒÅצÁÔÕÒÁ" +110 "ëÏÍÁÎÄÁ Vi ÎÅ ×ÄÁÌÁÓØ: צÄÏÂÒÁÖÅΦ ËÌÁצۦ Ú'¦ÇÎÏÒÏ×ÁÎÏ" +111 "æÁÊÌ¦× ÄÌÑ ÒÅÄÁÇÕ×ÁÎÎÑ Â¦ÌØÛÅ ÎÅÍÁ¤" +112 "ðÏÐÅÒÅÄÎØÏÇÏ ÆÁÊÌÕ ÄÌÑ ÒÅÄÁÇÕ×ÁÎÎÑ ÎÅÍÁ¤" +113 "ðÏÐÅÒÅÄÎØÏÇÏ ÆÁÊÌÕ ÄÌÑ ÐÅÒÅÇÌÑÄÕ ÎÅÍÁ¤" +114 "îÅÍÁ¤ ÆÁÊ̦×" +115 "îÅÍÁ¤ ÐÏÐÅÒÅÄÎØϧ ËÏÍÁÎÄÉ ÄÌÑ ÚÁͦÎÉ \"!\"" +116 "÷¦ÄÓÕÔΤ ¦Í'Ñ ÆÁÊÌÕ ÄÌÑ Ð¦ÄͦÎÉ %%" +117 "÷¦ÄÓÕÔΤ ¦Í'Ñ ÆÁÊÌÕ ÄÌÑ Ð¦ÄͦÎÉ #" +118 "ðÏÍÉÌËÁ: execl: %s" +119 "ðÏÍÉÌËÁ ××ÅÄÅÎÎÑ/×É×ÅÄÅÎÎÑ: %s" +120 "æÁÊÌ ÍÏÄÉƦËÏ×ÁÎÏ Ð¦ÓÌÑ ÏÓÔÁÎÎØϧ ËÏÍÁÎÄÉ ÐÏ×ÎÏÇÏ ÚÁÐÉÓÕ: ÚÂÅÒÅÖ¦ÔØ ÞÉ ×ÉËÏÒÉÓÔÁÊÔÅ ! ÄÌÑ ÏÂÈÏÄÕ" +121 "îÅÍÏÖÌÉ×Ï ÚÎÁÊÔÉ ÄÏÍÁÛÎ¦Ê ËÁÔÁÌÏÇ" +122 "îÏ×ÉÊ ËÁÔÁÌÏÇ: %s" +123 "îÅÍÁ¤ ÎÁÐÏ×ÎÅÎÉÈ ÂÕÆÅÒ¦×" +124 "ëÏÍÁÎÄÁ %s ÎÅ ×ÉËÏÒÉÓÔÏ×Õ¤ÔØÓÑ ÑË ÞÁÓÔÉÎÁ ËÏÍÁÎÄÉ global ÞÉ v" +125 "%s/%s: ΊצÄËÒÉÔÏ: ÎÅ ÎÁÌÅÖÉÔØ ÷ÁÍ ÞÉ ÁÄͦΦÓÔÒÁÔÏÒÕ" +126 "%s/%s: ΊצÄËÒÉÔÏ: ÎÅ ÎÁÌÅÖÉÔØ ÷ÁÍ" +127 "%s/%s: ΊצÄËÒÉÔÏ: ÍÏÖÌÉצÓÔØ ÚÁÐÉÓÕ ËÏÒÉÓÔÕ×ÁÞÅÍ, ÑËÉÊ ÎÅ ¤ ×ÌÁÓÎÉËÏÍ" +128 "%s: ΊצÄËÒÉÔÏ: ÎÅ ÎÁÌÅÖÉÔØ ÷ÁÍ ÞÉ ÁÄͦΦÓÔÒÁÔÏÒÕ" +129 "%s: ΊצÄËÒÉÔÏ: ÎÅ ÎÁÌÅÖÉÔØ ÷ÁÍ" +130 "%s: ΊצÄËÒÉÔÏ: ÍÏÖÌÉצÓÔØ ÚÁÐÉÓÕ ËÏÒÉÓÔÕ×ÁÞÅÍ, ÑËÉÊ ÎÅ ¤ ×ÌÁÓÎÉËÏÍ" +131 "îÅÍÁ¤ ¦ÌØÛÅ ÒÑÄË¦× ÄÌÑ ÏÂ'¤ÄÎÁÎÎÑ" +132 "îÅÍÁ¤ ÐÁÒÁÍÅÔÒ¦× ××ÅÄÅÎÎÑ" +133 "îÅÍÁ¤ ÐÁÒÁÍÅÔÒ¦× ËÏÍÁÎÄÉ" +134 "óÉÍ×ÏÌ %s ÎÅ ÍÏÖÎÁ ÐÅÒÅÎÁÚÎÁÞÉÔÉ" +135 "\"%s\" ÚÁÒÁÚ ÎÅ ÐÅÒÅÎÁÚÎÁÞÅÎÏ" +136 "IÍ'Ñ Í¦ÔËÉ -- ÏÄÉÎ ÓÉÍ×ÏÌ" +137 "%s ¦ÓÎÕ¤, ÎÅ ÚÁÐÉÓÁÎÏ; ×ÉËÏÒÉÓÔÁÊÔÅ ! ÄÌÑ ÏÂÈÏÄÕ" +138 "îÏ×ÉÊ ÆÁÊÌ exrÓ: %s" +139 "òÑÄÏË ÐÒÉÚÎÁÞÅÎÎÑ ÚÁÚÎÁÞÅÎÏ ×ÓÅÒÅÄÉΦ ĦÁÐÁÚÏÎÕ ÐÅÒÅͦÝÅÎÎÑ" +140 "ëÏÍÁÎÄÁ open ×ÉÍÁÇÁ¤ ×ÓÔÁÎÏ×ÌÅÎÎÑ ÏÐæ§ open" +141 "ëÏÍÁÎÄÕ open ÝÅ ÎÅ ÒÅÁ̦ÚÏ×ÁÎÏ" +142 "úÁÈÉÓÔ ÆÁÊÌÕ ÎÅÍÏÖÌÉ×ÉÊ" +143 "æÁÊÌ ÚÁÈÉÝÅÎÏ" +144 "%s ÒÏÚÛÉÒÉ×ÓÑ × ÎÁÄÔÏ ×ÅÌÉËÕ Ë¦ÌØ˦ÓÔØ ¦ÍÅÎ ÆÁÊ̦×" +145 "ðÒÏÞÉÔÁÔÉ ÍÏÖÎÁ Ô¦ÌØËÉ ÐÒÏÓÔÉÊ ÆÁÊÌ ÞÉ ¦ÍÅÎÏ×ÁÎÉÊ ËÁÎÁÌ(pipe)" +146 "%s: ÂÌÏËÕ×ÁÎÎÑ ×¦Ä ÞÉÔÁÎÎÑ ÎÅÍÏÖÌÉ×Å" +147 "úÞÉÔÕÀ..." +148 "%s: %lu ÒÑÄ˦×, %lu ÓÉÍ×Ï̦×" +149 "îÅÍÁ¤ Ô¦ÎØÏ×ÉÈ ×¦ËÏÎ" +150 "ëÏÍÁÎÄÁ script ÄÏÓÔÕÐÎÁ ÌÉÛÅ × ÒÅÖÉͦ vi" +151 "îÅÍÁ ËÏÍÁÎÄÉ ÄÌÑ ×ÉËÏÎÁÎÎÑ" +152 "ïÐæÀ shiftwidth ×ÓÔÁÎÏ×ÌÅÎÏ × 0" +153 "ðÅÒÅÐÏ×ÎÅÎÎÑ Ì¦ÞÉÌØÎÉËÁ" +154 "ãÉËÌ ×ÉËÏÎÁÎÏ ÎÅ ÄÏ Ë¦ÎÃÑ" +155 "÷ËÁÚÁÎÏ ÒÅÇÕÌÑÒÎÉÊ ×ÉÒÁÚ; ÐÁÒÁÍÅÔÒ 'r' ÎÅ ÍÁ¤ ÓÅÎÓÕ" +156 "ðÁÒÁÍÅÔÒÉ #, l ÔÁ p ÎÅ ÍÏÖÎÁ ËÏͦÎÕ×ÁÔÉ Ú ÐÁÒÁÍÅÔÒÏÍ 'c' × ÒÅÖÉͦ vi" +157 "óЦ×ÐÁÄÁÎØ ÎÅÍÁ¤" +158 "TÅÇ ×¦ÄÓÕÔΦÊ" +159 "íÅÎÛÅ Î¦Ö %s ÚÁÐÉÓ¦× Õ ÓÔÅËÕ ÔÅǦ×; ×ÉËÏÒÉÓÔÁÊÔÅ :display t[ags]" +160 "îÅÍÁ¤ ÆÁÊÌÕ %s × ÓÔÅËÕ ÔÅÇ¦× ÄÌÑ ÐÏ×ÅÒÎÅÎÎÑ; ×ÉËÏÒÉÓÔÁÊÔÅ :display t[ags]" +161 "îÁÔÉÓΦÔØ ENTER ÄÌÑ ÐÒÏÄÏ×ÖÅÎÎÑ: " +162 "%s: ÔÅÇ ÎÅ ÚÎÁÊÄÅÎÏ" +163 "%s: Ú¦ÐÓÏ×ÁÎÉÊ ÔÅÇ × %s" +164 "%s: ÎÏÍÅÒ ÒÑÄËÕ ÔÅÇÁ ÚÎÁÈÏÄÉÔØÓÑ ÚÁ ˦ÎÃÅÍ ÆÁÊÌÕ" +165 "óÔÅË ÔÅÇ¦× ÐÏÒÏÖΦÊ" +166 "%s: ÚÒÁÚÏË ÐÏÛÕËÕ ÎÅ ÚÎÁÊÄÅÎÏ" +167 "úÁÌÉÛÉÌÏÓØ %d ÆÁÊÌ¦× ÄÌÑ ÒÅÄÁÇÕ×ÁÎÎÑ" +168 "âÕÆÅÒ %s ÐÏÒÏÖΦÊ" +169 "úͦÎÉÔÉ? [n]" +170 "ðÅÒÅÒ×ÁÎÏ" +171 "îÅÍÁ¤ ÂÕÆÅÒÕ ÄÌÑ ×ÉËÏÒÉÓÔÁÎÎÑ" +172 "îÅÍÁ¤ ÐÏÐÅÒÅÄÎØÏÇÏ ÒÅÇÕÌÑÒÎÏÇÏ ×ÉÒÁÚÕ" +173 "ëÏÍÁÎÄÁ %s ×ÉÍÁÇÁ¤ ×ÖÅ ÐÒÏÞÉÔÁÎÉÊ ÆÁÊÌ" +174 "÷ÉËÏÒÉÓÔÁÎÎÑ: %s" +175 "ëÏÍÁÎÄÁ visual ×ÉÍÁÇÁ¤ ×ÓÔÁÎÏ×ÌÅÎÎÑ ÏÐæ§ open" +177 "ðÕÓÔÉÊ ÆÁÊÌ" +178 "îÅÍÁ¤ ÐÏÐÅÒÅÄÎØÏÇÏ ÐÏÛÕËÕ F, f, T, ÞÉ t" +179 "%s ÎÅ ÚÎÁÊÄÅÎÏ" +180 "îÅÍÁ¤ ÐÏÐÅÒÅÄÎØÏÇÏ ÆÁÊÌÕ ÄÌÑ ÒÅÄÁÇÕ×ÁÎÎÑ" +181 "ëÕÒÓÏÒ ÓÔϧÔØ ÎÅ ÎÁ ÃÉÆÒ¦" +182 "OÔÒÉÍÁÎÅ ÞÉÓÌÏ ÎÁÄÔÏ ×ÅÌÉËÅ" +183 "OÔÒÉÍÁÎÅ ÞÉÓÌÏ ÎÁÄÔÏ ÍÁÌÅ" +184 "îÅÍÁ¤ צÄÐÏצÄÎÏÇÏ ÓÉÍ×ÏÌÕ × ÃØÏÍÕ ÒÑÄËÕ" +185 "÷¦ÄÐÏצÄÎÉÊ ÓÉÍ×ÏÌ ÎÅ ÚÎÁÊÄÅÎÏ" +186 "îÅÍÁ¤ ÓÉÍ×ÏÌ¦× ÄÌÑ ÚÁͦÎÉ" +187 "îÅÍÁ¤ ¦ÎÛÏÇÏ ×¦ËÎÁ" +188 "óÉÍ×ÏÌÉ Ð¦ÓÌÑ ÒÑÄËÕ ÄÌÑ ÐÏÛÕËÕ, ÚͦÝÅÎÎÑ ÒÑÄËÕ ÔÁ/ÞÉ ËÏÍÁÎÄÉ z" +189 "îÅÍÁ¤ ÐÏÐÅÒÅÄÎØÏÇÏ ÚÒÁÚËÕ ÐÏÛÕËÕ" +190 "ðÏÛÕË ÚÁ˦ÎÞÉ×ÓÑ ÎÁ ÐÏÞÁÔËÏ×¦Ê ÐÏÚÉæ§" +191 "áÂÒÅצÁÔÕÒÁ ÐÅÒÅ×ÉÝÉÌÁ Ì¦Í¦Ô ÒÏÚÛÉÒÅÎÎÑ: ÓÉÍ×ÏÌÉ Ú'¦ÇÎÏÒÏ×ÁÎÏ" +192 "îÅÄÏÚ×ÏÌÅÎÉÊ ÓÉÍ×ÏÌ: ÚÁÄÁÊÔÅ × ÄÕÖËÁÈ" +193 "÷ÖÅ ÎÁ ÐÏÞÁÔËÕ ×ÓÔÁ×ËÉ" +194 "îÅÍÁ¤ ÓÉÍ×ÏÌ¦× ÄÌÑ ×ÉÄÁÌÅÎÎÑ" +195 "òÕÈ ÚÁ ˦ÎÅÃØ ÆÁÊÌÕ" +196 "òÕÈ ÚÁ ˦ÎÅÃØ ÒÑÄËÕ" +197 "ëÕÒÓÏÒ ÎÅ ÐÅÒÅͦÝÕ×Á×ÓÑ" +198 "÷ÖÅ ÎÁ ÐÏÞÁÔËÕ ÆÁÊÌÕ" +199 "òÕÈ ËÕÒÓÏÒÕ ÚÁ ÐÏÞÁÔÏË ÆÁÊÌÕ" +200 "÷ÖÅ × ÐÅÒÛ¦Ê ËÏÌÏÎæ" +201 "âÕÆÅÒ ÔÒÅÂÁ ×ËÁÚÕ×ÁÔÉ ÐÅÒÅÄ ËÏÍÁÎÄÏÀ" +202 "÷ÖÅ ÎÁ ˦Îæ ÆÁÊÌÕ" +203 "÷ÖÅ ÎÁ ˦Îæ ÒÑÄËÕ" +204 "%s ÎÅ ËÏÍÁÎÄÁ Vi" +205 "÷ÉËÏÒÉÓÔÁÎÎÑ: %s" +206 "îÅÍÁ¤ ÓÉÍ×ÏÌ¦× ÄÌÑ ×ÉÄÁÌÅÎÎÑ" +207 "ëÏÍÁÎÄÁ Q ×ÉÍÁÇÁ¤ ¦ÎÔÅÒÆÅÊÓÕ ex" +208 "îÅÍÁ¤ ËÏÍÁÎÄÉ ÄÌÑ ÐÏ×ÔÏÒÅÎÎÑ" +209 "æÁÊÌ ÐÕÓÔÉÊ" +210 "ëÏÍÁÎÄÕ %s ÎÅ ÍÏÖÎÁ ×ÉËÏÒÉÓÔÁÔÉ ÄÌÑ ÐÅÒÅͦÝÅÎÎÑ" +211 "÷ÖÅ × ËÏÍÁÎÄÎÏÍÕ ÒÅÖÉͦ" +212 "ëÕÒÓÏÒ ÓÔϧÔØ ÎÅ ÎÁ ÓÌÏצ" +214 "úÎÁÞÎÅÎÎÑ ÏÐæ§ Windows ÎÁÄÔÏ ×ÅÌÉËÅ, ÍÁËÓÉÍÕÍ = %u" +215 "äÏÐÉÓÁÔÉ" +216 "úͦÎÉÔÉ" +217 "ëÏÍÁÎÄÁ" +218 "÷ÓÔÁ×ÉÔÉ" +219 "úÁͦÎÉÔÉ" +220 "òÕÈ ËÕÒÓÏÒÕ ÚÁ ˦ÎÅÃØ ÜËÒÁÎÕ" +221 "òÕÈ ËÕÒÓÏÒÕ ÚÁ ÐÏÞÁÔÏË ÜËÒÁÎÕ" +222 "äÌÑ ÒÏÚÂÉÔÔÑ ×¦ËÎÏ ÍÁ¤ ͦÓÔÉÔÉ Â¦ÌØÛÅ Î¦Ö %d ÒÑÄ˦×" +223 "ô¦ÎØÏ×ÉÈ ×¦ËÏÎ ÎÅÍÁ¤" +224 "îÅÍÁ¤ Ô¦ÎØÏ×ÏÇÏ ×¦ËÎÁ Ú ÒÅÄÁÇÕ×ÁÎÎÑÍ ÆÁÊÌÕ %s" +225 "îÅ ÍÏÖÎÁ ÚÒÏÂÉÔÉ Ô¦ÎØÏ×ÉÍ ¤ÄÉΊצËÎÏ" +226 "÷¦ËÎÏ ÍÏÖÎÁ ÓÔÉÓÎÕÔÉ ÌÉÛÅ ÄÏ %d ÒÑÄ˦×" +227 "÷¦ËÎÏ ÎÅ ÍÏÖÎÁ ÓÔÉÓÎÕÔÉ" +228 "÷¦ËÎÏ ÎÅ ÍÏÖÎÁ ÒÏÚÛÉÒÉÔÉ" +230 "ãŠצËÎÏ ÎÅ ÍÏÖÎÁ ÐÒÉÚÕÐÉÎÉÔÉ" +231 "ðÅÒÅÒ×ÁÎÏ: צÄÏÂÒÁÖÅΦ ËÌÁצۦ Ú'¦ÇÎÏÒÏ×ÁÎÏ" +232 "vi: ÔÉÍÞÁÓÏ×ÉÊ ÂÕÆÕÒ ÎÅ ×ÉצÌØÎÅÎÏ" +233 "ãÅÊ ÔÉÐ ÔÅÒͦÎÁÌÕ ÎÅÍÁ¤ ËÌÁצۦ %s" +234 "íÏÖÎÁ ×ËÁÚÁÔÉ ÌÉÛÅ ÏÄÉÎ ÂÕÆÅÒ" +235 "þÉÓÌÏ Â¦ÌØÛÅ, Î¦Ö %lu" +236 "ðÅÒÅÒ×ÁÎÏ" +237 "îÅÍÏÖÌÕ ÓÔ×ÏÒÉÔÉ ÔÉÍÞÁÓÏ×ÉÊ ÆÁÊÌ" +238 "õ÷áçá: %s ÓÐÅæÁÌØÎÉÊ ÆÁÊÌ" +239 "%s ×ÖÅ ÚÁÂÌÏËÏ×ÁÎÏ, ÄÏÓÔÕÐÎÉÊ Ô¦ÌØËÉ ÄÌÑ ÞÉÔÁÎÎÑ" +240 "%s: ÓÔÅÒÔÏ" +241 "%s: ÚÁËÒÉÔÏ" +242 "%s: ÓÔÅÒÔÏ" +243 "%s: ÓÔÅÒÔÏ" +244 "æÁÊÌ Ô¦ÌØËÉ ÄÌÑ ÞÉÔÁÎÎÑ, ÎÅ ÚÁÐÉÓÁÎÏ: ÷ÉËÏÒÉÓÔÁÊÔÅ ! ÄÌÑ ÏÂÈÏÄÕ" +245 "æÁÊÌ Ô¦ÌØËÉ ÄÌÑ ÞÉÔÁÎÎÑ, ÎÅ ÚÁÐÉÓÁÎÏ" +246 "%s ¦ÓÎÕ¤, ÎÅ ÚÁÐÉÓÁÎÏ; ×ÉËÏÒÉÓÔÁÊÔÅ ! ÄÌÑ ÏÂÈÏÄÕ" +247 "%s ¦ÓÎÕ¤, ÎÅ ÚÁÐÉÓÁÎÏ" +248 "÷ÉËÏÒÉÓÔÁÊÔÅ ! ÄÌÑ ÞÁÓÔËÏ×ÏÇÏ ÚÁÐÉÓÕ ÆÁÊÌÕ" +249 "þÁÓÔÉÎÁ ÆÁÊÌÕ, ÆÁÊÌ ÎÅ ÚÁÐÉÓÁÎÏ" +250 "%s: æÁÊÌ ÚͦÎÀ×Á×ÓÑ Ð¦ÚΦÛÅ, Î¦Ö ÃÑ ËÏЦÑ: ×ÉËÏÒÉÓÔÁÊÔÅ ! ÄÌÑ ÏÂÈÏÄÕ" +251 "%s: æÁÊÌ ÚͦÎÀ×Á×ÓÑ Ð¦ÚΦÛÅ, Î¦Ö ÃÑ ËÏЦÑ" +252 "%s: ÚÁÈÉÓÔ ×¦Ä ÚÁÐÉÓÕ ÎÅÄÏÓÔÕÐÎÉÊ" +253 "úÁÐÉÓ..." +254 "%s: õ÷áçá: ÆÁÊÌ ÏÂÒ¦ÚÁÎÏ" +255 "÷ÖÅ ÎÁ ÐÅÒÛÏÍÕ ÔÅÇÕ × Ã¦Ê ÇÒÕЦ" +256 "%s: ÎÏ×ÉÊ ÆÁÊÌ: %lu ÒÑÄ˦×, %lu ÓÉÍ×Ï̦×" +257 "%s: %lu ÒÑÄ˦×, %lu ÓÉÍ×Ï̦×" +258 "%s ÒÏÚÛÉÒÉ×ÓÑ × ÎÁÄÔÏ ×ÅÌÉËÕ Ë¦ÌØ˦ÓÔØ ¦ÍÅÎ ÆÁÊ̦×" +259 "%s: ÓÐÅæÁÌØÎÉÊ ÆÁÊÌ" +260 "%s: ÎÅ ÎÁÌÅÖÉÔØ ÷ÁÍ" +261 "%s: ÄÏÓÔÕÐÎÉÊ ÎÅ ÌÉÛÅ ÷ÁÍ +262 "æÁÊÌ ÍÏÄÉƦËÏ×ÁÎÏ Ð¦ÓÌÑ ÏÓÔÁÎÎØϧ ËÏÍÁÎÄÉ ÚÁÐÉÓÕ: ÚÂÅÒÅÖ¦ÔØ ÞÉ ×ÉËÏÒÉÓÔÁÊÔÅ ! ÄÌÑ ÏÂÈÏÄÕ" +263 "æÁÊÌ ÍÏÄÉƦËÏ×ÁÎÏ Ð¦ÓÌÑ ÏÓÔÁÎÎØϧ ËÏÍÁÎÄÉ ÚÁÐÉÓÕ: ÚÂÅÒÅÖ¦ÔØ ÞÉ ×ÉËÏÒÉÓÔÁÊÔÅ :edit ÄÌÑ ÏÂÈÏÄÕ" +264 "æÁÊÌ ÍÏÄÉƦËÏ×ÁÎÏ Ð¦ÓÌÑ ÏÓÔÁÎÎØϧ ËÏÍÁÎÄÉ ÚÁÐÉÓÕ: ÚÂÅÒÅÖ¦ÔØ ÞÉ ×ÉËÏÒÉÓÔÁÊÔÅ ! ÄÌÑ ÏÂÈÏÄÕ" +265 "ôÉÍÞÁÓÏ×ÉÊ ÆÁÊÌ: ×ÉÈ¦Ä Ú¦ÔÒÅ ÚͦÎÉ" +266 "æÁÊÌ Ô¦ÌØËÉ ÄÌÑ ÞÉÔÁÎÎÑ, ÚͦÎÉ ÎÅ ÚÁÐÉÛÕÔØÓÑ Á×ÔÏÍÁÔÉÞÎÏ" +267 "úÁÐÉÓÉ ÐÏÞÁÔ¦ ÚÁÎÏ×Ï" +268 "ð¦ÄÔ×ÅÒÄÖÕ¤ÔÅ? [ynq]" +269 "îÁÔÉÓΦÔØ ENTER ÄÌÑ ÐÒÏÄÏ×ÖÅÎÎÑ: " +270 "îÁÔÉÓΦÔØ ENTER ÄÌÑ ÐÒÏÄÏ×ÖÅÎÎÑ [: ÄÌÑ ¦ÎÛÉÈ ËÏÍÁÎÄ] " +271 "îÁÔÉÓΦÔØ ENTER ÄÌÑ ÐÒÏÄÏ×ÖÅÎÎÑ [q ÄÌÑ ×ÉÈÏÄÕ]: " +272 "TÁËÁ ÆÏÒÍÁ %s ×ÉÍÁÇÁ¤ ¦ÎÔÅÒÆÅÊÓÕ ex" +273 "÷ÈÏÄÉÍ × ÒÅÖÉÍ ××ÅÄÅÎÎÑ ex" +274 "úÂ¦Ê ËÏÍÁÎÄÉ, ÆÁÊÌ ÎÅ ÐÒÏÞÉÔÁÎÏ" +275 "ðÒÏÄÏ×ÖÉÔÉ?" +276 "îÅÏÞ¦ËÕ×ÁÎÁ ÓÉÍ×ÏÌØÎÁ ÐÏĦÑ" +277 "îÅÏÞ¦ËÕ×ÁÎÁ ÐÏÄ¦Ñ Ë¦ÎÃÑ ÆÁÊÌÕ" +278 "îÅÍÁ¤ ÓЦ×ÐÁÄÁÎØ ÚÁ ÚÁÐÉÔÏÍ" +279 "îÅÏÞ¦ËÕ×ÁÎÁ ÐÏÄ¦Ñ ÐÅÒÅÒÉ×ÁÎÎÑ" +280 "îÅÏÞ¦ËÕ×ÁÎÁ ÐÏÄ¦Ñ ×ÉÈÏÄÕ" +281 "îÅÏÞ¦ËÕ×ÁÎÁ ÐÏÄ¦Ñ ÐÅÒÅÒÉÓÏ×ËÉ" +282 "÷ÖÅ ÎÁ ÏÓÔÁÎÎØÍÕ ôÅÇÕ × Ã¦Ê ÇÒÕЦ" +283 "ëÏÍÁÎÄÁ %s ×ÉÍÁÇÁ¤ ¦ÎÔÅÒÆÅÊÓÕ ex" +284 "TÁËÁ ÆÏÒÍÁ %s ÎÅ ÄÏÚ×ÏÌѤÔØÓÑ ÐÒÉ ×ÓÔÁÎÏ×ÌÅÎ¦Ê ÏÐæ§ secure edit" +285 "îÅÏÞ¦ËÕ×ÁÎÁ ÐÏÄ¦Ñ ÒÑÄËÕ" +286 "îÅÏÞ¦ËÕ×ÁÎÁ ÐÏÄ¦Ñ ÔÁÊÍ-ÁÕÔÕ" +287 "îÅÏÞ¦ËÕ×ÁÎÁ ÐÏÄ¦Ñ ÚÁÐÉÓÕ" +289 "Shell'¦×ÓËÅ ÄÏÐÏ×ÎÅÎÎÑ ÎÅ ÄÏÚ×ÏÌѤÔØÓÑ ÐÒÉ ×ÓÔÁÎÏ×ÌÅÎ¦Ê ÏÐæ§ secure edit" +290 "ëÏÍÁÎÄÁ %s ÎÅ ÄÏÚ×ÏÌѤÔØÓÑ ÐÒÉ ×ÓÔÁÎÏ×ÌÅÎ¦Ê ÏÐæ§ secure edit" +291 "set: ÏÐæÀ %s ÎÅÍÏÖÎÁ ×ÉÓÔÁ×ÉÔÉ ×ÉÍËÎÅÎÏÀ" +292 "åËÒÁÎ ÎÁÄÔÏ ÍÁÌÉÊ." +293 "ÄÏÄÁÎÏ" +294 "ÚͦÎÅÎÏ" +295 "ÓÔÅÒÔÏ" +296 "ÏÂ'¤ÄÎÁÎÏ" +297 "ÐÅÒÅͦÝÅÎÏ" +298 "ÚÄ×ÉÎÕÔÏ" +299 "×ÓÔÁ×ÌÅÎÏ" +300 "ÒÑÄÏË" +301 "ÒÑÄ˦×" +302 "Vi ÚÁ×ÁÎÔÁÖÅÎÏ ÂÅÚ ¦ÎÔÅÒÐÒÅÔÁÔÏÒÁ Tcl" +303 "æÁÊÌ ÍÏÄÉƦËÏ×ÁÎÏ Ð¦ÓÌÑ ÏÓÔÁÎÎØϧ ËÏÍÁÎÄÉ ÚÁÐÉÓÕ." +304 "îÅ×ÄÁÞÁ shell'¦×ÓØËÏÇÏ ÄÏÐÏ×ÎÅÎÎÑ" +305 "OÐæ§ ÒÅÄÁÇÕ×ÁÎÎÑ %s ÎÅ ×ËÁÚÁÎÏ" +306 "Vi ÚÁ×ÁÎÔÁÖÅÎÏ ÂÅÚ ¦ÎÔÅÒÐÒÅÔÁÔÏÒÁ Perl" +307 "îÅÍÁ¤ ËÏÍÁÎÄÉ ex ÄÌÑ ×ÉËÏÎÁÎÎÑ" +308 "îÁÔÉÓΦÔØ ENTER ÝÏ ×ÉËÏÎÁÔÉ ËÏÍÁÎÄÕ, q ÝÏ ×ÉÊÔÉ" +309 "÷×ÅĦÔØ 'cscope help' ÄÌÑ ¦ÎÆÏÒÍÁæ§" +310 "îÅÍÁ¤ cscope Ú'¤ÄÎÁÎÎØ" +311 "%s: ÎÅצÄÏÍÉÊ ÔÉÐ ÐÏÛÕËÕ: ×ÉËÏÒÉÓÔÏ×ÕÊÔÅ ÏÄÉÎ Ú %s" +312 "%d: ÎÅÍÁ¤ ÔÁËϧ ÓÅÓ¦§ cscope" +313 "set: ÏÐæÀ %s ÎÅÍÏÖÎÁ ×ÉÓÔÁ×ÉÔÉ ÕצÍËÎÅÎÏÀ" +314 "set: ÏÐæÀ %s ÎÅÍÏÖÎÁ ×ÉÓÔÁ×ÉÔÉ × 0" +315 "%s: ÄÏÄÁÎÏ: %lu ÒÑÄ˦×, %lu ÓÉÍ×Ï̦×" +316 "îÅÏÞ¦ËÕ×ÁÎÁ ÐÏÄ¦Ñ ÚͦÎÉ ÒÏÚͦÒÕ" +317 "%d ÆÁÊÌ¦× ÄÌÑ ÒÅÄÁÇÕ×ÁÎÎÑ" Property changes on: vendor/nvi/2.2.0-05ed8b9/catalog/uk_UA.KOI8-U.base ___________________________________________________________________ Added: fbsd:notbinary ## -0,0 +1 ## +catalog/dutch.base \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain; charset=KOI8-U \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/catalog/uk_UA.KOI8-U.owner =================================================================== --- vendor/nvi/2.2.0-05ed8b9/catalog/uk_UA.KOI8-U.owner (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/catalog/uk_UA.KOI8-U.owner (revision 366308) @@ -0,0 +1 @@ +Olexander Kunytsa aka Cawko Xakep Index: vendor/nvi/2.2.0-05ed8b9/catalog/zh_CN.GB2312.base =================================================================== --- vendor/nvi/2.2.0-05ed8b9/catalog/zh_CN.GB2312.base (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/catalog/zh_CN.GB2312.base (revision 366308) @@ -0,0 +1,311 @@ +002 "Ð㤶ÈÒç³ö" +003 "ÎÞ·¨É¾³ýµÚ %lu ÐÐ" +004 "ÎÞ·¨ÏòµÚ %lu ÐÐ×·¼Ó" +005 "ÎÞ·¨ÏòµÚ %lu ÐвåÈë" +006 "ÎÞ·¨´æ´¢µÚ %lu ÐÐ" +007 "ÎÞ·¨»ñµÃ×îºóÒ»ÐÐ" +008 "´íÎó£ºÎÞ·¨»ñÈ¡µÚ %lu ÐÐ" +009 "ÈÕÖ¾Îļþ" +010 "ÈÕ־δ¼Ç¼£¬ÎÞ·¨³·Ïú" +011 "δ×öÐ޸ģ¬ÎÞ·¨³·Ïú" +012 "ÈÕ־δ¼Ç¼£¬ÎÞ·¨³·Ïú" +013 "ÈÕ־δ¼Ç¼£¬ÎÞ·¨»Ø¹ö" +014 "δ×öÐ޸ģ¬ÎÞ·¨ÖØ×ö" +015 "%s/%d: ÈÕÖ¾´íÎó" +016 "Vi µÄ±ê×¼ÊäÈëºÍÊä³ö±ØÐëÊÇÖÕ¶Ë" +017 "±ê¼Ç %s: δÉèÖÃ" +018 "±ê¼Ç %s: ¸ÃÐб»É¾³ý" +019 "±ê¼Ç %s: ¹â±êλÖò»´æÔÚ" +020 "´íÎó£º" +021 "ÐÂÎļþ" +022 "ÎļþÃû±ä¸ü" +023 "ÒÑÐÞ¸Ä" +024 "δÐÞ¸Ä" +025 "ÒѽâËø" +026 "Ö»¶Á" +027 "µÚ %lu ÐУ¯¹² %lu ÐÐ [%ld%%]" +028 "¿ÕÎļþ" +029 "µÚ %lu ÐÐ" +030 "Îļþ %s ²»ÊÇÏûϢĿ¼" +031 "ÎÞ·¨ÉèÖÃÑ¡Ïî %s µÄĬÈÏÖµ" +032 "Ó÷¨ %s" +033 "set: ²»´æÔÚÑ¡Ïî %s£»Óà 'set all' ²é¿´ËùÓÐÑ¡ÏîµÄÖµ" +034 "set: Ñ¡Ïî [no]%s ²»½ÓÊܸ³Öµ" +035 "set: Ñ¡Ïî %s ²»ÊÇ¿ª¹Ø" +036 "set: Ñ¡Ïî %s: %s" +037 "set: Ñ¡Ïî %s: %s: ÖµÒç³ö" +038 "set: Ñ¡Ïî %s: %s ÊÇÒ»¸ö·Ç·¨Êý×Ö" +039 "set: Ñ¡Ïî %s ²»ÊÇ¿ª¹Ø" +040 "ÆÁĻ̫խ£¬ÁпíСÓÚ %d" +041 "ÆÁĻ̫¿í£¬Áпí´óÓÚ %d" +042 "ÆÁĻ̫°«£¬ÐиßСÓÚ %d" +043 "ÆÁĻ̫¸ß£¬ÐиߴóÓÚ %d" +044 "lisp Ñ¡ÏîδʵÏÖ" +045 "ÏûϢδ¹Ø±Õ£º%s" +046 "ÏûϢδ´ò¿ª£º%s" +047 "%s Ñ¡Ïî±ØÐëÿÁ½¸ö×Ö·ûÒ»×é" +053 "ĬÈÏ»º³åÇøΪ¿Õ" +054 "»º³åÇø %s Ϊ¿Õ" +055 "ÎļþÃûÖÐÓл»ÐеÄÎļþÊÇÎÞ·¨»Ö¸´µÄ" +056 "Ò»µ©»á»°Ê§°Ü£¬ÐÞ¸ÄÎÞ·¨»Ö¸´" +057 "ÕýÔÚ±¸·ÝÎļþ¡­¡­" +058 "±£´æʧ°Ü£º%s" +059 "Ò»µ©»á»°Ê§°Ü£¬ÐÞ¸ÄÎÞ·¨»Ö¸´" +060 "Îļþ±¸·Ýʧ°Ü£º%s" +061 "ÕýÔÚ±¸·ÝÎļþ¡­¡­" +062 "ID Ϊ %u µÄÓû§Î´ÕÒµ½" +063 "ÎÞ·¨¸ø»Ö¸´Îļþ¼ÓËø" +064 "»Ö¸´Îļþ»º³åÇøÒç³ö" +065 "»Ö¸´Îļþ" +066 "%s: »Ö¸´Îļþ¸ñʽÒì³£" +067 "%s: »Ö¸´Îļþ¸ñʽÒì³£" +068 "²»´æÔÚÃûΪ %s µÄ£¬¿É¶Á²¢ÐèÒª»Ö¸´µÄÎļþ" +069 "´æÔÚ´ËÎļþµÄ¾É°æ±¾ÐèÒªÄú»Ö¸´" +070 "´æÔÚÆäËüÐèÒªÄú»Ö¸´µÄÎļþ" +071 "Óʼþδ·¢³ö£º%s" +072 "ÎļþΪ¿Õ£¬ÎÞ·¨ËÑË÷" +073 "µ½´ïÎļþβ£¬Î´ÕÒµ½Ä£Ê½" +074 "ûÓÐÉÏÒ»¸öËÑË÷ģʽ" +075 "ģʽδÕÒµ½" +076 "µ½´ïÎļþÍ·£¬Î´ÕÒµ½Ä£Ê½" +077 "ËÑË÷»Øת" +078 "ÕýÔÚËÑË÷¡­¡­" +079 "δÕÒµ½²»¿É´òÓ¡×Ö·û" +080 "ÃüÁîÃû²»Ã÷" +082 "%s: ÃüÁîÔÚ ex ģʽϲ»¿ÉÓÃ" +083 "ÃüÁî¼ÆÊý²»¿ÉΪ 0" +084 "%s: ´íÎóµÄÐÐÃèÊö" +085 "ÄÚ²¿Óï·¨±í´íÎó (%s: %s)" +086 "Ó÷¨£º%s" +087 "%s: ÁÙʱ»º³åÇøδÊÍ·Å" +088 "ÐÞÊηûÆ«ÒÆÁ¿ÔÚµÚÒ»ÐÐ֮ǰ" +089 "ÐÞÊηûÆ«ÒÆÁ¿³¬¹ý×îºóÒ»ÐÐ" +090 "Îļþ£¯ÆÁÄ»¸Ä±äʱÓдø·¶Î§µÄ @ ÃüÁîÕýÔÚÔËÐÐ" +091 "Îļþ£¯ÆÁÄ»¸Ä±äʱÓÐÈ«¾ÖÃüÁv ÃüÁîÕýÔÚÔËÐÐ" +092 "Ex ÃüÁîʧ°Ü£ºµÈ´ýÖеÄÃüÁîÒѶªÆú" +093 "Ex ÃüÁîʧ°Ü£º¼üÓ³ÉäÒѶªÆú" +094 "µÚ¶þµØַСÓÚµÚÒ»µØÖ·" +095 "δÌṩ±ê¼ÇÃû" +096 "\\ ûÓиúÔÚ / »ò ? ºóÃæ" +097 "ÒýÓÃÁËСÓÚ 0 µÄÐкÅ" +098 "%s ÃüÁî²»Ã÷" +099 "µØÖ·ÖµÒç³ö" +100 "µØÖ·ÖµÏÂÒç" +101 "·Ç·¨µÄµØÖ·×éºÏ" +102 "·Ç·¨µØÖ·£ºÎļþÖ»ÓÐ %lu ÐÐ" +103 "·Ç·¨µØÖ·£ºÎļþΪ¿Õ" +104 "ÃüÁî %s ²»ÔÊÐíµØַΪ 0" +105 "ûÓпÉÏÔʾµÄËõд" +106 "Ëõд±ØÐëÒÔ¡¸µ¥´Ê¡¹×Ö·û½áÊø" +107 "Ëõд²»ÄÜ°üº¬ÖƱí·û»ò¿Õ¸ñ" +108 "Ëõд²»ÄÜÔÚ½áβ֮ÍâµÄµØ·½»ìÓõ¥´Ê£¯·Çµ¥´Ê×Ö·û" +109 "\"%s\" ²»ÊÇËõд" +110 "Vi ÃüÁîʧ°Ü£º¼üÓ³ÉäÒѶªÆú" +111 "ûÓÐÊ£ÓàµÄ´ý±à¼­Îļþ" +112 "ûÓÐÉÏÒ»¸ö´ý±à¼­Îļþ" +113 "ûÓÐÉÏÒ»¸öÐèÖØб༭µÄÎļþ" +114 "ûÓпÉÏÔʾµÄÎļþÁбí" +115 "ȱÉÙÓÃÓÚÌæ»» \"!\" µÄÉÏÒ»ÌõÃüÁî" +116 "ȱÉÙÓÃÓÚÌæ»» %% µÄÎļþÃû" +117 "ȱÉÙÓÃÓÚÌæ»» # µÄÎļþÃû" +118 "´íÎó£ºexecl: %s" +119 "ÊäÈ룯Êä³ö´íÎó£º%s" +120 "ÎļþÔÚÉÏÒ»´ÎÍêÕûдÈëºó±»Ð޸ģ»Ð´ÈëÎļþ£¬»òʹÓà ! Ç¿ÖÆÇл»Ä¿Â¼" +121 "ÎÞ·¨ÕÒµ½Óû§ÆðʼĿ¼" +122 "еĵ±Ç°Ä¿Â¼£º%s" +123 "ûÓпÉÏÔʾµÄ¼ôÇлº³åÇø" +124 "%s ÃüÁî²»Äܱ»ÓÃ×÷È«¾ÖÃüÁî»ò v ÃüÁîµÄÒ»²¿·Ö" +125 "%s/%s: δÒýÈ룺²»ÊôÓÚÄú»ò¸ùÓû§" +126 "%s/%s: δÒýÈ룺²»ÊôÓÚÄú" +127 "%s/%s: δÒýÈ룺¿ÉÒÔ±»ÎļþÊôÖ÷ÒÔÍâµÄÓû§Ð´Èë" +128 "%s: δÒýÈ룺²»ÊôÓÚÄú»ò¸ùÓû§" +129 "%s: δÒýÈ룺²»ÊôÓÚÄú" +130 "%s: δÒýÈ룺¿ÉÒÔ±»ÎļþÊôÖ÷ÒÔÍâµÄÓû§Ð´Èë" +131 "ȱÉÙ¿ÉÒԺϲ¢µÄÐÐ" +132 "ȱÉÙÊäÈëÓ³Éä" +133 "ȱÉÙÃüÁîÓ³Éä" +134 "%s ×Ö·û²»Äܱ»ÖØÐÂÓ³Éä" +135 "\"%s\" Ŀǰδ±»Ó³Éä" +136 "±ê¼ÇÃû±ØÐëÊǵ¥¸ö×Ö·û" +137 "%s ÒÑ´æÔÚ£¬Î´Ð´È룻Óà ! ¸²¸ÇÎļþ" +138 "н¨ exrc Îļþ£º%s" +139 "Ä¿±êÐÐÔÚÒƶ¯·¶Î§Ö®ÄÚ" +140 "open ÒªÇó¿ªÆô open Ñ¡Ïî" +141 "open ÃüÁîδʵÏÖ" +142 "ÎÞ·¨±£³Ö´ËÎļþ" +143 "ÎļþÒѱ£³Ö" +144 "%s: Õ¹¿ªµÄÎļþÃû¹ý¶à" +145 "Ö»ÄܶÁÈ¡³£¹æÎļþºÍ¾ßÃû¹ÜµÀ" +146 "%s: ¶ÁËø²»¿ÉÓÃ" +147 "ÕýÔÚ¶ÁÈ¡¡­¡­" +148 "%s: %lu ÐУ¬%lu ¸ö×Ö·û" +149 "ûÓпÉÏÔʾµÄºǫ́ÆÁÄ»" +150 "script ÃüÁî½öÔÚ vi ģʽÏ¿ÉÓÃ" +151 "ûÓÐÒªÖ´ÐеÄÃüÁî" +152 "shiftwidth Ñ¡Ïî±»ÉèΪ 0" +153 "ÃüÁî¼ÆÊýÒç³ö" +154 "ÃüÁî¼ÆÊýÏÂÒç" +155 "ÕýÔò±í´ïʽÒÑÖ¸¶¨£»r ÐÞÊηûÎÞЧ" +156 "#, l ºÍ p ÐÞÊηûÔÚ vi ģʽϲ»ÄÜÓë c ÐÞÊηû×éºÏ" +157 "δÕÒµ½Æ¥Åä" +158 "ûÓÐÉÏÒ»´Î½øÈëµÄ tag" +159 "tags Õ»ÉϵļǼÉÙÓÚ %s Ìõ£»Óà :display t[ags] ÏÔʾËüÃÇ" +160 "tags Õ»Éϲ»´æÔÚÎļþ %s£¬ÎÞ·¨·µ»Ø£»Óà :display t[ags] ²é¿´" +161 "°´»Ø³µ¼ü¼ÌÐø£º" +162 "%s: tag δÕÒµ½" +163 "%s: Ëð»µµÄ tag ÔÚ %s ÖÐ" +164 "%s: tag µÄÐкų¬¹ýÁËÎļþβ" +165 "tags ջΪ¿Õ" +166 "%s: ËÑË÷ģʽδÕÒµ½" +167 "»¹ÓÐ %d ¸ö´ý±à¼­Îļþ" +168 "»º³åÇø %s Ϊ¿Õ" +169 "È·ÈÏÐ޸ģ¿[n]" +170 "ÒÑÖжÏ" +171 "ûÓÐÉÏÒ»¸ö¿É¹©Ö´ÐеĻº³åÇø" +172 "ûÓÐÉÏÒ»ÌõÕýÔò±í´ïʽ" +173 "%s ÒªÇó´æÔÚÒ»¸öÒѶÁÈëµÄÎļþ" +174 "Ó÷¨£º%s" +175 "visual ÃüÁîÒªÇó¿ªÆô open Ñ¡Ïî" +177 "¿ÕÎļþ" +178 "ûÓÐÉÏÒ»´Î F, f, T »ò t ËÑË÷" +179 "%s δÕÒµ½" +180 "ûÓÐÉÏÒ»¸ö´ý±à¼­Îļþ" +181 "¹â±ê²»ÔÚÊý×ÖÉÏ" +182 "½á¹ûÊý×Ö¹ý´ó" +183 "½á¹ûÊý×Ö¹ýС" +184 "ÕâÒ»ÐÐÉÏûÓÐÆ¥ÅäµÄ×Ö·û" +185 "Æ¥Åä×Ö·ûδÕÒµ½" +186 "ûÓпÉÌæ»»µÄ×Ö·û" +187 "ûÓÐÆäËüÆÁÄ»¿ÉÒÔÇл»" +188 "ÔÚËÑË÷×Ö·û´®¡¢ÐÐÆ«ÒÆÁ¿»ò z ÃüÁîÖ®ºóÓжàÓà×Ö·û" +189 "ûÓÐÉÏÒ»¸öËÑË÷ģʽ" +190 "ËÑË÷»Øתµ½Á˳õʼλÖÃ" +191 "Ëõдչ¿ª³¬¹ýÏÞÖÆ£º×Ö·ûÒѶªÆú" +192 "·Ç·¨×Ö·û£»ÓÃÒýºÅÀ¨ÆðÀ´ÔÙÊäÈë" +193 "Òѵ½²åÈëµãµÄ¿ªÊ¼" +194 "ûÓпɲÁ³ýµÄÊ£Óà×Ö·û" +195 "Òƶ¯³¬¹ýÎļþβ" +196 "Òƶ¯³¬¹ýÐÐÄ©" +197 "¹â±êδÒƶ¯" +198 "Òѵ½ÎļþÍ·" +199 "Òƶ¯³¬¹ýÎļþÍ·" +200 "ÒÑλÓÚµÚÒ»ÁÐ" +201 "»º³åÇøÓ¦ÔÚÃüÁîÇ°Ö¸¶¨" +202 "Òѵ½Îļþβ" +203 "Òѵ½ÐÐÄ©" +204 "%s ²»ÊÇ vi ÃüÁî" +205 "Ó÷¨ %s" +206 "ûÓпÉɾ³ýµÄ×Ö·û" +207 "Q ÃüÁîÐèÒª ex Öն˽çÃæ" +208 "ûÓпÉÖظ´µÄÃüÁî" +209 "ÎļþΪ¿Õ" +210 "%s ²»Äܱ»ÓÃ×÷Òƶ¯ÃüÁî" +211 "ÒÑ´¦ÓÚÃüÁîģʽ" +212 "¹â±ê²»ÔÚµ¥´ÊÉÏ" +214 "´°¿ÚÑ¡ÏîµÄÖµ¹ý´ó£¬×î´óÖµ %u" +215 "×·¼Ó" +216 "ÐÞ¸Ä" +217 "ÃüÁî" +218 "²åÈë" +219 "Ìæ»»" +220 "Òƶ¯³¬¹ýÆÁÄ»ÖÕµã" +221 "Òƶ¯³¬¹ýÆÁÄ»Æðµã" +222 "·ÖÆÁÐèÒª¶àÓÚ %d ÐÐ" +223 "ûÓкǫ́ÆÁÄ»" +224 "²»´æÔÚÕýÔڱ༭Îļþ %s µÄºǫ́ÆÁÄ»" +225 "²»ÄÜ°ÑÄúΨһµÄÆÁÄ»ÖÃÓÚºǫ́" +226 "ÆÁĻֻÄÜÊÕËõµ½ %d ÐÐ" +227 "ÆÁÄ»²»ÄÜÊÕËõ" +228 "ÆÁÄ»²»ÄÜÔö¸ß" +230 "²»ÄܹÒÆð´ËÆÁÄ»" +231 "ÒÑÖжϣº¼üÓ³ÉäÒѶªÆú" +232 "vi: ÁÙʱ»º³åÇøδÊÍ·Å" +233 "´ËÖÕ¶ËûÓÐ %s ¼ü" +234 "Ö»ÄÜÖ¸¶¨Ò»¸ö»º³åÇø" +235 "Êý×Ö´óÓÚ %lu" +236 "ÒÑÖжÏ" +237 "ÎÞ·¨´´½¨ÁÙʱÎļþ" +238 "¾¯¸æ£º%s ²»Êdz£¹æÎļþ" +239 "%s ÒѼÓËø£¬»á»°ÎªÖ»¶Á" +240 "%s: ÒƳý" +241 "%s: ¹Ø±Õ" +242 "%s: ÒƳý" +243 "%s: ÒƳý" +244 "Ö»¶ÁÎļþ£¬Î´Ð´È룻Óà ! Ç¿ÖÆдÈë" +245 "Ö»¶ÁÎļþ£¬Î´Ð´Èë" +246 "%s ÒÑ´æÔÚ£¬Î´Ð´È룻Óà ! ¸²¸ÇÎļþ" +247 "%s ÒÑ´æÔÚ£¬Î´Ð´Èë" +248 "ÊÇÒÑ´æÔÚÎļþµÄÒ»²¿·Ö£¬Î´Ð´È룻Óà ! Ç¿ÖÆдÈë" +249 "ÊÇÒÑ´æÔÚÎļþµÄÒ»²¿·Ö£¬Î´Ð´Èë" +250 "%s: Îļþ±»Ð޸ģ¬ÐÂÓÚµ±Ç°¿½±´£»Óà ! Ç¿ÖÆдÈë" +251 "%s: Îļþ±»Ð޸ģ¬ÐÂÓÚµ±Ç°¿½±´" +252 "%s: дËø²»¿ÉÓÃ" +253 "ÕýÔÚдÈë¡­¡­" +254 "%s: ¾¯¸æ£ºÎļþ±»½Ø¶Ï" +255 "ÒÑλÓÚÕâ×é tags ÖеĵÚÒ»¸ö" +256 "%s: ÐÂÎļþ£º%lu ÐУ¬%lu ¸ö×Ö·û" +257 "%s: %lu ÐУ¬%lu ¸ö×Ö·û" +258 "%s: Õ¹¿ªµÄÎļþÃû¹ý¶à" +259 "%s: ²»Êdz£¹æÎļþ" +260 "%s: ²»ÊôÓÚÄú" +261 "%s: ¿É±»ÎļþÊôÖ÷ÒÔÍâµÄÓû§·ÃÎÊ" +262 "ÎļþÔÚÉÏÒ»´ÎÍêÕûдÈëºó±»Ð޸ģ»Ð´ÈëÎļþ£¬»òʹÓà ! Ç¿ÖÆÔØÈë" +263 "ÎļþÔÚÉÏÒ»´ÎÍêÕûдÈëºó±»Ð޸ģ»Ð´ÈëÎļþ£¬»òʹÓà :edit! Ç¿ÖƱ༭" +264 "ÎļþÔÚÉÏÒ»´ÎÍêÕûдÈëºó±»Ð޸ģ»Ð´ÈëÎļþ£¬»òʹÓà ! Ç¿ÖÆÖ´ÐÐ" +265 "ÁÙʱÎļþ£¬Í˳ö½«¶ªÆúÈ«²¿ÐÞ¸Ä" +266 "ÎļþÖ»¶Á£¬ÐÞ¸Äδ±»×Ô¶¯Ð´Èë" +267 "ÈÕÖ¾ÖØÆô" +268 "È·ÈÏ£¿[ynq]" +269 "°´ÈÎÒâ¼ü¼ÌÐø£º" +270 "°´ÈÎÒâ¼ü¼ÌÐø£Û°´ : ¼üÊäÈë ex ÃüÁî£Ý£º" +271 "°´ÈÎÒâ¼ü¼ÌÐø£Û°´ q ¼üÍƳö£Ý£º" +272 "¸ÃÐÎʽµÄ %s ÃüÁîÐèÒª ex Öն˽çÃæ" +273 "½øÈë ex ÊäÈëģʽ" +274 "ÃüÁîʧ°Ü£¬ÉÐδ¶ÁÈëÎļþ" +275 " ¼ÌÐø£¿" +276 "ÒâÍâµÄ×Ö·ûʼþ" +277 "ÒÔÍâµÄÎļþβʼþ" +278 "²éѯδÕÒµ½Æ¥Åä" +279 "ÒâÍâµÄÖжÏʼþ" +280 "ÒâÍâµÄÍ˳öʼþ" +281 "ÒâÍâµÄÖØ»æʼþ" +282 "ÒÑλÓÚÕâ×é tags ÖеÄ×îºóÒ»¸ö" +283 "%s ÃüÁîÐèÒª ex Öն˽çÃæ" +284 "secure ±à¼­Ñ¡ÏÆôʱ²»Ö§³Ö¸ÃÐÎʽµÄ %s ÃüÁî" +285 "ÒâÍâµÄ×Ö·û´®Ê¼þ" +286 "ÒâÍâµÄ³¬Ê±Ê¼þ" +287 "ÒâÍâµÄдÈëʼþ" +288 "·ÖÆÁÐèÒª¶àÓÚ %d ÁÐ" +289 "secure ±à¼­Ñ¡ÏÆôʱ²»Ö§³Ö shell Õ¹¿ª" +290 "secure ±à¼­Ñ¡ÏÆôʱ²»Ö§³Ö %s ÃüÁî" +291 "set: Ñ¡Ïî %s ²»ÄܹرÕ" +292 "ÏÔʾ¿Õ¼ä̫С" +293 "ÒÑÌí¼Ó" +294 "ÒÑÐÞ¸Ä" +295 "ÒÑɾ³ý" +296 "ÒѺϲ¢" +297 "ÒÑÒƶ¯" +298 "ÒÑÆ«ÒÆ" +299 "ÒѸ´ÖÆ" +300 "ÐÐ" +301 "ÐÐ" +303 "ÎļþÔÚÉÏÒ»´ÎдÈëºó±»ÐÞ¸Ä" +304 "Shell Õ¹¿ªÊ§°Ü" +305 "δָ¶¨ %s ±à¼­Ñ¡Ïî" +307 "ûÓÐÒªÖ´ÐÐµÄ ex ÃüÁî" +308 "¼üÈë»Ø³µÖ´ÐÐÒ»ÌõÃüÁ:q Í˳ö" +309 "ʹÓà \"cscope help\" ²é¿´°ïÖú" +310 "ûÓÐÕýÔÚÔËÐÐµÄ cscope Á¬½Ó" +311 "%s: ËÑË÷ÀàÐͲ»Ã÷£ºÊ¹Óà %s ÖеÄÒ»¸ö" +312 "%d: ÎÞ´Ë cscope »á»°" +313 "set: Ñ¡Ïî %s ¾ø¶Ô²»ÄÜ¿ªÆô" +314 "set: Ñ¡Ïî %s ¾ø¶Ô²»Äܱ»ÉèΪ 0" +315 "%s: ÒÑ×·¼Ó£º%lu ÐУ¬%lu ¸ö×Ö·û" +316 "ÒâÍâµÄ´óСµ÷Õûʼþ" +317 "%d ¸ö´ý±à¼­µÄÎļþ" +319 "%d ¸öºǫ́ÆÁÄ»£»Óà :display ÁгöËüÃÇ" +320 "¹â±êλÖò»Ã÷" +321 "²»Ö§³ÖÎļþ±àÂëת»»" +322 "²»Ö§³ÖÊäÈë±àÂëת»»" +323 "ÎÞЧÊäÈ룬ÒѽضÏ" +324 "µÚ %d ÐÐÉÏÓÐת»»´íÎó" Property changes on: vendor/nvi/2.2.0-05ed8b9/catalog/zh_CN.GB2312.base ___________________________________________________________________ Added: fbsd:notbinary ## -0,0 +1 ## +catalog/dutch.base \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain; charset=GB2312 \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/catalog/zh_CN.GB2312.owner =================================================================== --- vendor/nvi/2.2.0-05ed8b9/catalog/zh_CN.GB2312.owner (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/catalog/zh_CN.GB2312.owner (revision 366308) @@ -0,0 +1 @@ +Zhihao Yuan Index: vendor/nvi/2.2.0-05ed8b9/catalog/dutch.owner =================================================================== --- vendor/nvi/2.2.0-05ed8b9/catalog/dutch.owner (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/catalog/dutch.owner (revision 366308) @@ -0,0 +1 @@ +J.G. Vons Property changes on: vendor/nvi/2.2.0-05ed8b9/catalog/dutch.owner ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/catalog/english.owner =================================================================== --- vendor/nvi/2.2.0-05ed8b9/catalog/english.owner (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/catalog/english.owner (revision 366308) @@ -0,0 +1 @@ +Keith Bostic Property changes on: vendor/nvi/2.2.0-05ed8b9/catalog/english.owner ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/catalog/swedish.owner =================================================================== --- vendor/nvi/2.2.0-05ed8b9/catalog/swedish.owner (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/catalog/swedish.owner (revision 366308) @@ -0,0 +1 @@ +Jan Djarv Property changes on: vendor/nvi/2.2.0-05ed8b9/catalog/swedish.owner ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/cl/cl.h =================================================================== --- vendor/nvi/2.2.0-05ed8b9/cl/cl.h (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/cl/cl.h (revision 366308) @@ -0,0 +1,83 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#ifdef USE_WIDECHAR +#define _XOPEN_SOURCE_EXTENDED +#endif +#ifdef HAVE_NCURSESW_NCURSES_H +#include +#elif defined HAVE_NCURSES_H +#include +#else +#include +#endif + +typedef struct _cl_private { + char ibuf[256]; /* Input keys. */ + + size_t skip; /* Remaining keys. */ + + CONVWIN cw; /* Conversion buffer. */ + + int eof_count; /* EOF count. */ + + struct termios orig; /* Original terminal values. */ + struct termios ex_enter;/* Terminal values to enter ex. */ + struct termios vi_enter;/* Terminal values to enter vi. */ + + char *el; /* Clear to EOL terminal string. */ + char *cup; /* Cursor movement terminal string. */ + char *cuu1; /* Cursor up terminal string. */ + char *rmso, *smso; /* Inverse video terminal strings. */ + char *smcup, *rmcup; /* Terminal start/stop strings. */ + + char *oname; /* Original screen window name. */ + + SCR *focus; /* Screen that has the "focus". */ + + int killersig; /* Killer signal. */ +#define INDX_HUP 0 +#define INDX_INT 1 +#define INDX_TERM 2 +#define INDX_WINCH 3 +#define INDX_MAX 4 /* Original signal information. */ + struct sigaction oact[INDX_MAX]; + + enum { /* Tty group write mode. */ + TGW_UNKNOWN=0, TGW_SET, TGW_UNSET } tgw; + + enum { /* Terminal initialization strings. */ + TE_SENT=0, TI_SENT } ti_te; + +#define CL_IN_EX 0x0001 /* Currently running ex. */ +#define CL_LAYOUT 0x0002 /* Screen layout changed. */ +#define CL_RENAME 0x0004 /* X11 xterm icon/window renamed. */ +#define CL_RENAME_OK 0x0008 /* User wants the windows renamed. */ +#define CL_SCR_EX_INIT 0x0010 /* Ex screen initialized. */ +#define CL_SCR_VI_INIT 0x0020 /* Vi screen initialized. */ +#define CL_SIGHUP 0x0040 /* SIGHUP arrived. */ +#define CL_SIGINT 0x0080 /* SIGINT arrived. */ +#define CL_SIGTERM 0x0100 /* SIGTERM arrived. */ +#define CL_SIGWINCH 0x0200 /* SIGWINCH arrived. */ +#define CL_STDIN_TTY 0x0400 /* Talking to a terminal. */ + u_int32_t flags; +} CL_PRIVATE; + +#define CLP(sp) ((CL_PRIVATE *)((sp)->gp->cl_private)) +#define GCLP(gp) ((CL_PRIVATE *)gp->cl_private) +#define CLSP(sp) ((WINDOW *)((sp)->cl_private)) + +/* Return possibilities from the keyboard read routine. */ +typedef enum { INP_OK=0, INP_EOF, INP_ERR, INP_INTR, INP_TIMEOUT } input_t; + +/* The screen position relative to a specific window. */ +#define RCNO(sp, cno) (cno) +#define RLNO(sp, lno) (lno) + +#include "extern.h" Property changes on: vendor/nvi/2.2.0-05ed8b9/cl/cl.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/cl/cl_read.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/cl/cl_read.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/cl/cl_read.c (revision 366308) @@ -0,0 +1,327 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../common/common.h" +#include "../ex/script.h" +#include "cl.h" + +/* Pollution by Solaris curses. */ +#undef columns +#undef lines + +static input_t cl_read(SCR *, + u_int32_t, char *, size_t, int *, struct timeval *); +static int cl_resize(SCR *, size_t, size_t); + +/* + * cl_event -- + * Return a single event. + * + * PUBLIC: int cl_event(SCR *, EVENT *, u_int32_t, int); + */ +int +cl_event(SCR *sp, EVENT *evp, u_int32_t flags, int ms) +{ + struct timeval t, *tp; + CL_PRIVATE *clp; + size_t lines, columns; + int changed, nr = 0; + CHAR_T *wp; + size_t wlen; + int rc; + + /* + * Queue signal based events. We never clear SIGHUP or SIGTERM events, + * so that we just keep returning them until the editor dies. + */ + clp = CLP(sp); +retest: if (LF_ISSET(EC_INTERRUPT) || F_ISSET(clp, CL_SIGINT)) { + if (F_ISSET(clp, CL_SIGINT)) { + F_CLR(clp, CL_SIGINT); + evp->e_event = E_INTERRUPT; + } else + evp->e_event = E_TIMEOUT; + return (0); + } + if (F_ISSET(clp, CL_SIGHUP | CL_SIGTERM | CL_SIGWINCH)) { + if (F_ISSET(clp, CL_SIGHUP)) { + evp->e_event = E_SIGHUP; + return (0); + } + if (F_ISSET(clp, CL_SIGTERM)) { + evp->e_event = E_SIGTERM; + return (0); + } + if (F_ISSET(clp, CL_SIGWINCH)) { + F_CLR(clp, CL_SIGWINCH); + if (cl_ssize(sp, 1, &lines, &columns, &changed)) + return (1); + if (changed) { + (void)cl_resize(sp, lines, columns); + evp->e_event = E_WRESIZE; + return (0); + } + /* No real change, ignore the signal. */ + } + } + + /* Set timer. */ + if (ms == 0) + tp = NULL; + else { + t.tv_sec = ms / 1000; + t.tv_usec = (ms % 1000) * 1000; + tp = &t; + } + + /* Read input characters. */ +read: + switch (cl_read(sp, LF_ISSET(EC_QUOTED | EC_RAW), + clp->ibuf + clp->skip, SIZE(clp->ibuf) - clp->skip, &nr, tp)) { + case INP_OK: + rc = INPUT2INT5(sp, clp->cw, clp->ibuf, nr + clp->skip, + wp, wlen); + evp->e_csp = wp; + evp->e_len = wlen; + evp->e_event = E_STRING; + if (rc < 0) { + int n = -rc; + memmove(clp->ibuf, clp->ibuf + nr + clp->skip - n, n); + clp->skip = n; + if (wlen == 0) + goto read; + } else if (rc == 0) + clp->skip = 0; + else + msgq(sp, M_ERR, "323|Invalid input. Truncated."); + break; + case INP_EOF: + evp->e_event = E_EOF; + break; + case INP_ERR: + evp->e_event = E_ERR; + break; + case INP_INTR: + goto retest; + case INP_TIMEOUT: + evp->e_event = E_TIMEOUT; + break; + default: + abort(); + } + return (0); +} + +/* + * cl_read -- + * Read characters from the input. + */ +static input_t +cl_read(SCR *sp, u_int32_t flags, char *bp, size_t blen, int *nrp, + struct timeval *tp) +{ + struct termios term1, term2; + CL_PRIVATE *clp; + GS *gp; + fd_set rdfd; + input_t rval; + int maxfd, nr, term_reset; + + gp = sp->gp; + clp = CLP(sp); + term_reset = 0; + + /* + * 1: A read from a file or a pipe. In this case, the reads + * never timeout regardless. This means that we can hang + * when trying to complete a map, but we're going to hang + * on the next read anyway. + */ + if (!F_ISSET(clp, CL_STDIN_TTY)) { + switch (nr = read(STDIN_FILENO, bp, blen)) { + case 0: + return (INP_EOF); + case -1: + goto err; + default: + *nrp = nr; + return (INP_OK); + } + /* NOTREACHED */ + } + + /* + * 2: A read with an associated timeout, e.g., trying to complete + * a map sequence. If input exists, we fall into #3. + */ + if (tp != NULL) { + FD_ZERO(&rdfd); + FD_SET(STDIN_FILENO, &rdfd); + switch (select(STDIN_FILENO + 1, &rdfd, NULL, NULL, tp)) { + case 0: + return (INP_TIMEOUT); + case -1: + goto err; + default: + break; + } + } + + /* + * The user can enter a key in the editor to quote a character. If we + * get here and the next key is supposed to be quoted, do what we can. + * Reset the tty so that the user can enter a ^C, ^Q, ^S. There's an + * obvious race here, when the key has already been entered, but there's + * nothing that we can do to fix that problem. + * + * The editor can ask for the next literal character even thought it's + * generally running in line-at-a-time mode. Do what we can. + */ + if (LF_ISSET(EC_QUOTED | EC_RAW) && !tcgetattr(STDIN_FILENO, &term1)) { + term_reset = 1; + if (LF_ISSET(EC_QUOTED)) { + term2 = term1; + term2.c_lflag &= ~ISIG; + term2.c_iflag &= ~(IXON | IXOFF); + (void)tcsetattr(STDIN_FILENO, + TCSASOFT | TCSADRAIN, &term2); + } else + (void)tcsetattr(STDIN_FILENO, + TCSASOFT | TCSADRAIN, &clp->vi_enter); + } + + /* + * 3: Wait for input. + * + * Select on the command input and scripting window file descriptors. + * It's ugly that we wait on scripting file descriptors here, but it's + * the only way to keep from locking out scripting windows. + */ + if (F_ISSET(gp, G_SCRWIN)) { +loop: FD_ZERO(&rdfd); + FD_SET(STDIN_FILENO, &rdfd); + maxfd = STDIN_FILENO; + if (F_ISSET(sp, SC_SCRIPT)) { + FD_SET(sp->script->sh_master, &rdfd); + if (sp->script->sh_master > maxfd) + maxfd = sp->script->sh_master; + } + switch (select(maxfd + 1, &rdfd, NULL, NULL, NULL)) { + case 0: + abort(); + case -1: + goto err; + default: + break; + } + if (!FD_ISSET(STDIN_FILENO, &rdfd)) { + if (sscr_input(sp)) + return (INP_ERR); + goto loop; + } + } + + /* + * 4: Read the input. + * + * !!! + * What's going on here is some scary stuff. Ex runs the terminal in + * canonical mode. So, the character terminating a line of + * input is returned in the buffer, but a trailing character is + * not similarly included. As ex uses 0 and ^ as autoindent + * commands, it has to see the trailing characters to determine + * the difference between the user entering "0ab" and "0ab". We + * leave an extra slot in the buffer, so that we can add a trailing + * character if the buffer isn't terminated by a . We + * lose if the buffer is too small for the line and exactly N characters + * are entered followed by an character. + */ +#define ONE_FOR_EOF 1 + switch (nr = read(STDIN_FILENO, bp, blen - ONE_FOR_EOF)) { + case 0: /* EOF. */ + /* + * ^D in canonical mode returns a read of 0, i.e. EOF. EOF is + * a valid command, but we don't want to loop forever because + * the terminal driver is returning EOF because the user has + * disconnected. The editor will almost certainly try to write + * something before this fires, which should kill us, but You + * Never Know. + */ + if (++clp->eof_count < 50) { + bp[0] = clp->orig.c_cc[VEOF]; + *nrp = 1; + rval = INP_OK; + + } else + rval = INP_EOF; + break; + case -1: /* Error or interrupt. */ +err: if (errno == EINTR) + rval = INP_INTR; + else { + rval = INP_ERR; + msgq(sp, M_SYSERR, "input"); + } + break; + default: /* Input characters. */ + if (F_ISSET(sp, SC_EX) && bp[nr - 1] != '\n') + bp[nr++] = clp->orig.c_cc[VEOF]; + *nrp = nr; + clp->eof_count = 0; + rval = INP_OK; + break; + } + + /* Restore the terminal state if it was modified. */ + if (term_reset) + (void)tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &term1); + return (rval); +} + +/* + * cl_resize -- + * Reset the options for a resize event. + */ +static int +cl_resize(SCR *sp, size_t lines, size_t columns) +{ + ARGS *argv[2], a, b; + CHAR_T b1[1024]; + + a.bp = b1; + b.bp = NULL; + a.len = b.len = 0; + argv[0] = &a; + argv[1] = &b; + + a.len = SPRINTF(b1, sizeof(b1), L("lines=%lu"), (u_long)lines); + if (opts_set(sp, argv, NULL)) + return (1); + a.len = SPRINTF(b1, sizeof(b1), L("columns=%lu"), (u_long)columns); + if (opts_set(sp, argv, NULL)) + return (1); + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/cl/cl_read.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/cl/cl_term.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/cl/cl_term.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/cl/cl_term.c (revision 366308) @@ -0,0 +1,492 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_TERM_H +#include +#endif +#include +#include + +#include "../common/common.h" +#include "cl.h" + +static int cl_pfmap(SCR *, seq_t, CHAR_T *, size_t, CHAR_T *, size_t); +static size_t atoz_or(const char *, size_t); + +/* + * XXX + * THIS REQUIRES THAT ALL SCREENS SHARE A TERMINAL TYPE. + */ +typedef struct _tklist { + char *ts; /* Key's termcap string. */ + char *output; /* Corresponding vi command. */ + char *name; /* Name. */ + u_char value; /* Special value (for lookup). */ +} TKLIST; +static TKLIST const c_tklist[] = { /* Command mappings. */ + {"kil1", "O", "insert line"}, + {"kdch1", "x", "delete character"}, + {"kcud1", "j", "cursor down"}, + {"kel", "D", "delete to eol"}, + {"kind", "\004", "scroll down"}, /* ^D */ + {"kll", "$", "go to eol"}, + {"kend", "$", "go to eol"}, + {"khome", "^", "go to sol"}, + {"kich1", "i", "insert at cursor"}, + {"kdl1", "dd", "delete line"}, + {"kcub1", "h", "cursor left"}, + {"knp", "\006", "page down"}, /* ^F */ + {"kpp", "\002", "page up"}, /* ^B */ + {"kri", "\025", "scroll up"}, /* ^U */ + {"ked", "dG", "delete to end of screen"}, + {"kcuf1", "l", "cursor right"}, + {"kcuu1", "k", "cursor up"}, + {NULL}, +}; +static TKLIST const m1_tklist[] = { /* Input mappings (lookup). */ + {NULL}, +}; +static TKLIST const m2_tklist[] = { /* Input mappings (set or delete). */ + {"kcud1", "\033ja", "cursor down"}, /* ^[ja */ + {"kcub1", "\033ha", "cursor left"}, /* ^[ha */ + {"kcuu1", "\033ka", "cursor up"}, /* ^[ka */ + {"kcuf1", "\033la", "cursor right"}, /* ^[la */ + {NULL}, +}; + +/* + * cl_term_init -- + * Initialize the special keys defined by the termcap/terminfo entry. + * + * PUBLIC: int cl_term_init(SCR *); + */ +int +cl_term_init(SCR *sp) +{ + KEYLIST *kp; + SEQ *qp; + TKLIST const *tkp; + char *t; + CHAR_T name[60]; + CHAR_T output[5]; + CHAR_T ts[20]; + CHAR_T *wp; + size_t wlen; + + /* Command mappings. */ + for (tkp = c_tklist; tkp->name != NULL; ++tkp) { + if ((t = tigetstr(tkp->ts)) == NULL || t == (char *)-1) + continue; + CHAR2INT(sp, tkp->name, strlen(tkp->name), wp, wlen); + MEMCPY(name, wp, wlen); + CHAR2INT(sp, t, strlen(t), wp, wlen); + MEMCPY(ts, wp, wlen); + CHAR2INT(sp, tkp->output, strlen(tkp->output), wp, wlen); + MEMCPY(output, wp, wlen); + if (seq_set(sp, name, strlen(tkp->name), ts, strlen(t), + output, strlen(tkp->output), SEQ_COMMAND, + SEQ_NOOVERWRITE | SEQ_SCREEN)) + return (1); + } + + /* Input mappings needing to be looked up. */ + for (tkp = m1_tklist; tkp->name != NULL; ++tkp) { + if ((t = tigetstr(tkp->ts)) == NULL || t == (char *)-1) + continue; + for (kp = keylist;; ++kp) + if (kp->value == tkp->value) + break; + if (kp == NULL) + continue; + CHAR2INT(sp, tkp->name, strlen(tkp->name), wp, wlen); + MEMCPY(name, wp, wlen); + CHAR2INT(sp, t, strlen(t), wp, wlen); + MEMCPY(ts, wp, wlen); + output[0] = (UCHAR_T)kp->ch; + if (seq_set(sp, name, strlen(tkp->name), ts, strlen(t), + output, 1, SEQ_INPUT, SEQ_NOOVERWRITE | SEQ_SCREEN)) + return (1); + } + + /* Input mappings that are already set or are text deletions. */ + for (tkp = m2_tklist; tkp->name != NULL; ++tkp) { + if ((t = tigetstr(tkp->ts)) == NULL || t == (char *)-1) + continue; + /* + * !!! + * Some terminals' keys send single + * characters. This is okay in command mapping, but not okay + * in input mapping. That combination is the only one we'll + * ever see, hopefully, so kluge it here for now. + */ + if (!strcmp(t, "\b")) + continue; + if (tkp->output == NULL) { + CHAR2INT(sp, tkp->name, strlen(tkp->name), wp, wlen); + MEMCPY(name, wp, wlen); + CHAR2INT(sp, t, strlen(t), wp, wlen); + MEMCPY(ts, wp, wlen); + if (seq_set(sp, name, strlen(tkp->name), + ts, strlen(t), NULL, 0, + SEQ_INPUT, SEQ_NOOVERWRITE | SEQ_SCREEN)) + return (1); + } else { + CHAR2INT(sp, tkp->name, strlen(tkp->name), wp, wlen); + MEMCPY(name, wp, wlen); + CHAR2INT(sp, t, strlen(t), wp, wlen); + MEMCPY(ts, wp, wlen); + CHAR2INT(sp, tkp->output, strlen(tkp->output), wp, wlen); + MEMCPY(output, wp, wlen); + if (seq_set(sp, name, strlen(tkp->name), + ts, strlen(t), output, strlen(tkp->output), + SEQ_INPUT, SEQ_NOOVERWRITE | SEQ_SCREEN)) + return (1); + } + } + + /* + * Rework any function key mappings that were set before the + * screen was initialized. + */ + SLIST_FOREACH(qp, sp->gp->seqq, q) + if (F_ISSET(qp, SEQ_FUNCMAP)) + (void)cl_pfmap(sp, qp->stype, + qp->input, qp->ilen, qp->output, qp->olen); + return (0); +} + +/* + * cl_term_end -- + * End the special keys defined by the termcap/terminfo entry. + * + * PUBLIC: int cl_term_end(GS *); + */ +int +cl_term_end(GS *gp) +{ + SEQ *qp, *nqp, *pre_qp = NULL; + + /* Delete screen specific mappings. */ + SLIST_FOREACH_SAFE(qp, gp->seqq, q, nqp) + if (F_ISSET(qp, SEQ_SCREEN)) { + if (qp == SLIST_FIRST(gp->seqq)) + SLIST_REMOVE_HEAD(gp->seqq, q); + else + SLIST_REMOVE_AFTER(pre_qp, q); + (void)seq_free(qp); + } else + pre_qp = qp; + return (0); +} + +/* + * cl_fmap -- + * Map a function key. + * + * PUBLIC: int cl_fmap(SCR *, seq_t, CHAR_T *, size_t, CHAR_T *, size_t); + */ +int +cl_fmap(SCR *sp, seq_t stype, CHAR_T *from, size_t flen, CHAR_T *to, size_t tlen) +{ + /* Ignore until the screen is running, do the real work then. */ + if (F_ISSET(sp, SC_VI) && !F_ISSET(sp, SC_SCR_VI)) + return (0); + if (F_ISSET(sp, SC_EX) && !F_ISSET(sp, SC_SCR_EX)) + return (0); + + return (cl_pfmap(sp, stype, from, flen, to, tlen)); +} + +/* + * cl_pfmap -- + * Map a function key (private version). + */ +static int +cl_pfmap(SCR *sp, seq_t stype, CHAR_T *from, size_t flen, CHAR_T *to, size_t tlen) +{ + size_t nlen; + char *p; + char name[64]; + CHAR_T keyname[64]; + CHAR_T ts[20]; + CHAR_T *wp; + size_t wlen; + + (void)snprintf(name, sizeof(name), "kf%d", + (int)STRTOL(from+1,NULL,10)); + if ((p = tigetstr(name)) == NULL || + p == (char *)-1 || strlen(p) == 0) + p = NULL; + if (p == NULL) { + msgq_wstr(sp, M_ERR, from, "233|This terminal has no %s key"); + return (1); + } + + nlen = SPRINTF(keyname, + SIZE(keyname), L("function key %d"), + (int)STRTOL(from+1,NULL,10)); + CHAR2INT(sp, p, strlen(p), wp, wlen); + MEMCPY(ts, wp, wlen); + return (seq_set(sp, keyname, nlen, + ts, strlen(p), to, tlen, stype, SEQ_NOOVERWRITE | SEQ_SCREEN)); +} + +/* + * cl_optchange -- + * Curses screen specific "option changed" routine. + * + * PUBLIC: int cl_optchange(SCR *, int, char *, u_long *); + */ +int +cl_optchange(SCR *sp, int opt, char *str, u_long *valp) +{ + CL_PRIVATE *clp; + + clp = CLP(sp); + + switch (opt) { + case O_TERM: + F_CLR(sp, SC_SCR_EX | SC_SCR_VI); + /* FALLTHROUGH */ + case O_COLUMNS: + case O_LINES: + /* + * Changing the terminal type requires that we reinitialize + * curses, while resizing does not. + */ + F_SET(sp->gp, G_SRESTART); + break; + case O_MESG: + (void)cl_omesg(sp, clp, *valp); + break; + case O_WINDOWNAME: + if (*valp) { + F_SET(clp, CL_RENAME_OK); + + /* + * If the screen is live, i.e. we're not reading the + * .exrc file, update the window. + */ + if (sp->frp != NULL && sp->frp->name != NULL) + (void)cl_rename(sp, sp->frp->name, 1); + } else { + F_CLR(clp, CL_RENAME_OK); + + (void)cl_rename(sp, NULL, 0); + } + break; + } + return (0); +} + +/* + * cl_omesg -- + * Turn the tty write permission on or off. + * + * PUBLIC: int cl_omesg(SCR *, CL_PRIVATE *, int); + */ +int +cl_omesg(SCR *sp, CL_PRIVATE *clp, int on) +{ + struct stat sb; + char *tty; + + /* Find the tty, get the current permissions. */ + if ((tty = ttyname(STDERR_FILENO)) == NULL) { + if (sp != NULL) + msgq(sp, M_SYSERR, "stderr"); + return (1); + } + if (stat(tty, &sb) < 0) { + if (sp != NULL) + msgq(sp, M_SYSERR, "%s", tty); + return (1); + } + + /* Save the original status if it's unknown. */ + if (clp->tgw == TGW_UNKNOWN) + clp->tgw = sb.st_mode & S_IWGRP ? TGW_SET : TGW_UNSET; + + /* Toggle the permissions. */ + if (on) { + if (chmod(tty, sb.st_mode | S_IWGRP) < 0) { + if (sp != NULL) + msgq(sp, M_SYSERR, + "046|messages not turned on: %s", tty); + return (1); + } + } else + if (chmod(tty, sb.st_mode & ~S_IWGRP) < 0) { + if (sp != NULL) + msgq(sp, M_SYSERR, + "045|messages not turned off: %s", tty); + return (1); + } + return (0); +} + +/* + * cl_ssize -- + * Return the terminal size. + * + * PUBLIC: int cl_ssize(SCR *, int, size_t *, size_t *, int *); + */ +int +cl_ssize(SCR *sp, int sigwinch, size_t *rowp, size_t *colp, int *changedp) +{ + struct winsize win; + size_t col, row; + int rval; + char *p; + + /* Assume it's changed. */ + if (changedp != NULL) + *changedp = 1; + + /* + * !!! + * sp may be NULL. + * + * Get the screen rows and columns. If the values are wrong, it's + * not a big deal -- as soon as the user sets them explicitly the + * environment will be set and the screen package will use the new + * values. + * + * Try TIOCGWINSZ. + */ + row = col = 0; + if (ioctl(STDERR_FILENO, TIOCGWINSZ, &win) != -1) { + row = win.ws_row; + col = win.ws_col; + } + /* If here because of suspend or a signal, only trust TIOCGWINSZ. */ + if (sigwinch) { + /* + * Somebody didn't get TIOCGWINSZ right, or has suspend + * without window resizing support. The user just lost, + * but there's nothing we can do. + */ + if (row == 0 || col == 0) { + if (changedp != NULL) + *changedp = 0; + return (0); + } + + /* + * SunOS systems deliver SIGWINCH when windows are uncovered + * as well as when they change size. In addition, we call + * here when continuing after being suspended since the window + * may have changed size. Since we don't want to background + * all of the screens just because the window was uncovered, + * ignore the signal if there's no change. + */ + if (sp != NULL && + row == O_VAL(sp, O_LINES) && col == O_VAL(sp, O_COLUMNS)) { + if (changedp != NULL) + *changedp = 0; + return (0); + } + + if (rowp != NULL) + *rowp = row; + if (colp != NULL) + *colp = col; + return (0); + } + + /* + * !!! + * If TIOCGWINSZ failed, or had entries of 0, try termcap. This + * routine is called before any termcap or terminal information + * has been set up. If there's no TERM environmental variable set, + * let it go, at least ex can run. + */ + if (row == 0 || col == 0) { + if ((p = getenv("TERM")) == NULL) + goto noterm; + if (row == 0) { + if ((rval = tigetnum("lines")) < 0) + msgq(sp, M_SYSERR, "tigetnum: lines"); + else + row = rval; + } + if (col == 0) { + if ((rval = tigetnum("cols")) < 0) + msgq(sp, M_SYSERR, "tigetnum: cols"); + else + col = rval; + } + } + + /* If nothing else, well, it's probably a VT100. */ +noterm: if (row == 0) + row = 24; + if (col == 0) + col = 80; + + /* + * !!! + * POSIX 1003.2 requires the environment to override everything. + * Often, people can get nvi to stop messing up their screen by + * deleting the LINES and COLUMNS environment variables from their + * dot-files. + */ + if ((p = getenv("LINES")) != NULL) + row = atoz_or(p, row); + if ((p = getenv("COLUMNS")) != NULL) + col = atoz_or(p, col); + + if (rowp != NULL) + *rowp = row; + if (colp != NULL) + *colp = col; + return (0); +} + +/* + * atoz_or -- + * Parse non-zero positive decimal with a fallback. + */ +static size_t +atoz_or(const char *s, size_t y) +{ + char *ep; + long x = strtol(s, &ep, 10); + + if (*ep == '\0' && (0 < x && x < INT_MAX)) + return (size_t)x; + else + return y; +} + +/* + * cl_putchar -- + * Function version of putchar, for tputs. + * + * PUBLIC: int cl_putchar(int); + */ +int +cl_putchar(int ch) +{ + return (putchar(ch)); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/cl/cl_term.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/cl/extern.h =================================================================== --- vendor/nvi/2.2.0-05ed8b9/cl/extern.h (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/cl/extern.h (revision 366308) @@ -0,0 +1,31 @@ +int cl_waddstr(SCR *, const CHAR_T *, size_t); +int cl_addstr(SCR *, const char *, size_t); +int cl_attr(SCR *, scr_attr_t, int); +int cl_baud(SCR *, u_long *); +int cl_bell(SCR *); +int cl_clrtoeol(SCR *); +int cl_cursor(SCR *, size_t *, size_t *); +int cl_deleteln(SCR *); +int cl_discard(SCR *, SCR **); +int cl_ex_adjust(SCR *, exadj_t); +int cl_insertln(SCR *); +int cl_keyval(SCR *, scr_keyval_t, CHAR_T *, int *); +int cl_move(SCR *, size_t, size_t); +int cl_refresh(SCR *, int); +int cl_rename(SCR *, char *, int); +void cl_setname(GS *, char *); +int cl_split(SCR *, SCR *); +int cl_suspend(SCR *, int *); +void cl_usage(void); +int sig_init(GS *, SCR *); +int cl_event(SCR *, EVENT *, u_int32_t, int); +int cl_screen(SCR *, u_int32_t); +int cl_quit(GS *); +int cl_getcap(SCR *, char *, char **); +int cl_term_init(SCR *); +int cl_term_end(GS *); +int cl_fmap(SCR *, seq_t, CHAR_T *, size_t, CHAR_T *, size_t); +int cl_optchange(SCR *, int, char *, u_long *); +int cl_omesg(SCR *, CL_PRIVATE *, int); +int cl_ssize(SCR *, int, size_t *, size_t *, int *); +int cl_putchar(int); Property changes on: vendor/nvi/2.2.0-05ed8b9/cl/extern.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/cl/README.signal =================================================================== --- vendor/nvi/2.2.0-05ed8b9/cl/README.signal (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/cl/README.signal (revision 366308) @@ -0,0 +1,172 @@ +There are six (normally) asynchronous actions about which vi cares: +SIGHUP, SIGINT, SIGQUIT, SIGTERM, SIGTSTP and SIGWINCH. + +The assumptions: + 1: The DB routines are not reentrant. + 2: The curses routines may not be reentrant. + 3: Neither DB nor curses will restart system calls. + +XXX +Note, most C library functions don't restart system calls. So, we should +*probably* start blocking around any imported function that we don't know +doesn't make a system call. This is going to be a genuine annoyance... + +SIGHUP, SIGTERM + Used for file recovery. The DB routines can't be reentered, nor + can they handle interrupted system calls, so the vi routines that + call DB block signals. This means that DB routines could be + called at interrupt time, if necessary. + +SIGQUIT + Disabled by the signal initialization routines. Historically, ^\ + switched vi into ex mode, and we continue that practice. + +SIGWINCH: + The interrupt routine sets a global bit which is checked by the + key-read routine, so there are no reentrancy issues. This means + that the screen will not resize until vi runs out of keys, but + that doesn't seem like a problem. + +SIGINT and SIGTSTP are a much more difficult issue to resolve. Vi has +to permit the user to interrupt long-running operations. Generally, a +search, substitution or read/write is done on a large file, or, the user +creates a key mapping with an infinite loop. This problem will become +worse as more complex semantics are added to vi, especially things like +making it a pure text widget. There are four major solutions on the table, +each of which have minor permutations. + +1: Run in raw mode. + + The up side is that there's no asynchronous behavior to worry about, + and obviously no reentrancy problems. The down side is that it's easy + to misinterpret characters (e.g. :w big_file^Mi^V^C is going to look + like an interrupt) and it's easy to get into places where we won't see + interrupt characters (e.g. ":map a ixx^[hxxaXXX" infinitely loops in + historic implementations of vi). Periodically reading the terminal + input buffer might solve the latter problem, but it's not going to be + pretty. + + Also, we're going to be checking for ^C's and ^Z's both, all over + the place -- I hate to litter the source code with that. For example, + the historic version of vi didn't permit you to suspend the screen if + you were on the colon command line. This isn't right. ^Z isn't a vi + command, it's a terminal event. (Dammit.) + +2: Run in cbreak mode. There are two problems in this area. First, the + current curses implementations (both System V and Berkeley) don't give + you clean cbreak modes. For example, the IEXTEN bit is left on, turning + on DISCARD and LNEXT. To clarify, what vi WANTS is 8-bit clean, with + the exception that flow control and signals are turned on, and curses + cbreak mode doesn't give you this. + + We can either set raw mode and twiddle the tty, or cbreak mode and + twiddle the tty. I chose to use raw mode, on the grounds that raw + mode is better defined and I'm less likely to be surprised by a curses + implementation down the road. The twiddling consists of setting ISIG, + IXON/IXOFF, and disabling some of the interrupt characters (see the + comments in cl_init.c). This is all found in historic System V (SVID + 3) and POSIX 1003.1-1992, so it should be fairly portable. + + The second problem is that vi permits you to enter literal signal + characters, e.g. ^V^C. There are two possible solutions. First, you + can turn off signals when you get a ^V, but that means that a network + packet containing ^V and ^C will lose, since the ^C may take effect + before vi reads the ^V. (This is particularly problematic if you're + talking over a protocol that recognizes signals locally and sends OOB + packets when it sees them.) Second, you can turn the ^C into a literal + character in vi, but that means that there's a race between entering + ^V^C, i.e. the sequence may end up being ^V^C. + Also, the second solution doesn't work for flow control characters, as + they aren't delivered to the program as signals. + + Generally, this is what historic vi did. (It didn't have the curses + problems because it didn't use curses.) It entered signals following + ^V characters into the input stream, (which is why there's no way to + enter a literal flow control character). + +3: Run in mostly raw mode; turn signals on when doing an operation the + user might want to interrupt, but leave them off most of the time. + + This works well for things like file reads and writes. This doesn't + work well for trying to detect infinite maps. The problem is that + you can write the code so that you don't have to turn on interrupts + per keystroke, but the code isn't pretty and it's hard to make sure + that an optimization doesn't cover up an infinite loop. This also + requires interaction or state between the vi parser and the key + reading routines, as an infinite loop may still be returning keys + to the parser. + + Also, if the user inserts an interrupt into the tty queue while the + interrupts are turned off, the key won't be treated as an interrupt, + and requiring the user to pound the keyboard to catch an interrupt + window is nasty. + +4: Run in mostly raw mode, leaving signals on all of the time. Done + by setting raw mode, and twiddling the tty's termios ISIG bit. + + This works well for the interrupt cases, because the code only has + to check to see if the interrupt flag has been set, and can otherwise + ignore signals. It's also less likely that we'll miss a case, and we + don't have to worry about synchronizing between the vi parser and the + key read routines. + + The down side is that we have to turn signals off if the user wants + to enter a literal character (e.g. ^V^C). If the user enters the + combination fast enough, or as part of a single network packet, + the text input routines will treat it as a signal instead of as a + literal character. To some extent, we have this problem already, + since we turn off flow control so that the user can enter literal + XON/XOFF characters. + + This is probably the easiest to code, and provides the smoothest + programming interface. + +There are a couple of other problems to consider. + +First, System V's curses doesn't handle SIGTSTP correctly. If you use the +newterm() interface, the TSTP signal will leave you in raw mode, and the +final endwin() will leave you in the correct shell mode. If you use the +initscr() interface, the TSTP signal will return you to the correct shell +mode, but the final endwin() will leave you in raw mode. There you have +it: proof that drug testing is not making any significant headway in the +computer industry. The 4BSD curses is deficient in that it does not have +an interface to the terminal keypad. So, regardless, we have to do our +own SIGTSTP handling. + +The problem with this is that if we do our own SIGTSTP handling, in either +models #3 or #4, we're going to have to call curses routines at interrupt +time, which means that we might be reentering curses, which is something we +don't want to do. + +Second, SIGTSTP has its own little problems. It's broadcast to the entire +process group, not sent to a single process. The scenario goes something +like this: the shell execs the mail program, which execs vi. The user hits +^Z, and all three programs get the signal, in some random order. The mail +program goes to sleep immediately (since it probably didn't have a SIGTSTP +handler in place). The shell gets a SIGCHLD, does a wait, and finds out +that the only child in its foreground process group (of which it's aware) +is asleep. It then optionally resets the terminal (because the modes aren't +how it left them), and starts prompting the user for input. The problem is +that somewhere in the middle of all of this, vi is resetting the terminal, +and getting ready to send a SIGTSTP to the process group in order to put +itself to sleep. There's a solution to all of this: when vi starts, it puts +itself into its own process group, and then only it (and possible child +processes) receive the SIGTSTP. This permits it to clean up the terminal +and switch back to the original process group, where it sends that process +group a SIGTSTP, putting everyone to sleep and waking the shell. + +Third, handing SIGTSTP asynchronously is further complicated by the child +processes vi may fork off. If vi calls ex, ex resets the terminal and +starts running some filter, and SIGTSTP stops them both, vi has to know +when it restarts that it can't repaint the screen until ex's child has +finished running. This is solveable, but it's annoying. + +Well, somebody had to make a decision, and this is the way it's going to be +(unless I get talked out of it). SIGINT is handled asynchronously, so +that we can pretty much guarantee that the user can interrupt any operation +at any time. SIGTSTP is handled synchronously, so that we don't have to +reenter curses and so that we don't have to play the process group games. +^Z is recognized in the standard text input and command modes. (^Z should +also be recognized during operations that may potentially take a long time. +The simplest solution is probably to twiddle the tty, install a handler for +SIGTSTP, and then restore normal tty modes when the operation is complete.) Property changes on: vendor/nvi/2.2.0-05ed8b9/cl/README.signal ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/cl/cl_funcs.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/cl/cl_funcs.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/cl/cl_funcs.c (revision 366308) @@ -0,0 +1,848 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#ifdef HAVE_TERM_H +#include +#endif +#include +#include + +#include "../common/common.h" +#include "../vi/vi.h" +#include "cl.h" + +static void cl_rdiv(SCR *); + +static int +addstr4(SCR *sp, void *str, size_t len, int wide) +{ + CL_PRIVATE *clp; + WINDOW *win; + size_t y, x; + int iv; + + clp = CLP(sp); + win = CLSP(sp) ? CLSP(sp) : stdscr; + + /* + * If ex isn't in control, it's the last line of the screen and + * it's a split screen, use inverse video. + */ + iv = 0; + getyx(win, y, x); + if (!F_ISSET(sp, SC_SCR_EXWROTE) && + y == RLNO(sp, LASTLINE(sp)) && IS_SPLIT(sp)) { + iv = 1; + (void)wstandout(win); + } + +#ifdef USE_WIDECHAR + if (wide) { + if (waddnwstr(win, str, len) == ERR) + return (1); + } else +#endif + if (waddnstr(win, str, len) == ERR) + return (1); + + if (iv) + (void)wstandend(win); + return (0); +} + +/* + * cl_waddstr -- + * Add len bytes from the string at the cursor, advancing the cursor. + * + * PUBLIC: int cl_waddstr(SCR *, const CHAR_T *, size_t); + */ +int +cl_waddstr(SCR *sp, const CHAR_T *str, size_t len) +{ + return addstr4(sp, (void *)str, len, 1); +} + +/* + * cl_addstr -- + * Add len bytes from the string at the cursor, advancing the cursor. + * + * PUBLIC: int cl_addstr(SCR *, const char *, size_t); + */ +int +cl_addstr(SCR *sp, const char *str, size_t len) +{ + return addstr4(sp, (void *)str, len, 0); +} + +/* + * cl_attr -- + * Toggle a screen attribute on/off. + * + * PUBLIC: int cl_attr(SCR *, scr_attr_t, int); + */ +int +cl_attr(SCR *sp, scr_attr_t attribute, int on) +{ + CL_PRIVATE *clp; + WINDOW *win; + + clp = CLP(sp); + win = CLSP(sp) ? CLSP(sp) : stdscr; + + switch (attribute) { + case SA_ALTERNATE: + /* + * !!! + * There's a major layering violation here. The problem is that the + * X11 xterm screen has what's known as an "alternate" screen. Some + * xterm termcap/terminfo entries include sequences to switch to/from + * that alternate screen as part of the ti/te (smcup/rmcup) strings. + * Vi runs in the alternate screen, so that you are returned to the + * same screen contents on exit from vi that you had when you entered + * vi. Further, when you run :shell, or :!date or similar ex commands, + * you also see the original screen contents. This wasn't deliberate + * on vi's part, it's just that it historically sent terminal init/end + * sequences at those times, and the addition of the alternate screen + * sequences to the strings changed the behavior of vi. The problem + * caused by this is that we don't want to switch back to the alternate + * screen while getting a new command from the user, when the user is + * continuing to enter ex commands, e.g.: + * + * :!date <<< switch to original screen + * [Hit return to continue] <<< prompt user to continue + * :command <<< get command from user + * + * Note that the :command input is a true vi input mode, e.g., input + * maps and abbreviations are being done. So, we need to be able to + * switch back into the vi screen mode, without flashing the screen. + * + * To make matters worse, the curses initscr() and endwin() calls will + * do this automatically -- so, this attribute isn't as controlled by + * the higher level screen as closely as one might like. + */ + if (on) { + if (clp->ti_te != TI_SENT) { + clp->ti_te = TI_SENT; + if (clp->smcup == NULL) + (void)cl_getcap(sp, "smcup", &clp->smcup); + if (clp->smcup != NULL) + (void)tputs(clp->smcup, 1, cl_putchar); + } + } else + if (clp->ti_te != TE_SENT) { + clp->ti_te = TE_SENT; + if (clp->rmcup == NULL) + (void)cl_getcap(sp, "rmcup", &clp->rmcup); + if (clp->rmcup != NULL) + (void)tputs(clp->rmcup, 1, cl_putchar); + (void)fflush(stdout); + } + (void)fflush(stdout); + break; + case SA_INVERSE: + if (F_ISSET(sp, SC_EX | SC_SCR_EXWROTE)) { + if (clp->smso == NULL) + return (1); + if (on) + (void)tputs(clp->smso, 1, cl_putchar); + else + (void)tputs(clp->rmso, 1, cl_putchar); + (void)fflush(stdout); + } else { + if (on) + (void)wstandout(win); + else + (void)wstandend(win); + } + break; + default: + abort(); + } + return (0); +} + +/* + * cl_baud -- + * Return the baud rate. + * + * PUBLIC: int cl_baud(SCR *, u_long *); + */ +int +cl_baud(SCR *sp, u_long *ratep) +{ + CL_PRIVATE *clp; + + /* + * XXX + * There's no portable way to get a "baud rate" -- cfgetospeed(3) + * returns the value associated with some #define, which we may + * never have heard of, or which may be a purely local speed. Vi + * only cares if it's SLOW (w300), slow (w1200) or fast (w9600). + * Try and detect the slow ones, and default to fast. + */ + clp = CLP(sp); + switch (cfgetospeed(&clp->orig)) { + case B50: + case B75: + case B110: + case B134: + case B150: + case B200: + case B300: + case B600: + *ratep = 600; + break; + case B1200: + *ratep = 1200; + break; + default: + *ratep = 9600; + break; + } + return (0); +} + +/* + * cl_bell -- + * Ring the bell/flash the screen. + * + * PUBLIC: int cl_bell(SCR *); + */ +int +cl_bell(SCR *sp) +{ + if (F_ISSET(sp, SC_EX | SC_SCR_EXWROTE | SC_SCR_EX)) + (void)write(STDOUT_FILENO, "\07", 1); /* \a */ + else { + /* + * Vi has an edit option which determines if the terminal + * should be beeped or the screen flashed. + */ + if (O_ISSET(sp, O_FLASH)) + (void)flash(); + else + (void)beep(); + } + return (0); +} + +/* + * cl_clrtoeol -- + * Clear from the current cursor to the end of the line. + * + * PUBLIC: int cl_clrtoeol(SCR *); + */ +int +cl_clrtoeol(SCR *sp) +{ + WINDOW *win; +#if 0 + size_t spcnt, y, x; +#endif + + win = CLSP(sp) ? CLSP(sp) : stdscr; + +#if 0 + if (IS_VSPLIT(sp)) { + /* The cursor must be returned to its original position. */ + getyx(win, y, x); + for (spcnt = (sp->coff + sp->cols) - x; spcnt > 0; --spcnt) + (void)waddch(win, ' '); + (void)wmove(win, y, x); + return (0); + } else +#endif + return (wclrtoeol(win) == ERR); +} + +/* + * cl_cursor -- + * Return the current cursor position. + * + * PUBLIC: int cl_cursor(SCR *, size_t *, size_t *); + */ +int +cl_cursor(SCR *sp, size_t *yp, size_t *xp) +{ + WINDOW *win; + win = CLSP(sp) ? CLSP(sp) : stdscr; + /* + * The curses screen support splits a single underlying curses screen + * into multiple screens to support split screen semantics. For this + * reason the returned value must be adjusted to be relative to the + * current screen, and not absolute. Screens that implement the split + * using physically distinct screens won't need this hack. + */ + getyx(win, *yp, *xp); + /* + *yp -= sp->roff; + *xp -= sp->coff; + */ + return (0); +} + +/* + * cl_deleteln -- + * Delete the current line, scrolling all lines below it. + * + * PUBLIC: int cl_deleteln(SCR *); + */ +int +cl_deleteln(SCR *sp) +{ + CL_PRIVATE *clp; + WINDOW *win; + size_t y, x; + + clp = CLP(sp); + win = CLSP(sp) ? CLSP(sp) : stdscr; + + /* + * This clause is required because the curses screen uses reverse + * video to delimit split screens. If the screen does not do this, + * this code won't be necessary. + * + * If the bottom line was in reverse video, rewrite it in normal + * video before it's scrolled. + */ + if (!F_ISSET(sp, SC_SCR_EXWROTE) && IS_SPLIT(sp)) { + getyx(win, y, x); + mvwchgat(win, RLNO(sp, LASTLINE(sp)), 0, -1, A_NORMAL, 0, NULL); + (void)wmove(win, y, x); + } + + /* + * The bottom line is expected to be blank after this operation, + * and other screens must support that semantic. + */ + return (wdeleteln(win) == ERR); +} + +/* + * cl_discard -- + * Discard a screen. + * + * PUBLIC: int cl_discard(SCR *, SCR **); + */ +int +cl_discard(SCR *discardp, SCR **acquirep) +{ + CL_PRIVATE *clp; + SCR* tsp; + + if (discardp) { + clp = CLP(discardp); + F_SET(clp, CL_LAYOUT); + + if (CLSP(discardp)) { + delwin(CLSP(discardp)); + discardp->cl_private = NULL; + } + } + + /* no screens got a piece; we're done */ + if (!acquirep) + return 0; + + for (; (tsp = *acquirep) != NULL; ++acquirep) { + clp = CLP(tsp); + F_SET(clp, CL_LAYOUT); + + if (CLSP(tsp)) + delwin(CLSP(tsp)); + tsp->cl_private = subwin(stdscr, tsp->rows, tsp->cols, + tsp->roff, tsp->coff); + } + + /* discardp is going away, acquirep is taking up its space. */ + return (0); +} + +/* + * cl_ex_adjust -- + * Adjust the screen for ex. This routine is purely for standalone + * ex programs. All special purpose, all special case. + * + * PUBLIC: int cl_ex_adjust(SCR *, exadj_t); + */ +int +cl_ex_adjust(SCR *sp, exadj_t action) +{ + CL_PRIVATE *clp; + int cnt; + + clp = CLP(sp); + switch (action) { + case EX_TERM_SCROLL: + /* Move the cursor up one line if that's possible. */ + if (clp->cuu1 != NULL) + (void)tputs(clp->cuu1, 1, cl_putchar); + else if (clp->cup != NULL) + (void)tputs(tgoto(clp->cup, + 0, LINES - 2), 1, cl_putchar); + else + return (0); + /* FALLTHROUGH */ + case EX_TERM_CE: + /* Clear the line. */ + if (clp->el != NULL) { + (void)putchar('\r'); + (void)tputs(clp->el, 1, cl_putchar); + } else { + /* + * Historically, ex didn't erase the line, so, if the + * displayed line was only a single glyph, and + * was more than one glyph, the output would not fully + * overwrite the user's input. To fix this, output + * the maxiumum character number of spaces. Note, + * this won't help if the user entered extra prompt + * or characters before the command character. + * We'd have to do a lot of work to make that work, and + * it's almost certainly not worth the effort. + */ + for (cnt = 0; cnt < MAX_CHARACTER_COLUMNS; ++cnt) + (void)putchar('\b'); + for (cnt = 0; cnt < MAX_CHARACTER_COLUMNS; ++cnt) + (void)putchar(' '); + (void)putchar('\r'); + (void)fflush(stdout); + } + break; + default: + abort(); + } + return (0); +} + +/* + * cl_insertln -- + * Push down the current line, discarding the bottom line. + * + * PUBLIC: int cl_insertln(SCR *); + */ +int +cl_insertln(SCR *sp) +{ + WINDOW *win; + win = CLSP(sp) ? CLSP(sp) : stdscr; + /* + * The current line is expected to be blank after this operation, + * and the screen must support that semantic. + */ + return (winsertln(win) == ERR); +} + +/* + * cl_keyval -- + * Return the value for a special key. + * + * PUBLIC: int cl_keyval(SCR *, scr_keyval_t, CHAR_T *, int *); + */ +int +cl_keyval(SCR *sp, scr_keyval_t val, CHAR_T *chp, int *dnep) +{ + CL_PRIVATE *clp; + + /* + * VEOF, VERASE and VKILL are required by POSIX 1003.1-1990, + * VWERASE is a 4BSD extension. + */ + clp = CLP(sp); + switch (val) { + case KEY_VEOF: + *dnep = (*chp = clp->orig.c_cc[VEOF]) == _POSIX_VDISABLE; + break; + case KEY_VERASE: + *dnep = (*chp = clp->orig.c_cc[VERASE]) == _POSIX_VDISABLE; + break; + case KEY_VKILL: + *dnep = (*chp = clp->orig.c_cc[VKILL]) == _POSIX_VDISABLE; + break; +#ifdef VWERASE + case KEY_VWERASE: + *dnep = (*chp = clp->orig.c_cc[VWERASE]) == _POSIX_VDISABLE; + break; +#endif + default: + *dnep = 1; + break; + } + return (0); +} + +/* + * cl_move -- + * Move the cursor. + * + * PUBLIC: int cl_move(SCR *, size_t, size_t); + */ +int +cl_move(SCR *sp, size_t lno, size_t cno) +{ + WINDOW *win; + win = CLSP(sp) ? CLSP(sp) : stdscr; + /* See the comment in cl_cursor. */ + if (wmove(win, RLNO(sp, lno), RCNO(sp, cno)) == ERR) { + msgq(sp, M_ERR, "Error: move: l(%zu + %zu) c(%zu + %zu)", + lno, sp->roff, cno, sp->coff); + return (1); + } + return (0); +} + +/* + * cl_refresh -- + * Refresh the screen. + * + * PUBLIC: int cl_refresh(SCR *, int); + */ +int +cl_refresh(SCR *sp, int repaint) +{ + GS *gp; + CL_PRIVATE *clp; + WINDOW *win; + SCR *psp, *tsp; + size_t y, x; + + gp = sp->gp; + clp = CLP(sp); + win = CLSP(sp) ? CLSP(sp) : stdscr; + + /* + * If we received a killer signal, we're done, there's no point + * in refreshing the screen. + */ + if (clp->killersig) + return (0); + + /* + * If repaint is set, the editor is telling us that we don't know + * what's on the screen, so we have to repaint from scratch. + * + * If repaint set or the screen layout changed, we need to redraw + * any lines separating vertically split screens. If the horizontal + * offsets are the same, then the split was vertical, and need to + * draw a dividing line. + */ + if (repaint || F_ISSET(clp, CL_LAYOUT)) { + getyx(stdscr, y, x); + for (psp = sp; psp != NULL; psp = TAILQ_NEXT(psp, q)) + for (tsp = TAILQ_NEXT(psp, q); tsp != NULL; + tsp = TAILQ_NEXT(tsp, q)) + if (psp->roff == tsp->roff) { + if (psp->coff + psp->cols + 1 == tsp->coff) + cl_rdiv(psp); + else + if (tsp->coff + tsp->cols + 1 == psp->coff) + cl_rdiv(tsp); + } + (void)wmove(stdscr, y, x); + F_CLR(clp, CL_LAYOUT); + } + + /* + * In the curses library, doing wrefresh(curscr) is okay, but the + * screen flashes when we then apply the refresh() to bring it up + * to date. So, use clearok(). + */ + if (repaint) + clearok(curscr, 1); + /* + * Only do an actual refresh, when this is the focus window, + * i.e. the one holding the cursor. This assumes that refresh + * is called for that window after refreshing the others. + * This prevents the cursor being drawn in the other windows. + */ + return (wnoutrefresh(stdscr) == ERR || + wnoutrefresh(win) == ERR || + (sp == clp->focus && doupdate() == ERR)); +} + +/* + * cl_rdiv -- + * Draw a dividing line between two vertically split screens. + */ +static void +cl_rdiv(SCR *sp) +{ +#ifdef __NetBSD__ + mvvline(sp->roff, sp->cols + sp->coff, '|', sp->rows); +#else + mvvline(sp->roff, sp->cols + sp->coff, ACS_VLINE, sp->rows); +#endif +} + +/* + * cl_rename -- + * Rename the file. + * + * PUBLIC: int cl_rename(SCR *, char *, int); + */ +int +cl_rename(SCR *sp, char *name, int on) +{ + GS *gp; + CL_PRIVATE *clp; + FILE *pfp; + char buf[256], *s, *e; + char * wid; + char cmd[64]; + + gp = sp->gp; + clp = CLP(sp); + + /* + * XXX + * We can only rename windows for xterm. + */ + if (on) { + clp->focus = sp; + if (!F_ISSET(clp, CL_RENAME_OK) || + strncmp(OG_STR(gp, GO_TERM), "xterm", 5)) + return (0); + + if (clp->oname == NULL && (wid = getenv("WINDOWID"))) { + snprintf(cmd, sizeof(cmd), "xprop -id %s WM_NAME", wid); + if ((pfp = popen(cmd, "r")) == NULL) + goto rename; + if (fgets(buf, sizeof(buf), pfp) == NULL) { + pclose(pfp); + goto rename; + } + pclose(pfp); + if ((s = strchr(buf, '"')) != NULL && + (e = strrchr(buf, '"')) != NULL) + clp->oname = strndup(s + 1, e - s - 1); + } + +rename: cl_setname(gp, name); + + F_SET(clp, CL_RENAME); + } else + if (F_ISSET(clp, CL_RENAME)) { + cl_setname(gp, clp->oname); + + F_CLR(clp, CL_RENAME); + } + return (0); +} + +/* + * cl_setname -- + * Set a X11 icon/window name. + * + * PUBLIC: void cl_setname(GS *, char *); + */ +void +cl_setname(GS *gp, char *name) +{ +/* X11 xterm escape sequence to rename the icon/window. */ +#define XTERM_RENAME "\033]0;%s\007" + + (void)printf(XTERM_RENAME, name == NULL ? OG_STR(gp, GO_TERM) : name); + (void)fflush(stdout); +#undef XTERM_RENAME +} + +/* + * cl_split -- + * Split a screen. + * + * PUBLIC: int cl_split(SCR *, SCR *); + */ +int +cl_split(SCR *origp, SCR *newp) +{ + CL_PRIVATE *clp; + + clp = CLP(origp); + F_SET(clp, CL_LAYOUT); + + if (CLSP(origp)) + delwin(CLSP(origp)); + + origp->cl_private = subwin(stdscr, origp->rows, origp->cols, + origp->roff, origp->coff); + newp->cl_private = subwin(stdscr, newp->rows, newp->cols, + newp->roff, newp->coff); + + /* origp is the original screen, giving up space to newp. */ + return (0); +} + +/* + * cl_suspend -- + * Suspend a screen. + * + * PUBLIC: int cl_suspend(SCR *, int *); + */ +int +cl_suspend(SCR *sp, int *allowedp) +{ + struct termios t; + CL_PRIVATE *clp; + WINDOW *win; + GS *gp; + size_t y, x; + int changed; + + gp = sp->gp; + clp = CLP(sp); + win = CLSP(sp) ? CLSP(sp) : stdscr; + *allowedp = 1; + + /* + * The ex implementation of this function isn't needed by screens not + * supporting ex commands that require full terminal canonical mode + * (e.g. :suspend). + * + * The vi implementation of this function isn't needed by screens not + * supporting vi process suspension, i.e. any screen that isn't backed + * by a UNIX shell. + * + * Setting allowedp to 0 will cause the editor to reject the command. + */ + if (F_ISSET(sp, SC_EX)) { + /* Save the terminal settings, and restore the original ones. */ + if (F_ISSET(clp, CL_STDIN_TTY)) { + (void)tcgetattr(STDIN_FILENO, &t); + (void)tcsetattr(STDIN_FILENO, + TCSASOFT | TCSADRAIN, &clp->orig); + } + + /* Stop the process group. */ + (void)kill(0, SIGTSTP); + + /* Time passes ... */ + + /* Restore terminal settings. */ + if (F_ISSET(clp, CL_STDIN_TTY)) + (void)tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &t); + return (0); + } + + /* + * Move to the lower left-hand corner of the screen. + * + * XXX + * Not sure this is necessary in System V implementations, but it + * shouldn't hurt. + */ + getyx(win, y, x); + (void)wmove(win, LINES - 1, 0); + (void)wrefresh(win); + + /* + * Temporarily end the screen. System V introduced a semantic where + * endwin() could be restarted. We use it because restarting curses + * from scratch often fails in System V. 4BSD curses didn't support + * restarting after endwin(), so we have to do what clean up we can + * without calling it. + */ + /* Save the terminal settings. */ + (void)tcgetattr(STDIN_FILENO, &t); + + /* Restore the cursor keys to normal mode. */ + (void)keypad(stdscr, FALSE); + + /* Restore the window name. */ + (void)cl_rename(sp, NULL, 0); + + (void)endwin(); + + /* + * XXX + * Restore the original terminal settings. This is bad -- the + * reset can cause character loss from the tty queue. However, + * we can't call endwin() in BSD curses implementations, and too + * many System V curses implementations don't get it right. + */ + (void)tcsetattr(STDIN_FILENO, TCSADRAIN | TCSASOFT, &clp->orig); + + /* Stop the process group. */ + (void)kill(0, SIGTSTP); + + /* Time passes ... */ + + /* + * If we received a killer signal, we're done. Leave everything + * unchanged. In addition, the terminal has already been reset + * correctly, so leave it alone. + */ + if (clp->killersig) { + F_CLR(clp, CL_SCR_EX_INIT | CL_SCR_VI_INIT); + return (0); + } + + /* Restore terminal settings. */ + wrefresh(win); /* Needed on SunOs/Solaris ? */ + if (F_ISSET(clp, CL_STDIN_TTY)) + (void)tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &t); + + /* Set the window name. */ + (void)cl_rename(sp, sp->frp->name, 1); + + /* Put the cursor keys into application mode. */ + (void)keypad(stdscr, TRUE); + + /* Refresh and repaint the screen. */ + (void)wmove(win, y, x); + (void)cl_refresh(sp, 1); + + /* If the screen changed size, set the SIGWINCH bit. */ + if (cl_ssize(sp, 1, NULL, NULL, &changed)) + return (1); + if (changed) + F_SET(CLP(sp), CL_SIGWINCH); + + return (0); +} + +/* + * cl_usage -- + * Print out the curses usage messages. + * + * PUBLIC: void cl_usage(void); + */ +void +cl_usage(void) +{ +#define USAGE "\ +usage: ex [-eFRrSsv] [-c command] [-t tag] [-w size] [file ...]\n\ +usage: vi [-eFlRrSv] [-c command] [-t tag] [-w size] [file ...]\n" + (void)fprintf(stderr, "%s", USAGE); +#undef USAGE +} + +#ifdef DEBUG +/* + * gdbrefresh -- + * Stub routine so can flush out curses screen changes using gdb. + */ +static int + __attribute__((unused)) +gdbrefresh(void) +{ + refresh(); + return (0); /* XXX Convince gdb to run it. */ +} +#endif Property changes on: vendor/nvi/2.2.0-05ed8b9/cl/cl_funcs.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/cl/cl_main.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/cl/cl_main.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/cl/cl_main.c (revision 366308) @@ -0,0 +1,391 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_TERM_H +#include +#endif +#include +#include + +#include "../common/common.h" +#include "cl.h" +#include "pathnames.h" + +GS *__global_list; /* GLOBAL: List of screens. */ +sigset_t __sigblockset; /* GLOBAL: Blocked signals. */ + +static void cl_func_std(GS *); +static CL_PRIVATE *cl_init(GS *); +static GS *gs_init(void); +static int setsig(int, struct sigaction *, void (*)(int)); +static void sig_end(GS *); +static void term_init(char *); + +/* + * main -- + * This is the main loop for the standalone curses editor. + */ +int +main(int argc, char *argv[]) +{ + static int reenter; + CL_PRIVATE *clp; + GS *gp; + size_t rows, cols; + int rval; + char **p_av, **t_av, *ttype; + + /* If loaded at 0 and jumping through a NULL pointer, stop. */ + if (reenter++) + abort(); + + /* Create and initialize the global structure. */ + __global_list = gp = gs_init(); + + /* + * Strip out any arguments that vi isn't going to understand. There's + * no way to portably call getopt twice, so arguments parsed here must + * be removed from the argument list. + */ + for (p_av = t_av = argv;;) { + if (*t_av == NULL) { + *p_av = NULL; + break; + } + if (!strcmp(*t_av, "--")) { + while ((*p_av++ = *t_av++) != NULL); + break; + } + *p_av++ = *t_av++; + } + + /* Create and initialize the CL_PRIVATE structure. */ + clp = cl_init(gp); + + /* + * Initialize the terminal information. + * + * We have to know what terminal it is from the start, since we may + * have to use termcap/terminfo to find out how big the screen is. + */ + if ((ttype = getenv("TERM")) == NULL) + ttype = "ansi"; + term_init(ttype); + + /* Add the terminal type to the global structure. */ + if ((OG_D_STR(gp, GO_TERM) = + OG_STR(gp, GO_TERM) = strdup(ttype)) == NULL) + err(1, NULL); + + /* Figure out how big the screen is. */ + if (cl_ssize(NULL, 0, &rows, &cols, NULL)) + exit (1); + + /* Add the rows and columns to the global structure. */ + OG_VAL(gp, GO_LINES) = OG_D_VAL(gp, GO_LINES) = rows; + OG_VAL(gp, GO_COLUMNS) = OG_D_VAL(gp, GO_COLUMNS) = cols; + + /* Ex wants stdout to be buffered. */ + (void)setvbuf(stdout, NULL, _IOFBF, 0); + + /* Start catching signals. */ + if (sig_init(gp, NULL)) + exit (1); + + /* Run ex/vi. */ + rval = editor(gp, argc, argv); + + /* Clean up signals. */ + sig_end(gp); + + /* Clean up the terminal. */ + (void)cl_quit(gp); + + /* + * XXX + * Reset the O_MESG option. + */ + if (clp->tgw != TGW_UNKNOWN) + (void)cl_omesg(NULL, clp, clp->tgw == TGW_SET); + + /* + * XXX + * Reset the X11 xterm icon/window name. + */ + if (F_ISSET(clp, CL_RENAME)) + cl_setname(gp, clp->oname); + + /* If a killer signal arrived, pretend we just got it. */ + if (clp->killersig) { + (void)signal(clp->killersig, SIG_DFL); + (void)kill(getpid(), clp->killersig); + /* NOTREACHED */ + } + + /* Free the global and CL private areas. */ +#if defined(DEBUG) || defined(PURIFY) + free(clp->oname); + free(clp); + free(OG_STR(gp, GO_TERM)); + free(gp); +#endif + + exit (rval); +} + +/* + * gs_init -- + * Create and partially initialize the GS structure. + */ +static GS * +gs_init(void) +{ + GS *gp; + + gp = calloc(1, sizeof(GS)); + if (gp == NULL) + err(1, NULL); + + return (gp); +} + +/* + * cl_init -- + * Create and partially initialize the CL structure. + */ +static CL_PRIVATE * +cl_init(GS *gp) +{ + CL_PRIVATE *clp; + int fd; + + clp = calloc(1, sizeof(CL_PRIVATE)); + if (clp == NULL) + err(1, NULL); + gp->cl_private = clp; + + /* + * Set the CL_STDIN_TTY flag. It's purpose is to avoid setting + * and resetting the tty if the input isn't from there. We also + * use the same test to determine if we're running a script or + * not. + */ + if (isatty(STDIN_FILENO)) + F_SET(clp, CL_STDIN_TTY); + else + F_SET(gp, G_SCRIPTED); + + /* + * We expect that if we've lost our controlling terminal that the + * open() (but not the tcgetattr()) will fail. + */ + if (F_ISSET(clp, CL_STDIN_TTY)) { + if (tcgetattr(STDIN_FILENO, &clp->orig) == -1) + goto tcfail; + } else if ((fd = open(_PATH_TTY, O_RDONLY, 0)) != -1) { + if (tcgetattr(fd, &clp->orig) == -1) { +tcfail: err(1, "tcgetattr"); + exit (1); + } + (void)close(fd); + } + + /* Initialize the list of curses functions. */ + cl_func_std(gp); + + return (clp); +} + +/* + * term_init -- + * Initialize terminal information. + */ +static void +term_init(char *ttype) +{ + int err; + + /* Set up the terminal database information. */ + setupterm(ttype, STDOUT_FILENO, &err); + switch (err) { + case -1: + errx(1, "No terminal database found"); + case 0: + errx(1, "%s: unknown terminal type", ttype); + } +} + +#define GLOBAL_CLP \ + CL_PRIVATE *clp = GCLP(__global_list); +static void +h_hup(int signo) +{ + GLOBAL_CLP; + + F_SET(clp, CL_SIGHUP); + clp->killersig = SIGHUP; +} + +static void +h_int(int signo) +{ + GLOBAL_CLP; + + F_SET(clp, CL_SIGINT); +} + +static void +h_term(int signo) +{ + GLOBAL_CLP; + + F_SET(clp, CL_SIGTERM); + clp->killersig = SIGTERM; +} + +static void +h_winch(int signo) +{ + GLOBAL_CLP; + + F_SET(clp, CL_SIGWINCH); +} +#undef GLOBAL_CLP + +/* + * sig_init -- + * Initialize signals. + * + * PUBLIC: int sig_init(GS *, SCR *); + */ +int +sig_init(GS *gp, SCR *sp) +{ + CL_PRIVATE *clp; + + clp = GCLP(gp); + + if (sp == NULL) { + (void)sigemptyset(&__sigblockset); + if (sigaddset(&__sigblockset, SIGHUP) || + setsig(SIGHUP, &clp->oact[INDX_HUP], h_hup) || + sigaddset(&__sigblockset, SIGINT) || + setsig(SIGINT, &clp->oact[INDX_INT], h_int) || + sigaddset(&__sigblockset, SIGTERM) || + setsig(SIGTERM, &clp->oact[INDX_TERM], h_term) +#ifdef SIGWINCH + || + sigaddset(&__sigblockset, SIGWINCH) || + setsig(SIGWINCH, &clp->oact[INDX_WINCH], h_winch) +#endif + ) { + err(1, NULL); + return (1); + } + } else + if (setsig(SIGHUP, NULL, h_hup) || + setsig(SIGINT, NULL, h_int) || + setsig(SIGTERM, NULL, h_term) +#ifdef SIGWINCH + || + setsig(SIGWINCH, NULL, h_winch) +#endif + ) { + msgq(sp, M_SYSERR, "signal-reset"); + } + return (0); +} + +/* + * setsig -- + * Set a signal handler. + */ +static int +setsig(int signo, struct sigaction *oactp, void (*handler)(int)) +{ + struct sigaction act; + + /* + * Use sigaction(2), not signal(3), since we don't always want to + * restart system calls. The example is when waiting for a command + * mode keystroke and SIGWINCH arrives. Besides, you can't portably + * restart system calls (thanks, POSIX!). + */ + act.sa_handler = handler; + sigemptyset(&act.sa_mask); + + act.sa_flags = 0; + return (sigaction(signo, &act, oactp)); +} + +/* + * sig_end -- + * End signal setup. + */ +static void +sig_end(GS *gp) +{ + CL_PRIVATE *clp; + + clp = GCLP(gp); + (void)sigaction(SIGHUP, NULL, &clp->oact[INDX_HUP]); + (void)sigaction(SIGINT, NULL, &clp->oact[INDX_INT]); + (void)sigaction(SIGTERM, NULL, &clp->oact[INDX_TERM]); +#ifdef SIGWINCH + (void)sigaction(SIGWINCH, NULL, &clp->oact[INDX_WINCH]); +#endif +} + +/* + * cl_func_std -- + * Initialize the standard curses functions. + */ +static void +cl_func_std(GS *gp) +{ + gp->scr_addstr = cl_addstr; + gp->scr_waddstr = cl_waddstr; + gp->scr_attr = cl_attr; + gp->scr_baud = cl_baud; + gp->scr_bell = cl_bell; + gp->scr_busy = NULL; + gp->scr_child = NULL; + gp->scr_clrtoeol = cl_clrtoeol; + gp->scr_cursor = cl_cursor; + gp->scr_deleteln = cl_deleteln; + gp->scr_reply = NULL; + gp->scr_discard = cl_discard; + gp->scr_event = cl_event; + gp->scr_ex_adjust = cl_ex_adjust; + gp->scr_fmap = cl_fmap; + gp->scr_insertln = cl_insertln; + gp->scr_keyval = cl_keyval; + gp->scr_move = cl_move; + gp->scr_msg = NULL; + gp->scr_optchange = cl_optchange; + gp->scr_refresh = cl_refresh; + gp->scr_rename = cl_rename; + gp->scr_screen = cl_screen; + gp->scr_split = cl_split; + gp->scr_suspend = cl_suspend; + gp->scr_usage = cl_usage; +} Property changes on: vendor/nvi/2.2.0-05ed8b9/cl/cl_main.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/cl/cl_screen.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/cl/cl_screen.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/cl/cl_screen.c (revision 366308) @@ -0,0 +1,570 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#ifdef HAVE_TERM_H +#include +#endif +#include +#include + +#include "../common/common.h" +#include "cl.h" + +static int cl_ex_end(GS *); +static int cl_ex_init(SCR *); +static void cl_freecap(CL_PRIVATE *); +static int cl_vi_end(GS *); +static int cl_vi_init(SCR *); +static int cl_putenv(char *, char *, u_long); + +/* + * cl_screen -- + * Switch screen types. + * + * PUBLIC: int cl_screen(SCR *, u_int32_t); + */ +int +cl_screen(SCR *sp, u_int32_t flags) +{ + CL_PRIVATE *clp; + WINDOW *win; + GS *gp; + + gp = sp->gp; + clp = CLP(sp); + win = CLSP(sp) ? CLSP(sp) : stdscr; + + /* See if the current information is incorrect. */ + if (F_ISSET(gp, G_SRESTART)) { + if ((!F_ISSET(sp, SC_SCR_EX | SC_SCR_VI) || + resizeterm(O_VAL(sp, O_LINES), O_VAL(sp, O_COLUMNS))) && + cl_quit(gp)) + return (1); + F_CLR(gp, G_SRESTART); + } + + /* See if we're already in the right mode. */ + if ((LF_ISSET(SC_EX) && F_ISSET(sp, SC_SCR_EX)) || + (LF_ISSET(SC_VI) && F_ISSET(sp, SC_SCR_VI))) + return (0); + + /* + * Fake leaving ex mode. + * + * We don't actually exit ex or vi mode unless forced (e.g. by a window + * size change). This is because many curses implementations can't be + * called twice in a single program. Plus, it's faster. If the editor + * "leaves" vi to enter ex, when it exits ex we'll just fall back into + * vi. + */ + if (F_ISSET(sp, SC_SCR_EX)) + F_CLR(sp, SC_SCR_EX); + + /* + * Fake leaving vi mode. + * + * Clear out the rest of the screen if we're in the middle of a split + * screen. Move to the last line in the current screen -- this makes + * terminal scrolling happen naturally. Note: *don't* move past the + * end of the screen, as there are ex commands (e.g., :read ! cat file) + * that don't want to. Don't clear the info line, its contents may be + * valid, e.g. :file|append. + */ + if (F_ISSET(sp, SC_SCR_VI)) { + F_CLR(sp, SC_SCR_VI); + + if (TAILQ_NEXT(sp, q) != NULL) { + (void)wmove(win, RLNO(sp, sp->rows), 0); + wclrtobot(win); + } + (void)wmove(win, RLNO(sp, sp->rows) - 1, 0); + wrefresh(win); + } + + /* Enter the requested mode. */ + if (LF_ISSET(SC_EX)) { + if (cl_ex_init(sp)) + return (1); + F_SET(clp, CL_IN_EX | CL_SCR_EX_INIT); + + /* + * If doing an ex screen for ex mode, move to the last line + * on the screen. + */ + if (F_ISSET(sp, SC_EX) && clp->cup != NULL) + tputs(tgoto(clp->cup, + 0, O_VAL(sp, O_LINES) - 1), 1, cl_putchar); + } else { + if (cl_vi_init(sp)) + return (1); + F_CLR(clp, CL_IN_EX); + F_SET(clp, CL_SCR_VI_INIT); + } + return (0); +} + +/* + * cl_quit -- + * Shutdown the screens. + * + * PUBLIC: int cl_quit(GS *); + */ +int +cl_quit(GS *gp) +{ + CL_PRIVATE *clp; + int rval; + + rval = 0; + clp = GCLP(gp); + + /* + * If we weren't really running, ignore it. This happens if the + * screen changes size before we've called curses. + */ + if (!F_ISSET(clp, CL_SCR_EX_INIT | CL_SCR_VI_INIT)) + return (0); + + /* Clean up the terminal mappings. */ + if (cl_term_end(gp)) + rval = 1; + + /* Really leave vi mode. */ + if (F_ISSET(clp, CL_STDIN_TTY) && + F_ISSET(clp, CL_SCR_VI_INIT) && cl_vi_end(gp)) + rval = 1; + + /* Really leave ex mode. */ + if (F_ISSET(clp, CL_STDIN_TTY) && + F_ISSET(clp, CL_SCR_EX_INIT) && cl_ex_end(gp)) + rval = 1; + + /* + * If we were running ex when we quit, or we're using an implementation + * of curses where endwin() doesn't get this right, restore the original + * terminal modes. + * + * XXX + * We always do this because it's too hard to figure out what curses + * implementations get it wrong. It may discard type-ahead characters + * from the tty queue. + */ + (void)tcsetattr(STDIN_FILENO, TCSADRAIN | TCSASOFT, &clp->orig); + + F_CLR(clp, CL_SCR_EX_INIT | CL_SCR_VI_INIT); + return (rval); +} + +/* + * cl_vi_init -- + * Initialize the curses vi screen. + */ +static int +cl_vi_init(SCR *sp) +{ + CL_PRIVATE *clp; + GS *gp; + char *o_cols, *o_lines, *o_term, *ttype; + + gp = sp->gp; + clp = CLP(sp); + + /* If already initialized, just set the terminal modes. */ + if (F_ISSET(clp, CL_SCR_VI_INIT)) + goto fast; + + /* Curses vi always reads from (and writes to) a terminal. */ + if (!F_ISSET(clp, CL_STDIN_TTY) || !isatty(STDOUT_FILENO)) { + msgq(sp, M_ERR, + "016|Vi's standard input and output must be a terminal"); + return (1); + } + + /* We'll need a terminal type. */ + if (opts_empty(sp, O_TERM, 0)) + return (1); + ttype = O_STR(sp, O_TERM); + + /* + * XXX + * Changing the row/column and terminal values is done by putting them + * into the environment, which is then read by curses. What this loses + * in ugliness, it makes up for in stupidity. We can't simply put the + * values into the environment ourselves, because in the presence of a + * kernel mechanism for returning the window size, entering values into + * the environment will screw up future screen resizing events, e.g. if + * the user enters a :shell command and then resizes their window. So, + * if they weren't already in the environment, we make sure to delete + * them immediately after setting them. + * + * XXX + * Putting the TERM variable into the environment is necessary, even + * though we're using newterm() here. We may be using initscr() as + * the underlying function. + */ + o_term = getenv("TERM"); + cl_putenv("TERM", ttype, 0); + o_lines = getenv("LINES"); + cl_putenv("LINES", NULL, (u_long)O_VAL(sp, O_LINES)); + o_cols = getenv("COLUMNS"); + cl_putenv("COLUMNS", NULL, (u_long)O_VAL(sp, O_COLUMNS)); + + /* + * The terminal is aways initialized, either in `main`, or by a + * previous call to newterm(3X). + */ + (void)del_curterm(cur_term); + + /* + * We never have more than one SCREEN at a time, so set_term(NULL) will + * give us the last SCREEN. + */ + errno = 0; + if (newterm(ttype, stdout, stdin) == NULL) { + if (errno) + msgq(sp, M_SYSERR, "%s", ttype); + else + msgq(sp, M_ERR, "%s: unknown terminal type", ttype); + return (1); + } + + if (o_term == NULL) + unsetenv("TERM"); + if (o_lines == NULL) + unsetenv("LINES"); + if (o_cols == NULL) + unsetenv("COLUMNS"); + + /* + * XXX + * Someone got let out alone without adult supervision -- the SunOS + * newterm resets the signal handlers. There's a race, but it's not + * worth closing. + */ + (void)sig_init(sp->gp, sp); + + /* + * We use raw mode. What we want is 8-bit clean, however, signals + * and flow control should continue to work. Admittedly, it sounds + * like cbreak, but it isn't. Using cbreak() can get you additional + * things like IEXTEN, which turns on flags like DISCARD and LNEXT. + * + * !!! + * If raw isn't turning off echo and newlines, something's wrong. + * However, it shouldn't hurt. + */ + noecho(); /* No character echo. */ + nonl(); /* No CR/NL translation. */ + raw(); /* 8-bit clean. */ + idlok(stdscr, 1); /* Use hardware insert/delete line. */ + + /* Put the cursor keys into application mode. */ + (void)keypad(stdscr, TRUE); + + /* + * XXX + * The screen TI sequence just got sent. See the comment in + * cl_funcs.c:cl_attr(). + */ + clp->ti_te = TI_SENT; + + /* + * XXX + * Historic implementations of curses handled SIGTSTP signals + * in one of three ways. They either: + * + * 1: Set their own handler, regardless. + * 2: Did not set a handler if a handler was already installed. + * 3: Set their own handler, but then called any previously set + * handler after completing their own cleanup. + * + * We don't try and figure out which behavior is in place, we force + * it to SIG_DFL after initializing the curses interface, which means + * that curses isn't going to take the signal. Since curses isn't + * reentrant (i.e., the whole curses SIGTSTP interface is a fantasy), + * we're doing The Right Thing. + */ + (void)signal(SIGTSTP, SIG_DFL); + + /* + * If flow control was on, turn it back on. Turn signals on. ISIG + * turns on VINTR, VQUIT, VDSUSP and VSUSP. The main curses code + * already installed a handler for VINTR. We're going to disable the + * other three. + * + * XXX + * We want to use ^Y as a vi scrolling command. If the user has the + * DSUSP character set to ^Y (common practice) clean it up. As it's + * equally possible that the user has VDSUSP set to 'a', we disable + * it regardless. It doesn't make much sense to suspend vi at read, + * so I don't think anyone will care. Alternatively, we could look + * it up in the table of legal command characters and turn it off if + * it matches one. VDSUSP wasn't in POSIX 1003.1-1990, so we test for + * it. + * + * XXX + * We don't check to see if the user had signals enabled originally. + * If they didn't, it's unclear what we're supposed to do here, but + * it's also pretty unlikely. + */ + if (tcgetattr(STDIN_FILENO, &clp->vi_enter)) { + msgq(sp, M_SYSERR, "tcgetattr"); + goto err; + } + if (clp->orig.c_iflag & IXON) + clp->vi_enter.c_iflag |= IXON; + if (clp->orig.c_iflag & IXOFF) + clp->vi_enter.c_iflag |= IXOFF; + + clp->vi_enter.c_lflag |= ISIG; +#ifdef VDSUSP + clp->vi_enter.c_cc[VDSUSP] = _POSIX_VDISABLE; +#endif + clp->vi_enter.c_cc[VQUIT] = _POSIX_VDISABLE; + clp->vi_enter.c_cc[VSUSP] = _POSIX_VDISABLE; + + /* + * XXX + * OSF/1 doesn't turn off the , or + * characters when curses switches into raw mode. It should be OK + * to do it explicitly for everyone. + */ +#ifdef VDISCARD + clp->vi_enter.c_cc[VDISCARD] = _POSIX_VDISABLE; +#endif +#ifdef VLNEXT + clp->vi_enter.c_cc[VLNEXT] = _POSIX_VDISABLE; +#endif +#ifdef VSTATUS + clp->vi_enter.c_cc[VSTATUS] = _POSIX_VDISABLE; +#endif + + /* Initialize terminal based information. */ + if (cl_term_init(sp)) + goto err; + +fast: /* Set the terminal modes. */ + if (tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &clp->vi_enter)) { + if (errno == EINTR) + goto fast; + msgq(sp, M_SYSERR, "tcsetattr"); +err: (void)cl_vi_end(sp->gp); + return (1); + } + return (0); +} + +/* + * cl_vi_end -- + * Shutdown the vi screen. + */ +static int +cl_vi_end(GS *gp) +{ + CL_PRIVATE *clp; + + clp = GCLP(gp); + + /* Restore the cursor keys to normal mode. */ + (void)keypad(stdscr, FALSE); + + /* + * If we were running vi when we quit, scroll the screen up a single + * line so we don't lose any information. + * + * Move to the bottom of the window (some endwin implementations don't + * do this for you). + */ + if (!F_ISSET(clp, CL_IN_EX)) { + (void)move(0, 0); + (void)deleteln(); + (void)move(LINES - 1, 0); + (void)refresh(); + } + + cl_freecap(clp); + + /* End curses window. */ + (void)endwin(); + + /* Free the SCREEN created by newterm(3X). */ + delscreen(set_term(NULL)); + + /* + * XXX + * The screen TE sequence just got sent. See the comment in + * cl_funcs.c:cl_attr(). + */ + clp->ti_te = TE_SENT; + + return (0); +} + +/* + * cl_ex_init -- + * Initialize the ex screen. + */ +static int +cl_ex_init(SCR *sp) +{ + CL_PRIVATE *clp; + + clp = CLP(sp); + + /* If already initialized, just set the terminal modes. */ + if (F_ISSET(clp, CL_SCR_EX_INIT)) + goto fast; + + /* If not reading from a file, we're done. */ + if (!F_ISSET(clp, CL_STDIN_TTY)) + return (0); + + /* Get the ex termcap/terminfo strings. */ + (void)cl_getcap(sp, "cup", &clp->cup); + (void)cl_getcap(sp, "smso", &clp->smso); + (void)cl_getcap(sp, "rmso", &clp->rmso); + (void)cl_getcap(sp, "el", &clp->el); + (void)cl_getcap(sp, "cuu1", &clp->cuu1); + + /* Enter_standout_mode and exit_standout_mode are paired. */ + if (clp->smso == NULL || clp->rmso == NULL) { + free(clp->smso); + clp->smso = NULL; + + free(clp->rmso); + clp->rmso = NULL; + } + + /* + * Turn on canonical mode, with normal input and output processing. + * Start with the original terminal settings as the user probably + * had them (including any local extensions) set correctly for the + * current terminal. + * + * !!! + * We can't get everything that we need portably; for example, ONLCR, + * mapping to on output isn't required + * by POSIX 1003.1b-1993. If this turns out to be a problem, then + * we'll either have to play some games on the mapping, or we'll have + * to make all ex printf's output \r\n instead of \n. + */ + clp->ex_enter = clp->orig; + clp->ex_enter.c_lflag |= ECHO | ECHOE | ECHOK | ICANON | IEXTEN | ISIG; +#ifdef ECHOCTL + clp->ex_enter.c_lflag |= ECHOCTL; +#endif +#ifdef ECHOKE + clp->ex_enter.c_lflag |= ECHOKE; +#endif + clp->ex_enter.c_iflag |= ICRNL; + clp->ex_enter.c_oflag |= OPOST; +#ifdef ONLCR + clp->ex_enter.c_oflag |= ONLCR; +#endif + +fast: if (tcsetattr(STDIN_FILENO, TCSADRAIN | TCSASOFT, &clp->ex_enter)) { + if (errno == EINTR) + goto fast; + msgq(sp, M_SYSERR, "tcsetattr"); + return (1); + } + return (0); +} + +/* + * cl_ex_end -- + * Shutdown the ex screen. + */ +static int +cl_ex_end(GS *gp) +{ + CL_PRIVATE *clp; + + clp = GCLP(gp); + + cl_freecap(clp); + + return (0); +} + +/* + * cl_getcap -- + * Retrieve termcap/terminfo strings. + * + * PUBLIC: int cl_getcap(SCR *, char *, char **); + */ +int +cl_getcap(SCR *sp, char *name, char **elementp) +{ + size_t len; + char *t; + + if ((t = tigetstr(name)) != NULL && + t != (char *)-1 && (len = strlen(t)) != 0) { + MALLOC_RET(sp, *elementp, len + 1); + memmove(*elementp, t, len + 1); + } + return (0); +} + +/* + * cl_freecap -- + * Free any allocated termcap/terminfo strings. + */ +static void +cl_freecap(CL_PRIVATE *clp) +{ + free(clp->el); + clp->el = NULL; + + free(clp->cup); + clp->cup = NULL; + + free(clp->cuu1); + clp->cuu1 = NULL; + + free(clp->rmso); + clp->rmso = NULL; + + free(clp->smso); + clp->smso = NULL; + + /* Required by libcursesw :) */ + free(clp->cw.bp1.c); + clp->cw.bp1.c = NULL; + clp->cw.blen1 = 0; +} + +/* + * cl_putenv -- + * Put a value into the environment. + */ +static int +cl_putenv(char *name, char *str, u_long value) +{ + char buf[40]; + + if (str == NULL) { + (void)snprintf(buf, sizeof(buf), "%lu", value); + return (setenv(name, buf, 1)); + } else + return (setenv(name, str, 1)); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/cl/cl_screen.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/common/common.h =================================================================== --- vendor/nvi/2.2.0-05ed8b9/common/common.h (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/common/common.h (revision 366308) @@ -0,0 +1,94 @@ +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1991, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#ifndef TCSASOFT +#define TCSASOFT 0 +#endif + +#ifdef __linux__ +#include "/usr/include/db1/db.h" /* Only include db1. */ +#else +#include "/usr/include/db.h" /* Only include db1. */ +#endif +#include /* May refer to the bundled regex. */ + +/* + * Forward structure declarations. Not pretty, but the include files + * are far too interrelated for a clean solution. + */ +typedef struct _cb CB; +typedef struct _csc CSC; +typedef struct _conv CONV; +typedef struct _conv_win CONVWIN; +typedef struct _event EVENT; +typedef struct _excmd EXCMD; +typedef struct _exf EXF; +typedef struct _fref FREF; +typedef struct _gs GS; +typedef struct _lmark LMARK; +typedef struct _mark MARK; +typedef struct _msg MSGS; +typedef struct _option OPTION; +typedef struct _optlist OPTLIST; +typedef struct _scr SCR; +typedef struct _script SCRIPT; +typedef struct _seq SEQ; +typedef struct _tag TAG; +typedef struct _tagf TAGF; +typedef struct _tagq TAGQ; +typedef struct _text TEXT; + +/* Autoindent state. */ +typedef enum { C_NOTSET, C_CARATSET, C_ZEROSET } carat_t; + +/* Busy message types. */ +typedef enum { BUSY_ON = 1, BUSY_OFF, BUSY_UPDATE } busy_t; + +/* + * Routines that return a confirmation return: + * + * CONF_NO User answered no. + * CONF_QUIT User answered quit, eof or an error. + * CONF_YES User answered yes. + */ +typedef enum { CONF_NO, CONF_QUIT, CONF_YES } conf_t; + +/* Directions. */ +typedef enum { NOTSET, FORWARD, BACKWARD } dir_t; + +/* Line operations. */ +typedef enum { LINE_APPEND, LINE_DELETE, LINE_INSERT, LINE_RESET } lnop_t; + +/* Lock return values. */ +typedef enum { LOCK_FAILED, LOCK_SUCCESS, LOCK_UNAVAIL } lockr_t; + +/* Sequence types. */ +typedef enum { SEQ_ABBREV, SEQ_COMMAND, SEQ_INPUT } seq_t; + +/* + * Local includes. + */ +#include "key.h" /* Required by args.h. */ +#include "args.h" /* Required by options.h. */ +#include "options.h" /* Required by screen.h. */ + +#include "msg.h" /* Required by gs.h. */ +#include "cut.h" /* Required by gs.h. */ +#include "seq.h" /* Required by screen.h. */ +#include "util.h" /* Required by ex.h. */ +#include "mark.h" /* Required by gs.h. */ +#include "conv.h" /* Required by ex.h and screen.h */ +#include "../ex/ex.h" /* Required by gs.h. */ +#include "gs.h" /* Required by screen.h. */ +#include "screen.h" /* Required by exf.h. */ +#include "exf.h" +#include "log.h" +#include "mem.h" + +#include "extern.h" Property changes on: vendor/nvi/2.2.0-05ed8b9/common/common.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/common/cut.h =================================================================== --- vendor/nvi/2.2.0-05ed8b9/common/cut.h (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/common/cut.h (revision 366308) @@ -0,0 +1,77 @@ +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1991, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +typedef struct _texth TEXTH; /* TEXT list head structure. */ +TAILQ_HEAD(_texth, _text); + +/* Cut buffers. */ +struct _cb { + SLIST_ENTRY(_cb) q; /* Linked list of cut buffers. */ + TEXTH textq[1]; /* Linked list of TEXT structures. */ + /* XXXX Needed ? Can non ascii-chars be cut buffer names ? */ + CHAR_T name; /* Cut buffer name. */ + size_t len; /* Total length of cut text. */ + +#define CB_LMODE 0x01 /* Cut was in line mode. */ + u_int8_t flags; +}; + +/* Lines/blocks of text. */ +struct _text { /* Text: a linked list of lines. */ + TAILQ_ENTRY(_text) q; /* Linked list of text structures. */ + CHAR_T *lb; /* Line buffer. */ + size_t lb_len; /* Line buffer length. */ + size_t len; /* Line length. */ + + /* These fields are used by the vi text input routine. */ + recno_t lno; /* 1-N: file line. */ + +#define ENTIRE_LINE ((size_t)-1) /* cno: end of the line. */ + size_t cno; /* 0-N: file character in line. */ + size_t ai; /* 0-N: autoindent bytes. */ + size_t insert; /* 0-N: bytes to insert (push). */ + size_t offset; /* 0-N: initial, unerasable chars. */ + size_t owrite; /* 0-N: chars to overwrite. */ + size_t R_erase; /* 0-N: 'R' erase count. */ + size_t sv_cno; /* 0-N: Saved line cursor. */ + size_t sv_len; /* 0-N: Saved line length. */ + + /* + * These fields returns information from the vi text input routine. + * + * The termination condition. Note, this field is only valid if the + * text input routine returns success. + * TERM_BS: User backspaced over the prompt. + * TERM_CEDIT: User entered . + * TERM_CR: User entered ; no data. + * TERM_ESC: User entered ; no data. + * TERM_OK: Data available. + * TERM_SEARCH: Incremental search. + */ + enum { + TERM_BS, TERM_CEDIT, TERM_CR, TERM_ESC, TERM_OK, TERM_SEARCH + } term; +}; + +/* + * Get named buffer 'name'. + * Translate upper-case buffer names to lower-case buffer names. + */ +#define CBNAME(sp, cbp, nch) do { \ + CHAR_T L__name; \ + L__name = isupper(nch) ? tolower(nch) : (nch); \ + SLIST_FOREACH(cbp, sp->gp->cutq, q) \ + if (cbp->name == L__name) \ + break; \ +} while (0) + +/* Flags to the cut() routine. */ +#define CUT_LINEMODE 0x01 /* Cut in line mode. */ +#define CUT_NUMOPT 0x02 /* Numeric buffer: optional. */ +#define CUT_NUMREQ 0x04 /* Numeric buffer: required. */ Property changes on: vendor/nvi/2.2.0-05ed8b9/common/cut.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/common/exf.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/common/exf.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/common/exf.c (revision 366308) @@ -0,0 +1,1479 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include +#include + +/* + * We include , because the flock(2) and open(2) #defines + * were found there on historical systems. We also include + * because the open(2) #defines are found there on newer systems. + */ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" + +static int file_backup(SCR *, char *, char *); +static void file_cinit(SCR *); +static void file_encinit(SCR *); +static void file_comment(SCR *); +static int file_spath(SCR *, FREF *, struct stat *, int *); + +/* + * file_add -- + * Insert a file name into the FREF list, if it doesn't already + * appear in it. + * + * !!! + * The "if it doesn't already appear" changes vi's semantics slightly. If + * you do a "vi foo bar", and then execute "next bar baz", the edit of bar + * will reflect the line/column of the previous edit session. Historic nvi + * did not do this. The change is a logical extension of the change where + * vi now remembers the last location in any file that it has ever edited, + * not just the previously edited file. + * + * PUBLIC: FREF *file_add(SCR *, char *); + */ +FREF * +file_add(SCR *sp, char *name) +{ + GS *gp; + FREF *frp, *tfrp; + + /* + * Return it if it already exists. Note that we test against the + * user's name, whatever that happens to be, including if it's a + * temporary file. + * + * If the user added a file but was unable to initialize it, there + * can be file list entries where the name field is NULL. Discard + * them the next time we see them. + */ + gp = sp->gp; + if (name != NULL) + TAILQ_FOREACH_SAFE(frp, gp->frefq, q, tfrp) { + if (frp->name == NULL) { + TAILQ_REMOVE(gp->frefq, frp, q); + free(frp->name); + free(frp); + continue; + } + if (!strcmp(frp->name, name)) + return (frp); + } + + /* Allocate and initialize the FREF structure. */ + CALLOC(sp, frp, 1, sizeof(FREF)); + if (frp == NULL) + return (NULL); + + /* + * If no file name specified, or if the file name is a request + * for something temporary, file_init() will allocate the file + * name. Temporary files are always ignored. + */ + if (name != NULL && strcmp(name, TEMPORARY_FILE_STRING) && + (frp->name = strdup(name)) == NULL) { + free(frp); + msgq(sp, M_SYSERR, NULL); + return (NULL); + } + + /* Append into the chain of file names. */ + TAILQ_INSERT_TAIL(gp->frefq, frp, q); + + return (frp); +} + +/* + * file_init -- + * Start editing a file, based on the FREF structure. If successsful, + * let go of any previous file. Don't release the previous file until + * absolutely sure we have the new one. + * + * PUBLIC: int file_init(SCR *, FREF *, char *, int); + */ +int +file_init(SCR *sp, FREF *frp, char *rcv_name, int flags) +{ + EXF *ep; + RECNOINFO oinfo = { 0 }; + struct stat sb; + size_t psize; + int fd, exists, open_err, readonly; + char *oname, *tname; + + open_err = readonly = 0; + + /* + * If the file is a recovery file, let the recovery code handle it. + * Clear the FR_RECOVER flag first -- the recovery code does set up, + * and then calls us! If the recovery call fails, it's probably + * because the named file doesn't exist. So, move boldly forward, + * presuming that there's an error message the user will get to see. + */ + if (F_ISSET(frp, FR_RECOVER)) { + F_CLR(frp, FR_RECOVER); + return (rcv_read(sp, frp)); + } + + /* + * Required FRP initialization; the only flag we keep is the + * cursor information. + */ + F_CLR(frp, ~FR_CURSORSET); + + /* + * Required EXF initialization: + * Flush the line caches. + * Default recover mail file fd to -1. + * Set initial EXF flag bits. + */ + CALLOC_RET(sp, ep, 1, sizeof(EXF)); + ep->c_lno = ep->c_nlines = OOBLNO; + ep->rcv_fd = -1; + F_SET(ep, F_FIRSTMODIFY); + + /* + * Scan the user's path to find the file that we're going to + * try and open. + */ + if (file_spath(sp, frp, &sb, &exists)) + return (1); + + /* + * If no name or backing file, for whatever reason, create a backing + * temporary file, saving the temp file name so we can later unlink + * it. If the user never named this file, copy the temporary file name + * to the real name (we display that until the user renames it). + */ + oname = frp->name; + if (LF_ISSET(FS_OPENERR) || oname == NULL || !exists) { + struct stat sb; + + if (opts_empty(sp, O_TMPDIR, 0)) + goto err; + if ((tname = + join(O_STR(sp, O_TMPDIR), "vi.XXXXXXXXXX")) == NULL) { + msgq(sp, M_SYSERR, NULL); + goto err; + } + if ((fd = mkstemp(tname)) == -1 || fstat(fd, &sb)) { + free(tname); + msgq(sp, M_SYSERR, + "237|Unable to create temporary file"); + goto err; + } + (void)close(fd); + + frp->tname = tname; + if (frp->name == NULL) { + F_SET(frp, FR_TMPFILE); + if ((frp->name = strdup(tname)) == NULL) { + msgq(sp, M_SYSERR, NULL); + goto err; + } + } + oname = frp->tname; + psize = 1024; + if (!LF_ISSET(FS_OPENERR)) + F_SET(frp, FR_NEWFILE); + + ep->mtim = sb.st_mtim; + } else { + /* + * XXX + * A seat of the pants calculation: try to keep the file in + * 15 pages or less. Don't use a page size larger than 16K + * (vi should have good locality) or smaller than 1K. + */ + psize = ((sb.st_size / 15) + 1023) / 1024; + if (psize > 16) + psize = 16; + if (psize == 0) + psize = 1; + psize = p2roundup(psize) << 10; + + F_SET(ep, F_DEVSET); + ep->mdev = sb.st_dev; + ep->minode = sb.st_ino; + + ep->mtim = sb.st_mtim; + + if (!S_ISREG(sb.st_mode)) + msgq_str(sp, M_ERR, oname, + "238|Warning: %s is not a regular file"); + } + + /* Set up recovery. */ + oinfo.bval = '\n'; /* Always set. */ + oinfo.psize = psize; + oinfo.flags = F_ISSET(sp->gp, G_SNAPSHOT) ? R_SNAPSHOT : 0; + if (rcv_name == NULL) { + if (!rcv_tmp(sp, ep, frp->name)) + oinfo.bfname = ep->rcv_path; + } else { + if ((ep->rcv_path = strdup(rcv_name)) == NULL) { + msgq(sp, M_SYSERR, NULL); + goto err; + } + oinfo.bfname = ep->rcv_path; + F_SET(ep, F_MODIFIED); + } + + /* Open a db structure. */ + if ((ep->db = dbopen(rcv_name == NULL ? oname : NULL, + O_NONBLOCK | O_RDONLY, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, + DB_RECNO, &oinfo)) == NULL) { + msgq_str(sp, + M_SYSERR, rcv_name == NULL ? oname : rcv_name, "%s"); + if (F_ISSET(frp, FR_NEWFILE)) + goto err; + /* + * !!! + * Historically, vi permitted users to edit files that couldn't + * be read. This isn't useful for single files from a command + * line, but it's quite useful for "vi *.c", since you can skip + * past files that you can't read. + */ + open_err = 1; + goto oerr; + } + + /* + * Do the remaining things that can cause failure of the new file, + * mark and logging initialization. + */ + if (mark_init(sp, ep) || log_init(sp, ep)) + goto err; + + /* + * Set the alternate file name to be the file we're discarding. + * + * !!! + * Temporary files can't become alternate files, so there's no file + * name. This matches historical practice, although it could only + * happen in historical vi as the result of the initial command, i.e. + * if vi was executed without a file name. + */ + if (LF_ISSET(FS_SETALT)) + set_alt_name(sp, sp->frp == NULL || + F_ISSET(sp->frp, FR_TMPFILE) ? NULL : sp->frp->name); + + /* + * Close the previous file; if that fails, close the new one and run + * for the border. + * + * !!! + * There's a nasty special case. If the user edits a temporary file, + * and then does an ":e! %", we need to re-initialize the backing + * file, but we can't change the name. (It's worse -- we're dealing + * with *names* here, we can't even detect that it happened.) Set a + * flag so that the file_end routine ignores the backing information + * of the old file if it happens to be the same as the new one. + * + * !!! + * Side-effect: after the call to file_end(), sp->frp may be NULL. + */ + if (sp->ep != NULL) { + F_SET(frp, FR_DONTDELETE); + if (file_end(sp, NULL, LF_ISSET(FS_FORCE))) { + (void)file_end(sp, ep, 1); + goto err; + } + F_CLR(frp, FR_DONTDELETE); + } + + /* + * Lock the file; if it's a recovery file, it should already be + * locked. Note, we acquire the lock after the previous file + * has been ended, so that we don't get an "already locked" error + * for ":edit!". + * + * XXX + * While the user can't interrupt us between the open and here, + * there's a race between the dbopen() and the lock. Not much + * we can do about it. + * + * XXX + * We don't make a big deal of not being able to lock the file. As + * locking rarely works over NFS, and often fails if the file was + * mmap(2)'d, it's far too common to do anything like print an error + * message, let alone make the file readonly. At some future time, + * when locking is a little more reliable, this should change to be + * an error. + */ + if (rcv_name == NULL) + switch (file_lock(sp, oname, ep->db->fd(ep->db), 0)) { + case LOCK_FAILED: + F_SET(frp, FR_UNLOCKED); + break; + case LOCK_UNAVAIL: + readonly = 1; + if (F_ISSET(sp, SC_READONLY)) + break; + msgq_str(sp, M_INFO, oname, + "239|%s already locked, session is read-only"); + break; + case LOCK_SUCCESS: + break; + } + + /* + * Historically, the readonly edit option was set per edit buffer in + * vi, unless the -R command-line option was specified or the program + * was executed as "view". (Well, to be truthful, if the letter 'w' + * occurred anywhere in the program name, but let's not get into that.) + * So, the persistent readonly state has to be stored in the screen + * structure, and the edit option value toggles with the contents of + * the edit buffer. If the persistent readonly flag is set, set the + * readonly edit option. + * + * Otherwise, try and figure out if a file is readonly. This is a + * dangerous thing to do. The kernel is the only arbiter of whether + * or not a file is writeable, and the best that a user program can + * do is guess. Obvious loopholes are files that are on a file system + * mounted readonly (access catches this one on a few systems), or + * alternate protection mechanisms, ACL's for example, that we can't + * portably check. Lots of fun, and only here because users whined. + * + * !!! + * Historic vi displayed the readonly message if none of the file + * write bits were set, or if an an access(2) call on the path + * failed. This seems reasonable. If the file is mode 444, root + * users may want to know that the owner of the file did not expect + * it to be written. + * + * Historic vi set the readonly bit if no write bits were set for + * a file, even if the access call would have succeeded. This makes + * the superuser force the write even when vi expects that it will + * succeed. I'm less supportive of this semantic, but it's historic + * practice and the conservative approach to vi'ing files as root. + * + * It would be nice if there was some way to update this when the user + * does a "^Z; chmod ...". The problem is that we'd first have to + * distinguish between readonly bits set because of file permissions + * and those set for other reasons. That's not too hard, but deciding + * when to reevaluate the permissions is trickier. An alternative + * might be to turn off the readonly bit if the user forces a write + * and it succeeds. + * + * XXX + * Access(2) doesn't consider the effective uid/gid values. This + * probably isn't a problem for vi when it's running standalone. + */ + if (readonly || F_ISSET(sp, SC_READONLY) || + (!F_ISSET(frp, FR_NEWFILE) && + (!(sb.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) || + access(frp->name, W_OK)))) + O_SET(sp, O_READONLY); + else + O_CLR(sp, O_READONLY); + + /* Switch... */ + ++ep->refcnt; + sp->ep = ep; + sp->frp = frp; + + /* Detect and set the file encoding */ + file_encinit(sp); + + /* Set the initial cursor position, queue initial command. */ + file_cinit(sp); + + /* Redraw the screen from scratch, schedule a welcome message. */ + F_SET(sp, SC_SCR_REFORMAT | SC_STATUS); + + return (0); + +err: free(frp->name); + frp->name = NULL; + if (frp->tname != NULL) { + (void)unlink(frp->tname); + free(frp->tname); + frp->tname = NULL; + } + +oerr: if (F_ISSET(ep, F_RCV_ON)) + (void)unlink(ep->rcv_path); + free(ep->rcv_path); + ep->rcv_path = NULL; + + if (ep->db != NULL) + (void)ep->db->close(ep->db); + free(ep); + + return (open_err ? + file_init(sp, frp, rcv_name, flags | FS_OPENERR) : 1); +} + +/* + * file_spath -- + * Scan the user's path to find the file that we're going to + * try and open. + */ +static int +file_spath(SCR *sp, FREF *frp, struct stat *sbp, int *existsp) +{ + int savech; + size_t len; + int found; + char *name, *p, *t, *path; + + /* + * If the name is NULL or an explicit reference (i.e., the first + * component is . or ..) ignore the O_PATH option. + */ + name = frp->name; + if (name == NULL) { + *existsp = 0; + return (0); + } + if (name[0] == '/' || (name[0] == '.' && + (name[1] == '/' || (name[1] == '.' && name[2] == '/')))) { + *existsp = !stat(name, sbp); + return (0); + } + + /* Try . */ + if (!stat(name, sbp)) { + *existsp = 1; + return (0); + } + + /* Try the O_PATH option values. */ + for (found = 0, p = t = O_STR(sp, O_PATH);; ++p) + if (*p == ':' || *p == '\0') { + /* + * Ignore the empty strings and ".", since we've already + * tried the current directory. + */ + if (t < p && (p - t != 1 || *t != '.')) { + savech = *p; + *p = '\0'; + if ((path = join(t, name)) == NULL) { + msgq(sp, M_SYSERR, NULL); + break; + } + len = strlen(path); + *p = savech; + if (!stat(path, sbp)) { + found = 1; + break; + } + free(path); + } + t = p + 1; + if (*p == '\0') + break; + } + + /* If we found it, build a new pathname and discard the old one. */ + if (found) { + free(frp->name); + frp->name = path; + } + *existsp = found; + return (0); +} + +/* + * file_cinit -- + * Set up the initial cursor position. + */ +static void +file_cinit(SCR *sp) +{ + GS *gp; + MARK m; + size_t len; + int nb; + CHAR_T *wp; + size_t wlen; + + /* Set some basic defaults. */ + sp->lno = 1; + sp->cno = 0; + + /* + * Historically, initial commands (the -c option) weren't executed + * until a file was loaded, e.g. "vi +10 nofile", followed by an + * :edit or :tag command, would execute the +10 on the file loaded + * by the subsequent command, (assuming that it existed). This + * applied as well to files loaded using the tag commands, and we + * follow that historic practice. Also, all initial commands were + * ex commands and were always executed on the last line of the file. + * + * Otherwise, if no initial command for this file: + * If in ex mode, move to the last line, first nonblank character. + * If the file has previously been edited, move to the last known + * position, and check it for validity. + * Otherwise, move to the first line, first nonblank. + * + * This gets called by the file init code, because we may be in a + * file of ex commands and we want to execute them from the right + * location in the file. + */ + nb = 0; + gp = sp->gp; + if (gp->c_option != NULL && !F_ISSET(sp->frp, FR_NEWFILE)) { + if (db_last(sp, &sp->lno)) + return; + if (sp->lno == 0) { + sp->lno = 1; + sp->cno = 0; + } + CHAR2INT(sp, gp->c_option, strlen(gp->c_option) + 1, + wp, wlen); + if (ex_run_str(sp, "-c option", wp, wlen - 1, 1, 0)) + return; + gp->c_option = NULL; + } else if (F_ISSET(sp, SC_EX)) { + if (db_last(sp, &sp->lno)) + return; + if (sp->lno == 0) { + sp->lno = 1; + sp->cno = 0; + return; + } + nb = 1; + } else { + if (F_ISSET(sp->frp, FR_CURSORSET)) { + sp->lno = sp->frp->lno; + sp->cno = sp->frp->cno; + + /* If returning to a file in vi, center the line. */ + F_SET(sp, SC_SCR_CENTER); + } else { + if (O_ISSET(sp, O_COMMENT)) + file_comment(sp); + else + sp->lno = 1; + nb = 1; + } + if (db_get(sp, sp->lno, 0, NULL, &len)) { + sp->lno = 1; + sp->cno = 0; + return; + } + if (!nb && sp->cno > len) + nb = 1; + } + if (nb) { + sp->cno = 0; + (void)nonblank(sp, sp->lno, &sp->cno); + } + + /* + * !!! + * The initial column is also the most attractive column. + */ + sp->rcm = sp->cno; + + /* + * !!! + * Historically, vi initialized the absolute mark, but ex did not. + * Which meant, that if the first command in ex mode was "visual", + * or if an ex command was executed first (e.g. vi +10 file) vi was + * entered without the mark being initialized. For consistency, if + * the file isn't empty, we initialize it for everyone, believing + * that it can't hurt, and is generally useful. Not initializing it + * if the file is empty is historic practice, although it has always + * been possible to set (and use) marks in empty vi files. + */ + m.lno = sp->lno; + m.cno = sp->cno; + (void)mark_set(sp, ABSMARK1, &m, 0); +} + +/* + * file_end -- + * Stop editing a file. + * + * PUBLIC: int file_end(SCR *, EXF *, int); + */ +int +file_end(SCR *sp, EXF *ep, int force) +{ + FREF *frp; + + /* + * !!! + * ep MAY NOT BE THE SAME AS sp->ep, DON'T USE THE LATTER. + * (If argument ep is NULL, use sp->ep.) + * + * If multiply referenced, just decrement the count and return. + */ + if (ep == NULL) + ep = sp->ep; + if (--ep->refcnt != 0) + return (0); + + /* + * + * Clean up the FREF structure. + * + * Save the cursor location. + * + * XXX + * It would be cleaner to do this somewhere else, but by the time + * ex or vi knows that we're changing files it's already happened. + */ + frp = sp->frp; + frp->lno = sp->lno; + frp->cno = sp->cno; + F_SET(frp, FR_CURSORSET); + + /* + * We may no longer need the temporary backing file, so clean it + * up. We don't need the FREF structure either, if the file was + * never named, so lose it. + * + * !!! + * Re: FR_DONTDELETE, see the comment above in file_init(). + */ + if (!F_ISSET(frp, FR_DONTDELETE) && frp->tname != NULL) { + if (unlink(frp->tname)) + msgq_str(sp, M_SYSERR, frp->tname, "240|%s: remove"); + free(frp->tname); + frp->tname = NULL; + if (F_ISSET(frp, FR_TMPFILE)) { + TAILQ_REMOVE(sp->gp->frefq, frp, q); + free(frp->name); + free(frp); + } + sp->frp = NULL; + } + + /* + * Clean up the EXF structure. + * + * Close the db structure. + */ + if (ep->db->close != NULL && ep->db->close(ep->db) && !force) { + msgq_str(sp, M_SYSERR, frp->name, "241|%s: close"); + ++ep->refcnt; + return (1); + } + + /* COMMITTED TO THE CLOSE. THERE'S NO GOING BACK... */ + + /* Stop logging. */ + (void)log_end(sp, ep); + + /* Free up any marks. */ + (void)mark_end(sp, ep); + + /* + * Delete recovery files, close the open descriptor, free recovery + * memory. See recover.c for a description of the protocol. + * + * XXX + * Unlink backup file first, we can detect that the recovery file + * doesn't reference anything when the user tries to recover it. + * There's a race, here, obviously, but it's fairly small. + */ + if (!F_ISSET(ep, F_RCV_NORM)) { + if (ep->rcv_path != NULL && unlink(ep->rcv_path)) + msgq_str(sp, M_SYSERR, ep->rcv_path, "242|%s: remove"); + if (ep->rcv_mpath != NULL && unlink(ep->rcv_mpath)) + msgq_str(sp, M_SYSERR, ep->rcv_mpath, "243|%s: remove"); + } + if (ep->rcv_fd != -1) + (void)close(ep->rcv_fd); + free(ep->rcv_path); + free(ep->rcv_mpath); + if (ep->c_blen > 0) + free(ep->c_lp); + + free(ep); + return (0); +} + +/* + * file_write -- + * Write the file to disk. Historic vi had fairly convoluted + * semantics for whether or not writes would happen. That's + * why all the flags. + * + * PUBLIC: int file_write(SCR *, MARK *, MARK *, char *, int); + */ +int +file_write(SCR *sp, MARK *fm, MARK *tm, char *name, int flags) +{ + enum { NEWFILE, OLDFILE } mtype; + struct stat sb; + EXF *ep; + FILE *fp; + FREF *frp; + MARK from, to; + size_t len; + u_long nlno, nch; + int fd, nf, noname, oflags, rval; + char *p, *s, *t, buf[1024]; + const char *msgstr; + + ep = sp->ep; + frp = sp->frp; + + /* + * Writing '%', or naming the current file explicitly, has the + * same semantics as writing without a name. + */ + if (name == NULL || !strcmp(name, frp->name)) { + noname = 1; + name = frp->name; + } else + noname = 0; + + /* Can't write files marked read-only, unless forced. */ + if (!LF_ISSET(FS_FORCE) && noname && O_ISSET(sp, O_READONLY)) { + msgq(sp, M_ERR, LF_ISSET(FS_POSSIBLE) ? + "244|Read-only file, not written; use ! to override" : + "245|Read-only file, not written"); + return (1); + } + + /* If not forced, not appending, and "writeany" not set ... */ + if (!LF_ISSET(FS_FORCE | FS_APPEND) && !O_ISSET(sp, O_WRITEANY)) { + /* Don't overwrite anything but the original file. */ + if ((!noname || F_ISSET(frp, FR_NAMECHANGE)) && + !stat(name, &sb)) { + msgq_str(sp, M_ERR, name, + LF_ISSET(FS_POSSIBLE) ? + "246|%s exists, not written; use ! to override" : + "247|%s exists, not written"); + return (1); + } + + /* + * Don't write part of any existing file. Only test for the + * original file, the previous test catches anything else. + */ + if (!LF_ISSET(FS_ALL) && noname && !stat(name, &sb)) { + msgq(sp, M_ERR, LF_ISSET(FS_POSSIBLE) ? + "248|Partial file, not written; use ! to override" : + "249|Partial file, not written"); + return (1); + } + } + + /* + * Figure out if the file already exists -- if it doesn't, we display + * the "new file" message. The stat might not be necessary, but we + * just repeat it because it's easier than hacking the previous tests. + * The information is only used for the user message and modification + * time test, so we can ignore the obvious race condition. + * + * One final test. If we're not forcing or appending the current file, + * and we have a saved modification time, object if the file changed + * since we last edited or wrote it, and make them force it. + */ + if (stat(name, &sb)) + mtype = NEWFILE; + else { + if (noname && !LF_ISSET(FS_FORCE | FS_APPEND) && + ((F_ISSET(ep, F_DEVSET) && + (sb.st_dev != ep->mdev || sb.st_ino != ep->minode)) || + timespeccmp(&sb.st_mtim, &ep->mtim, !=))) { + msgq_str(sp, M_ERR, name, LF_ISSET(FS_POSSIBLE) ? +"250|%s: file modified more recently than this copy; use ! to override" : +"251|%s: file modified more recently than this copy"); + return (1); + } + + mtype = OLDFILE; + } + + /* Set flags to create, write, and either append or truncate. */ + oflags = O_CREAT | O_WRONLY | + (LF_ISSET(FS_APPEND) ? O_APPEND : O_TRUNC); + + /* Backup the file if requested. */ + if (!opts_empty(sp, O_BACKUP, 1) && + file_backup(sp, name, O_STR(sp, O_BACKUP)) && !LF_ISSET(FS_FORCE)) + return (1); + + /* Open the file. */ + if ((fd = open(name, oflags, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) < 0) { + if (errno == EACCES && LF_ISSET(FS_FORCE)) { + /* + * If the user owns the file but does not + * have write permission on it, grant it + * automatically for the duration of the + * opening of the file, if possible. + */ + struct stat sb; + mode_t fmode; + + if (stat(name, &sb) != 0) + goto fail_open; + fmode = sb.st_mode; + if (!(sb.st_mode & S_IWUSR) && sb.st_uid == getuid()) + fmode |= S_IWUSR; + else + goto fail_open; + if (chmod(name, fmode) != 0) + goto fail_open; + fd = open(name, oflags, S_IRUSR | S_IWUSR | + S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); + if (fd == -1) + goto fail_open; + (void)fchmod(fd, sb.st_mode); + goto success_open; + fail_open: + errno = EACCES; + } + msgq_str(sp, M_SYSERR, name, "%s"); + return (1); + } +success_open: + + /* Try and get a lock. */ + if (!noname && file_lock(sp, NULL, fd, 0) == LOCK_UNAVAIL) + msgq_str(sp, M_ERR, name, + "252|%s: write lock was unavailable"); + + /* + * Use stdio for buffering. + * + * XXX + * SVR4.2 requires the fdopen mode exactly match the original open + * mode, i.e. you have to open with "a" if appending. + */ + if ((fp = fdopen(fd, LF_ISSET(FS_APPEND) ? "a" : "w")) == NULL) { + msgq_str(sp, M_SYSERR, name, "%s"); + (void)close(fd); + return (1); + } + + /* Build fake addresses, if necessary. */ + if (fm == NULL) { + from.lno = 1; + from.cno = 0; + fm = &from; + if (db_last(sp, &to.lno)) + return (1); + to.cno = 0; + tm = &to; + } + + rval = ex_writefp(sp, name, fp, fm, tm, &nlno, &nch, 0); + + /* + * Save the new last modification time -- even if the write fails + * we re-init the time. That way the user can clean up the disk + * and rewrite without having to force it. + */ + if (noname) { + if (stat(name, &sb)) + timepoint_system(&ep->mtim); + else { + F_SET(ep, F_DEVSET); + ep->mdev = sb.st_dev; + ep->minode = sb.st_ino; + + ep->mtim = sb.st_mtim; + } + } + + /* + * If the write failed, complain loudly. ex_writefp() has already + * complained about the actual error, reinforce it if data was lost. + */ + if (rval) { + if (!LF_ISSET(FS_APPEND)) + msgq_str(sp, M_ERR, name, + "254|%s: WARNING: FILE TRUNCATED"); + return (1); + } + + /* + * Once we've actually written the file, it doesn't matter that the + * file name was changed -- if it was, we've already whacked it. + */ + F_CLR(frp, FR_NAMECHANGE); + + /* + * If wrote the entire file, and it wasn't by appending it to a file, + * clear the modified bit. If the file was written to the original + * file name and the file is a temporary, set the "no exit" bit. This + * permits the user to write the file and use it in the context of the + * filesystem, but still keeps them from discarding their changes by + * exiting. + */ + if (LF_ISSET(FS_ALL) && !LF_ISSET(FS_APPEND)) { + F_CLR(ep, F_MODIFIED); + if (F_ISSET(frp, FR_TMPFILE)) { + if (noname) + F_SET(frp, FR_TMPEXIT); + else + F_CLR(frp, FR_TMPEXIT); + } + } + + p = msg_print(sp, name, &nf); + switch (mtype) { + case NEWFILE: + msgstr = msg_cat(sp, + "256|%s: new file: %lu lines, %lu characters", NULL); + len = snprintf(buf, sizeof(buf), msgstr, p, nlno, nch); + break; + case OLDFILE: + msgstr = msg_cat(sp, LF_ISSET(FS_APPEND) ? + "315|%s: appended: %lu lines, %lu characters" : + "257|%s: %lu lines, %lu characters", NULL); + len = snprintf(buf, sizeof(buf), msgstr, p, nlno, nch); + break; + default: + abort(); + } + + /* + * There's a nasty problem with long path names. Cscope and tags files + * can result in long paths and vi will request a continuation key from + * the user. Unfortunately, the user has typed ahead, and chaos will + * result. If we assume that the characters in the filenames only take + * a single screen column each, we can trim the filename. + */ + s = buf; + if (len >= sp->cols) { + for (s = buf, t = buf + strlen(p); s < t && + (*s != '/' || len >= sp->cols - 3); ++s, --len); + if (s == t) + s = buf; + else { + *--s = '.'; /* Leading ellipses. */ + *--s = '.'; + *--s = '.'; + } + } + msgq(sp, M_INFO, "%s", s); + if (nf) + FREE_SPACE(sp, p, 0); + return (0); +} + +/* + * file_backup -- + * Backup the about-to-be-written file. + * + * XXX + * We do the backup by copying the entire file. It would be nice to do + * a rename instead, but: (1) both files may not fit and we want to fail + * before doing the rename; (2) the backup file may not be on the same + * disk partition as the file being written; (3) there may be optional + * file information (MACs, DACs, whatever) that we won't get right if we + * recreate the file. So, let's not risk it. + */ +static int +file_backup(SCR *sp, char *name, char *bname) +{ + struct dirent *dp; + struct stat sb; + DIR *dirp; + EXCMD cmd; + off_t off; + size_t blen; + int flags, maxnum, nr, num, nw, rfd, wfd, version; + char *bp, *estr, *p, *pct, *slash, *t, *wfname, buf[8192]; + CHAR_T *wp; + size_t wlen; + size_t nlen; + char *d = NULL; + + rfd = wfd = -1; + bp = estr = wfname = NULL; + + /* + * Open the current file for reading. Do this first, so that + * we don't exec a shell before the most likely failure point. + * If it doesn't exist, it's okay, there's just nothing to back + * up. + */ + errno = 0; + if ((rfd = open(name, O_RDONLY, 0)) < 0) { + if (errno == ENOENT) + return (0); + estr = name; + goto err; + } + + /* + * If the name starts with an 'N' character, add a version number + * to the name. Strip the leading N from the string passed to the + * expansion routines, for no particular reason. It would be nice + * to permit users to put the version number anywhere in the backup + * name, but there isn't a special character that we can use in the + * name, and giving a new character a special meaning leads to ugly + * hacks both here and in the supporting ex routines. + * + * Shell and file name expand the option's value. + */ + ex_cinit(sp, &cmd, 0, 0, 0, 0, 0); + if (bname[0] == 'N') { + version = 1; + ++bname; + } else + version = 0; + CHAR2INT(sp, bname, strlen(bname), wp, wlen); + if ((wp = v_wstrdup(sp, wp, wlen)) == NULL) + return (1); + if (argv_exp2(sp, &cmd, wp, wlen)) { + free(wp); + return (1); + } + free(wp); + + /* + * 0 args: impossible. + * 1 args: use it. + * >1 args: object, too many args. + */ + if (cmd.argc != 1) { + msgq_str(sp, M_ERR, bname, + "258|%s expanded into too many file names"); + (void)close(rfd); + return (1); + } + + /* + * If appending a version number, read through the directory, looking + * for file names that match the name followed by a number. Make all + * of the other % characters in name literal, so the user doesn't get + * surprised and sscanf doesn't drop core indirecting through pointers + * that don't exist. If any such files are found, increment its number + * by one. + */ + if (version) { + GET_SPACE_GOTOC(sp, bp, blen, cmd.argv[0]->len * 2 + 50); + INT2CHAR(sp, cmd.argv[0]->bp, cmd.argv[0]->len + 1, + p, nlen); + d = strdup(p); + p = d; + for (t = bp, slash = NULL; + p[0] != '\0'; *t++ = *p++) + if (p[0] == '%') { + if (p[1] != '%') + *t++ = '%'; + } else if (p[0] == '/') + slash = t; + pct = t; + *t++ = '%'; + *t++ = 'd'; + *t = '\0'; + + if (slash == NULL) { + dirp = opendir("."); + p = bp; + } else { + *slash = '\0'; + dirp = opendir(bp); + *slash = '/'; + p = slash + 1; + } + if (dirp == NULL) { + INT2CHAR(sp, cmd.argv[0]->bp, cmd.argv[0]->len + 1, + estr, nlen); + goto err; + } + + for (maxnum = 0; (dp = readdir(dirp)) != NULL;) + if (sscanf(dp->d_name, p, &num) == 1 && num > maxnum) + maxnum = num; + (void)closedir(dirp); + + /* Format the backup file name. */ + (void)snprintf(pct, blen - (pct - bp), "%d", maxnum + 1); + wfname = bp; + } else { + bp = NULL; + INT2CHAR(sp, cmd.argv[0]->bp, cmd.argv[0]->len + 1, + wfname, nlen); + } + + /* Open the backup file, avoiding lurkers. */ + if (stat(wfname, &sb) == 0) { + if (!S_ISREG(sb.st_mode)) { + msgq_str(sp, M_ERR, bname, + "259|%s: not a regular file"); + goto err; + } + if (sb.st_uid != getuid()) { + msgq_str(sp, M_ERR, bname, "260|%s: not owned by you"); + goto err; + } + if (sb.st_mode & (S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) { + msgq_str(sp, M_ERR, bname, + "261|%s: accessible by a user other than the owner"); + goto err; + } + flags = O_TRUNC; + } else + flags = O_CREAT | O_EXCL; + if ((wfd = open(wfname, flags | O_WRONLY, S_IRUSR | S_IWUSR)) < 0) { + estr = bname; + goto err; + } + + /* Copy the file's current contents to its backup value. */ + while ((nr = read(rfd, buf, sizeof(buf))) > 0) + for (off = 0; nr != 0; nr -= nw, off += nw) + if ((nw = write(wfd, buf + off, nr)) < 0) { + estr = wfname; + goto err; + } + if (nr < 0) { + estr = name; + goto err; + } + + if (close(rfd)) { + estr = name; + goto err; + } + if (close(wfd)) { + estr = wfname; + goto err; + } + free(d); + if (bp != NULL) + FREE_SPACE(sp, bp, blen); + return (0); + +alloc_err: +err: if (rfd != -1) + (void)close(rfd); + if (wfd != -1) { + (void)unlink(wfname); + (void)close(wfd); + } + if (estr) + msgq_str(sp, M_SYSERR, estr, "%s"); + free(d); + if (bp != NULL) + FREE_SPACE(sp, bp, blen); + return (1); +} + +/* + * file_encinit -- + * Read the first line and set the O_FILEENCODING. + */ +static void +file_encinit(SCR *sp) +{ +#if defined(USE_WIDECHAR) && defined(USE_ICONV) + size_t len; + char *p; + size_t blen = 0; + char buf[4096]; /* not need to be '\0'-terminated */ + recno_t ln = 1; + EXF *ep; + + ep = sp->ep; + + while (!db_rget(sp, ln++, &p, &len)) { + if (blen + len > sizeof(buf)) + len = sizeof(buf) - blen; + memcpy(buf + blen, p, len); + blen += len; + if (blen == sizeof(buf)) + break; + else + buf[blen++] = '\n'; + } + + /* + * Detect UTF-8 and fallback to the locale/preset encoding. + * + * XXX + * A manually set O_FILEENCODING indicates the "fallback + * encoding", but UTF-8, which can be safely detected, is not + * inherited from the old screen. + */ + if (looks_utf8(buf, blen) > 1) + o_set(sp, O_FILEENCODING, OS_STRDUP, "utf-8", 0); + else if (!O_ISSET(sp, O_FILEENCODING) || + !strcasecmp(O_STR(sp, O_FILEENCODING), "utf-8")) + o_set(sp, O_FILEENCODING, OS_STRDUP, codeset(), 0); + + conv_enc(sp, O_FILEENCODING, 0); +#endif +} + +/* + * file_comment -- + * Skip the first comment. + */ +static void +file_comment(SCR *sp) +{ + recno_t lno; + size_t len; + CHAR_T *p; + + for (lno = 1; !db_get(sp, lno, 0, &p, &len) && len == 0; ++lno); + if (p == NULL) + return; + if (p[0] == '#') { + F_SET(sp, SC_SCR_TOP); + while (!db_get(sp, ++lno, 0, &p, &len)) + if (len < 1 || p[0] != '#') { + sp->lno = lno; + return; + } + } else if (len > 1 && p[0] == '/' && p[1] == '*') { + F_SET(sp, SC_SCR_TOP); + do { + for (; len > 1; --len, ++p) + if (p[0] == '*' && p[1] == '/') { + sp->lno = lno; + return; + } + } while (!db_get(sp, ++lno, 0, &p, &len)); + } else if (len > 1 && p[0] == '/' && p[1] == '/') { + F_SET(sp, SC_SCR_TOP); + p += 2; + len -= 2; + do { + for (; len > 1; --len, ++p) + if (p[0] == '/' && p[1] == '/') { + sp->lno = lno; + return; + } + } while (!db_get(sp, ++lno, 0, &p, &len)); + } +} + +/* + * file_m1 -- + * First modification check routine. The :next, :prev, :rewind, :tag, + * :tagpush, :tagpop, ^^ modifications check. + * + * PUBLIC: int file_m1(SCR *, int, int); + */ +int +file_m1(SCR *sp, int force, int flags) +{ + EXF *ep; + + ep = sp->ep; + + /* If no file loaded, return no modifications. */ + if (ep == NULL) + return (0); + + /* + * If the file has been modified, we'll want to write it back or + * fail. If autowrite is set, we'll write it back automatically, + * unless force is also set. Otherwise, we fail unless forced or + * there's another open screen on this file. + */ + if (F_ISSET(ep, F_MODIFIED)) { + if (O_ISSET(sp, O_AUTOWRITE)) { + if (!force && file_aw(sp, flags)) + return (1); + } else if (ep->refcnt <= 1 && !force) { + msgq(sp, M_ERR, LF_ISSET(FS_POSSIBLE) ? +"262|File modified since last complete write; write or use ! to override" : +"263|File modified since last complete write; write or use :edit! to override"); + return (1); + } + } + + return (file_m3(sp, force)); +} + +/* + * file_m2 -- + * Second modification check routine. The :edit, :quit, :recover + * modifications check. + * + * PUBLIC: int file_m2(SCR *, int); + */ +int +file_m2(SCR *sp, int force) +{ + EXF *ep; + + ep = sp->ep; + + /* If no file loaded, return no modifications. */ + if (ep == NULL) + return (0); + + /* + * If the file has been modified, we'll want to fail, unless forced + * or there's another open screen on this file. + */ + if (F_ISSET(ep, F_MODIFIED) && ep->refcnt <= 1 && !force) { + msgq(sp, M_ERR, +"264|File modified since last complete write; write or use ! to override"); + return (1); + } + + return (file_m3(sp, force)); +} + +/* + * file_m3 -- + * Third modification check routine. + * + * PUBLIC: int file_m3(SCR *, int); + */ +int +file_m3(SCR *sp, int force) +{ + EXF *ep; + + ep = sp->ep; + + /* If no file loaded, return no modifications. */ + if (ep == NULL) + return (0); + + /* + * Don't exit while in a temporary files if the file was ever modified. + * The problem is that if the user does a ":wq", we write and quit, + * unlinking the temporary file. Not what the user had in mind at all. + * We permit writing to temporary files, so that user maps using file + * system names work with temporary files. + */ + if (F_ISSET(sp->frp, FR_TMPEXIT) && ep->refcnt <= 1 && !force) { + msgq(sp, M_ERR, + "265|File is a temporary; exit will discard modifications"); + return (1); + } + return (0); +} + +/* + * file_aw -- + * Autowrite routine. If modified, autowrite is set and the readonly bit + * is not set, write the file. A routine so there's a place to put the + * comment. + * + * PUBLIC: int file_aw(SCR *, int); + */ +int +file_aw(SCR *sp, int flags) +{ + if (!F_ISSET(sp->ep, F_MODIFIED)) + return (0); + if (!O_ISSET(sp, O_AUTOWRITE)) + return (0); + + /* + * !!! + * Historic 4BSD vi attempted to write the file if autowrite was set, + * regardless of the writeability of the file (as defined by the file + * readonly flag). System V changed this as some point, not attempting + * autowrite if the file was readonly. This feels like a bug fix to + * me (e.g. the principle of least surprise is violated if readonly is + * set and vi writes the file), so I'm compatible with System V. + */ + if (O_ISSET(sp, O_READONLY)) { + msgq(sp, M_INFO, + "266|File readonly, modifications not auto-written"); + return (1); + } + return (file_write(sp, NULL, NULL, NULL, flags)); +} + +/* + * set_alt_name -- + * Set the alternate pathname. + * + * Set the alternate pathname. It's a routine because I wanted some place + * to hang this comment. The alternate pathname (normally referenced using + * the special character '#' during file expansion and in the vi ^^ command) + * is set by almost all ex commands that take file names as arguments. The + * rules go something like this: + * + * 1: If any ex command takes a file name as an argument (except for the + * :next command), the alternate pathname is set to that file name. + * This excludes the command ":e" and ":w !command" as no file name + * was specified. Note, historically, the :source command did not set + * the alternate pathname. It does in nvi, for consistency. + * + * 2: However, if any ex command sets the current pathname, e.g. the + * ":e file" or ":rew" commands succeed, then the alternate pathname + * is set to the previous file's current pathname, if it had one. + * This includes the ":file" command and excludes the ":e" command. + * So, by rule #1 and rule #2, if ":edit foo" fails, the alternate + * pathname will be "foo", if it succeeds, the alternate pathname will + * be the previous current pathname. The ":e" command will not set + * the alternate or current pathnames regardless. + * + * 3: However, if it's a read or write command with a file argument and + * the current pathname has not yet been set, the file name becomes + * the current pathname, and the alternate pathname is unchanged. + * + * If the user edits a temporary file, there may be times when there is no + * alternative file name. A name argument of NULL turns it off. + * + * PUBLIC: void set_alt_name(SCR *, char *); + */ +void +set_alt_name(SCR *sp, char *name) +{ + free(sp->alt_name); + if (name == NULL) + sp->alt_name = NULL; + else if ((sp->alt_name = strdup(name)) == NULL) + msgq(sp, M_SYSERR, NULL); +} + +/* + * file_lock -- + * Get an exclusive lock on a file. + * + * PUBLIC: lockr_t file_lock(SCR *, char *, int, int); + */ +lockr_t +file_lock(SCR *sp, char *name, int fd, int iswrite) +{ + if (!O_ISSET(sp, O_LOCKFILES)) + return (LOCK_SUCCESS); + + /* + * !!! + * We need to distinguish a lock not being available for the file + * from the file system not supporting locking. Flock is documented + * as returning EWOULDBLOCK; add EAGAIN for good measure, and assume + * they are the former. There's no portable way to do this. + */ + errno = 0; + if (!flock(fd, LOCK_EX | LOCK_NB)) { + fcntl(fd, F_SETFD, 1); + return (LOCK_SUCCESS); + } + return (errno == EAGAIN +#ifdef EWOULDBLOCK + || errno == EWOULDBLOCK +#endif + ? LOCK_UNAVAIL : LOCK_FAILED); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/common/exf.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/common/key.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/common/key.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/common/key.c (revision 366308) @@ -0,0 +1,839 @@ +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1991, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "../vi/vi.h" + +static int v_event_append(SCR *, EVENT *); +static int v_event_grow(SCR *, int); +static int v_key_cmp(const void *, const void *); +static void v_keyval(SCR *, int, scr_keyval_t); +static void v_sync(SCR *, int); + +/* + * !!! + * Historic vi always used: + * + * ^D: autoindent deletion + * ^H: last character deletion + * ^W: last word deletion + * ^Q: quote the next character (if not used in flow control). + * ^V: quote the next character + * + * regardless of the user's choices for these characters. The user's erase + * and kill characters worked in addition to these characters. Nvi wires + * down the above characters, but in addition permits the VEOF, VERASE, VKILL + * and VWERASE characters described by the user's termios structure. + * + * Ex was not consistent with this scheme, as it historically ran in tty + * cooked mode. This meant that the scroll command and autoindent erase + * characters were mapped to the user's EOF character, and the character + * and word deletion characters were the user's tty character and word + * deletion characters. This implementation makes it all consistent, as + * described above for vi. + * + * !!! + * This means that all screens share a special key set. + */ +KEYLIST keylist[] = { + {K_BACKSLASH, '\\'}, /* \ */ + {K_CARAT, '^'}, /* ^ */ + {K_CNTRLD, '\004'}, /* ^D */ + {K_CNTRLR, '\022'}, /* ^R */ + {K_CNTRLT, '\024'}, /* ^T */ + {K_CNTRLZ, '\032'}, /* ^Z */ + {K_COLON, ':'}, /* : */ + {K_CR, '\r'}, /* \r */ + {K_ESCAPE, '\033'}, /* ^[ */ + {K_FORMFEED, '\f'}, /* \f */ + {K_HEXCHAR, '\030'}, /* ^X */ + {K_NL, '\n'}, /* \n */ + {K_RIGHTBRACE, '}'}, /* } */ + {K_RIGHTPAREN, ')'}, /* ) */ + {K_TAB, '\t'}, /* \t */ + {K_VERASE, '\b'}, /* \b */ + {K_VKILL, '\025'}, /* ^U */ + {K_VLNEXT, '\021'}, /* ^Q */ + {K_VLNEXT, '\026'}, /* ^V */ + {K_VWERASE, '\027'}, /* ^W */ + {K_ZERO, '0'}, /* 0 */ + +#define ADDITIONAL_CHARACTERS 4 + {K_NOTUSED, 0}, /* VEOF, VERASE, VKILL, VWERASE */ + {K_NOTUSED, 0}, + {K_NOTUSED, 0}, + {K_NOTUSED, 0}, +}; +static int nkeylist = + (sizeof(keylist) / sizeof(keylist[0])) - ADDITIONAL_CHARACTERS; + +/* + * v_key_init -- + * Initialize the special key lookup table. + * + * PUBLIC: int v_key_init(SCR *); + */ +int +v_key_init(SCR *sp) +{ + int ch; + GS *gp; + KEYLIST *kp; + int cnt; + + gp = sp->gp; + + v_key_ilookup(sp); + + v_keyval(sp, K_CNTRLD, KEY_VEOF); + v_keyval(sp, K_VERASE, KEY_VERASE); + v_keyval(sp, K_VKILL, KEY_VKILL); + v_keyval(sp, K_VWERASE, KEY_VWERASE); + + /* Sort the special key list. */ + qsort(keylist, nkeylist, sizeof(keylist[0]), v_key_cmp); + + /* Initialize the fast lookup table. */ + for (kp = keylist, cnt = nkeylist; cnt--; ++kp) + gp->special_key[kp->ch] = kp->value; + + /* Find a non-printable character to use as a message separator. */ + for (ch = 1; ch <= UCHAR_MAX; ++ch) + if (!isprint(ch)) { + gp->noprint = ch; + break; + } + if (ch != gp->noprint) { + msgq(sp, M_ERR, "079|No non-printable character found"); + return (1); + } + return (0); +} + +/* + * v_keyval -- + * Set key values. + * + * We've left some open slots in the keylist table, and if these values exist, + * we put them into place. Note, they may reset (or duplicate) values already + * in the table, so we check for that first. + */ +static void +v_keyval(SCR *sp, int val, scr_keyval_t name) +{ + KEYLIST *kp; + CHAR_T ch; + int dne; + + /* Get the key's value from the screen. */ + if (sp->gp->scr_keyval(sp, name, &ch, &dne)) + return; + if (dne) + return; + + /* Check for duplication. */ + for (kp = keylist; kp->value != K_NOTUSED; ++kp) + if (kp->ch == ch) { + kp->value = val; + return; + } + + /* Add a new entry. */ + if (kp->value == K_NOTUSED) { + keylist[nkeylist].ch = ch; + keylist[nkeylist].value = val; + ++nkeylist; + } +} + +/* + * v_key_ilookup -- + * Build the fast-lookup key display array. + * + * PUBLIC: void v_key_ilookup(SCR *); + */ +void +v_key_ilookup(SCR *sp) +{ + UCHAR_T ch; + char *p, *t; + GS *gp; + size_t len; + + for (gp = sp->gp, ch = 0;; ++ch) { + for (p = gp->cname[ch].name, t = v_key_name(sp, ch), + len = gp->cname[ch].len = sp->clen; len--;) + *p++ = *t++; + if (ch == MAX_FAST_KEY) + break; + } +} + +/* + * v_key_len -- + * Return the length of the string that will display the key. + * This routine is the backup for the KEY_LEN() macro. + * + * PUBLIC: size_t v_key_len(SCR *, ARG_CHAR_T); + */ +size_t +v_key_len(SCR *sp, ARG_CHAR_T ch) +{ + (void)v_key_name(sp, ch); + return (sp->clen); +} + +/* + * v_key_name -- + * Return the string that will display the key. This routine + * is the backup for the KEY_NAME() macro. + * + * PUBLIC: char *v_key_name(SCR *, ARG_CHAR_T); + */ +char * +v_key_name(SCR *sp, ARG_CHAR_T ach) +{ + static const char hexdigit[] = "0123456789abcdef"; + static const char octdigit[] = "01234567"; + int ch; + size_t len; + char *chp; + + /* + * Cache the last checked character. It won't be a problem + * since nvi will rescan the mapping when settings changed. + */ + if (ach && sp->lastc == ach) + return (sp->cname); + sp->lastc = ach; + +#ifdef USE_WIDECHAR + len = wctomb(sp->cname, ach); + if (len > MB_CUR_MAX) +#endif + sp->cname[(len = 1)-1] = (u_char)ach; + + ch = (u_char)sp->cname[0]; + sp->cname[len] = '\0'; + + /* See if the character was explicitly declared printable or not. */ + if ((chp = O_STR(sp, O_PRINT)) != NULL) + if (strstr(chp, sp->cname) != NULL) + goto done; + if ((chp = O_STR(sp, O_NOPRINT)) != NULL) + if (strstr(chp, sp->cname) != NULL) + goto nopr; + + /* + * Historical (ARPA standard) mappings. Printable characters are left + * alone. Control characters less than 0x20 are represented as '^' + * followed by the character offset from the '@' character in the ASCII + * character set. Del (0x7f) is represented as '^' followed by '?'. + * + * XXX + * The following code depends on the current locale being identical to + * the ASCII map from 0x40 to 0x5f (since 0x1f + 0x40 == 0x5f). I'm + * told that this is a reasonable assumption... + * + * XXX + * The code prints non-printable wide characters in 4 or 5 digits + * Unicode escape sequences, so only supports plane 0 to 15. + */ + if (CAN_PRINT(sp, ach)) + goto done; +nopr: if (iscntrl(ch) && (ch < 0x20 || ch == 0x7f)) { + sp->cname[0] = '^'; + sp->cname[1] = ch == 0x7f ? '?' : '@' + ch; + len = 2; + goto done; + } +#ifdef USE_WIDECHAR + if (INTISWIDE(ach)) { + int uc = -1; + + if (!strcmp(codeset(), "UTF-8")) + uc = decode_utf8(sp->cname); +#ifdef USE_ICONV + else { + char buf[sizeof(sp->cname)] = ""; + size_t left = sizeof(sp->cname); + char *in = sp->cname; + char *out = buf; + iconv(sp->conv.id[IC_IE_TO_UTF16], + (iconv_src_t)&in, &len, &out, &left); + iconv(sp->conv.id[IC_IE_TO_UTF16], + NULL, NULL, NULL, NULL); + uc = decode_utf16(buf, 1); + } +#endif + if (uc >= 0) { + len = snprintf(sp->cname, sizeof(sp->cname), + uc < 0x10000 ? "\\u%04x" : "\\U%05X", uc); + goto done; + } + } +#endif + if (O_ISSET(sp, O_OCTAL)) { + sp->cname[0] = '\\'; + sp->cname[1] = octdigit[(ch & 0300) >> 6]; + sp->cname[2] = octdigit[(ch & 070) >> 3]; + sp->cname[3] = octdigit[ ch & 07 ]; + } else { + sp->cname[0] = '\\'; + sp->cname[1] = 'x'; + sp->cname[2] = hexdigit[(ch & 0xf0) >> 4]; + sp->cname[3] = hexdigit[ ch & 0x0f ]; + } + len = 4; +done: sp->cname[sp->clen = len] = '\0'; + return (sp->cname); +} + +/* + * v_key_val -- + * Fill in the value for a key. This routine is the backup + * for the KEY_VAL() macro. + * + * PUBLIC: e_key_t v_key_val(SCR *, ARG_CHAR_T); + */ +e_key_t +v_key_val(SCR *sp, ARG_CHAR_T ch) +{ + KEYLIST k, *kp; + + k.ch = ch; + kp = bsearch(&k, keylist, nkeylist, sizeof(keylist[0]), v_key_cmp); + return (kp == NULL ? K_NOTUSED : kp->value); +} + +/* + * v_event_push -- + * Push events/keys onto the front of the buffer. + * + * There is a single input buffer in ex/vi. Characters are put onto the + * end of the buffer by the terminal input routines, and pushed onto the + * front of the buffer by various other functions in ex/vi. Each key has + * an associated flag value, which indicates if it has already been quoted, + * and if it is the result of a mapping or an abbreviation. + * + * PUBLIC: int v_event_push(SCR *, EVENT *, CHAR_T *, size_t, u_int); + */ +int +v_event_push(SCR *sp, + EVENT *p_evp, /* Push event. */ + CHAR_T *p_s, /* Push characters. */ + size_t nitems, /* Number of items to push. */ + u_int flags) /* CH_* flags. */ +{ + EVENT *evp; + GS *gp; + size_t total; + + /* If we have room, stuff the items into the buffer. */ + gp = sp->gp; + if (nitems <= gp->i_next || + (gp->i_event != NULL && gp->i_cnt == 0 && nitems <= gp->i_nelem)) { + if (gp->i_cnt != 0) + gp->i_next -= nitems; + goto copy; + } + + /* + * If there are currently items in the queue, shift them up, + * leaving some extra room. Get enough space plus a little + * extra. + */ +#define TERM_PUSH_SHIFT 30 + total = gp->i_cnt + gp->i_next + nitems + TERM_PUSH_SHIFT; + if (total >= gp->i_nelem && v_event_grow(sp, MAX(total, 64))) + return (1); + if (gp->i_cnt) + memmove(gp->i_event + TERM_PUSH_SHIFT + nitems, + gp->i_event + gp->i_next, gp->i_cnt * sizeof(EVENT)); + gp->i_next = TERM_PUSH_SHIFT; + + /* Put the new items into the queue. */ +copy: gp->i_cnt += nitems; + for (evp = gp->i_event + gp->i_next; nitems--; ++evp) { + if (p_evp != NULL) + *evp = *p_evp++; + else { + evp->e_event = E_CHARACTER; + evp->e_c = *p_s++; + evp->e_value = KEY_VAL(sp, evp->e_c); + F_INIT(&evp->e_ch, flags); + } + } + return (0); +} + +/* + * v_event_append -- + * Append events onto the tail of the buffer. + */ +static int +v_event_append(SCR *sp, EVENT *argp) +{ + CHAR_T *s; /* Characters. */ + EVENT *evp; + GS *gp; + size_t nevents; /* Number of events. */ + + /* Grow the buffer as necessary. */ + nevents = argp->e_event == E_STRING ? argp->e_len : 1; + gp = sp->gp; + if (gp->i_event == NULL || + nevents > gp->i_nelem - (gp->i_next + gp->i_cnt)) + v_event_grow(sp, MAX(nevents, 64)); + evp = gp->i_event + gp->i_next + gp->i_cnt; + gp->i_cnt += nevents; + + /* Transform strings of characters into single events. */ + if (argp->e_event == E_STRING) + for (s = argp->e_csp; nevents--; ++evp) { + evp->e_event = E_CHARACTER; + evp->e_c = *s++; + evp->e_value = KEY_VAL(sp, evp->e_c); + evp->e_flags = 0; + } + else + *evp = *argp; + return (0); +} + +/* Remove events from the queue. */ +#define QREM(len) do { \ + if ((gp->i_cnt -= len) == 0) \ + gp->i_next = 0; \ + else \ + gp->i_next += len; \ +} while (0) + +/* + * v_event_get -- + * Return the next event. + * + * !!! + * The flag EC_NODIGIT probably needs some explanation. First, the idea of + * mapping keys is that one or more keystrokes act like a function key. + * What's going on is that vi is reading a number, and the character following + * the number may or may not be mapped (EC_MAPCOMMAND). For example, if the + * user is entering the z command, a valid command is "z40+", and we don't want + * to map the '+', i.e. if '+' is mapped to "xxx", we don't want to change it + * into "z40xxx". However, if the user enters "35x", we want to put all of the + * characters through the mapping code. + * + * Historical practice is a bit muddled here. (Surprise!) It always permitted + * mapping digits as long as they weren't the first character of the map, e.g. + * ":map ^A1 xxx" was okay. It also permitted the mapping of the digits 1-9 + * (the digit 0 was a special case as it doesn't indicate the start of a count) + * as the first character of the map, but then ignored those mappings. While + * it's probably stupid to map digits, vi isn't your mother. + * + * The way this works is that the EC_MAPNODIGIT causes term_key to return the + * end-of-digit without "looking" at the next character, i.e. leaving it as the + * user entered it. Presumably, the next term_key call will tell us how the + * user wants it handled. + * + * There is one more complication. Users might map keys to digits, and, as + * it's described above, the commands: + * + * :map g 1G + * d2g + * + * would return the keys "d21G", when the user probably wanted + * "d21G". So, if a map starts off with a digit we continue as + * before, otherwise, we pretend we haven't mapped the character, and return + * . + * + * Now that that's out of the way, let's talk about Energizer Bunny macros. + * It's easy to create macros that expand to a loop, e.g. map x 3x. It's + * fairly easy to detect this example, because it's all internal to term_key. + * If we're expanding a macro and it gets big enough, at some point we can + * assume it's looping and kill it. The examples that are tough are the ones + * where the parser is involved, e.g. map x "ayyx"byy. We do an expansion + * on 'x', and get "ayyx"byy. We then return the first 4 characters, and then + * find the looping macro again. There is no way that we can detect this + * without doing a full parse of the command, because the character that might + * cause the loop (in this case 'x') may be a literal character, e.g. the map + * map x "ayy"xyy"byy is perfectly legal and won't cause a loop. + * + * Historic vi tried to detect looping macros by disallowing obvious cases in + * the map command, maps that that ended with the same letter as they started + * (which wrongly disallowed "map x 'x"), and detecting macros that expanded + * too many times before keys were returned to the command parser. It didn't + * get many (most?) of the tricky cases right, however, and it was certainly + * possible to create macros that ran forever. And, even if it did figure out + * what was going on, the user was usually tossed into ex mode. Finally, any + * changes made before vi realized that the macro was recursing were left in + * place. We recover gracefully, but the only recourse the user has in an + * infinite macro loop is to interrupt. + * + * !!! + * It is historic practice that mapping characters to themselves as the first + * part of the mapped string was legal, and did not cause infinite loops, i.e. + * ":map! { {^M^T" and ":map n nz." were known to work. The initial, matching + * characters were returned instead of being remapped. + * + * !!! + * It is also historic practice that the macro "map ] ]]^" caused a single ] + * keypress to behave as the command ]] (the ^ got the map past the vi check + * for "tail recursion"). Conversely, the mapping "map n nn^" went recursive. + * What happened was that, in the historic vi, maps were expanded as the keys + * were retrieved, but not all at once and not centrally. So, the keypress ] + * pushed ]]^ on the stack, and then the first ] from the stack was passed to + * the ]] command code. The ]] command then retrieved a key without entering + * the mapping code. This could bite us anytime a user has a map that depends + * on secondary keys NOT being mapped. I can't see any possible way to make + * this work in here without the complete abandonment of Rationality Itself. + * + * XXX + * The final issue is recovery. It would be possible to undo all of the work + * that was done by the macro if we entered a record into the log so that we + * knew when the macro started, and, in fact, this might be worth doing at some + * point. Given that this might make the log grow unacceptably (consider that + * cursor keys are done with maps), for now we leave any changes made in place. + * + * PUBLIC: int v_event_get(SCR *, EVENT *, int, u_int32_t); + */ +int +v_event_get(SCR *sp, EVENT *argp, int timeout, u_int32_t flags) +{ + EVENT *evp, ev; + GS *gp; + SEQ *qp; + int init_nomap, ispartial, istimeout, remap_cnt; + + gp = sp->gp; + + /* If simply checking for interrupts, argp may be NULL. */ + if (argp == NULL) + argp = &ev; + +retry: istimeout = remap_cnt = 0; + + /* + * If the queue isn't empty and we're timing out for characters, + * return immediately. + */ + if (gp->i_cnt != 0 && LF_ISSET(EC_TIMEOUT)) + return (0); + + /* + * If the queue is empty, we're checking for interrupts, or we're + * timing out for characters, get more events. + */ + if (gp->i_cnt == 0 || LF_ISSET(EC_INTERRUPT | EC_TIMEOUT)) { + /* + * If we're reading new characters, check any scripting + * windows for input. + */ + if (F_ISSET(gp, G_SCRWIN) && sscr_input(sp)) + return (1); +loop: if (gp->scr_event(sp, argp, + LF_ISSET(EC_INTERRUPT | EC_QUOTED | EC_RAW), timeout)) + return (1); + switch (argp->e_event) { + case E_ERR: + case E_SIGHUP: + case E_SIGTERM: + /* + * Fatal conditions cause the file to be synced to + * disk immediately. + */ + v_sync(sp, RCV_ENDSESSION | RCV_PRESERVE | + (argp->e_event == E_SIGTERM ? 0: RCV_EMAIL)); + return (1); + case E_TIMEOUT: + istimeout = 1; + break; + case E_INTERRUPT: + /* Set the global interrupt flag. */ + F_SET(sp->gp, G_INTERRUPTED); + + /* + * If the caller was interested in interrupts, return + * immediately. + */ + if (LF_ISSET(EC_INTERRUPT)) + return (0); + goto append; + default: +append: if (v_event_append(sp, argp)) + return (1); + break; + } + } + + /* + * If the caller was only interested in interrupts or timeouts, return + * immediately. (We may have gotten characters, and that's okay, they + * were queued up for later use.) + */ + if (LF_ISSET(EC_INTERRUPT | EC_TIMEOUT)) + return (0); + +newmap: evp = &gp->i_event[gp->i_next]; + + /* + * If the next event in the queue isn't a character event, return + * it, we're done. + */ + if (evp->e_event != E_CHARACTER) { + *argp = *evp; + QREM(1); + return (0); + } + + /* + * If the key isn't mappable because: + * + * + ... the timeout has expired + * + ... it's not a mappable key + * + ... neither the command or input map flags are set + * + ... there are no maps that can apply to it + * + * return it forthwith. + */ + if (istimeout || F_ISSET(&evp->e_ch, CH_NOMAP) || + !LF_ISSET(EC_MAPCOMMAND | EC_MAPINPUT) || + ((evp->e_c & ~MAX_BIT_SEQ) == 0 && + !bit_test(gp->seqb, evp->e_c))) + goto nomap; + + /* Search the map. */ + qp = seq_find(sp, NULL, evp, NULL, gp->i_cnt, + LF_ISSET(EC_MAPCOMMAND) ? SEQ_COMMAND : SEQ_INPUT, &ispartial); + + /* + * If get a partial match, get more characters and retry the map. + * If time out without further characters, return the characters + * unmapped. + * + * !!! + * characters are a problem. Cursor keys start with + * characters, so there's almost always a map in place that begins with + * an character. If we timeout keys in the same way + * that we timeout other keys, the user will get a noticeable pause as + * they enter to terminate input mode. If key timeout is set + * for a slow link, users will get an even longer pause. Nvi used to + * simply timeout characters at 1/10th of a second, but this + * loses over PPP links where the latency is greater than 100Ms. + */ + if (ispartial) { + if (O_ISSET(sp, O_TIMEOUT)) + timeout = (evp->e_value == K_ESCAPE ? + O_VAL(sp, O_ESCAPETIME) : + O_VAL(sp, O_KEYTIME)) * 100; + else + timeout = 0; + goto loop; + } + + /* If no map, return the character. */ + if (qp == NULL) { +nomap: if (!ISDIGIT(evp->e_c) && LF_ISSET(EC_MAPNODIGIT)) + goto not_digit; + *argp = *evp; + QREM(1); + return (0); + } + + /* + * If looking for the end of a digit string, and the first character + * of the map is it, pretend we haven't seen the character. + */ + if (LF_ISSET(EC_MAPNODIGIT) && + qp->output != NULL && !ISDIGIT(qp->output[0])) { +not_digit: argp->e_c = CH_NOT_DIGIT; + argp->e_value = K_NOTUSED; + argp->e_event = E_CHARACTER; + F_INIT(&argp->e_ch, 0); + return (0); + } + + /* Find out if the initial segments are identical. */ + init_nomap = !e_memcmp(qp->output, &gp->i_event[gp->i_next], qp->ilen); + + /* Delete the mapped characters from the queue. */ + QREM(qp->ilen); + + /* If keys mapped to nothing, go get more. */ + if (qp->output == NULL) + goto retry; + + /* If remapping characters... */ + if (O_ISSET(sp, O_REMAP)) { + /* + * Periodically check for interrupts. Always check the first + * time through, because it's possible to set up a map that + * will return a character every time, but will expand to more, + * e.g. "map! a aaaa" will always return a 'a', but we'll never + * get anywhere useful. + */ + if ((++remap_cnt == 1 || remap_cnt % 10 == 0) && + (gp->scr_event(sp, &ev, + EC_INTERRUPT, 0) || ev.e_event == E_INTERRUPT)) { + F_SET(sp->gp, G_INTERRUPTED); + argp->e_event = E_INTERRUPT; + return (0); + } + + /* + * If an initial part of the characters mapped, they are not + * further remapped -- return the first one. Push the rest + * of the characters, or all of the characters if no initial + * part mapped, back on the queue. + */ + if (init_nomap) { + if (v_event_push(sp, NULL, qp->output + qp->ilen, + qp->olen - qp->ilen, CH_MAPPED)) + return (1); + if (v_event_push(sp, NULL, + qp->output, qp->ilen, CH_NOMAP | CH_MAPPED)) + return (1); + evp = &gp->i_event[gp->i_next]; + goto nomap; + } + if (v_event_push(sp, NULL, qp->output, qp->olen, CH_MAPPED)) + return (1); + goto newmap; + } + + /* Else, push the characters on the queue and return one. */ + if (v_event_push(sp, NULL, qp->output, qp->olen, CH_MAPPED | CH_NOMAP)) + return (1); + + goto nomap; +} + +/* + * v_sync -- + * Walk the screen lists, sync'ing files to their backup copies. + */ +static void +v_sync(SCR *sp, int flags) +{ + GS *gp; + + gp = sp->gp; + TAILQ_FOREACH(sp, gp->dq, q) + rcv_sync(sp, flags); + TAILQ_FOREACH(sp, gp->hq, q) + rcv_sync(sp, flags); +} + +/* + * v_event_err -- + * Unexpected event. + * + * PUBLIC: void v_event_err(SCR *, EVENT *); + */ +void +v_event_err(SCR *sp, EVENT *evp) +{ + switch (evp->e_event) { + case E_CHARACTER: + msgq(sp, M_ERR, "276|Unexpected character event"); + break; + case E_EOF: + msgq(sp, M_ERR, "277|Unexpected end-of-file event"); + break; + case E_INTERRUPT: + msgq(sp, M_ERR, "279|Unexpected interrupt event"); + break; + case E_REPAINT: + msgq(sp, M_ERR, "281|Unexpected repaint event"); + break; + case E_STRING: + msgq(sp, M_ERR, "285|Unexpected string event"); + break; + case E_TIMEOUT: + msgq(sp, M_ERR, "286|Unexpected timeout event"); + break; + case E_WRESIZE: + msgq(sp, M_ERR, "316|Unexpected resize event"); + break; + + /* + * Theoretically, none of these can occur, as they're handled at the + * top editor level. + */ + case E_ERR: + case E_SIGHUP: + case E_SIGTERM: + default: + abort(); + } + + /* Free any allocated memory. */ + free(evp->e_asp); +} + +/* + * v_event_flush -- + * Flush any flagged keys, returning if any keys were flushed. + * + * PUBLIC: int v_event_flush(SCR *, u_int); + */ +int +v_event_flush(SCR *sp, u_int flags) +{ + GS *gp; + int rval; + + for (rval = 0, gp = sp->gp; gp->i_cnt != 0 && + F_ISSET(&gp->i_event[gp->i_next].e_ch, flags); rval = 1) + QREM(1); + return (rval); +} + +/* + * v_event_grow -- + * Grow the terminal queue. + */ +static int +v_event_grow(SCR *sp, int add) +{ + GS *gp; + size_t new_nelem, olen; + + gp = sp->gp; + new_nelem = gp->i_nelem + add; + olen = gp->i_nelem * sizeof(gp->i_event[0]); + BINC_RET(sp, EVENT, gp->i_event, olen, new_nelem * sizeof(gp->i_event[0])); + gp->i_nelem = olen / sizeof(gp->i_event[0]); + return (0); +} + +/* + * v_key_cmp -- + * Compare two keys for sorting. + */ +static int +v_key_cmp(const void *ap, const void *bp) +{ + return (((KEYLIST *)ap)->ch - ((KEYLIST *)bp)->ch); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/common/key.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/common/log.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/common/log.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/common/log.c (revision 366308) @@ -0,0 +1,736 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" + +/* + * The log consists of records, each containing a type byte and a variable + * length byte string, as follows: + * + * LOG_CURSOR_INIT MARK + * LOG_CURSOR_END MARK + * LOG_LINE_APPEND recno_t char * + * LOG_LINE_DELETE recno_t char * + * LOG_LINE_INSERT recno_t char * + * LOG_LINE_RESET_F recno_t char * + * LOG_LINE_RESET_B recno_t char * + * LOG_MARK LMARK + * + * We do before image physical logging. This means that the editor layer + * MAY NOT modify records in place, even if simply deleting or overwriting + * characters. Since the smallest unit of logging is a line, we're using + * up lots of space. This may eventually have to be reduced, probably by + * doing logical logging, which is a much cooler database phrase. + * + * The implementation of the historic vi 'u' command, using roll-forward and + * roll-back, is simple. Each set of changes has a LOG_CURSOR_INIT record, + * followed by a number of other records, followed by a LOG_CURSOR_END record. + * LOG_LINE_RESET records come in pairs. The first is a LOG_LINE_RESET_B + * record, and is the line before the change. The second is LOG_LINE_RESET_F, + * and is the line after the change. Roll-back is done by backing up to the + * first LOG_CURSOR_INIT record before a change. Roll-forward is done in a + * similar fashion. + * + * The 'U' command is implemented by rolling backward to a LOG_CURSOR_END + * record for a line different from the current one. It should be noted that + * this means that a subsequent 'u' command will make a change based on the + * new position of the log's cursor. This is okay, and, in fact, historic vi + * behaved that way. + */ + +static int log_cursor1(SCR *, int); +static void log_err(SCR *, char *, int); +#if defined(DEBUG) && 0 +static void log_trace(SCR *, char *, recno_t, u_char *); +#endif +static int apply_with(int (*)(SCR *, recno_t, CHAR_T *, size_t), + SCR *, recno_t, u_char *, size_t); + +/* Try and restart the log on failure, i.e. if we run out of memory. */ +#define LOG_ERR do { \ + log_err(sp, __FILE__, __LINE__); \ + return (1); \ +} while (0) + +/* offset of CHAR_T string in log needs to be aligned on some systems + * because it is passed to db_set as a string + */ +typedef struct { + char data[sizeof(u_char) /* type */ + sizeof(recno_t)]; + CHAR_T str[1]; +} log_t; +#define CHAR_T_OFFSET ((char *)(((log_t*)0)->str) - (char *)0) + +/* + * log_init -- + * Initialize the logging subsystem. + * + * PUBLIC: int log_init(SCR *, EXF *); + */ +int +log_init(SCR *sp, EXF *ep) +{ + /* + * !!! + * ep MAY NOT BE THE SAME AS sp->ep, DON'T USE THE LATTER. + * + * Initialize the buffer. The logging subsystem has its own + * buffers because the global ones are almost by definition + * going to be in use when the log runs. + */ + ep->l_lp = NULL; + ep->l_len = 0; + ep->l_cursor.lno = 1; /* XXX Any valid recno. */ + ep->l_cursor.cno = 0; + ep->l_high = ep->l_cur = 1; + + ep->log = dbopen(NULL, O_CREAT | O_NONBLOCK | O_RDWR, + S_IRUSR | S_IWUSR, DB_RECNO, NULL); + if (ep->log == NULL) { + msgq(sp, M_SYSERR, "009|Log file"); + F_SET(ep, F_NOLOG); + return (1); + } + + return (0); +} + +/* + * log_end -- + * Close the logging subsystem. + * + * PUBLIC: int log_end(SCR *, EXF *); + */ +int +log_end(SCR *sp, EXF *ep) +{ + /* + * !!! + * ep MAY NOT BE THE SAME AS sp->ep, DON'T USE THE LATTER. + */ + if (ep->log != NULL) { + (void)(ep->log->close)(ep->log); + ep->log = NULL; + } + free(ep->l_lp); + ep->l_lp = NULL; + ep->l_len = 0; + ep->l_cursor.lno = 1; /* XXX Any valid recno. */ + ep->l_cursor.cno = 0; + ep->l_high = ep->l_cur = 1; + return (0); +} + +/* + * log_cursor -- + * Log the current cursor position, starting an event. + * + * PUBLIC: int log_cursor(SCR *); + */ +int +log_cursor(SCR *sp) +{ + EXF *ep; + + ep = sp->ep; + if (F_ISSET(ep, F_NOLOG)) + return (0); + + /* + * If any changes were made since the last cursor init, + * put out the ending cursor record. + */ + if (ep->l_cursor.lno == OOBLNO) { + ep->l_cursor.lno = sp->lno; + ep->l_cursor.cno = sp->cno; + return (log_cursor1(sp, LOG_CURSOR_END)); + } + ep->l_cursor.lno = sp->lno; + ep->l_cursor.cno = sp->cno; + return (0); +} + +/* + * log_cursor1 -- + * Actually push a cursor record out. + */ +static int +log_cursor1(SCR *sp, int type) +{ + DBT data, key; + EXF *ep; + + ep = sp->ep; + + BINC_RETC(sp, ep->l_lp, ep->l_len, sizeof(u_char) + sizeof(MARK)); + ep->l_lp[0] = type; + memmove(ep->l_lp + sizeof(u_char), &ep->l_cursor, sizeof(MARK)); + + key.data = &ep->l_cur; + key.size = sizeof(recno_t); + data.data = ep->l_lp; + data.size = sizeof(u_char) + sizeof(MARK); + if (ep->log->put(ep->log, &key, &data, 0) == -1) + LOG_ERR; + +#if defined(DEBUG) && 0 + TRACE(sp, "%lu: %s: %u/%u\n", ep->l_cur, + type == LOG_CURSOR_INIT ? "log_cursor_init" : "log_cursor_end", + sp->lno, sp->cno); +#endif + /* Reset high water mark. */ + ep->l_high = ++ep->l_cur; + + return (0); +} + +/* + * log_line -- + * Log a line change. + * + * PUBLIC: int log_line(SCR *, recno_t, u_int); + */ +int +log_line(SCR *sp, recno_t lno, u_int action) +{ + DBT data, key; + EXF *ep; + size_t len; + CHAR_T *lp; + recno_t lcur; + + ep = sp->ep; + if (F_ISSET(ep, F_NOLOG)) + return (0); + + /* + * XXX + * + * Kluge for vi. Clear the EXF undo flag so that the + * next 'u' command does a roll-back, regardless. + */ + F_CLR(ep, F_UNDO); + + /* Put out one initial cursor record per set of changes. */ + if (ep->l_cursor.lno != OOBLNO) { + if (log_cursor1(sp, LOG_CURSOR_INIT)) + return (1); + ep->l_cursor.lno = OOBLNO; + } + + /* + * Put out the changes. If it's a LOG_LINE_RESET_B call, it's a + * special case, avoid the caches. Also, if it fails and it's + * line 1, it just means that the user started with an empty file, + * so fake an empty length line. + */ + if (action == LOG_LINE_RESET_B) { + if (db_get(sp, lno, DBG_NOCACHE, &lp, &len)) { + if (lno != 1) { + db_err(sp, lno); + return (1); + } + len = 0; + lp = L(""); + } + } else + if (db_get(sp, lno, DBG_FATAL, &lp, &len)) + return (1); + BINC_RETC(sp, + ep->l_lp, ep->l_len, + len * sizeof(CHAR_T) + CHAR_T_OFFSET); + ep->l_lp[0] = action; + memmove(ep->l_lp + sizeof(u_char), &lno, sizeof(recno_t)); + memmove(ep->l_lp + CHAR_T_OFFSET, lp, len * sizeof(CHAR_T)); + + lcur = ep->l_cur; + key.data = &lcur; + key.size = sizeof(recno_t); + data.data = ep->l_lp; + data.size = len * sizeof(CHAR_T) + CHAR_T_OFFSET; + if (ep->log->put(ep->log, &key, &data, 0) == -1) + LOG_ERR; + +#if defined(DEBUG) && 0 + switch (action) { + case LOG_LINE_APPEND: + TRACE(sp, "%lu: log_line: append: %lu {%u}\n", + ep->l_cur, lno, len); + break; + case LOG_LINE_DELETE: + TRACE(sp, "%lu: log_line: delete: %lu {%u}\n", + ep->l_cur, lno, len); + break; + case LOG_LINE_INSERT: + TRACE(sp, "%lu: log_line: insert: %lu {%u}\n", + ep->l_cur, lno, len); + break; + case LOG_LINE_RESET_F: + TRACE(sp, "%lu: log_line: reset_f: %lu {%u}\n", + ep->l_cur, lno, len); + break; + case LOG_LINE_RESET_B: + TRACE(sp, "%lu: log_line: reset_b: %lu {%u}\n", + ep->l_cur, lno, len); + break; + } +#endif + /* Reset high water mark. */ + ep->l_high = ++ep->l_cur; + + return (0); +} + +/* + * log_mark -- + * Log a mark position. For the log to work, we assume that there + * aren't any operations that just put out a log record -- this + * would mean that undo operations would only reset marks, and not + * cause any other change. + * + * PUBLIC: int log_mark(SCR *, LMARK *); + */ +int +log_mark(SCR *sp, LMARK *lmp) +{ + DBT data, key; + EXF *ep; + + ep = sp->ep; + if (F_ISSET(ep, F_NOLOG)) + return (0); + + /* Put out one initial cursor record per set of changes. */ + if (ep->l_cursor.lno != OOBLNO) { + if (log_cursor1(sp, LOG_CURSOR_INIT)) + return (1); + ep->l_cursor.lno = OOBLNO; + } + + BINC_RETC(sp, ep->l_lp, + ep->l_len, sizeof(u_char) + sizeof(LMARK)); + ep->l_lp[0] = LOG_MARK; + memmove(ep->l_lp + sizeof(u_char), lmp, sizeof(LMARK)); + + key.data = &ep->l_cur; + key.size = sizeof(recno_t); + data.data = ep->l_lp; + data.size = sizeof(u_char) + sizeof(LMARK); + if (ep->log->put(ep->log, &key, &data, 0) == -1) + LOG_ERR; + +#if defined(DEBUG) && 0 + TRACE(sp, "%lu: mark %c: %lu/%u\n", + ep->l_cur, lmp->name, lmp->lno, lmp->cno); +#endif + /* Reset high water mark. */ + ep->l_high = ++ep->l_cur; + return (0); +} + +/* + * Log_backward -- + * Roll the log backward one operation. + * + * PUBLIC: int log_backward(SCR *, MARK *); + */ +int +log_backward(SCR *sp, MARK *rp) +{ + DBT key, data; + EXF *ep; + LMARK lm; + MARK m; + recno_t lno; + int didop; + u_char *p; + + ep = sp->ep; + if (F_ISSET(ep, F_NOLOG)) { + msgq(sp, M_ERR, + "010|Logging not being performed, undo not possible"); + return (1); + } + + if (ep->l_cur == 1) { + msgq(sp, M_BERR, "011|No changes to undo"); + return (1); + } + + F_SET(ep, F_NOLOG); /* Turn off logging. */ + + key.data = &ep->l_cur; /* Initialize db request. */ + key.size = sizeof(recno_t); + for (didop = 0;;) { + --ep->l_cur; + if (ep->log->get(ep->log, &key, &data, 0)) + LOG_ERR; +#if defined(DEBUG) && 0 + log_trace(sp, "log_backward", ep->l_cur, data.data); +#endif + switch (*(p = (u_char *)data.data)) { + case LOG_CURSOR_INIT: + if (didop) { + memmove(rp, p + sizeof(u_char), sizeof(MARK)); + F_CLR(ep, F_NOLOG); + return (0); + } + break; + case LOG_CURSOR_END: + break; + case LOG_LINE_APPEND: + case LOG_LINE_INSERT: + didop = 1; + memmove(&lno, p + sizeof(u_char), sizeof(recno_t)); + if (db_delete(sp, lno)) + goto err; + ++sp->rptlines[L_DELETED]; + break; + case LOG_LINE_DELETE: + didop = 1; + memmove(&lno, p + sizeof(u_char), sizeof(recno_t)); + if (apply_with(db_insert, sp, lno, + p + CHAR_T_OFFSET, data.size - CHAR_T_OFFSET)) + goto err; + ++sp->rptlines[L_ADDED]; + break; + case LOG_LINE_RESET_F: + break; + case LOG_LINE_RESET_B: + didop = 1; + memmove(&lno, p + sizeof(u_char), sizeof(recno_t)); + if (apply_with(db_set, sp, lno, + p + CHAR_T_OFFSET, data.size - CHAR_T_OFFSET)) + goto err; + if (sp->rptlchange != lno) { + sp->rptlchange = lno; + ++sp->rptlines[L_CHANGED]; + } + break; + case LOG_MARK: + didop = 1; + memmove(&lm, p + sizeof(u_char), sizeof(LMARK)); + m.lno = lm.lno; + m.cno = lm.cno; + if (mark_set(sp, lm.name, &m, 0)) + goto err; + break; + default: + abort(); + } + } + +err: F_CLR(ep, F_NOLOG); + return (1); +} + +/* + * Log_setline -- + * Reset the line to its original appearance. + * + * XXX + * There's a bug in this code due to our not logging cursor movements + * unless a change was made. If you do a change, move off the line, + * then move back on and do a 'U', the line will be restored to the way + * it was before the original change. + * + * PUBLIC: int log_setline(SCR *); + */ +int +log_setline(SCR *sp) +{ + DBT key, data; + EXF *ep; + LMARK lm; + MARK m; + recno_t lno; + u_char *p; + + ep = sp->ep; + if (F_ISSET(ep, F_NOLOG)) { + msgq(sp, M_ERR, + "012|Logging not being performed, undo not possible"); + return (1); + } + + if (ep->l_cur == 1) + return (1); + + F_SET(ep, F_NOLOG); /* Turn off logging. */ + + key.data = &ep->l_cur; /* Initialize db request. */ + key.size = sizeof(recno_t); + for (;;) { + --ep->l_cur; + if (ep->log->get(ep->log, &key, &data, 0)) + LOG_ERR; +#if defined(DEBUG) && 0 + log_trace(sp, "log_setline", ep->l_cur, data.data); +#endif + switch (*(p = (u_char *)data.data)) { + case LOG_CURSOR_INIT: + memmove(&m, p + sizeof(u_char), sizeof(MARK)); + if (m.lno != sp->lno || ep->l_cur == 1) { + F_CLR(ep, F_NOLOG); + return (0); + } + break; + case LOG_CURSOR_END: + memmove(&m, p + sizeof(u_char), sizeof(MARK)); + if (m.lno != sp->lno) { + ++ep->l_cur; + F_CLR(ep, F_NOLOG); + return (0); + } + break; + case LOG_LINE_APPEND: + case LOG_LINE_INSERT: + case LOG_LINE_DELETE: + case LOG_LINE_RESET_F: + break; + case LOG_LINE_RESET_B: + memmove(&lno, p + sizeof(u_char), sizeof(recno_t)); + if (lno == sp->lno && + apply_with(db_set, sp, lno, + p + CHAR_T_OFFSET, data.size - CHAR_T_OFFSET)) + goto err; + if (sp->rptlchange != lno) { + sp->rptlchange = lno; + ++sp->rptlines[L_CHANGED]; + } + case LOG_MARK: + memmove(&lm, p + sizeof(u_char), sizeof(LMARK)); + m.lno = lm.lno; + m.cno = lm.cno; + if (mark_set(sp, lm.name, &m, 0)) + goto err; + break; + default: + abort(); + } + } + +err: F_CLR(ep, F_NOLOG); + return (1); +} + +/* + * Log_forward -- + * Roll the log forward one operation. + * + * PUBLIC: int log_forward(SCR *, MARK *); + */ +int +log_forward(SCR *sp, MARK *rp) +{ + DBT key, data; + EXF *ep; + LMARK lm; + MARK m; + recno_t lno; + int didop; + u_char *p; + + ep = sp->ep; + if (F_ISSET(ep, F_NOLOG)) { + msgq(sp, M_ERR, + "013|Logging not being performed, roll-forward not possible"); + return (1); + } + + if (ep->l_cur == ep->l_high) { + msgq(sp, M_BERR, "014|No changes to re-do"); + return (1); + } + + F_SET(ep, F_NOLOG); /* Turn off logging. */ + + key.data = &ep->l_cur; /* Initialize db request. */ + key.size = sizeof(recno_t); + for (didop = 0;;) { + ++ep->l_cur; + if (ep->log->get(ep->log, &key, &data, 0)) + LOG_ERR; +#if defined(DEBUG) && 0 + log_trace(sp, "log_forward", ep->l_cur, data.data); +#endif + switch (*(p = (u_char *)data.data)) { + case LOG_CURSOR_END: + if (didop) { + ++ep->l_cur; + memmove(rp, p + sizeof(u_char), sizeof(MARK)); + F_CLR(ep, F_NOLOG); + return (0); + } + break; + case LOG_CURSOR_INIT: + break; + case LOG_LINE_APPEND: + case LOG_LINE_INSERT: + didop = 1; + memmove(&lno, p + sizeof(u_char), sizeof(recno_t)); + if (apply_with(db_insert, sp, lno, + p + CHAR_T_OFFSET, data.size - CHAR_T_OFFSET)) + goto err; + ++sp->rptlines[L_ADDED]; + break; + case LOG_LINE_DELETE: + didop = 1; + memmove(&lno, p + sizeof(u_char), sizeof(recno_t)); + if (db_delete(sp, lno)) + goto err; + ++sp->rptlines[L_DELETED]; + break; + case LOG_LINE_RESET_B: + break; + case LOG_LINE_RESET_F: + didop = 1; + memmove(&lno, p + sizeof(u_char), sizeof(recno_t)); + if (apply_with(db_set, sp, lno, + p + CHAR_T_OFFSET, data.size - CHAR_T_OFFSET)) + goto err; + if (sp->rptlchange != lno) { + sp->rptlchange = lno; + ++sp->rptlines[L_CHANGED]; + } + break; + case LOG_MARK: + didop = 1; + memmove(&lm, p + sizeof(u_char), sizeof(LMARK)); + m.lno = lm.lno; + m.cno = lm.cno; + if (mark_set(sp, lm.name, &m, 0)) + goto err; + break; + default: + abort(); + } + } + +err: F_CLR(ep, F_NOLOG); + return (1); +} + +/* + * log_err -- + * Try and restart the log on failure, i.e. if we run out of memory. + */ +static void +log_err(SCR *sp, char *file, int line) +{ + EXF *ep; + + msgq(sp, M_SYSERR, "015|%s/%d: log put error", basename(file), line); + ep = sp->ep; + (void)ep->log->close(ep->log); + if (!log_init(sp, ep)) + msgq(sp, M_ERR, "267|Log restarted"); +} + +#if defined(DEBUG) && 0 +static void +log_trace(SCR *sp, char *msg, recno_t rno, u_char *p) +{ + LMARK lm; + MARK m; + recno_t lno; + + switch (*p) { + case LOG_CURSOR_INIT: + memmove(&m, p + sizeof(u_char), sizeof(MARK)); + TRACE(sp, "%lu: %s: C_INIT: %u/%u\n", rno, msg, m.lno, m.cno); + break; + case LOG_CURSOR_END: + memmove(&m, p + sizeof(u_char), sizeof(MARK)); + TRACE(sp, "%lu: %s: C_END: %u/%u\n", rno, msg, m.lno, m.cno); + break; + case LOG_LINE_APPEND: + memmove(&lno, p + sizeof(u_char), sizeof(recno_t)); + TRACE(sp, "%lu: %s: APPEND: %lu\n", rno, msg, lno); + break; + case LOG_LINE_INSERT: + memmove(&lno, p + sizeof(u_char), sizeof(recno_t)); + TRACE(sp, "%lu: %s: INSERT: %lu\n", rno, msg, lno); + break; + case LOG_LINE_DELETE: + memmove(&lno, p + sizeof(u_char), sizeof(recno_t)); + TRACE(sp, "%lu: %s: DELETE: %lu\n", rno, msg, lno); + break; + case LOG_LINE_RESET_F: + memmove(&lno, p + sizeof(u_char), sizeof(recno_t)); + TRACE(sp, "%lu: %s: RESET_F: %lu\n", rno, msg, lno); + break; + case LOG_LINE_RESET_B: + memmove(&lno, p + sizeof(u_char), sizeof(recno_t)); + TRACE(sp, "%lu: %s: RESET_B: %lu\n", rno, msg, lno); + break; + case LOG_MARK: + memmove(&lm, p + sizeof(u_char), sizeof(LMARK)); + TRACE(sp, + "%lu: %s: MARK: %u/%u\n", rno, msg, lm.lno, lm.cno); + break; + default: + abort(); + } +} +#endif + +/* + * apply_with -- + * Apply a realigned line from the log db to the file db. + */ +static int +apply_with(int (*db_func)(SCR *, recno_t, CHAR_T *, size_t), SCR *sp, + recno_t lno, u_char *p, size_t len) +{ +#ifdef USE_WIDECHAR + typedef unsigned long nword; + + static size_t blen; + static nword *bp; + nword *lp = (nword *)((uintptr_t)p / sizeof(nword) * sizeof(nword)); + + if (lp != (nword *)p) { + int offl = ((uintptr_t)p - (uintptr_t)lp) << 3; + int offr = (sizeof(nword) << 3) - offl; + size_t i, cnt = (len + sizeof(nword) / 2) / sizeof(nword); + + if (len > blen) { + blen = p2roundup(MAX(len, 512)); + REALLOC(sp, bp, nword *, blen); + if (bp == NULL) + return (1); + } + for (i = 0; i < cnt; ++i) +#if BYTE_ORDER == BIG_ENDIAN + bp[i] = (lp[i] << offl) ^ (lp[i+1] >> offr); +#else + bp[i] = (lp[i] >> offl) ^ (lp[i+1] << offr); +#endif + p = (u_char *)bp; + } +#endif + return db_func(sp, lno, (CHAR_T *)p, len / sizeof(CHAR_T)); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/common/log.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/common/main.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/common/main.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/common/main.c (revision 366308) @@ -0,0 +1,576 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "../vi/vi.h" +#include "pathnames.h" + +static void attach(GS *); +static int v_obsolete(char *[]); + +/* + * editor -- + * Main editor routine. + * + * PUBLIC: int editor(GS *, int, char *[]); + */ +int +editor(GS *gp, int argc, char *argv[]) +{ + extern int optind; + extern char *optarg; + const char *p; + EVENT ev; + FREF *frp; + SCR *sp; + size_t len; + u_int flags; + int ch, flagchk, lflag, secure, startup, readonly, rval, silent; + char *tag_f, *wsizearg; + CHAR_T *w, path[256]; + size_t wlen; + + /* Initialize the busy routine, if not defined by the screen. */ + if (gp->scr_busy == NULL) + gp->scr_busy = vs_busy; + /* Initialize the message routine, if not defined by the screen. */ + if (gp->scr_msg == NULL) + gp->scr_msg = vs_msg; + gp->catd = (nl_catd)-1; + + /* Common global structure initialization. */ + TAILQ_INIT(gp->dq); + TAILQ_INIT(gp->hq); + SLIST_INIT(gp->ecq); + SLIST_INSERT_HEAD(gp->ecq, &gp->excmd, q); + gp->noprint = DEFAULT_NOPRINT; + + /* Structures shared by screens so stored in the GS structure. */ + TAILQ_INIT(gp->frefq); + TAILQ_INIT(gp->dcb_store.textq); + SLIST_INIT(gp->cutq); + SLIST_INIT(gp->seqq); + + /* Set initial screen type and mode based on the program name. */ + readonly = 0; + if (!strcmp(getprogname(), "ex") || !strcmp(getprogname(), "nex")) + LF_INIT(SC_EX); + else { + /* Nview, view are readonly. */ + if (!strcmp(getprogname(), "nview") || + !strcmp(getprogname(), "view")) + readonly = 1; + + /* Vi is the default. */ + LF_INIT(SC_VI); + } + + /* Convert old-style arguments into new-style ones. */ + if (v_obsolete(argv)) + return (1); + + /* Parse the arguments. */ + flagchk = '\0'; + tag_f = wsizearg = NULL; + lflag = secure = silent = 0; + startup = 1; + + /* Set the file snapshot flag. */ + F_SET(gp, G_SNAPSHOT); + +#ifdef DEBUG + while ((ch = getopt(argc, argv, "c:D:eFlRrSsT:t:vw:")) != EOF) +#else + while ((ch = getopt(argc, argv, "c:eFlRrSst:vw:")) != EOF) +#endif + switch (ch) { + case 'c': /* Run the command. */ + /* + * XXX + * We should support multiple -c options. + */ + if (gp->c_option != NULL) { + warnx("only one -c command may be specified."); + return (1); + } + gp->c_option = optarg; + break; +#ifdef DEBUG + case 'D': + switch (optarg[0]) { + case 's': + startup = 0; + break; + case 'w': + attach(gp); + break; + default: + warnx("usage: -D requires s or w argument."); + return (1); + } + break; +#endif + case 'e': /* Ex mode. */ + LF_CLR(SC_VI); + LF_SET(SC_EX); + break; + case 'F': /* No snapshot. */ + F_CLR(gp, G_SNAPSHOT); + break; + case 'l': /* Set lisp, showmatch options. */ + lflag = 1; + break; + case 'R': /* Readonly. */ + readonly = 1; + break; + case 'r': /* Recover. */ + if (flagchk == 't') { + warnx("only one of -r and -t may be specified."); + return (1); + } + flagchk = 'r'; + break; + case 'S': + secure = 1; + break; + case 's': + silent = 1; + break; +#ifdef DEBUG + case 'T': /* Trace. */ + if ((gp->tracefp = fopen(optarg, "w")) == NULL) { + warn("%s", optarg); + goto err; + } + (void)fprintf(gp->tracefp, + "\n===\ntrace: open %s\n", optarg); + break; +#endif + case 't': /* Tag. */ + if (flagchk == 'r') { + warnx("only one of -r and -t may be specified."); + return (1); + } + if (flagchk == 't') { + warnx("only one tag file may be specified."); + return (1); + } + flagchk = 't'; + tag_f = optarg; + break; + case 'v': /* Vi mode. */ + LF_CLR(SC_EX); + LF_SET(SC_VI); + break; + case 'w': + wsizearg = optarg; + break; + case '?': + default: + (void)gp->scr_usage(); + return (1); + } + argc -= optind; + argv += optind; + + /* + * -s option is only meaningful to ex. + * + * If not reading from a terminal, it's like -s was specified. + */ + if (silent && !LF_ISSET(SC_EX)) { + warnx("-s option is only applicable to ex."); + goto err; + } + if (LF_ISSET(SC_EX) && F_ISSET(gp, G_SCRIPTED)) + silent = 1; + + /* + * Build and initialize the first/current screen. This is a bit + * tricky. If an error is returned, we may or may not have a + * screen structure. If we have a screen structure, put it on a + * display queue so that the error messages get displayed. + * + * !!! + * Everything we do until we go interactive is done in ex mode. + */ + if (screen_init(gp, NULL, &sp)) { + if (sp != NULL) + TAILQ_INSERT_HEAD(gp->dq, sp, q); + goto err; + } + F_SET(sp, SC_EX); + TAILQ_INSERT_HEAD(gp->dq, sp, q); + + if (v_key_init(sp)) /* Special key initialization. */ + goto err; + + { int oargs[5], *oargp = oargs; + if (lflag) { /* Command-line options. */ + *oargp++ = O_LISP; + *oargp++ = O_SHOWMATCH; + } + if (readonly) + *oargp++ = O_READONLY; + if (secure) + *oargp++ = O_SECURE; + *oargp = -1; /* Options initialization. */ + if (opts_init(sp, oargs)) + goto err; + } + if (wsizearg != NULL) { + ARGS *av[2], a, b; + (void)SPRINTF(path, SIZE(path), L("window=%s"), wsizearg); + a.bp = (CHAR_T *)path; + a.len = SIZE(path); + b.bp = NULL; + b.len = 0; + av[0] = &a; + av[1] = &b; + (void)opts_set(sp, av, NULL); + } + if (silent) { /* Ex batch mode option values. */ + O_CLR(sp, O_AUTOPRINT); + O_CLR(sp, O_PROMPT); + O_CLR(sp, O_VERBOSE); + O_CLR(sp, O_WARN); + F_SET(sp, SC_EX_SILENT); + } + + sp->rows = O_VAL(sp, O_LINES); /* Make ex formatting work. */ + sp->cols = O_VAL(sp, O_COLUMNS); + + if (!silent && startup) { /* Read EXINIT, exrc files. */ + if (ex_exrc(sp)) + goto err; + if (F_ISSET(sp, SC_EXIT | SC_EXIT_FORCE)) { + if (screen_end(sp)) + goto err; + goto done; + } + } + + /* + * List recovery files if -r specified without file arguments. + * Note, options must be initialized and startup information + * read before doing this. + */ + if (flagchk == 'r' && argv[0] == NULL) { + if (rcv_list(sp)) + goto err; + if (screen_end(sp)) + goto err; + goto done; + } + + /* + * !!! + * Initialize the default ^D, ^U scrolling value here, after the + * user has had every opportunity to set the window option. + * + * It's historic practice that changing the value of the window + * option did not alter the default scrolling value, only giving + * a count to ^D/^U did that. + */ + sp->defscroll = (O_VAL(sp, O_WINDOW) + 1) / 2; + + /* + * If we don't have a command-line option, switch into the right + * editor now, so that we position default files correctly, and + * so that any tags file file-already-locked messages are in the + * vi screen, not the ex screen. + * + * XXX + * If we have a command-line option, the error message can end + * up in the wrong place, but I think that the combination is + * unlikely. + */ + if (gp->c_option == NULL) { + F_CLR(sp, SC_EX | SC_VI); + F_SET(sp, LF_ISSET(SC_EX | SC_VI)); + } + + /* Open a tag file if specified. */ + if (tag_f != NULL) { + CHAR2INT(sp, tag_f, strlen(tag_f) + 1, w, wlen); + if (ex_tag_first(sp, w)) + goto err; + } + + /* + * Append any remaining arguments as file names. Files are recovery + * files if -r specified. If the tag option or ex startup commands + * loaded a file, then any file arguments are going to come after it. + */ + if (*argv != NULL) { + if (sp->frp != NULL) { + /* Cheat -- we know we have an extra argv slot. */ + *--argv = strdup(sp->frp->name); + if (*argv == NULL) { + warn(NULL); + goto err; + } + } + sp->argv = sp->cargv = argv; + F_SET(sp, SC_ARGNOFREE); + if (flagchk == 'r') + F_SET(sp, SC_ARGRECOVER); + } + + /* + * If the ex startup commands and or/the tag option haven't already + * created a file, create one. If no command-line files were given, + * use a temporary file. + */ + if (sp->frp == NULL) { + if (sp->argv == NULL) { + if ((frp = file_add(sp, NULL)) == NULL) + goto err; + } else { + if ((frp = file_add(sp, sp->argv[0])) == NULL) + goto err; + if (F_ISSET(sp, SC_ARGRECOVER)) + F_SET(frp, FR_RECOVER); + } + + if (file_init(sp, frp, NULL, 0)) + goto err; + if (EXCMD_RUNNING(gp)) { + (void)ex_cmd(sp); + if (F_ISSET(sp, SC_EXIT | SC_EXIT_FORCE)) { + if (screen_end(sp)) + goto err; + goto done; + } + } + } + + /* + * Check to see if we need to wait for ex. If SC_SCR_EX is set, ex + * was forced to initialize the screen during startup. We'd like to + * wait for a single character from the user, but we can't because + * we're not in raw mode. We can't switch to raw mode because the + * vi initialization will switch to xterm's alternate screen, causing + * us to lose the messages we're pausing to make sure the user read. + * So, wait for a complete line. + */ + if (F_ISSET(sp, SC_SCR_EX)) { + p = msg_cmsg(sp, CMSG_CONT_R, &len); + (void)write(STDOUT_FILENO, p, len); + for (;;) { + if (v_event_get(sp, &ev, 0, 0)) + goto err; + if (ev.e_event == E_INTERRUPT || + (ev.e_event == E_CHARACTER && + (ev.e_value == K_CR || ev.e_value == K_NL))) + break; + (void)gp->scr_bell(sp); + } + } + + /* Switch into the right editor, regardless. */ + F_CLR(sp, SC_EX | SC_VI); + F_SET(sp, LF_ISSET(SC_EX | SC_VI) | SC_STATUS_CNT); + + /* + * Main edit loop. Vi handles split screens itself, we only return + * here when switching editor modes or restarting the screen. + */ + while (sp != NULL) + if (F_ISSET(sp, SC_EX) ? ex(&sp) : vi(&sp)) + goto err; + +done: rval = 0; + if (0) +err: rval = 1; + + /* Clean out the global structure. */ + v_end(gp); + + return (rval); +} + +/* + * v_end -- + * End the program, discarding screens and most of the global area. + * + * PUBLIC: void v_end(GS *); + */ +void +v_end(gp) + GS *gp; +{ + MSGS *mp; + SCR *sp; + + /* If there are any remaining screens, kill them off. */ + if (gp->ccl_sp != NULL) { + (void)file_end(gp->ccl_sp, NULL, 1); + (void)screen_end(gp->ccl_sp); + } + while ((sp = TAILQ_FIRST(gp->dq)) != NULL) + (void)screen_end(sp); + while ((sp = TAILQ_FIRST(gp->hq)) != NULL) + (void)screen_end(sp); + +#if defined(DEBUG) || defined(PURIFY) + { FREF *frp; + /* Free FREF's. */ + while ((frp = TAILQ_FIRST(gp->frefq)) != NULL) { + TAILQ_REMOVE(gp->frefq, frp, q); + free(frp->name); + free(frp->tname); + free(frp); + } + } + + /* Free key input queue. */ + free(gp->i_event); + + /* Free cut buffers. */ + cut_close(gp); + + /* Free map sequences. */ + seq_close(gp); + + /* Free default buffer storage. */ + (void)text_lfree(gp->dcb_store.textq); + + /* Close message catalogs. */ + msg_close(gp); +#endif + + /* Ring the bell if scheduled. */ + if (F_ISSET(gp, G_BELLSCHED)) + (void)fprintf(stderr, "\07"); /* \a */ + + /* + * Flush any remaining messages. If a message is here, it's almost + * certainly the message about the event that killed us (although + * it's possible that the user is sourcing a file that exits from the + * editor). + */ + while ((mp = SLIST_FIRST(gp->msgq)) != NULL) { + (void)fprintf(stderr, "%s%.*s", + mp->mtype == M_ERR ? "ex/vi: " : "", (int)mp->len, mp->buf); + SLIST_REMOVE_HEAD(gp->msgq, q); +#if defined(DEBUG) || defined(PURIFY) + free(mp->buf); + free(mp); +#endif + } + +#if defined(DEBUG) || defined(PURIFY) + /* Free any temporary space. */ + free(gp->tmp_bp); + +#if defined(DEBUG) + /* Close debugging file descriptor. */ + if (gp->tracefp != NULL) + (void)fclose(gp->tracefp); +#endif +#endif +} + +/* + * v_obsolete -- + * Convert historic arguments into something getopt(3) will like. + */ +static int +v_obsolete(char *argv[]) +{ + size_t len; + char *p; + + /* + * Translate old style arguments into something getopt will like. + * Make sure it's not text space memory, because ex modifies the + * strings. + * Change "+" into "-c$". + * Change "+" into "-c". + * Change "-" into "-s" + * The c, T, t and w options take arguments so they can't be + * special arguments. + * + * Stop if we find "--" as an argument, the user may want to edit + * a file named "+foo". + */ + while (*++argv && strcmp(argv[0], "--")) + if (argv[0][0] == '+') { + if (argv[0][1] == '\0') { + argv[0] = strdup("-c$"); + if (argv[0] == NULL) + goto nomem; + } else { + p = argv[0]; + len = strlen(argv[0]); + argv[0] = malloc(len + 2); + if (argv[0] == NULL) + goto nomem; + argv[0][0] = '-'; + argv[0][1] = 'c'; + (void)strlcpy(argv[0] + 2, p + 1, len); + } + } else if (argv[0][0] == '-') { + if (argv[0][1] == '\0') { + argv[0] = strdup("-s"); + if (argv[0] == NULL) { +nomem: warn(NULL); + return (1); + } + } else + if ((argv[0][1] == 'c' || argv[0][1] == 'T' || + argv[0][1] == 't' || argv[0][1] == 'w') && + argv[0][2] == '\0') + ++argv; + } + return (0); +} + +#ifdef DEBUG +static void +attach(GS *gp) +{ + int fd; + char ch; + + if ((fd = open(_PATH_TTY, O_RDONLY, 0)) < 0) { + warn("%s", _PATH_TTY); + return; + } + + (void)printf("process %lu waiting, enter to continue: ", + (u_long)getpid()); + (void)fflush(stdout); + + do { + if (read(fd, &ch, 1) != 1) { + (void)close(fd); + return; + } + } while (ch != '\n' && ch != '\r'); + (void)close(fd); +} +#endif Property changes on: vendor/nvi/2.2.0-05ed8b9/common/main.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/common/mark.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/common/mark.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/common/mark.c (revision 366308) @@ -0,0 +1,257 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "common.h" + +static LMARK *mark_find(SCR *, ARG_CHAR_T); + +/* + * Marks are maintained in a key sorted singly linked list. We can't + * use arrays because we have no idea how big an index key could be. + * The underlying assumption is that users don't have more than, say, + * 10 marks at any one time, so this will be is fast enough. + * + * Marks are fixed, and modifications to the line don't update the mark's + * position in the line. This can be hard. If you add text to the line, + * place a mark in that text, undo the addition and use ` to move to the + * mark, the location will have disappeared. It's tempting to try to adjust + * the mark with the changes in the line, but this is hard to do, especially + * if we've given the line to v_ntext.c:v_ntext() for editing. Historic vi + * would move to the first non-blank on the line when the mark location was + * past the end of the line. This can be complicated by deleting to a mark + * that has disappeared using the ` command. Historic vi treated this as + * a line-mode motion and deleted the line. This implementation complains to + * the user. + * + * In historic vi, marks returned if the operation was undone, unless the + * mark had been subsequently reset. Tricky. This is hard to start with, + * but in the presence of repeated undo it gets nasty. When a line is + * deleted, we delete (and log) any marks on that line. An undo will create + * the mark. Any mark creations are noted as to whether the user created + * it or if it was created by an undo. The former cannot be reset by another + * undo, but the latter may. + * + * All of these routines translate ABSMARK2 to ABSMARK1. Setting either of + * the absolute mark locations sets both, so that "m'" and "m`" work like + * they, ah, for lack of a better word, "should". + */ + +/* + * mark_init -- + * Set up the marks. + * + * PUBLIC: int mark_init(SCR *, EXF *); + */ +int +mark_init(SCR *sp, EXF *ep) +{ + /* + * !!! + * ep MAY NOT BE THE SAME AS sp->ep, DON'T USE THE LATTER. + * + * Set up the marks. + */ + SLIST_INIT(ep->marks); + return (0); +} + +/* + * mark_end -- + * Free up the marks. + * + * PUBLIC: int mark_end(SCR *, EXF *); + */ +int +mark_end(SCR *sp, EXF *ep) +{ + LMARK *lmp; + + /* + * !!! + * ep MAY NOT BE THE SAME AS sp->ep, DON'T USE THE LATTER. + */ + while ((lmp = SLIST_FIRST(ep->marks)) != NULL) { + SLIST_REMOVE_HEAD(ep->marks, q); + free(lmp); + } + return (0); +} + +/* + * mark_get -- + * Get the location referenced by a mark. + * + * PUBLIC: int mark_get(SCR *, ARG_CHAR_T, MARK *, mtype_t); + */ +int +mark_get(SCR *sp, ARG_CHAR_T key, MARK *mp, mtype_t mtype) +{ + LMARK *lmp; + + if (key == ABSMARK2) + key = ABSMARK1; + + lmp = mark_find(sp, key); + if (lmp == NULL || lmp->name != key) { + msgq(sp, mtype, "017|Mark %s: not set", KEY_NAME(sp, key)); + return (1); + } + if (F_ISSET(lmp, MARK_DELETED)) { + msgq(sp, mtype, + "018|Mark %s: the line was deleted", KEY_NAME(sp, key)); + return (1); + } + + /* + * !!! + * The absolute mark is initialized to lno 1/cno 0, and historically + * you could use it in an empty file. Make such a mark always work. + */ + if ((lmp->lno != 1 || lmp->cno != 0) && !db_exist(sp, lmp->lno)) { + msgq(sp, mtype, + "019|Mark %s: cursor position no longer exists", + KEY_NAME(sp, key)); + return (1); + } + mp->lno = lmp->lno; + mp->cno = lmp->cno; + return (0); +} + +/* + * mark_set -- + * Set the location referenced by a mark. + * + * PUBLIC: int mark_set(SCR *, ARG_CHAR_T, MARK *, int); + */ +int +mark_set(SCR *sp, ARG_CHAR_T key, MARK *value, int userset) +{ + LMARK *lmp, *lmt; + + if (key == ABSMARK2) + key = ABSMARK1; + + /* + * The rules are simple. If the user is setting a mark (if it's a + * new mark this is always true), it always happens. If not, it's + * an undo, and we set it if it's not already set or if it was set + * by a previous undo. + */ + lmp = mark_find(sp, key); + if (lmp == NULL || lmp->name != key) { + MALLOC_RET(sp, lmt, sizeof(LMARK)); + if (lmp == NULL) { + SLIST_INSERT_HEAD(sp->ep->marks, lmt, q); + } else + SLIST_INSERT_AFTER(lmp, lmt, q); + lmp = lmt; + } else if (!userset && + !F_ISSET(lmp, MARK_DELETED) && F_ISSET(lmp, MARK_USERSET)) + return (0); + + lmp->lno = value->lno; + lmp->cno = value->cno; + lmp->name = key; + lmp->flags = userset ? MARK_USERSET : 0; + return (0); +} + +/* + * mark_find -- + * Find the requested mark, or, the slot immediately before + * where it would go. + */ +static LMARK * +mark_find(SCR *sp, ARG_CHAR_T key) +{ + LMARK *lmp, *lastlmp = NULL; + + /* + * Return the requested mark or the slot immediately before + * where it should go. + */ + SLIST_FOREACH(lmp, sp->ep->marks, q) { + if (lmp->name >= key) + return (lmp->name == key ? lmp : lastlmp); + lastlmp = lmp; + } + return (lastlmp); +} + +/* + * mark_insdel -- + * Update the marks based on an insertion or deletion. + * + * PUBLIC: int mark_insdel(SCR *, lnop_t, recno_t); + */ +int +mark_insdel(SCR *sp, lnop_t op, recno_t lno) +{ + LMARK *lmp; + recno_t lline; + + switch (op) { + case LINE_APPEND: + /* All insert/append operations are done as inserts. */ + abort(); + case LINE_DELETE: + SLIST_FOREACH(lmp, sp->ep->marks, q) + if (lmp->lno >= lno) { + if (lmp->lno == lno) { + F_SET(lmp, MARK_DELETED); + (void)log_mark(sp, lmp); + } else + --lmp->lno; + } + break; + case LINE_INSERT: + /* + * XXX + * Very nasty special case. If the file was empty, then we're + * adding the first line, which is a replacement. So, we don't + * modify the marks. This is a hack to make: + * + * mz:r!echo foo'z + * + * work, i.e. historically you could mark the "line" in an empty + * file and replace it, and continue to use the mark. Insane, + * well, yes, I know, but someone complained. + * + * Check for line #2 before going to the end of the file. + */ + if (!db_exist(sp, 2)) { + if (db_last(sp, &lline)) + return (1); + if (lline == 1) + return (0); + } + + SLIST_FOREACH(lmp, sp->ep->marks, q) + if (lmp->lno >= lno) + ++lmp->lno; + break; + case LINE_RESET: + break; + } + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/common/mark.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/common/mem.h =================================================================== --- vendor/nvi/2.2.0-05ed8b9/common/mem.h (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/common/mem.h (revision 366308) @@ -0,0 +1,217 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#ifdef DEBUG +#define CHECK_TYPE(type, var) \ + type L__lp __attribute__((unused)) = var; +#else +#define CHECK_TYPE(type, var) +#endif + +/* Increase the size of a malloc'd buffer. Two versions, one that + * returns, one that jumps to an error label. + */ +#define BINC_GOTO(sp, type, lp, llen, nlen) do { \ + CHECK_TYPE(type *, lp) \ + void *L__bincp; \ + if ((nlen) > llen) { \ + if ((L__bincp = binc(sp, lp, &(llen), nlen)) == NULL) \ + goto alloc_err; \ + /* \ + * !!! \ + * Possible pointer conversion. \ + */ \ + lp = L__bincp; \ + } \ +} while (0) +#define BINC_GOTOC(sp, lp, llen, nlen) \ + BINC_GOTO(sp, char, lp, llen, nlen) +#define BINC_GOTOW(sp, lp, llen, nlen) \ + BINC_GOTO(sp, CHAR_T, lp, llen, (nlen) * sizeof(CHAR_T)) +#define BINC_RET(sp, type, lp, llen, nlen) do { \ + CHECK_TYPE(type *, lp) \ + void *L__bincp; \ + if ((nlen) > llen) { \ + if ((L__bincp = binc(sp, lp, &(llen), nlen)) == NULL) \ + return (1); \ + /* \ + * !!! \ + * Possible pointer conversion. \ + */ \ + lp = L__bincp; \ + } \ +} while (0) +#define BINC_RETC(sp, lp, llen, nlen) \ + BINC_RET(sp, char, lp, llen, nlen) +#define BINC_RETW(sp, lp, llen, nlen) \ + BINC_RET(sp, CHAR_T, lp, llen, (nlen) * sizeof(CHAR_T)) + +/* + * Get some temporary space, preferably from the global temporary buffer, + * from a malloc'd buffer otherwise. Two versions, one that returns, one + * that jumps to an error label. + */ +#define GET_SPACE_GOTO(sp, type, bp, blen, nlen) do { \ + CHECK_TYPE(type *, bp) \ + GS *L__gp = (sp) == NULL ? NULL : (sp)->gp; \ + if (L__gp == NULL || F_ISSET(L__gp, G_TMP_INUSE)) { \ + bp = NULL; \ + blen = 0; \ + BINC_GOTO(sp, type, bp, blen, nlen); \ + } else { \ + BINC_GOTOC(sp, L__gp->tmp_bp, L__gp->tmp_blen, nlen); \ + bp = (type *) L__gp->tmp_bp; \ + blen = L__gp->tmp_blen; \ + F_SET(L__gp, G_TMP_INUSE); \ + } \ +} while (0) +#define GET_SPACE_GOTOC(sp, bp, blen, nlen) \ + GET_SPACE_GOTO(sp, char, bp, blen, nlen) +#define GET_SPACE_GOTOW(sp, bp, blen, nlen) \ + GET_SPACE_GOTO(sp, CHAR_T, bp, blen, (nlen) * sizeof(CHAR_T)) +#define GET_SPACE_RET(sp, type, bp, blen, nlen) do { \ + CHECK_TYPE(type *, bp) \ + GS *L__gp = (sp) == NULL ? NULL : (sp)->gp; \ + if (L__gp == NULL || F_ISSET(L__gp, G_TMP_INUSE)) { \ + bp = NULL; \ + blen = 0; \ + BINC_RET(sp, type, bp, blen, nlen); \ + } else { \ + BINC_RETC(sp, L__gp->tmp_bp, L__gp->tmp_blen, nlen); \ + bp = (type *) L__gp->tmp_bp; \ + blen = L__gp->tmp_blen; \ + F_SET(L__gp, G_TMP_INUSE); \ + } \ +} while (0) +#define GET_SPACE_RETC(sp, bp, blen, nlen) \ + GET_SPACE_RET(sp, char, bp, blen, nlen) +#define GET_SPACE_RETW(sp, bp, blen, nlen) \ + GET_SPACE_RET(sp, CHAR_T, bp, blen, (nlen) * sizeof(CHAR_T)) + +/* + * Add space to a GET_SPACE returned buffer. Two versions, one that + * returns, one that jumps to an error label. + */ +#define ADD_SPACE_GOTO(sp, type, bp, blen, nlen) do { \ + CHECK_TYPE(type *, bp) \ + GS *L__gp = (sp) == NULL ? NULL : (sp)->gp; \ + if (L__gp == NULL || bp == (type *)L__gp->tmp_bp) { \ + F_CLR(L__gp, G_TMP_INUSE); \ + BINC_GOTOC(sp, L__gp->tmp_bp, L__gp->tmp_blen, nlen); \ + bp = (type *) L__gp->tmp_bp; \ + blen = L__gp->tmp_blen; \ + F_SET(L__gp, G_TMP_INUSE); \ + } else \ + BINC_GOTO(sp, type, bp, blen, nlen); \ +} while (0) +#define ADD_SPACE_GOTOC(sp, bp, blen, nlen) \ + ADD_SPACE_GOTO(sp, char, bp, blen, nlen) +#define ADD_SPACE_GOTOW(sp, bp, blen, nlen) \ + ADD_SPACE_GOTO(sp, CHAR_T, bp, blen, (nlen) * sizeof(CHAR_T)) +#define ADD_SPACE_RET(sp, type, bp, blen, nlen) do { \ + CHECK_TYPE(type *, bp) \ + GS *L__gp = (sp) == NULL ? NULL : (sp)->gp; \ + if (L__gp == NULL || bp == (type *)L__gp->tmp_bp) { \ + F_CLR(L__gp, G_TMP_INUSE); \ + BINC_RETC(sp, L__gp->tmp_bp, L__gp->tmp_blen, nlen); \ + bp = (type *) L__gp->tmp_bp; \ + blen = L__gp->tmp_blen; \ + F_SET(L__gp, G_TMP_INUSE); \ + } else \ + BINC_RET(sp, type, bp, blen, nlen); \ +} while (0) +#define ADD_SPACE_RETC(sp, bp, blen, nlen) \ + ADD_SPACE_RET(sp, char, bp, blen, nlen) +#define ADD_SPACE_RETW(sp, bp, blen, nlen) \ + ADD_SPACE_RET(sp, CHAR_T, bp, blen, (nlen) * sizeof(CHAR_T)) + +/* Free a GET_SPACE returned buffer. */ +#define FREE_SPACE(sp, bp, blen) do { \ + GS *L__gp = (sp) == NULL ? NULL : (sp)->gp; \ + if (L__gp != NULL && bp == L__gp->tmp_bp) \ + F_CLR(L__gp, G_TMP_INUSE); \ + else \ + free(bp); \ +} while (0) +#define FREE_SPACEW(sp, bp, blen) do { \ + CHECK_TYPE(CHAR_T *, bp) \ + FREE_SPACE(sp, (char *)bp, blen); \ +} while (0) + +/* + * Malloc a buffer, casting the return pointer. Various versions. + */ +#define CALLOC(sp, p, nmemb, size) do { \ + if ((p = calloc(nmemb, size)) == NULL) \ + msgq(sp, M_SYSERR, NULL); \ +} while (0) +#define CALLOC_GOTO(sp, p, nmemb, size) do { \ + if ((p = calloc(nmemb, size)) == NULL) \ + goto alloc_err; \ +} while (0) +#define CALLOC_RET(sp, p, nmemb, size) do { \ + if ((p = calloc(nmemb, size)) == NULL) { \ + msgq(sp, M_SYSERR, NULL); \ + return (1); \ + } \ +} while (0) + +#define MALLOC(sp, p, size) do { \ + if ((p = malloc(size)) == NULL) \ + msgq(sp, M_SYSERR, NULL); \ +} while (0) +#define MALLOC_GOTO(sp, p, size) do { \ + if ((p = malloc(size)) == NULL) \ + goto alloc_err; \ +} while (0) +#define MALLOC_RET(sp, p, size) do { \ + if ((p = malloc(size)) == NULL) { \ + msgq(sp, M_SYSERR, NULL); \ + return (1); \ + } \ +} while (0) + +/* + * Resize a buffer, free any already held memory if we can't get more. + * FreeBSD's reallocf(3) does the same thing, but it's not portable yet. + */ +#define REALLOC(sp, p, cast, size) do { \ + cast newp; \ + if ((newp = realloc(p, size)) == NULL) { \ + free(p); \ + msgq(sp, M_SYSERR, NULL); \ + } \ + p = newp; \ +} while (0) + +/* + * p2roundup -- + * Get next power of 2; convenient for realloc. + * + * Reference: FreeBSD /usr/src/lib/libc/stdio/getdelim.c + */ +static __inline size_t +p2roundup(size_t n) +{ + n--; + n |= n >> 1; + n |= n >> 2; + n |= n >> 4; + n |= n >> 8; + n |= n >> 16; +#if SIZE_T_MAX > 0xffffffffU + n |= n >> 32; +#endif + n++; + return (n); +} + +/* Additional TAILQ helper. */ +#define TAILQ_ENTRY_ISVALID(elm, field) \ + ((elm)->field.tqe_prev != NULL) Property changes on: vendor/nvi/2.2.0-05ed8b9/common/mem.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/common/msg.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/common/msg.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/common/msg.c (revision 366308) @@ -0,0 +1,887 @@ +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1991, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "../vi/vi.h" + +/* + * msgq -- + * Display a message. + * + * PUBLIC: void msgq(SCR *, mtype_t, const char *, ...); + */ +void +msgq(SCR *sp, mtype_t mt, const char *fmt, ...) +{ +#ifndef NL_ARGMAX +#define __NL_ARGMAX 20 /* Set to 9 by System V. */ + struct { + const char *str; /* String pointer. */ + size_t arg; /* Argument number. */ + size_t prefix; /* Prefix string length. */ + size_t skip; /* Skipped string length. */ + size_t suffix; /* Suffix string length. */ + } str[__NL_ARGMAX]; +#endif + static int reenter; /* STATIC: Re-entrancy check. */ + GS *gp; + size_t blen, len, mlen, nlen; + const char *p; + char *bp, *mp; + va_list ap; +#ifndef NL_ARGMAX + int ch; + char *rbp, *s_rbp; + const char *t, *u; + size_t cnt1, cnt2, soff; +#endif + + /* + * !!! + * It's possible to enter msg when there's no screen to hold the + * message. If sp is NULL, ignore the special cases and put the + * message out to stderr. + */ + if (sp == NULL) { + gp = NULL; + if (mt == M_BERR) + mt = M_ERR; + else if (mt == M_VINFO) + mt = M_INFO; + } else { + gp = sp->gp; + switch (mt) { + case M_BERR: + if (F_ISSET(sp, SC_VI) && !O_ISSET(sp, O_VERBOSE)) { + F_SET(gp, G_BELLSCHED); + return; + } + mt = M_ERR; + break; + case M_VINFO: + if (!O_ISSET(sp, O_VERBOSE)) + return; + mt = M_INFO; + /* FALLTHROUGH */ + case M_INFO: + if (F_ISSET(sp, SC_EX_SILENT)) + return; + break; + case M_ERR: + case M_SYSERR: + break; + default: + abort(); + } + } + + /* + * It's possible to reenter msg when it allocates space. We're + * probably dead anyway, but there's no reason to drop core. + * + * XXX + * Yes, there's a race, but it should only be two instructions. + */ + if (reenter++) + return; + + /* Get space for the message. */ + nlen = 1024; + if (0) { +retry: FREE_SPACE(sp, bp, blen); + nlen *= 2; + } + bp = NULL; + blen = 0; + GET_SPACE_GOTOC(sp, bp, blen, nlen); + + /* + * Error prefix. + * + * mp: pointer to the current next character to be written + * mlen: length of the already written characters + * blen: total length of the buffer + */ +#define REM (blen - mlen) + mp = bp; + mlen = 0; + if (mt == M_SYSERR) { + p = msg_cat(sp, "020|Error: ", &len); + if (REM < len) + goto retry; + memcpy(mp, p, len); + mp += len; + mlen += len; + } + + /* + * If we're running an ex command that the user didn't enter, display + * the file name and line number prefix. + */ + if ((mt == M_ERR || mt == M_SYSERR) && + sp != NULL && gp != NULL && gp->if_name != NULL) { + CHAR_T *wp; + size_t wlen; + + CHAR2INT(sp, gp->if_name, strlen(gp->if_name) + 1, wp, wlen); + for (; *wp != '\0'; ++wp) { + len = snprintf(mp, REM, "%s", KEY_NAME(sp, *wp)); + mp += len; + if ((mlen += len) > blen) + goto retry; + } + len = snprintf(mp, REM, ", %d: ", gp->if_lno); + mp += len; + if ((mlen += len) > blen) + goto retry; + } + + /* If nothing to format, we're done. */ + if (fmt == NULL) + goto nofmt; + fmt = msg_cat(sp, fmt, NULL); + +#ifndef NL_ARGMAX + /* + * Nvi should run on machines that don't support the numbered argument + * specifications (%[digit]*$). We do this by reformatting the string + * so that we can hand it to vsprintf(3) and it will use the arguments + * in the right order. When vsprintf returns, we put the string back + * into the right order. It's undefined, according to SVID III, to mix + * numbered argument specifications with the standard style arguments, + * so this should be safe. + * + * In addition, we also need a character that is known to not occur in + * any vi message, for separating the parts of the string. As callers + * of msgq are responsible for making sure that all the non-printable + * characters are formatted for printing before calling msgq, we use a + * random non-printable character selected at terminal initialization + * time. This code isn't fast by any means, but as messages should be + * relatively short and normally have only a few arguments, it won't be + * too bad. Regardless, nobody has come up with any other solution. + * + * The result of this loop is an array of pointers into the message + * string, with associated lengths and argument numbers. The array + * is in the "correct" order, and the arg field contains the argument + * order. + */ + for (p = fmt, soff = 0; soff < __NL_ARGMAX;) { + for (t = p; *p != '\0' && *p != '%'; ++p); + if (*p == '\0') + break; + ++p; + if (!isdigit((u_char)*p)) { + if (*p == '%') + ++p; + continue; + } + for (u = p; *++p != '\0' && isdigit((u_char)*p);); + if (*p != '$') + continue; + + /* Up to, and including the % character. */ + str[soff].str = t; + str[soff].prefix = u - t; + + /* Up to, and including the $ character. */ + str[soff].arg = atoi(u); + str[soff].skip = (p - u) + 1; + if (str[soff].arg >= __NL_ARGMAX) + goto ret; + + /* Up to, and including the conversion character. */ + for (u = p; (ch = *++p) != '\0';) + if (isalpha(ch) && + strchr("diouxXfeEgGcspn", ch) != NULL) + break; + str[soff].suffix = p - u; + if (ch != '\0') + ++p; + ++soff; + } + + /* If no magic strings, we're done. */ + if (soff == 0) + goto format; + + /* Get space for the reordered strings. */ + if ((rbp = malloc(nlen)) == NULL) + goto ret; + s_rbp = rbp; + + /* + * Reorder the strings into the message string based on argument + * order. + * + * !!! + * We ignore arguments that are out of order, i.e. if we don't find + * an argument, we continue. Assume (almost certainly incorrectly) + * that whoever created the string knew what they were doing. + * + * !!! + * Brute force "sort", but since we don't expect more than one or two + * arguments in a string, the setup cost of a fast sort will be more + * expensive than the loop. + */ + for (cnt1 = 1; cnt1 <= soff; ++cnt1) + for (cnt2 = 0; cnt2 < soff; ++cnt2) + if (cnt1 == str[cnt2].arg) { + memmove(s_rbp, str[cnt2].str, str[cnt2].prefix); + memmove(s_rbp + str[cnt2].prefix, + str[cnt2].str + str[cnt2].prefix + + str[cnt2].skip, str[cnt2].suffix); + s_rbp += str[cnt2].prefix + str[cnt2].suffix; + *s_rbp++ = + gp == NULL ? DEFAULT_NOPRINT : gp->noprint; + break; + } + *s_rbp = '\0'; + fmt = rbp; +#endif + +#ifndef NL_ARGMAX +format: /* Format the arguments into the string. */ +#endif + va_start(ap, fmt); + len = vsnprintf(mp, REM, fmt, ap); + va_end(ap); + if (len >= nlen) + goto retry; + +#ifndef NL_ARGMAX + if (soff == 0) + goto nofmt; + + /* + * Go through the resulting string, and, for each separator character + * separated string, enter its new starting position and length in the + * array. + */ + for (p = t = mp, cnt1 = 1, + ch = gp == NULL ? DEFAULT_NOPRINT : gp->noprint; *p != '\0'; ++p) + if (*p == ch) { + for (cnt2 = 0; cnt2 < soff; ++cnt2) + if (str[cnt2].arg == cnt1) + break; + str[cnt2].str = t; + str[cnt2].prefix = p - t; + t = p + 1; + ++cnt1; + } + + /* + * Reorder the strings once again, putting them back into the + * message buffer. + * + * !!! + * Note, the length of the message gets decremented once for + * each substring, when we discard the separator character. + */ + for (s_rbp = rbp, cnt1 = 0; cnt1 < soff; ++cnt1) { + memmove(rbp, str[cnt1].str, str[cnt1].prefix); + rbp += str[cnt1].prefix; + --len; + } + memmove(mp, s_rbp, rbp - s_rbp); + + /* Free the reordered string memory. */ + free(s_rbp); +#endif + +nofmt: mp += len; + if ((mlen += len) > blen) + goto retry; + if (mt == M_SYSERR) { + len = snprintf(mp, REM, ": %s", strerror(errno)); + mp += len; + if ((mlen += len) > blen) + goto retry; + mt = M_ERR; + } + + /* Add trailing newline. */ + if ((mlen += 1) > blen) + goto retry; + *mp = '\n'; + + if (sp != NULL) + (void)ex_fflush(sp); + if (gp != NULL) + gp->scr_msg(sp, mt, bp, mlen); + else + (void)fprintf(stderr, "%.*s", (int)mlen, bp); + + /* Cleanup. */ +#ifndef NL_ARGMAX +ret: +#endif + FREE_SPACE(sp, bp, blen); +alloc_err: + reenter = 0; +} + +/* + * msgq_wstr -- + * Display a message with an embedded string. + * + * PUBLIC: void msgq_wstr(SCR *, mtype_t, const CHAR_T *, const char *); + */ +void +msgq_wstr(SCR *sp, mtype_t mtype, const CHAR_T *str, const char *fmt) +{ + size_t nlen; + CONST char *nstr; + + if (str == NULL) { + msgq(sp, mtype, "%s", fmt); + return; + } + INT2CHAR(sp, str, STRLEN(str) + 1, nstr, nlen); + msgq_str(sp, mtype, nstr, fmt); +} + +/* + * msgq_str -- + * Display a message with an embedded string. + * + * PUBLIC: void msgq_str(SCR *, mtype_t, const char *, const char *); + */ +void +msgq_str(SCR *sp, mtype_t mtype, const char *str, const char *fmt) +{ + int nf, sv_errno; + char *p; + + if (str == NULL) { + msgq(sp, mtype, "%s", fmt); + return; + } + + sv_errno = errno; + p = msg_print(sp, str, &nf); + errno = sv_errno; + msgq(sp, mtype, fmt, p); + if (nf) + FREE_SPACE(sp, p, 0); +} + +/* + * mod_rpt -- + * Report on the lines that changed. + * + * !!! + * Historic vi documentation (USD:15-8) claimed that "The editor will also + * always tell you when a change you make affects text which you cannot see." + * This wasn't true -- edit a large file and do "100d|1". We don't implement + * this semantic since it requires tracking each line that changes during a + * command instead of just keeping count. + * + * Line counts weren't right in historic vi, either. For example, given the + * file: + * abc + * def + * the command 2d}, from the 'b' would report that two lines were deleted, + * not one. + * + * PUBLIC: void mod_rpt(SCR *); + */ +void +mod_rpt(SCR *sp) +{ + static char * const action[] = { + "293|added", + "294|changed", + "295|deleted", + "296|joined", + "297|moved", + "298|shifted", + "299|yanked", + }; + static char * const lines[] = { + "300|line", + "301|lines", + }; + recno_t total; + u_long rptval; + int first, cnt; + size_t blen, len, tlen; + const char *t; + char * const *ap; + char *bp, *p; + + /* Change reports are turned off in batch mode. */ + if (F_ISSET(sp, SC_EX_SILENT)) + return; + + /* Reset changing line number. */ + sp->rptlchange = OOBLNO; + + /* + * Don't build a message if not enough changed. + * + * !!! + * And now, a vi clone test. Historically, vi reported if the number + * of changed lines was > than the value, not >=, unless it was a yank + * command, which used >=. No lie. Furthermore, an action was never + * reported for a single line action. This is consistent for actions + * other than yank, but yank didn't report single line actions even if + * the report edit option was set to 1. In addition, setting report to + * 0 in the 4BSD historic vi was equivalent to setting it to 1, for an + * unknown reason (this bug was fixed in System III/V at some point). + * I got complaints, so nvi conforms to System III/V historic practice + * except that we report a yank of 1 line if report is set to 1. + */ +#define ARSIZE(a) sizeof(a) / sizeof (*a) +#define MAXNUM 25 + rptval = O_VAL(sp, O_REPORT); + for (cnt = 0, total = 0; cnt < ARSIZE(action); ++cnt) + total += sp->rptlines[cnt]; + if (total == 0) + return; + if (total <= rptval && sp->rptlines[L_YANKED] < rptval) { + for (cnt = 0; cnt < ARSIZE(action); ++cnt) + sp->rptlines[cnt] = 0; + return; + } + + /* Build and display the message. */ + GET_SPACE_GOTOC(sp, bp, blen, sizeof(action) * MAXNUM + 1); + for (p = bp, first = 1, tlen = 0, + ap = action, cnt = 0; cnt < ARSIZE(action); ++ap, ++cnt) + if (sp->rptlines[cnt] != 0) { + if (first) + first = 0; + else { + *p++ = ';'; + *p++ = ' '; + tlen += 2; + } + len = snprintf(p, MAXNUM, "%lu ", + (u_long)sp->rptlines[cnt]); + p += len; + tlen += len; + t = msg_cat(sp, + lines[sp->rptlines[cnt] == 1 ? 0 : 1], &len); + memcpy(p, t, len); + p += len; + tlen += len; + *p++ = ' '; + ++tlen; + t = msg_cat(sp, *ap, &len); + memcpy(p, t, len); + p += len; + tlen += len; + sp->rptlines[cnt] = 0; + } + + /* Add trailing newline. */ + *p = '\n'; + ++tlen; + + (void)ex_fflush(sp); + sp->gp->scr_msg(sp, M_INFO, bp, tlen); + + FREE_SPACE(sp, bp, blen); +alloc_err: + return; + +#undef ARSIZE +#undef MAXNUM +} + +/* + * msgq_status -- + * Report on the file's status. + * + * PUBLIC: void msgq_status(SCR *, recno_t, u_int); + */ +void +msgq_status(SCR *sp, recno_t lno, u_int flags) +{ + recno_t last; + size_t blen, len; + int cnt, needsep; + const char *t; + char **ap, *bp, *np, *p, *s, *ep; + CHAR_T *wp; + size_t wlen; + + /* Get sufficient memory. */ + len = strlen(sp->frp->name); + GET_SPACE_GOTOC(sp, bp, blen, len * MAX_CHARACTER_COLUMNS + 128); + p = bp; + ep = bp + blen; + + /* Convert the filename. */ + CHAR2INT(sp, sp->frp->name, len + 1, wp, wlen); + + /* Copy in the filename. */ + for (; *wp != '\0'; ++wp) { + len = KEY_LEN(sp, *wp); + memcpy(p, KEY_NAME(sp, *wp), len); + p += len; + } + np = p; + *p++ = ':'; + *p++ = ' '; + + /* Copy in the argument count. */ + if (F_ISSET(sp, SC_STATUS_CNT) && sp->argv != NULL) { + for (cnt = 0, ap = sp->argv; *ap != NULL; ++ap, ++cnt); + if (cnt > 1) { + (void)snprintf(p, ep - p, + msg_cat(sp, "317|%d files to edit", NULL), cnt); + p += strlen(p); + *p++ = ':'; + *p++ = ' '; + } + F_CLR(sp, SC_STATUS_CNT); + } + + /* + * See nvi/exf.c:file_init() for a description of how and when the + * read-only bit is set. + * + * !!! + * The historic display for "name changed" was "[Not edited]". + */ + needsep = 0; + if (F_ISSET(sp->frp, FR_NEWFILE)) { + F_CLR(sp->frp, FR_NEWFILE); + t = msg_cat(sp, "021|new file", &len); + memcpy(p, t, len); + p += len; + needsep = 1; + } else { + if (F_ISSET(sp->frp, FR_NAMECHANGE)) { + t = msg_cat(sp, "022|name changed", &len); + memcpy(p, t, len); + p += len; + needsep = 1; + } + if (needsep) { + *p++ = ','; + *p++ = ' '; + } + if (F_ISSET(sp->ep, F_MODIFIED)) + t = msg_cat(sp, "023|modified", &len); + else + t = msg_cat(sp, "024|unmodified", &len); + memcpy(p, t, len); + p += len; + needsep = 1; + } + if (F_ISSET(sp->frp, FR_UNLOCKED)) { + if (needsep) { + *p++ = ','; + *p++ = ' '; + } + t = msg_cat(sp, "025|UNLOCKED", &len); + memcpy(p, t, len); + p += len; + needsep = 1; + } + if (O_ISSET(sp, O_READONLY)) { + if (needsep) { + *p++ = ','; + *p++ = ' '; + } + t = msg_cat(sp, "026|readonly", &len); + memcpy(p, t, len); + p += len; + needsep = 1; + } + if (needsep) { + *p++ = ':'; + *p++ = ' '; + } + if (LF_ISSET(MSTAT_SHOWLAST)) { + if (db_last(sp, &last)) + return; + if (last == 0) { + t = msg_cat(sp, "028|empty file", &len); + memcpy(p, t, len); + p += len; + } else { + t = msg_cat(sp, "027|line %lu of %lu [%ld%%]", &len); + (void)snprintf(p, ep - p, t, (u_long)lno, (u_long)last, + ((u_long)lno * 100) / last); + p += strlen(p); + } + } else { + t = msg_cat(sp, "029|line %lu", &len); + (void)snprintf(p, ep - p, t, (u_long)lno); + p += strlen(p); + } +#ifdef DEBUG + (void)snprintf(p, ep - p, " (pid %lu)", (u_long)getpid()); + p += strlen(p); +#endif + *p++ = '\n'; + len = p - bp; + + /* + * There's a nasty problem with long path names. Cscope and tags files + * can result in long paths and vi will request a continuation key from + * the user as soon as it starts the screen. Unfortunately, the user + * has already typed ahead, and chaos results. If we assume that the + * characters in the filenames and informational messages only take a + * single screen column each, we can trim the filename. + * + * XXX + * Status lines get put up at fairly awkward times. For example, when + * you do a filter read (e.g., :read ! echo foo) in the top screen of a + * split screen, we have to repaint the status lines for all the screens + * below the top screen. We don't want users having to enter continue + * characters for those screens. Make it really hard to screw this up. + */ + s = bp; + if (LF_ISSET(MSTAT_TRUNCATE) && len > sp->cols) { + for (; s < np && (*s != '/' || (p - s) > sp->cols - 3); ++s); + if (s == np) { + s = p - (sp->cols - 5); + *--s = ' '; + } + *--s = '.'; + *--s = '.'; + *--s = '.'; + len = p - s; + } + + /* Flush any waiting ex messages. */ + (void)ex_fflush(sp); + + sp->gp->scr_msg(sp, M_INFO, s, len); + + FREE_SPACE(sp, bp, blen); +alloc_err: + return; +} + +/* + * msg_open -- + * Open the message catalogs. + * + * PUBLIC: int msg_open(SCR *, char *); + */ +int +msg_open(SCR *sp, char *file) +{ + /* + * !!! + * Assume that the first file opened is the system default, and that + * all subsequent ones user defined. Only display error messages + * if we can't open the user defined ones -- it's useful to know if + * the system one wasn't there, but if nvi is being shipped with an + * installed system, the file will be there, if it's not, then the + * message will be repeated every time nvi is started up. + */ + static int first = 1; + nl_catd catd; + char *p; + int rval = 0; + + if ((p = strrchr(file, '/')) != NULL && p[1] == '\0') { + /* Confirms to XPG4. */ + if ((p = join(file, setlocale(LC_MESSAGES, NULL))) == NULL) { + msgq(sp, M_SYSERR, NULL); + return (1); + } + } else { + /* Make sure it's recognized as a path by catopen(3). */ + if ((p = join(".", file)) == NULL) { + msgq(sp, M_SYSERR, NULL); + return (1); + } + } + errno = 0; + if ((catd = catopen(p, NL_CAT_LOCALE)) == (nl_catd)-1) { + if (first) { + first = 0; + rval = 1; + goto ret; + } + + /* + * POSIX.1-2008 gives no instruction on how to report a + * corrupt catalog file. Errno == 0 is not rare; add + * EFTYPE, which is seen on FreeBSD, for a good measure. + */ +#ifdef EFTYPE + if (errno == 0 || errno == EFTYPE) +#else + if (errno == 0) +#endif + msgq_str(sp, M_ERR, p, + "030|The file %s is not a message catalog"); + else + msgq_str(sp, M_SYSERR, p, "%s"); + rval = 1; + goto ret; + } + first = 0; + + msg_close(sp->gp); + sp->gp->catd = catd; +ret: free(p); + return (rval); +} + +/* + * msg_close -- + * Close the message catalogs. + * + * PUBLIC: void msg_close(GS *); + */ +void +msg_close(GS *gp) +{ + if (gp->catd != (nl_catd)-1) + (void)catclose(gp->catd); +} + +/* + * msg_cont -- + * Return common continuation messages. + * + * PUBLIC: const char *msg_cmsg(SCR *, cmsg_t, size_t *); + */ +const char * +msg_cmsg(SCR *sp, cmsg_t which, size_t *lenp) +{ + switch (which) { + case CMSG_CONF: + return (msg_cat(sp, "268|confirm? [ynq]", lenp)); + case CMSG_CONT: + return (msg_cat(sp, "269|Press any key to continue: ", lenp)); + case CMSG_CONT_EX: + return (msg_cat(sp, + "270|Press any key to continue [: to enter more ex commands]: ", + lenp)); + case CMSG_CONT_R: + return (msg_cat(sp, "161|Press Enter to continue: ", lenp)); + case CMSG_CONT_S: + return (msg_cat(sp, "275| cont?", lenp)); + case CMSG_CONT_Q: + return (msg_cat(sp, + "271|Press any key to continue [q to quit]: ", lenp)); + default: + abort(); + } + /* NOTREACHED */ +} + +/* + * msg_cat -- + * Return a single message from the catalog, plus its length. + * + * !!! + * Only a single catalog message can be accessed at a time, if multiple + * ones are needed, they must be copied into local memory. + * + * PUBLIC: const char *msg_cat(SCR *, const char *, size_t *); + */ +const char * +msg_cat(SCR *sp, const char *str, size_t *lenp) +{ + GS *gp; + char *p; + int msgno; + + /* + * If it's not a catalog message, i.e. has doesn't have a leading + * number and '|' symbol, we're done. + */ + if (isdigit((u_char)str[0]) && + isdigit((u_char)str[1]) && + isdigit((u_char)str[2]) && str[3] == '|') { + msgno = atoi(str); + str = &str[4]; + + gp = sp == NULL ? NULL : sp->gp; + if (gp != NULL && gp->catd != (nl_catd)-1 && + (p = catgets(gp->catd, 1, msgno, str)) != NULL) { + if (lenp != NULL) + *lenp = strlen(p); + return (p); + } + } + if (lenp != NULL) + *lenp = strlen(str); + return (str); +} + +/* + * msg_print -- + * Return a printable version of a string, in allocated memory. + * + * PUBLIC: char *msg_print(SCR *, const char *, int *); + */ +char * +msg_print(SCR *sp, const char *s, int *needfree) +{ + size_t blen, nlen; + char *bp, *ep, *p, *t; + CHAR_T *wp, *cp; + size_t wlen; + + *needfree = 0; + + /* XXX Not good for debugging ex_read & ex_filter.*/ + CHAR2INT5(sp, EXP(sp)->ibcw, (char *)s, strlen(s) + 1, wp, wlen); + for (cp = wp; *cp != '\0'; ++cp) + if (!ISPRINT(*cp)) + break; + if (*cp == '\0') + return ((char *)s); /* SAFE: needfree set to 0. */ + + nlen = 0; + if (0) { +retry: if (sp == NULL) + free(bp); + else + FREE_SPACE(sp, bp, blen); + *needfree = 0; + } + nlen += 256; + if (sp == NULL) { + if ((bp = malloc(nlen)) == NULL) + goto alloc_err; + } else + GET_SPACE_GOTOC(sp, bp, blen, nlen); + if (0) { +alloc_err: return (""); + } + *needfree = 1; + + for (p = bp, ep = (bp + blen) - 1; *wp != '\0' && p < ep; ++wp) + for (t = KEY_NAME(sp, *wp); *t != '\0' && p < ep; *p++ = *t++); + if (p == ep) + goto retry; + *p = '\0'; + return (bp); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/common/msg.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/common/options.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/common/options.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/common/options.c (revision 366308) @@ -0,0 +1,1166 @@ +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1991, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "../vi/vi.h" +#include "pathnames.h" + +static int opts_abbcmp(const void *, const void *); +static int opts_cmp(const void *, const void *); +static int opts_print(SCR *, OPTLIST const *); + +#ifdef USE_WIDECHAR +#define OPT_WC 0 +#else +#define OPT_WC (OPT_NOSAVE | OPT_NDISP) +#endif + +/* + * O'Reilly noted options and abbreviations are from "Learning the VI Editor", + * Fifth Edition, May 1992. There's no way of knowing what systems they are + * actually from. + * + * HPUX noted options and abbreviations are from "The Ultimate Guide to the + * VI and EX Text Editors", 1990. + */ +OPTLIST const optlist[] = { +/* O_ALTWERASE 4.4BSD */ + {L("altwerase"), f_altwerase, OPT_0BOOL, 0}, +/* O_AUTOINDENT 4BSD */ + {L("autoindent"), NULL, OPT_0BOOL, 0}, +/* O_AUTOPRINT 4BSD */ + {L("autoprint"), NULL, OPT_1BOOL, 0}, +/* O_AUTOWRITE 4BSD */ + {L("autowrite"), NULL, OPT_0BOOL, 0}, +/* O_BACKUP 4.4BSD */ + {L("backup"), NULL, OPT_STR, 0}, +/* O_BEAUTIFY 4BSD */ + {L("beautify"), NULL, OPT_0BOOL, 0}, +/* O_CDPATH 4.4BSD */ + {L("cdpath"), NULL, OPT_STR, 0}, +/* O_CEDIT 4.4BSD */ + {L("cedit"), NULL, OPT_STR, 0}, +/* O_COLUMNS 4.4BSD */ + {L("columns"), f_columns, OPT_NUM, OPT_NOSAVE}, +/* O_COMBINED */ + {L("combined"), NULL, OPT_0BOOL, OPT_NOSET|OPT_WC}, +/* O_COMMENT 4.4BSD */ + {L("comment"), NULL, OPT_0BOOL, 0}, +/* O_TMPDIR 4BSD */ + {L("directory"), NULL, OPT_STR, 0}, +/* O_EDCOMPATIBLE 4BSD */ + {L("edcompatible"),NULL, OPT_0BOOL, 0}, +/* O_ERRORBELLS 4BSD */ + {L("errorbells"), NULL, OPT_0BOOL, 0}, +/* O_ESCAPETIME 4.4BSD */ + {L("escapetime"), NULL, OPT_NUM, 0}, +/* O_EXPANDTAB NetBSD 5.0 */ + {L("expandtab"), NULL, OPT_0BOOL, 0}, +/* O_EXRC System V (undocumented) */ + {L("exrc"), NULL, OPT_0BOOL, 0}, +/* O_EXTENDED 4.4BSD */ + {L("extended"), f_recompile, OPT_0BOOL, 0}, +/* O_FILEC 4.4BSD */ + {L("filec"), NULL, OPT_STR, 0}, +/* O_FILEENCODING */ + {L("fileencoding"),f_encoding, OPT_STR, OPT_WC}, +/* O_FLASH HPUX */ + {L("flash"), NULL, OPT_1BOOL, 0}, +/* O_HARDTABS 4BSD */ + {L("hardtabs"), NULL, OPT_NUM, 0}, +/* O_ICLOWER 4.4BSD */ + {L("iclower"), f_recompile, OPT_0BOOL, 0}, +/* O_IGNORECASE 4BSD */ + {L("ignorecase"), f_recompile, OPT_0BOOL, 0}, +/* O_INPUTENCODING */ + {L("inputencoding"),f_encoding, OPT_STR, OPT_WC}, +/* O_KEYTIME 4.4BSD */ + {L("keytime"), NULL, OPT_NUM, 0}, +/* O_LEFTRIGHT 4.4BSD */ + {L("leftright"), f_reformat, OPT_0BOOL, 0}, +/* O_LINES 4.4BSD */ + {L("lines"), f_lines, OPT_NUM, OPT_NOSAVE}, +/* O_LISP 4BSD + * XXX + * When the lisp option is implemented, delete the OPT_NOSAVE flag, + * so that :mkexrc dumps it. + */ + {L("lisp"), f_lisp, OPT_0BOOL, OPT_NOSAVE}, +/* O_LIST 4BSD */ + {L("list"), f_reformat, OPT_0BOOL, 0}, +/* O_LOCKFILES 4.4BSD + * XXX + * Locking isn't reliable enough over NFS to require it, in addition, + * it's a serious startup performance problem over some remote links. + */ + {L("lock"), NULL, OPT_1BOOL, 0}, +/* O_MAGIC 4BSD */ + {L("magic"), NULL, OPT_1BOOL, 0}, +/* O_MATCHCHARS NetBSD 2.0 */ + {L("matchchars"), NULL, OPT_STR, OPT_PAIRS}, +/* O_MATCHTIME 4.4BSD */ + {L("matchtime"), NULL, OPT_NUM, 0}, +/* O_MESG 4BSD */ + {L("mesg"), NULL, OPT_1BOOL, 0}, +/* O_MODELINE 4BSD + * !!! + * This has been documented in historical systems as both "modeline" + * and as "modelines". Regardless of the name, this option represents + * a security problem of mammoth proportions, not to mention a stunning + * example of what your intro CS professor referred to as the perils of + * mixing code and data. Don't add it, or I will kill you. + */ + {L("modeline"), NULL, OPT_0BOOL, OPT_NOSET}, +/* O_MSGCAT 4.4BSD */ + {L("msgcat"), f_msgcat, OPT_STR, 0}, +/* O_NOPRINT 4.4BSD */ + {L("noprint"), f_print, OPT_STR, 0}, +/* O_NUMBER 4BSD */ + {L("number"), f_reformat, OPT_0BOOL, 0}, +/* O_OCTAL 4.4BSD */ + {L("octal"), f_print, OPT_0BOOL, 0}, +/* O_OPEN 4BSD */ + {L("open"), NULL, OPT_1BOOL, 0}, +/* O_OPTIMIZE 4BSD */ + {L("optimize"), NULL, OPT_1BOOL, 0}, +/* O_PARAGRAPHS 4BSD */ + {L("paragraphs"), NULL, OPT_STR, OPT_PAIRS}, +/* O_PATH 4.4BSD */ + {L("path"), NULL, OPT_STR, 0}, +/* O_PRINT 4.4BSD */ + {L("print"), f_print, OPT_STR, 0}, +/* O_PROMPT 4BSD */ + {L("prompt"), NULL, OPT_1BOOL, 0}, +/* O_READONLY 4BSD (undocumented) */ + {L("readonly"), f_readonly, OPT_0BOOL, OPT_ALWAYS}, +/* O_RECDIR 4.4BSD */ + {L("recdir"), NULL, OPT_STR, 0}, +/* O_REDRAW 4BSD */ + {L("redraw"), NULL, OPT_0BOOL, 0}, +/* O_REMAP 4BSD */ + {L("remap"), NULL, OPT_1BOOL, 0}, +/* O_REPORT 4BSD */ + {L("report"), NULL, OPT_NUM, 0}, +/* O_RULER 4.4BSD */ + {L("ruler"), NULL, OPT_0BOOL, 0}, +/* O_SCROLL 4BSD */ + {L("scroll"), NULL, OPT_NUM, 0}, +/* O_SEARCHINCR 4.4BSD */ + {L("searchincr"), NULL, OPT_0BOOL, 0}, +/* O_SECTIONS 4BSD */ + {L("sections"), NULL, OPT_STR, OPT_PAIRS}, +/* O_SECURE 4.4BSD */ + {L("secure"), NULL, OPT_0BOOL, OPT_NOUNSET}, +/* O_SHELL 4BSD */ + {L("shell"), NULL, OPT_STR, 0}, +/* O_SHELLMETA 4.4BSD */ + {L("shellmeta"), NULL, OPT_STR, 0}, +/* O_SHIFTWIDTH 4BSD */ + {L("shiftwidth"), NULL, OPT_NUM, OPT_NOZERO}, +/* O_SHOWMATCH 4BSD */ + {L("showmatch"), NULL, OPT_0BOOL, 0}, +/* O_SHOWMODE 4.4BSD */ + {L("showmode"), NULL, OPT_0BOOL, 0}, +/* O_SIDESCROLL 4.4BSD */ + {L("sidescroll"), NULL, OPT_NUM, OPT_NOZERO}, +/* O_SLOWOPEN 4BSD */ + {L("slowopen"), NULL, OPT_0BOOL, 0}, +/* O_SOURCEANY 4BSD (undocumented) + * !!! + * Historic vi, on startup, source'd $HOME/.exrc and ./.exrc, if they + * were owned by the user. The sourceany option was an undocumented + * feature of historic vi which permitted the startup source'ing of + * .exrc files the user didn't own. This is an obvious security problem, + * and we ignore the option. + */ + {L("sourceany"), NULL, OPT_0BOOL, OPT_NOSET}, +/* O_TABSTOP 4BSD */ + {L("tabstop"), f_reformat, OPT_NUM, OPT_NOZERO}, +/* O_TAGLENGTH 4BSD */ + {L("taglength"), NULL, OPT_NUM, 0}, +/* O_TAGS 4BSD */ + {L("tags"), NULL, OPT_STR, 0}, +/* O_TERM 4BSD + * !!! + * By default, the historic vi always displayed information about two + * options, redraw and term. Term seems sufficient. + */ + {L("term"), NULL, OPT_STR, OPT_ADISP|OPT_NOSAVE}, +/* O_TERSE 4BSD */ + {L("terse"), NULL, OPT_0BOOL, 0}, +/* O_TILDEOP 4.4BSD */ + {L("tildeop"), NULL, OPT_0BOOL, 0}, +/* O_TIMEOUT 4BSD (undocumented) */ + {L("timeout"), NULL, OPT_1BOOL, 0}, +/* O_TTYWERASE 4.4BSD */ + {L("ttywerase"), f_ttywerase, OPT_0BOOL, 0}, +/* O_VERBOSE 4.4BSD */ + {L("verbose"), NULL, OPT_0BOOL, 0}, +/* O_W1200 4BSD */ + {L("w1200"), f_w1200, OPT_NUM, OPT_NDISP|OPT_NOSAVE}, +/* O_W300 4BSD */ + {L("w300"), f_w300, OPT_NUM, OPT_NDISP|OPT_NOSAVE}, +/* O_W9600 4BSD */ + {L("w9600"), f_w9600, OPT_NUM, OPT_NDISP|OPT_NOSAVE}, +/* O_WARN 4BSD */ + {L("warn"), NULL, OPT_1BOOL, 0}, +/* O_WINDOW 4BSD */ + {L("window"), f_window, OPT_NUM, 0}, +/* O_WINDOWNAME 4BSD */ + {L("windowname"), NULL, OPT_0BOOL, 0}, +/* O_WRAPLEN 4.4BSD */ + {L("wraplen"), NULL, OPT_NUM, 0}, +/* O_WRAPMARGIN 4BSD */ + {L("wrapmargin"), NULL, OPT_NUM, 0}, +/* O_WRAPSCAN 4BSD */ + {L("wrapscan"), NULL, OPT_1BOOL, 0}, +/* O_WRITEANY 4BSD */ + {L("writeany"), NULL, OPT_0BOOL, 0}, + {NULL}, +}; + +typedef struct abbrev { + CHAR_T *name; + int offset; +} OABBREV; + +static OABBREV const abbrev[] = { + {L("ai"), O_AUTOINDENT}, /* 4BSD */ + {L("ap"), O_AUTOPRINT}, /* 4BSD */ + {L("aw"), O_AUTOWRITE}, /* 4BSD */ + {L("bf"), O_BEAUTIFY}, /* 4BSD */ + {L("co"), O_COLUMNS}, /* 4.4BSD */ + {L("dir"), O_TMPDIR}, /* 4BSD */ + {L("eb"), O_ERRORBELLS}, /* 4BSD */ + {L("ed"), O_EDCOMPATIBLE}, /* 4BSD */ + {L("et"), O_EXPANDTAB}, /* NetBSD 5.0 */ + {L("ex"), O_EXRC}, /* System V (undocumented) */ + {L("fe"), O_FILEENCODING}, + {L("ht"), O_HARDTABS}, /* 4BSD */ + {L("ic"), O_IGNORECASE}, /* 4BSD */ + {L("ie"), O_INPUTENCODING}, + {L("li"), O_LINES}, /* 4.4BSD */ + {L("modelines"), O_MODELINE}, /* HPUX */ + {L("nu"), O_NUMBER}, /* 4BSD */ + {L("opt"), O_OPTIMIZE}, /* 4BSD */ + {L("para"), O_PARAGRAPHS}, /* 4BSD */ + {L("re"), O_REDRAW}, /* O'Reilly */ + {L("ro"), O_READONLY}, /* 4BSD (undocumented) */ + {L("scr"), O_SCROLL}, /* 4BSD (undocumented) */ + {L("sect"), O_SECTIONS}, /* O'Reilly */ + {L("sh"), O_SHELL}, /* 4BSD */ + {L("slow"), O_SLOWOPEN}, /* 4BSD */ + {L("sm"), O_SHOWMATCH}, /* 4BSD */ + {L("smd"), O_SHOWMODE}, /* 4BSD */ + {L("sw"), O_SHIFTWIDTH}, /* 4BSD */ + {L("tag"), O_TAGS}, /* 4BSD (undocumented) */ + {L("tl"), O_TAGLENGTH}, /* 4BSD */ + {L("to"), O_TIMEOUT}, /* 4BSD (undocumented) */ + {L("ts"), O_TABSTOP}, /* 4BSD */ + {L("tty"), O_TERM}, /* 4BSD (undocumented) */ + {L("ttytype"), O_TERM}, /* 4BSD (undocumented) */ + {L("w"), O_WINDOW}, /* O'Reilly */ + {L("wa"), O_WRITEANY}, /* 4BSD */ + {L("wi"), O_WINDOW}, /* 4BSD (undocumented) */ + {L("wl"), O_WRAPLEN}, /* 4.4BSD */ + {L("wm"), O_WRAPMARGIN}, /* 4BSD */ + {L("ws"), O_WRAPSCAN}, /* 4BSD */ + {NULL}, +}; + +/* + * opts_init -- + * Initialize some of the options. + * + * PUBLIC: int opts_init(SCR *, int *); + */ +int +opts_init(SCR *sp, int *oargs) +{ + ARGS *argv[2], a, b; + OPTLIST const *op; + u_long v; + int cnt, optindx = 0; + char *s; + CHAR_T b2[1024]; + + a.bp = b2; + b.bp = NULL; + a.len = b.len = 0; + argv[0] = &a; + argv[1] = &b; + + /* Set numeric and string default values. */ +#define OI(indx, str) do { \ + a.len = STRLEN(str); \ + if ((CHAR_T*)str != b2) /* GCC puts strings in text-space. */ \ + (void)MEMCPY(b2, str, a.len+1); \ + if (opts_set(sp, argv, NULL)) { \ + optindx = indx; \ + goto err; \ + } \ +} while (0) + /* + * Indirect global options to global space. Specifically, set up + * terminal, lines, columns first, they're used by other options. + * Note, don't set the flags until we've set up the indirection. + */ + if (o_set(sp, O_TERM, 0, NULL, GO_TERM)) + goto err; + F_SET(&sp->opts[O_TERM], OPT_GLOBAL); + if (o_set(sp, O_LINES, 0, NULL, GO_LINES)) + goto err; + F_SET(&sp->opts[O_LINES], OPT_GLOBAL); + if (o_set(sp, O_COLUMNS, 0, NULL, GO_COLUMNS)) + goto err; + F_SET(&sp->opts[O_COLUMNS], OPT_GLOBAL); + if (o_set(sp, O_SECURE, 0, NULL, GO_SECURE)) + goto err; + F_SET(&sp->opts[O_SECURE], OPT_GLOBAL); + + /* Initialize string values. */ + (void)SPRINTF(b2, SIZE(b2), + L("cdpath=%s"), (s = getenv("CDPATH")) == NULL ? ":" : s); + OI(O_CDPATH, b2); + OI(O_CEDIT, L("cedit=\033")); + + /* + * !!! + * Vi historically stored temporary files in /var/tmp. We store them + * in /tmp by default, hoping it's a memory based file system. There + * are two ways to change this -- the user can set either the directory + * option or the TMPDIR environmental variable. + */ + (void)SPRINTF(b2, SIZE(b2), + L("directory=%s"), (s = getenv("TMPDIR")) == NULL ? _PATH_TMP : s); + OI(O_TMPDIR, b2); + OI(O_ESCAPETIME, L("escapetime=6")); + OI(O_FILEC, L("filec=\t")); + OI(O_KEYTIME, L("keytime=6")); + OI(O_MATCHCHARS, L("matchchars=()[]{}")); + OI(O_MATCHTIME, L("matchtime=7")); + (void)SPRINTF(b2, SIZE(b2), L("msgcat=%s"), _PATH_MSGCAT); + OI(O_MSGCAT, b2); + OI(O_REPORT, L("report=5")); + OI(O_PARAGRAPHS, L("paragraphs=IPLPPPQPP LIpplpipbp")); + (void)SPRINTF(b2, SIZE(b2), L("path=%s"), ""); + OI(O_PATH, b2); + (void)SPRINTF(b2, SIZE(b2), L("recdir=%s"), NVI_PATH_PRESERVE); + OI(O_RECDIR, b2); + OI(O_SECTIONS, L("sections=NHSHH HUnhsh")); + (void)SPRINTF(b2, SIZE(b2), + L("shell=%s"), (s = getenv("SHELL")) == NULL ? _PATH_BSHELL : s); + OI(O_SHELL, b2); + OI(O_SHELLMETA, L("shellmeta=~{[*?$`'\"\\")); + OI(O_SHIFTWIDTH, L("shiftwidth=8")); + OI(O_SIDESCROLL, L("sidescroll=16")); + OI(O_TABSTOP, L("tabstop=8")); + (void)SPRINTF(b2, SIZE(b2), L("tags=%s"), _PATH_TAGS); + OI(O_TAGS, b2); + + /* + * XXX + * Initialize O_SCROLL here, after term; initializing term should + * have created a LINES/COLUMNS value. + */ + if ((v = (O_VAL(sp, O_LINES) - 1) / 2) == 0) + v = 1; + (void)SPRINTF(b2, SIZE(b2), L("scroll=%ld"), v); + OI(O_SCROLL, b2); + + /* + * The default window option values are: + * 8 if baud rate <= 600 + * 16 if baud rate <= 1200 + * LINES - 1 if baud rate > 1200 + * + * Note, the windows option code will correct any too-large value + * or when the O_LINES value is 1. + */ + if (sp->gp->scr_baud(sp, &v)) + return (1); + if (v <= 600) + v = 8; + else if (v <= 1200) + v = 16; + else if ((v = O_VAL(sp, O_LINES) - 1) == 0) + v = 1; + + (void)SPRINTF(b2, SIZE(b2), L("window=%lu"), v); + OI(O_WINDOW, b2); + + /* + * Set boolean default values, and copy all settings into the default + * information. OS_NOFREE is set, we're copying, not replacing. + */ + for (op = optlist, cnt = 0; op->name != NULL; ++op, ++cnt) { + if (F_ISSET(op, OPT_GLOBAL)) + continue; + switch (op->type) { + case OPT_0BOOL: + break; + case OPT_1BOOL: + O_SET(sp, cnt); + O_D_SET(sp, cnt); + break; + case OPT_NUM: + o_set(sp, cnt, OS_DEF, NULL, O_VAL(sp, cnt)); + break; + case OPT_STR: + if (O_STR(sp, cnt) != NULL && o_set(sp, cnt, + OS_DEF | OS_NOFREE | OS_STRDUP, O_STR(sp, cnt), 0)) + goto err; + break; + default: + abort(); + } + } + + /* + * !!! + * Some options can be initialized by the command name or the + * command-line arguments. They don't set the default values, + * it's historic practice. + */ + for (; *oargs != -1; ++oargs) + OI(*oargs, optlist[*oargs].name); +#undef OI + return (0); + +err: msgq_wstr(sp, M_ERR, optlist[optindx].name, + "031|Unable to set default %s option"); + return (1); +} + +/* + * opts_set -- + * Change the values of one or more options. + * + * PUBLIC: int opts_set(SCR *, ARGS *[], char *); + */ +int +opts_set(SCR *sp, ARGS *argv[], char *usage) +{ + enum optdisp disp; + enum nresult nret; + OPTLIST const *op; + OPTION *spo; + u_long isset, turnoff, value; + int ch, equals, nf, nf2, offset, qmark, rval; + CHAR_T *endp, *name, *p, *sep; + char *p2, *t2; + char *np; + size_t nlen; + + disp = NO_DISPLAY; + for (rval = 0; argv[0]->len != 0; ++argv) { + /* + * The historic vi dumped the options for each occurrence of + * "all" in the set list. Puhleeze. + */ + if (!STRCMP(argv[0]->bp, L("all"))) { + disp = ALL_DISPLAY; + continue; + } + + /* Find equals sign or question mark. */ + for (sep = NULL, equals = qmark = 0, + p = name = argv[0]->bp; (ch = *p) != '\0'; ++p) + if (ch == '=' || ch == '?') { + if (p == name) { + if (usage != NULL) + msgq(sp, M_ERR, + "032|Usage: %s", usage); + return (1); + } + sep = p; + if (ch == '=') + equals = 1; + else + qmark = 1; + break; + } + + turnoff = 0; + op = NULL; + if (sep != NULL) + *sep++ = '\0'; + + /* Search for the name, then name without any leading "no". */ + if ((op = opts_search(name)) == NULL && + name[0] == 'n' && name[1] == 'o') { + turnoff = 1; + name += 2; + op = opts_search(name); + } + if (op == NULL) { + opts_nomatch(sp, name); + rval = 1; + continue; + } + + /* Find current option values. */ + offset = op - optlist; + spo = sp->opts + offset; + + /* + * !!! + * Historically, the question mark could be a separate + * argument. + */ + if (!equals && !qmark && + argv[1]->len == 1 && argv[1]->bp[0] == '?') { + ++argv; + qmark = 1; + } + + /* Set name, value. */ + switch (op->type) { + case OPT_0BOOL: + case OPT_1BOOL: + /* Some options may not be reset. */ + if (F_ISSET(op, OPT_NOUNSET) && turnoff) { + msgq_wstr(sp, M_ERR, name, + "291|set: the %s option may not be turned off"); + rval = 1; + break; + } + + /* Some options may not be set. */ + if (F_ISSET(op, OPT_NOSET) && !turnoff) { + msgq_wstr(sp, M_ERR, name, + "313|set: the %s option may never be turned on"); + rval = 1; + break; + } + + if (equals) { + msgq_wstr(sp, M_ERR, name, + "034|set: [no]%s option doesn't take a value"); + rval = 1; + break; + } + if (qmark) { + if (!disp) + disp = SELECT_DISPLAY; + F_SET(spo, OPT_SELECTED); + break; + } + + /* + * Do nothing if the value is unchanged, the underlying + * functions can be expensive. + */ + isset = !turnoff; + if (!F_ISSET(op, OPT_ALWAYS)) { + if (isset) { + if (O_ISSET(sp, offset)) + break; + } else + if (!O_ISSET(sp, offset)) + break; + } + + /* Report to subsystems. */ + if ((op->func != NULL && + op->func(sp, spo, NULL, &isset)) || + ex_optchange(sp, offset, NULL, &isset) || + v_optchange(sp, offset, NULL, &isset) || + sp->gp->scr_optchange(sp, offset, NULL, &isset)) { + rval = 1; + break; + } + + /* Set the value. */ + if (isset) + O_SET(sp, offset); + else + O_CLR(sp, offset); + break; + case OPT_NUM: + if (turnoff) { + msgq_wstr(sp, M_ERR, name, + "035|set: %s option isn't a boolean"); + rval = 1; + break; + } + if (qmark || !equals) { + if (!disp) + disp = SELECT_DISPLAY; + F_SET(spo, OPT_SELECTED); + break; + } + + if (!ISDIGIT(sep[0])) + goto badnum; + if ((nret = + nget_uslong(&value, sep, &endp, 10)) != NUM_OK) { + INT2CHAR(sp, name, STRLEN(name) + 1, + np, nlen); + p2 = msg_print(sp, np, &nf); + INT2CHAR(sp, sep, STRLEN(sep) + 1, + np, nlen); + t2 = msg_print(sp, np, &nf2); + switch (nret) { + case NUM_ERR: + msgq(sp, M_SYSERR, + "036|set: %s option: %s", p2, t2); + break; + case NUM_OVER: + msgq(sp, M_ERR, + "037|set: %s option: %s: value overflow", p2, t2); + break; + case NUM_OK: + case NUM_UNDER: + abort(); + } + if (nf) + FREE_SPACE(sp, p2, 0); + if (nf2) + FREE_SPACE(sp, t2, 0); + rval = 1; + break; + } + if (*endp && !cmdskip(*endp)) { +badnum: INT2CHAR(sp, name, STRLEN(name) + 1, + np, nlen); + p2 = msg_print(sp, np, &nf); + INT2CHAR(sp, sep, STRLEN(sep) + 1, + np, nlen); + t2 = msg_print(sp, np, &nf2); + msgq(sp, M_ERR, + "038|set: %s option: %s is an illegal number", p2, t2); + if (nf) + FREE_SPACE(sp, p2, 0); + if (nf2) + FREE_SPACE(sp, t2, 0); + rval = 1; + break; + } + + /* Some options may never be set to zero. */ + if (F_ISSET(op, OPT_NOZERO) && value == 0) { + msgq_wstr(sp, M_ERR, name, + "314|set: the %s option may never be set to 0"); + rval = 1; + break; + } + + /* + * Do nothing if the value is unchanged, the underlying + * functions can be expensive. + */ + if (!F_ISSET(op, OPT_ALWAYS) && + O_VAL(sp, offset) == value) + break; + + /* Report to subsystems. */ + INT2CHAR(sp, sep, STRLEN(sep) + 1, np, nlen); + if ((op->func != NULL && + op->func(sp, spo, np, &value)) || + ex_optchange(sp, offset, np, &value) || + v_optchange(sp, offset, np, &value) || + sp->gp->scr_optchange(sp, offset, np, &value)) { + rval = 1; + break; + } + + /* Set the value. */ + if (o_set(sp, offset, 0, NULL, value)) + rval = 1; + break; + case OPT_STR: + if (turnoff) { + msgq_wstr(sp, M_ERR, name, + "039|set: %s option isn't a boolean"); + rval = 1; + break; + } + if (qmark || !equals) { + if (!disp) + disp = SELECT_DISPLAY; + F_SET(spo, OPT_SELECTED); + break; + } + + /* Check for strings that must have even length. */ + if (F_ISSET(op, OPT_PAIRS) && STRLEN(sep) & 1) { + msgq_wstr(sp, M_ERR, name, + "047|The %s option must be in two character groups"); + rval = 1; + break; + } + + /* + * Do nothing if the value is unchanged, the underlying + * functions can be expensive. + */ + INT2CHAR(sp, sep, STRLEN(sep) + 1, np, nlen); + if (!F_ISSET(op, OPT_ALWAYS) && + O_STR(sp, offset) != NULL && + !strcmp(O_STR(sp, offset), np)) + break; + + /* Report to subsystems. */ + if ((op->func != NULL && + op->func(sp, spo, np, NULL)) || + ex_optchange(sp, offset, np, NULL) || + v_optchange(sp, offset, np, NULL) || + sp->gp->scr_optchange(sp, offset, np, NULL)) { + rval = 1; + break; + } + + /* Set the value. */ + if (o_set(sp, offset, OS_STRDUP, np, 0)) + rval = 1; + break; + default: + abort(); + } + } + if (disp != NO_DISPLAY) + opts_dump(sp, disp); + return (rval); +} + +/* + * o_set -- + * Set an option's value. + * + * PUBLIC: int o_set(SCR *, int, u_int, char *, u_long); + */ +int +o_set(SCR *sp, int opt, u_int flags, char *str, u_long val) +{ + OPTION *op; + + /* Set a pointer to the options area. */ + op = F_ISSET(&sp->opts[opt], OPT_GLOBAL) ? + &sp->gp->opts[sp->opts[opt].o_cur.val] : &sp->opts[opt]; + + /* Copy the string, if requested. */ + if (LF_ISSET(OS_STRDUP) && (str = strdup(str)) == NULL) { + msgq(sp, M_SYSERR, NULL); + return (1); + } + + /* Free the previous string, if requested, and set the value. */ + if LF_ISSET(OS_DEF) + if (LF_ISSET(OS_STR | OS_STRDUP)) { + if (!LF_ISSET(OS_NOFREE)) + free(op->o_def.str); + op->o_def.str = str; + } else + op->o_def.val = val; + else + if (LF_ISSET(OS_STR | OS_STRDUP)) { + if (!LF_ISSET(OS_NOFREE)) + free(op->o_cur.str); + op->o_cur.str = str; + } else + op->o_cur.val = val; + return (0); +} + +/* + * opts_empty -- + * Return 1 if the string option is invalid, 0 if it's OK. + * + * PUBLIC: int opts_empty(SCR *, int, int); + */ +int +opts_empty(SCR *sp, int off, int silent) +{ + char *p; + + if ((p = O_STR(sp, off)) == NULL || p[0] == '\0') { + if (!silent) + msgq_wstr(sp, M_ERR, optlist[off].name, + "305|No %s edit option specified"); + return (1); + } + return (0); +} + +/* + * opts_dump -- + * List the current values of selected options. + * + * PUBLIC: void opts_dump(SCR *, enum optdisp); + */ +void +opts_dump(SCR *sp, enum optdisp type) +{ + OPTLIST const *op; + int base, b_num, cnt, col, colwidth, curlen, s_num; + int numcols, numrows, row; + int b_op[O_OPTIONCOUNT], s_op[O_OPTIONCOUNT]; + char nbuf[20]; + + /* + * Options are output in two groups -- those that fit in a column and + * those that don't. Output is done on 6 character "tab" boundaries + * for no particular reason. (Since we don't output tab characters, + * we can ignore the terminal's tab settings.) Ignore the user's tab + * setting because we have no idea how reasonable it is. + * + * Find a column width we can live with, testing from 10 columns to 1. + */ + for (numcols = 10; numcols > 1; --numcols) { + colwidth = sp->cols / numcols & ~(STANDARD_TAB - 1); + if (colwidth >= 10) { + colwidth = + (colwidth + STANDARD_TAB) & ~(STANDARD_TAB - 1); + numcols = sp->cols / colwidth; + break; + } + colwidth = 0; + } + + /* + * Get the set of options to list, entering them into + * the column list or the overflow list. + */ + for (b_num = s_num = 0, op = optlist; op->name != NULL; ++op) { + cnt = op - optlist; + + /* If OPT_NDISP set, it's never displayed. */ + if (F_ISSET(op, OPT_NDISP)) + continue; + + switch (type) { + case ALL_DISPLAY: /* Display all. */ + break; + case CHANGED_DISPLAY: /* Display changed. */ + /* If OPT_ADISP set, it's always "changed". */ + if (F_ISSET(op, OPT_ADISP)) + break; + switch (op->type) { + case OPT_0BOOL: + case OPT_1BOOL: + case OPT_NUM: + if (O_VAL(sp, cnt) == O_D_VAL(sp, cnt)) + continue; + break; + case OPT_STR: + if (O_STR(sp, cnt) == O_D_STR(sp, cnt) || + (O_D_STR(sp, cnt) != NULL && + !strcmp(O_STR(sp, cnt), O_D_STR(sp, cnt)))) + continue; + break; + } + break; + case SELECT_DISPLAY: /* Display selected. */ + if (!F_ISSET(&sp->opts[cnt], OPT_SELECTED)) + continue; + break; + default: + case NO_DISPLAY: + abort(); + } + F_CLR(&sp->opts[cnt], OPT_SELECTED); + + curlen = STRLEN(op->name); + switch (op->type) { + case OPT_0BOOL: + case OPT_1BOOL: + if (!O_ISSET(sp, cnt)) + curlen += 2; + break; + case OPT_NUM: + (void)snprintf(nbuf, + sizeof(nbuf), "%ld", O_VAL(sp, cnt)); + curlen += strlen(nbuf); + break; + case OPT_STR: + if (O_STR(sp, cnt) != NULL) + curlen += strlen(O_STR(sp, cnt)); + curlen += 3; + break; + } + /* Offset by 2 so there's a gap. */ + if (curlen <= colwidth - 2) + s_op[s_num++] = cnt; + else + b_op[b_num++] = cnt; + } + + if (s_num > 0) { + /* Figure out the number of rows. */ + if (s_num > numcols) { + numrows = s_num / numcols; + if (s_num % numcols) + ++numrows; + } else + numrows = 1; + + /* Display the options in sorted order. */ + for (row = 0; row < numrows;) { + for (base = row, col = 0; col < numcols; ++col) { + cnt = opts_print(sp, &optlist[s_op[base]]); + if ((base += numrows) >= s_num) + break; + (void)ex_printf(sp, "%*s", + (int)(colwidth - cnt), ""); + } + if (++row < numrows || b_num) + (void)ex_puts(sp, "\n"); + } + } + + for (row = 0; row < b_num;) { + (void)opts_print(sp, &optlist[b_op[row]]); + if (++row < b_num) + (void)ex_puts(sp, "\n"); + } + (void)ex_puts(sp, "\n"); +} + +/* + * opts_print -- + * Print out an option. + */ +static int +opts_print(SCR *sp, OPTLIST const *op) +{ + int curlen, offset; + const char *p; + + curlen = 0; + offset = op - optlist; + switch (op->type) { + case OPT_0BOOL: + case OPT_1BOOL: + curlen += ex_printf(sp, + "%s"WS, O_ISSET(sp, offset) ? "" : "no", op->name); + break; + case OPT_NUM: + curlen += ex_printf(sp, WS"=%ld", op->name, O_VAL(sp, offset)); + break; + case OPT_STR: + curlen += ex_printf(sp, WS"=\"", op->name); + p = O_STR(sp, offset); + /* Keep correct count for unprintable character sequences */ + if (p != NULL) + for (; *p != '\0'; ++p) + curlen += ex_puts(sp, unctrl(*p)); + curlen += ex_puts(sp, "\""); + break; + } + return (curlen); +} + +/* + * opts_save -- + * Write the current configuration to a file. + * + * PUBLIC: int opts_save(SCR *, FILE *); + */ +int +opts_save(SCR *sp, FILE *fp) +{ + OPTLIST const *op; + CHAR_T ch, *p; + char nch, *np; + int cnt; + + for (op = optlist; op->name != NULL; ++op) { + if (F_ISSET(op, OPT_NOSAVE)) + continue; + cnt = op - optlist; + switch (op->type) { + case OPT_0BOOL: + case OPT_1BOOL: + if (O_ISSET(sp, cnt)) + (void)fprintf(fp, "set "WS"\n", op->name); + else + (void)fprintf(fp, "set no"WS"\n", op->name); + break; + case OPT_NUM: + (void)fprintf(fp, + "set "WS"=%-3ld\n", op->name, O_VAL(sp, cnt)); + break; + case OPT_STR: + if (O_STR(sp, cnt) == NULL) + break; + (void)fprintf(fp, "set "); + for (p = op->name; (ch = *p) != '\0'; ++p) { + if (cmdskip(ch) || ch == '\\') + (void)putc('\\', fp); + fprintf(fp, WC, ch); + } + (void)putc('=', fp); + for (np = O_STR(sp, cnt); (nch = *np) != '\0'; ++np) { + if (cmdskip(nch) || nch == '\\') + (void)putc('\\', fp); + (void)putc(nch, fp); + } + (void)putc('\n', fp); + break; + } + if (ferror(fp)) { + msgq(sp, M_SYSERR, NULL); + return (1); + } + } + return (0); +} + +/* + * opts_search -- + * Search for an option. + * + * PUBLIC: OPTLIST const *opts_search(CHAR_T *); + */ +OPTLIST const * +opts_search(CHAR_T *name) +{ + OPTLIST const *op, *found; + OABBREV atmp, *ap; + OPTLIST otmp; + size_t len; + + /* Check list of abbreviations. */ + atmp.name = name; + if ((ap = bsearch(&atmp, abbrev, sizeof(abbrev) / sizeof(OABBREV) - 1, + sizeof(OABBREV), opts_abbcmp)) != NULL) + return (optlist + ap->offset); + + /* Check list of options. */ + otmp.name = name; + if ((op = bsearch(&otmp, optlist, sizeof(optlist) / sizeof(OPTLIST) - 1, + sizeof(OPTLIST), opts_cmp)) != NULL) + return (op); + + /* + * Check to see if the name is the prefix of one (and only one) + * option. If so, return the option. + */ + len = STRLEN(name); + for (found = NULL, op = optlist; op->name != NULL; ++op) { + if (op->name[0] < name[0]) + continue; + if (op->name[0] > name[0]) + break; + if (!MEMCMP(op->name, name, len)) { + if (found != NULL) + return (NULL); + found = op; + } + } + return (found); +} + +/* + * opts_nomatch -- + * Standard nomatch error message for options. + * + * PUBLIC: void opts_nomatch(SCR *, CHAR_T *); + */ +void +opts_nomatch(SCR *sp, CHAR_T *name) +{ + msgq_wstr(sp, M_ERR, name, + "033|set: no %s option: 'set all' gives all option values"); +} + +static int +opts_abbcmp(const void *a, const void *b) +{ + return(STRCMP(((OABBREV *)a)->name, ((OABBREV *)b)->name)); +} + +static int +opts_cmp(const void *a, const void *b) +{ + return(STRCMP(((OPTLIST *)a)->name, ((OPTLIST *)b)->name)); +} + +/* + * opts_copy -- + * Copy a screen's OPTION array. + * + * PUBLIC: int opts_copy(SCR *, SCR *); + */ +int +opts_copy(SCR *orig, SCR *sp) +{ + int cnt, rval; + + /* Copy most everything without change. */ + memcpy(sp->opts, orig->opts, sizeof(orig->opts)); + + /* Copy the string edit options. */ + for (cnt = rval = 0; cnt < O_OPTIONCOUNT; ++cnt) { + if (optlist[cnt].type != OPT_STR || + F_ISSET(&sp->opts[cnt], OPT_GLOBAL)) + continue; + /* + * If never set, or already failed, NULL out the entries -- + * have to continue after failure, otherwise would have two + * screens referencing the same memory. + */ + if (rval || O_STR(sp, cnt) == NULL) { + o_set(sp, cnt, OS_NOFREE | OS_STR, NULL, 0); + o_set(sp, cnt, OS_DEF | OS_NOFREE | OS_STR, NULL, 0); + continue; + } + + /* Copy the current string. */ + if (o_set(sp, cnt, OS_NOFREE | OS_STRDUP, O_STR(sp, cnt), 0)) { + o_set(sp, cnt, OS_DEF | OS_NOFREE | OS_STR, NULL, 0); + goto nomem; + } + + /* Copy the default string. */ + if (O_D_STR(sp, cnt) != NULL && o_set(sp, cnt, + OS_DEF | OS_NOFREE | OS_STRDUP, O_D_STR(sp, cnt), 0)) { +nomem: msgq(orig, M_SYSERR, NULL); + rval = 1; + } + } + return (rval); +} + +/* + * opts_free -- + * Free all option strings + * + * PUBLIC: void opts_free(SCR *); + */ +void +opts_free(SCR *sp) +{ + int cnt; + + for (cnt = 0; cnt < O_OPTIONCOUNT; ++cnt) { + if (optlist[cnt].type != OPT_STR || + F_ISSET(&sp->opts[cnt], OPT_GLOBAL)) + continue; + free(O_STR(sp, cnt)); + free(O_D_STR(sp, cnt)); + } +} Property changes on: vendor/nvi/2.2.0-05ed8b9/common/options.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/common/put.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/common/put.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/common/put.c (revision 366308) @@ -0,0 +1,224 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "common.h" + +/* + * put -- + * Put text buffer contents into the file. + * + * PUBLIC: int put(SCR *, CB *, CHAR_T *, MARK *, MARK *, int); + */ +int +put(SCR *sp, CB *cbp, CHAR_T *namep, MARK *cp, MARK *rp, int append) +{ + CHAR_T name; + TEXT *ltp, *tp; + recno_t lno; + size_t blen, clen, len; + int rval; + CHAR_T *bp, *t; + CHAR_T *p; + + if (cbp == NULL) { + if (namep == NULL) { + cbp = sp->gp->dcbp; + if (cbp == NULL) { + msgq(sp, M_ERR, + "053|The default buffer is empty"); + return (1); + } + } else { + name = *namep; + CBNAME(sp, cbp, name); + if (cbp == NULL) { + msgq(sp, M_ERR, "054|Buffer %s is empty", + KEY_NAME(sp, name)); + return (1); + } + } + } + tp = TAILQ_FIRST(cbp->textq); + + /* + * It's possible to do a put into an empty file, meaning that the cut + * buffer simply becomes the file. It's a special case so that we can + * ignore it in general. + * + * !!! + * Historically, pasting into a file with no lines in vi would preserve + * the single blank line. This is surely a result of the fact that the + * historic vi couldn't deal with a file that had no lines in it. This + * implementation treats that as a bug, and does not retain the blank + * line. + * + * Historical practice is that the cursor ends at the first character + * in the file. + */ + if (cp->lno == 1) { + if (db_last(sp, &lno)) + return (1); + if (lno == 0) { + for (; tp != NULL; + ++lno, ++sp->rptlines[L_ADDED], tp = TAILQ_NEXT(tp, q)) + if (db_append(sp, 1, lno, tp->lb, tp->len)) + return (1); + rp->lno = 1; + rp->cno = 0; + return (0); + } + } + + /* If a line mode buffer, append each new line into the file. */ + if (F_ISSET(cbp, CB_LMODE)) { + lno = append ? cp->lno : cp->lno - 1; + rp->lno = lno + 1; + for (; tp != NULL; + ++lno, ++sp->rptlines[L_ADDED], tp = TAILQ_NEXT(tp, q)) + if (db_append(sp, 1, lno, tp->lb, tp->len)) + return (1); + rp->cno = 0; + (void)nonblank(sp, rp->lno, &rp->cno); + return (0); + } + + /* + * If buffer was cut in character mode, replace the current line with + * one built from the portion of the first line to the left of the + * split plus the first line in the CB. Append each intermediate line + * in the CB. Append a line built from the portion of the first line + * to the right of the split plus the last line in the CB. + * + * Get the first line. + */ + lno = cp->lno; + if (db_get(sp, lno, DBG_FATAL, &p, &len)) + return (1); + + GET_SPACE_RETW(sp, bp, blen, tp->len + len + 1); + t = bp; + + /* Original line, left of the split. */ + if (len > 0 && (clen = cp->cno + (append ? 1 : 0)) > 0) { + MEMCPY(bp, p, clen); + p += clen; + t += clen; + } + + /* First line from the CB. */ + if (tp->len != 0) { + MEMCPY(t, tp->lb, tp->len); + t += tp->len; + } + + /* Calculate length left in the original line. */ + clen = len == 0 ? 0 : len - (cp->cno + (append ? 1 : 0)); + + /* + * !!! + * In the historical 4BSD version of vi, character mode puts within + * a single line have two cursor behaviors: if the put is from the + * unnamed buffer, the cursor moves to the character inserted which + * appears last in the file. If the put is from a named buffer, + * the cursor moves to the character inserted which appears first + * in the file. In System III/V, it was changed at some point and + * the cursor always moves to the first character. In both versions + * of vi, character mode puts that cross line boundaries leave the + * cursor on the first character. Nvi implements the System III/V + * behavior, and expect POSIX.2 to do so as well. + */ + rp->lno = lno; + rp->cno = len == 0 ? 0 : sp->cno + (append && tp->len ? 1 : 0); + + /* + * If no more lines in the CB, append the rest of the original + * line and quit. Otherwise, build the last line before doing + * the intermediate lines, because the line changes will lose + * the cached line. + */ + if (TAILQ_NEXT(tp, q) == NULL) { + if (clen > 0) { + MEMCPY(t, p, clen); + t += clen; + } + if (db_set(sp, lno, bp, t - bp)) + goto err; + if (sp->rptlchange != lno) { + sp->rptlchange = lno; + ++sp->rptlines[L_CHANGED]; + } + } else { + /* + * Have to build both the first and last lines of the + * put before doing any sets or we'll lose the cached + * line. Build both the first and last lines in the + * same buffer, so we don't have to have another buffer + * floating around. + * + * Last part of original line; check for space, reset + * the pointer into the buffer. + */ + ltp = TAILQ_LAST(cbp->textq, _texth); + len = t - bp; + ADD_SPACE_RETW(sp, bp, blen, ltp->len + clen); + t = bp + len; + + /* Add in last part of the CB. */ + MEMCPY(t, ltp->lb, ltp->len); + if (clen) + MEMCPY(t + ltp->len, p, clen); + clen += ltp->len; + + /* + * Now: bp points to the first character of the first + * line, t points to the last character of the last + * line, t - bp is the length of the first line, and + * clen is the length of the last. Just figured you'd + * want to know. + * + * Output the line replacing the original line. + */ + if (db_set(sp, lno, bp, t - bp)) + goto err; + if (sp->rptlchange != lno) { + sp->rptlchange = lno; + ++sp->rptlines[L_CHANGED]; + } + + /* Output any intermediate lines in the CB. */ + for (tp = TAILQ_NEXT(tp, q); TAILQ_NEXT(tp, q) != NULL; + ++lno, ++sp->rptlines[L_ADDED], tp = TAILQ_NEXT(tp, q)) + if (db_append(sp, 1, lno, tp->lb, tp->len)) + goto err; + + if (db_append(sp, 1, lno, t, clen)) + goto err; + ++sp->rptlines[L_ADDED]; + } + rval = 0; + + if (0) +err: rval = 1; + + FREE_SPACEW(sp, bp, blen); + return (rval); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/common/put.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/common/recover.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/common/recover.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/common/recover.c (revision 366308) @@ -0,0 +1,940 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +/* + * We include , because the open #defines were found there + * on historical systems. We also include because the open(2) + * #defines are found there on newer systems. + */ +#include + +#include +#include +#include +#include +#include +#include +#include /* Required by resolv.h. */ +#include +#include +#include +#include +#include +#include + +#include "../ex/version.h" +#include "common.h" +#include "pathnames.h" + +/* + * Recovery code. + * + * The basic scheme is as follows. In the EXF structure, we maintain full + * paths of a b+tree file and a mail recovery file. The former is the file + * used as backing store by the DB package. The latter is the file that + * contains an email message to be sent to the user if we crash. The two + * simple states of recovery are: + * + * + first starting the edit session: + * the b+tree file exists and is mode 700, the mail recovery + * file doesn't exist. + * + after the file has been modified: + * the b+tree file exists and is mode 600, the mail recovery + * file exists, and is exclusively locked. + * + * In the EXF structure we maintain a file descriptor that is the locked + * file descriptor for the mail recovery file. + * + * To find out if a recovery file/backing file pair are in use, try to get + * a lock on the recovery file. + * + * To find out if a backing file can be deleted at boot time, check for an + * owner execute bit. (Yes, I know it's ugly, but it's either that or put + * special stuff into the backing file itself, or correlate the files at + * boot time, neither of which looks like fun.) Note also that there's a + * window between when the file is created and the X bit is set. It's small, + * but it's there. To fix the window, check for 0 length files as well. + * + * To find out if a file can be recovered, check the F_RCV_ON bit. Note, + * this DOES NOT mean that any initialization has been done, only that we + * haven't yet failed at setting up or doing recovery. + * + * To preserve a recovery file/backing file pair, set the F_RCV_NORM bit. + * If that bit is not set when ending a file session: + * If the EXF structure paths (rcv_path and rcv_mpath) are not NULL, + * they are unlink(2)'d, and free(3)'d. + * If the EXF file descriptor (rcv_fd) is not -1, it is closed. + * + * The backing b+tree file is set up when a file is first edited, so that + * the DB package can use it for on-disk caching and/or to snapshot the + * file. When the file is first modified, the mail recovery file is created, + * the backing file permissions are updated, the file is sync(2)'d to disk, + * and the timer is started. Then, at RCV_PERIOD second intervals, the + * b+tree file is synced to disk. RCV_PERIOD is measured using SIGALRM, which + * means that the data structures (SCR, EXF, the underlying tree structures) + * must be consistent when the signal arrives. + * + * The recovery mail file contains normal mail headers, with two additional + * + * X-vi-data: ; + * + * MIME headers; the folding character is limited to ' '. + * + * Btree files are named "vi.XXXXXX" and recovery files are named + * "recover.XXXXXX". + */ + +#define VI_DHEADER "X-vi-data:" + +static int rcv_copy(SCR *, int, char *); +static void rcv_email(SCR *, char *); +static int rcv_mailfile(SCR *, int, char *); +static int rcv_mktemp(SCR *, char *, char *); +static int rcv_dlnwrite(SCR *, const char *, const char *, FILE *); +static int rcv_dlnread(SCR *, char **, char **, FILE *); + +/* + * rcv_tmp -- + * Build a file name that will be used as the recovery file. + * + * PUBLIC: int rcv_tmp(SCR *, EXF *, char *); + */ +int +rcv_tmp(SCR *sp, EXF *ep, char *name) +{ + struct stat sb; + int fd; + char *dp, *path; + + /* + * !!! + * ep MAY NOT BE THE SAME AS sp->ep, DON'T USE THE LATTER. + * + * + * If the recovery directory doesn't exist, try and create it. As + * the recovery files are themselves protected from reading/writing + * by other than the owner, the worst that can happen is that a user + * would have permission to remove other user's recovery files. If + * the sticky bit has the BSD semantics, that too will be impossible. + */ + if (opts_empty(sp, O_RECDIR, 0)) + goto err; + dp = O_STR(sp, O_RECDIR); + if (stat(dp, &sb)) { + if (errno != ENOENT || mkdir(dp, 0)) { + msgq(sp, M_SYSERR, "%s", dp); + goto err; + } + (void)chmod(dp, S_IRWXU | S_IRWXG | S_IRWXO | S_ISVTX); + } + + if ((path = join(dp, "vi.XXXXXX")) == NULL) + goto err; + if ((fd = rcv_mktemp(sp, path, dp)) == -1) { + free(path); + goto err; + } + (void)fchmod(fd, S_IRWXU); + (void)close(fd); + + ep->rcv_path = path; + if (0) { +err: msgq(sp, M_ERR, + "056|Modifications not recoverable if the session fails"); + return (1); + } + + /* We believe the file is recoverable. */ + F_SET(ep, F_RCV_ON); + return (0); +} + +/* + * rcv_init -- + * Force the file to be snapshotted for recovery. + * + * PUBLIC: int rcv_init(SCR *); + */ +int +rcv_init(SCR *sp) +{ + EXF *ep; + recno_t lno; + + ep = sp->ep; + + /* Only do this once. */ + F_CLR(ep, F_FIRSTMODIFY); + + /* If we already know the file isn't recoverable, we're done. */ + if (!F_ISSET(ep, F_RCV_ON)) + return (0); + + /* Turn off recoverability until we figure out if this will work. */ + F_CLR(ep, F_RCV_ON); + + /* Test if we're recovering a file, not editing one. */ + if (ep->rcv_mpath == NULL) { + /* Build a file to mail to the user. */ + if (rcv_mailfile(sp, 0, NULL)) + goto err; + + /* Force a read of the entire file. */ + if (db_last(sp, &lno)) + goto err; + + /* Turn on a busy message, and sync it to backing store. */ + sp->gp->scr_busy(sp, + "057|Copying file for recovery...", BUSY_ON); + if (ep->db->sync(ep->db, R_RECNOSYNC)) { + msgq_str(sp, M_SYSERR, ep->rcv_path, + "058|Preservation failed: %s"); + sp->gp->scr_busy(sp, NULL, BUSY_OFF); + goto err; + } + sp->gp->scr_busy(sp, NULL, BUSY_OFF); + } + + /* Turn off the owner execute bit. */ + (void)chmod(ep->rcv_path, S_IRUSR | S_IWUSR); + + /* We believe the file is recoverable. */ + F_SET(ep, F_RCV_ON); + return (0); + +err: msgq(sp, M_ERR, + "059|Modifications not recoverable if the session fails"); + return (1); +} + +/* + * rcv_sync -- + * Sync the file, optionally: + * flagging the backup file to be preserved + * snapshotting the backup file and send email to the user + * sending email to the user if the file was modified + * ending the file session + * + * PUBLIC: int rcv_sync(SCR *, u_int); + */ +int +rcv_sync(SCR *sp, u_int flags) +{ + EXF *ep; + int fd, rval; + char *dp, *buf; + + /* Make sure that there's something to recover/sync. */ + ep = sp->ep; + if (ep == NULL || !F_ISSET(ep, F_RCV_ON)) + return (0); + + /* Sync the file if it's been modified. */ + if (F_ISSET(ep, F_MODIFIED)) { + if (ep->db->sync(ep->db, R_RECNOSYNC)) { + F_CLR(ep, F_RCV_ON | F_RCV_NORM); + msgq_str(sp, M_SYSERR, + ep->rcv_path, "060|File backup failed: %s"); + return (1); + } + + /* REQUEST: don't remove backing file on exit. */ + if (LF_ISSET(RCV_PRESERVE)) + F_SET(ep, F_RCV_NORM); + + /* REQUEST: send email. */ + if (LF_ISSET(RCV_EMAIL)) + rcv_email(sp, ep->rcv_mpath); + } + + /* + * !!! + * Each time the user exec's :preserve, we have to snapshot all of + * the recovery information, i.e. it's like the user re-edited the + * file. We copy the DB(3) backing file, and then create a new mail + * recovery file, it's simpler than exiting and reopening all of the + * underlying files. + * + * REQUEST: snapshot the file. + */ + rval = 0; + if (LF_ISSET(RCV_SNAPSHOT)) { + if (opts_empty(sp, O_RECDIR, 0)) + goto err; + dp = O_STR(sp, O_RECDIR); + if ((buf = join(dp, "vi.XXXXXX")) == NULL) { + msgq(sp, M_SYSERR, NULL); + goto err; + } + if ((fd = rcv_mktemp(sp, buf, dp)) == -1) { + free(buf); + goto err; + } + sp->gp->scr_busy(sp, + "061|Copying file for recovery...", BUSY_ON); + if (rcv_copy(sp, fd, ep->rcv_path) || + close(fd) || rcv_mailfile(sp, 1, buf)) { + (void)unlink(buf); + (void)close(fd); + rval = 1; + } + free(buf); + sp->gp->scr_busy(sp, NULL, BUSY_OFF); + } + if (0) { +err: rval = 1; + } + + /* REQUEST: end the file session. */ + if (LF_ISSET(RCV_ENDSESSION) && file_end(sp, NULL, 1)) + rval = 1; + + return (rval); +} + +/* + * rcv_mailfile -- + * Build the file to mail to the user. + */ +static int +rcv_mailfile(SCR *sp, int issync, char *cp_path) +{ + EXF *ep; + GS *gp; + struct passwd *pw; + int len; + time_t now; + uid_t uid; + int fd; + FILE *fp; + char *dp, *p, *t, *qt, *buf, *mpath; + char *t1, *t2, *t3; + int st; + + /* + * XXX + * MAXHOSTNAMELEN/HOST_NAME_MAX are deprecated. We try sysconf(3) + * first, then fallback to _POSIX_HOST_NAME_MAX. + */ + char *host; + long hostmax = sysconf(_SC_HOST_NAME_MAX); + if (hostmax < 0) + hostmax = _POSIX_HOST_NAME_MAX; + + gp = sp->gp; + if ((pw = getpwuid(uid = getuid())) == NULL) { + msgq(sp, M_ERR, + "062|Information on user id %u not found", uid); + return (1); + } + + if (opts_empty(sp, O_RECDIR, 0)) + return (1); + dp = O_STR(sp, O_RECDIR); + if ((mpath = join(dp, "recover.XXXXXX")) == NULL) { + msgq(sp, M_SYSERR, NULL); + return (1); + } + if ((fd = rcv_mktemp(sp, mpath, dp)) == -1) { + free(mpath); + return (1); + } + if ((fp = fdopen(fd, "w")) == NULL) { + free(mpath); + close(fd); + return (1); + } + + /* + * XXX + * We keep an open lock on the file so that the recover option can + * distinguish between files that are live and those that need to + * be recovered. There's an obvious window between the mkstemp call + * and the lock, but it's pretty small. + */ + ep = sp->ep; + if (file_lock(sp, NULL, fd, 1) != LOCK_SUCCESS) + msgq(sp, M_SYSERR, "063|Unable to lock recovery file"); + if (!issync) { + /* Save the recover file descriptor, and mail path. */ + ep->rcv_fd = dup(fd); + ep->rcv_mpath = mpath; + cp_path = ep->rcv_path; + } + + t = sp->frp->name; + if ((p = strrchr(t, '/')) == NULL) + p = t; + else + ++p; + (void)time(&now); + + if ((st = rcv_dlnwrite(sp, "file", t, fp))) { + if (st == 1) + goto werr; + goto err; + } + if ((st = rcv_dlnwrite(sp, "path", cp_path, fp))) { + if (st == 1) + goto werr; + goto err; + } + + MALLOC(sp, host, hostmax + 1); + if (host == NULL) + goto err; + (void)gethostname(host, hostmax + 1); + + len = fprintf(fp, "%s%s%s\n%s%s%s%s\n%s%.40s\n%s\n\n", + "From: root@", host, " (Nvi recovery program)", + "To: ", pw->pw_name, "@", host, + "Subject: Nvi saved the file ", p, + "Precedence: bulk"); /* For vacation(1). */ + if (len < 0) { + free(host); + goto werr; + } + + if ((qt = quote(t)) == NULL) { + free(host); + msgq(sp, M_SYSERR, NULL); + goto err; + } + len = asprintf(&buf, "%s%.24s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n\n", + "On ", ctime(&now), ", the user ", pw->pw_name, + " was editing a file named ", t, " on the machine ", + host, ", when it was saved for recovery. ", + "You can recover most, if not all, of the changes ", + "to this file using the -r option to ", getprogname(), ":\n\n\t", + getprogname(), " -r ", qt); + free(qt); + free(host); + if (len == -1) { + msgq(sp, M_SYSERR, NULL); + goto err; + } + + /* + * Format the message. (Yes, I know it's silly.) + * Requires that the message end in a . + */ +#define FMTCOLS 60 + for (t1 = buf; len > 0; len -= t2 - t1, t1 = t2) { + /* Check for a short length. */ + if (len <= FMTCOLS) { + t2 = t1 + (len - 1); + goto wout; + } + + /* Check for a required . */ + t2 = strchr(t1, '\n'); + if (t2 - t1 <= FMTCOLS) + goto wout; + + /* Find the closest space, if any. */ + for (t3 = t2; t2 > t1; --t2) + if (*t2 == ' ') { + if (t2 - t1 <= FMTCOLS) + goto wout; + t3 = t2; + } + t2 = t3; + + /* t2 points to the last character to display. */ +wout: *t2++ = '\n'; + + /* t2 points one after the last character to display. */ + if (fwrite(t1, 1, t2 - t1, fp) != t2 - t1) { + free(buf); + goto werr; + } + } + + if (issync) { + fflush(fp); + rcv_email(sp, mpath); + free(mpath); + } + if (fclose(fp)) { + free(buf); +werr: msgq(sp, M_SYSERR, "065|Recovery file"); + goto err; + } + free(buf); + return (0); + +err: if (!issync) + ep->rcv_fd = -1; + if (fp != NULL) + (void)fclose(fp); + return (1); +} + +/* + * people making love + * never exactly the same + * just like a snowflake + * + * rcv_list -- + * List the files that can be recovered by this user. + * + * PUBLIC: int rcv_list(SCR *); + */ +int +rcv_list(SCR *sp) +{ + struct dirent *dp; + struct stat sb; + DIR *dirp; + FILE *fp; + int found; + char *p, *file, *path; + char *dtype, *data; + int st; + + /* Open the recovery directory for reading. */ + if (opts_empty(sp, O_RECDIR, 0)) + return (1); + p = O_STR(sp, O_RECDIR); + if (chdir(p) || (dirp = opendir(".")) == NULL) { + msgq_str(sp, M_SYSERR, p, "recdir: %s"); + return (1); + } + + /* Read the directory. */ + for (found = 0; (dp = readdir(dirp)) != NULL;) { + if (strncmp(dp->d_name, "recover.", 8)) + continue; + + /* If it's readable, it's recoverable. */ + if ((fp = fopen(dp->d_name, "r")) == NULL) + continue; + + switch (file_lock(sp, NULL, fileno(fp), 1)) { + case LOCK_FAILED: + /* + * XXX + * Assume that a lock can't be acquired, but that we + * should permit recovery anyway. If this is wrong, + * and someone else is using the file, we're going to + * die horribly. + */ + break; + case LOCK_SUCCESS: + break; + case LOCK_UNAVAIL: + /* If it's locked, it's live. */ + (void)fclose(fp); + continue; + } + + /* Check the headers. */ + for (file = NULL, path = NULL; + file == NULL || path == NULL;) { + if ((st = rcv_dlnread(sp, &dtype, &data, fp))) { + if (st == 1) + msgq_str(sp, M_ERR, dp->d_name, + "066|%s: malformed recovery file"); + goto next; + } + if (dtype == NULL) + continue; + if (!strcmp(dtype, "file")) + file = data; + else if (!strcmp(dtype, "path")) + path = data; + else + free(data); + } + + /* + * If the file doesn't exist, it's an orphaned recovery file, + * toss it. + * + * XXX + * This can occur if the backup file was deleted and we crashed + * before deleting the email file. + */ + errno = 0; + if (stat(path, &sb) && + errno == ENOENT) { + (void)unlink(dp->d_name); + goto next; + } + + /* Get the last modification time and display. */ + (void)fstat(fileno(fp), &sb); + (void)printf("%.24s: %s\n", + ctime(&sb.st_mtime), file); + found = 1; + + /* Close, discarding lock. */ +next: (void)fclose(fp); + free(file); + free(path); + } + if (found == 0) + (void)printf("%s: No files to recover\n", getprogname()); + (void)closedir(dirp); + return (0); +} + +/* + * rcv_read -- + * Start a recovered file as the file to edit. + * + * PUBLIC: int rcv_read(SCR *, FREF *); + */ +int +rcv_read(SCR *sp, FREF *frp) +{ + struct dirent *dp; + struct stat sb; + DIR *dirp; + FILE *fp; + EXF *ep; + struct timespec rec_mtim = { 0, 0 }; + int found, locked = 0, requested, sv_fd; + char *name, *p, *t, *rp, *recp, *pathp; + char *file, *path, *recpath; + char *dtype, *data; + int st; + + if (opts_empty(sp, O_RECDIR, 0)) + return (1); + rp = O_STR(sp, O_RECDIR); + if ((dirp = opendir(rp)) == NULL) { + msgq_str(sp, M_SYSERR, rp, "%s"); + return (1); + } + + name = frp->name; + sv_fd = -1; + recp = pathp = NULL; + for (found = requested = 0; (dp = readdir(dirp)) != NULL;) { + if (strncmp(dp->d_name, "recover.", 8)) + continue; + if ((recpath = join(rp, dp->d_name)) == NULL) { + msgq(sp, M_SYSERR, NULL); + continue; + } + + /* If it's readable, it's recoverable. */ + if ((fp = fopen(recpath, "r")) == NULL) { + free(recpath); + continue; + } + + switch (file_lock(sp, NULL, fileno(fp), 1)) { + case LOCK_FAILED: + /* + * XXX + * Assume that a lock can't be acquired, but that we + * should permit recovery anyway. If this is wrong, + * and someone else is using the file, we're going to + * die horribly. + */ + locked = 0; + break; + case LOCK_SUCCESS: + locked = 1; + break; + case LOCK_UNAVAIL: + /* If it's locked, it's live. */ + (void)fclose(fp); + continue; + } + + /* Check the headers. */ + for (file = NULL, path = NULL; + file == NULL || path == NULL;) { + if ((st = rcv_dlnread(sp, &dtype, &data, fp))) { + if (st == 1) + msgq_str(sp, M_ERR, dp->d_name, + "067|%s: malformed recovery file"); + goto next; + } + if (dtype == NULL) + continue; + if (!strcmp(dtype, "file")) + file = data; + else if (!strcmp(dtype, "path")) + path = data; + else + free(data); + } + ++found; + + /* + * If the file doesn't exist, it's an orphaned recovery file, + * toss it. + * + * XXX + * This can occur if the backup file was deleted and we crashed + * before deleting the email file. + */ + errno = 0; + if (stat(path, &sb) && + errno == ENOENT) { + (void)unlink(dp->d_name); + goto next; + } + + /* Check the file name. */ + if (strcmp(file, name)) + goto next; + + ++requested; + + /* If we've found more than one, take the most recent. */ + (void)fstat(fileno(fp), &sb); + if (recp == NULL || + timespeccmp(&rec_mtim, &sb.st_mtim, <)) { + p = recp; + t = pathp; + recp = recpath; + pathp = path; + if (p != NULL) { + free(p); + free(t); + } + rec_mtim = sb.st_mtim; + if (sv_fd != -1) + (void)close(sv_fd); + sv_fd = dup(fileno(fp)); + } else { +next: free(recpath); + free(path); + } + (void)fclose(fp); + free(file); + } + (void)closedir(dirp); + + if (recp == NULL) { + msgq_str(sp, M_INFO, name, + "068|No files named %s, readable by you, to recover"); + return (1); + } + if (found) { + if (requested > 1) + msgq(sp, M_INFO, + "069|There are older versions of this file for you to recover"); + if (found > requested) + msgq(sp, M_INFO, + "070|There are other files for you to recover"); + } + + /* + * Create the FREF structure, start the btree file. + * + * XXX + * file_init() is going to set ep->rcv_path. + */ + if (file_init(sp, frp, pathp, 0)) { + free(recp); + free(pathp); + (void)close(sv_fd); + return (1); + } + free(pathp); + + /* + * We keep an open lock on the file so that the recover option can + * distinguish between files that are live and those that need to + * be recovered. The lock is already acquired, just copy it. + */ + ep = sp->ep; + ep->rcv_mpath = recp; + ep->rcv_fd = sv_fd; + if (!locked) + F_SET(frp, FR_UNLOCKED); + + /* We believe the file is recoverable. */ + F_SET(ep, F_RCV_ON); + return (0); +} + +/* + * rcv_copy -- + * Copy a recovery file. + */ +static int +rcv_copy(SCR *sp, int wfd, char *fname) +{ + int nr, nw, off, rfd; + char buf[8 * 1024]; + + if ((rfd = open(fname, O_RDONLY, 0)) == -1) + goto err; + while ((nr = read(rfd, buf, sizeof(buf))) > 0) + for (off = 0; nr; nr -= nw, off += nw) + if ((nw = write(wfd, buf + off, nr)) < 0) + goto err; + if (nr == 0) + return (0); + +err: msgq_str(sp, M_SYSERR, fname, "%s"); + return (1); +} + +/* + * rcv_mktemp -- + * Paranoid make temporary file routine. + */ +static int +rcv_mktemp(SCR *sp, char *path, char *dname) +{ + int fd; + + if ((fd = mkstemp(path)) == -1) + msgq_str(sp, M_SYSERR, dname, "%s"); + return (fd); +} + +/* + * rcv_email -- + * Send email. + */ +static void +rcv_email(SCR *sp, char *fname) +{ + char *buf; + + if (asprintf(&buf, _PATH_SENDMAIL " -odb -t < %s", fname) == -1) { + msgq_str(sp, M_ERR, strerror(errno), + "071|not sending email: %s"); + return; + } + (void)system(buf); + free(buf); +} + +/* + * rcv_dlnwrite -- + * Encode a string into an X-vi-data line and write it. + */ +static int +rcv_dlnwrite(SCR *sp, const char *dtype, const char *src, FILE *fp) +{ + char *bp = NULL, *p; + size_t blen = 0; + size_t dlen, len; + int plen, xlen; + + len = strlen(src); + dlen = strlen(dtype); + GET_SPACE_GOTOC(sp, bp, blen, (len + 2) / 3 * 4 + dlen + 2); + (void)memcpy(bp, dtype, dlen); + bp[dlen] = ';'; + if ((xlen = b64_ntop((u_char *)src, + len, bp + dlen + 1, blen)) == -1) + goto err; + xlen += dlen + 1; + + /* Output as an MIME folding header. */ + if ((plen = fprintf(fp, VI_DHEADER " %.*s\n", + FMTCOLS - (int)sizeof(VI_DHEADER), bp)) < 0) + goto err; + plen -= (int)sizeof(VI_DHEADER) + 1; + for (p = bp, xlen -= plen; xlen > 0; xlen -= plen) { + p += plen; + if ((plen = fprintf(fp, " %.*s\n", FMTCOLS - 1, p)) < 0) + goto err; + plen -= 2; + } + FREE_SPACE(sp, bp, blen); + return (0); + +err: FREE_SPACE(sp, bp, blen); + return (1); +alloc_err: + msgq(sp, M_SYSERR, NULL); + return (-1); +} + +/* + * rcv_dlnread -- + * Read an X-vi-data line and decode it. + */ +static int +rcv_dlnread(SCR *sp, char **dtypep, + char **datap, /* free *datap if != NULL after use. */ + FILE *fp) +{ + int ch; + char buf[1024]; + char *bp = NULL, *p, *src; + size_t blen = 0; + size_t len, off, dlen; + char *dtype, *data; + int xlen; + + if (fgets(buf, sizeof(buf), fp) == NULL) + return (1); + if (strncmp(buf, VI_DHEADER, sizeof(VI_DHEADER) - 1)) { + *dtypep = NULL; + *datap = NULL; + return (0); + } + + /* Fetch an MIME folding header. */ + len = strlen(buf) - sizeof(VI_DHEADER) + 1; + GET_SPACE_GOTOC(sp, bp, blen, len); + (void)memcpy(bp, buf + sizeof(VI_DHEADER) - 1, len); + p = bp + len; + while ((ch = fgetc(fp)) == ' ') { + if (fgets(buf, sizeof(buf), fp) == NULL) + goto err; + off = strlen(buf); + len += off; + ADD_SPACE_GOTOC(sp, bp, blen, len); + p = bp + len - off; + (void)memcpy(p, buf, off); + } + bp[len] = '\0'; + (void)ungetc(ch, fp); + + for (p = bp; *p == ' ' || *p == '\n'; p++); + if ((src = strchr(p, ';')) == NULL) + goto err; + dlen = src - p; + src += 1; + len -= src - bp; + + /* Memory looks like: "\0\0". */ + MALLOC(sp, data, dlen + len / 4 * 3 + 2); + if (data == NULL) + goto err; + if ((xlen = (b64_pton(p + dlen + 1, + (u_char *)data, len / 4 * 3 + 1))) == -1) { + free(data); + goto err; + } + data[xlen] = '\0'; + dtype = data + xlen + 1; + (void)memcpy(dtype, p, dlen); + dtype[dlen] = '\0'; + FREE_SPACE(sp, bp, blen); + *dtypep = dtype; + *datap = data; + return (0); + +err: FREE_SPACE(sp, bp, blen); + return (1); +alloc_err: + msgq(sp, M_SYSERR, NULL); + return (-1); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/common/recover.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/common/util.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/common/util.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/common/util.c (revision 366308) @@ -0,0 +1,383 @@ +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1991, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include + +#ifdef __APPLE__ +#include +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" + +/* + * binc -- + * Increase the size of a buffer. + * + * PUBLIC: void *binc(SCR *, void *, size_t *, size_t); + */ +void * +binc(SCR *sp, /* sp MAY BE NULL!!! */ + void *bp, size_t *bsizep, size_t min) +{ + size_t csize; + + /* If already larger than the minimum, just return. */ + if (min && *bsizep >= min) + return (bp); + + csize = p2roundup(MAX(min, 256)); + REALLOC(sp, bp, void *, csize); + + if (bp == NULL) { + *bsizep = 0; + return (NULL); + } + /* + * Memory is guaranteed to be zero-filled, various parts of + * nvi depend on this. + */ + memset((char *)bp + *bsizep, 0, csize - *bsizep); + *bsizep = csize; + return (bp); +} + +/* + * nonblank -- + * Set the column number of the first non-blank character + * including or after the starting column. On error, set + * the column to 0, it's safest. + * + * PUBLIC: int nonblank(SCR *, recno_t, size_t *); + */ +int +nonblank(SCR *sp, recno_t lno, size_t *cnop) +{ + CHAR_T *p; + size_t cnt, len, off; + int isempty; + + /* Default. */ + off = *cnop; + *cnop = 0; + + /* Get the line, succeeding in an empty file. */ + if (db_eget(sp, lno, &p, &len, &isempty)) + return (!isempty); + + /* Set the offset. */ + if (len == 0 || off >= len) + return (0); + + for (cnt = off, p = &p[off], + len -= off; len && ISBLANK(*p); ++cnt, ++p, --len); + + /* Set the return. */ + *cnop = len ? cnt : cnt - 1; + return (0); +} + +/* + * join -- + * Join two paths; need free. + * + * PUBLIC: char *join(char *, char *); + */ +char * +join(char *path1, char *path2) +{ + char *p; + + if (path1[0] == '\0' || path2[0] == '/') + return strdup(path2); + if (asprintf(&p, path1[strlen(path1)-1] == '/' ? + "%s%s" : "%s/%s", path1, path2) == -1) + return NULL; + return p; +} + +/* + * expanduser -- + * Return a "~" or "~user" expanded path; need free. + * + * PUBLIC: char *expanduser(char *); + */ +char * +expanduser(char *str) +{ + struct passwd *pwd; + char *p, *t, *u, *h; + + /* + * This function always expands the content between the + * leading '~' and the first '/' or '\0' from the input. + * Return NULL whenever we fail to do so. + */ + if (*str != '~') + return (NULL); + p = str + 1; + for (t = p; *t != '/' && *t != '\0'; ++t) + continue; + if (t == p) { + /* ~ */ +#ifdef __GLIBC__ + extern char *secure_getenv(const char *); + if ((h = secure_getenv("HOME")) == NULL) { +#else + if (issetugid() != 0 || + (h = getenv("HOME")) == NULL) { +#endif + if (((h = getlogin()) != NULL && + (pwd = getpwnam(h)) != NULL) || + (pwd = getpwuid(getuid())) != NULL) + h = pwd->pw_dir; + else + return (NULL); + } + } else { + /* ~user */ + if ((u = strndup(p, t - p)) == NULL) + return (NULL); + if ((pwd = getpwnam(u)) == NULL) { + free(u); + return (NULL); + } else + h = pwd->pw_dir; + free(u); + } + + for (; *t == '/' && *t != '\0'; ++t) + continue; + return (join(h, t)); +} + +/* + * quote -- + * Return a escaped string for /bin/sh; need free. + * + * PUBLIC: char *quote(char *); + */ +char * +quote(char *str) +{ + char *p, *t; + size_t i = 0, n = 0; + int unsafe = 0; + + for (p = str; *p != '\0'; p++, i++) { + if (*p == '\'') + n++; + if (unsafe) + continue; + if (isascii((u_char)*p)) { + if (isalnum((u_char)*p)) + continue; + switch (*p) { + case '%': case '+': case ',': case '-': case '.': + case '/': case ':': case '=': case '@': case '_': + continue; + } + } + unsafe = 1; + } + if (!unsafe) + t = strdup(str); +#define SQT "'\\''" + else if ((p = t = malloc(i + n * (sizeof(SQT) - 2) + 3)) != NULL) { + *p++ = '\''; + for (; *str != '\0'; str++) { + if (*str == '\'') { + (void)memcpy(p, SQT, sizeof(SQT) - 1); + p += sizeof(SQT) - 1; + } else + *p++ = *str; + } + *p++ = '\''; + *p = '\0'; + } + return t; +} + +/* + * v_strdup -- + * Strdup for 8-bit character strings with an associated length. + * + * PUBLIC: char *v_strdup(SCR *, const char *, size_t); + */ +char * +v_strdup(SCR *sp, const char *str, size_t len) +{ + char *copy; + + MALLOC(sp, copy, len + 1); + if (copy == NULL) + return (NULL); + memcpy(copy, str, len); + copy[len] = '\0'; + return (copy); +} + +/* + * v_wstrdup -- + * Strdup for wide character strings with an associated length. + * + * PUBLIC: CHAR_T *v_wstrdup(SCR *, const CHAR_T *, size_t); + */ +CHAR_T * +v_wstrdup(SCR *sp, const CHAR_T *str, size_t len) +{ + CHAR_T *copy; + + MALLOC(sp, copy, (len + 1) * sizeof(CHAR_T)); + if (copy == NULL) + return (NULL); + MEMCPY(copy, str, len); + copy[len] = '\0'; + return (copy); +} + +/* + * nget_uslong -- + * Get an unsigned long, checking for overflow. + * + * PUBLIC: enum nresult nget_uslong(u_long *, const CHAR_T *, CHAR_T **, int); + */ +enum nresult +nget_uslong(u_long *valp, const CHAR_T *p, CHAR_T **endp, int base) +{ + errno = 0; + *valp = STRTOUL(p, endp, base); + if (errno == 0) + return (NUM_OK); + if (errno == ERANGE && *valp == ULONG_MAX) + return (NUM_OVER); + return (NUM_ERR); +} + +/* + * nget_slong -- + * Convert a signed long, checking for overflow and underflow. + * + * PUBLIC: enum nresult nget_slong(long *, const CHAR_T *, CHAR_T **, int); + */ +enum nresult +nget_slong(long *valp, const CHAR_T *p, CHAR_T **endp, int base) +{ + errno = 0; + *valp = STRTOL(p, endp, base); + if (errno == 0) + return (NUM_OK); + if (errno == ERANGE) { + if (*valp == LONG_MAX) + return (NUM_OVER); + if (*valp == LONG_MIN) + return (NUM_UNDER); + } + return (NUM_ERR); +} + +/* + * timepoint_steady -- + * Get a timestamp from a monotonic clock. + * + * PUBLIC: void timepoint_steady(struct timespec *); + */ +void +timepoint_steady(struct timespec *ts) +{ +#ifdef __APPLE__ + static mach_timebase_info_data_t base = { 0 }; + uint64_t val; + uint64_t ns; + + if (base.denom == 0) + (void)mach_timebase_info(&base); + + val = mach_absolute_time(); + ns = val * base.numer / base.denom; + ts->tv_sec = ns / 1000000000; + ts->tv_nsec = ns % 1000000000; +#else +#ifdef CLOCK_MONOTONIC_FAST + (void)clock_gettime(CLOCK_MONOTONIC_FAST, ts); +#else + (void)clock_gettime(CLOCK_MONOTONIC, ts); +#endif +#endif +} + +/* + * timepoint_system -- + * Get the current calendar time. + * + * PUBLIC: void timepoint_system(struct timespec *); + */ +void +timepoint_system(struct timespec *ts) +{ +#ifdef __APPLE__ + clock_serv_t clk; + mach_timespec_t mts; + kern_return_t kr; + + kr = host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &clk); + if (kr != KERN_SUCCESS) + return; + (void)clock_get_time(clk, &mts); + (void)mach_port_deallocate(mach_task_self(), clk); + ts->tv_sec = mts.tv_sec; + ts->tv_nsec = mts.tv_nsec; +#else +#ifdef CLOCK_REALTIME_FAST + (void)clock_gettime(CLOCK_REALTIME_FAST, ts); +#else + (void)clock_gettime(CLOCK_REALTIME, ts); +#endif +#endif +} + +#ifdef DEBUG +#include + +/* + * TRACE -- + * debugging trace routine. + * + * PUBLIC: void TRACE(SCR *, const char *, ...); + */ +void +TRACE(SCR *sp, const char *fmt, ...) +{ + FILE *tfp; + va_list ap; + + if ((tfp = sp->gp->tracefp) == NULL) + return; + va_start(ap, fmt); + (void)vfprintf(tfp, fmt, ap); + va_end(ap); + + (void)fflush(tfp); +} +#endif Property changes on: vendor/nvi/2.2.0-05ed8b9/common/util.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/common/extern.h =================================================================== --- vendor/nvi/2.2.0-05ed8b9/common/extern.h (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/common/extern.h (revision 366308) @@ -0,0 +1,131 @@ +char * codeset(void); +void conv_init(SCR *, SCR *); +int conv_enc(SCR *, int, char *); +void conv_end(SCR *); +int cut(SCR *, CHAR_T *, MARK *, MARK *, int); +int cut_line(SCR *, recno_t, size_t, size_t, CB *); +void cut_close(GS *); +TEXT *text_init(SCR *, const CHAR_T *, size_t, size_t); +void text_lfree(TEXTH *); +void text_free(TEXT *); +int del(SCR *, MARK *, MARK *, int); +int looks_utf8(const char *, size_t); +int looks_utf16(const char *, size_t); +int decode_utf8(const char *); +int decode_utf16(const char *, int); +FREF *file_add(SCR *, char *); +int file_init(SCR *, FREF *, char *, int); +int file_end(SCR *, EXF *, int); +int file_write(SCR *, MARK *, MARK *, char *, int); +int file_m1(SCR *, int, int); +int file_m2(SCR *, int); +int file_m3(SCR *, int); +int file_aw(SCR *, int); +void set_alt_name(SCR *, char *); +lockr_t file_lock(SCR *, char *, int, int); +int v_key_init(SCR *); +void v_key_ilookup(SCR *); +size_t v_key_len(SCR *, ARG_CHAR_T); +char *v_key_name(SCR *, ARG_CHAR_T); +e_key_t v_key_val(SCR *, ARG_CHAR_T); +int v_event_push(SCR *, EVENT *, CHAR_T *, size_t, u_int); +int v_event_get(SCR *, EVENT *, int, u_int32_t); +void v_event_err(SCR *, EVENT *); +int v_event_flush(SCR *, u_int); +int db_eget(SCR *, recno_t, CHAR_T **, size_t *, int *); +int db_get(SCR *, recno_t, u_int32_t, CHAR_T **, size_t *); +int db_delete(SCR *, recno_t); +int db_append(SCR *, int, recno_t, CHAR_T *, size_t); +int db_insert(SCR *, recno_t, CHAR_T *, size_t); +int db_set(SCR *, recno_t, CHAR_T *, size_t); +int db_exist(SCR *, recno_t); +int db_last(SCR *, recno_t *); +int db_rget(SCR *, recno_t, char **, size_t *); +int db_rset(SCR *, recno_t, char *, size_t); +void db_err(SCR *, recno_t); +int log_init(SCR *, EXF *); +int log_end(SCR *, EXF *); +int log_cursor(SCR *); +int log_line(SCR *, recno_t, u_int); +int log_mark(SCR *, LMARK *); +int log_backward(SCR *, MARK *); +int log_setline(SCR *); +int log_forward(SCR *, MARK *); +int editor(GS *, int, char *[]); +void v_end(GS *); +int mark_init(SCR *, EXF *); +int mark_end(SCR *, EXF *); +int mark_get(SCR *, ARG_CHAR_T, MARK *, mtype_t); +int mark_set(SCR *, ARG_CHAR_T, MARK *, int); +int mark_insdel(SCR *, lnop_t, recno_t); +void msgq(SCR *, mtype_t, const char *, ...); +void msgq_wstr(SCR *, mtype_t, const CHAR_T *, const char *); +void msgq_str(SCR *, mtype_t, const char *, const char *); +void mod_rpt(SCR *); +void msgq_status(SCR *, recno_t, u_int); +int msg_open(SCR *, char *); +void msg_close(GS *); +const char *msg_cmsg(SCR *, cmsg_t, size_t *); +const char *msg_cat(SCR *, const char *, size_t *); +char *msg_print(SCR *, const char *, int *); +int opts_init(SCR *, int *); +int opts_set(SCR *, ARGS *[], char *); +int o_set(SCR *, int, u_int, char *, u_long); +int opts_empty(SCR *, int, int); +void opts_dump(SCR *, enum optdisp); +int opts_save(SCR *, FILE *); +OPTLIST const *opts_search(CHAR_T *); +void opts_nomatch(SCR *, CHAR_T *); +int opts_copy(SCR *, SCR *); +void opts_free(SCR *); +int f_altwerase(SCR *, OPTION *, char *, u_long *); +int f_columns(SCR *, OPTION *, char *, u_long *); +int f_lines(SCR *, OPTION *, char *, u_long *); +int f_lisp(SCR *, OPTION *, char *, u_long *); +int f_msgcat(SCR *, OPTION *, char *, u_long *); +int f_print(SCR *, OPTION *, char *, u_long *); +int f_readonly(SCR *, OPTION *, char *, u_long *); +int f_recompile(SCR *, OPTION *, char *, u_long *); +int f_reformat(SCR *, OPTION *, char *, u_long *); +int f_ttywerase(SCR *, OPTION *, char *, u_long *); +int f_w300(SCR *, OPTION *, char *, u_long *); +int f_w1200(SCR *, OPTION *, char *, u_long *); +int f_w9600(SCR *, OPTION *, char *, u_long *); +int f_window(SCR *, OPTION *, char *, u_long *); +int f_encoding(SCR *, OPTION *, char *, u_long *); +int put(SCR *, CB *, CHAR_T *, MARK *, MARK *, int); +int rcv_tmp(SCR *, EXF *, char *); +int rcv_init(SCR *); +int rcv_sync(SCR *, u_int); +int rcv_list(SCR *); +int rcv_read(SCR *, FREF *); +int screen_init(GS *, SCR *, SCR **); +int screen_end(SCR *); +SCR *screen_next(SCR *); +int f_search(SCR *, + MARK *, MARK *, CHAR_T *, size_t, CHAR_T **, u_int); +int b_search(SCR *, + MARK *, MARK *, CHAR_T *, size_t, CHAR_T **, u_int); +void search_busy(SCR *, busy_t); +int seq_set(SCR *, CHAR_T *, + size_t, CHAR_T *, size_t, CHAR_T *, size_t, seq_t, int); +int seq_delete(SCR *, CHAR_T *, size_t, seq_t); +int seq_free(SEQ *); +SEQ *seq_find + (SCR *, SEQ **, EVENT *, CHAR_T *, size_t, seq_t, int *); +void seq_close(GS *); +int seq_dump(SCR *, seq_t, int); +int seq_save(SCR *, FILE *, char *, seq_t); +int e_memcmp(CHAR_T *, EVENT *, size_t); +void *binc(SCR *, void *, size_t *, size_t); +int nonblank(SCR *, recno_t, size_t *); +char *join(char *, char *); +char *expanduser(char *); +char *quote(char *); +char *v_strdup(SCR *, const char *, size_t); +CHAR_T *v_wstrdup(SCR *, const CHAR_T *, size_t); +enum nresult nget_uslong(u_long *, const CHAR_T *, CHAR_T **, int); +enum nresult nget_slong(long *, const CHAR_T *, CHAR_T **, int); +void timepoint_steady(struct timespec *); +void timepoint_system(struct timespec *); +void TRACE(SCR *, const char *, ...); Property changes on: vendor/nvi/2.2.0-05ed8b9/common/extern.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/common/options_def.h =================================================================== --- vendor/nvi/2.2.0-05ed8b9/common/options_def.h (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/common/options_def.h (revision 366308) @@ -0,0 +1,84 @@ +#define O_ALTWERASE 0 +#define O_AUTOINDENT 1 +#define O_AUTOPRINT 2 +#define O_AUTOWRITE 3 +#define O_BACKUP 4 +#define O_BEAUTIFY 5 +#define O_CDPATH 6 +#define O_CEDIT 7 +#define O_COLUMNS 8 +#define O_COMBINED 9 +#define O_COMMENT 10 +#define O_TMPDIR 11 +#define O_EDCOMPATIBLE 12 +#define O_ERRORBELLS 13 +#define O_ESCAPETIME 14 +#define O_EXPANDTAB 15 +#define O_EXRC 16 +#define O_EXTENDED 17 +#define O_FILEC 18 +#define O_FILEENCODING 19 +#define O_FLASH 20 +#define O_HARDTABS 21 +#define O_ICLOWER 22 +#define O_IGNORECASE 23 +#define O_INPUTENCODING 24 +#define O_KEYTIME 25 +#define O_LEFTRIGHT 26 +#define O_LINES 27 +#define O_LISP 28 +#define O_LIST 29 +#define O_LOCKFILES 30 +#define O_MAGIC 31 +#define O_MATCHCHARS 32 +#define O_MATCHTIME 33 +#define O_MESG 34 +#define O_MODELINE 35 +#define O_MSGCAT 36 +#define O_NOPRINT 37 +#define O_NUMBER 38 +#define O_OCTAL 39 +#define O_OPEN 40 +#define O_OPTIMIZE 41 +#define O_PARAGRAPHS 42 +#define O_PATH 43 +#define O_PRINT 44 +#define O_PROMPT 45 +#define O_READONLY 46 +#define O_RECDIR 47 +#define O_REDRAW 48 +#define O_REMAP 49 +#define O_REPORT 50 +#define O_RULER 51 +#define O_SCROLL 52 +#define O_SEARCHINCR 53 +#define O_SECTIONS 54 +#define O_SECURE 55 +#define O_SHELL 56 +#define O_SHELLMETA 57 +#define O_SHIFTWIDTH 58 +#define O_SHOWMATCH 59 +#define O_SHOWMODE 60 +#define O_SIDESCROLL 61 +#define O_SLOWOPEN 62 +#define O_SOURCEANY 63 +#define O_TABSTOP 64 +#define O_TAGLENGTH 65 +#define O_TAGS 66 +#define O_TERM 67 +#define O_TERSE 68 +#define O_TILDEOP 69 +#define O_TIMEOUT 70 +#define O_TTYWERASE 71 +#define O_VERBOSE 72 +#define O_W1200 73 +#define O_W300 74 +#define O_W9600 75 +#define O_WARN 76 +#define O_WINDOW 77 +#define O_WINDOWNAME 78 +#define O_WRAPLEN 79 +#define O_WRAPMARGIN 80 +#define O_WRAPSCAN 81 +#define O_WRITEANY 82 +#define O_OPTIONCOUNT 83 Property changes on: vendor/nvi/2.2.0-05ed8b9/common/options_def.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/common/args.h =================================================================== --- vendor/nvi/2.2.0-05ed8b9/common/args.h (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/common/args.h (revision 366308) @@ -0,0 +1,27 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +/* + * Structure for building "argc/argv" vector of arguments. + * + * !!! + * All arguments are nul terminated as well as having an associated length. + * The argument vector is NOT necessarily NULL terminated. The proper way + * to check the number of arguments is to use the argc value in the EXCMDARG + * structure or to walk the array until an ARGS structure with a length of 0 + * is found. + */ +typedef struct _args { + CHAR_T *bp; /* Argument. */ + size_t blen; /* Buffer length. */ + size_t len; /* Argument length. */ + +#define A_ALLOCATED 0x01 /* If allocated space. */ + u_int8_t flags; +} ARGS; Property changes on: vendor/nvi/2.2.0-05ed8b9/common/args.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/common/conv.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/common/conv.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/common/conv.c (revision 366308) @@ -0,0 +1,465 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * Copyright (c) 2011, 2012 + * Zhihao Yuan. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" + +/* + * codeset -- + * Get the locale encoding. + * + * PUBLIC: char * codeset(void); + */ +char * +codeset(void) +{ + static char *cs; + + if (cs == NULL) + cs = nl_langinfo(CODESET); + + return cs; +} + +#ifdef USE_WIDECHAR +static int +raw2int(SCR *sp, const char * str, ssize_t len, CONVWIN *cw, size_t *tolen, + CHAR_T **dst) +{ + int i; + CHAR_T **tostr = &cw->bp1.wc; + size_t *blen = &cw->blen1; + + BINC_RETW(NULL, *tostr, *blen, len); + + *tolen = len; + for (i = 0; i < len; ++i) + (*tostr)[i] = (u_char) str[i]; + + *dst = cw->bp1.wc; + + return 0; +} + +#define CONV_BUFFER_SIZE 512 +/* fill the buffer with codeset encoding of string pointed to by str + * left has the number of bytes left in str and is adjusted + * len contains the number of bytes put in the buffer + */ +#ifdef USE_ICONV +#define CONVERT(str, left, src, len) \ + do { \ + size_t outleft; \ + char *bp = buffer; \ + outleft = CONV_BUFFER_SIZE; \ + errno = 0; \ + if (iconv(id, (iconv_src_t)&str, &left, &bp, &outleft) \ + == -1 && errno != E2BIG) \ + goto err; \ + if ((len = CONV_BUFFER_SIZE - outleft) == 0) { \ + error = -left; \ + goto err; \ + } \ + src = buffer; \ + } while (0) + +#define IC_RESET() \ + do { \ + if (id != (iconv_t)-1) \ + iconv(id, NULL, NULL, NULL, NULL); \ + } while(0) +#else +#define CONVERT(str, left, src, len) +#define IC_RESET() +#endif + +static int +default_char2int(SCR *sp, const char * str, ssize_t len, CONVWIN *cw, + size_t *tolen, CHAR_T **dst, iconv_t id) +{ + size_t i = 0, j; + CHAR_T **tostr = &cw->bp1.wc; + size_t *blen = &cw->blen1; + mbstate_t mbs; + size_t n; + ssize_t nlen = len; + char *src = (char *)str; +#ifdef USE_ICONV + char buffer[CONV_BUFFER_SIZE]; +#endif + size_t left = len; + int error = 1; + + memset(&mbs, 0, sizeof(mbs)); + BINC_RETW(NULL, *tostr, *blen, nlen); + +#ifdef USE_ICONV + if (id != (iconv_t)-1) + CONVERT(str, left, src, len); +#endif + + for (i = 0, j = 0; j < len; ) { + n = mbrtowc((*tostr)+i, src+j, len-j, &mbs); + /* NULL character converted */ + if (n == -2) + error = -(len-j); + if (n == -1 || n == -2) + goto err; + if (n == 0) + n = 1; + j += n; + if (++i >= *blen) { + nlen += 256; + BINC_RETW(NULL, *tostr, *blen, nlen); + } + if (id != (iconv_t)-1 && j == len && left) { + CONVERT(str, left, src, len); + j = 0; + } + } + + error = 0; +err: + *tolen = i; + *dst = cw->bp1.wc; + IC_RESET(); + + return error; +} + +static int +fe_char2int(SCR *sp, const char * str, ssize_t len, CONVWIN *cw, size_t *tolen, + CHAR_T **dst) +{ + return default_char2int(sp, str, len, cw, tolen, dst, + sp->conv.id[IC_FE_CHAR2INT]); +} + +static int +ie_char2int(SCR *sp, const char * str, ssize_t len, CONVWIN *cw, size_t *tolen, + CHAR_T **dst) +{ + return default_char2int(sp, str, len, cw, tolen, dst, + sp->conv.id[IC_IE_CHAR2INT]); +} + +static int +cs_char2int(SCR *sp, const char * str, ssize_t len, CONVWIN *cw, size_t *tolen, + CHAR_T **dst) +{ + return default_char2int(sp, str, len, cw, tolen, dst, (iconv_t)-1); +} + +static int +int2raw(SCR *sp, const CHAR_T * str, ssize_t len, CONVWIN *cw, size_t *tolen, + char **dst) +{ + int i; + char **tostr = &cw->bp1.c; + size_t *blen = &cw->blen1; + + BINC_RETC(NULL, *tostr, *blen, len); + + *tolen = len; + for (i = 0; i < len; ++i) + (*tostr)[i] = str[i]; + + *dst = cw->bp1.c; + + return 0; +} + +static int +default_int2char(SCR *sp, const CHAR_T * str, ssize_t len, CONVWIN *cw, + size_t *tolen, char **pdst, iconv_t id) +{ + size_t i, j, offset = 0; + char **tostr = &cw->bp1.c; + size_t *blen = &cw->blen1; + mbstate_t mbs; + size_t n; + ssize_t nlen = len + MB_CUR_MAX; + char *dst; + size_t buflen; +#ifdef USE_ICONV + char buffer[CONV_BUFFER_SIZE]; +#endif + int error = 1; + +/* convert first len bytes of buffer and append it to cw->bp + * len is adjusted => 0 + * offset contains the offset in cw->bp and is adjusted + * cw->bp is grown as required + */ +#ifdef USE_ICONV +#define CONVERT2(_buffer, lenp, cw, offset) \ + do { \ + char *bp = _buffer; \ + int ret; \ + do { \ + size_t outleft = cw->blen1 - offset; \ + char *obp = cw->bp1.c + offset; \ + if (cw->blen1 < offset + MB_CUR_MAX) { \ + nlen += 256; \ + BINC_RETC(NULL, cw->bp1.c, cw->blen1, \ + nlen); \ + } \ + errno = 0; \ + ret = iconv(id, (iconv_src_t)&bp, lenp, &obp, \ + &outleft); \ + if (ret == -1 && errno != E2BIG) \ + goto err; \ + offset = cw->blen1 - outleft; \ + } while (ret != 0); \ + } while (0) +#else +#define CONVERT2(_buffer, lenp, cw, offset) +#endif + + + memset(&mbs, 0, sizeof(mbs)); + BINC_RETC(NULL, *tostr, *blen, nlen); + dst = *tostr; buflen = *blen; + +#ifdef USE_ICONV + if (id != (iconv_t)-1) { + dst = buffer; buflen = CONV_BUFFER_SIZE; + } +#endif + + for (i = 0, j = 0; i < len; ++i) { + n = wcrtomb(dst+j, str[i], &mbs); + if (n == -1) + goto err; + j += n; + if (buflen < j + MB_CUR_MAX) { + if (id != (iconv_t)-1) { + CONVERT2(buffer, &j, cw, offset); + } else { + nlen += 256; + BINC_RETC(NULL, *tostr, *blen, nlen); + dst = *tostr; buflen = *blen; + } + } + } + + n = wcrtomb(dst+j, L'\0', &mbs); + j += n - 1; /* don't count NUL at the end */ + *tolen = j; + + if (id != (iconv_t)-1) { + CONVERT2(buffer, &j, cw, offset); + /* back to the initial state */ + CONVERT2(NULL, NULL, cw, offset); + *tolen = offset; + } + + error = 0; +err: + if (error) + *tolen = j; + *pdst = cw->bp1.c; + IC_RESET(); + + return error; +} + +static int +fe_int2char(SCR *sp, const CHAR_T * str, ssize_t len, CONVWIN *cw, + size_t *tolen, char **dst) +{ + return default_int2char(sp, str, len, cw, tolen, dst, + sp->conv.id[IC_FE_INT2CHAR]); +} + +static int +cs_int2char(SCR *sp, const CHAR_T * str, ssize_t len, CONVWIN *cw, + size_t *tolen, char **dst) +{ + return default_int2char(sp, str, len, cw, tolen, dst, (iconv_t)-1); +} + +#endif + +/* + * conv_init -- + * Initialize the iconv environment. + * + * PUBLIC: void conv_init(SCR *, SCR *); + */ +void +conv_init(SCR *orig, SCR *sp) +{ + int i; + + if (orig == NULL) + setlocale(LC_ALL, ""); + if (orig != NULL) + memmove(&sp->conv, &orig->conv, sizeof(CONV)); +#ifdef USE_WIDECHAR + else { + char *ctype = setlocale(LC_CTYPE, NULL); + + /* + * XXX + * This hack fixes the libncursesw issue on FreeBSD. + */ + if (!strcmp(ctype, "ko_KR.CP949")) + setlocale(LC_CTYPE, "ko_KR.eucKR"); + else if (!strcmp(ctype, "zh_CN.GB2312")) + setlocale(LC_CTYPE, "zh_CN.eucCN"); + else if (!strcmp(ctype, "zh_CN.GBK")) + setlocale(LC_CTYPE, "zh_CN.GB18030"); + + /* + * Switch to 8bit mode if locale is C; + * LC_CTYPE should be reseted to C if unmatched. + */ + if (!strcmp(ctype, "C") || !strcmp(ctype, "POSIX")) { + sp->conv.sys2int = sp->conv.file2int = raw2int; + sp->conv.int2sys = sp->conv.int2file = int2raw; + sp->conv.input2int = raw2int; + } else { + sp->conv.sys2int = cs_char2int; + sp->conv.int2sys = cs_int2char; + sp->conv.file2int = fe_char2int; + sp->conv.int2file = fe_int2char; + sp->conv.input2int = ie_char2int; + } +#ifdef USE_ICONV + o_set(sp, O_INPUTENCODING, OS_STRDUP, codeset(), 0); +#endif + } +#endif + + /* iconv descriptors must be distinct to screens. */ + for (i = 0; i <= IC_IE_TO_UTF16; ++i) + sp->conv.id[i] = (iconv_t)-1; +#ifdef USE_ICONV + conv_enc(sp, O_INPUTENCODING, 0); +#endif +} + +/* + * conv_enc -- + * Convert file/input encoding. + * + * PUBLIC: int conv_enc(SCR *, int, char *); + */ +int +conv_enc(SCR *sp, int option, char *enc) +{ +#if defined(USE_WIDECHAR) && defined(USE_ICONV) + iconv_t *c2w, *w2c; + iconv_t id_c2w, id_w2c; + + switch (option) { + case O_FILEENCODING: + c2w = sp->conv.id + IC_FE_CHAR2INT; + w2c = sp->conv.id + IC_FE_INT2CHAR; + if (!enc) + enc = O_STR(sp, O_FILEENCODING); + + if (strcasecmp(codeset(), enc)) { + if ((id_c2w = iconv_open(codeset(), enc)) == + (iconv_t)-1) + goto err; + if ((id_w2c = iconv_open(enc, codeset())) == + (iconv_t)-1) + goto err; + } else { + id_c2w = (iconv_t)-1; + id_w2c = (iconv_t)-1; + } + + break; + + case O_INPUTENCODING: + c2w = sp->conv.id + IC_IE_CHAR2INT; + w2c = sp->conv.id + IC_IE_TO_UTF16; + if (!enc) + enc = O_STR(sp, O_INPUTENCODING); + + if (strcasecmp(codeset(), enc)) { + if ((id_c2w = iconv_open(codeset(), enc)) == + (iconv_t)-1) + goto err; + } else + id_c2w = (iconv_t)-1; + + /* UTF-16 can not be locale and can not be inputed. */ + if ((id_w2c = iconv_open("utf-16be", enc)) == (iconv_t)-1) + goto err; + + break; + + default: + abort(); + } + + if (*c2w != (iconv_t)-1) + iconv_close(*c2w); + if (*w2c != (iconv_t)-1) + iconv_close(*w2c); + + *c2w = id_c2w; + *w2c = id_w2c; + + F_CLR(sp, SC_CONV_ERROR); + F_SET(sp, SC_SCR_REFORMAT); + + return 0; +err: +#endif + switch (option) { + case O_FILEENCODING: + msgq(sp, M_ERR, "321|File encoding conversion not supported"); + break; + case O_INPUTENCODING: + msgq(sp, M_ERR, "322|Input encoding conversion not supported"); + break; + } + return 1; +} + +/* + * conv_end -- + * Close the iconv descriptors, release the buffer. + * + * PUBLIC: void conv_end(SCR *); + */ +void +conv_end(SCR *sp) +{ +#if defined(USE_WIDECHAR) && defined(USE_ICONV) + int i; + for (i = 0; i <= IC_IE_TO_UTF16; ++i) + if (sp->conv.id[i] != (iconv_t)-1) + iconv_close(sp->conv.id[i]); + free(sp->cw.bp1.c); +#endif +} Property changes on: vendor/nvi/2.2.0-05ed8b9/common/conv.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/common/conv.h =================================================================== --- vendor/nvi/2.2.0-05ed8b9/common/conv.h (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/common/conv.h (revision 366308) @@ -0,0 +1,55 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * Copyright (c) 2011, 2012 + * Zhihao Yuan. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#ifdef USE_ICONV +#include +#ifdef ICONV_TRADITIONAL +typedef char ** iconv_src_t; +#else +typedef char const ** iconv_src_t; +#endif +#else +typedef int iconv_t; +#endif + +/* + * XXX + * We can not use MB_CUR_MAX here, since UTF-8 may report it as 6, but + * a sequence longer than 4 is deprecated by RFC 3629. + */ +#define KEY_NEEDSWIDE(sp, ch) \ + (INTISWIDE(ch) && KEY_LEN(sp, ch) <= 4) +#define KEY_COL(sp, ch) \ + (KEY_NEEDSWIDE(sp, ch) ? CHAR_WIDTH(sp, ch) : KEY_LEN(sp, ch)) + +enum { IC_FE_CHAR2INT, IC_FE_INT2CHAR, IC_IE_CHAR2INT, IC_IE_TO_UTF16 }; + +struct _conv_win { + union { + char *c; + CHAR_T *wc; + } bp1; + size_t blen1; +}; + +typedef int (*char2wchar_t) + (SCR *, const char *, ssize_t, struct _conv_win *, size_t *, CHAR_T **); +typedef int (*wchar2char_t) + (SCR *, const CHAR_T *, ssize_t, struct _conv_win *, size_t *, char **); + +struct _conv { + char2wchar_t sys2int; + wchar2char_t int2sys; + char2wchar_t file2int; + wchar2char_t int2file; + char2wchar_t input2int; + iconv_t id[IC_IE_TO_UTF16 + 1]; +}; Property changes on: vendor/nvi/2.2.0-05ed8b9/common/conv.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/common/cut.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/common/cut.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/common/cut.c (revision 366308) @@ -0,0 +1,333 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" + +static void cb_rotate(SCR *); + +/* + * cut -- + * Put a range of lines/columns into a TEXT buffer. + * + * There are two buffer areas, both found in the global structure. The first + * is the linked list of all the buffers the user has named, the second is the + * unnamed buffer storage. There is a pointer, too, which is the current + * default buffer, i.e. it may point to the unnamed buffer or a named buffer + * depending on into what buffer the last text was cut. Logically, in both + * delete and yank operations, if the user names a buffer, the text is cut + * into it. If it's a delete of information on more than a single line, the + * contents of the numbered buffers are rotated up one, the contents of the + * buffer named '9' are discarded, and the text is cut into the buffer named + * '1'. The text is always cut into the unnamed buffer. + * + * In all cases, upper-case buffer names are the same as lower-case names, + * with the exception that they cause the buffer to be appended to instead + * of replaced. Note, however, that if text is appended to a buffer, the + * default buffer only contains the appended text, not the entire contents + * of the buffer. + * + * !!! + * The contents of the default buffer would disappear after most operations + * in historic vi. It's unclear that this is useful, so we don't bother. + * + * When users explicitly cut text into the numeric buffers, historic vi became + * genuinely strange. I've never been able to figure out what was supposed to + * happen. It behaved differently if you deleted text than if you yanked text, + * and, in the latter case, the text was appended to the buffer instead of + * replacing the contents. Hopefully it's not worth getting right, and here + * we just treat the numeric buffers like any other named buffer. + * + * PUBLIC: int cut(SCR *, CHAR_T *, MARK *, MARK *, int); + */ +int +cut(SCR *sp, CHAR_T *namep, MARK *fm, MARK *tm, int flags) +{ + CB *cbp; + CHAR_T name = '\0'; + recno_t lno; + int append, copy_one, copy_def; + + /* + * If the user specified a buffer, put it there. (This may require + * a copy into the numeric buffers. We do the copy so that we don't + * have to reference count and so we don't have to deal with things + * like appends to buffers that are used multiple times.) + * + * Otherwise, if it's supposed to be put in a numeric buffer (usually + * a delete) put it there. The rules for putting things in numeric + * buffers were historically a little strange. There were three cases. + * + * 1: Some motions are always line mode motions, which means + * that the cut always goes into the numeric buffers. + * 2: Some motions aren't line mode motions, e.g. d10w, but + * can cross line boundaries. For these commands, if the + * cut crosses a line boundary, it goes into the numeric + * buffers. This includes most of the commands. + * 3: Some motions aren't line mode motions, e.g. d`, + * but always go into the numeric buffers, regardless. This + * was the commands: % ` / ? ( ) N n { } -- and nvi adds ^A. + * + * Otherwise, put it in the unnamed buffer. + */ + append = copy_one = copy_def = 0; + if (namep != NULL) { + name = *namep; + if (LF_ISSET(CUT_NUMREQ) || (LF_ISSET(CUT_NUMOPT) && + (LF_ISSET(CUT_LINEMODE) || fm->lno != tm->lno))) { + copy_one = 1; + cb_rotate(sp); + } + if ((append = isupper(name))) { + if (!copy_one) + copy_def = 1; + name = tolower(name); + } +namecb: CBNAME(sp, cbp, name); + } else if (LF_ISSET(CUT_NUMREQ) || (LF_ISSET(CUT_NUMOPT) && + (LF_ISSET(CUT_LINEMODE) || fm->lno != tm->lno))) { + name = '1'; + cb_rotate(sp); + goto namecb; + } else + cbp = &sp->gp->dcb_store; + +copyloop: + /* + * If this is a new buffer, create it and add it into the list. + * Otherwise, if it's not an append, free its current contents. + */ + if (cbp == NULL) { + CALLOC_RET(sp, cbp, 1, sizeof(CB)); + cbp->name = name; + TAILQ_INIT(cbp->textq); + SLIST_INSERT_HEAD(sp->gp->cutq, cbp, q); + } else if (!append) { + text_lfree(cbp->textq); + cbp->len = 0; + cbp->flags = 0; + } + + + /* In line mode, it's pretty easy, just cut the lines. */ + if (LF_ISSET(CUT_LINEMODE)) { + cbp->flags |= CB_LMODE; + for (lno = fm->lno; lno <= tm->lno; ++lno) + if (cut_line(sp, lno, 0, ENTIRE_LINE, cbp)) + goto cut_line_err; + } else { + /* + * Get the first line. A length of ENTIRE_LINE causes + * cut_line to cut from the MARK to the end of the line. + */ + if (cut_line(sp, fm->lno, fm->cno, fm->lno != tm->lno ? + ENTIRE_LINE : (tm->cno - fm->cno) + 1, cbp)) + goto cut_line_err; + + /* Get the intermediate lines. */ + for (lno = fm->lno; ++lno < tm->lno;) + if (cut_line(sp, lno, 0, ENTIRE_LINE, cbp)) + goto cut_line_err; + + /* Get the last line. */ + if (tm->lno != fm->lno && + cut_line(sp, lno, 0, tm->cno + 1, cbp)) + goto cut_line_err; + } + + append = 0; /* Only append to the named buffer. */ + sp->gp->dcbp = cbp; /* Repoint the default buffer on each pass. */ + + if (copy_one) { /* Copy into numeric buffer 1. */ + name = '1'; + CBNAME(sp, cbp, name); + copy_one = 0; + goto copyloop; + } + if (copy_def) { /* Copy into the default buffer. */ + cbp = &sp->gp->dcb_store; + copy_def = 0; + goto copyloop; + } + return (0); + +cut_line_err: + text_lfree(cbp->textq); + cbp->len = 0; + cbp->flags = 0; + return (1); +} + +/* + * cb_rotate -- + * Rotate the numbered buffers up one. + */ +static void +cb_rotate(SCR *sp) +{ + CB *cbp, *del_cbp = NULL, *pre_cbp = NULL; + + SLIST_FOREACH(cbp, sp->gp->cutq, q) { + switch(cbp->name) { + case '1': case '2': case '3': + case '4': case '5': case '6': + case '7': case '8': + cbp->name += 1; + break; + case '9': + if (cbp == SLIST_FIRST(sp->gp->cutq)) + SLIST_REMOVE_HEAD(sp->gp->cutq, q); + else + SLIST_REMOVE_AFTER(pre_cbp, q); + del_cbp = cbp; + break; + } + pre_cbp = cbp; + } + if (del_cbp != NULL) { + text_lfree(del_cbp->textq); + free(del_cbp); + } +} + +/* + * cut_line -- + * Cut a portion of a single line. + * + * PUBLIC: int cut_line(SCR *, recno_t, size_t, size_t, CB *); + */ +int +cut_line(SCR *sp, recno_t lno, size_t fcno, size_t clen, CB *cbp) +{ + TEXT *tp; + size_t len; + CHAR_T *p; + + /* Get the line. */ + if (db_get(sp, lno, DBG_FATAL, &p, &len)) + return (1); + + /* Create a TEXT structure that can hold the entire line. */ + if ((tp = text_init(sp, NULL, 0, len)) == NULL) + return (1); + + /* + * If the line isn't empty and it's not the entire line, + * copy the portion we want, and reset the TEXT length. + */ + if (len != 0) { + if (clen == ENTIRE_LINE) + clen = len - fcno; + MEMCPY(tp->lb, p + fcno, clen); + tp->len = clen; + } + + /* Append to the end of the cut buffer. */ + TAILQ_INSERT_TAIL(cbp->textq, tp, q); + cbp->len += tp->len; + + return (0); +} + +/* + * cut_close -- + * Discard all cut buffers. + * + * PUBLIC: void cut_close(GS *); + */ +void +cut_close(GS *gp) +{ + CB *cbp; + + /* Free cut buffer list. */ + while ((cbp = SLIST_FIRST(gp->cutq)) != NULL) { + if (!TAILQ_EMPTY(cbp->textq)) + text_lfree(cbp->textq); + SLIST_REMOVE_HEAD(gp->cutq, q); + free(cbp); + } + + /* Free default cut storage. */ + cbp = &gp->dcb_store; + if (!TAILQ_EMPTY(cbp->textq)) + text_lfree(cbp->textq); +} + +/* + * text_init -- + * Allocate a new TEXT structure. + * + * PUBLIC: TEXT *text_init(SCR *, const CHAR_T *, size_t, size_t); + */ +TEXT * +text_init(SCR *sp, const CHAR_T *p, size_t len, size_t total_len) +{ + TEXT *tp; + + CALLOC(sp, tp, 1, sizeof(TEXT)); + if (tp == NULL) + return (NULL); + /* ANSI C doesn't define a call to malloc(3) for 0 bytes. */ + if ((tp->lb_len = total_len * sizeof(CHAR_T)) != 0) { + MALLOC(sp, tp->lb, tp->lb_len); + if (tp->lb == NULL) { + free(tp); + return (NULL); + } + if (p != NULL && len != 0) + MEMCPY(tp->lb, p, len); + } + tp->len = len; + return (tp); +} + +/* + * text_lfree -- + * Free a chain of text structures. + * + * PUBLIC: void text_lfree(TEXTH *); + */ +void +text_lfree(TEXTH *headp) +{ + TEXT *tp; + + while ((tp = TAILQ_FIRST(headp)) != NULL) { + TAILQ_REMOVE(headp, tp, q); + text_free(tp); + } +} + +/* + * text_free -- + * Free a text structure. + * + * PUBLIC: void text_free(TEXT *); + */ +void +text_free(TEXT *tp) +{ + free(tp->lb); + free(tp); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/common/cut.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/common/delete.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/common/delete.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/common/delete.c (revision 366308) @@ -0,0 +1,157 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "common.h" + +/* + * del -- + * Delete a range of text. + * + * PUBLIC: int del(SCR *, MARK *, MARK *, int); + */ +int +del(SCR *sp, MARK *fm, MARK *tm, int lmode) +{ + recno_t lno; + size_t blen, len, nlen, tlen; + CHAR_T *bp, *p; + int eof, rval; + + bp = NULL; + + /* Case 1 -- delete in line mode. */ + if (lmode) { + for (lno = tm->lno; lno >= fm->lno; --lno) { + if (db_delete(sp, lno)) + return (1); + ++sp->rptlines[L_DELETED]; + if (lno % INTERRUPT_CHECK == 0 && INTERRUPTED(sp)) + break; + } + goto done; + } + + /* + * Case 2 -- delete to EOF. This is a special case because it's + * easier to pick it off than try and find it in the other cases. + */ + if (db_last(sp, &lno)) + return (1); + if (tm->lno >= lno) { + if (tm->lno == lno) { + if (db_get(sp, lno, DBG_FATAL, &p, &len)) + return (1); + eof = tm->cno != ENTIRE_LINE && tm->cno >= len ? 1 : 0; + } else + eof = 1; + if (eof) { + for (lno = tm->lno; lno > fm->lno; --lno) { + if (db_delete(sp, lno)) + return (1); + ++sp->rptlines[L_DELETED]; + if (lno % + INTERRUPT_CHECK == 0 && INTERRUPTED(sp)) + break; + } + if (db_get(sp, fm->lno, DBG_FATAL, &p, &len)) + return (1); + GET_SPACE_RETW(sp, bp, blen, fm->cno); + MEMCPY(bp, p, fm->cno); + if (db_set(sp, fm->lno, bp, fm->cno)) + return (1); + goto done; + } + } + + /* Case 3 -- delete within a single line. */ + if (tm->lno == fm->lno) { + if (db_get(sp, fm->lno, DBG_FATAL, &p, &len)) + return (1); + if (len != 0) { + GET_SPACE_RETW(sp, bp, blen, len); + if (fm->cno != 0) + MEMCPY(bp, p, fm->cno); + MEMCPY(bp + fm->cno, p + (tm->cno + 1), + len - (tm->cno + 1)); + if (db_set(sp, fm->lno, + bp, len - ((tm->cno - fm->cno) + 1))) + goto err; + } + goto done; + } + + /* + * Case 4 -- delete over multiple lines. + * + * Copy the start partial line into place. + */ + if ((tlen = fm->cno) != 0) { + if (db_get(sp, fm->lno, DBG_FATAL, &p, NULL)) + return (1); + GET_SPACE_RETW(sp, bp, blen, tlen + 256); + MEMCPY(bp, p, tlen); + } + + /* Copy the end partial line into place. */ + if (db_get(sp, tm->lno, DBG_FATAL, &p, &len)) + goto err; + if (len != 0 && tm->cno != len - 1) { + /* + * XXX + * We can overflow memory here, if the total length is greater + * than SIZE_T_MAX. The only portable way I've found to test + * is depending on the overflow being less than the value. + */ + nlen = (len - (tm->cno + 1)) + tlen; + if (tlen > nlen) { + msgq(sp, M_ERR, "002|Line length overflow"); + goto err; + } + if (tlen == 0) { + GET_SPACE_RETW(sp, bp, blen, nlen); + } else + ADD_SPACE_RETW(sp, bp, blen, nlen); + + MEMCPY(bp + tlen, p + (tm->cno + 1), len - (tm->cno + 1)); + tlen += len - (tm->cno + 1); + } + + /* Set the current line. */ + if (db_set(sp, fm->lno, bp, tlen)) + goto err; + + /* Delete the last and intermediate lines. */ + for (lno = tm->lno; lno > fm->lno; --lno) { + if (db_delete(sp, lno)) + goto err; + ++sp->rptlines[L_DELETED]; + if (lno % INTERRUPT_CHECK == 0 && INTERRUPTED(sp)) + break; + } + +done: rval = 0; + if (0) +err: rval = 1; + if (bp != NULL) + FREE_SPACEW(sp, bp, blen); + return (rval); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/common/delete.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/common/encoding.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/common/encoding.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/common/encoding.c (revision 366308) @@ -0,0 +1,232 @@ +/*- + * Copyright (c) 2011, 2012 + * Zhihao Yuan. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include + +int looks_utf8(const char *, size_t); +int looks_utf16(const char *, size_t); +int decode_utf8(const char *); +int decode_utf16(const char *, int); + +#define F 0 /* character never appears in text */ +#define T 1 /* character appears in plain ASCII text */ +#define I 2 /* character appears in ISO-8859 text */ +#define X 3 /* character appears in non-ISO extended ASCII (Mac, IBM PC) */ + +static char text_chars[256] = { + /* BEL BS HT LF FF CR */ + F, F, F, F, F, F, F, T, T, T, T, F, T, T, F, F, /* 0x0X */ + /* ESC */ + F, F, F, F, F, F, F, F, F, F, F, T, F, F, F, F, /* 0x1X */ + T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x2X */ + T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x3X */ + T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x4X */ + T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x5X */ + T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x6X */ + T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, F, /* 0x7X */ + /* NEL */ + X, X, X, X, X, T, X, X, X, X, X, X, X, X, X, X, /* 0x8X */ + X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, /* 0x9X */ + I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xaX */ + I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xbX */ + I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xcX */ + I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xdX */ + I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xeX */ + I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I /* 0xfX */ +}; + +/* + * looks_utf8 -- + * Decide whether some text looks like UTF-8. Returns: + * + * -1: invalid UTF-8 + * 0: uses odd control characters, so doesn't look like text + * 1: 7-bit text + * 2: definitely UTF-8 text (valid high-bit set bytes) + * + * Based on RFC 3629. UTF-8 with BOM is not accepted. + * + * PUBLIC: int looks_utf8(const char *, size_t); + */ +int +looks_utf8(const char *ibuf, size_t nbytes) +{ + const u_char *buf = (u_char *)ibuf; + size_t i; + int n; + int gotone = 0, ctrl = 0; + + for (i = 0; i < nbytes; i++) { + if ((buf[i] & 0x80) == 0) { /* 0xxxxxxx is plain ASCII */ + /* + * Even if the whole file is valid UTF-8 sequences, + * still reject it if it uses weird control characters. + */ + + if (text_chars[buf[i]] != T) + ctrl = 1; + } else if ((buf[i] & 0x40) == 0) { /* 10xxxxxx never 1st byte */ + return -1; + } else { /* 11xxxxxx begins UTF-8 */ + int following; + + if ((buf[i] & 0x20) == 0) /* 110xxxxx */ + if (buf[i] > 0xC1) /* C0, C1 */ + following = 1; + else return -1; + else if ((buf[i] & 0x10) == 0) /* 1110xxxx */ + following = 2; + else if ((buf[i] & 0x08) == 0) /* 11110xxx */ + if (buf[i] < 0xF5) + following = 3; + else return -1; /* F5, F6, F7 */ + else + return -1; /* F8~FF */ + + for (n = 0; n < following; n++) { + i++; + if (i >= nbytes) + goto done; + + if ((buf[i] & 0xc0) != 0x80) /* 10xxxxxx */ + return -1; + } + + gotone = 1; + } + } +done: + return ctrl ? 0 : (gotone ? 2 : 1); +} + +/* + * looks_utf16 -- + * Decide whether some text looks like UTF-16. Returns: + * + * 0: invalid UTF-16 + * 1: Little-endian UTF-16 + * 2: Big-endian UTF-16 + * + * PUBLIC: int looks_utf16(const char *, size_t); + */ +int +looks_utf16(const char *ibuf, size_t nbytes) +{ + const u_char *buf = (u_char *)ibuf; + int bigend; + size_t i; + unsigned int c; + int bom; + int following = 0; + + if (nbytes < 2) + return 0; + + bom = buf[0] << 8 ^ buf[1]; + if (bom == 0xFFFE) + bigend = 0; + else if (bom == 0xFEFF) + bigend = 1; + else + return 0; + + for (i = 2; i + 1 < nbytes; i += 2) { + if (bigend) + c = buf[i] << 8 ^ buf[i + 1]; + else + c = buf[i] ^ buf[i + 1] << 8; + + if (!following) + if (c < 0xD800 || c > 0xDFFF) + if (c < 128 && text_chars[c] != T) + return 0; + else + following = 0; + else if (c > 0xDBFF) + return 0; + else { + following = 1; + continue; + } + else if (c < 0xDC00 || c > 0xDFFF) + return 0; + } + + return 1 + bigend; +} + +#undef F +#undef T +#undef I +#undef X + +/* + * decode_utf8 -- + * Decode a UTF-8 character from byte string to Unicode. + * Returns -1 if the first byte is a not UTF-8 leader. + * + * Based on RFC 3629, but without error detection. + * + * PUBLIC: int decode_utf8(const char *); + */ +int +decode_utf8(const char *ibuf) +{ + const u_char *buf = (u_char *)ibuf; + int u = -1; + + if ((buf[0] & 0x80) == 0) + u = buf[0]; + else if ((buf[0] & 0x40) == 0); + else { + if ((buf[0] & 0x20) == 0) + u = (buf[0] ^ 0xC0) << 6 ^ (buf[1] ^ 0x80); + else if ((buf[0] & 0x10) == 0) + u = (buf[0] ^ 0xE0) << 12 ^ (buf[1] ^ 0x80) << 6 + ^ (buf[2] ^ 0x80); + else if (((buf[0] & 0x08) == 0)) + u = (buf[0] ^ 0xF0) << 18 ^ (buf[1] ^ 0x80) << 12 + ^ (buf[2] ^ 0x80) << 6 ^ (buf[3] ^ 0x80); + } + + return u; +} + +/* + * decode_utf16 -- + * Decode a UTF-16 character from byte string to Unicode. + * Returns -1 if the first unsigned integer is invalid. + * + * No error detection on supplementary bytes. + * + * PUBLIC: int decode_utf16(const char *, int); + */ +int +decode_utf16(const char* ibuf, int bigend) +{ + const u_char *buf = (u_char *)ibuf; + int u = -1; + unsigned int w1, w2; + + if (bigend) + w1 = buf[0] << 8 ^ buf[1]; + else + w1 = buf[0] ^ buf[1] << 8; + + if (w1 < 0xD800 || w1 > 0xDFFF) + u = w1; + else if (w1 > 0xDBFF); + else { + if (bigend) + w2 = buf[2] << 8 ^ buf[3]; + else + w2 = buf[2] ^ buf[3] << 8; + u = ((w1 ^ 0xD800) << 10 ^ (w2 ^ 0xDC00)) + 0x10000; + } + + return u; +} Property changes on: vendor/nvi/2.2.0-05ed8b9/common/encoding.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/common/exf.h =================================================================== --- vendor/nvi/2.2.0-05ed8b9/common/exf.h (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/common/exf.h (revision 366308) @@ -0,0 +1,76 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + /* Undo direction. */ +/* + * exf -- + * The file structure. + */ +struct _exf { + int refcnt; /* Reference count. */ + + /* Underlying database state. */ + DB *db; /* File db structure. */ + CHAR_T *c_lp; /* Cached line. */ + size_t c_len; /* Cached line length. */ + size_t c_blen; /* Cached line buffer length. */ + recno_t c_lno; /* Cached line number. */ + recno_t c_nlines; /* Cached lines in the file. */ + + DB *log; /* Log db structure. */ + char *l_lp; /* Log buffer. */ + size_t l_len; /* Log buffer length. */ + recno_t l_high; /* Log last + 1 record number. */ + recno_t l_cur; /* Log current record number. */ + MARK l_cursor; /* Log cursor position. */ + dir_t lundo; /* Last undo direction. */ + + /* Linked list of file MARK's. */ + SLIST_HEAD(_markh, _lmark) marks[1]; + + dev_t mdev; /* Device. */ + ino_t minode; /* Inode. */ + struct timespec mtim; /* Last modification time. */ + + /* + * Recovery in general, and these fields specifically, are described + * in recover.c. + */ +#define RCV_PERIOD 120 /* Sync every two minutes. */ + char *rcv_path; /* Recover file name. */ + char *rcv_mpath; /* Recover mail file name. */ + int rcv_fd; /* Locked mail file descriptor. */ + +#define F_DEVSET 0x001 /* mdev/minode fields initialized. */ +#define F_FIRSTMODIFY 0x002 /* File not yet modified. */ +#define F_MODIFIED 0x004 /* File is currently dirty. */ +#define F_MULTILOCK 0x008 /* Multiple processes running, lock. */ +#define F_NOLOG 0x010 /* Logging turned off. */ +#define F_RCV_NORM 0x020 /* Don't delete recovery files. */ +#define F_RCV_ON 0x040 /* Recovery is possible. */ +#define F_UNDO 0x080 /* No change since last undo. */ + u_int8_t flags; +}; + +/* Flags to db_get(). */ +#define DBG_FATAL 0x001 /* If DNE, error message. */ +#define DBG_NOCACHE 0x002 /* Ignore the front-end cache. */ + +/* Flags to file_init() and file_write(). */ +#define FS_ALL 0x001 /* Write the entire file. */ +#define FS_APPEND 0x002 /* Append to the file. */ +#define FS_FORCE 0x004 /* Force is set. */ +#define FS_OPENERR 0x008 /* Open failed, try it again. */ +#define FS_POSSIBLE 0x010 /* Force could have been set. */ +#define FS_SETALT 0x020 /* Set alternate file name. */ + +/* Flags to rcv_sync(). */ +#define RCV_EMAIL 0x01 /* Send the user email, IFF file modified. */ +#define RCV_ENDSESSION 0x02 /* End the file session. */ +#define RCV_PRESERVE 0x04 /* Preserve backup file, IFF file modified. */ +#define RCV_SNAPSHOT 0x08 /* Snapshot the recovery, and send email. */ Property changes on: vendor/nvi/2.2.0-05ed8b9/common/exf.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/common/gs.h =================================================================== --- vendor/nvi/2.2.0-05ed8b9/common/gs.h (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/common/gs.h (revision 366308) @@ -0,0 +1,194 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#define TEMPORARY_FILE_STRING "/tmp" /* Default temporary file name. */ + +#include + +/* + * File reference structure (FREF). The structure contains the name of the + * file, along with the information that follows the name. + * + * !!! + * The read-only bit follows the file name, not the file itself. + */ +struct _fref { + TAILQ_ENTRY(_fref) q; /* Linked list of file references. */ + char *name; /* File name. */ + char *tname; /* Backing temporary file name. */ + + recno_t lno; /* 1-N: file cursor line. */ + size_t cno; /* 0-N: file cursor column. */ + +#define FR_CURSORSET 0x0001 /* If lno/cno values valid. */ +#define FR_DONTDELETE 0x0002 /* Don't delete the temporary file. */ +#define FR_EXNAMED 0x0004 /* Read/write renamed the file. */ +#define FR_NAMECHANGE 0x0008 /* If the name changed. */ +#define FR_NEWFILE 0x0010 /* File doesn't really exist yet. */ +#define FR_RECOVER 0x0020 /* File is being recovered. */ +#define FR_TMPEXIT 0x0040 /* Modified temporary file, no exit. */ +#define FR_TMPFILE 0x0080 /* If file has no name. */ +#define FR_UNLOCKED 0x0100 /* File couldn't be locked. */ + u_int16_t flags; +}; + +/* Action arguments to scr_exadjust(). */ +typedef enum { EX_TERM_CE, EX_TERM_SCROLL } exadj_t; + +/* Screen attribute arguments to scr_attr(). */ +typedef enum { SA_ALTERNATE, SA_INVERSE } scr_attr_t; + +/* Key type arguments to scr_keyval(). */ +typedef enum { KEY_VEOF, KEY_VERASE, KEY_VKILL, KEY_VWERASE } scr_keyval_t; + +/* + * GS: + * + * Structure that describes global state of the running program. + */ +struct _gs { + int id; /* Last allocated screen id. */ + TAILQ_HEAD(_dqh, _scr) dq[1]; /* Displayed screens. */ + TAILQ_HEAD(_hqh, _scr) hq[1]; /* Hidden screens. */ + + SCR *ccl_sp; /* Colon command-line screen. */ + + void *cl_private; /* Curses support private area. */ + + /* File references. */ + TAILQ_HEAD(_frefh, _fref) frefq[1]; + +#define GO_COLUMNS 0 /* Global options: columns. */ +#define GO_LINES 1 /* Global options: lines. */ +#define GO_SECURE 2 /* Global options: secure. */ +#define GO_TERM 3 /* Global options: terminal type. */ + OPTION opts[GO_TERM + 1]; + + nl_catd catd; /* Message catalog descriptor. */ + MSGH msgq[1]; /* User message list. */ +#define DEFAULT_NOPRINT '\1' /* Emergency non-printable character. */ + int noprint; /* Cached, unprintable character. */ + + char *tmp_bp; /* Temporary buffer. */ + size_t tmp_blen; /* Temporary buffer size. */ + + /* + * Ex command structures (EXCMD). Defined here because ex commands + * exist outside of any particular screen or file. + */ +#define EXCMD_RUNNING(gp) (SLIST_FIRST((gp)->ecq)->clen != 0) + /* Ex command linked list. */ + SLIST_HEAD(_excmdh, _excmd) ecq[1]; + EXCMD excmd; /* Default ex command structure. */ + char *if_name; /* Current associated file. */ + recno_t if_lno; /* Current associated line number. */ + + char *c_option; /* Ex initial, command-line command. */ + +#ifdef DEBUG + FILE *tracefp; /* Trace file pointer. */ +#endif + + EVENT *i_event; /* Array of input events. */ + size_t i_nelem; /* Number of array elements. */ + size_t i_cnt; /* Count of events. */ + size_t i_next; /* Offset of next event. */ + + CB *dcbp; /* Default cut buffer pointer. */ + CB dcb_store; /* Default cut buffer storage. */ + SLIST_HEAD(_cuth, _cb) cutq[1]; /* Linked list of cut buffers. */ + +#define MAX_BIT_SEQ 0x7f /* Max + 1 fast check character. */ + SLIST_HEAD(_seqh, _seq) seqq[1];/* Linked list of maps, abbrevs. */ + bitstr_t bit_decl(seqb, MAX_BIT_SEQ + 1); + +#define MAX_FAST_KEY 0xff /* Max fast check character.*/ +#define KEY_LEN(sp, ch) \ + (((ch) & ~MAX_FAST_KEY) == 0 ? \ + sp->gp->cname[(unsigned char)ch].len : v_key_len(sp, ch)) +#define KEY_NAME(sp, ch) \ + (((ch) & ~MAX_FAST_KEY) == 0 ? \ + sp->gp->cname[(unsigned char)ch].name : v_key_name(sp, ch)) + struct { + char name[MAX_CHARACTER_COLUMNS + 1]; + u_int8_t len; + } cname[MAX_FAST_KEY + 1]; /* Fast lookup table. */ + +#define KEY_VAL(sp, ch) \ + (((ch) & ~MAX_FAST_KEY) == 0 ? \ + sp->gp->special_key[(unsigned char)ch] : v_key_val(sp,ch)) + e_key_t /* Fast lookup table. */ + special_key[MAX_FAST_KEY + 1]; + +/* Flags. */ +#define G_ABBREV 0x0001 /* If have abbreviations. */ +#define G_BELLSCHED 0x0002 /* Bell scheduled. */ +#define G_INTERRUPTED 0x0004 /* Interrupted. */ +#define G_RECOVER_SET 0x0008 /* Recover system initialized. */ +#define G_SCRIPTED 0x0010 /* Ex script session. */ +#define G_SCRWIN 0x0020 /* Scripting windows running. */ +#define G_SNAPSHOT 0x0040 /* Always snapshot files. */ +#define G_SRESTART 0x0080 /* Screen restarted. */ +#define G_TMP_INUSE 0x0100 /* Temporary buffer in use. */ + u_int32_t flags; + + /* Screen interface functions. */ + /* Add a string to the screen. */ + int (*scr_addstr)(SCR *, const char *, size_t); + /* Add a string to the screen. */ + int (*scr_waddstr)(SCR *, const CHAR_T *, size_t); + /* Toggle a screen attribute. */ + int (*scr_attr)(SCR *, scr_attr_t, int); + /* Terminal baud rate. */ + int (*scr_baud)(SCR *, u_long *); + /* Beep/bell/flash the terminal. */ + int (*scr_bell)(SCR *); + /* Display a busy message. */ + void (*scr_busy)(SCR *, const char *, busy_t); + /* Prepare child. */ + int (*scr_child)(SCR *); + /* Clear to the end of the line. */ + int (*scr_clrtoeol)(SCR *); + /* Return the cursor location. */ + int (*scr_cursor)(SCR *, size_t *, size_t *); + /* Delete a line. */ + int (*scr_deleteln)(SCR *); + /* Discard a screen. */ + int (*scr_discard)(SCR *, SCR **); + /* Get a keyboard event. */ + int (*scr_event)(SCR *, EVENT *, u_int32_t, int); + /* Ex: screen adjustment routine. */ + int (*scr_ex_adjust)(SCR *, exadj_t); + int (*scr_fmap) /* Set a function key. */ + (SCR *, seq_t, CHAR_T *, size_t, CHAR_T *, size_t); + /* Get terminal key value. */ + int (*scr_keyval)(SCR *, scr_keyval_t, CHAR_T *, int *); + /* Insert a line. */ + int (*scr_insertln)(SCR *); + /* Handle an option change. */ + int (*scr_optchange)(SCR *, int, char *, u_long *); + /* Move the cursor. */ + int (*scr_move)(SCR *, size_t, size_t); + /* Message or ex output. */ + void (*scr_msg)(SCR *, mtype_t, char *, size_t); + /* Refresh the screen. */ + int (*scr_refresh)(SCR *, int); + /* Rename the file. */ + int (*scr_rename)(SCR *, char *, int); + /* Reply to an event. */ + int (*scr_reply)(SCR *, int, char *); + /* Set the screen type. */ + int (*scr_screen)(SCR *, u_int32_t); + /* Split the screen. */ + int (*scr_split)(SCR *, SCR *); + /* Suspend the editor. */ + int (*scr_suspend)(SCR *, int *); + /* Print usage message. */ + void (*scr_usage)(void); +}; Property changes on: vendor/nvi/2.2.0-05ed8b9/common/gs.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/common/key.h =================================================================== --- vendor/nvi/2.2.0-05ed8b9/common/key.h (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/common/key.h (revision 366308) @@ -0,0 +1,240 @@ +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1991, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "multibyte.h" + +#ifdef USE_WIDECHAR +#define FILE2INT5(sp,buf,n,nlen,w,wlen) \ + sp->conv.file2int(sp, n, nlen, &buf, &wlen, &w) +#define INT2FILE(sp,w,wlen,n,nlen) \ + sp->conv.int2file(sp, w, wlen, &sp->cw, &nlen, &n) +#define CHAR2INT5(sp,buf,n,nlen,w,wlen) \ + sp->conv.sys2int(sp, n, nlen, &buf, &wlen, &w) +#define INT2CHAR(sp,w,wlen,n,nlen) \ + sp->conv.int2sys(sp, w, wlen, &sp->cw, &nlen, &n) +#define INPUT2INT5(sp,cw,n,nlen,w,wlen) \ + sp->conv.input2int(sp, n, nlen, &(cw), &wlen, &w) +#define CONST +#define INTISWIDE(c) (wctob(c) == EOF) +#define CHAR_WIDTH(sp, ch) wcwidth(ch) +#define CAN_PRINT(sp, ch) (CHAR_WIDTH(sp, ch) > 0) +#else +#define FILE2INT5(sp,buf,n,nlen,w,wlen) \ + (w = n, wlen = nlen, 0) +#define INT2FILE(sp,w,wlen,n,nlen) \ + (n = w, nlen = wlen, 0) +#define CHAR2INT5(sp,buf,n,nlen,w,wlen) \ + (w = n, wlen = nlen, 0) +#define INT2CHAR(sp,w,wlen,n,nlen) \ + (n = w, nlen = wlen, 0) +#define INPUT2INT5(sp,buf,n,nlen,w,wlen) \ + (w = n, wlen = nlen, 0) +#define CONST const +#define INTISWIDE(c) 0 +#define CHAR_WIDTH(sp, ch) 1 +#define CAN_PRINT(sp, ch) isprint(ch) +#endif +#define FILE2INT(sp,n,nlen,w,wlen) \ + FILE2INT5(sp,sp->cw,n,nlen,w,wlen) +#define CHAR2INT(sp,n,nlen,w,wlen) \ + CHAR2INT5(sp,sp->cw,n,nlen,w,wlen) + +/* The maximum number of columns any character can take up on a screen. */ +#define MAX_CHARACTER_COLUMNS 7 + +/* + * Event types. + * + * The program structure depends on the event loop being able to return + * E_EOF/E_ERR multiple times -- eventually enough things will end due + * to the events that vi will reach the command level for the screen, at + * which point the exit flags will be set and vi will exit. + */ +typedef enum { + E_NOTUSED = 0, /* Not set. */ + E_CHARACTER, /* Input character: e_c set. */ + E_EOF, /* End of input (NOT ^D). */ + E_ERR, /* Input error. */ + E_INTERRUPT, /* Interrupt. */ + E_REPAINT, /* Repaint: e_flno, e_tlno set. */ + E_SIGHUP, /* SIGHUP. */ + E_SIGTERM, /* SIGTERM. */ + E_STRING, /* Input string: e_csp, e_len set. */ + E_TIMEOUT, /* Timeout. */ + E_WRESIZE, /* Window resize. */ +} e_event_t; + +/* + * Character values. + */ +typedef enum { + K_NOTUSED = 0, /* Not set. */ + K_BACKSLASH, /* \ */ + K_CARAT, /* ^ */ + K_CNTRLD, /* ^D */ + K_CNTRLR, /* ^R */ + K_CNTRLT, /* ^T */ + K_CNTRLZ, /* ^Z */ + K_COLON, /* : */ + K_CR, /* \r */ + K_ESCAPE, /* ^[ */ + K_FORMFEED, /* \f */ + K_HEXCHAR, /* ^X */ + K_NL, /* \n */ + K_RIGHTBRACE, /* } */ + K_RIGHTPAREN, /* ) */ + K_TAB, /* \t */ + K_VERASE, /* set from tty: default ^H */ + K_VKILL, /* set from tty: default ^U */ + K_VLNEXT, /* set from tty: default ^V */ + K_VWERASE, /* set from tty: default ^W */ + K_ZERO /* 0 */ +} e_key_t; + +struct _event { + TAILQ_ENTRY(_event) q; /* Linked list of events. */ + e_event_t e_event; /* Event type. */ + union { + struct { /* Input character. */ + CHAR_T c; /* Character. */ + e_key_t value; /* Key type. */ + +#define CH_ABBREVIATED 0x01 /* Character is from an abbreviation. */ +#define CH_MAPPED 0x02 /* Character is from a map. */ +#define CH_NOMAP 0x04 /* Do not map the character. */ +#define CH_QUOTED 0x08 /* Character is already quoted. */ + u_int8_t flags; + } _e_ch; +#define e_ch _u_event._e_ch /* !!! The structure, not the char. */ +#define e_c _u_event._e_ch.c +#define e_value _u_event._e_ch.value +#define e_flags _u_event._e_ch.flags + + struct { /* Screen position, size. */ + size_t lno1; /* Line number. */ + size_t cno1; /* Column number. */ + size_t lno2; /* Line number. */ + size_t cno2; /* Column number. */ + } _e_mark; +#define e_lno _u_event._e_mark.lno1 /* Single location. */ +#define e_cno _u_event._e_mark.cno1 +#define e_flno _u_event._e_mark.lno1 /* Text region. */ +#define e_fcno _u_event._e_mark.cno1 +#define e_tlno _u_event._e_mark.lno2 +#define e_tcno _u_event._e_mark.cno2 + + struct { /* Input string. */ + CHAR_T *asp; /* Allocated string. */ + CHAR_T *csp; /* String. */ + size_t len; /* String length. */ + } _e_str; +#define e_asp _u_event._e_str.asp +#define e_csp _u_event._e_str.csp +#define e_len _u_event._e_str.len + } _u_event; +}; + +typedef struct _keylist { + e_key_t value; /* Special value. */ + int ch; /* Key. */ +} KEYLIST; +extern KEYLIST keylist[]; + + /* Return if more keys in queue. */ +#define KEYS_WAITING(sp) ((sp)->gp->i_cnt != 0) +#define MAPPED_KEYS_WAITING(sp) \ + (KEYS_WAITING(sp) && \ + F_ISSET(&sp->gp->i_event[sp->gp->i_next].e_ch, CH_MAPPED)) + +/* + * Ex/vi commands are generally separated by whitespace characters. We + * can't use the standard isspace(3) macro because it returns true for + * characters like ^K in the ASCII character set. The POSIX isblank(3) + * has the same problem for non-ASCII locale, so we need a standalone one. + */ + +static __inline int +cmdskip(CHAR_T ch) +{ + return ch == ' ' || ch == '\t'; +} + +/* The "standard" tab width, for displaying things to users. */ +#define STANDARD_TAB 6 + +/* Various special characters, messages. */ +#define CH_BSEARCH '?' /* Backward search prompt. */ +#define CH_CURSOR ' ' /* Cursor character. */ +#define CH_ENDMARK '$' /* End of a range. */ +#define CH_EXPROMPT ':' /* Ex prompt. */ +#define CH_FSEARCH '/' /* Forward search prompt. */ +#define CH_HEX '\030' /* Leading hex character. */ +#define CH_LITERAL '\026' /* ASCII ^V. */ +#define CH_NO 'n' /* No. */ +#define CH_NOT_DIGIT 'a' /* A non-isdigit() character. */ +#define CH_QUIT 'q' /* Quit. */ +#define CH_YES 'y' /* Yes. */ + +/* + * Checking for interrupts means that we look at the bit that gets set if the + * screen code supports asynchronous events, and call back into the event code + * so that non-asynchronous screens get a chance to post the interrupt. + * + * INTERRUPT_CHECK is the number of lines "operated" on before checking for + * interrupts. + */ +#define INTERRUPT_CHECK 100 +#define INTERRUPTED(sp) \ + (F_ISSET((sp)->gp, G_INTERRUPTED) || \ + (!v_event_get(sp, NULL, 0, EC_INTERRUPT) && \ + F_ISSET((sp)->gp, G_INTERRUPTED))) +#define CLR_INTERRUPT(sp) \ + F_CLR((sp)->gp, G_INTERRUPTED) + +/* Flags describing types of characters being requested. */ +#define EC_INTERRUPT 0x001 /* Checking for interrupts. */ +#define EC_MAPCOMMAND 0x002 /* Apply the command map. */ +#define EC_MAPINPUT 0x004 /* Apply the input map. */ +#define EC_MAPNODIGIT 0x008 /* Return to a digit. */ +#define EC_QUOTED 0x010 /* Try to quote next character */ +#define EC_RAW 0x020 /* Any next character. XXX: not used. */ +#define EC_TIMEOUT 0x040 /* Timeout to next character. */ + +/* Flags describing text input special cases. */ +#define TXT_ADDNEWLINE 0x00000001 /* Replay starts on a new line. */ +#define TXT_AICHARS 0x00000002 /* Leading autoindent chars. */ +#define TXT_ALTWERASE 0x00000004 /* Option: altwerase. */ +#define TXT_APPENDEOL 0x00000008 /* Appending after EOL. */ +#define TXT_AUTOINDENT 0x00000010 /* Autoindent set this line. */ +#define TXT_BACKSLASH 0x00000020 /* Backslashes escape characters. */ +#define TXT_BEAUTIFY 0x00000040 /* Only printable characters. */ +#define TXT_BS 0x00000080 /* Backspace returns the buffer. */ +#define TXT_CEDIT 0x00000100 /* Can return TERM_CEDIT. */ +#define TXT_CNTRLD 0x00000200 /* Control-D is a command. */ +#define TXT_CNTRLT 0x00000400 /* Control-T is an indent special. */ +#define TXT_CR 0x00000800 /* CR returns the buffer. */ +#define TXT_DOTTERM 0x00001000 /* Leading '.' terminates the input. */ +#define TXT_EMARK 0x00002000 /* End of replacement mark. */ +#define TXT_EOFCHAR 0x00004000 /* ICANON set, return EOF character. */ +#define TXT_ESCAPE 0x00008000 /* Escape returns the buffer. */ +#define TXT_FILEC 0x00010000 /* Option: filec. */ +#define TXT_INFOLINE 0x00020000 /* Editing the info line. */ +#define TXT_MAPINPUT 0x00040000 /* Apply the input map. */ +#define TXT_NLECHO 0x00080000 /* Echo the newline. */ +#define TXT_NUMBER 0x00100000 /* Number the line. */ +#define TXT_OVERWRITE 0x00200000 /* Overwrite characters. */ +#define TXT_PROMPT 0x00400000 /* Display a prompt. */ +#define TXT_RECORD 0x00800000 /* Record for replay. */ +#define TXT_REPLACE 0x01000000 /* Replace; don't delete overwrite. */ +#define TXT_REPLAY 0x02000000 /* Replay the last input. */ +#define TXT_RESOLVE 0x04000000 /* Resolve the text into the file. */ +#define TXT_SEARCHINCR 0x08000000 /* Incremental search. */ +#define TXT_SHOWMATCH 0x10000000 /* Option: showmatch. */ +#define TXT_TTYWERASE 0x20000000 /* Option: ttywerase. */ +#define TXT_WRAPMARGIN 0x40000000 /* Option: wrapmargin. */ Property changes on: vendor/nvi/2.2.0-05ed8b9/common/key.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/common/line.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/common/line.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/common/line.c (revision 366308) @@ -0,0 +1,621 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "common.h" +#include "../vi/vi.h" + +static int scr_update(SCR *, recno_t, lnop_t, int); + +/* + * db_eget -- + * Front-end to db_get, special case handling for empty files. + * + * PUBLIC: int db_eget(SCR *, recno_t, CHAR_T **, size_t *, int *); + */ +int +db_eget(SCR *sp, + recno_t lno, /* Line number. */ + CHAR_T **pp, /* Pointer store. */ + size_t *lenp, /* Length store. */ + int *isemptyp) +{ + recno_t l1; + + if (isemptyp != NULL) + *isemptyp = 0; + + /* If the line exists, simply return it. */ + if (!db_get(sp, lno, 0, pp, lenp)) + return (0); + + /* + * If the user asked for line 0 or line 1, i.e. the only possible + * line in an empty file, find the last line of the file; db_last + * fails loudly. + */ + if ((lno == 0 || lno == 1) && db_last(sp, &l1)) + return (1); + + /* If the file isn't empty, fail loudly. */ + if ((lno != 0 && lno != 1) || l1 != 0) { + db_err(sp, lno); + return (1); + } + + if (isemptyp != NULL) + *isemptyp = 1; + + return (1); +} + +/* + * db_get -- + * Look in the text buffers for a line, followed by the cache, followed + * by the database. + * + * PUBLIC: int db_get(SCR *, recno_t, u_int32_t, CHAR_T **, size_t *); + */ +int +db_get(SCR *sp, + recno_t lno, /* Line number. */ + u_int32_t flags, + CHAR_T **pp, /* Pointer store. */ + size_t *lenp) /* Length store. */ +{ + DBT data, key; + EXF *ep; + TEXT *tp; + recno_t l1, l2; + CHAR_T *wp; + size_t wlen; + + /* + * The underlying recno stuff handles zero by returning NULL, but + * have to have an OOB condition for the look-aside into the input + * buffer anyway. + */ + if (lno == 0) + goto err1; + + /* Check for no underlying file. */ + if ((ep = sp->ep) == NULL) { + ex_emsg(sp, NULL, EXM_NOFILEYET); + goto err3; + } + + if (LF_ISSET(DBG_NOCACHE)) + goto nocache; + + /* + * Look-aside into the TEXT buffers and see if the line we want + * is there. + */ + if (F_ISSET(sp, SC_TINPUT)) { + l1 = ((TEXT *)TAILQ_FIRST(sp->tiq))->lno; + l2 = ((TEXT *)TAILQ_LAST(sp->tiq, _texth))->lno; + if (l1 <= lno && l2 >= lno) { +#if defined(DEBUG) && 0 + TRACE(sp, "retrieve TEXT buffer line %lu\n", (u_long)lno); +#endif + for (tp = TAILQ_FIRST(sp->tiq); + tp->lno != lno; tp = TAILQ_NEXT(tp, q)); + if (lenp != NULL) + *lenp = tp->len; + if (pp != NULL) + *pp = tp->lb; + return (0); + } + /* + * Adjust the line number for the number of lines used + * by the text input buffers. + */ + if (lno > l2) + lno -= l2 - l1; + } + + /* Look-aside into the cache, and see if the line we want is there. */ + if (lno == ep->c_lno) { +#if defined(DEBUG) && 0 + TRACE(sp, "retrieve cached line %lu\n", (u_long)lno); +#endif + if (lenp != NULL) + *lenp = ep->c_len; + if (pp != NULL) + *pp = ep->c_lp; + return (0); + } + ep->c_lno = OOBLNO; + +nocache: + /* Get the line from the underlying database. */ + key.data = &lno; + key.size = sizeof(lno); + switch (ep->db->get(ep->db, &key, &data, 0)) { + case -1: + goto err2; + case 1: +err1: if (LF_ISSET(DBG_FATAL)) +err2: db_err(sp, lno); +alloc_err: +err3: if (lenp != NULL) + *lenp = 0; + if (pp != NULL) + *pp = NULL; + return (1); + } + + if (FILE2INT(sp, data.data, data.size, wp, wlen)) { + if (!F_ISSET(sp, SC_CONV_ERROR)) { + F_SET(sp, SC_CONV_ERROR); + msgq(sp, M_ERR, "324|Conversion error on line %d", lno); + } + goto err3; + } + + /* Reset the cache. */ + if (wp != data.data) { + BINC_GOTOW(sp, ep->c_lp, ep->c_blen, wlen); + MEMCPY(ep->c_lp, wp, wlen); + } else + ep->c_lp = data.data; + ep->c_lno = lno; + ep->c_len = wlen; + +#if defined(DEBUG) && 0 + TRACE(sp, "retrieve DB line %lu\n", (u_long)lno); +#endif + if (lenp != NULL) + *lenp = wlen; + if (pp != NULL) + *pp = ep->c_lp; + return (0); +} + +/* + * db_delete -- + * Delete a line from the file. + * + * PUBLIC: int db_delete(SCR *, recno_t); + */ +int +db_delete(SCR *sp, recno_t lno) +{ + DBT key; + EXF *ep; + +#if defined(DEBUG) && 0 + TRACE(sp, "delete line %lu\n", (u_long)lno); +#endif + /* Check for no underlying file. */ + if ((ep = sp->ep) == NULL) { + ex_emsg(sp, NULL, EXM_NOFILEYET); + return (1); + } + + /* Update marks, @ and global commands. */ + if (mark_insdel(sp, LINE_DELETE, lno)) + return (1); + if (ex_g_insdel(sp, LINE_DELETE, lno)) + return (1); + + /* Log change. */ + log_line(sp, lno, LOG_LINE_DELETE); + + /* Update file. */ + key.data = &lno; + key.size = sizeof(lno); + if (ep->db->del(ep->db, &key, 0) == 1) { + msgq(sp, M_SYSERR, + "003|unable to delete line %lu", (u_long)lno); + return (1); + } + + /* Flush the cache, update line count, before screen update. */ + if (lno <= ep->c_lno) + ep->c_lno = OOBLNO; + if (ep->c_nlines != OOBLNO) + --ep->c_nlines; + + /* File now modified. */ + if (F_ISSET(ep, F_FIRSTMODIFY)) + (void)rcv_init(sp); + F_SET(ep, F_MODIFIED); + + /* Update screen. */ + return (scr_update(sp, lno, LINE_DELETE, 1)); +} + +/* + * db_append -- + * Append a line into the file. + * + * PUBLIC: int db_append(SCR *, int, recno_t, CHAR_T *, size_t); + */ +int +db_append(SCR *sp, int update, recno_t lno, CHAR_T *p, size_t len) +{ + DBT data, key; + EXF *ep; + char *fp; + size_t flen; + int rval; + +#if defined(DEBUG) && 0 + TRACE(sp, "append to %lu: len %u {%.*s}\n", lno, len, MIN(len, 20), p); +#endif + /* Check for no underlying file. */ + if ((ep = sp->ep) == NULL) { + ex_emsg(sp, NULL, EXM_NOFILEYET); + return (1); + } + + INT2FILE(sp, p, len, fp, flen); + + /* Update file. */ + key.data = &lno; + key.size = sizeof(lno); + data.data = fp; + data.size = flen; + if (ep->db->put(ep->db, &key, &data, R_IAFTER) == -1) { + msgq(sp, M_SYSERR, + "004|unable to append to line %lu", (u_long)lno); + return (1); + } + + /* Flush the cache, update line count, before screen update. */ + if (lno < ep->c_lno) + ep->c_lno = OOBLNO; + if (ep->c_nlines != OOBLNO) + ++ep->c_nlines; + + /* File now dirty. */ + if (F_ISSET(ep, F_FIRSTMODIFY)) + (void)rcv_init(sp); + F_SET(ep, F_MODIFIED); + + /* Log change. */ + log_line(sp, lno + 1, LOG_LINE_APPEND); + + /* Update marks, @ and global commands. */ + rval = 0; + if (mark_insdel(sp, LINE_INSERT, lno + 1)) + rval = 1; + if (ex_g_insdel(sp, LINE_INSERT, lno + 1)) + rval = 1; + + /* + * Update screen. + * + * XXX + * Nasty hack. If multiple lines are input by the user, they aren't + * committed until an is entered. The problem is the screen was + * updated/scrolled as each line was entered. So, when this routine + * is called to copy the new lines from the cut buffer into the file, + * it has to know not to update the screen again. + */ + return (scr_update(sp, lno, LINE_APPEND, update) || rval); +} + +/* + * db_insert -- + * Insert a line into the file. + * + * PUBLIC: int db_insert(SCR *, recno_t, CHAR_T *, size_t); + */ +int +db_insert(SCR *sp, recno_t lno, CHAR_T *p, size_t len) +{ + DBT data, key; + EXF *ep; + char *fp; + size_t flen; + int rval; + +#if defined(DEBUG) && 0 + TRACE(sp, "insert before %lu: len %lu {%.*s}\n", + (u_long)lno, (u_long)len, MIN(len, 20), p); +#endif + /* Check for no underlying file. */ + if ((ep = sp->ep) == NULL) { + ex_emsg(sp, NULL, EXM_NOFILEYET); + return (1); + } + + INT2FILE(sp, p, len, fp, flen); + + /* Update file. */ + key.data = &lno; + key.size = sizeof(lno); + data.data = fp; + data.size = flen; + if (ep->db->put(ep->db, &key, &data, R_IBEFORE) == -1) { + msgq(sp, M_SYSERR, + "005|unable to insert at line %lu", (u_long)lno); + return (1); + } + + /* Flush the cache, update line count, before screen update. */ + if (lno >= ep->c_lno) + ep->c_lno = OOBLNO; + if (ep->c_nlines != OOBLNO) + ++ep->c_nlines; + + /* File now dirty. */ + if (F_ISSET(ep, F_FIRSTMODIFY)) + (void)rcv_init(sp); + F_SET(ep, F_MODIFIED); + + /* Log change. */ + log_line(sp, lno, LOG_LINE_INSERT); + + /* Update marks, @ and global commands. */ + rval = 0; + if (mark_insdel(sp, LINE_INSERT, lno)) + rval = 1; + if (ex_g_insdel(sp, LINE_INSERT, lno)) + rval = 1; + + /* Update screen. */ + return (scr_update(sp, lno, LINE_INSERT, 1) || rval); +} + +/* + * db_set -- + * Store a line in the file. + * + * PUBLIC: int db_set(SCR *, recno_t, CHAR_T *, size_t); + */ +int +db_set(SCR *sp, recno_t lno, CHAR_T *p, size_t len) +{ + DBT data, key; + EXF *ep; + char *fp; + size_t flen; + +#if defined(DEBUG) && 0 + TRACE(sp, "replace line %lu: len %lu {%.*s}\n", + (u_long)lno, (u_long)len, MIN(len, 20), p); +#endif + /* Check for no underlying file. */ + if ((ep = sp->ep) == NULL) { + ex_emsg(sp, NULL, EXM_NOFILEYET); + return (1); + } + + /* Log before change. */ + log_line(sp, lno, LOG_LINE_RESET_B); + + INT2FILE(sp, p, len, fp, flen); + + /* Update file. */ + key.data = &lno; + key.size = sizeof(lno); + data.data = fp; + data.size = flen; + if (ep->db->put(ep->db, &key, &data, 0) == -1) { + msgq(sp, M_SYSERR, + "006|unable to store line %lu", (u_long)lno); + return (1); + } + + /* Flush the cache, before logging or screen update. */ + if (lno == ep->c_lno) + ep->c_lno = OOBLNO; + + /* File now dirty. */ + if (F_ISSET(ep, F_FIRSTMODIFY)) + (void)rcv_init(sp); + F_SET(ep, F_MODIFIED); + + /* Log after change. */ + log_line(sp, lno, LOG_LINE_RESET_F); + + /* Update screen. */ + return (scr_update(sp, lno, LINE_RESET, 1)); +} + +/* + * db_exist -- + * Return if a line exists. + * + * PUBLIC: int db_exist(SCR *, recno_t); + */ +int +db_exist(SCR *sp, recno_t lno) +{ + EXF *ep; + + /* Check for no underlying file. */ + if ((ep = sp->ep) == NULL) { + ex_emsg(sp, NULL, EXM_NOFILEYET); + return (1); + } + + if (lno == OOBLNO) + return (0); + + /* + * Check the last-line number cache. Adjust the cached line + * number for the lines used by the text input buffers. + */ + if (ep->c_nlines != OOBLNO) + return (lno <= (F_ISSET(sp, SC_TINPUT) ? + ep->c_nlines + (((TEXT *)TAILQ_LAST(sp->tiq, _texth))->lno - + ((TEXT *)TAILQ_FIRST(sp->tiq))->lno) : ep->c_nlines)); + + /* Go get the line. */ + return (!db_get(sp, lno, 0, NULL, NULL)); +} + +/* + * db_last -- + * Return the number of lines in the file. + * + * PUBLIC: int db_last(SCR *, recno_t *); + */ +int +db_last(SCR *sp, recno_t *lnop) +{ + DBT data, key; + EXF *ep; + recno_t lno; + CHAR_T *wp; + size_t wlen; + + /* Check for no underlying file. */ + if ((ep = sp->ep) == NULL) { + ex_emsg(sp, NULL, EXM_NOFILEYET); + return (1); + } + + /* + * Check the last-line number cache. Adjust the cached line + * number for the lines used by the text input buffers. + */ + if (ep->c_nlines != OOBLNO) { + *lnop = ep->c_nlines; + if (F_ISSET(sp, SC_TINPUT)) + *lnop += ((TEXT *)TAILQ_LAST(sp->tiq, _texth))->lno - + ((TEXT *)TAILQ_FIRST(sp->tiq))->lno; + return (0); + } + + key.data = &lno; + key.size = sizeof(lno); + + switch (ep->db->seq(ep->db, &key, &data, R_LAST)) { + case -1: +alloc_err: + msgq(sp, M_SYSERR, "007|unable to get last line"); + *lnop = 0; + return (1); + case 1: + *lnop = 0; + return (0); + } + + memcpy(&lno, key.data, sizeof(lno)); + + if (lno != ep->c_lno) { + FILE2INT(sp, data.data, data.size, wp, wlen); + + /* Fill the cache. */ + if (wp != data.data) { + BINC_GOTOW(sp, ep->c_lp, ep->c_blen, wlen); + MEMCPY(ep->c_lp, wp, wlen); + } else + ep->c_lp = data.data; + ep->c_lno = lno; + ep->c_len = wlen; + } + ep->c_nlines = lno; + + /* Return the value. */ + *lnop = (F_ISSET(sp, SC_TINPUT) && + ((TEXT *)TAILQ_LAST(sp->tiq, _texth))->lno > lno ? + ((TEXT *)TAILQ_LAST(sp->tiq, _texth))->lno : lno); + return (0); +} + +/* + * db_rget -- + * Retrieve a raw line from the database. + * + * PUBLIC: int db_rget(SCR *, recno_t, char **, size_t *); + */ +int +db_rget(SCR *sp, + recno_t lno, /* Line number. */ + char **pp, /* Pointer store. */ + size_t *lenp) /* Length store. */ +{ + DBT data, key; + EXF *ep = sp->ep; + int rval; + + /* Get the line from the underlying database. */ + key.data = &lno; + key.size = sizeof(lno); + if ((rval = ep->db->get(ep->db, &key, &data, 0)) == 0) + { + *lenp = data.size; + *pp = data.data; + } + + return (rval); +} + +/* + * db_rset -- + * Store a raw line into the database. + * + * PUBLIC: int db_rset(SCR *, recno_t, char *, size_t); + */ +int +db_rset(SCR *sp, recno_t lno, char *p, size_t len) +{ + DBT data, key; + EXF *ep = sp->ep; + + /* Update file. */ + key.data = &lno; + key.size = sizeof(lno); + data.data = p; + data.size = len; + return ep->db->put(ep->db, &key, &data, 0); +} + +/* + * db_err -- + * Report a line error. + * + * PUBLIC: void db_err(SCR *, recno_t); + */ +void +db_err(SCR *sp, recno_t lno) +{ + msgq(sp, M_ERR, + "008|Error: unable to retrieve line %lu", (u_long)lno); +} + +/* + * scr_update -- + * Update all of the screens that are backed by the file that + * just changed. + */ +static int +scr_update(SCR *sp, recno_t lno, lnop_t op, int current) +{ + EXF *ep; + SCR *tsp; + + if (F_ISSET(sp, SC_EX)) + return (0); + + ep = sp->ep; + if (ep->refcnt != 1) + TAILQ_FOREACH(tsp, sp->gp->dq, q) + if (sp != tsp && tsp->ep == ep) + if (vs_change(tsp, lno, op)) + return (1); + return (current ? vs_change(sp, lno, op) : 0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/common/line.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/common/log.h =================================================================== --- vendor/nvi/2.2.0-05ed8b9/common/log.h (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/common/log.h (revision 366308) @@ -0,0 +1,18 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#define LOG_NOTYPE 0 +#define LOG_CURSOR_INIT 1 +#define LOG_CURSOR_END 2 +#define LOG_LINE_APPEND 3 +#define LOG_LINE_DELETE 4 +#define LOG_LINE_INSERT 5 +#define LOG_LINE_RESET_F 6 +#define LOG_LINE_RESET_B 7 +#define LOG_MARK 8 Property changes on: vendor/nvi/2.2.0-05ed8b9/common/log.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/common/mark.h =================================================================== --- vendor/nvi/2.2.0-05ed8b9/common/mark.h (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/common/mark.h (revision 366308) @@ -0,0 +1,41 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +/* + * The MARK and LMARK structures define positions in the file. There are + * two structures because the mark subroutines are the only places where + * anything cares about something other than line and column. + * + * Because of the different interfaces used by the db(3) package, curses, + * and users, the line number is 1 based and the column number is 0 based. + * Additionally, it is known that the out-of-band line number is less than + * any legal line number. The line number is of type recno_t, as that's + * the underlying type of the database. The column number is of type size_t, + * guaranteeing that we can malloc a line. + */ +struct _mark { +#define OOBLNO 0 /* Out-of-band line number. */ + recno_t lno; /* Line number. */ + size_t cno; /* Column number. */ +}; + +struct _lmark { + SLIST_ENTRY(_lmark) q; /* Linked list of marks. */ + recno_t lno; /* Line number. */ + size_t cno; /* Column number. */ + /* XXXX Needed ? Can non ascii-chars be mark names ? */ + CHAR_T name; /* Mark name. */ + +#define MARK_DELETED 0x01 /* Mark was deleted. */ +#define MARK_USERSET 0x02 /* User set this mark. */ + u_int8_t flags; +}; + +#define ABSMARK1 '\'' /* Absolute mark name. */ +#define ABSMARK2 '`' /* Absolute mark name. */ Property changes on: vendor/nvi/2.2.0-05ed8b9/common/mark.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/common/msg.h =================================================================== --- vendor/nvi/2.2.0-05ed8b9/common/msg.h (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/common/msg.h (revision 366308) @@ -0,0 +1,63 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +/* + * Common messages (continuation or confirmation). + */ +typedef enum { + CMSG_CONF, CMSG_CONT, CMSG_CONT_EX, + CMSG_CONT_R, CMSG_CONT_S, CMSG_CONT_Q } cmsg_t; + +/* + * Message types. + * + * !!! + * In historical vi, O_VERBOSE didn't exist, and O_TERSE made the error + * messages shorter. In this implementation, O_TERSE has no effect and + * O_VERBOSE results in informational displays about common errors, for + * naive users. + * + * M_NONE Display to the user, no reformatting, no nothing. + * + * M_BERR Error: M_ERR if O_VERBOSE, else bell. + * M_ERR Error: Display in inverse video. + * M_INFO Info: Display in normal video. + * M_SYSERR Error: M_ERR, using strerror(3) message. + * M_VINFO Info: M_INFO if O_VERBOSE, else ignore. + * + * The underlying message display routines only need to know about M_NONE, + * M_ERR and M_INFO -- all the other message types are converted into one + * of them by the message routines. + */ +typedef enum { + M_NONE = 1, M_BERR, M_ERR, M_INFO, M_SYSERR, M_VINFO } mtype_t; + +/* + * There are major problems with error messages being generated by routines + * preparing the screen to display error messages. It's possible for the + * editor to generate messages before we have a screen in which to display + * them, or during the transition between ex (and vi startup) and a true vi. + * There's a queue in the global area to hold them. + * + * If SC_EX/SC_VI is set, that's the mode that the editor is in. If the flag + * S_SCREEN_READY is set, that means that the screen is prepared to display + * messages. + */ +typedef struct _msgh MSGH; /* MSGS list head structure. */ +SLIST_HEAD(_msgh, _msg); +struct _msg { + SLIST_ENTRY(_msg) q; /* Linked list of messages. */ + mtype_t mtype; /* Message type: M_NONE, M_ERR, M_INFO. */ + char *buf; /* Message buffer. */ + size_t len; /* Message length. */ +}; + +/* Flags to msgq_status(). */ +#define MSTAT_SHOWLAST 0x01 /* Show the line number of the last line. */ +#define MSTAT_TRUNCATE 0x02 /* Truncate the file name if it's too long. */ Property changes on: vendor/nvi/2.2.0-05ed8b9/common/msg.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/common/multibyte.h =================================================================== --- vendor/nvi/2.2.0-05ed8b9/common/multibyte.h (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/common/multibyte.h (revision 366308) @@ -0,0 +1,147 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#ifndef MULTIBYTE_H +#define MULTIBYTE_H + +/* + * Fundamental character types. + * + * CHAR_T An integral type that can hold any character. + * ARG_CHAR_T The type of a CHAR_T when passed as an argument using + * traditional promotion rules. It should also be able + * to be compared against any CHAR_T for equality without + * problems. + * UCHAR_T The shortest unified character type (8-bit clean). + * RCHAR_T The character type used by the internal regex engine. + * + * If no integral type can hold a character, don't even try the port. + */ +typedef int ARG_CHAR_T; + +#ifdef USE_WIDECHAR +#include +#include + +typedef wchar_t CHAR_T; +typedef wint_t UCHAR_T; +typedef wchar_t RCHAR_T; +#define REOF WEOF + +#define STRLEN wcslen +#define STRTOL wcstol +#define STRTOUL wcstoul +#define SPRINTF swprintf +#define STRCMP wcscmp +#define STRPBRK wcspbrk +#define ISBLANK iswblank +#define ISCNTRL iswcntrl +#define ISDIGIT iswdigit +#define ISXDIGIT iswxdigit +#define ISGRAPH iswgraph +#define ISLOWER iswlower +#define ISPRINT iswprint +#define ISPUNCT iswpunct +#define ISSPACE iswspace +#define ISUPPER iswupper +#define TOLOWER towlower +#define TOUPPER towupper +#define STRSET wmemset +#define STRCHR wcschr +#define STRRCHR wcsrchr +#define GETC getwc + +#define L(ch) L ## ch +#define WS "%ls" +#define WVS "%*ls" +#define WC "%lc" + +#else +typedef u_char CHAR_T; +typedef u_char UCHAR_T; +typedef char RCHAR_T; +#define REOF EOF + +#define STRLEN strlen +#define STRTOL(a,b,c) (strtol(a,(char**)b,c)) +#define STRTOUL(a,b,c) (strtoul(a,(char**)b,c)) +#define SPRINTF snprintf +#define STRCMP strcmp +#define STRPBRK strpbrk +#define ISBLANK isblank +#define ISCNTRL iscntrl +#define ISDIGIT isdigit +#define ISXDIGIT isxdigit +#define ISGRAPH isgraph +#define ISLOWER islower +#define ISPRINT isprint +#define ISPUNCT ispunct +#define ISSPACE isspace +#define ISUPPER isupper +#define TOLOWER tolower +#define TOUPPER toupper +#define STRSET memset +#define STRCHR strchr +#define STRRCHR strrchr +#define GETC getc + +#define L(ch) ch +#define WS "%s" +#define WVS "%*s" +#define WC "%c" + +#endif + +#if defined(USE_WIDECHAR) && defined(DEBUG) +#define MEMCPY wmemcpy +#define MEMMOVE wmemmove +#define MEMCMP wmemcmp +#else +#define MEMCPY(p, t, len) memcpy(p, t, (len) * sizeof(CHAR_T)) +#define MEMMOVE(p, t, len) memmove(p, t, (len) * sizeof(CHAR_T)) +#define MEMCMP(p, t, len) memcmp(p, t, (len) * sizeof(CHAR_T)) +#endif + +#define SIZE(w) (sizeof(w) / sizeof(*w)) + +/* + * Locale insensitive character category detection. + */ + +static __inline int +isatoz(CHAR_T c) +{ + return 'a' <= c && c <= 'z'; +} + +static __inline int +isAtoZ(CHAR_T c) +{ + return 'A' <= c && c <= 'Z'; +} + +static __inline int +is0to9(CHAR_T c) +{ + return '0' <= c && c <= '9'; +} + +static __inline int +isazAZ(CHAR_T c) +{ + return isatoz(c) || isAtoZ(c); +} + +static __inline int +is09azAZ(CHAR_T c) +{ + return is0to9(c) || isazAZ(c); +} + +#endif Property changes on: vendor/nvi/2.2.0-05ed8b9/common/multibyte.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/common/options.h =================================================================== --- vendor/nvi/2.2.0-05ed8b9/common/options.h (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/common/options.h (revision 366308) @@ -0,0 +1,100 @@ +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1991, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +/* + * Edit option information. Historically, if you set a boolean or numeric + * edit option value to its "default" value, it didn't show up in the :set + * display, i.e. it wasn't considered "changed". String edit options would + * show up as changed, regardless. We maintain a parallel set of values + * which are the default values and never consider an edit option changed + * if it was reset to the default value. + * + * Macros to retrieve boolean, integral and string option values, and to + * set, clear and test boolean option values. Some options (secure, lines, + * columns, terminal type) are global in scope, and are therefore stored + * in the global area. The offset in the global options array is stored + * in the screen's value field. This is set up when the options are first + * initialized. + */ +#define O_V(sp, o, fld) \ + (F_ISSET(&(sp)->opts[(o)], OPT_GLOBAL) ? \ + (sp)->gp->opts[(sp)->opts[(o)].o_cur.val].fld : \ + (sp)->opts[(o)].fld) + +/* Global option macros. */ +#define OG_CLR(gp, o) ((gp)->opts[(o)].o_cur.val) = 0 +#define OG_SET(gp, o) ((gp)->opts[(o)].o_cur.val) = 1 +#define OG_STR(gp, o) ((gp)->opts[(o)].o_cur.str) +#define OG_VAL(gp, o) ((gp)->opts[(o)].o_cur.val) +#define OG_ISSET(gp, o) OG_VAL(gp, o) + +#define OG_D_STR(gp, o) ((gp)->opts[(o)].o_def.str) +#define OG_D_VAL(gp, o) ((gp)->opts[(o)].o_def.val) + +/* + * Flags to o_set(); need explicit OS_STR as can be setting the value to + * NULL. + */ +#define OS_DEF 0x01 /* Set the default value. */ +#define OS_NOFREE 0x02 /* Don't free the old string. */ +#define OS_STR 0x04 /* Set to string argument. */ +#define OS_STRDUP 0x08 /* Copy then set to string argument. */ + +struct _option { + union { + u_long val; /* Value or boolean. */ + char *str; /* String. */ + } o_cur; +#define O_CLR(sp, o) o_set(sp, o, 0, NULL, 0) +#define O_SET(sp, o) o_set(sp, o, 0, NULL, 1) +#define O_STR(sp, o) O_V(sp, o, o_cur.str) +#define O_VAL(sp, o) O_V(sp, o, o_cur.val) +#define O_ISSET(sp, o) O_VAL(sp, o) + + union { + u_long val; /* Value or boolean. */ + char *str; /* String. */ + } o_def; +#define O_D_CLR(sp, o) o_set(sp, o, OS_DEF, NULL, 0) +#define O_D_SET(sp, o) o_set(sp, o, OS_DEF, NULL, 1) +#define O_D_STR(sp, o) O_V(sp, o, o_def.str) +#define O_D_VAL(sp, o) O_V(sp, o, o_def.val) +#define O_D_ISSET(sp, o) O_D_VAL(sp, o) + +#define OPT_GLOBAL 0x01 /* Option is global. */ +#define OPT_SELECTED 0x02 /* Selected for display. */ + u_int8_t flags; +}; + +/* List of option names, associated update functions and information. */ +struct _optlist { + CHAR_T *name; /* Name. */ + /* Change function. */ + int (*func)(SCR *, OPTION *, char *, u_long *); + /* Type of object. */ + enum { OPT_0BOOL, OPT_1BOOL, OPT_NUM, OPT_STR } type; + +#define OPT_ADISP 0x001 /* Always display the option. */ +#define OPT_ALWAYS 0x002 /* Always call the support function. */ +#define OPT_NDISP 0x004 /* Never display the option. */ +#define OPT_NOSAVE 0x008 /* Mkexrc command doesn't save. */ +#define OPT_NOSET 0x010 /* Option may not be set. */ +#define OPT_NOUNSET 0x020 /* Option may not be unset. */ +#define OPT_NOZERO 0x040 /* Option may not be set to 0. */ +#define OPT_PAIRS 0x080 /* String with even length. */ + u_int8_t flags; +}; + +/* Option argument to opts_dump(). */ +enum optdisp { NO_DISPLAY, ALL_DISPLAY, CHANGED_DISPLAY, SELECT_DISPLAY }; + +/* Options array. */ +extern OPTLIST const optlist[]; + +#include "options_def.h" Property changes on: vendor/nvi/2.2.0-05ed8b9/common/options.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/common/options_f.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/common/options_f.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/common/options_f.c (revision 366308) @@ -0,0 +1,293 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" + +/* + * PUBLIC: int f_altwerase(SCR *, OPTION *, char *, u_long *); + */ +int +f_altwerase(SCR *sp, OPTION *op, char *str, u_long *valp) +{ + if (*valp) + O_CLR(sp, O_TTYWERASE); + return (0); +} + +/* + * PUBLIC: int f_columns(SCR *, OPTION *, char *, u_long *); + */ +int +f_columns(SCR *sp, OPTION *op, char *str, u_long *valp) +{ + /* Validate the number. */ + if (*valp < MINIMUM_SCREEN_COLS) { + msgq(sp, M_ERR, "040|Screen columns too small, less than %d", + MINIMUM_SCREEN_COLS); + return (1); + } + + /* + * !!! + * It's not uncommon for allocation of huge chunks of memory to cause + * core dumps on various systems. So, we prune out numbers that are + * "obviously" wrong. Vi will not work correctly if it has the wrong + * number of lines/columns for the screen, but at least we don't drop + * core. + */ +#define MAXIMUM_SCREEN_COLS 500 + if (*valp > MAXIMUM_SCREEN_COLS) { + msgq(sp, M_ERR, "041|Screen columns too large, greater than %d", + MAXIMUM_SCREEN_COLS); + return (1); + } + return (0); +} + +/* + * PUBLIC: int f_lines(SCR *, OPTION *, char *, u_long *); + */ +int +f_lines(SCR *sp, OPTION *op, char *str, u_long *valp) +{ + /* Validate the number. */ + if (*valp < MINIMUM_SCREEN_ROWS) { + msgq(sp, M_ERR, "042|Screen lines too small, less than %d", + MINIMUM_SCREEN_ROWS); + return (1); + } + + /* + * !!! + * It's not uncommon for allocation of huge chunks of memory to cause + * core dumps on various systems. So, we prune out numbers that are + * "obviously" wrong. Vi will not work correctly if it has the wrong + * number of lines/columns for the screen, but at least we don't drop + * core. + */ +#define MAXIMUM_SCREEN_ROWS 500 + if (*valp > MAXIMUM_SCREEN_ROWS) { + msgq(sp, M_ERR, "043|Screen lines too large, greater than %d", + MAXIMUM_SCREEN_ROWS); + return (1); + } + + /* + * Set the value, and the related scroll value. If no window + * value set, set a new default window. + */ + o_set(sp, O_LINES, 0, NULL, *valp); + if (*valp == 1) { + sp->defscroll = 1; + + if (O_VAL(sp, O_WINDOW) == O_D_VAL(sp, O_WINDOW) || + O_VAL(sp, O_WINDOW) > *valp) { + o_set(sp, O_WINDOW, 0, NULL, 1); + o_set(sp, O_WINDOW, OS_DEF, NULL, 1); + } + } else { + sp->defscroll = (*valp - 1) / 2; + + if (O_VAL(sp, O_WINDOW) == O_D_VAL(sp, O_WINDOW) || + O_VAL(sp, O_WINDOW) > *valp) { + o_set(sp, O_WINDOW, 0, NULL, *valp - 1); + o_set(sp, O_WINDOW, OS_DEF, NULL, *valp - 1); + } + } + return (0); +} + +/* + * PUBLIC: int f_lisp(SCR *, OPTION *, char *, u_long *); + */ +int +f_lisp(SCR *sp, OPTION *op, char *str, u_long *valp) +{ + msgq(sp, M_ERR, "044|The lisp option is not implemented"); + return (0); +} + +/* + * PUBLIC: int f_msgcat(SCR *, OPTION *, char *, u_long *); + */ +int +f_msgcat(SCR *sp, OPTION *op, char *str, u_long *valp) +{ + (void)msg_open(sp, str); + return (0); +} + +/* + * PUBLIC: int f_print(SCR *, OPTION *, char *, u_long *); + */ +int +f_print(SCR *sp, OPTION *op, char *str, u_long *valp) +{ + int offset = op - sp->opts; + + /* Preset the value, needed for reinitialization of lookup table. */ + if (offset == O_OCTAL) { + if (*valp) + O_SET(sp, offset); + else + O_CLR(sp, offset); + } else if (o_set(sp, offset, OS_STRDUP, str, 0)) + return(1); + + /* Reinitialize the key fast lookup table. */ + v_key_ilookup(sp); + + /* Reformat the screen. */ + F_SET(sp, SC_SCR_REFORMAT); + return (0); +} + +/* + * PUBLIC: int f_readonly(SCR *, OPTION *, char *, u_long *); + */ +int +f_readonly(SCR *sp, OPTION *op, char *str, u_long *valp) +{ + /* + * !!! + * See the comment in exf.c. + */ + if (*valp) + F_SET(sp, SC_READONLY); + else + F_CLR(sp, SC_READONLY); + return (0); +} + +/* + * PUBLIC: int f_recompile(SCR *, OPTION *, char *, u_long *); + */ +int +f_recompile(SCR *sp, OPTION *op, char *str, u_long *valp) +{ + if (F_ISSET(sp, SC_RE_SEARCH)) { + regfree(&sp->re_c); + F_CLR(sp, SC_RE_SEARCH); + } + if (F_ISSET(sp, SC_RE_SUBST)) { + regfree(&sp->subre_c); + F_CLR(sp, SC_RE_SUBST); + } + return (0); +} + +/* + * PUBLIC: int f_reformat(SCR *, OPTION *, char *, u_long *); + */ +int +f_reformat(SCR *sp, OPTION *op, char *str, u_long *valp) +{ + F_SET(sp, SC_SCR_REFORMAT); + return (0); +} + +/* + * PUBLIC: int f_ttywerase(SCR *, OPTION *, char *, u_long *); + */ +int +f_ttywerase(SCR *sp, OPTION *op, char *str, u_long *valp) +{ + if (*valp) + O_CLR(sp, O_ALTWERASE); + return (0); +} + +/* + * PUBLIC: int f_w300(SCR *, OPTION *, char *, u_long *); + */ +int +f_w300(SCR *sp, OPTION *op, char *str, u_long *valp) +{ + u_long v; + + /* Historical behavior for w300 was < 1200. */ + if (sp->gp->scr_baud(sp, &v)) + return (1); + if (v >= 1200) + return (0); + + return (f_window(sp, op, str, valp)); +} + +/* + * PUBLIC: int f_w1200(SCR *, OPTION *, char *, u_long *); + */ +int +f_w1200(SCR *sp, OPTION *op, char *str, u_long *valp) +{ + u_long v; + + /* Historical behavior for w1200 was == 1200. */ + if (sp->gp->scr_baud(sp, &v)) + return (1); + if (v < 1200 || v > 4800) + return (0); + + return (f_window(sp, op, str, valp)); +} + +/* + * PUBLIC: int f_w9600(SCR *, OPTION *, char *, u_long *); + */ +int +f_w9600(SCR *sp, OPTION *op, char *str, u_long *valp) +{ + u_long v; + + /* Historical behavior for w9600 was > 1200. */ + if (sp->gp->scr_baud(sp, &v)) + return (1); + if (v <= 4800) + return (0); + + return (f_window(sp, op, str, valp)); +} + +/* + * PUBLIC: int f_window(SCR *, OPTION *, char *, u_long *); + */ +int +f_window(SCR *sp, OPTION *op, char *str, u_long *valp) +{ + if (*valp >= O_VAL(sp, O_LINES) - 1 && + (*valp = O_VAL(sp, O_LINES) - 1) == 0) + *valp = 1; + return (0); +} + +/* + * PUBLIC: int f_encoding(SCR *, OPTION *, char *, u_long *); + */ +int +f_encoding(SCR *sp, OPTION *op, char *str, u_long *valp) +{ + int offset = op - sp->opts; + + return conv_enc(sp, offset, str); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/common/options_f.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/common/screen.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/common/screen.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/common/screen.c (revision 366308) @@ -0,0 +1,220 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "../vi/vi.h" + +/* + * screen_init -- + * Do the default initialization of an SCR structure. + * + * PUBLIC: int screen_init(GS *, SCR *, SCR **); + */ +int +screen_init(GS *gp, SCR *orig, SCR **spp) +{ + SCR *sp; + size_t len; + + *spp = NULL; + CALLOC_RET(orig, sp, 1, sizeof(SCR)); + *spp = sp; + +/* INITIALIZED AT SCREEN CREATE. */ + sp->id = ++gp->id; + sp->refcnt = 1; + + sp->gp = gp; /* All ref the GS structure. */ + + sp->ccnt = 2; /* Anything > 1 */ + + /* + * XXX + * sp->defscroll is initialized by the opts_init() code because + * we don't have the option information yet. + */ + + TAILQ_INIT(sp->tiq); + +/* PARTIALLY OR COMPLETELY COPIED FROM PREVIOUS SCREEN. */ + if (orig == NULL) { + sp->searchdir = NOTSET; + } else { + /* Alternate file name. */ + if (orig->alt_name != NULL && + (sp->alt_name = strdup(orig->alt_name)) == NULL) + goto mem; + + /* Last executed at buffer. */ + if (F_ISSET(orig, SC_AT_SET)) { + F_SET(sp, SC_AT_SET); + sp->at_lbuf = orig->at_lbuf; + } + + /* Retain searching/substitution information. */ + sp->searchdir = orig->searchdir == NOTSET ? NOTSET : FORWARD; + if (orig->re != NULL && (sp->re = + v_wstrdup(sp, orig->re, orig->re_len)) == NULL) + goto mem; + sp->re_len = orig->re_len; + if (orig->subre != NULL && (sp->subre = + v_wstrdup(sp, orig->subre, orig->subre_len)) == NULL) + goto mem; + sp->subre_len = orig->subre_len; + if (orig->repl != NULL && (sp->repl = + v_wstrdup(sp, orig->repl, orig->repl_len)) == NULL) + goto mem; + sp->repl_len = orig->repl_len; + if (orig->newl_len) { + len = orig->newl_len * sizeof(size_t); + MALLOC(sp, sp->newl, len); + if (sp->newl == NULL) { +mem: msgq(orig, M_SYSERR, NULL); + goto err; + } + sp->newl_len = orig->newl_len; + sp->newl_cnt = orig->newl_cnt; + memcpy(sp->newl, orig->newl, len); + } + + if (opts_copy(orig, sp)) + goto err; + + F_SET(sp, F_ISSET(orig, SC_EX | SC_VI)); + } + + if (ex_screen_copy(orig, sp)) /* Ex. */ + goto err; + if (v_screen_copy(orig, sp)) /* Vi. */ + goto err; + sp->cl_private = 0; /* XXX */ + conv_init(orig, sp); /* XXX */ + + *spp = sp; + return (0); + +err: screen_end(sp); + return (1); +} + +/* + * screen_end -- + * Release a screen, no matter what had (and had not) been + * initialized. + * + * PUBLIC: int screen_end(SCR *); + */ +int +screen_end(SCR *sp) +{ + int rval; + + /* If multiply referenced, just decrement the count and return. */ + if (--sp->refcnt != 0) + return (0); + + /* + * Remove the screen from the displayed queue. + * + * If a created screen failed during initialization, it may not + * be linked into the chain. + */ + if (TAILQ_ENTRY_ISVALID(sp, q)) + TAILQ_REMOVE(sp->gp->dq, sp, q); + + /* The screen is no longer real. */ + F_CLR(sp, SC_SCR_EX | SC_SCR_VI); + + rval = 0; + if (v_screen_end(sp)) /* End vi. */ + rval = 1; + if (ex_screen_end(sp)) /* End ex. */ + rval = 1; + + /* Free file names. */ + { char **ap; + if (!F_ISSET(sp, SC_ARGNOFREE) && sp->argv != NULL) { + for (ap = sp->argv; *ap != NULL; ++ap) + free(*ap); + free(sp->argv); + } + } + + /* Free any text input. */ + if (!TAILQ_EMPTY(sp->tiq)) + text_lfree(sp->tiq); + + /* Free alternate file name. */ + free(sp->alt_name); + + /* Free up search information. */ + free(sp->re); + if (F_ISSET(sp, SC_RE_SEARCH)) + regfree(&sp->re_c); + free(sp->subre); + if (F_ISSET(sp, SC_RE_SUBST)) + regfree(&sp->subre_c); + free(sp->repl); + free(sp->newl); + + /* Free the iconv environment */ + conv_end(sp); + + /* Free all the options */ + opts_free(sp); + + /* Free the screen itself. */ + free(sp); + + return (rval); +} + +/* + * screen_next -- + * Return the next screen in the queue. + * + * PUBLIC: SCR *screen_next(SCR *); + */ +SCR * +screen_next(SCR *sp) +{ + GS *gp; + SCR *next; + + /* Try the display queue, without returning the current screen. */ + gp = sp->gp; + TAILQ_FOREACH(next, gp->dq, q) + if (next != sp) + break; + if (next != NULL) + return (next); + + /* Try the hidden queue; if found, move screen to the display queue. */ + if (!TAILQ_EMPTY(gp->hq)) { + next = TAILQ_FIRST(gp->hq); + TAILQ_REMOVE(gp->hq, next, q); + TAILQ_INSERT_HEAD(gp->dq, next, q); + return (next); + } + return (NULL); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/common/screen.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/common/screen.h =================================================================== --- vendor/nvi/2.2.0-05ed8b9/common/screen.h (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/common/screen.h (revision 366308) @@ -0,0 +1,209 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +/* + * There are minimum values that vi has to have to display a screen. The row + * minimum is fixed at 1 (the svi code can share a line between the text line + * and the colon command/message line). Column calculation is a lot trickier. + * For example, you have to have enough columns to display the line number, + * not to mention guaranteeing that tabstop and shiftwidth values are smaller + * than the current column value. It's simpler to have a fixed value and not + * worry about it. + * + * XXX + * MINIMUM_SCREEN_COLS is almost certainly wrong. + */ +#define MINIMUM_SCREEN_ROWS 1 +#define MINIMUM_SCREEN_COLS 20 + +/* + * SCR -- + * The screen structure. To the extent possible, all screen information + * is stored in the various private areas. The only information here + * is used by global routines or is shared by too many screens. + */ +struct _scr { +/* INITIALIZED AT SCREEN CREATE. */ + TAILQ_ENTRY(_scr) q; /* Screens. */ + + int id; /* Screen id #. */ + int refcnt; /* Reference count. */ + + GS *gp; /* Pointer to global area. */ + SCR *nextdisp; /* Next display screen. */ + SCR *ccl_parent; /* Colon command-line parent screen. */ + EXF *ep; /* Screen's current EXF structure. */ + + FREF *frp; /* FREF being edited. */ + char **argv; /* NULL terminated file name array. */ + char **cargv; /* Current file name. */ + + u_long ccnt; /* Command count. */ + u_long q_ccnt; /* Quit or ZZ command count. */ + + /* Screen's: */ + size_t rows; /* 1-N: number of rows. */ + size_t cols; /* 1-N: number of columns. */ + size_t t_rows; /* 1-N: cur number of text rows. */ + size_t t_maxrows; /* 1-N: max number of text rows. */ + size_t t_minrows; /* 1-N: min number of text rows. */ + size_t coff; /* 0-N: screen col offset in display. */ + size_t roff; /* 0-N: screen row offset in display. */ + + /* Cursor's: */ + recno_t lno; /* 1-N: file line. */ + size_t cno; /* 0-N: file character in line. */ + + size_t rcm; /* Vi: 0-N: Most attractive column. */ + +#define L_ADDED 0 /* Added lines. */ +#define L_CHANGED 1 /* Changed lines. */ +#define L_DELETED 2 /* Deleted lines. */ +#define L_JOINED 3 /* Joined lines. */ +#define L_MOVED 4 /* Moved lines. */ +#define L_SHIFT 5 /* Shift lines. */ +#define L_YANKED 6 /* Yanked lines. */ + recno_t rptlchange; /* Ex/vi: last L_CHANGED lno. */ + recno_t rptlines[L_YANKED + 1];/* Ex/vi: lines changed by last op. */ + + TEXTH tiq[1]; /* Ex/vi: text input queue. */ + + SCRIPT *script; /* Vi: script mode information .*/ + + recno_t defscroll; /* Vi: ^D, ^U scroll information. */ + + /* Display character. */ + char cname[MAX_CHARACTER_COLUMNS + 1]; + size_t clen; /* Length of display character. */ + ARG_CHAR_T lastc; /* The last display character. */ + + enum { /* Vi editor mode. */ + SM_APPEND = 0, SM_CHANGE, SM_COMMAND, SM_INSERT, + SM_REPLACE } showmode; + + void *ex_private; /* Ex private area. */ + void *vi_private; /* Vi private area. */ + void *cl_private; /* Curses private area. */ + + CONV conv; /* Conversion functions. */ + CONVWIN cw; /* Conversion buffer. */ + +/* PARTIALLY OR COMPLETELY COPIED FROM PREVIOUS SCREEN. */ + char *alt_name; /* Ex/vi: alternate file name. */ + + CHAR_T at_lbuf; /* Ex/vi: Last executed at buffer. */ + + /* Ex/vi: re_compile flags. */ +#define RE_C_CSCOPE 0x0001 /* Compile cscope pattern. */ +#define RE_C_SEARCH 0x0002 /* Compile search replacement. */ +#define RE_C_SILENT 0x0004 /* No error messages. */ +#define RE_C_SUBST 0x0008 /* Compile substitute replacement. */ +#define RE_C_TAG 0x0010 /* Compile ctag pattern. */ + +#define RE_WSTART L("[[:<:]]") /* Ex/vi: not-in-word search pattern. */ +#define RE_WSTOP L("[[:>:]]") +#define RE_WSTART_LEN (SIZE(RE_WSTART) - 1) +#define RE_WSTOP_LEN (SIZE(RE_WSTOP) - 1) + /* Ex/vi: flags to search routines. */ +#define SEARCH_CSCOPE 0x0001 /* Search for a cscope pattern. */ +#define SEARCH_EOL 0x0002 /* Offset past EOL is okay. */ +#define SEARCH_FILE 0x0004 /* Search the entire file. */ +#define SEARCH_INCR 0x0008 /* Search incrementally. */ +#define SEARCH_MSG 0x0010 /* Display search messages. */ +#define SEARCH_PARSE 0x0020 /* Parse the search pattern. */ +#define SEARCH_SET 0x0040 /* Set search direction. */ +#define SEARCH_TAG 0x0080 /* Search for a tag pattern. */ +#define SEARCH_WMSG 0x0100 /* Display search-wrapped messages. */ + + /* Ex/vi: RE information. */ + dir_t searchdir; /* Last file search direction. */ + regex_t re_c; /* Search RE: compiled form. */ + CHAR_T *re; /* Search RE: uncompiled form. */ + size_t re_len; /* Search RE: uncompiled length. */ + regex_t subre_c; /* Substitute RE: compiled form. */ + CHAR_T *subre; /* Substitute RE: uncompiled form. */ + size_t subre_len; /* Substitute RE: uncompiled length). */ + CHAR_T *repl; /* Substitute replacement. */ + size_t repl_len; /* Substitute replacement length.*/ + size_t *newl; /* Newline offset array. */ + size_t newl_len; /* Newline array size. */ + size_t newl_cnt; /* Newlines in replacement. */ + u_int8_t c_suffix; /* Edcompatible 'c' suffix value. */ + u_int8_t g_suffix; /* Edcompatible 'g' suffix value. */ + + OPTION opts[O_OPTIONCOUNT]; /* Ex/vi: Options. */ + +/* + * Screen flags. + * + * Editor screens. + */ +#define SC_EX 0x00000001 /* Ex editor. */ +#define SC_VI 0x00000002 /* Vi editor. */ + +/* + * Screen formatting flags, first major, then minor. + * + * SC_SCR_EX + * Ex screen, i.e. cooked mode. + * SC_SCR_VI + * Vi screen, i.e. raw mode. + * SC_SCR_EXWROTE + * The editor had to write on the screen behind curses' back, and we can't + * let curses change anything until the user agrees, e.g. entering the + * commands :!utility followed by :set. We have to switch back into the + * vi "editor" to read the user's command input, but we can't touch the + * rest of the screen because it's known to be wrong. + * SC_SCR_REFORMAT + * The expected presentation of the lines on the screen have changed, + * requiring that the intended screen lines be recalculated. Implies + * SC_SCR_REDRAW. + * SC_SCR_REDRAW + * The screen doesn't correctly represent the file; repaint it. Note, + * setting SC_SCR_REDRAW in the current window causes *all* windows to + * be repainted. + * SC_SCR_CENTER + * If the current line isn't already on the screen, center it. + * SC_SCR_TOP + * If the current line isn't already on the screen, put it at the to@. + */ +#define SC_SCR_EX 0x00000004 /* Screen is in ex mode. */ +#define SC_SCR_VI 0x00000008 /* Screen is in vi mode. */ +#define SC_SCR_EXWROTE 0x00000010 /* Ex overwrite: see comment above. */ +#define SC_SCR_REFORMAT 0x00000020 /* Reformat (refresh). */ +#define SC_SCR_REDRAW 0x00000040 /* Refresh. */ + +#define SC_SCR_CENTER 0x00000080 /* Center the line if not visible. */ +#define SC_SCR_TOP 0x00000100 /* Top the line if not visible. */ + +/* Screen/file changes. */ +#define SC_EXIT 0x00000200 /* Exiting (not forced). */ +#define SC_EXIT_FORCE 0x00000400 /* Exiting (forced). */ +#define SC_FSWITCH 0x00000800 /* Switch underlying files. */ +#define SC_SSWITCH 0x00001000 /* Switch screens. */ + +#define SC_ARGNOFREE 0x00002000 /* Argument list wasn't allocated. */ +#define SC_ARGRECOVER 0x00004000 /* Argument list is recovery files. */ +#define SC_AT_SET 0x00008000 /* Last at buffer set. */ +#define SC_COMEDIT 0x00010000 /* Colon command-line edit window. */ +#define SC_EX_GLOBAL 0x00020000 /* Ex: executing a global command. */ +#define SC_EX_SILENT 0x00040000 /* Ex: batch script. */ +#define SC_EX_WAIT_NO 0x00080000 /* Ex: don't wait for the user. */ +#define SC_EX_WAIT_YES 0x00100000 /* Ex: do wait for the user. */ +#define SC_READONLY 0x00200000 /* Persistent readonly state. */ +#define SC_RE_SEARCH 0x00400000 /* Search RE has been compiled. */ +#define SC_RE_SUBST 0x00800000 /* Substitute RE has been compiled. */ +#define SC_SCRIPT 0x01000000 /* Shell script window. */ +#define SC_STATUS 0x02000000 /* Welcome message. */ +#define SC_STATUS_CNT 0x04000000 /* Welcome message plus file count. */ +#define SC_TINPUT 0x08000000 /* Doing text input. */ +#define SC_TINPUT_INFO 0x10000000 /* Doing text input on info line. */ +#define SC_CONV_ERROR 0x20000000 /* Met with a conversion error. */ + u_int32_t flags; +}; Property changes on: vendor/nvi/2.2.0-05ed8b9/common/screen.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/common/search.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/common/search.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/common/search.c (revision 366308) @@ -0,0 +1,474 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" + +typedef enum { S_EMPTY, S_EOF, S_NOPREV, S_NOTFOUND, S_SOF, S_WRAP } smsg_t; + +static void search_msg(SCR *, smsg_t); +static int search_init(SCR *, dir_t, CHAR_T *, size_t, CHAR_T **, u_int); + +/* + * search_init -- + * Set up a search. + */ +static int +search_init(SCR *sp, dir_t dir, CHAR_T *ptrn, size_t plen, CHAR_T **epp, + u_int flags) +{ + recno_t lno; + int delim; + CHAR_T *p, *t; + + /* If the file is empty, it's a fast search. */ + if (sp->lno <= 1) { + if (db_last(sp, &lno)) + return (1); + if (lno == 0) { + if (LF_ISSET(SEARCH_MSG)) + search_msg(sp, S_EMPTY); + return (1); + } + } + + if (LF_ISSET(SEARCH_PARSE)) { /* Parse the string. */ + /* + * Use the saved pattern if no pattern specified, or if only + * one or two delimiter characters specified. + * + * !!! + * Historically, only the pattern itself was saved, vi didn't + * preserve addressing or delta information. + */ + if (ptrn == NULL) + goto prev; + if (plen == 1) { + if (epp != NULL) + *epp = ptrn + 1; + goto prev; + } + if (ptrn[0] == ptrn[1]) { + if (epp != NULL) + *epp = ptrn + 2; + + /* Complain if we don't have a previous pattern. */ +prev: if (sp->re == NULL) { + search_msg(sp, S_NOPREV); + return (1); + } + /* Re-compile the search pattern if necessary. */ + if (!F_ISSET(sp, SC_RE_SEARCH) && re_compile(sp, + sp->re, sp->re_len, NULL, NULL, &sp->re_c, + RE_C_SEARCH | + (LF_ISSET(SEARCH_MSG) ? 0 : RE_C_SILENT))) + return (1); + + /* Set the search direction. */ + if (LF_ISSET(SEARCH_SET)) + sp->searchdir = dir; + return (0); + } + + /* + * Set the delimiter, and move forward to the terminating + * delimiter, handling escaped delimiters. + * + * QUOTING NOTE: + * Only discard an escape character if it escapes a delimiter. + */ + for (delim = *ptrn, p = t = ++ptrn;; *t++ = *p++) { + if (--plen == 0 || p[0] == delim) { + if (plen != 0) + ++p; + break; + } + if (plen > 1 && p[0] == '\\' && p[1] == delim) { + ++p; + --plen; + } + } + if (epp != NULL) + *epp = p; + + plen = t - ptrn; + } + + /* Compile the RE. */ + if (re_compile(sp, ptrn, plen, &sp->re, &sp->re_len, &sp->re_c, + RE_C_SEARCH | + (LF_ISSET(SEARCH_MSG) ? 0 : RE_C_SILENT) | + (LF_ISSET(SEARCH_TAG) ? RE_C_TAG : 0) | + (LF_ISSET(SEARCH_CSCOPE) ? RE_C_CSCOPE : 0))) + return (1); + + /* Set the search direction. */ + if (LF_ISSET(SEARCH_SET)) + sp->searchdir = dir; + + return (0); +} + +/* + * f_search -- + * Do a forward search. + * + * PUBLIC: int f_search(SCR *, + * PUBLIC: MARK *, MARK *, CHAR_T *, size_t, CHAR_T **, u_int); + */ +int +f_search(SCR *sp, MARK *fm, MARK *rm, CHAR_T *ptrn, size_t plen, + CHAR_T **eptrn, u_int flags) +{ + busy_t btype; + recno_t lno; + regmatch_t match[1]; + size_t coff, len; + int cnt, eval, rval, wrapped = 0; + CHAR_T *l; + + if (search_init(sp, FORWARD, ptrn, plen, eptrn, flags)) + return (1); + + if (LF_ISSET(SEARCH_FILE)) { + lno = 1; + coff = 0; + } else { + if (db_get(sp, fm->lno, DBG_FATAL, &l, &len)) + return (1); + lno = fm->lno; + + /* + * If doing incremental search, start searching at the previous + * column, so that we search a minimal distance and still match + * special patterns, e.g., \< for beginning of a word. + * + * Otherwise, start searching immediately after the cursor. If + * at the end of the line, start searching on the next line. + * This is incompatible (read bug fix) with the historic vi -- + * searches for the '$' pattern never moved forward, and the + * "-t foo" didn't work if the 'f' was the first character in + * the file. + */ + if (LF_ISSET(SEARCH_INCR)) { + if ((coff = fm->cno) != 0) + --coff; + } else if (fm->cno + 1 >= len) { + coff = 0; + lno = fm->lno + 1; + if (db_get(sp, lno, 0, &l, &len)) { + if (!O_ISSET(sp, O_WRAPSCAN)) { + if (LF_ISSET(SEARCH_MSG)) + search_msg(sp, S_EOF); + return (1); + } + lno = 1; + wrapped = 1; + } + } else + coff = fm->cno + 1; + } + + btype = BUSY_ON; + for (cnt = INTERRUPT_CHECK, rval = 1;; ++lno, coff = 0) { + if (cnt-- == 0) { + if (INTERRUPTED(sp)) + break; + if (LF_ISSET(SEARCH_MSG)) { + search_busy(sp, btype); + btype = BUSY_UPDATE; + } + cnt = INTERRUPT_CHECK; + } + if ((wrapped && lno > fm->lno) || db_get(sp, lno, 0, &l, &len)) { + if (wrapped) { + if (LF_ISSET(SEARCH_MSG)) + search_msg(sp, S_NOTFOUND); + break; + } + if (!O_ISSET(sp, O_WRAPSCAN)) { + if (LF_ISSET(SEARCH_MSG)) + search_msg(sp, S_EOF); + break; + } + lno = 0; + wrapped = 1; + continue; + } + + /* If already at EOL, just keep going. */ + if (len != 0 && coff == len) + continue; + + /* Set the termination. */ + match[0].rm_so = coff; + match[0].rm_eo = len; + +#if defined(DEBUG) && 0 + TRACE(sp, "F search: %lu from %u to %u\n", + lno, coff, len != 0 ? len - 1 : len); +#endif + /* Search the line. */ + eval = regexec(&sp->re_c, l, 1, match, + (match[0].rm_so == 0 ? 0 : REG_NOTBOL) | REG_STARTEND); + if (eval == REG_NOMATCH) + continue; + if (eval != 0) { + if (LF_ISSET(SEARCH_MSG)) + re_error(sp, eval, &sp->re_c); + else + (void)sp->gp->scr_bell(sp); + break; + } + + /* Warn if the search wrapped. */ + if (wrapped && LF_ISSET(SEARCH_WMSG)) + search_msg(sp, S_WRAP); + +#if defined(DEBUG) && 0 + TRACE(sp, "F search: %qu to %qu\n", + match[0].rm_so, match[0].rm_eo); +#endif + rm->lno = lno; + rm->cno = match[0].rm_so; + + /* + * If a change command, it's possible to move beyond the end + * of a line. Historic vi generally got this wrong (e.g. try + * "c?$"). Not all that sure this gets it right, there + * are lots of strange cases. + */ + if (!LF_ISSET(SEARCH_EOL) && rm->cno >= len) + rm->cno = len != 0 ? len - 1 : 0; + + rval = 0; + break; + } + + if (LF_ISSET(SEARCH_MSG)) + search_busy(sp, BUSY_OFF); + return (rval); +} + +/* + * b_search -- + * Do a backward search. + * + * PUBLIC: int b_search(SCR *, + * PUBLIC: MARK *, MARK *, CHAR_T *, size_t, CHAR_T **, u_int); + */ +int +b_search(SCR *sp, MARK *fm, MARK *rm, CHAR_T *ptrn, size_t plen, + CHAR_T **eptrn, u_int flags) +{ + busy_t btype; + recno_t lno; + regmatch_t match[1]; + size_t coff, last, len; + int cnt, eval, rval, wrapped; + CHAR_T *l; + + if (search_init(sp, BACKWARD, ptrn, plen, eptrn, flags)) + return (1); + + /* + * If doing incremental search, set the "starting" position past the + * current column, so that we search a minimal distance and still + * match special patterns, e.g., \> for the end of a word. This is + * safe when the cursor is at the end of a line because we only use + * it for comparison with the location of the match. + * + * Otherwise, start searching immediately before the cursor. If in + * the first column, start search on the previous line. + */ + if (LF_ISSET(SEARCH_INCR)) { + lno = fm->lno; + coff = fm->cno + 1; + } else { + if (fm->cno == 0) { + if (fm->lno == 1 && !O_ISSET(sp, O_WRAPSCAN)) { + if (LF_ISSET(SEARCH_MSG)) + search_msg(sp, S_SOF); + return (1); + } + lno = fm->lno - 1; + } else + lno = fm->lno; + coff = fm->cno; + } + + btype = BUSY_ON; + for (cnt = INTERRUPT_CHECK, rval = 1, wrapped = 0;; --lno, coff = 0) { + if (cnt-- == 0) { + if (INTERRUPTED(sp)) + break; + if (LF_ISSET(SEARCH_MSG)) { + search_busy(sp, btype); + btype = BUSY_UPDATE; + } + cnt = INTERRUPT_CHECK; + } + if ((wrapped && lno < fm->lno) || lno == 0) { + if (wrapped) { + if (LF_ISSET(SEARCH_MSG)) + search_msg(sp, S_NOTFOUND); + break; + } + if (!O_ISSET(sp, O_WRAPSCAN)) { + if (LF_ISSET(SEARCH_MSG)) + search_msg(sp, S_SOF); + break; + } + if (db_last(sp, &lno)) + break; + if (lno == 0) { + if (LF_ISSET(SEARCH_MSG)) + search_msg(sp, S_EMPTY); + break; + } + ++lno; + wrapped = 1; + continue; + } + + if (db_get(sp, lno, 0, &l, &len)) + break; + + /* Set the termination. */ + match[0].rm_so = 0; + match[0].rm_eo = len; + +#if defined(DEBUG) && 0 + TRACE(sp, "B search: %lu from 0 to %qu\n", lno, match[0].rm_eo); +#endif + /* Search the line. */ + eval = regexec(&sp->re_c, l, 1, match, + (match[0].rm_eo == len ? 0 : REG_NOTEOL) | REG_STARTEND); + if (eval == REG_NOMATCH) + continue; + if (eval != 0) { + if (LF_ISSET(SEARCH_MSG)) + re_error(sp, eval, &sp->re_c); + else + (void)sp->gp->scr_bell(sp); + break; + } + + /* Check for a match starting past the cursor. */ + if (coff != 0 && match[0].rm_so >= coff) + continue; + + /* Warn if the search wrapped. */ + if (wrapped && LF_ISSET(SEARCH_WMSG)) + search_msg(sp, S_WRAP); + +#if defined(DEBUG) && 0 + TRACE(sp, "B found: %qu to %qu\n", + match[0].rm_so, match[0].rm_eo); +#endif + /* + * We now have the first match on the line. Step through the + * line character by character until find the last acceptable + * match. This is painful, we need a better interface to regex + * to make this work. + */ + for (;;) { + last = match[0].rm_so++; + if (match[0].rm_so >= len) + break; + match[0].rm_eo = len; + eval = regexec(&sp->re_c, l, 1, match, + (match[0].rm_so == 0 ? 0 : REG_NOTBOL) | + REG_STARTEND); + if (eval == REG_NOMATCH) + break; + if (eval != 0) { + if (LF_ISSET(SEARCH_MSG)) + re_error(sp, eval, &sp->re_c); + else + (void)sp->gp->scr_bell(sp); + goto err; + } + if (coff && match[0].rm_so >= coff) + break; + } + rm->lno = lno; + + /* See comment in f_search(). */ + if (!LF_ISSET(SEARCH_EOL) && last >= len) + rm->cno = len != 0 ? len - 1 : 0; + else + rm->cno = last; + rval = 0; + break; + } + +err: if (LF_ISSET(SEARCH_MSG)) + search_busy(sp, BUSY_OFF); + return (rval); +} + +/* + * search_msg -- + * Display one of the search messages. + */ +static void +search_msg(SCR *sp, smsg_t msg) +{ + switch (msg) { + case S_EMPTY: + msgq(sp, M_ERR, "072|File empty; nothing to search"); + break; + case S_EOF: + msgq(sp, M_ERR, + "073|Reached end-of-file without finding the pattern"); + break; + case S_NOPREV: + msgq(sp, M_ERR, "074|No previous search pattern"); + break; + case S_NOTFOUND: + msgq(sp, M_ERR, "075|Pattern not found"); + break; + case S_SOF: + msgq(sp, M_ERR, + "076|Reached top-of-file without finding the pattern"); + break; + case S_WRAP: + msgq(sp, M_ERR, "077|Search wrapped"); + break; + default: + abort(); + } +} + +/* + * search_busy -- + * Put up the busy searching message. + * + * PUBLIC: void search_busy(SCR *, busy_t); + */ +void +search_busy(SCR *sp, busy_t btype) +{ + sp->gp->scr_busy(sp, "078|Searching...", btype); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/common/search.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/common/seq.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/common/seq.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/common/seq.c (revision 366308) @@ -0,0 +1,371 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" + +/* + * seq_set -- + * Internal version to enter a sequence. + * + * PUBLIC: int seq_set(SCR *, CHAR_T *, + * PUBLIC: size_t, CHAR_T *, size_t, CHAR_T *, size_t, seq_t, int); + */ +int +seq_set(SCR *sp, CHAR_T *name, size_t nlen, CHAR_T *input, size_t ilen, + CHAR_T *output, size_t olen, seq_t stype, int flags) +{ + CHAR_T *p; + SEQ *lastqp, *qp; + int sv_errno; + + /* + * An input string must always be present. The output string + * can be NULL, when set internally, that's how we throw away + * input. + * + * Just replace the output field if the string already set. + */ + if ((qp = + seq_find(sp, &lastqp, NULL, input, ilen, stype, NULL)) != NULL) { + if (LF_ISSET(SEQ_NOOVERWRITE)) + return (0); + if (output == NULL || olen == 0) { + p = NULL; + olen = 0; + } else if ((p = v_wstrdup(sp, output, olen)) == NULL) { + sv_errno = errno; + goto mem1; + } + free(qp->output); + qp->olen = olen; + qp->output = p; + return (0); + } + + /* Allocate and initialize SEQ structure. */ + CALLOC(sp, qp, 1, sizeof(SEQ)); + if (qp == NULL) { + sv_errno = errno; + goto mem1; + } + + /* Name. */ + if (name == NULL || nlen == 0) + qp->name = NULL; + else if ((qp->name = v_wstrdup(sp, name, nlen)) == NULL) { + sv_errno = errno; + goto mem2; + } + qp->nlen = nlen; + + /* Input. */ + if ((qp->input = v_wstrdup(sp, input, ilen)) == NULL) { + sv_errno = errno; + goto mem3; + } + qp->ilen = ilen; + + /* Output. */ + if (output == NULL) { + qp->output = NULL; + olen = 0; + } else if ((qp->output = v_wstrdup(sp, output, olen)) == NULL) { + sv_errno = errno; + free(qp->input); +mem3: free(qp->name); +mem2: free(qp); +mem1: errno = sv_errno; + msgq(sp, M_SYSERR, NULL); + return (1); + } + qp->olen = olen; + + /* Type, flags. */ + qp->stype = stype; + qp->flags = flags; + + /* Link into the chain. */ + if (lastqp == NULL) { + SLIST_INSERT_HEAD(sp->gp->seqq, qp, q); + } else { + SLIST_INSERT_AFTER(lastqp, qp, q); + } + + /* Set the fast lookup bit. */ + if ((qp->input[0] & ~MAX_BIT_SEQ) == 0) + bit_set(sp->gp->seqb, qp->input[0]); + + return (0); +} + +/* + * seq_delete -- + * Delete a sequence. + * + * PUBLIC: int seq_delete(SCR *, CHAR_T *, size_t, seq_t); + */ +int +seq_delete(SCR *sp, CHAR_T *input, size_t ilen, seq_t stype) +{ + SEQ *qp, *pre_qp = NULL; + int diff; + + SLIST_FOREACH(qp, sp->gp->seqq, q) { + if (qp->stype == stype && qp->ilen == ilen) { + diff = MEMCMP(qp->input, input, ilen); + if (!diff) { + if (F_ISSET(qp, SEQ_FUNCMAP)) + break; + if (qp == SLIST_FIRST(sp->gp->seqq)) + SLIST_REMOVE_HEAD(sp->gp->seqq, q); + else + SLIST_REMOVE_AFTER(pre_qp, q); + return (seq_free(qp)); + } + if (diff > 0) + break; + } + pre_qp = qp; + } + return (1); +} + +/* + * seq_free -- + * Free a map entry. + * + * PUBLIC: int seq_free(SEQ *); + */ +int +seq_free(SEQ *qp) +{ + free(qp->name); + free(qp->input); + free(qp->output); + free(qp); + return (0); +} + +/* + * seq_find -- + * Search the sequence list for a match to a buffer, if ispartial + * isn't NULL, partial matches count. + * + * PUBLIC: SEQ *seq_find + * PUBLIC: (SCR *, SEQ **, EVENT *, CHAR_T *, size_t, seq_t, int *); + */ +SEQ * +seq_find(SCR *sp, SEQ **lastqp, EVENT *e_input, CHAR_T *c_input, size_t ilen, + seq_t stype, int *ispartialp) +{ + SEQ *lqp = NULL, *qp; + int diff; + + /* + * Ispartialp is a location where we return if there was a + * partial match, i.e. if the string were extended it might + * match something. + * + * XXX + * Overload the meaning of ispartialp; only the terminal key + * search doesn't want the search limited to complete matches, + * i.e. ilen may be longer than the match. + */ + if (ispartialp != NULL) + *ispartialp = 0; + for (qp = SLIST_FIRST(sp->gp->seqq); qp != NULL; + lqp = qp, qp = SLIST_NEXT(qp, q)) { + /* + * Fast checks on the first character and type, and then + * a real comparison. + */ + if (e_input == NULL) { + if (qp->input[0] > c_input[0]) + break; + if (qp->input[0] < c_input[0] || + qp->stype != stype || F_ISSET(qp, SEQ_FUNCMAP)) + continue; + diff = MEMCMP(qp->input, c_input, MIN(qp->ilen, ilen)); + } else { + if (qp->input[0] > e_input->e_c) + break; + if (qp->input[0] < e_input->e_c || + qp->stype != stype || F_ISSET(qp, SEQ_FUNCMAP)) + continue; + diff = + e_memcmp(qp->input, e_input, MIN(qp->ilen, ilen)); + } + if (diff > 0) + break; + if (diff < 0) + continue; + /* + * If the entry is the same length as the string, return a + * match. If the entry is shorter than the string, return a + * match if called from the terminal key routine. Otherwise, + * keep searching for a complete match. + */ + if (qp->ilen <= ilen) { + if (qp->ilen == ilen || ispartialp != NULL) { + if (lastqp != NULL) + *lastqp = lqp; + return (qp); + } + continue; + } + /* + * If the entry longer than the string, return partial match + * if called from the terminal key routine. Otherwise, no + * match. + */ + if (ispartialp != NULL) + *ispartialp = 1; + break; + } + if (lastqp != NULL) + *lastqp = lqp; + return (NULL); +} + +/* + * seq_close -- + * Discard all sequences. + * + * PUBLIC: void seq_close(GS *); + */ +void +seq_close(GS *gp) +{ + SEQ *qp; + + while ((qp = SLIST_FIRST(gp->seqq)) != NULL) { + SLIST_REMOVE_HEAD(gp->seqq, q); + (void)seq_free(qp); + } +} + +/* + * seq_dump -- + * Display the sequence entries of a specified type. + * + * PUBLIC: int seq_dump(SCR *, seq_t, int); + */ +int +seq_dump(SCR *sp, seq_t stype, int isname) +{ + CHAR_T *p; + GS *gp; + SEQ *qp; + int cnt, len, olen; + + cnt = 0; + gp = sp->gp; + SLIST_FOREACH(qp, sp->gp->seqq, q) { + if (stype != qp->stype || F_ISSET(qp, SEQ_FUNCMAP)) + continue; + ++cnt; + for (p = qp->input, + olen = qp->ilen, len = 0; olen > 0; --olen, ++p) + len += ex_puts(sp, KEY_NAME(sp, *p)); + for (len = STANDARD_TAB - len % STANDARD_TAB; len > 0;) + len -= ex_puts(sp, " "); + + if (qp->output != NULL) + for (p = qp->output, + olen = qp->olen, len = 0; olen > 0; --olen, ++p) + len += ex_puts(sp, KEY_NAME(sp, *p)); + else + len = 0; + + if (isname && qp->name != NULL) { + for (len = STANDARD_TAB - len % STANDARD_TAB; len > 0;) + len -= ex_puts(sp, " "); + for (p = qp->name, + olen = qp->nlen; olen > 0; --olen, ++p) + (void)ex_puts(sp, KEY_NAME(sp, *p)); + } + (void)ex_puts(sp, "\n"); + } + return (cnt); +} + +/* + * seq_save -- + * Save the sequence entries to a file. + * + * PUBLIC: int seq_save(SCR *, FILE *, char *, seq_t); + */ +int +seq_save(SCR *sp, FILE *fp, char *prefix, seq_t stype) +{ + CHAR_T *p; + SEQ *qp; + size_t olen; + int ch; + + /* Write a sequence command for all keys the user defined. */ + SLIST_FOREACH(qp, sp->gp->seqq, q) { + if (stype != qp->stype || !F_ISSET(qp, SEQ_USERDEF)) + continue; + if (prefix) + (void)fprintf(fp, "%s", prefix); + for (p = qp->input, olen = qp->ilen; olen > 0; --olen) { + ch = *p++; + if (ch == CH_LITERAL || ch == '|' || + cmdskip(ch) || KEY_VAL(sp, ch) == K_NL) + (void)putc(CH_LITERAL, fp); + (void)putc(ch, fp); + } + (void)putc(' ', fp); + if (qp->output != NULL) + for (p = qp->output, + olen = qp->olen; olen > 0; --olen) { + ch = *p++; + if (ch == CH_LITERAL || ch == '|' || + KEY_VAL(sp, ch) == K_NL) + (void)putc(CH_LITERAL, fp); + (void)putc(ch, fp); + } + (void)putc('\n', fp); + } + return (0); +} + +/* + * e_memcmp -- + * Compare a string of EVENT's to a string of CHAR_T's. + * + * PUBLIC: int e_memcmp(CHAR_T *, EVENT *, size_t); + */ +int +e_memcmp(CHAR_T *p1, EVENT *ep, size_t n) +{ + if (n != 0) { + do { + if (*p1++ != ep->e_c) + return (*--p1 - ep->e_c); + ++ep; + } while (--n != 0); + } + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/common/seq.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/common/seq.h =================================================================== --- vendor/nvi/2.2.0-05ed8b9/common/seq.h (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/common/seq.h (revision 366308) @@ -0,0 +1,42 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +/* + * Map and abbreviation structures. + * + * The map structure is singly linked list, sorted by input string and by + * input length within the string. (The latter is necessary so that short + * matches will happen before long matches when the list is searched.) + * Additionally, there is a bitmap which has bits set if there are entries + * starting with the corresponding character. This keeps us from walking + * the list unless it's necessary. + * + * The name and the output fields of a SEQ can be empty, i.e. NULL. + * Only the input field is required. + * + * XXX + * The fast-lookup bits are never turned off -- users don't usually unmap + * things, though, so it's probably not a big deal. + */ +struct _seq { + SLIST_ENTRY(_seq) q; /* Linked list of all sequences. */ + seq_t stype; /* Sequence type. */ + CHAR_T *name; /* Sequence name (if any). */ + size_t nlen; /* Name length. */ + CHAR_T *input; /* Sequence input keys. */ + size_t ilen; /* Input keys length. */ + CHAR_T *output; /* Sequence output keys. */ + size_t olen; /* Output keys length. */ + +#define SEQ_FUNCMAP 0x01 /* If unresolved function key.*/ +#define SEQ_NOOVERWRITE 0x02 /* Don't replace existing entry. */ +#define SEQ_SCREEN 0x04 /* If screen specific. */ +#define SEQ_USERDEF 0x08 /* If user defined. */ + u_int8_t flags; +}; Property changes on: vendor/nvi/2.2.0-05ed8b9/common/seq.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/common/util.h =================================================================== --- vendor/nvi/2.2.0-05ed8b9/common/util.h (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/common/util.h (revision 366308) @@ -0,0 +1,91 @@ +/*- + * Copyright (c) 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +/* Macros to init/set/clear/test flags. */ +#define FL_INIT(l, f) (l) = (f) /* Specific flags location. */ +#define FL_SET(l, f) ((l) |= (f)) +#define FL_CLR(l, f) ((l) &= ~(f)) +#define FL_ISSET(l, f) ((l) & (f)) + +#define LF_INIT(f) FL_INIT(flags, f) /* Local variable flags. */ +#define LF_SET(f) FL_SET(flags, f) +#define LF_CLR(f) FL_CLR(flags, f) +#define LF_ISSET(f) FL_ISSET(flags, f) + +#define F_INIT(p, f) FL_INIT((p)->flags, f) /* Structure element flags. */ +#define F_SET(p, f) FL_SET((p)->flags, f) +#define F_CLR(p, f) FL_CLR((p)->flags, f) +#define F_ISSET(p, f) FL_ISSET((p)->flags, f) + +/* Offset to next column of stop size, e.g. tab offsets. */ +#define COL_OFF(c, stop) ((stop) - ((c) % (stop))) + +/* Busy message types. */ +typedef enum { B_NONE, B_OFF, B_READ, B_RECOVER, B_SEARCH, B_WRITE } bmsg_t; + +/* + * Number handling defines and protoypes. + * + * NNFITS: test for addition of two negative numbers under a limit + * NPFITS: test for addition of two positive numbers under a limit + * NADD_SLONG: test for addition of two signed longs + * NADD_USLONG: test for addition of two unsigned longs + */ +enum nresult { NUM_ERR, NUM_OK, NUM_OVER, NUM_UNDER }; +#define NNFITS(min, cur, add) \ + (((long)(min)) - (cur) <= (add)) +#define NPFITS(max, cur, add) \ + (((unsigned long)(max)) - (cur) >= (add)) +#define NADD_SLONG(sp, v1, v2) \ + ((v1) < 0 ? \ + ((v2) < 0 && \ + NNFITS(LONG_MIN, (v1), (v2))) ? NUM_UNDER : NUM_OK : \ + (v1) > 0 ? \ + (v2) > 0 && \ + NPFITS(LONG_MAX, (v1), (v2)) ? NUM_OK : NUM_OVER : \ + NUM_OK) +#define NADD_USLONG(sp, v1, v2) \ + (NPFITS(ULONG_MAX, (v1), (v2)) ? NUM_OK : NUM_OVER) + +/* Macros for min/max. */ +#undef MIN +#undef MAX +#define MIN(_a,_b) ((_a)<(_b)?(_a):(_b)) +#define MAX(_a,_b) ((_a)<(_b)?(_b):(_a)) + +/* Operations on timespecs */ +#undef timespecclear +#undef timespecisset +#undef timespeccmp +#undef timespecadd +#undef timespecsub +#define timespecclear(tvp) ((tvp)->tv_sec = (tvp)->tv_nsec = 0) +#define timespecisset(tvp) ((tvp)->tv_sec || (tvp)->tv_nsec) +#define timespeccmp(tvp, uvp, cmp) \ + (((tvp)->tv_sec == (uvp)->tv_sec) ? \ + ((tvp)->tv_nsec cmp (uvp)->tv_nsec) : \ + ((tvp)->tv_sec cmp (uvp)->tv_sec)) +#define timespecadd(vvp, uvp) \ + do { \ + (vvp)->tv_sec += (uvp)->tv_sec; \ + (vvp)->tv_nsec += (uvp)->tv_nsec; \ + if ((vvp)->tv_nsec >= 1000000000) { \ + (vvp)->tv_sec++; \ + (vvp)->tv_nsec -= 1000000000; \ + } \ + } while (0) +#define timespecsub(vvp, uvp) \ + do { \ + (vvp)->tv_sec -= (uvp)->tv_sec; \ + (vvp)->tv_nsec -= (uvp)->tv_nsec; \ + if ((vvp)->tv_nsec < 0) { \ + (vvp)->tv_sec--; \ + (vvp)->tv_nsec += 1000000000; \ + } \ + } while (0) Property changes on: vendor/nvi/2.2.0-05ed8b9/common/util.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/common/options.awk =================================================================== --- vendor/nvi/2.2.0-05ed8b9/common/options.awk (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/common/options.awk (revision 366308) @@ -0,0 +1,9 @@ +# @(#)options.awk 10.1 (Berkeley) 6/8/95 + +/^\/\* O_[0-9A-Z_]*/ { + printf("#define %s %d\n", $2, cnt++); + next; +} +END { + printf("#define O_OPTIONCOUNT %d\n", cnt); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/common/options.awk ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex.c (revision 366308) @@ -0,0 +1,2367 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../common/common.h" +#include "../vi/vi.h" + +#if defined(DEBUG) && defined(COMLOG) +static void ex_comlog(SCR *, EXCMD *); +#endif +static EXCMDLIST const * + ex_comm_search(CHAR_T *, size_t); +static int ex_discard(SCR *); +static int ex_line(SCR *, EXCMD *, MARK *, int *, int *); +static int ex_load(SCR *); +static void ex_unknown(SCR *, CHAR_T *, size_t); + +/* + * ex -- + * Main ex loop. + * + * PUBLIC: int ex(SCR **); + */ +int +ex(SCR **spp) +{ + EX_PRIVATE *exp; + GS *gp; + MSGS *mp; + SCR *sp; + TEXT *tp; + u_int32_t flags; + + sp = *spp; + gp = sp->gp; + exp = EXP(sp); + + /* Start the ex screen. */ + if (ex_init(sp)) + return (1); + + /* Flush any saved messages. */ + while ((mp = SLIST_FIRST(gp->msgq)) != NULL) { + gp->scr_msg(sp, mp->mtype, mp->buf, mp->len); + SLIST_REMOVE_HEAD(gp->msgq, q); + free(mp->buf); + free(mp); + } + + /* If reading from a file, errors should have name and line info. */ + if (F_ISSET(gp, G_SCRIPTED)) { + gp->excmd.if_lno = 1; + gp->excmd.if_name = "script"; + } + + /* + * !!! + * Initialize the text flags. The beautify edit option historically + * applied to ex command input read from a file. In addition, the + * first time a ^H was discarded from the input, there was a message, + * "^H discarded", that was displayed. We don't bother. + */ + LF_INIT(TXT_BACKSLASH | TXT_CNTRLD | TXT_CR); + for (;; ++gp->excmd.if_lno) { + /* Display status line and flush. */ + if (F_ISSET(sp, SC_STATUS)) { + if (!F_ISSET(sp, SC_EX_SILENT)) + msgq_status(sp, sp->lno, 0); + F_CLR(sp, SC_STATUS); + } + (void)ex_fflush(sp); + + /* Set the flags the user can reset. */ + if (O_ISSET(sp, O_BEAUTIFY)) + LF_SET(TXT_BEAUTIFY); + if (O_ISSET(sp, O_PROMPT)) + LF_SET(TXT_PROMPT); + + /* Clear any current interrupts, and get a command. */ + CLR_INTERRUPT(sp); + if (ex_txt(sp, sp->tiq, ':', flags)) + return (1); + if (INTERRUPTED(sp)) { + (void)ex_puts(sp, "\n"); + (void)ex_fflush(sp); + continue; + } + + /* Initialize the command structure. */ + CLEAR_EX_PARSER(&gp->excmd); + + /* + * If the user entered a single carriage return, send + * ex_cmd() a separator -- it discards single newlines. + */ + tp = TAILQ_FIRST(sp->tiq); + if (tp->len == 0) { + gp->excmd.cp = L(" "); /* __TK__ why not |? */ + gp->excmd.clen = 1; + } else { + gp->excmd.cp = tp->lb; + gp->excmd.clen = tp->len; + } + F_INIT(&gp->excmd, E_NRSEP); + + if (ex_cmd(sp) && F_ISSET(gp, G_SCRIPTED)) + return (1); + + if (INTERRUPTED(sp)) { + CLR_INTERRUPT(sp); + msgq(sp, M_ERR, "170|Interrupted"); + } + + /* + * If the last command caused a restart, or switched screens + * or into vi, return. + */ + if (F_ISSET(gp, G_SRESTART) || F_ISSET(sp, SC_SSWITCH | SC_VI)) { + *spp = sp; + break; + } + + /* If the last command switched files, we don't care. */ + F_CLR(sp, SC_FSWITCH); + + /* + * If we're exiting this screen, move to the next one. By + * definition, this means returning into vi, so return to the + * main editor loop. The ordering is careful, don't discard + * the contents of sp until the end. + */ + if (F_ISSET(sp, SC_EXIT | SC_EXIT_FORCE)) { + if (file_end(sp, NULL, F_ISSET(sp, SC_EXIT_FORCE))) + return (1); + *spp = screen_next(sp); + return (screen_end(sp)); + } + } + return (0); +} + +/* + * ex_cmd -- + * The guts of the ex parser: parse and execute a string containing + * ex commands. + * + * !!! + * This code MODIFIES the string that gets passed in, to delete quoting + * characters, etc. The string cannot be readonly/text space, nor should + * you expect to use it again after ex_cmd() returns. + * + * !!! + * For the fun of it, if you want to see if a vi clone got the ex argument + * parsing right, try: + * + * echo 'foo|bar' > file1; echo 'foo/bar' > file2; + * vi + * :edit +1|s/|/PIPE/|w file1| e file2|1 | s/\//SLASH/|wq + * + * or: vi + * :set|file|append|set|file + * + * For extra credit, try them in a startup .exrc file. + * + * PUBLIC: int ex_cmd(SCR *); + */ +int +ex_cmd(SCR *sp) +{ + enum nresult nret; + EX_PRIVATE *exp; + EXCMD *ecp; + GS *gp; + MARK cur; + recno_t lno; + size_t arg1_len, discard, len; + u_int32_t flags; + long ltmp; + int at_found, gv_found; + int cnt, delim, isaddr, namelen; + int newscreen, notempty, tmp, vi_address; + CHAR_T *arg1, *s, *p, *t; + CHAR_T ch = '\0'; + CHAR_T *n; + char *np; + + gp = sp->gp; + exp = EXP(sp); + + /* + * We always start running the command on the top of the stack. + * This means that *everything* must be resolved when we leave + * this function for any reason. + */ +loop: ecp = SLIST_FIRST(gp->ecq); + + /* If we're reading a command from a file, set up error information. */ + if (ecp->if_name != NULL) { + gp->if_lno = ecp->if_lno; + gp->if_name = ecp->if_name; + } + + /* + * If a move to the end of the file is scheduled for this command, + * do it now. + */ + if (F_ISSET(ecp, E_MOVETOEND)) { + if (db_last(sp, &sp->lno)) + goto rfail; + sp->cno = 0; + F_CLR(ecp, E_MOVETOEND); + } + + /* If we found a newline, increment the count now. */ + if (F_ISSET(ecp, E_NEWLINE)) { + ++gp->if_lno; + ++ecp->if_lno; + F_CLR(ecp, E_NEWLINE); + } + + /* (Re)initialize the EXCMD structure, preserving some flags. */ + CLEAR_EX_CMD(ecp); + + /* Initialize the argument structures. */ + if (argv_init(sp, ecp)) + goto err; + + /* Initialize +cmd, saved command information. */ + arg1 = NULL; + ecp->save_cmdlen = 0; + + /* Skip s, empty lines. */ + for (notempty = 0; ecp->clen > 0; ++ecp->cp, --ecp->clen) + if ((ch = *ecp->cp) == '\n') { + ++gp->if_lno; + ++ecp->if_lno; + } else if (cmdskip(ch)) + notempty = 1; + else + break; + + /* + * !!! + * Permit extra colons at the start of the line. Historically, + * ex/vi allowed a single extra one. It's simpler not to count. + * The stripping is done here because, historically, any command + * could have preceding colons, e.g. ":g/pattern/:p" worked. + */ + if (ecp->clen != 0 && ch == ':') { + notempty = 1; + while (--ecp->clen > 0 && (ch = *++ecp->cp) == ':'); + } + + /* + * Command lines that start with a double-quote are comments. + * + * !!! + * Historically, there was no escape or delimiter for a comment, e.g. + * :"foo|set was a single comment and nothing was output. Since nvi + * permits users to escape characters into command lines, we + * have to check for that case. + */ + if (ecp->clen != 0 && ch == '"') { + while (--ecp->clen > 0 && *++ecp->cp != '\n'); + if (*ecp->cp == '\n') { + F_SET(ecp, E_NEWLINE); + ++ecp->cp; + --ecp->clen; + } + goto loop; + } + + /* Skip whitespace. */ + for (; ecp->clen > 0; ++ecp->cp, --ecp->clen) { + ch = *ecp->cp; + if (!cmdskip(ch)) + break; + } + + /* + * The last point at which an empty line can mean do nothing. + * + * !!! + * Historically, in ex mode, lines containing only characters + * were the same as a single , i.e. a default command. + * In vi mode, they were ignored. In .exrc files this was a serious + * annoyance, as vi kept trying to treat them as print commands. We + * ignore backward compatibility in this case, discarding lines that + * contain only characters from .exrc files. + * + * !!! + * This is where you end up when you're done a command, i.e. clen has + * gone to zero. Continue if there are more commands to run. + */ + if (ecp->clen == 0 && + (!notempty || F_ISSET(sp, SC_VI) || F_ISSET(ecp, E_BLIGNORE))) { + if (ex_load(sp)) + goto rfail; + ecp = SLIST_FIRST(gp->ecq); + if (ecp->clen == 0) + goto rsuccess; + goto loop; + } + + /* + * Check to see if this is a command for which we may want to move + * the cursor back up to the previous line. (The command :1 + * wants a separator, but the command : wants to erase + * the command line.) If the line is empty except for s, + * or , we'll probably want to move up. I + * don't think there's any way to get characters *after* the + * command character, but this is the ex parser, and I've been wrong + * before. + */ + if (F_ISSET(ecp, E_NRSEP) && + ecp->clen != 0 && (ecp->clen != 1 || ecp->cp[0] != '\004')) + F_CLR(ecp, E_NRSEP); + + /* Parse command addresses. */ + if (ex_range(sp, ecp, &tmp)) + goto rfail; + if (tmp) + goto err; + + /* + * Skip s and any more colons (the command :3,5:print + * worked, historically). + */ + for (; ecp->clen > 0; ++ecp->cp, --ecp->clen) { + ch = *ecp->cp; + if (!cmdskip(ch) && ch != ':') + break; + } + + /* + * If no command, ex does the last specified of p, l, or #, and vi + * moves to the line. Otherwise, determine the length of the command + * name by looking for the first non-alphabetic character. (There + * are a few non-alphabetic characters in command names, but they're + * all single character commands.) This isn't a great test, because + * it means that, for the command ":e +cut.c file", we'll report that + * the command "cut" wasn't known. However, it makes ":e+35 file" work + * correctly. + * + * !!! + * Historically, lines with multiple adjacent (or separated) + * command separators were very strange. For example, the command + * |||, when the cursor was on line 1, displayed + * lines 2, 3 and 5 of the file. In addition, the command " | " + * would only display the line after the next line, instead of the + * next two lines. No ideas why. It worked reasonably when executed + * from vi mode, and displayed lines 2, 3, and 4, so we do a default + * command for each separator. + */ +#define SINGLE_CHAR_COMMANDS L("\004!#&*<=>@~") + newscreen = 0; + if (ecp->clen != 0 && ecp->cp[0] != '|' && ecp->cp[0] != '\n') { + if (STRCHR(SINGLE_CHAR_COMMANDS, *ecp->cp)) { + p = ecp->cp; + ++ecp->cp; + --ecp->clen; + namelen = 1; + } else { + for (p = ecp->cp; + ecp->clen > 0; --ecp->clen, ++ecp->cp) + if (!isazAZ(*ecp->cp)) + break; + if ((namelen = ecp->cp - p) == 0) { + msgq(sp, M_ERR, "080|Unknown command name"); + goto err; + } + } + + /* + * !!! + * Historic vi permitted flags to immediately follow any + * subset of the 'delete' command, but then did not permit + * further arguments (flag, buffer, count). Make it work. + * Permit further arguments for the few shreds of dignity + * it offers. + * + * Adding commands that start with 'd', and match "delete" + * up to a l, p, +, - or # character can break this code. + * + * !!! + * Capital letters beginning the command names ex, edit, + * next, previous, tag and visual (in vi mode) indicate the + * command should happen in a new screen. + */ + switch (p[0]) { + case 'd': + for (s = p, + n = cmds[C_DELETE].name; *s == *n; ++s, ++n); + if (s[0] == 'l' || s[0] == 'p' || s[0] == '+' || + s[0] == '-' || s[0] == '^' || s[0] == '#') { + len = (ecp->cp - p) - (s - p); + ecp->cp -= len; + ecp->clen += len; + ecp->rcmd = cmds[C_DELETE]; + ecp->rcmd.syntax = "1bca1"; + ecp->cmd = &ecp->rcmd; + goto skip_srch; + } + break; + case 'E': case 'F': case 'N': case 'P': case 'T': case 'V': + newscreen = 1; + p[0] = tolower(p[0]); + break; + } + + /* + * Search the table for the command. + * + * !!! + * Historic vi permitted the mark to immediately follow the + * 'k' in the 'k' command. Make it work. + * + * !!! + * Historic vi permitted any flag to follow the s command, e.g. + * "s/e/E/|s|sgc3p" was legal. Make the command "sgc" work. + * Since the following characters all have to be flags, i.e. + * alphabetics, we can let the s command routine return errors + * if it was some illegal command string. This code will break + * if an "sg" or similar command is ever added. The substitute + * code doesn't care if it's a "cgr" flag or a "#lp" flag that + * follows the 's', but we limit the choices here to "cgr" so + * that we get unknown command messages for wrong combinations. + */ + if ((ecp->cmd = ex_comm_search(p, namelen)) == NULL) + switch (p[0]) { + case 'k': + if (namelen == 2) { + ecp->cp -= namelen - 1; + ecp->clen += namelen - 1; + ecp->cmd = &cmds[C_K]; + break; + } + goto unknown; + case 's': + for (s = p + 1, cnt = namelen; --cnt; ++s) + if (s[0] != 'c' && + s[0] != 'g' && s[0] != 'r') + break; + if (cnt == 0) { + ecp->cp -= namelen - 1; + ecp->clen += namelen - 1; + ecp->rcmd = cmds[C_SUBSTITUTE]; + ecp->rcmd.fn = ex_subagain; + ecp->cmd = &ecp->rcmd; + break; + } + /* FALLTHROUGH */ + default: +unknown: if (newscreen) + p[0] = toupper(p[0]); + ex_unknown(sp, p, namelen); + goto err; + } + + /* + * The visual command has a different syntax when called + * from ex than when called from a vi colon command. FMH. + * Make the change now, before we test for the newscreen + * semantic, so that we're testing the right one. + */ +skip_srch: if (ecp->cmd == &cmds[C_VISUAL_EX] && F_ISSET(sp, SC_VI)) + ecp->cmd = &cmds[C_VISUAL_VI]; + + /* + * !!! + * Historic vi permitted a capital 'P' at the beginning of + * any command that started with 'p'. Probably wanted the + * P[rint] command for backward compatibility, and the code + * just made Preserve and Put work by accident. Nvi uses + * Previous to mean previous-in-a-new-screen, so be careful. + */ + if (newscreen && !F_ISSET(ecp->cmd, E_NEWSCREEN) && + (ecp->cmd == &cmds[C_PRINT] || + ecp->cmd == &cmds[C_PRESERVE])) + newscreen = 0; + + /* Test for a newscreen associated with this command. */ + if (newscreen && !F_ISSET(ecp->cmd, E_NEWSCREEN)) + goto unknown; + + /* Secure means no shell access. */ + if (F_ISSET(ecp->cmd, E_SECURE) && O_ISSET(sp, O_SECURE)) { + ex_wemsg(sp, ecp->cmd->name, EXM_SECURE); + goto err; + } + + /* + * Multiple < and > characters; another "feature". Note, + * The string passed to the underlying function may not be + * nul terminated in this case. + */ + if ((ecp->cmd == &cmds[C_SHIFTL] && *p == '<') || + (ecp->cmd == &cmds[C_SHIFTR] && *p == '>')) { + for (ch = *p; + ecp->clen > 0; --ecp->clen, ++ecp->cp) + if (*ecp->cp != ch) + break; + if (argv_exp0(sp, ecp, p, ecp->cp - p)) + goto err; + } + + /* Set the format style flags for the next command. */ + if (ecp->cmd == &cmds[C_HASH]) + exp->fdef = E_C_HASH; + else if (ecp->cmd == &cmds[C_LIST]) + exp->fdef = E_C_LIST; + else if (ecp->cmd == &cmds[C_PRINT]) + exp->fdef = E_C_PRINT; + F_CLR(ecp, E_USELASTCMD); + } else { + /* Print is the default command. */ + ecp->cmd = &cmds[C_PRINT]; + + /* Set the saved format flags. */ + F_SET(ecp, exp->fdef); + + /* + * !!! + * If no address was specified, and it's not a global command, + * we up the address by one. (I have no idea why globals are + * exempted, but it's (ahem) historic practice.) + */ + if (ecp->addrcnt == 0 && !F_ISSET(sp, SC_EX_GLOBAL)) { + ecp->addrcnt = 1; + ecp->addr1.lno = sp->lno + 1; + ecp->addr1.cno = sp->cno; + } + + F_SET(ecp, E_USELASTCMD); + } + + /* + * !!! + * Historically, the number option applied to both ex and vi. One + * strangeness was that ex didn't switch display formats until a + * command was entered, e.g. 's after the set didn't change to + * the new format, but :1p would. + */ + if (O_ISSET(sp, O_NUMBER)) { + F_SET(ecp, E_OPTNUM); + FL_SET(ecp->iflags, E_C_HASH); + } else + F_CLR(ecp, E_OPTNUM); + + /* Check for ex mode legality. */ + if (F_ISSET(sp, SC_EX) && (F_ISSET(ecp->cmd, E_VIONLY) || newscreen)) { + msgq_wstr(sp, M_ERR, ecp->cmd->name, + "082|%s: command not available in ex mode"); + goto err; + } + + /* Add standard command flags. */ + F_SET(ecp, ecp->cmd->flags); + if (!newscreen) + F_CLR(ecp, E_NEWSCREEN); + + /* + * There are three normal termination cases for an ex command. They + * are the end of the string (ecp->clen), or unescaped (by characters) or '|' characters. As we're now past + * possible addresses, we can determine how long the command is, so we + * don't have to look for all the possible terminations. Naturally, + * there are some exciting special cases: + * + * 1: The bang, global, v and the filter versions of the read and + * write commands are delimited by s (they can contain + * shell pipes). + * 2: The ex, edit, next and visual in vi mode commands all take ex + * commands as their first arguments. + * 3: The s command takes an RE as its first argument, and wants it + * to be specially delimited. + * + * Historically, '|' characters in the first argument of the ex, edit, + * next, vi visual, and s commands didn't delimit the command. And, + * in the filter cases for read and write, and the bang, global and v + * commands, they did not delimit the command at all. + * + * For example, the following commands were legal: + * + * :edit +25|s/abc/ABC/ file.c + * :s/|/PIPE/ + * :read !spell % | columnate + * :global/pattern/p|l + * + * It's not quite as simple as it sounds, however. The command: + * + * :s/a/b/|s/c/d|set + * + * was also legal, i.e. the historic ex parser (using the word loosely, + * since "parser" implies some regularity of syntax) delimited the RE's + * based on its delimiter and not anything so irretrievably vulgar as a + * command syntax. + * + * Anyhow, the following code makes this all work. First, for the + * special cases we move past their special argument(s). Then, we + * do normal command processing on whatever is left. Barf-O-Rama. + */ + discard = 0; /* Characters discarded from the command. */ + arg1_len = 0; + ecp->save_cmd = ecp->cp; + if (ecp->cmd == &cmds[C_EDIT] || ecp->cmd == &cmds[C_EX] || + ecp->cmd == &cmds[C_NEXT] || ecp->cmd == &cmds[C_VISUAL_VI] || + ecp->cmd == &cmds[C_VSPLIT]) { + /* + * Move to the next non-whitespace character. A '!' + * immediately following the command is eaten as a + * force flag. + */ + if (ecp->clen > 0 && *ecp->cp == '!') { + ++ecp->cp; + --ecp->clen; + FL_SET(ecp->iflags, E_C_FORCE); + + /* Reset, don't reparse. */ + ecp->save_cmd = ecp->cp; + } + for (; ecp->clen > 0; --ecp->clen, ++ecp->cp) + if (!cmdskip(*ecp->cp)) + break; + /* + * QUOTING NOTE: + * + * The historic implementation ignored all escape characters + * so there was no way to put a space or newline into the +cmd + * field. We do a simplistic job of fixing it by moving to the + * first whitespace character that isn't escaped. The escaping + * characters are stripped as no longer useful. + */ + if (ecp->clen > 0 && *ecp->cp == '+') { + ++ecp->cp; + --ecp->clen; + for (arg1 = p = ecp->cp; + ecp->clen > 0; --ecp->clen, ++ecp->cp) { + ch = *ecp->cp; + if (IS_ESCAPE(sp, ecp, ch) && + ecp->clen > 1) { + ++discard; + --ecp->clen; + ch = *++ecp->cp; + } else if (cmdskip(ch)) + break; + *p++ = ch; + } + arg1_len = ecp->cp - arg1; + + /* Reset, so the first argument isn't reparsed. */ + ecp->save_cmd = ecp->cp; + } + } else if (ecp->cmd == &cmds[C_BANG] || + ecp->cmd == &cmds[C_GLOBAL] || ecp->cmd == &cmds[C_V]) { + /* + * QUOTING NOTE: + * + * We use backslashes to escape characters, although + * this wasn't historic practice for the bang command. It was + * for the global and v commands, and it's common usage when + * doing text insert during the command. Escaping characters + * are stripped as no longer useful. + */ + for (p = ecp->cp; ecp->clen > 0; --ecp->clen, ++ecp->cp) { + ch = *ecp->cp; + if (ch == '\\' && ecp->clen > 1 && ecp->cp[1] == '\n') { + ++discard; + --ecp->clen; + ch = *++ecp->cp; + + ++gp->if_lno; + ++ecp->if_lno; + } else if (ch == '\n') + break; + *p++ = ch; + } + } else if (ecp->cmd == &cmds[C_READ] || ecp->cmd == &cmds[C_WRITE]) { + /* + * For write commands, if the next character is a , and + * the next non-blank character is a '!', it's a filter command + * and we want to eat everything up to the . For read + * commands, if the next non-blank character is a '!', it's a + * filter command and we want to eat everything up to the next + * . Otherwise, we're done. + */ + for (tmp = 0; ecp->clen > 0; --ecp->clen, ++ecp->cp) { + ch = *ecp->cp; + if (cmdskip(ch)) + tmp = 1; + else + break; + } + if (ecp->clen > 0 && ch == '!' && + (ecp->cmd == &cmds[C_READ] || tmp)) + for (; ecp->clen > 0; --ecp->clen, ++ecp->cp) + if (ecp->cp[0] == '\n') + break; + } else if (ecp->cmd == &cmds[C_SUBSTITUTE]) { + /* + * Move to the next non-whitespace character, we'll use it as + * the delimiter. If the character isn't an alphanumeric or + * a '|', it's the delimiter, so parse it. Otherwise, we're + * into something like ":s g", so use the special s command. + */ + for (; ecp->clen > 0; --ecp->clen, ++ecp->cp) + if (!cmdskip(ecp->cp[0])) + break; + + if (is09azAZ(ecp->cp[0]) || ecp->cp[0] == '|') { + ecp->rcmd = cmds[C_SUBSTITUTE]; + ecp->rcmd.fn = ex_subagain; + ecp->cmd = &ecp->rcmd; + } else if (ecp->clen > 0) { + /* + * QUOTING NOTE: + * + * Backslashes quote delimiter characters for RE's. + * The backslashes are NOT removed since they'll be + * used by the RE code. Move to the third delimiter + * that's not escaped (or the end of the command). + */ + delim = *ecp->cp; + ++ecp->cp; + --ecp->clen; + for (cnt = 2; ecp->clen > 0 && + cnt != 0; --ecp->clen, ++ecp->cp) + if (ecp->cp[0] == '\\' && + ecp->clen > 1) { + ++ecp->cp; + --ecp->clen; + } else if (ecp->cp[0] == delim) + --cnt; + } + } + + /* + * Use normal quoting and termination rules to find the end of this + * command. + * + * QUOTING NOTE: + * + * Historically, vi permitted ^V's to escape 's in the .exrc + * file. It was almost certainly a bug, but that's what bug-for-bug + * compatibility means, Grasshopper. Also, ^V's escape the command + * delimiters. Literal next quote characters in front of the newlines, + * '|' characters or literal next characters are stripped as they're + * no longer useful. + */ + vi_address = ecp->clen != 0 && ecp->cp[0] != '\n'; + for (p = ecp->cp; ecp->clen > 0; --ecp->clen, ++ecp->cp) { + ch = ecp->cp[0]; + if (IS_ESCAPE(sp, ecp, ch) && ecp->clen > 1) { + CHAR_T tmp = ecp->cp[1]; + if (tmp == '\n' || tmp == '|') { + if (tmp == '\n') { + ++gp->if_lno; + ++ecp->if_lno; + } + ++discard; + --ecp->clen; + ++ecp->cp; + ch = tmp; + } + } else if (ch == '\n' || ch == '|') { + if (ch == '\n') + F_SET(ecp, E_NEWLINE); + --ecp->clen; + break; + } + *p++ = ch; + } + + /* + * Save off the next command information, go back to the + * original start of the command. + */ + p = ecp->cp + 1; + ecp->cp = ecp->save_cmd; + ecp->save_cmd = p; + ecp->save_cmdlen = ecp->clen; + ecp->clen = ((ecp->save_cmd - ecp->cp) - 1) - discard; + + /* + * QUOTING NOTE: + * + * The "set tags" command historically used a backslash, not the + * user's literal next character, to escape whitespace. Handle + * it here instead of complicating the argv_exp3() code. Note, + * this isn't a particularly complex trap, and if backslashes were + * legal in set commands, this would have to be much more complicated. + */ + if (ecp->cmd == &cmds[C_SET]) { + for (p = ecp->cp, len = ecp->clen; len > 0; --len, ++p) + if (IS_ESCAPE(sp, ecp, *p) && len > 1) { + --len; + ++p; + } else if (*p == '\\') + *p = CH_LITERAL; + } + + /* + * Set the default addresses. It's an error to specify an address for + * a command that doesn't take them. If two addresses are specified + * for a command that only takes one, lose the first one. Two special + * cases here, some commands take 0 or 2 addresses. For most of them + * (the E_ADDR2_ALL flag), 0 defaults to the entire file. For one + * (the `!' command, the E_ADDR2_NONE flag), 0 defaults to no lines. + * + * Also, if the file is empty, some commands want to use an address of + * 0, i.e. the entire file is 0 to 0, and the default first address is + * 0. Otherwise, an entire file is 1 to N and the default line is 1. + * Note, we also add the E_ADDR_ZERO flag to the command flags, for the + * case where the 0 address is only valid if it's a default address. + * + * Also, set a flag if we set the default addresses. Some commands + * (ex: z) care if the user specified an address or if we just used + * the current cursor. + */ + switch (F_ISSET(ecp, E_ADDR1 | E_ADDR2 | E_ADDR2_ALL | E_ADDR2_NONE)) { + case E_ADDR1: /* One address: */ + switch (ecp->addrcnt) { + case 0: /* Default cursor/empty file. */ + ecp->addrcnt = 1; + F_SET(ecp, E_ADDR_DEF); + if (F_ISSET(ecp, E_ADDR_ZERODEF)) { + if (db_last(sp, &lno)) + goto err; + if (lno == 0) { + ecp->addr1.lno = 0; + F_SET(ecp, E_ADDR_ZERO); + } else + ecp->addr1.lno = sp->lno; + } else + ecp->addr1.lno = sp->lno; + ecp->addr1.cno = sp->cno; + break; + case 1: + break; + case 2: /* Lose the first address. */ + ecp->addrcnt = 1; + ecp->addr1 = ecp->addr2; + } + break; + case E_ADDR2_NONE: /* Zero/two addresses: */ + if (ecp->addrcnt == 0) /* Default to nothing. */ + break; + goto two_addr; + case E_ADDR2_ALL: /* Zero/two addresses: */ + if (ecp->addrcnt == 0) { /* Default entire/empty file. */ + F_SET(ecp, E_ADDR_DEF); + ecp->addrcnt = 2; + if (sp->ep == NULL) + ecp->addr2.lno = 0; + else if (db_last(sp, &ecp->addr2.lno)) + goto err; + if (F_ISSET(ecp, E_ADDR_ZERODEF) && + ecp->addr2.lno == 0) { + ecp->addr1.lno = 0; + F_SET(ecp, E_ADDR_ZERO); + } else + ecp->addr1.lno = 1; + ecp->addr1.cno = ecp->addr2.cno = 0; + F_SET(ecp, E_ADDR2_ALL); + break; + } + /* FALLTHROUGH */ + case E_ADDR2: /* Two addresses: */ +two_addr: switch (ecp->addrcnt) { + case 0: /* Default cursor/empty file. */ + ecp->addrcnt = 2; + F_SET(ecp, E_ADDR_DEF); + if (sp->lno == 1 && + F_ISSET(ecp, E_ADDR_ZERODEF)) { + if (db_last(sp, &lno)) + goto err; + if (lno == 0) { + ecp->addr1.lno = ecp->addr2.lno = 0; + F_SET(ecp, E_ADDR_ZERO); + } else + ecp->addr1.lno = + ecp->addr2.lno = sp->lno; + } else + ecp->addr1.lno = ecp->addr2.lno = sp->lno; + ecp->addr1.cno = ecp->addr2.cno = sp->cno; + break; + case 1: /* Default to first address. */ + ecp->addrcnt = 2; + ecp->addr2 = ecp->addr1; + break; + case 2: + break; + } + break; + default: + if (ecp->addrcnt) /* Error. */ + goto usage; + } + + /* + * !!! + * The ^D scroll command historically scrolled the value of the scroll + * option or to EOF. It was an error if the cursor was already at EOF. + * (Leading addresses were permitted, but were then ignored.) + */ + if (ecp->cmd == &cmds[C_SCROLL]) { + ecp->addrcnt = 2; + ecp->addr1.lno = sp->lno + 1; + ecp->addr2.lno = sp->lno + O_VAL(sp, O_SCROLL); + ecp->addr1.cno = ecp->addr2.cno = sp->cno; + if (db_last(sp, &lno)) + goto err; + if (lno != 0 && lno > sp->lno && ecp->addr2.lno > lno) + ecp->addr2.lno = lno; + } + + ecp->flagoff = 0; + for (np = ecp->cmd->syntax; *np != '\0'; ++np) { + /* + * The force flag is sensitive to leading whitespace, i.e. + * "next !" is different from "next!". Handle it before + * skipping leading s. + */ + if (*np == '!') { + if (ecp->clen > 0 && *ecp->cp == '!') { + ++ecp->cp; + --ecp->clen; + FL_SET(ecp->iflags, E_C_FORCE); + } + continue; + } + + /* Skip leading s. */ + for (; ecp->clen > 0; --ecp->clen, ++ecp->cp) + if (!cmdskip(*ecp->cp)) + break; + if (ecp->clen == 0) + break; + + switch (*np) { + case '1': /* +, -, #, l, p */ + /* + * !!! + * Historically, some flags were ignored depending + * on where they occurred in the command line. For + * example, in the command, ":3+++p--#", historic vi + * acted on the '#' flag, but ignored the '-' flags. + * It's unambiguous what the flags mean, so we just + * handle them regardless of the stupidity of their + * location. + */ + for (; ecp->clen; --ecp->clen, ++ecp->cp) + switch (*ecp->cp) { + case '+': + ++ecp->flagoff; + break; + case '-': + case '^': + --ecp->flagoff; + break; + case '#': + F_CLR(ecp, E_OPTNUM); + FL_SET(ecp->iflags, E_C_HASH); + exp->fdef |= E_C_HASH; + break; + case 'l': + FL_SET(ecp->iflags, E_C_LIST); + exp->fdef |= E_C_LIST; + break; + case 'p': + FL_SET(ecp->iflags, E_C_PRINT); + exp->fdef |= E_C_PRINT; + break; + default: + goto end_case1; + } +end_case1: break; + case '2': /* -, ., +, ^ */ + case '3': /* -, ., +, ^, = */ + for (; ecp->clen; --ecp->clen, ++ecp->cp) + switch (*ecp->cp) { + case '-': + FL_SET(ecp->iflags, E_C_DASH); + break; + case '.': + FL_SET(ecp->iflags, E_C_DOT); + break; + case '+': + FL_SET(ecp->iflags, E_C_PLUS); + break; + case '^': + FL_SET(ecp->iflags, E_C_CARAT); + break; + case '=': + if (*np == '3') { + FL_SET(ecp->iflags, E_C_EQUAL); + break; + } + /* FALLTHROUGH */ + default: + goto end_case23; + } +end_case23: break; + case 'b': /* buffer */ + /* + * !!! + * Historically, "d #" was a delete with a flag, not a + * delete into the '#' buffer. If the current command + * permits a flag, don't use one as a buffer. However, + * the 'l' and 'p' flags were legal buffer names in the + * historic ex, and were used as buffers, not flags. + */ + if ((ecp->cp[0] == '+' || ecp->cp[0] == '-' || + ecp->cp[0] == '^' || ecp->cp[0] == '#') && + strchr(np, '1') != NULL) + break; + /* + * !!! + * Digits can't be buffer names in ex commands, or the + * command "d2" would be a delete into buffer '2', and + * not a two-line deletion. + */ + if (!ISDIGIT(ecp->cp[0])) { + ecp->buffer = *ecp->cp; + ++ecp->cp; + --ecp->clen; + FL_SET(ecp->iflags, E_C_BUFFER); + } + break; + case 'c': /* count [01+a] */ + ++np; + /* Validate any signed value. */ + if (!ISDIGIT(*ecp->cp) && (*np != '+' || + (*ecp->cp != '+' && *ecp->cp != '-'))) + break; + /* If a signed value, set appropriate flags. */ + if (*ecp->cp == '-') + FL_SET(ecp->iflags, E_C_COUNT_NEG); + else if (*ecp->cp == '+') + FL_SET(ecp->iflags, E_C_COUNT_POS); + if ((nret = + nget_slong(<mp, ecp->cp, &t, 10)) != NUM_OK) { + ex_badaddr(sp, NULL, A_NOTSET, nret); + goto err; + } + if (ltmp == 0 && *np != '0') { + msgq(sp, M_ERR, "083|Count may not be zero"); + goto err; + } + ecp->clen -= (t - ecp->cp); + ecp->cp = t; + + /* + * Counts as address offsets occur in commands taking + * two addresses. Historic vi practice was to use + * the count as an offset from the *second* address. + * + * Set a count flag; some underlying commands (see + * join) do different things with counts than with + * line addresses. + */ + if (*np == 'a') { + ecp->addr1 = ecp->addr2; + ecp->addr2.lno = ecp->addr1.lno + ltmp - 1; + } else + ecp->count = ltmp; + FL_SET(ecp->iflags, E_C_COUNT); + break; + case 'f': /* file */ + if (argv_exp2(sp, ecp, ecp->cp, ecp->clen)) + goto err; + goto arg_cnt_chk; + case 'l': /* line */ + /* + * Get a line specification. + * + * If the line was a search expression, we may have + * changed state during the call, and we're now + * searching the file. Push ourselves onto the state + * stack. + */ + if (ex_line(sp, ecp, &cur, &isaddr, &tmp)) + goto rfail; + if (tmp) + goto err; + + /* Line specifications are always required. */ + if (!isaddr) { + msgq_wstr(sp, M_ERR, ecp->cp, + "084|%s: bad line specification"); + goto err; + } + /* + * The target line should exist for these commands, + * but 0 is legal for them as well. + */ + if (cur.lno != 0 && !db_exist(sp, cur.lno)) { + ex_badaddr(sp, NULL, A_EOF, NUM_OK); + goto err; + } + ecp->lineno = cur.lno; + break; + case 'S': /* string, file exp. */ + if (ecp->clen != 0) { + if (argv_exp1(sp, ecp, ecp->cp, + ecp->clen, ecp->cmd == &cmds[C_BANG])) + goto err; + goto addr_verify; + } + /* FALLTHROUGH */ + case 's': /* string */ + if (argv_exp0(sp, ecp, ecp->cp, ecp->clen)) + goto err; + goto addr_verify; + case 'W': /* word string */ + /* + * QUOTING NOTE: + * + * Literal next characters escape the following + * character. Quoting characters are stripped here + * since they are no longer useful. + * + * First there was the word. + */ + for (p = t = ecp->cp; + ecp->clen > 0; --ecp->clen, ++ecp->cp) { + ch = *ecp->cp; + if (IS_ESCAPE(sp, + ecp, ch) && ecp->clen > 1) { + --ecp->clen; + *p++ = *++ecp->cp; + } else if (cmdskip(ch)) { + ++ecp->cp; + --ecp->clen; + break; + } else + *p++ = ch; + } + if (argv_exp0(sp, ecp, t, p - t)) + goto err; + + /* Delete intervening whitespace. */ + for (; ecp->clen > 0; + --ecp->clen, ++ecp->cp) { + ch = *ecp->cp; + if (!cmdskip(ch)) + break; + } + if (ecp->clen == 0) + goto usage; + + /* Followed by the string. */ + for (p = t = ecp->cp; ecp->clen > 0; + --ecp->clen, ++ecp->cp, ++p) { + ch = *ecp->cp; + if (IS_ESCAPE(sp, + ecp, ch) && ecp->clen > 1) { + --ecp->clen; + *p = *++ecp->cp; + } else + *p = ch; + } + if (argv_exp0(sp, ecp, t, p - t)) + goto err; + goto addr_verify; + case 'w': /* word */ + if (argv_exp3(sp, ecp, ecp->cp, ecp->clen)) + goto err; +arg_cnt_chk: if (*++np != 'N') { /* N */ + /* + * If a number is specified, must either be + * 0 or that number, if optional, and that + * number, if required. + */ + tmp = *np - '0'; + if ((*++np != 'o' || exp->argsoff != 0) && + exp->argsoff != tmp) + goto usage; + } + goto addr_verify; + default: { + size_t nlen; + char *nstr; + + INT2CHAR(sp, ecp->cmd->name, STRLEN(ecp->cmd->name) + 1, + nstr, nlen); + msgq(sp, M_ERR, + "085|Internal syntax table error (%s: %s)", + nstr, KEY_NAME(sp, *np)); + } + } + } + + /* Skip trailing whitespace. */ + for (; ecp->clen > 0; --ecp->clen) { + ch = *ecp->cp++; + if (!cmdskip(ch)) + break; + } + + /* + * There shouldn't be anything left, and no more required fields, + * i.e neither 'l' or 'r' in the syntax string. + */ + if (ecp->clen != 0 || strpbrk(np, "lr")) { +usage: msgq(sp, M_ERR, "086|Usage: %s", ecp->cmd->usage); + goto err; + } + + /* + * Verify that the addresses are legal. Check the addresses here, + * because this is a place where all ex addresses pass through. + * (They don't all pass through ex_line(), for instance.) We're + * assuming that any non-existent line doesn't exist because it's + * past the end-of-file. That's a pretty good guess. + * + * If it's a "default vi command", an address of zero is okay. + */ +addr_verify: + switch (ecp->addrcnt) { + case 2: + /* + * Historic ex/vi permitted commands with counts to go past + * EOF. So, for example, if the file only had 5 lines, the + * ex command "1,6>" would fail, but the command ">300" + * would succeed. Since we don't want to have to make all + * of the underlying commands handle random line numbers, + * fix it here. + */ + if (ecp->addr2.lno == 0) { + if (!F_ISSET(ecp, E_ADDR_ZERO) && + (F_ISSET(sp, SC_EX) || + !F_ISSET(ecp, E_USELASTCMD))) { + ex_badaddr(sp, ecp->cmd, A_ZERO, NUM_OK); + goto err; + } + } else if (!db_exist(sp, ecp->addr2.lno)) { + if (FL_ISSET(ecp->iflags, E_C_COUNT)) { + if (db_last(sp, &lno)) + goto err; + ecp->addr2.lno = lno; + } else { + ex_badaddr(sp, NULL, A_EOF, NUM_OK); + goto err; + } + } + /* FALLTHROUGH */ + case 1: + if (ecp->addr1.lno == 0) { + if (!F_ISSET(ecp, E_ADDR_ZERO) && + (F_ISSET(sp, SC_EX) || + !F_ISSET(ecp, E_USELASTCMD))) { + ex_badaddr(sp, ecp->cmd, A_ZERO, NUM_OK); + goto err; + } + } else if (!db_exist(sp, ecp->addr1.lno)) { + ex_badaddr(sp, NULL, A_EOF, NUM_OK); + goto err; + } + break; + } + + /* + * If doing a default command and there's nothing left on the line, + * vi just moves to the line. For example, ":3" and ":'a,'b" just + * move to line 3 and line 'b, respectively, but ":3|" prints line 3. + * + * !!! + * In addition, IF THE LINE CHANGES, move to the first nonblank of + * the line. + * + * !!! + * This is done before the absolute mark gets set; historically, + * "/a/,/b/" did NOT set vi's absolute mark, but "/a/,/b/d" did. + */ + if ((F_ISSET(sp, SC_VI) || F_ISSET(ecp, E_NOPRDEF)) && + F_ISSET(ecp, E_USELASTCMD) && vi_address == 0) { + switch (ecp->addrcnt) { + case 2: + if (sp->lno != + (ecp->addr2.lno ? ecp->addr2.lno : 1)) { + sp->lno = + ecp->addr2.lno ? ecp->addr2.lno : 1; + sp->cno = 0; + (void)nonblank(sp, sp->lno, &sp->cno); + } + break; + case 1: + if (sp->lno != + (ecp->addr1.lno ? ecp->addr1.lno : 1)) { + sp->lno = + ecp->addr1.lno ? ecp->addr1.lno : 1; + sp->cno = 0; + (void)nonblank(sp, sp->lno, &sp->cno); + } + break; + } + ecp->cp = ecp->save_cmd; + ecp->clen = ecp->save_cmdlen; + goto loop; + } + + /* + * Set the absolute mark -- we have to set it for vi here, in case + * it's a compound command, e.g. ":5p|6" should set the absolute + * mark for vi. + */ + if (F_ISSET(ecp, E_ABSMARK)) { + cur.lno = sp->lno; + cur.cno = sp->cno; + F_CLR(ecp, E_ABSMARK); + if (mark_set(sp, ABSMARK1, &cur, 1)) + goto err; + } + +#if defined(DEBUG) && defined(COMLOG) + ex_comlog(sp, ecp); +#endif + /* Increment the command count if not called from vi. */ + if (F_ISSET(sp, SC_EX)) + ++sp->ccnt; + + /* + * If file state available, and not doing a global command, + * log the start of an action. + */ + if (sp->ep != NULL && !F_ISSET(sp, SC_EX_GLOBAL)) + (void)log_cursor(sp); + + /* + * !!! + * There are two special commands for the purposes of this code: the + * default command () or the scrolling commands (^D + * and ) as the first non- characters in the line. + * + * If this is the first command in the command line, we received the + * command from the ex command loop and we're talking to a tty, and + * and there's nothing else on the command line, and it's one of the + * special commands, we move back up to the previous line, and erase + * the prompt character with the output. Since ex runs in canonical + * mode, we don't have to do anything else, a has already + * been echoed by the tty driver. It's OK if vi calls us -- we won't + * be in ex mode so we'll do nothing. + */ + if (F_ISSET(ecp, E_NRSEP)) { + if (sp->ep != NULL && + F_ISSET(sp, SC_EX) && !F_ISSET(gp, G_SCRIPTED) && + (F_ISSET(ecp, E_USELASTCMD) || ecp->cmd == &cmds[C_SCROLL])) + gp->scr_ex_adjust(sp, EX_TERM_SCROLL); + F_CLR(ecp, E_NRSEP); + } + + /* + * Call the underlying function for the ex command. + * + * XXX + * Interrupts behave like errors, for now. + */ + if (ecp->cmd->fn(sp, ecp) || INTERRUPTED(sp)) { + if (F_ISSET(gp, G_SCRIPTED)) + F_SET(sp, SC_EXIT_FORCE); + goto err; + } + +#ifdef DEBUG + /* Make sure no function left global temporary space locked. */ + if (F_ISSET(gp, G_TMP_INUSE)) { + F_CLR(gp, G_TMP_INUSE); + msgq_wstr(sp, M_ERR, ecp->cmd->name, + "087|%s: temporary buffer not released"); + } +#endif + /* + * Ex displayed the number of lines modified immediately after each + * command, so the command "1,10d|1,10d" would display: + * + * 10 lines deleted + * 10 lines deleted + * + * + * Executing ex commands from vi only reported the final modified + * lines message -- that's wrong enough that we don't match it. + */ + if (F_ISSET(sp, SC_EX)) + mod_rpt(sp); + + /* + * Integrate any offset parsed by the underlying command, and make + * sure the referenced line exists. + * + * XXX + * May not match historic practice (which I've never been able to + * completely figure out.) For example, the '=' command from vi + * mode often got the offset wrong, and complained it was too large, + * but didn't seem to have a problem with the cursor. If anyone + * complains, ask them how it's supposed to work, they might know. + */ + if (sp->ep != NULL && ecp->flagoff) { + if (ecp->flagoff < 0) { + if (sp->lno <= -ecp->flagoff) { + msgq(sp, M_ERR, + "088|Flag offset to before line 1"); + goto err; + } + } else { + if (!NPFITS(MAX_REC_NUMBER, sp->lno, ecp->flagoff)) { + ex_badaddr(sp, NULL, A_NOTSET, NUM_OVER); + goto err; + } + if (!db_exist(sp, sp->lno + ecp->flagoff)) { + msgq(sp, M_ERR, + "089|Flag offset past end-of-file"); + goto err; + } + } + sp->lno += ecp->flagoff; + } + + /* + * If the command executed successfully, we may want to display a line + * based on the autoprint option or an explicit print flag. (Make sure + * that there's a line to display.) Also, the autoprint edit option is + * turned off for the duration of global commands. + */ + if (F_ISSET(sp, SC_EX) && sp->ep != NULL && sp->lno != 0) { + /* + * The print commands have already handled the `print' flags. + * If so, clear them. + */ + if (FL_ISSET(ecp->iflags, E_CLRFLAG)) + FL_CLR(ecp->iflags, E_C_HASH | E_C_LIST | E_C_PRINT); + + /* If hash set only because of the number option, discard it. */ + if (F_ISSET(ecp, E_OPTNUM)) + FL_CLR(ecp->iflags, E_C_HASH); + + /* + * If there was an explicit flag to display the new cursor line, + * or autoprint is set and a change was made, display the line. + * If any print flags were set use them, else default to print. + */ + LF_INIT(FL_ISSET(ecp->iflags, E_C_HASH | E_C_LIST | E_C_PRINT)); + if (!LF_ISSET(E_C_HASH | E_C_LIST | E_C_PRINT | E_NOAUTO) && + !F_ISSET(sp, SC_EX_GLOBAL) && + O_ISSET(sp, O_AUTOPRINT) && F_ISSET(ecp, E_AUTOPRINT)) + LF_INIT(E_C_PRINT); + + if (LF_ISSET(E_C_HASH | E_C_LIST | E_C_PRINT)) { + cur.lno = sp->lno; + cur.cno = 0; + (void)ex_print(sp, ecp, &cur, &cur, flags); + } + } + + /* + * If the command had an associated "+cmd", it has to be executed + * before we finish executing any more of this ex command. For + * example, consider a .exrc file that contains the following lines: + * + * :set all + * :edit +25 file.c|s/abc/ABC/|1 + * :3,5 print + * + * This can happen more than once -- the historic vi simply hung or + * dropped core, of course. Prepend the + command back into the + * current command and continue. We may have to add an additional + * character. We know that it will fit because we + * discarded at least one space and the + character. + */ + if (arg1_len != 0) { + /* + * If the last character of the + command was a + * character, it would be treated differently because of the + * append. Quote it, if necessary. + */ + if (IS_ESCAPE(sp, ecp, arg1[arg1_len - 1])) { + *--ecp->save_cmd = CH_LITERAL; + ++ecp->save_cmdlen; + } + + ecp->save_cmd -= arg1_len; + ecp->save_cmdlen += arg1_len; + MEMMOVE(ecp->save_cmd, arg1, arg1_len); + + /* + * Any commands executed from a +cmd are executed starting at + * the first column of the last line of the file -- NOT the + * first nonblank.) The main file startup code doesn't know + * that a +cmd was set, however, so it may have put us at the + * top of the file. (Note, this is safe because we must have + * switched files to get here.) + */ + F_SET(ecp, E_MOVETOEND); + } + + /* Update the current command. */ + ecp->cp = ecp->save_cmd; + ecp->clen = ecp->save_cmdlen; + + /* + * !!! + * If we've changed screens or underlying files, any pending global or + * v command, or @ buffer that has associated addresses, has to be + * discarded. This is historic practice for globals, and necessary for + * @ buffers that had associated addresses. + * + * Otherwise, if we've changed underlying files, it's not a problem, + * we continue with the rest of the ex command(s), operating on the + * new file. However, if we switch screens (either by exiting or by + * an explicit command), we have no way of knowing where to put output + * messages, and, since we don't control screens here, we could screw + * up the upper layers, (e.g. we could exit/reenter a screen multiple + * times). So, return and continue after we've got a new screen. + */ + if (F_ISSET(sp, SC_EXIT | SC_EXIT_FORCE | SC_FSWITCH | SC_SSWITCH)) { + at_found = gv_found = 0; + SLIST_FOREACH(ecp, sp->gp->ecq, q) + switch (ecp->agv_flags) { + case 0: + case AGV_AT_NORANGE: + break; + case AGV_AT: + if (!at_found) { + at_found = 1; + msgq(sp, M_ERR, + "090|@ with range running when the file/screen changed"); + } + break; + case AGV_GLOBAL: + case AGV_V: + if (!gv_found) { + gv_found = 1; + msgq(sp, M_ERR, + "091|Global/v command running when the file/screen changed"); + } + break; + default: + abort(); + } + if (at_found || gv_found) + goto discard; + if (F_ISSET(sp, SC_EXIT | SC_EXIT_FORCE | SC_SSWITCH)) + goto rsuccess; + } + + goto loop; + /* NOTREACHED */ + +err: /* + * On command failure, we discard keys and pending commands remaining, + * as well as any keys that were mapped and waiting. The save_cmdlen + * test is not necessarily correct. If we fail early enough we don't + * know if the entire string was a single command or not. Guess, as + * it's useful to know if commands other than the current one are being + * discarded. + */ + if (ecp->save_cmdlen == 0) + for (; ecp->clen; --ecp->clen) { + ch = *ecp->cp++; + if (IS_ESCAPE(sp, ecp, ch) && ecp->clen > 1) { + --ecp->clen; + ++ecp->cp; + } else if (ch == '\n' || ch == '|') { + if (ecp->clen > 1) + ecp->save_cmdlen = 1; + break; + } + } + if (ecp->save_cmdlen != 0 || SLIST_FIRST(gp->ecq) != &gp->excmd) { +discard: msgq(sp, M_BERR, + "092|Ex command failed: pending commands discarded"); + ex_discard(sp); + } + if (v_event_flush(sp, CH_MAPPED)) + msgq(sp, M_BERR, + "093|Ex command failed: mapped keys discarded"); + +rfail: tmp = 1; + if (0) +rsuccess: tmp = 0; + + /* Turn off any file name error information. */ + gp->if_name = NULL; + + /* Turn off the global bit. */ + F_CLR(sp, SC_EX_GLOBAL); + + return (tmp); +} + +/* + * ex_range -- + * Get a line range for ex commands, or perform a vi ex address search. + * + * PUBLIC: int ex_range(SCR *, EXCMD *, int *); + */ +int +ex_range(SCR *sp, EXCMD *ecp, int *errp) +{ + enum { ADDR_FOUND, ADDR_NEED, ADDR_NONE } addr; + GS *gp; + EX_PRIVATE *exp; + MARK m; + int isaddr; + + *errp = 0; + + /* + * Parse comma or semi-colon delimited line specs. + * + * Semi-colon delimiters update the current address to be the last + * address. For example, the command + * + * :3;/pattern/ecp->cp + * + * will search for pattern from line 3. In addition, if ecp->cp + * is not a valid command, the current line will be left at 3, not + * at the original address. + * + * Extra addresses are discarded, starting with the first. + * + * !!! + * If any addresses are missing, they default to the current line. + * This was historically true for both leading and trailing comma + * delimited addresses as well as for trailing semicolon delimited + * addresses. For consistency, we make it true for leading semicolon + * addresses as well. + */ + gp = sp->gp; + exp = EXP(sp); + for (addr = ADDR_NONE, ecp->addrcnt = 0; ecp->clen > 0;) + switch (*ecp->cp) { + case '%': /* Entire file. */ + /* Vi ex address searches didn't permit % signs. */ + if (F_ISSET(ecp, E_VISEARCH)) + goto ret; + + /* It's an error if the file is empty. */ + if (sp->ep == NULL) { + ex_badaddr(sp, NULL, A_EMPTY, NUM_OK); + *errp = 1; + return (0); + } + /* + * !!! + * A percent character addresses all of the lines in + * the file. Historically, it couldn't be followed by + * any other address. We do it as a text substitution + * for simplicity. POSIX 1003.2 is expected to follow + * this practice. + * + * If it's an empty file, the first line is 0, not 1. + */ + if (addr == ADDR_FOUND) { + ex_badaddr(sp, NULL, A_COMBO, NUM_OK); + *errp = 1; + return (0); + } + if (db_last(sp, &ecp->addr2.lno)) + return (1); + ecp->addr1.lno = ecp->addr2.lno == 0 ? 0 : 1; + ecp->addr1.cno = ecp->addr2.cno = 0; + ecp->addrcnt = 2; + addr = ADDR_FOUND; + ++ecp->cp; + --ecp->clen; + break; + case ',': /* Comma delimiter. */ + /* Vi ex address searches didn't permit commas. */ + if (F_ISSET(ecp, E_VISEARCH)) + goto ret; + /* FALLTHROUGH */ + case ';': /* Semi-colon delimiter. */ + if (sp->ep == NULL) { + ex_badaddr(sp, NULL, A_EMPTY, NUM_OK); + *errp = 1; + return (0); + } + if (addr != ADDR_FOUND) + switch (ecp->addrcnt) { + case 0: + ecp->addr1.lno = sp->lno; + ecp->addr1.cno = sp->cno; + ecp->addrcnt = 1; + break; + case 2: + ecp->addr1 = ecp->addr2; + /* FALLTHROUGH */ + case 1: + ecp->addr2.lno = sp->lno; + ecp->addr2.cno = sp->cno; + ecp->addrcnt = 2; + break; + } + if (*ecp->cp == ';') + switch (ecp->addrcnt) { + case 0: + abort(); + /* NOTREACHED */ + case 1: + sp->lno = ecp->addr1.lno; + sp->cno = ecp->addr1.cno; + break; + case 2: + sp->lno = ecp->addr2.lno; + sp->cno = ecp->addr2.cno; + break; + } + addr = ADDR_NEED; + /* FALLTHROUGH */ + case ' ': /* Whitespace. */ + case '\t': /* Whitespace. */ + ++ecp->cp; + --ecp->clen; + break; + default: + /* Get a line specification. */ + if (ex_line(sp, ecp, &m, &isaddr, errp)) + return (1); + if (*errp) + return (0); + if (!isaddr) + goto ret; + if (addr == ADDR_FOUND) { + ex_badaddr(sp, NULL, A_COMBO, NUM_OK); + *errp = 1; + return (0); + } + switch (ecp->addrcnt) { + case 0: + ecp->addr1 = m; + ecp->addrcnt = 1; + break; + case 1: + ecp->addr2 = m; + ecp->addrcnt = 2; + break; + case 2: + ecp->addr1 = ecp->addr2; + ecp->addr2 = m; + break; + } + addr = ADDR_FOUND; + break; + } + + /* + * !!! + * Vi ex address searches are indifferent to order or trailing + * semi-colons. + */ +ret: if (F_ISSET(ecp, E_VISEARCH)) + return (0); + + if (addr == ADDR_NEED) + switch (ecp->addrcnt) { + case 0: + ecp->addr1.lno = sp->lno; + ecp->addr1.cno = sp->cno; + ecp->addrcnt = 1; + break; + case 2: + ecp->addr1 = ecp->addr2; + /* FALLTHROUGH */ + case 1: + ecp->addr2.lno = sp->lno; + ecp->addr2.cno = sp->cno; + ecp->addrcnt = 2; + break; + } + + if (ecp->addrcnt == 2 && ecp->addr2.lno < ecp->addr1.lno) { + msgq(sp, M_ERR, + "094|The second address is smaller than the first"); + *errp = 1; + } + return (0); +} + +/* + * ex_line -- + * Get a single line address specifier. + * + * The way the "previous context" mark worked was that any "non-relative" + * motion set it. While ex/vi wasn't totally consistent about this, ANY + * numeric address, search pattern, '$', or mark reference in an address + * was considered non-relative, and set the value. Which should explain + * why we're hacking marks down here. The problem was that the mark was + * only set if the command was called, i.e. we have to set a flag and test + * it later. + * + * XXX + * This is probably still not exactly historic practice, although I think + * it's fairly close. + */ +static int +ex_line(SCR *sp, EXCMD *ecp, MARK *mp, int *isaddrp, int *errp) +{ + enum nresult nret; + EX_PRIVATE *exp; + GS *gp; + long total, val; + int isneg; + int (*sf)(SCR *, MARK *, MARK *, CHAR_T *, size_t, CHAR_T **, u_int); + CHAR_T *endp; + + gp = sp->gp; + exp = EXP(sp); + + *isaddrp = *errp = 0; + F_CLR(ecp, E_DELTA); + + /* No addresses permitted until a file has been read in. */ + if (sp->ep == NULL && STRCHR(L("$0123456789'\\/?.+-^"), *ecp->cp)) { + ex_badaddr(sp, NULL, A_EMPTY, NUM_OK); + *errp = 1; + return (0); + } + + switch (*ecp->cp) { + case '$': /* Last line in the file. */ + *isaddrp = 1; + F_SET(ecp, E_ABSMARK); + + mp->cno = 0; + if (db_last(sp, &mp->lno)) + return (1); + ++ecp->cp; + --ecp->clen; + break; /* Absolute line number. */ + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + *isaddrp = 1; + F_SET(ecp, E_ABSMARK); + + if ((nret = nget_slong(&val, ecp->cp, &endp, 10)) != NUM_OK) { + ex_badaddr(sp, NULL, A_NOTSET, nret); + *errp = 1; + return (0); + } + if (!NPFITS(MAX_REC_NUMBER, 0, val)) { + ex_badaddr(sp, NULL, A_NOTSET, NUM_OVER); + *errp = 1; + return (0); + } + mp->lno = val; + mp->cno = 0; + ecp->clen -= (endp - ecp->cp); + ecp->cp = endp; + break; + case '\'': /* Use a mark. */ + *isaddrp = 1; + F_SET(ecp, E_ABSMARK); + + if (ecp->clen == 1) { + msgq(sp, M_ERR, "095|No mark name supplied"); + *errp = 1; + return (0); + } + if (mark_get(sp, ecp->cp[1], mp, M_ERR)) { + *errp = 1; + return (0); + } + ecp->cp += 2; + ecp->clen -= 2; + break; + case '\\': /* Search: forward/backward. */ + /* + * !!! + * I can't find any difference between // and \/ or between + * ?? and \?. Mark Horton doesn't remember there being any + * difference. C'est la vie. + */ + if (ecp->clen < 2 || + (ecp->cp[1] != '/' && ecp->cp[1] != '?')) { + msgq(sp, M_ERR, "096|\\ not followed by / or ?"); + *errp = 1; + return (0); + } + ++ecp->cp; + --ecp->clen; + sf = ecp->cp[0] == '/' ? f_search : b_search; + goto search; + case '/': /* Search forward. */ + sf = f_search; + goto search; + case '?': /* Search backward. */ + sf = b_search; + +search: mp->lno = sp->lno; + mp->cno = sp->cno; + if (sf(sp, mp, mp, ecp->cp, ecp->clen, &endp, + SEARCH_MSG | SEARCH_PARSE | SEARCH_SET | + (F_ISSET(ecp, E_SEARCH_WMSG) ? SEARCH_WMSG : 0))) { + *errp = 1; + return (0); + } + + /* Fix up the command pointers. */ + ecp->clen -= (endp - ecp->cp); + ecp->cp = endp; + + *isaddrp = 1; + F_SET(ecp, E_ABSMARK); + break; + case '.': /* Current position. */ + *isaddrp = 1; + mp->cno = sp->cno; + + /* If an empty file, then '.' is 0, not 1. */ + if (sp->lno == 1) { + if (db_last(sp, &mp->lno)) + return (1); + if (mp->lno != 0) + mp->lno = 1; + } else + mp->lno = sp->lno; + + /* + * !!! + * Historically, . was the same as .+, i.e. + * the '+' could be omitted. (This feature is found in ed + * as well.) + */ + if (ecp->clen > 1 && ISDIGIT(ecp->cp[1])) + *ecp->cp = '+'; + else { + ++ecp->cp; + --ecp->clen; + } + break; + } + + /* Skip trailing s. */ + for (; ecp->clen > 0 && + cmdskip(ecp->cp[0]); ++ecp->cp, --ecp->clen); + + /* + * Evaluate any offset. If no address yet found, the offset + * is relative to ".". + */ + total = 0; + if (ecp->clen != 0 && (ISDIGIT(ecp->cp[0]) || + ecp->cp[0] == '+' || ecp->cp[0] == '-' || + ecp->cp[0] == '^')) { + if (!*isaddrp) { + *isaddrp = 1; + mp->lno = sp->lno; + mp->cno = sp->cno; + } + /* + * Evaluate an offset, defined as: + * + * [+-^]*[]*[0-9]* + * + * The rough translation is any number of signs, optionally + * followed by numbers, or a number by itself, all + * separated. + * + * !!! + * All address offsets were additive, e.g. "2 2 3p" was the + * same as "7p", or, "/ZZZ/ 2" was the same as "/ZZZ/+2". + * Note, however, "2 /ZZZ/" was an error. It was also legal + * to insert signs without numbers, so "3 - 2" was legal, and + * equal to 4. + * + * !!! + * Offsets were historically permitted for any line address, + * e.g. the command "1,2 copy 2 2 2 2" copied lines 1,2 after + * line 8. + * + * !!! + * Offsets were historically permitted for search commands, + * and handled as addresses: "/pattern/2 2 2" was legal, and + * referenced the 6th line after pattern. + */ + F_SET(ecp, E_DELTA); + for (;;) { + for (; ecp->clen > 0 && cmdskip(ecp->cp[0]); + ++ecp->cp, --ecp->clen); + if (ecp->clen == 0 || (!ISDIGIT(ecp->cp[0]) && + ecp->cp[0] != '+' && ecp->cp[0] != '-' && + ecp->cp[0] != '^')) + break; + if (!ISDIGIT(ecp->cp[0]) && + !ISDIGIT(ecp->cp[1])) { + total += ecp->cp[0] == '+' ? 1 : -1; + --ecp->clen; + ++ecp->cp; + } else { + if (ecp->cp[0] == '-' || + ecp->cp[0] == '^') { + ++ecp->cp; + --ecp->clen; + isneg = 1; + } else + isneg = 0; + + /* Get a signed long, add it to the total. */ + if ((nret = nget_slong(&val, + ecp->cp, &endp, 10)) != NUM_OK || + (nret = NADD_SLONG(sp, + total, val)) != NUM_OK) { + ex_badaddr(sp, NULL, A_NOTSET, nret); + *errp = 1; + return (0); + } + total += isneg ? -val : val; + ecp->clen -= (endp - ecp->cp); + ecp->cp = endp; + } + } + } + + /* + * Any value less than 0 is an error. Make sure that the new value + * will fit into a recno_t. + */ + if (*isaddrp && total != 0) { + if (total < 0) { + if (-total > mp->lno) { + msgq(sp, M_ERR, + "097|Reference to a line number less than 0"); + *errp = 1; + return (0); + } + } else + if (!NPFITS(MAX_REC_NUMBER, mp->lno, total)) { + ex_badaddr(sp, NULL, A_NOTSET, NUM_OVER); + *errp = 1; + return (0); + } + mp->lno += total; + } + return (0); +} + + +/* + * ex_load -- + * Load up the next command, which may be an @ buffer or global command. + */ +static int +ex_load(SCR *sp) +{ + GS *gp; + EXCMD *ecp; + RANGE *rp; + + F_CLR(sp, SC_EX_GLOBAL); + + /* + * Lose any exhausted commands. We know that the first command + * can't be an AGV command, which makes things a bit easier. + */ + for (gp = sp->gp;;) { + ecp = SLIST_FIRST(gp->ecq); + + /* Discard the allocated source name as requested. */ + if (F_ISSET(ecp, E_NAMEDISCARD)) + free(ecp->if_name); + + /* + * If we're back to the original structure, leave it around, + * since we've returned to the beginning of the command stack. + */ + if (ecp == &gp->excmd) { + ecp->if_name = NULL; + return (0); + } + + /* + * ecp->clen will be 0 for the first discarded command, but + * may not be 0 for subsequent ones, e.g. if the original + * command was ":g/xx/@a|s/b/c/", then when we discard the + * command pushed on the stack by the @a, we have to resume + * the global command which included the substitute command. + */ + if (ecp->clen != 0) + return (0); + + /* + * If it's an @, global or v command, we may need to continue + * the command on a different line. + */ + if (FL_ISSET(ecp->agv_flags, AGV_ALL)) { + /* Discard any exhausted ranges. */ + while ((rp = TAILQ_FIRST(ecp->rq)) != NULL) + if (rp->start > rp->stop) { + TAILQ_REMOVE(ecp->rq, rp, q); + free(rp); + } else + break; + + /* If there's another range, continue with it. */ + if (rp != NULL) + break; + + /* If it's a global/v command, fix up the last line. */ + if (FL_ISSET(ecp->agv_flags, + AGV_GLOBAL | AGV_V) && ecp->range_lno != OOBLNO) { + if (db_exist(sp, ecp->range_lno)) + sp->lno = ecp->range_lno; + else { + if (db_last(sp, &sp->lno)) + return (1); + if (sp->lno == 0) + sp->lno = 1; + } + } + free(ecp->o_cp); + } + + /* Discard the EXCMD. */ + SLIST_REMOVE_HEAD(gp->ecq, q); + free(ecp); + } + + /* + * We only get here if it's an active @, global or v command. Set + * the current line number, and get a new copy of the command for + * the parser. Note, the original pointer almost certainly moved, + * so we have play games. + */ + ecp->cp = ecp->o_cp; + MEMCPY(ecp->cp, ecp->cp + ecp->o_clen, ecp->o_clen); + ecp->clen = ecp->o_clen; + ecp->range_lno = sp->lno = rp->start++; + + if (FL_ISSET(ecp->agv_flags, AGV_GLOBAL | AGV_V)) + F_SET(sp, SC_EX_GLOBAL); + return (0); +} + +/* + * ex_discard -- + * Discard any pending ex commands. + */ +static int +ex_discard(SCR *sp) +{ + GS *gp; + EXCMD *ecp; + RANGE *rp; + + /* + * We know the first command can't be an AGV command, so we don't + * process it specially. We do, however, nail the command itself. + */ + for (gp = sp->gp;;) { + ecp = SLIST_FIRST(gp->ecq); + if (F_ISSET(ecp, E_NAMEDISCARD)) + free(ecp->if_name); + /* Reset the last command without dropping it. */ + if (ecp == &gp->excmd) + break; + if (FL_ISSET(ecp->agv_flags, AGV_ALL)) { + while ((rp = TAILQ_FIRST(ecp->rq)) != NULL) { + TAILQ_REMOVE(ecp->rq, rp, q); + free(rp); + } + free(ecp->o_cp); + } + SLIST_REMOVE_HEAD(gp->ecq, q); + free(ecp); + } + + ecp->if_name = NULL; + ecp->clen = 0; + return (0); +} + +/* + * ex_unknown -- + * Display an unknown command name. + */ +static void +ex_unknown(SCR *sp, CHAR_T *cmd, size_t len) +{ + size_t blen; + CHAR_T *bp; + + GET_SPACE_GOTOW(sp, bp, blen, len + 1); + bp[len] = '\0'; + MEMCPY(bp, cmd, len); + msgq_wstr(sp, M_ERR, bp, "098|The %s command is unknown"); + FREE_SPACEW(sp, bp, blen); + +alloc_err: + return; +} + +/* + * ex_is_abbrev - + * The vi text input routine needs to know if ex thinks this is an + * [un]abbreviate command, so it can turn off abbreviations. See + * the usual ranting in the vi/v_txt_ev.c:txt_abbrev() routine. + * + * PUBLIC: int ex_is_abbrev(CHAR_T *, size_t); + */ +int +ex_is_abbrev(CHAR_T *name, size_t len) +{ + EXCMDLIST const *cp; + + return ((cp = ex_comm_search(name, len)) != NULL && + (cp == &cmds[C_ABBR] || cp == &cmds[C_UNABBREVIATE])); +} + +/* + * ex_is_unmap - + * The vi text input routine needs to know if ex thinks this is an + * unmap command, so it can turn off input mapping. See the usual + * ranting in the vi/v_txt_ev.c:txt_unmap() routine. + * + * PUBLIC: int ex_is_unmap(CHAR_T *, size_t); + */ +int +ex_is_unmap(CHAR_T *name, size_t len) +{ + EXCMDLIST const *cp; + + /* + * The command the vi input routines are really interested in + * is "unmap!", not just unmap. + */ + if (name[len - 1] != '!') + return (0); + --len; + return ((cp = ex_comm_search(name, len)) != NULL && + cp == &cmds[C_UNMAP]); +} + +/* + * ex_comm_search -- + * Search for a command name. + */ +static EXCMDLIST const * +ex_comm_search(CHAR_T *name, size_t len) +{ + EXCMDLIST const *cp; + + for (cp = cmds; cp->name != NULL; ++cp) { + if (cp->name[0] > name[0]) + return (NULL); + if (cp->name[0] != name[0]) + continue; + if (!MEMCMP(name, cp->name, len)) + return (cp); + } + return (NULL); +} + +/* + * ex_badaddr -- + * Display a bad address message. + * + * PUBLIC: void ex_badaddr + * PUBLIC: (SCR *, EXCMDLIST const *, enum badaddr, enum nresult); + */ +void +ex_badaddr(SCR *sp, const EXCMDLIST *cp, enum badaddr ba, enum nresult nret) +{ + recno_t lno; + + switch (nret) { + case NUM_OK: + break; + case NUM_ERR: + msgq(sp, M_SYSERR, NULL); + return; + case NUM_OVER: + msgq(sp, M_ERR, "099|Address value overflow"); + return; + case NUM_UNDER: + msgq(sp, M_ERR, "100|Address value underflow"); + return; + } + + /* + * When encountering an address error, tell the user if there's no + * underlying file, that's the real problem. + */ + if (sp->ep == NULL) { + ex_wemsg(sp, cp ? cp->name : NULL, EXM_NOFILEYET); + return; + } + + switch (ba) { + case A_COMBO: + msgq(sp, M_ERR, "101|Illegal address combination"); + break; + case A_EOF: + if (db_last(sp, &lno)) + return; + if (lno != 0) { + msgq(sp, M_ERR, + "102|Illegal address: only %lu lines in the file", + (u_long)lno); + break; + } + /* FALLTHROUGH */ + case A_EMPTY: + msgq(sp, M_ERR, "103|Illegal address: the file is empty"); + break; + case A_NOTSET: + abort(); + /* NOTREACHED */ + case A_ZERO: + msgq_wstr(sp, M_ERR, cp->name, + "104|The %s command doesn't permit an address of 0"); + break; + } + return; +} + +#if defined(DEBUG) && defined(COMLOG) +/* + * ex_comlog -- + * Log ex commands. + */ +static void +ex_comlog(sp, ecp) + SCR *sp; + EXCMD *ecp; +{ + TRACE(sp, "ecmd: "WS, ecp->cmd->name); + if (ecp->addrcnt > 0) { + TRACE(sp, " a1 %d", ecp->addr1.lno); + if (ecp->addrcnt > 1) + TRACE(sp, " a2: %d", ecp->addr2.lno); + } + if (ecp->lineno) + TRACE(sp, " line %d", ecp->lineno); + if (ecp->flags) + TRACE(sp, " flags 0x%x", ecp->flags); + if (FL_ISSET(ecp->iflags, E_C_BUFFER)) + TRACE(sp, " buffer "WC, ecp->buffer); + if (ecp->argc) { + int cnt; + for (cnt = 0; cnt < ecp->argc; ++cnt) + TRACE(sp, " arg %d: {"WS"}", cnt, ecp->argv[cnt]->bp); + } + TRACE(sp, "\n"); +} +#endif Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex.h =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex.h (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex.h (revision 366308) @@ -0,0 +1,231 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#define PROMPTCHAR ':' /* Prompt using a colon. */ + +typedef struct _excmdlist { /* Ex command table structure. */ + CHAR_T *name; /* Command name, underlying function. */ + int (*fn)(SCR *, EXCMD *); + +#define E_ADDR1 0x00000001 /* One address. */ +#define E_ADDR2 0x00000002 /* Two addresses. */ +#define E_ADDR2_ALL 0x00000004 /* Zero/two addresses; zero == all. */ +#define E_ADDR2_NONE 0x00000008 /* Zero/two addresses; zero == none. */ +#define E_ADDR_ZERO 0x00000010 /* 0 is a legal addr1. */ +#define E_ADDR_ZERODEF 0x00000020 /* 0 is default addr1 of empty files. */ +#define E_AUTOPRINT 0x00000040 /* Command always sets autoprint. */ +#define E_CLRFLAG 0x00000080 /* Clear the print (#, l, p) flags. */ +#define E_NEWSCREEN 0x00000100 /* Create a new screen. */ +#define E_SECURE 0x00000200 /* Permission denied if O_SECURE set. */ +#define E_VIONLY 0x00000400 /* Meaningful only in vi. */ +#define __INUSE1 0xfffff800 /* Same name space as EX_PRIVATE. */ + u_int16_t flags; + + char *syntax; /* Syntax script. */ + char *usage; /* Usage line. */ + char *help; /* Help line. */ +} EXCMDLIST; + +#define MAXCMDNAMELEN 12 /* Longest command name. */ +extern EXCMDLIST const cmds[]; /* Table of ex commands. */ + +/* + * !!! + * QUOTING NOTE: + * + * Historically, .exrc files and EXINIT variables could only use ^V as an + * escape character, neither ^Q or a user specified character worked. We + * enforce that here, just in case someone depends on it. + */ +#define IS_ESCAPE(sp, cmdp, ch) \ + (F_ISSET(cmdp, E_VLITONLY) ? \ + (ch) == CH_LITERAL : KEY_VAL(sp, ch) == K_VLNEXT) + +#define IS_SHELLMETA(sp, ch) \ + ((ch) <= CHAR_MAX && strchr(O_STR(sp, O_SHELLMETA), ch) != NULL) + +/* + * File state must be checked for each command -- any ex command may be entered + * at any time, and most of them won't work well if a file hasn't yet been read + * in. Historic vi generally took the easy way out and dropped core. + */ +#define NEEDFILE(sp, cmdp) do { \ + if ((sp)->ep == NULL) { \ + ex_wemsg(sp, (cmdp)->cmd->name, EXM_NOFILEYET); \ + return (1); \ + } \ +} while (0) + +/* Range structures for global and @ commands. */ +typedef struct _range RANGE; +struct _range { /* Global command range. */ + TAILQ_ENTRY(_range) q; /* Linked list of ranges. */ + recno_t start, stop; /* Start/stop of the range. */ +}; + +/* Ex command structure. */ +struct _excmd { + SLIST_ENTRY(_excmd) q; /* Linked list of commands. */ + + char *if_name; /* Associated file. */ + recno_t if_lno; /* Associated line number. */ + + /* Clear the structure for the ex parser. */ +#define CLEAR_EX_PARSER(cmdp) \ + memset(&((cmdp)->cp), 0, ((char *)&(cmdp)->flags - \ + (char *)&((cmdp)->cp)) + sizeof((cmdp)->flags)) + + CHAR_T *cp; /* Current command text. */ + size_t clen; /* Current command length. */ + + CHAR_T *save_cmd; /* Remaining command. */ + size_t save_cmdlen; /* Remaining command length. */ + + EXCMDLIST const *cmd; /* Command: entry in command table. */ + EXCMDLIST rcmd; /* Command: table entry/replacement. */ + + TAILQ_HEAD(_rh, _range) rq[1]; /* @/global range: linked list. */ + recno_t range_lno; /* @/global range: set line number. */ + CHAR_T *o_cp; /* Original @/global command. */ + size_t o_clen; /* Original @/global command length. */ +#define AGV_AT 0x01 /* @ buffer execution. */ +#define AGV_AT_NORANGE 0x02 /* @ buffer execution without range. */ +#define AGV_GLOBAL 0x04 /* global command. */ +#define AGV_V 0x08 /* v command. */ +#define AGV_ALL (AGV_AT | AGV_AT_NORANGE | AGV_GLOBAL | AGV_V) + u_int8_t agv_flags; + + /* Clear the structure before each ex command. */ +#define CLEAR_EX_CMD(cmdp) do { \ + u_int32_t L__f = F_ISSET(cmdp, E_PRESERVE); \ + memset(&((cmdp)->buffer), 0, ((char *)&(cmdp)->flags - \ + (char *)&((cmdp)->buffer)) + sizeof((cmdp)->flags)); \ + F_SET(cmdp, L__f); \ +} while (0) + + CHAR_T buffer; /* Command: named buffer. */ + recno_t lineno; /* Command: line number. */ + long count; /* Command: signed count. */ + long flagoff; /* Command: signed flag offset. */ + int addrcnt; /* Command: addresses (0, 1 or 2). */ + MARK addr1; /* Command: 1st address. */ + MARK addr2; /* Command: 2nd address. */ + ARGS **argv; /* Command: array of arguments. */ + int argc; /* Command: count of arguments. */ + +#define E_C_BUFFER 0x00001 /* Buffer name specified. */ +#define E_C_CARAT 0x00002 /* ^ flag. */ +#define E_C_COUNT 0x00004 /* Count specified. */ +#define E_C_COUNT_NEG 0x00008 /* Count was signed negative. */ +#define E_C_COUNT_POS 0x00010 /* Count was signed positive. */ +#define E_C_DASH 0x00020 /* - flag. */ +#define E_C_DOT 0x00040 /* . flag. */ +#define E_C_EQUAL 0x00080 /* = flag. */ +#define E_C_FORCE 0x00100 /* ! flag. */ +#define E_C_HASH 0x00200 /* # flag. */ +#define E_C_LIST 0x00400 /* l flag. */ +#define E_C_PLUS 0x00800 /* + flag. */ +#define E_C_PRINT 0x01000 /* p flag. */ + u_int16_t iflags; /* User input information. */ + +#define __INUSE2 0x000007ff /* Same name space as EXCMDLIST. */ +#define E_BLIGNORE 0x00000800 /* Ignore blank lines. */ +#define E_NAMEDISCARD 0x00001000 /* Free/discard the name. */ +#define E_NOAUTO 0x00002000 /* Don't do autoprint output. */ +#define E_NOPRDEF 0x00004000 /* Don't print as default. */ +#define E_NRSEP 0x00008000 /* Need to line adjust ex output. */ +#define E_OPTNUM 0x00010000 /* Number edit option affected. */ +#define E_VLITONLY 0x00020000 /* Use ^V quoting only. */ +#define E_PRESERVE 0x0003f800 /* Bits to preserve across commands. */ + +#define E_ABSMARK 0x00040000 /* Set the absolute mark. */ +#define E_ADDR_DEF 0x00080000 /* Default addresses used. */ +#define E_DELTA 0x00100000 /* Search address with delta. */ +#define E_MODIFY 0x00200000 /* File name expansion modified arg. */ +#define E_MOVETOEND 0x00400000 /* Move to the end of the file first. */ +#define E_NEWLINE 0x00800000 /* Found ending . */ +#define E_SEARCH_WMSG 0x01000000 /* Display search-wrapped message. */ +#define E_USELASTCMD 0x02000000 /* Use the last command. */ +#define E_VISEARCH 0x04000000 /* It's really a vi search command. */ + u_int32_t flags; /* Current flags. */ +}; + +/* Ex private, per-screen memory. */ +typedef struct _ex_private { + /* Tag file list. */ + TAILQ_HEAD(_tagfh, _tagf) tagfq[1]; + TAILQ_HEAD(_tqh, _tagq) tq[1]; /* Tag queue. */ + SLIST_HEAD(_csch, _csc) cscq[1];/* Cscope connection list. */ + CHAR_T *tag_last; /* Saved last tag string. */ + + CHAR_T *lastbcomm; /* Last bang command. */ + + ARGS **args; /* Command: argument list. */ + int argscnt; /* Command: argument list count. */ + int argsoff; /* Command: offset into arguments. */ + + u_int32_t fdef; /* Saved E_C_* default command flags. */ + + char *ibp; /* File line input buffer. */ + size_t ibp_len; /* File line input buffer length. */ + CONVWIN ibcw; /* File line input conversion buffer. */ + + /* + * Buffers for the ex output. The screen/vi support doesn't do any + * character buffering of any kind. We do it here so that we're not + * calling the screen output routines on every character. + * + * XXX + * Change to grow dynamically. + */ + char obp[1024]; /* Ex output buffer. */ + size_t obp_len; /* Ex output buffer length. */ + +#define EXP_CSCINIT 0x01 /* Cscope initialized. */ + u_int8_t flags; +} EX_PRIVATE; +#define EXP(sp) ((EX_PRIVATE *)((sp)->ex_private)) + +/* + * Filter actions: + * + * FILTER_BANG !: filter text through the utility. + * FILTER_RBANG !: read from the utility (without stdin). + * FILTER_READ read: read from the utility (with stdin). + * FILTER_WRITE write: write to the utility, display its output. + */ +enum filtertype { FILTER_BANG, FILTER_RBANG, FILTER_READ, FILTER_WRITE }; + +/* Ex common error messages. */ +typedef enum { + EXM_EMPTYBUF, /* Empty buffer. */ + EXM_FILECOUNT, /* Too many file names. */ + EXM_NOCANON, /* No terminal interface. */ + EXM_NOCANON_F, /* EXM_NOCANO: filter version. */ + EXM_NOFILEYET, /* Illegal until a file read in. */ + EXM_NOPREVBUF, /* No previous buffer specified. */ + EXM_NOPREVRE, /* No previous RE specified. */ + EXM_NOSUSPEND, /* No suspension. */ + EXM_SECURE, /* Illegal if secure edit option set. */ + EXM_SECURE_F, /* EXM_SECURE: filter version */ + EXM_USAGE /* Standard usage message. */ +} exm_t; + +/* Ex address error types. */ +enum badaddr { A_COMBO, A_EMPTY, A_EOF, A_NOTSET, A_ZERO }; + +/* Ex common tag error messages. */ +typedef enum { + TAG_BADLNO, /* Tag line doesn't exist. */ + TAG_EMPTY, /* Tags stack is empty. */ + TAG_SEARCH /* Tags search pattern wasn't found. */ +} tagmsg_t; + +#include "ex_def.h" +#include "extern.h" Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_argv.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_argv.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_argv.c (revision 366308) @@ -0,0 +1,918 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../common/common.h" + +static int argv_alloc(SCR *, size_t); +static int argv_comp(const void *, const void *); +static int argv_fexp(SCR *, EXCMD *, + CHAR_T *, size_t, CHAR_T *, size_t *, CHAR_T **, size_t *, int); +static int argv_sexp(SCR *, CHAR_T **, size_t *, size_t *); +static int argv_flt_user(SCR *, EXCMD *, CHAR_T *, size_t); + +/* + * argv_init -- + * Build a prototype arguments list. + * + * PUBLIC: int argv_init(SCR *, EXCMD *); + */ +int +argv_init(SCR *sp, EXCMD *excp) +{ + EX_PRIVATE *exp; + + exp = EXP(sp); + exp->argsoff = 0; + argv_alloc(sp, 1); + + excp->argv = exp->args; + excp->argc = exp->argsoff; + return (0); +} + +/* + * argv_exp0 -- + * Append a string to the argument list. + * + * PUBLIC: int argv_exp0(SCR *, EXCMD *, CHAR_T *, size_t); + */ +int +argv_exp0(SCR *sp, EXCMD *excp, CHAR_T *cmd, size_t cmdlen) +{ + EX_PRIVATE *exp; + + exp = EXP(sp); + argv_alloc(sp, cmdlen); + MEMCPY(exp->args[exp->argsoff]->bp, cmd, cmdlen); + exp->args[exp->argsoff]->bp[cmdlen] = '\0'; + exp->args[exp->argsoff]->len = cmdlen; + ++exp->argsoff; + excp->argv = exp->args; + excp->argc = exp->argsoff; + return (0); +} + +/* + * argv_exp1 -- + * Do file name expansion on a string, and append it to the + * argument list. + * + * PUBLIC: int argv_exp1(SCR *, EXCMD *, CHAR_T *, size_t, int); + */ +int +argv_exp1(SCR *sp, EXCMD *excp, CHAR_T *cmd, size_t cmdlen, int is_bang) +{ + EX_PRIVATE *exp; + size_t blen, len; + CHAR_T *p, *t, *bp; + + GET_SPACE_RETW(sp, bp, blen, 512); + + len = 0; + exp = EXP(sp); + if (argv_fexp(sp, excp, cmd, cmdlen, bp, &len, &bp, &blen, is_bang)) { + FREE_SPACEW(sp, bp, blen); + return (1); + } + + /* If it's empty, we're done. */ + if (len != 0) { + for (p = bp, t = bp + len; p < t; ++p) + if (!cmdskip(*p)) + break; + if (p == t) + goto ret; + } else + goto ret; + + (void)argv_exp0(sp, excp, bp, len); + +ret: FREE_SPACEW(sp, bp, blen); + return (0); +} + +/* + * argv_exp2 -- + * Do file name and shell expansion on a string, and append it to + * the argument list. + * + * PUBLIC: int argv_exp2(SCR *, EXCMD *, CHAR_T *, size_t); + */ +int +argv_exp2(SCR *sp, EXCMD *excp, CHAR_T *cmd, size_t cmdlen) +{ + size_t blen, len, n; + int rval; + CHAR_T *bp, *p; + + GET_SPACE_RETW(sp, bp, blen, 512); + +#define SHELLECHO L("echo ") +#define SHELLOFFSET (SIZE(SHELLECHO) - 1) + MEMCPY(bp, SHELLECHO, SHELLOFFSET); + p = bp + SHELLOFFSET; + len = SHELLOFFSET; + +#if defined(DEBUG) && 0 + TRACE(sp, "file_argv: {%.*s}\n", (int)cmdlen, cmd); +#endif + + if (argv_fexp(sp, excp, cmd, cmdlen, p, &len, &bp, &blen, 0)) { + rval = 1; + goto err; + } + +#if defined(DEBUG) && 0 + TRACE(sp, "before shell: %d: {%s}\n", len, bp); +#endif + + /* + * Do shell word expansion -- it's very, very hard to figure out what + * magic characters the user's shell expects. Historically, it was a + * union of v7 shell and csh meta characters. We match that practice + * by default, so ":read \%" tries to read a file named '%'. It would + * make more sense to pass any special characters through the shell, + * but then, if your shell was csh, the above example will behave + * differently in nvi than in vi. If you want to get other characters + * passed through to your shell, change the "meta" option. + */ + if (opts_empty(sp, O_SHELL, 1) || opts_empty(sp, O_SHELLMETA, 1)) + n = 0; + else { + p = bp + SHELLOFFSET; + n = len - SHELLOFFSET; + for (; n > 0; --n, ++p) + if (IS_SHELLMETA(sp, *p)) + break; + } + + /* + * If we found a meta character in the string, fork a shell to expand + * it. Unfortunately, this is comparatively slow. Historically, it + * didn't matter much, since users don't enter meta characters as part + * of pathnames that frequently. The addition of filename completion + * broke that assumption because it's easy to use. To increase the + * completion performance, nvi used to have an internal routine to + * handle "filename*". However, the shell special characters does not + * limit to "shellmeta", so such a hack breaks historic practice. + * After it all, we split the completion logic out from here. + */ + switch (n) { + case 0: + p = bp + SHELLOFFSET; + len -= SHELLOFFSET; + rval = argv_exp3(sp, excp, p, len); + break; + default: + if (argv_sexp(sp, &bp, &blen, &len)) { + rval = 1; + goto err; + } + p = bp; + rval = argv_exp3(sp, excp, p, len); + break; + } + +err: FREE_SPACEW(sp, bp, blen); + return (rval); +} + +/* + * argv_exp3 -- + * Take a string and break it up into an argv, which is appended + * to the argument list. + * + * PUBLIC: int argv_exp3(SCR *, EXCMD *, CHAR_T *, size_t); + */ +int +argv_exp3(SCR *sp, EXCMD *excp, CHAR_T *cmd, size_t cmdlen) +{ + EX_PRIVATE *exp; + size_t len; + int ch, off; + CHAR_T *ap, *p; + + for (exp = EXP(sp); cmdlen > 0; ++exp->argsoff) { + /* Skip any leading whitespace. */ + for (; cmdlen > 0; --cmdlen, ++cmd) { + ch = *cmd; + if (!cmdskip(ch)) + break; + } + if (cmdlen == 0) + break; + + /* + * Determine the length of this whitespace delimited + * argument. + * + * QUOTING NOTE: + * + * Skip any character preceded by the user's quoting + * character. + */ + for (ap = cmd, len = 0; cmdlen > 0; ++cmd, --cmdlen, ++len) { + ch = *cmd; + if (IS_ESCAPE(sp, excp, ch) && cmdlen > 1) { + ++cmd; + --cmdlen; + } else if (cmdskip(ch)) + break; + } + + /* + * Copy the argument into place. + * + * QUOTING NOTE: + * + * Lose quote chars. + */ + argv_alloc(sp, len); + off = exp->argsoff; + exp->args[off]->len = len; + for (p = exp->args[off]->bp; len > 0; --len, *p++ = *ap++) + if (IS_ESCAPE(sp, excp, *ap)) + ++ap; + *p = '\0'; + } + excp->argv = exp->args; + excp->argc = exp->argsoff; + +#if defined(DEBUG) && 0 + for (cnt = 0; cnt < exp->argsoff; ++cnt) + TRACE(sp, "arg %d: {%s}\n", cnt, exp->argv[cnt]); +#endif + return (0); +} + +/* + * argv_flt_ex -- + * Filter the ex commands with a prefix, and append the results to + * the argument list. + * + * PUBLIC: int argv_flt_ex(SCR *, EXCMD *, CHAR_T *, size_t); + */ +int +argv_flt_ex(SCR *sp, EXCMD *excp, CHAR_T *cmd, size_t cmdlen) +{ + EX_PRIVATE *exp; + EXCMDLIST const *cp; + int off; + size_t len; + + exp = EXP(sp); + + for (off = exp->argsoff, cp = cmds; cp->name != NULL; ++cp) { + len = STRLEN(cp->name); + if (cmdlen > 0 && + (cmdlen > len || MEMCMP(cmd, cp->name, cmdlen))) + continue; + + /* Copy the matched ex command name. */ + argv_alloc(sp, len + 1); + MEMCPY(exp->args[exp->argsoff]->bp, cp->name, len + 1); + exp->args[exp->argsoff]->len = len; + ++exp->argsoff; + excp->argv = exp->args; + excp->argc = exp->argsoff; + } + + return (0); +} + +/* + * argv_flt_user -- + * Filter the ~user list on the system with a prefix, and append + * the results to the argument list. + */ +static int +argv_flt_user(SCR *sp, EXCMD *excp, CHAR_T *uname, size_t ulen) +{ + EX_PRIVATE *exp; + struct passwd *pw; + int off; + char *np; + size_t len, nlen; + + exp = EXP(sp); + off = exp->argsoff; + + /* The input must come with a leading '~'. */ + INT2CHAR(sp, uname + 1, ulen - 1, np, nlen); + if ((np = v_strdup(sp, np, nlen)) == NULL) + return (1); + + setpwent(); + while ((pw = getpwent()) != NULL) { + len = strlen(pw->pw_name); + if (nlen > 0 && + (nlen > len || memcmp(np, pw->pw_name, nlen))) + continue; + + /* Copy '~' + the matched user name. */ + CHAR2INT(sp, pw->pw_name, len + 1, uname, ulen); + argv_alloc(sp, ulen + 1); + exp->args[exp->argsoff]->bp[0] = '~'; + MEMCPY(exp->args[exp->argsoff]->bp + 1, uname, ulen); + exp->args[exp->argsoff]->len = ulen; + ++exp->argsoff; + excp->argv = exp->args; + excp->argc = exp->argsoff; + } + endpwent(); + free(np); + + qsort(exp->args + off, exp->argsoff - off, sizeof(ARGS *), argv_comp); + return (0); +} + +/* + * argv_fexp -- + * Do file name and bang command expansion. + */ +static int +argv_fexp(SCR *sp, EXCMD *excp, CHAR_T *cmd, size_t cmdlen, CHAR_T *p, size_t *lenp, CHAR_T **bpp, size_t *blenp, int is_bang) +{ + EX_PRIVATE *exp; + char *t; + size_t blen, len, off, tlen; + CHAR_T *bp; + CHAR_T *wp; + size_t wlen; + + /* Replace file name characters. */ + for (bp = *bpp, blen = *blenp, len = *lenp; cmdlen > 0; --cmdlen, ++cmd) + switch (*cmd) { + case '!': + if (!is_bang) + goto ins_ch; + exp = EXP(sp); + if (exp->lastbcomm == NULL) { + msgq(sp, M_ERR, + "115|No previous command to replace \"!\""); + return (1); + } + len += tlen = STRLEN(exp->lastbcomm); + off = p - bp; + ADD_SPACE_RETW(sp, bp, blen, len); + p = bp + off; + MEMCPY(p, exp->lastbcomm, tlen); + p += tlen; + F_SET(excp, E_MODIFY); + break; + case '%': + if ((t = sp->frp->name) == NULL) { + msgq(sp, M_ERR, + "116|No filename to substitute for %%"); + return (1); + } + tlen = strlen(t); + len += tlen; + off = p - bp; + ADD_SPACE_RETW(sp, bp, blen, len); + p = bp + off; + CHAR2INT(sp, t, tlen, wp, wlen); + MEMCPY(p, wp, wlen); + p += wlen; + F_SET(excp, E_MODIFY); + break; + case '#': + if ((t = sp->alt_name) == NULL) { + msgq(sp, M_ERR, + "117|No filename to substitute for #"); + return (1); + } + len += tlen = strlen(t); + off = p - bp; + ADD_SPACE_RETW(sp, bp, blen, len); + p = bp + off; + CHAR2INT(sp, t, tlen, wp, wlen); + MEMCPY(p, wp, wlen); + p += wlen; + F_SET(excp, E_MODIFY); + break; + case '\\': + /* + * QUOTING NOTE: + * + * Strip any backslashes that protected the file + * expansion characters. + */ + if (cmdlen > 1 && + (cmd[1] == '%' || cmd[1] == '#' || cmd[1] == '!')) { + ++cmd; + --cmdlen; + } + /* FALLTHROUGH */ + default: +ins_ch: ++len; + off = p - bp; + ADD_SPACE_RETW(sp, bp, blen, len); + p = bp + off; + *p++ = *cmd; + } + + /* Nul termination. */ + ++len; + off = p - bp; + ADD_SPACE_RETW(sp, bp, blen, len); + p = bp + off; + *p = '\0'; + + /* Return the new string length, buffer, buffer length. */ + *lenp = len - 1; + *bpp = bp; + *blenp = blen; + return (0); +} + +/* + * argv_alloc -- + * Make more space for arguments. + */ +static int +argv_alloc(SCR *sp, size_t len) +{ + ARGS *ap; + EX_PRIVATE *exp; + int cnt, off; + + /* + * Allocate room for another argument, always leaving + * enough room for an ARGS structure with a length of 0. + */ +#define INCREMENT 20 + exp = EXP(sp); + off = exp->argsoff; + if (exp->argscnt == 0 || off + 2 >= exp->argscnt - 1) { + cnt = exp->argscnt + INCREMENT; + REALLOC(sp, exp->args, ARGS **, cnt * sizeof(ARGS *)); + if (exp->args == NULL) { + (void)argv_free(sp); + goto mem; + } + memset(&exp->args[exp->argscnt], 0, INCREMENT * sizeof(ARGS *)); + exp->argscnt = cnt; + } + + /* First argument. */ + if (exp->args[off] == NULL) { + CALLOC(sp, exp->args[off], 1, sizeof(ARGS)); + if (exp->args[off] == NULL) + goto mem; + } + + /* First argument buffer. */ + ap = exp->args[off]; + ap->len = 0; + if (ap->blen < len + 1) { + ap->blen = len + 1; + REALLOC(sp, ap->bp, CHAR_T *, ap->blen * sizeof(CHAR_T)); + if (ap->bp == NULL) { + ap->bp = NULL; + ap->blen = 0; + F_CLR(ap, A_ALLOCATED); +mem: msgq(sp, M_SYSERR, NULL); + return (1); + } + F_SET(ap, A_ALLOCATED); + } + + /* Second argument. */ + if (exp->args[++off] == NULL) { + CALLOC(sp, exp->args[off], 1, sizeof(ARGS)); + if (exp->args[off] == NULL) + goto mem; + } + /* 0 length serves as end-of-argument marker. */ + exp->args[off]->len = 0; + return (0); +} + +/* + * argv_free -- + * Free up argument structures. + * + * PUBLIC: int argv_free(SCR *); + */ +int +argv_free(SCR *sp) +{ + EX_PRIVATE *exp; + int off; + + exp = EXP(sp); + if (exp->args != NULL) { + for (off = 0; off < exp->argscnt; ++off) { + if (exp->args[off] == NULL) + continue; + if (F_ISSET(exp->args[off], A_ALLOCATED)) + free(exp->args[off]->bp); + free(exp->args[off]); + } + free(exp->args); + } + exp->args = NULL; + exp->argscnt = 0; + exp->argsoff = 0; + return (0); +} + +/* + * argv_flt_path -- + * Find all file names matching the prefix and append them to the + * argument list. + * + * PUBLIC: int argv_flt_path(SCR *, EXCMD *, CHAR_T *, size_t); + */ +int +argv_flt_path(SCR *sp, EXCMD *excp, CHAR_T *path, size_t plen) +{ + struct dirent *dp; + DIR *dirp; + EX_PRIVATE *exp; + int off; + size_t dlen, len, nlen; + CHAR_T *dname; + CHAR_T *p, *np, *n; + char *name, *tp, *epd = NULL; + CHAR_T *wp; + size_t wlen; + + exp = EXP(sp); + + /* Set up the name and length for comparison. */ + if ((path = v_wstrdup(sp, path, plen)) == NULL) + return (1); + if ((p = STRRCHR(path, '/')) == NULL) { + if (*path == '~') { + int rc; + + /* Filter ~user list instead. */ + rc = argv_flt_user(sp, excp, path, plen); + free(path); + return (rc); + } + dname = L("."); + dlen = 0; + np = path; + } else { + if (p == path) { + dname = L("/"); + dlen = 1; + } else { + *p = '\0'; + dname = path; + dlen = p - path; + } + np = p + 1; + } + + INT2CHAR(sp, dname, dlen + 1, tp, nlen); + if ((epd = expanduser(tp)) != NULL) + tp = epd; + if ((dirp = opendir(tp)) == NULL) { + free(epd); + free(path); + return (1); + } + free(epd); + + INT2CHAR(sp, np, STRLEN(np), tp, nlen); + if ((name = v_strdup(sp, tp, nlen)) == NULL) { + free(path); + return (1); + } + + for (off = exp->argsoff; (dp = readdir(dirp)) != NULL;) { + if (nlen == 0) { + if (dp->d_name[0] == '.') + continue; +#ifdef HAVE_DIRENT_D_NAMLEN + len = dp->d_namlen; +#else + len = strlen(dp->d_name); +#endif + } else { +#ifdef HAVE_DIRENT_D_NAMLEN + len = dp->d_namlen; +#else + len = strlen(dp->d_name); +#endif + if (len < nlen || memcmp(dp->d_name, name, nlen)) + continue; + } + + /* Directory + name + slash + null. */ + CHAR2INT(sp, dp->d_name, len + 1, wp, wlen); + argv_alloc(sp, dlen + wlen + 1); + n = exp->args[exp->argsoff]->bp; + if (dlen != 0) { + MEMCPY(n, dname, dlen); + n += dlen; + if (dlen > 1 || dname[0] != '/') + *n++ = '/'; + exp->args[exp->argsoff]->len = dlen + 1; + } + MEMCPY(n, wp, wlen); + exp->args[exp->argsoff]->len += wlen - 1; + ++exp->argsoff; + excp->argv = exp->args; + excp->argc = exp->argsoff; + } + closedir(dirp); + free(name); + free(path); + + qsort(exp->args + off, exp->argsoff - off, sizeof(ARGS *), argv_comp); + return (0); +} + +/* + * argv_comp -- + * Alphabetic comparison. + */ +static int +argv_comp(const void *a, const void *b) +{ + return (STRCMP((*(ARGS **)a)->bp, (*(ARGS **)b)->bp)); +} + +/* + * argv_sexp -- + * Fork a shell, pipe a command through it, and read the output into + * a buffer. + */ +static int +argv_sexp(SCR *sp, CHAR_T **bpp, size_t *blenp, size_t *lenp) +{ + enum { SEXP_ERR, SEXP_EXPANSION_ERR, SEXP_OK } rval; + FILE *ifp; + pid_t pid; + size_t blen, len; + int ch, std_output[2]; + CHAR_T *bp, *p; + char *sh, *sh_path; + char *np; + size_t nlen; + + /* Secure means no shell access. */ + if (O_ISSET(sp, O_SECURE)) { + msgq(sp, M_ERR, +"289|Shell expansions not supported when the secure edit option is set"); + return (1); + } + + sh_path = O_STR(sp, O_SHELL); + if ((sh = strrchr(sh_path, '/')) == NULL) + sh = sh_path; + else + ++sh; + + /* Local copies of the buffer variables. */ + bp = *bpp; + blen = *blenp; + + /* + * There are two different processes running through this code, named + * the utility (the shell) and the parent. The utility reads standard + * input and writes standard output and standard error output. The + * parent writes to the utility, reads its standard output and ignores + * its standard error output. Historically, the standard error output + * was discarded by vi, as it produces a lot of noise when file patterns + * don't match. + * + * The parent reads std_output[0], and the utility writes std_output[1]. + */ + ifp = NULL; + std_output[0] = std_output[1] = -1; + if (pipe(std_output) < 0) { + msgq(sp, M_SYSERR, "pipe"); + return (1); + } + if ((ifp = fdopen(std_output[0], "r")) == NULL) { + msgq(sp, M_SYSERR, "fdopen"); + goto err; + } + + /* + * Do the minimal amount of work possible, the shell is going to run + * briefly and then exit. We sincerely hope. + */ + switch (pid = vfork()) { + case -1: /* Error. */ + msgq(sp, M_SYSERR, "vfork"); +err: if (ifp != NULL) + (void)fclose(ifp); + else if (std_output[0] != -1) + close(std_output[0]); + if (std_output[1] != -1) + close(std_output[0]); + return (1); + case 0: /* Utility. */ + /* Redirect stdout to the write end of the pipe. */ + (void)dup2(std_output[1], STDOUT_FILENO); + + /* Close the utility's file descriptors. */ + (void)close(std_output[0]); + (void)close(std_output[1]); + (void)close(STDERR_FILENO); + + /* + * XXX + * Assume that all shells have -c. + */ + INT2CHAR(sp, bp, STRLEN(bp)+1, np, nlen); + execl(sh_path, sh, "-c", np, (char *)NULL); + msgq_str(sp, M_SYSERR, sh_path, "118|Error: execl: %s"); + _exit(127); + default: /* Parent. */ + /* Close the pipe ends the parent won't use. */ + (void)close(std_output[1]); + break; + } + + /* + * Copy process standard output into a buffer. + * + * !!! + * Historic vi apparently discarded leading \n and \r's from + * the shell output stream. We don't on the grounds that any + * shell that does that is broken. + */ + for (p = bp, len = 0, ch = EOF; + (ch = GETC(ifp)) != EOF; *p++ = ch, blen-=sizeof(CHAR_T), ++len) + if (blen < 5) { + ADD_SPACE_GOTOW(sp, bp, *blenp, *blenp * 2); + p = bp + len; + blen = *blenp - len; + } + + /* Delete the final newline, nul terminate the string. */ + if (p > bp && (p[-1] == '\n' || p[-1] == '\r')) { + --p; + --len; + } + *p = '\0'; + *lenp = len; + *bpp = bp; /* *blenp is already updated. */ + + if (ferror(ifp)) + goto ioerr; + if (fclose(ifp)) { +ioerr: msgq_str(sp, M_ERR, sh, "119|I/O error: %s"); +alloc_err: rval = SEXP_ERR; + } else + rval = SEXP_OK; + + /* + * Wait for the process. If the shell process fails (e.g., "echo $q" + * where q wasn't a defined variable) or if the returned string has + * no characters or only blank characters, (e.g., "echo $5"), complain + * that the shell expansion failed. We can't know for certain that's + * the error, but it's a good guess, and it matches historic practice. + * This won't catch "echo foo_$5", but that's not a common error and + * historic vi didn't catch it either. + */ + if (proc_wait(sp, (long)pid, sh, 1, 0)) + rval = SEXP_EXPANSION_ERR; + + for (p = bp; len; ++p, --len) + if (!cmdskip(*p)) + break; + if (len == 0) + rval = SEXP_EXPANSION_ERR; + + if (rval == SEXP_EXPANSION_ERR) + msgq(sp, M_ERR, "304|Shell expansion failed"); + + return (rval == SEXP_OK ? 0 : 1); +} + +/* + * argv_esc -- + * Escape a string into an ex and shell argument. + * + * PUBLIC: CHAR_T *argv_esc(SCR *, EXCMD *, CHAR_T *, size_t); + */ +CHAR_T * +argv_esc(SCR *sp, EXCMD *excp, CHAR_T *str, size_t len) +{ + size_t blen, off; + CHAR_T *bp, *p; + int ch; + + GET_SPACE_GOTOW(sp, bp, blen, len + 1); + + /* + * Leaving the first '~' unescaped causes the user to need a + * "./" prefix to edit a file which really starts with a '~'. + * However, the file completion happens to not work for these + * files without the prefix. + * + * All ex expansion characters, "!%#", are double escaped. + */ + for (p = bp; len > 0; ++str, --len) { + ch = *str; + off = p - bp; + if (blen / sizeof(CHAR_T) - off < 3) { + ADD_SPACE_GOTOW(sp, bp, blen, off + 3); + p = bp + off; + } + if (cmdskip(ch) || ch == '\n' || + IS_ESCAPE(sp, excp, ch)) /* Ex. */ + *p++ = CH_LITERAL; + else switch (ch) { + case '~': /* ~user. */ + if (p != bp) + *p++ = '\\'; + break; + case '+': /* Ex +cmd. */ + if (p == bp) + *p++ = '\\'; + break; + case '!': case '%': case '#': /* Ex exp. */ + *p++ = '\\'; + *p++ = '\\'; + break; + case ',': case '-': case '.': case '/': /* Safe. */ + case ':': case '=': case '@': case '_': + break; + default: /* Unsafe. */ + if (isascii(ch) && !isalnum(ch)) + *p++ = '\\'; + } + *p++ = ch; + } + *p = '\0'; + + return bp; + +alloc_err: + return NULL; +} + +/* + * argv_uesc -- + * Unescape an escaped ex and shell argument. + * + * PUBLIC: CHAR_T *argv_uesc(SCR *, EXCMD *, CHAR_T *, size_t); + */ +CHAR_T * +argv_uesc(SCR *sp, EXCMD *excp, CHAR_T *str, size_t len) +{ + size_t blen; + CHAR_T *bp, *p; + + GET_SPACE_GOTOW(sp, bp, blen, len + 1); + + for (p = bp; len > 0; ++str, --len) { + if (IS_ESCAPE(sp, excp, *str)) { + if (--len < 1) + break; + ++str; + } else if (*str == '\\') { + if (--len < 1) + break; + ++str; + + /* Check for double escaping. */ + if (*str == '\\' && len > 1) + switch (str[1]) { + case '!': case '%': case '#': + ++str; + --len; + } + } + *p++ = *str; + } + *p = '\0'; + + return bp; + +alloc_err: + return NULL; +} Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_argv.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_bang.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_bang.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_bang.c (revision 366308) @@ -0,0 +1,187 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "../common/common.h" +#include "../vi/vi.h" + +/* + * ex_bang -- :[line [,line]] ! command + * + * Pass the rest of the line after the ! character to the program named by + * the O_SHELL option. + * + * Historical vi did NOT do shell expansion on the arguments before passing + * them, only file name expansion. This means that the O_SHELL program got + * "$t" as an argument if that is what the user entered. Also, there's a + * special expansion done for the bang command. Any exclamation points in + * the user's argument are replaced by the last, expanded ! command. + * + * There's some fairly amazing slop in this routine to make the different + * ways of getting here display the right things. It took a long time to + * get it right (wrong?), so be careful. + * + * PUBLIC: int ex_bang(SCR *, EXCMD *); + */ +int +ex_bang(SCR *sp, EXCMD *cmdp) +{ + enum filtertype ftype; + ARGS *ap; + EX_PRIVATE *exp; + MARK rm; + recno_t lno; + int rval; + const char *msg; + char *np; + size_t nlen; + + ap = cmdp->argv[0]; + if (ap->len == 0) { + ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE); + return (1); + } + + /* Set the "last bang command" remembered value. */ + exp = EXP(sp); + free(exp->lastbcomm); + if ((exp->lastbcomm = v_wstrdup(sp, ap->bp, ap->len)) == NULL) { + msgq(sp, M_SYSERR, NULL); + return (1); + } + + /* + * If the command was modified by the expansion, it was historically + * redisplayed. + */ + if (F_ISSET(cmdp, E_MODIFY) && !F_ISSET(sp, SC_EX_SILENT)) { + /* + * Display the command if modified. Historic ex/vi displayed + * the command if it was modified due to file name and/or bang + * expansion. If piping lines in vi, it would be immediately + * overwritten by any error or line change reporting. + */ + if (F_ISSET(sp, SC_VI)) + vs_update(sp, "!", ap->bp); + else { + (void)ex_printf(sp, "!"WS"\n", ap->bp); + (void)ex_fflush(sp); + } + } + + /* + * If no addresses were specified, run the command. If there's an + * underlying file, it's been modified and autowrite is set, write + * the file back. If the file has been modified, autowrite is not + * set and the warn option is set, tell the user about the file. + */ + if (cmdp->addrcnt == 0) { + msg = NULL; + if (sp->ep != NULL && F_ISSET(sp->ep, F_MODIFIED)) { + if (O_ISSET(sp, O_AUTOWRITE)) { + if (file_aw(sp, FS_ALL)) + return (0); + } else if (O_ISSET(sp, O_WARN) && + !F_ISSET(sp, SC_EX_SILENT)) + msg = msg_cat(sp, + "303|File modified since last write.", + NULL); + } + + /* If we're still in a vi screen, move out explicitly. */ + INT2CHAR(sp, ap->bp, ap->len+1, np, nlen); + (void)ex_exec_proc(sp, + cmdp, np, msg, !F_ISSET(sp, SC_EX | SC_SCR_EXWROTE)); + } + + /* + * If addresses were specified, pipe lines from the file through the + * command. + * + * Historically, vi lines were replaced by both the stdout and stderr + * lines of the command, but ex lines by only the stdout lines. This + * makes no sense to me, so nvi makes it consistent for both, and + * matches vi's historic behavior. + */ + else { + NEEDFILE(sp, cmdp); + + /* Autoprint is set historically, even if the command fails. */ + F_SET(cmdp, E_AUTOPRINT); + + /* + * !!! + * Historical vi permitted "!!" in an empty file. When this + * happens, we arrive here with two addresses of 1,1 and a + * bad attitude. The simple solution is to turn it into a + * FILTER_READ operation, with the exception that stdin isn't + * opened for the utility, and the cursor position isn't the + * same. The only historic glitch (I think) is that we don't + * put an empty line into the default cut buffer, as historic + * vi did. Imagine, if you can, my disappointment. + */ + ftype = FILTER_BANG; + if (cmdp->addr1.lno == 1 && cmdp->addr2.lno == 1) { + if (db_last(sp, &lno)) + return (1); + if (lno == 0) { + cmdp->addr1.lno = cmdp->addr2.lno = 0; + ftype = FILTER_RBANG; + } + } + rval = ex_filter(sp, cmdp, + &cmdp->addr1, &cmdp->addr2, &rm, ap->bp, ftype); + + /* + * If in vi mode, move to the first nonblank. + * + * !!! + * Historic vi wasn't consistent in this area -- if you used + * a forward motion it moved to the first nonblank, but if you + * did a backward motion it didn't. And, if you followed a + * backward motion with a forward motion, it wouldn't move to + * the nonblank for either. Going to the nonblank generally + * seems more useful and consistent, so we do it. + */ + sp->lno = rm.lno; + if (F_ISSET(sp, SC_VI)) { + sp->cno = 0; + (void)nonblank(sp, sp->lno, &sp->cno); + } else + sp->cno = rm.cno; + } + + /* Ex terminates with a bang, even if the command fails. */ + if (!F_ISSET(sp, SC_VI) && !F_ISSET(sp, SC_EX_SILENT)) + (void)ex_puts(sp, "!\n"); + + /* Apply expandtab to the new text */ + if (O_ISSET(sp, O_EXPANDTAB)) + ex_retab(sp, cmdp); + + /* + * XXX + * The ! commands never return an error, so that autoprint always + * happens in the ex parser. + */ + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_bang.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_cscope.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_cscope.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_cscope.c (revision 366308) @@ -0,0 +1,1086 @@ +/*- + * Copyright (c) 1994, 1996 + * Rob Mayoff. All rights reserved. + * Copyright (c) 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../common/common.h" +#include "pathnames.h" +#include "tag.h" + +#define CSCOPE_DBFILE "cscope.out" +#define CSCOPE_PATHS "cscope.tpath" + +/* + * 0name find all uses of name + * 1name find definition of name + * 2name find all function calls made from name + * 3name find callers of name + * 4string find text string (cscope 12.9) + * 4name find assignments to name (cscope 13.3) + * 5pattern change pattern -- NOT USED + * 6pattern find pattern + * 7name find files with name as substring + * 8name find files #including name + */ +#define FINDHELP "\ +find c|d|e|f|g|i|s|t buffer|pattern\n\ + c: find callers of name\n\ + d: find all function calls made from name\n\ + e: find pattern\n\ + f: find files with name as substring\n\ + g: find definition of name\n\ + i: find files #including name\n\ + s: find all uses of name\n\ + t: find assignments to name" + +static int cscope_add(SCR *, EXCMD *, CHAR_T *); +static int cscope_find(SCR *, EXCMD*, CHAR_T *); +static int cscope_help(SCR *, EXCMD *, CHAR_T *); +static int cscope_kill(SCR *, EXCMD *, CHAR_T *); +static int cscope_reset(SCR *, EXCMD *, CHAR_T *); + +typedef struct _cc { + char *name; + int (*function)(SCR *, EXCMD *, CHAR_T *); + char *help_msg; + char *usage_msg; +} CC; + +static CC const cscope_cmds[] = { + { "add", cscope_add, + "Add a new cscope database", "add file | directory" }, + { "find", cscope_find, + "Query the databases for a pattern", FINDHELP }, + { "help", cscope_help, + "Show help for cscope commands", "help [command]" }, + { "kill", cscope_kill, + "Kill a cscope connection", "kill number" }, + { "reset", cscope_reset, + "Discard all current cscope connections", "reset" }, + { NULL } +}; + +static TAGQ *create_cs_cmd(SCR *, char *, size_t *); +static int csc_help(SCR *, char *); +static void csc_file(SCR *, + CSC *, char *, char **, size_t *, int *); +static int get_paths(SCR *, CSC *); +static CC const *lookup_ccmd(char *); +static int parse(SCR *, CSC *, TAGQ *, int *); +static int read_prompt(SCR *, CSC *); +static int run_cscope(SCR *, CSC *, char *); +static int start_cscopes(SCR *, EXCMD *); +static int terminate(SCR *, CSC *, int); + +/* + * ex_cscope -- + * Perform an ex cscope. + * + * PUBLIC: int ex_cscope(SCR *, EXCMD *); + */ +int +ex_cscope(SCR *sp, EXCMD *cmdp) +{ + CC const *ccp; + EX_PRIVATE *exp; + int i; + CHAR_T *cmd; + CHAR_T *p; + char *np; + size_t nlen; + + /* Initialize the default cscope directories. */ + exp = EXP(sp); + if (!F_ISSET(exp, EXP_CSCINIT) && start_cscopes(sp, cmdp)) + return (1); + F_SET(exp, EXP_CSCINIT); + + /* Skip leading whitespace. */ + for (p = cmdp->argv[0]->bp, i = cmdp->argv[0]->len; i > 0; --i, ++p) + if (!isspace(*p)) + break; + if (i == 0) + goto usage; + + /* Skip the command to any arguments. */ + for (cmd = p; i > 0; --i, ++p) + if (isspace(*p)) + break; + if (*p != '\0') { + *p++ = '\0'; + for (; *p && isspace(*p); ++p); + } + + INT2CHAR(sp, cmd, STRLEN(cmd) + 1, np, nlen); + if ((ccp = lookup_ccmd(np)) == NULL) { +usage: msgq(sp, M_ERR, "309|Use \"cscope help\" for help"); + return (1); + } + + /* Call the underlying function. */ + return (ccp->function(sp, cmdp, p)); +} + +/* + * start_cscopes -- + * Initialize the cscope package. + */ +static int +start_cscopes(SCR *sp, EXCMD *cmdp) +{ + size_t blen, len; + char *bp, *cscopes, *p, *t; + CHAR_T *wp; + size_t wlen; + + /* + * EXTENSION #1: + * + * If the CSCOPE_DIRS environment variable is set, we treat it as a + * list of cscope directories that we're using, similar to the tags + * edit option. + * + * XXX + * This should probably be an edit option, although that implies that + * we start/stop cscope processes periodically, instead of once when + * the editor starts. + */ + if ((cscopes = getenv("CSCOPE_DIRS")) == NULL) + return (0); + len = strlen(cscopes); + GET_SPACE_RETC(sp, bp, blen, len); + memcpy(bp, cscopes, len + 1); + + for (cscopes = t = bp; (p = strsep(&t, "\t :")) != NULL;) + if (*p != '\0') { + CHAR2INT(sp, p, strlen(p) + 1, wp, wlen); + (void)cscope_add(sp, cmdp, wp); + } + + FREE_SPACE(sp, bp, blen); + return (0); +} + +/* + * cscope_add -- + * The cscope add command. + */ +static int +cscope_add(SCR *sp, EXCMD *cmdp, CHAR_T *dname) +{ + struct stat sb; + EX_PRIVATE *exp; + CSC *csc; + size_t len; + int cur_argc; + char *dbname, *path; + char *np = NULL; + size_t nlen; + + exp = EXP(sp); + + /* + * 0 additional args: usage. + * 1 additional args: matched a file. + * >1 additional args: object, too many args. + */ + cur_argc = cmdp->argc; + if (argv_exp2(sp, cmdp, dname, STRLEN(dname))) { + return (1); + } + if (cmdp->argc == cur_argc) { + (void)csc_help(sp, "add"); + return (1); + } + if (cmdp->argc == cur_argc + 1) + dname = cmdp->argv[cur_argc]->bp; + else { + ex_emsg(sp, np, EXM_FILECOUNT); + return (1); + } + + INT2CHAR(sp, dname, STRLEN(dname)+1, np, nlen); + + /* + * The user can specify a specific file (so they can have multiple + * Cscope databases in a single directory) or a directory. If the + * file doesn't exist, we're done. If it's a directory, append the + * standard database file name and try again. Store the directory + * name regardless so that we can use it as a base for searches. + */ + if (stat(np, &sb)) { + msgq(sp, M_SYSERR, "%s", np); + return (1); + } + if (S_ISDIR(sb.st_mode)) { + if ((path = join(np, CSCOPE_DBFILE)) == NULL) { + msgq(sp, M_SYSERR, NULL); + return (1); + } + if (stat(path, &sb)) { + msgq(sp, M_SYSERR, "%s", path); + free(path); + return (1); + } + free(path); + dbname = CSCOPE_DBFILE; + } else if ((dbname = strrchr(np, '/')) != NULL) + *dbname++ = '\0'; + else { + dbname = np; + np = "."; + } + + /* Allocate a cscope connection structure and initialize its fields. */ + len = strlen(np); + CALLOC_RET(sp, csc, 1, sizeof(CSC) + len); + csc->dname = csc->buf; + csc->dlen = len; + memcpy(csc->dname, np, len); + csc->mtim = sb.st_mtim; + + /* Get the search paths for the cscope. */ + if (get_paths(sp, csc)) + goto err; + + /* Start the cscope process. */ + if (run_cscope(sp, csc, dbname)) + goto err; + + /* + * Add the cscope connection to the screen's list. From now on, + * on error, we have to call terminate, which expects the csc to + * be on the chain. + */ + SLIST_INSERT_HEAD(exp->cscq, csc, q); + + /* Read the initial prompt from the cscope to make sure it's okay. */ + return read_prompt(sp, csc); + +err: free(csc); + return (1); +} + +/* + * get_paths -- + * Get the directories to search for the files associated with this + * cscope database. + */ +static int +get_paths(SCR *sp, CSC *csc) +{ + struct stat sb; + int fd, nentries; + size_t len; + char *p, **pathp, *buf; + + /* + * EXTENSION #2: + * + * If there's a cscope directory with a file named CSCOPE_PATHS, it + * contains a colon-separated list of paths in which to search for + * files returned by cscope. + * + * XXX + * These paths are absolute paths, and not relative to the cscope + * directory. To fix this, rewrite the each path using the cscope + * directory as a prefix. + */ + if ((buf = join(csc->dname, CSCOPE_PATHS)) == NULL) { + msgq(sp, M_SYSERR, NULL); + return (1); + } + if (stat(buf, &sb) == 0) { + /* Read in the CSCOPE_PATHS file. */ + len = sb.st_size; + MALLOC_RET(sp, csc->pbuf, len + 1); + if ((fd = open(buf, O_RDONLY, 0)) < 0 || + read(fd, csc->pbuf, len) != len) { + msgq_str(sp, M_SYSERR, buf, "%s"); + if (fd >= 0) + (void)close(fd); + free(buf); + return (1); + } + (void)close(fd); + free(buf); + csc->pbuf[len] = '\0'; + + /* Count up the entries. */ + for (nentries = 0, p = csc->pbuf; *p != '\0'; ++p) + if (p[0] == ':' && p[1] != '\0') + ++nentries; + + /* Build an array of pointers to the paths. */ + CALLOC_GOTO(sp, csc->paths, nentries + 1, sizeof(char **)); + for (pathp = csc->paths, p = strtok(csc->pbuf, ":"); + p != NULL; p = strtok(NULL, ":")) + *pathp++ = p; + return (0); + } + free(buf); + + /* + * If the CSCOPE_PATHS file doesn't exist, we look for files + * relative to the cscope directory. + */ + if ((csc->pbuf = strdup(csc->dname)) == NULL) { + msgq(sp, M_SYSERR, NULL); + return (1); + } + CALLOC_GOTO(sp, csc->paths, 2, sizeof(char *)); + csc->paths[0] = csc->pbuf; + return (0); + +alloc_err: + free(csc->pbuf); + csc->pbuf = NULL; + return (1); +} + +/* + * run_cscope -- + * Fork off the cscope process. + */ +static int +run_cscope(SCR *sp, CSC *csc, char *dbname) +{ + int to_cs[2], from_cs[2]; + char *cmd; + + /* + * Cscope reads from to_cs[0] and writes to from_cs[1]; vi reads from + * from_cs[0] and writes to to_cs[1]. + */ + to_cs[0] = to_cs[1] = from_cs[0] = from_cs[1] = -1; + if (pipe(to_cs) < 0 || pipe(from_cs) < 0) { + msgq(sp, M_SYSERR, "pipe"); + goto err; + } + switch (csc->pid = vfork()) { + char *dn, *dbn; + case -1: + msgq(sp, M_SYSERR, "vfork"); +err: if (to_cs[0] != -1) + (void)close(to_cs[0]); + if (to_cs[1] != -1) + (void)close(to_cs[1]); + if (from_cs[0] != -1) + (void)close(from_cs[0]); + if (from_cs[1] != -1) + (void)close(from_cs[1]); + return (1); + case 0: /* child: run cscope. */ + (void)dup2(to_cs[0], STDIN_FILENO); + (void)dup2(from_cs[1], STDOUT_FILENO); + (void)dup2(from_cs[1], STDERR_FILENO); + + /* Close unused file descriptors. */ + (void)close(to_cs[1]); + (void)close(from_cs[0]); + + /* Run the cscope command. */ +#define CSCOPE_CMD_FMT "cd %s && exec cscope -dl -f %s" + if ((dn = quote(csc->dname)) == NULL) + goto nomem; + if ((dbn = quote(dbname)) == NULL) { + free(dn); + goto nomem; + } + if (asprintf(&cmd, CSCOPE_CMD_FMT, dn, dbn) == -1) + cmd = NULL; + free(dbn); + free(dn); + if (cmd == NULL) { +nomem: msgq(sp, M_SYSERR, NULL); + _exit (1); + } + (void)execl(_PATH_BSHELL, "sh", "-c", cmd, (char *)NULL); + msgq_str(sp, M_SYSERR, cmd, "execl: %s"); + free(cmd); + _exit (127); + /* NOTREACHED */ + default: /* parent. */ + /* Close unused file descriptors. */ + (void)close(to_cs[0]); + (void)close(from_cs[1]); + + /* + * Save the file descriptors for later duplication, and + * reopen as streams. + */ + csc->to_fd = to_cs[1]; + csc->to_fp = fdopen(to_cs[1], "w"); + csc->from_fd = from_cs[0]; + csc->from_fp = fdopen(from_cs[0], "r"); + break; + } + return (0); +} + +/* + * cscope_find -- + * The cscope find command. + */ +static int +cscope_find(SCR *sp, EXCMD *cmdp, CHAR_T *pattern) +{ + CSC *csc, *csc_next; + EX_PRIVATE *exp; + FREF *frp; + TAGQ *rtqp, *tqp; + TAG *rtp; + recno_t lno; + size_t cno, search; + int force, istmp, matches; + char *np = NULL; + size_t nlen; + + exp = EXP(sp); + + /* Check for connections. */ + if (SLIST_EMPTY(exp->cscq)) { + msgq(sp, M_ERR, "310|No cscope connections running"); + return (1); + } + + /* + * Allocate all necessary memory before doing anything hard. If the + * tags stack is empty, we'll need the `local context' TAGQ structure + * later. + */ + rtp = NULL; + rtqp = NULL; + if (TAILQ_EMPTY(exp->tq)) { + /* Initialize the `local context' tag queue structure. */ + CALLOC_GOTO(sp, rtqp, 1, sizeof(TAGQ)); + TAILQ_INIT(rtqp->tagq); + + /* Initialize and link in its tag structure. */ + CALLOC_GOTO(sp, rtp, 1, sizeof(TAG)); + TAILQ_INSERT_HEAD(rtqp->tagq, rtp, q); + rtqp->current = rtp; + } + + /* Create the cscope command. */ + INT2CHAR(sp, pattern, STRLEN(pattern) + 1, np, nlen); + np = strdup(np); + if ((tqp = create_cs_cmd(sp, np, &search)) == NULL) + goto err; + free(np); + np = NULL; + + /* + * Stick the current context in a convenient place, we'll lose it + * when we switch files. + */ + frp = sp->frp; + lno = sp->lno; + cno = sp->cno; + istmp = F_ISSET(sp->frp, FR_TMPFILE) && !F_ISSET(cmdp, E_NEWSCREEN); + + /* Search all open connections for a match. */ + matches = 0; + /* Copy next connect here in case csc is killed. */ + SLIST_FOREACH_SAFE(csc, exp->cscq, q, csc_next) { + /* + * Send the command to the cscope program. (We skip the + * first two bytes of the command, because we stored the + * search cscope command character and a leading space + * there.) + */ + (void)fprintf(csc->to_fp, "%lu%s\n", search, tqp->tag + 2); + (void)fflush(csc->to_fp); + + /* Read the output. */ + if (parse(sp, csc, tqp, &matches)) + goto nomatch; + } + + if (matches == 0) { + msgq(sp, M_INFO, "278|No matches for query"); +nomatch: free(rtp); + free(rtqp); + tagq_free(sp, tqp); + return (1); + } + + /* Try to switch to the first tag. */ + force = FL_ISSET(cmdp->iflags, E_C_FORCE); + if (F_ISSET(cmdp, E_NEWSCREEN)) { + if (ex_tag_Nswitch(sp, tqp->current, force)) + goto err; + + /* Everything else gets done in the new screen. */ + sp = sp->nextdisp; + exp = EXP(sp); + } else + if (ex_tag_nswitch(sp, tqp->current, force)) + goto err; + + /* + * If this is the first tag, put a `current location' queue entry + * in place, so we can pop all the way back to the current mark. + * Note, it doesn't point to much of anything, it's a placeholder. + */ + if (TAILQ_EMPTY(exp->tq)) { + TAILQ_INSERT_HEAD(exp->tq, rtqp, q); + } else + rtqp = TAILQ_FIRST(exp->tq); + + /* Link the current TAGQ structure into place. */ + TAILQ_INSERT_HEAD(exp->tq, tqp, q); + + (void)cscope_search(sp, tqp, tqp->current); + + /* + * Move the current context from the temporary save area into the + * right structure. + * + * If we were in a temporary file, we don't have a context to which + * we can return, so just make it be the same as what we're moving + * to. It will be a little odd that ^T doesn't change anything, but + * I don't think it's a big deal. + */ + if (istmp) { + rtqp->current->frp = sp->frp; + rtqp->current->lno = sp->lno; + rtqp->current->cno = sp->cno; + } else { + rtqp->current->frp = frp; + rtqp->current->lno = lno; + rtqp->current->cno = cno; + } + + return (0); + +err: +alloc_err: + free(rtqp); + free(rtp); + free(np); + return (1); +} + +/* + * create_cs_cmd -- + * Build a cscope command, creating and initializing the base TAGQ. + */ +static TAGQ * +create_cs_cmd(SCR *sp, char *pattern, size_t *searchp) +{ + CB *cbp; + TAGQ *tqp; + size_t tlen; + char *p; + + /* + * Cscope supports a "change pattern" command which we never use, + * cscope command 5. Set CSCOPE_QUERIES[5] to " " since the user + * can't pass " " as the first character of pattern. That way the + * user can't ask for pattern 5 so we don't need any special-case + * code. + */ +#define CSCOPE_QUERIES "sgdct efi" + + if (pattern == NULL) + goto usage; + + /* Skip leading blanks, check for command character. */ + for (; cmdskip(pattern[0]); ++pattern); + if (pattern[0] == '\0' || !cmdskip(pattern[1])) + goto usage; + for (*searchp = 0, p = CSCOPE_QUERIES; + *p != '\0' && *p != pattern[0]; ++*searchp, ++p); + if (*p == '\0') { + msgq(sp, M_ERR, + "311|%s: unknown search type: use one of %s", + KEY_NAME(sp, pattern[0]), CSCOPE_QUERIES); + return (NULL); + } + + /* Skip characters to the pattern. */ + for (p = pattern + 1; *p != '\0' && cmdskip(*p); ++p); + if (*p == '\0') { +usage: (void)csc_help(sp, "find"); + return (NULL); + } + + /* The user can specify the contents of a buffer as the pattern. */ + cbp = NULL; + if (p[0] == '"' && p[1] != '\0' && p[2] == '\0') + CBNAME(sp, cbp, p[1]); + if (cbp != NULL) { + INT2CHAR(sp, TAILQ_FIRST(cbp->textq)->lb, + TAILQ_FIRST(cbp->textq)->len, p, tlen); + } else + tlen = strlen(p); + + /* Allocate and initialize the TAGQ structure. */ + CALLOC(sp, tqp, 1, sizeof(TAGQ) + tlen + 3); + if (tqp == NULL) + return (NULL); + TAILQ_INIT(tqp->tagq); + tqp->tag = tqp->buf; + tqp->tag[0] = pattern[0]; + tqp->tag[1] = ' '; + tqp->tlen = tlen + 2; + memcpy(tqp->tag + 2, p, tlen); + tqp->tag[tlen + 2] = '\0'; + F_SET(tqp, TAG_CSCOPE); + + return (tqp); +} + +/* + * parse -- + * Parse the cscope output. + */ +static int +parse(SCR *sp, CSC *csc, TAGQ *tqp, int *matchesp) +{ + TAG *tp; + recno_t slno = 0; + size_t dlen, nlen = 0, slen = 0; + int ch, i, isolder = 0, nlines; + char *dname = NULL, *name = NULL, *search, *p, *t, dummy[2], buf[2048]; + CHAR_T *wp; + size_t wlen; + + for (;;) { + if (!fgets(buf, sizeof(buf), csc->from_fp)) + goto io_err; + + /* + * If the database is out of date, or there's some other + * problem, cscope will output error messages before the + * number-of-lines output. Display/discard any output + * that doesn't match what we want. + */ +#define CSCOPE_NLINES_FMT "cscope: %d lines%1[\n]" + if (sscanf(buf, CSCOPE_NLINES_FMT, &nlines, dummy) == 2) + break; + if ((p = strchr(buf, '\n')) != NULL) + *p = '\0'; + msgq(sp, M_ERR, "%s: \"%s\"", csc->dname, buf); + } + + while (nlines--) { + if (fgets(buf, sizeof(buf), csc->from_fp) == NULL) + goto io_err; + + /* If the line's too long for the buffer, discard it. */ + if ((p = strchr(buf, '\n')) == NULL) { + while ((ch = getc(csc->from_fp)) != EOF && ch != '\n'); + continue; + } + *p = '\0'; + + /* + * The cscope output is in the following format: + * + * + * + * Figure out how long everything is so we can allocate in one + * swell foop, but discard anything that looks wrong. + */ + for (p = buf, i = 0; + i < 3 && (t = strsep(&p, "\t ")) != NULL; ++i) + switch (i) { + case 0: /* Filename. */ + name = t; + nlen = strlen(name); + break; + case 1: /* Context. */ + break; + case 2: /* Line number. */ + slno = (recno_t)atol(t); + break; + } + if (i != 3 || p == NULL || t == NULL) + continue; + + /* The rest of the string is the search pattern. */ + search = p; + slen = strlen(p); + + /* Resolve the file name. */ + csc_file(sp, csc, name, &dname, &dlen, &isolder); + + /* + * If the file is older than the cscope database, that is, + * the database was built since the file was last modified, + * or there wasn't a search string, use the line number. + */ + if (isolder || strcmp(search, "") == 0) { + search = NULL; + slen = 0; + } + + /* + * Allocate and initialize a tag structure plus the variable + * length cscope information that follows it. + */ + CALLOC_RET(sp, tp, 1, + sizeof(TAG) + dlen + 2 + nlen + 1 + (slen + 1) * sizeof(CHAR_T)); + tp->fname = (char *)tp->buf; + if (dlen == 1 && *dname == '.') + --dlen; + else if (dlen != 0) { + memcpy(tp->fname, dname, dlen); + tp->fname[dlen] = '/'; + ++dlen; + } + memcpy(tp->fname + dlen, name, nlen + 1); + tp->fnlen = dlen + nlen; + tp->slno = slno; + if (slen != 0) { + tp->search = (CHAR_T*)(tp->fname + tp->fnlen + 1); + CHAR2INT(sp, search, slen + 1, wp, wlen); + MEMCPY(tp->search, wp, (tp->slen = slen) + 1); + } + TAILQ_INSERT_TAIL(tqp->tagq, tp, q); + + /* Try to preset the tag within the current file. */ + if (sp->frp != NULL && sp->frp->name != NULL && + tqp->current == NULL && !strcmp(tp->fname, sp->frp->name)) + tqp->current = tp; + + ++*matchesp; + } + + if (tqp->current == NULL) + tqp->current = TAILQ_FIRST(tqp->tagq); + + return read_prompt(sp, csc); + +io_err: if (feof(csc->from_fp)) + errno = EIO; + msgq_str(sp, M_SYSERR, "%s", csc->dname); + terminate(sp, csc, 0); + return (1); +} + +/* + * csc_file -- + * Search for the right path to this file. + */ +static void +csc_file(SCR *sp, CSC *csc, char *name, char **dirp, size_t *dlenp, int *isolderp) +{ + struct stat sb; + char **pp, *buf; + + /* + * Check for the file in all of the listed paths. If we don't + * find it, we simply return it unchanged. We have to do this + * now, even though it's expensive, because if the user changes + * directories, we can't change our minds as to where the file + * lives. + */ + for (pp = csc->paths; *pp != NULL; ++pp) { + if ((buf = join(*pp, name)) == NULL) { + msgq(sp, M_SYSERR, NULL); + *dlenp = 0; + return; + } + if (stat(buf, &sb) == 0) { + free(buf); + *dirp = *pp; + *dlenp = strlen(*pp); + *isolderp = timespeccmp( + &sb.st_mtim, &csc->mtim, <); + return; + } + free(buf); + } + *dlenp = 0; +} + +/* + * cscope_help -- + * The cscope help command. + */ +static int +cscope_help(SCR *sp, EXCMD *cmdp, CHAR_T *subcmd) +{ + char *np; + size_t nlen; + + INT2CHAR(sp, subcmd, STRLEN(subcmd) + 1, np, nlen); + return (csc_help(sp, np)); +} + +/* + * csc_help -- + * Display help/usage messages. + */ +static int +csc_help(SCR *sp, char *cmd) +{ + CC const *ccp; + + if (cmd != NULL && *cmd != '\0') { + if ((ccp = lookup_ccmd(cmd)) == NULL) { + ex_printf(sp, + "%s doesn't match any cscope command\n", cmd); + return (1); + } else { + ex_printf(sp, + "Command: %s (%s)\n", ccp->name, ccp->help_msg); + ex_printf(sp, " Usage: %s\n", ccp->usage_msg); + return (0); + } + } + + ex_printf(sp, "cscope commands:\n"); + for (ccp = cscope_cmds; ccp->name != NULL; ++ccp) + ex_printf(sp, " %*s: %s\n", 5, ccp->name, ccp->help_msg); + return (0); +} + +/* + * cscope_kill -- + * The cscope kill command. + */ +static int +cscope_kill(SCR *sp, EXCMD *cmdp, CHAR_T *cn) +{ + char *np; + size_t nlen; + int n = 1; + + if (*cn) { + INT2CHAR(sp, cn, STRLEN(cn) + 1, np, nlen); + n = atoi(np); + } + return (terminate(sp, NULL, n)); +} + +/* + * terminate -- + * Detach from a cscope process. + */ +static int +terminate(SCR *sp, CSC *csc, int n) +{ + EX_PRIVATE *exp; + int i = 0, pstat; + CSC *cp, *pre_cp = NULL; + + exp = EXP(sp); + + /* + * We either get a csc structure or a number. Locate and remove + * the candidate which matches the structure or the number. + */ + if (csc == NULL && n < 1) + goto badno; + SLIST_FOREACH(cp, exp->cscq, q) { + ++i; + if (csc == NULL ? i != n : cp != csc) { + pre_cp = cp; + continue; + } + if (cp == SLIST_FIRST(exp->cscq)) + SLIST_REMOVE_HEAD(exp->cscq, q); + else + SLIST_REMOVE_AFTER(pre_cp, q); + csc = cp; + break; + } + if (csc == NULL) { +badno: msgq(sp, M_ERR, "312|%d: no such cscope session", n); + return (1); + } + + /* + * XXX + * Theoretically, we have the only file descriptors to the process, + * so closing them should let it exit gracefully, deleting temporary + * files, etc. However, the earlier created cscope processes seems + * to refuse to quit unless we send a SIGTERM signal. + */ + if (csc->from_fp != NULL) + (void)fclose(csc->from_fp); + if (csc->to_fp != NULL) + (void)fclose(csc->to_fp); + if (i > 1) + (void)kill(csc->pid, SIGTERM); + (void)waitpid(csc->pid, &pstat, 0); + + /* Discard cscope connection information. */ + free(csc->pbuf); + free(csc->paths); + free(csc); + return (0); +} + +/* + * cscope_reset -- + * The cscope reset command. + */ +static int +cscope_reset(SCR *sp, EXCMD *cmdp, CHAR_T *notusedp) +{ + return cscope_end(sp); +} + +/* + * cscope_end -- + * End all cscope connections. + * + * PUBLIC: int cscope_end(SCR *); + */ +int +cscope_end(SCR *sp) +{ + EX_PRIVATE *exp; + + for (exp = EXP(sp); !SLIST_EMPTY(exp->cscq);) + if (terminate(sp, NULL, 1)) + return (1); + return (0); +} + +/* + * cscope_display -- + * Display current connections. + * + * PUBLIC: int cscope_display(SCR *); + */ +int +cscope_display(SCR *sp) +{ + EX_PRIVATE *exp; + CSC *csc; + int i = 0; + + exp = EXP(sp); + if (SLIST_EMPTY(exp->cscq)) { + ex_printf(sp, "No cscope connections.\n"); + return (0); + } + SLIST_FOREACH(csc, exp->cscq, q) + ex_printf(sp, "%2d %s (process %lu)\n", + ++i, csc->dname, (u_long)csc->pid); + return (0); +} + +/* + * cscope_search -- + * Search a file for a cscope entry. + * + * PUBLIC: int cscope_search(SCR *, TAGQ *, TAG *); + */ +int +cscope_search(SCR *sp, TAGQ *tqp, TAG *tp) +{ + MARK m; + + /* If we don't have a search pattern, use the line number. */ + if (tp->search == NULL) { + if (!db_exist(sp, tp->slno)) { + tag_msg(sp, TAG_BADLNO, tqp->tag); + return (1); + } + m.lno = tp->slno; + } else { + /* + * Search for the tag; cheap fallback for C functions + * if the name is the same but the arguments have changed. + */ + m.lno = 1; + m.cno = 0; + if (f_search(sp, &m, &m, + tp->search, tp->slen, NULL, SEARCH_CSCOPE | SEARCH_FILE)) { + tag_msg(sp, TAG_SEARCH, tqp->tag); + return (1); + } + + /* + * !!! + * Historically, tags set the search direction if it wasn't + * already set. + */ + if (sp->searchdir == NOTSET) + sp->searchdir = FORWARD; + } + + /* + * !!! + * Tags move to the first non-blank, NOT the search pattern start. + */ + sp->lno = m.lno; + sp->cno = 0; + (void)nonblank(sp, sp->lno, &sp->cno); + return (0); +} + + +/* + * lookup_ccmd -- + * Return a pointer to the command structure. + */ +static CC const * +lookup_ccmd(char *name) +{ + CC const *ccp; + size_t len; + + len = strlen(name); + for (ccp = cscope_cmds; ccp->name != NULL; ++ccp) + if (strncmp(name, ccp->name, len) == 0) + return (ccp); + return (NULL); +} + +/* + * read_prompt -- + * Read a prompt from cscope. + */ +static int +read_prompt(SCR *sp, CSC *csc) +{ + int ch; + +#define CSCOPE_PROMPT ">> " + for (;;) { + while ((ch = + getc(csc->from_fp)) != EOF && ch != CSCOPE_PROMPT[0]); + if (ch == EOF) { + terminate(sp, csc, 0); + return (1); + } + if (getc(csc->from_fp) != CSCOPE_PROMPT[1]) + continue; + if (getc(csc->from_fp) != CSCOPE_PROMPT[2]) + continue; + break; + } + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_cscope.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_filter.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_filter.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_filter.c (revision 366308) @@ -0,0 +1,315 @@ +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1991, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../common/common.h" + +static int filter_ldisplay(SCR *, FILE *); + +/* + * ex_filter -- + * Run a range of lines through a filter utility and optionally + * replace the original text with the stdout/stderr output of + * the utility. + * + * PUBLIC: int ex_filter(SCR *, + * PUBLIC: EXCMD *, MARK *, MARK *, MARK *, CHAR_T *, enum filtertype); + */ +int +ex_filter(SCR *sp, EXCMD *cmdp, MARK *fm, MARK *tm, MARK *rp, CHAR_T *cmd, enum filtertype ftype) +{ + FILE *ifp, *ofp; + pid_t parent_writer_pid, utility_pid; + recno_t nread; + int input[2], output[2], rval; + char *name; + char *np; + size_t nlen; + + rval = 0; + + /* Set return cursor position, which is never less than line 1. */ + *rp = *fm; + if (rp->lno == 0) + rp->lno = 1; + + /* We're going to need a shell. */ + if (opts_empty(sp, O_SHELL, 0)) + return (1); + + /* + * There are three different processes running through this code. + * They are the utility, the parent-writer and the parent-reader. + * The parent-writer is the process that writes from the file to + * the utility, the parent reader is the process that reads from + * the utility. + * + * Input and output are named from the utility's point of view. + * The utility reads from input[0] and the parent(s) write to + * input[1]. The parent(s) read from output[0] and the utility + * writes to output[1]. + * + * !!! + * Historically, in the FILTER_READ case, the utility reads from + * the terminal (e.g. :r! cat works). Otherwise open up utility + * input pipe. + */ + ofp = NULL; + input[0] = input[1] = output[0] = output[1] = -1; + if (ftype != FILTER_READ && pipe(input) < 0) { + msgq(sp, M_SYSERR, "pipe"); + goto err; + } + + /* Open up utility output pipe. */ + if (pipe(output) < 0) { + msgq(sp, M_SYSERR, "pipe"); + goto err; + } + if ((ofp = fdopen(output[0], "r")) == NULL) { + msgq(sp, M_SYSERR, "fdopen"); + goto err; + } + + /* Fork off the utility process. */ + switch (utility_pid = vfork()) { + case -1: /* Error. */ + msgq(sp, M_SYSERR, "vfork"); +err: if (input[0] != -1) + (void)close(input[0]); + if (input[1] != -1) + (void)close(input[1]); + if (ofp != NULL) + (void)fclose(ofp); + else if (output[0] != -1) + (void)close(output[0]); + if (output[1] != -1) + (void)close(output[1]); + return (1); + case 0: /* Utility. */ + /* + * Redirect stdin from the read end of the input pipe, and + * redirect stdout/stderr to the write end of the output pipe. + * + * !!! + * Historically, ex only directed stdout into the input pipe, + * letting stderr come out on the terminal as usual. Vi did + * not, directing both stdout and stderr into the input pipe. + * We match that practice in both ex and vi for consistency. + */ + if (input[0] != -1) + (void)dup2(input[0], STDIN_FILENO); + (void)dup2(output[1], STDOUT_FILENO); + (void)dup2(output[1], STDERR_FILENO); + + /* Close the utility's file descriptors. */ + if (input[0] != -1) + (void)close(input[0]); + if (input[1] != -1) + (void)close(input[1]); + (void)close(output[0]); + (void)close(output[1]); + + if ((name = strrchr(O_STR(sp, O_SHELL), '/')) == NULL) + name = O_STR(sp, O_SHELL); + else + ++name; + + INT2CHAR(sp, cmd, STRLEN(cmd)+1, np, nlen); + execl(O_STR(sp, O_SHELL), name, "-c", np, (char *)NULL); + msgq_str(sp, M_SYSERR, O_STR(sp, O_SHELL), "execl: %s"); + _exit (127); + /* NOTREACHED */ + default: /* Parent-reader, parent-writer. */ + /* Close the pipe ends neither parent will use. */ + if (input[0] != -1) + (void)close(input[0]); + (void)close(output[1]); + break; + } + + /* + * FILTER_RBANG, FILTER_READ: + * + * Reading is the simple case -- we don't need a parent writer, + * so the parent reads the output from the read end of the output + * pipe until it finishes, then waits for the child. Ex_readfp + * appends to the MARK, and closes ofp. + * + * For FILTER_RBANG, there is nothing to write to the utility. + * Make sure it doesn't wait forever by closing its standard + * input. + * + * !!! + * Set the return cursor to the last line read in for FILTER_READ. + * Historically, this behaves differently from ":r file" command, + * which leaves the cursor at the first line read in. Check to + * make sure that it's not past EOF because we were reading into an + * empty file. + */ + if (ftype == FILTER_RBANG || ftype == FILTER_READ) { + if (ftype == FILTER_RBANG) + (void)close(input[1]); + + if (ex_readfp(sp, "filter", ofp, fm, &nread, 1)) + rval = 1; + sp->rptlines[L_ADDED] += nread; + if (ftype == FILTER_READ) { + if (fm->lno == 0) + rp->lno = nread; + else + rp->lno += nread; + } + goto uwait; + } + + /* + * FILTER_BANG, FILTER_WRITE + * + * Here we need both a reader and a writer. Temporary files are + * expensive and we'd like to avoid disk I/O. Using pipes has the + * obvious starvation conditions. It's done as follows: + * + * fork + * child + * write lines out + * exit + * parent + * FILTER_BANG: + * read lines into the file + * delete old lines + * FILTER_WRITE + * read and display lines + * wait for child + * + * XXX + * We get away without locking the underlying database because we know + * that none of the records that we're reading will be modified until + * after we've read them. This depends on the fact that the current + * B+tree implementation doesn't balance pages or similar things when + * it inserts new records. When the DB code has locking, we should + * treat vi as if it were multiple applications sharing a database, and + * do the required locking. If necessary a work-around would be to do + * explicit locking in the line.c:db_get() code, based on the flag set + * here. + */ + F_SET(sp->ep, F_MULTILOCK); + switch (parent_writer_pid = fork()) { + case -1: /* Error. */ + msgq(sp, M_SYSERR, "fork"); + (void)close(input[1]); + (void)close(output[0]); + rval = 1; + break; + case 0: /* Parent-writer. */ + /* + * Write the selected lines to the write end of the input + * pipe. This instance of ifp is closed by ex_writefp. + */ + (void)close(output[0]); + if ((ifp = fdopen(input[1], "w")) == NULL) + _exit (1); + _exit(ex_writefp(sp, "filter", ifp, fm, tm, NULL, NULL, 1)); + + /* NOTREACHED */ + default: /* Parent-reader. */ + (void)close(input[1]); + if (ftype == FILTER_WRITE) { + /* + * Read the output from the read end of the output + * pipe and display it. Filter_ldisplay closes ofp. + */ + if (filter_ldisplay(sp, ofp)) + rval = 1; + } else { + /* + * Read the output from the read end of the output + * pipe. Ex_readfp appends to the MARK and closes + * ofp. + */ + if (ex_readfp(sp, "filter", ofp, tm, &nread, 1)) + rval = 1; + sp->rptlines[L_ADDED] += nread; + } + + /* Wait for the parent-writer. */ + if (proc_wait(sp, + (long)parent_writer_pid, "parent-writer", 0, 1)) + rval = 1; + + /* Delete any lines written to the utility. */ + if (rval == 0 && ftype == FILTER_BANG && + (cut(sp, NULL, fm, tm, CUT_LINEMODE) || + del(sp, fm, tm, 1))) { + rval = 1; + break; + } + + /* + * If the filter had no output, we may have just deleted + * the cursor. Don't do any real error correction, we'll + * try and recover later. + */ + if (rp->lno > 1 && !db_exist(sp, rp->lno)) + --rp->lno; + break; + } + F_CLR(sp->ep, F_MULTILOCK); + + /* + * !!! + * Ignore errors on vi file reads, to make reads prettier. It's + * completely inconsistent, and historic practice. + */ +uwait: INT2CHAR(sp, cmd, STRLEN(cmd) + 1, np, nlen); + return (proc_wait(sp, (long)utility_pid, np, + ftype == FILTER_READ && F_ISSET(sp, SC_VI) ? 1 : 0, 0) || rval); +} + +/* + * filter_ldisplay -- + * Display output from a utility. + * + * !!! + * Historically, the characters were passed unmodified to the terminal. + * We use the ex print routines to make sure they're printable. + */ +static int +filter_ldisplay(SCR *sp, FILE *fp) +{ + size_t len; + size_t wlen; + CHAR_T *wp; + + EX_PRIVATE *exp; + + for (exp = EXP(sp); !ex_getline(sp, fp, &len) && !INTERRUPTED(sp);) { + FILE2INT5(sp, exp->ibcw, exp->ibp, len, wp, wlen); + if (ex_ldisplay(sp, wp, wlen, 0, 0)) + break; + } + if (ferror(fp)) + msgq(sp, M_SYSERR, "filter read"); + (void)fclose(fp); + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_filter.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_global.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_global.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_global.c (revision 366308) @@ -0,0 +1,313 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../common/common.h" + +enum which {GLOBAL, V}; + +static int ex_g_setup(SCR *, EXCMD *, enum which); + +/* + * ex_global -- [line [,line]] g[lobal][!] /pattern/ [commands] + * Exec on lines matching a pattern. + * + * PUBLIC: int ex_global(SCR *, EXCMD *); + */ +int +ex_global(SCR *sp, EXCMD *cmdp) +{ + return (ex_g_setup(sp, + cmdp, FL_ISSET(cmdp->iflags, E_C_FORCE) ? V : GLOBAL)); +} + +/* + * ex_v -- [line [,line]] v /pattern/ [commands] + * Exec on lines not matching a pattern. + * + * PUBLIC: int ex_v(SCR *, EXCMD *); + */ +int +ex_v(SCR *sp, EXCMD *cmdp) +{ + return (ex_g_setup(sp, cmdp, V)); +} + +/* + * ex_g_setup -- + * Ex global and v commands. + */ +static int +ex_g_setup(SCR *sp, EXCMD *cmdp, enum which cmd) +{ + CHAR_T *ptrn, *p, *t; + EXCMD *ecp; + MARK abs; + RANGE *rp; + busy_t btype; + recno_t start, end; + regex_t *re; + regmatch_t match[1]; + size_t len; + int cnt, delim, eval; + CHAR_T *dbp; + + NEEDFILE(sp, cmdp); + + if (F_ISSET(sp, SC_EX_GLOBAL)) { + msgq_wstr(sp, M_ERR, cmdp->cmd->name, + "124|The %s command can't be used as part of a global or v command"); + return (1); + } + + /* + * Skip leading white space. Historic vi allowed any non-alphanumeric + * to serve as the global command delimiter. + */ + if (cmdp->argc == 0) + goto usage; + for (p = cmdp->argv[0]->bp; cmdskip(*p); ++p); + if (*p == '\0' || is09azAZ(*p) || + *p == '\\' || *p == '|' || *p == '\n') { +usage: ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE); + return (1); + } + delim = *p++; + + /* + * Get the pattern string, toss escaped characters. + * + * QUOTING NOTE: + * Only toss an escaped character if it escapes a delimiter. + */ + for (ptrn = t = p;;) { + if (p[0] == '\0' || p[0] == delim) { + if (p[0] == delim) + ++p; + /* + * !!! + * Nul terminate the pattern string -- it's passed + * to regcomp which doesn't understand anything else. + */ + *t = '\0'; + break; + } + if (p[0] == '\\') { + if (p[1] == delim) + ++p; + else if (p[1] == '\\') + *t++ = *p++; + } + *t++ = *p++; + } + + /* If the pattern string is empty, use the last one. */ + if (*ptrn == '\0') { + if (sp->re == NULL) { + ex_emsg(sp, NULL, EXM_NOPREVRE); + return (1); + } + + /* Re-compile the RE if necessary. */ + if (!F_ISSET(sp, SC_RE_SEARCH) && + re_compile(sp, sp->re, sp->re_len, + NULL, NULL, &sp->re_c, RE_C_SEARCH)) + return (1); + } else { + /* Compile the RE. */ + if (re_compile(sp, ptrn, t - ptrn, &sp->re, + &sp->re_len, &sp->re_c, RE_C_SEARCH)) + return (1); + + /* + * Set saved RE. Historic practice is that globals set + * direction as well as the RE. + */ + sp->searchdir = FORWARD; + } + re = &sp->re_c; + + /* The global commands always set the previous context mark. */ + abs.lno = sp->lno; + abs.cno = sp->cno; + if (mark_set(sp, ABSMARK1, &abs, 1)) + return (1); + + /* Get an EXCMD structure. */ + CALLOC_RET(sp, ecp, 1, sizeof(EXCMD)); + TAILQ_INIT(ecp->rq); + + /* + * Get a copy of the command string; the default command is print. + * Don't worry about a set of s with no command, that will + * default to print in the ex parser. We need to have two copies + * because the ex parser may step on the command string when it's + * parsing it. + */ + if ((len = cmdp->argv[0]->len - (p - cmdp->argv[0]->bp)) == 0) { + p = L("p"); + len = 1; + } + + MALLOC_RET(sp, ecp->cp, (len * 2) * sizeof(CHAR_T)); + ecp->o_cp = ecp->cp; + ecp->o_clen = len; + MEMCPY(ecp->cp + len, p, len); + ecp->range_lno = OOBLNO; + FL_SET(ecp->agv_flags, cmd == GLOBAL ? AGV_GLOBAL : AGV_V); + SLIST_INSERT_HEAD(sp->gp->ecq, ecp, q); + + /* + * For each line... The semantics of global matching are that we first + * have to decide which lines are going to get passed to the command, + * and then pass them to the command, ignoring other changes. There's + * really no way to do this in a single pass, since arbitrary line + * creation, deletion and movement can be done in the ex command. For + * example, a good vi clone test is ":g/X/mo.-3", or "g/X/.,.+1d". + * What we do is create linked list of lines that are tracked through + * each ex command. There's a callback routine which the DB interface + * routines call when a line is created or deleted. This doesn't help + * the layering much. + */ + btype = BUSY_ON; + cnt = INTERRUPT_CHECK; + for (start = cmdp->addr1.lno, + end = cmdp->addr2.lno; start <= end; ++start) { + if (cnt-- == 0) { + if (INTERRUPTED(sp)) { + SLIST_REMOVE_HEAD(sp->gp->ecq, q); + free(ecp->cp); + free(ecp); + break; + } + search_busy(sp, btype); + btype = BUSY_UPDATE; + cnt = INTERRUPT_CHECK; + } + if (db_get(sp, start, DBG_FATAL, &dbp, &len)) + return (1); + match[0].rm_so = 0; + match[0].rm_eo = len; + switch (eval = + regexec(&sp->re_c, dbp, 0, match, REG_STARTEND)) { + case 0: + if (cmd == V) + continue; + break; + case REG_NOMATCH: + if (cmd == GLOBAL) + continue; + break; + default: + re_error(sp, eval, &sp->re_c); + break; + } + + /* If follows the last entry, extend the last entry's range. */ + if ((rp = TAILQ_LAST(ecp->rq, _rh)) != NULL && + rp->stop == start - 1) { + ++rp->stop; + continue; + } + + /* Allocate a new range, and append it to the list. */ + CALLOC(sp, rp, 1, sizeof(RANGE)); + if (rp == NULL) + return (1); + rp->start = rp->stop = start; + TAILQ_INSERT_TAIL(ecp->rq, rp, q); + } + search_busy(sp, BUSY_OFF); + return (0); +} + +/* + * ex_g_insdel -- + * Update the ranges based on an insertion or deletion. + * + * PUBLIC: int ex_g_insdel(SCR *, lnop_t, recno_t); + */ +int +ex_g_insdel(SCR *sp, lnop_t op, recno_t lno) +{ + EXCMD *ecp; + RANGE *nrp, *rp; + + /* All insert/append operations are done as inserts. */ + if (op == LINE_APPEND) + abort(); + + if (op == LINE_RESET) + return (0); + + SLIST_FOREACH(ecp, sp->gp->ecq, q) { + if (!FL_ISSET(ecp->agv_flags, AGV_AT | AGV_GLOBAL | AGV_V)) + continue; + TAILQ_FOREACH_SAFE(rp, ecp->rq, q, nrp) { + /* If range less than the line, ignore it. */ + if (rp->stop < lno) + continue; + + /* + * If range greater than the line, decrement or + * increment the range. + */ + if (rp->start > lno) { + if (op == LINE_DELETE) { + --rp->start; + --rp->stop; + } else { + ++rp->start; + ++rp->stop; + } + continue; + } + + /* + * Lno is inside the range, decrement the end point + * for deletion, and split the range for insertion. + * In the latter case, since we're inserting a new + * element, neither range can be exhausted. + */ + if (op == LINE_DELETE) { + if (rp->start > --rp->stop) { + TAILQ_REMOVE(ecp->rq, rp, q); + free(rp); + } + } else { + CALLOC_RET(sp, nrp, 1, sizeof(RANGE)); + nrp->start = lno + 1; + nrp->stop = rp->stop + 1; + rp->stop = lno - 1; + TAILQ_INSERT_AFTER(ecp->rq, rp, nrp, q); + } + } + + /* + * If the command deleted/inserted lines, the cursor moves to + * the line after the deleted/inserted line. + */ + ecp->range_lno = lno; + } + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_global.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_script.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_script.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_script.c (revision 366308) @@ -0,0 +1,624 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Brian Hirt. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_LIBUTIL_H +#include +#elif defined HAVE_PTY_H +#include +#else +#include +#endif + +#include "../common/common.h" +#include "../vi/vi.h" +#include "script.h" +#include "pathnames.h" + +static void sscr_check(SCR *); +static int sscr_getprompt(SCR *); +static int sscr_init(SCR *); +static int sscr_insert(SCR *); +static int sscr_matchprompt(SCR *, char *, size_t, size_t *); +static int sscr_setprompt(SCR *, char *, size_t); + +/* + * ex_script -- : sc[ript][!] [file] + * Switch to script mode. + * + * PUBLIC: int ex_script(SCR *, EXCMD *); + */ +int +ex_script(SCR *sp, EXCMD *cmdp) +{ + /* Vi only command. */ + if (!F_ISSET(sp, SC_VI)) { + msgq(sp, M_ERR, + "150|The script command is only available in vi mode"); + return (1); + } + + /* Switch to the new file. */ + if (cmdp->argc != 0 && ex_edit(sp, cmdp)) + return (1); + + /* Create the shell, figure out the prompt. */ + if (sscr_init(sp)) + return (1); + + return (0); +} + +/* + * sscr_init -- + * Create a pty setup for a shell. + */ +static int +sscr_init(SCR *sp) +{ + SCRIPT *sc; + char *sh, *sh_path; + + /* We're going to need a shell. */ + if (opts_empty(sp, O_SHELL, 0)) + return (1); + + MALLOC_RET(sp, sc, sizeof(SCRIPT)); + sp->script = sc; + sc->sh_prompt = NULL; + sc->sh_prompt_len = 0; + + /* + * There are two different processes running through this code. + * They are the shell and the parent. + */ + sc->sh_master = sc->sh_slave = -1; + + if (tcgetattr(STDIN_FILENO, &sc->sh_term) == -1) { + msgq(sp, M_SYSERR, "tcgetattr"); + goto err; + } + + /* + * Turn off output postprocessing and echo. + */ + sc->sh_term.c_oflag &= ~OPOST; + sc->sh_term.c_cflag &= ~(ECHO|ECHOE|ECHONL|ECHOK); + + if (ioctl(STDIN_FILENO, TIOCGWINSZ, &sc->sh_win) == -1) { + msgq(sp, M_SYSERR, "tcgetattr"); + goto err; + } + + if (openpty(&sc->sh_master, + &sc->sh_slave, sc->sh_name, &sc->sh_term, &sc->sh_win) == -1) { + msgq(sp, M_SYSERR, "openpty"); + goto err; + } + + /* + * __TK__ huh? + * Don't use vfork() here, because the signal semantics differ from + * implementation to implementation. + */ + switch (sc->sh_pid = fork()) { + case -1: /* Error. */ + msgq(sp, M_SYSERR, "fork"); +err: if (sc->sh_master != -1) + (void)close(sc->sh_master); + if (sc->sh_slave != -1) + (void)close(sc->sh_slave); + return (1); + case 0: /* Utility. */ + /* + * XXX + * So that shells that do command line editing turn it off. + */ + (void)setenv("TERM", "emacs", 1); + (void)setenv("TERMCAP", "emacs:", 1); + (void)setenv("EMACS", "t", 1); + + (void)setsid(); +#ifdef TIOCSCTTY + /* + * 4.4BSD allocates a controlling terminal using the TIOCSCTTY + * ioctl, not by opening a terminal device file. POSIX 1003.1 + * doesn't define a portable way to do this. If TIOCSCTTY is + * not available, hope that the open does it. + */ + (void)ioctl(sc->sh_slave, TIOCSCTTY, 0); +#endif + (void)close(sc->sh_master); + (void)dup2(sc->sh_slave, STDIN_FILENO); + (void)dup2(sc->sh_slave, STDOUT_FILENO); + (void)dup2(sc->sh_slave, STDERR_FILENO); + (void)close(sc->sh_slave); + + /* Assumes that all shells have -i. */ + sh_path = O_STR(sp, O_SHELL); + if ((sh = strrchr(sh_path, '/')) == NULL) + sh = sh_path; + else + ++sh; + execl(sh_path, sh, "-i", NULL); + msgq_str(sp, M_SYSERR, sh_path, "execl: %s"); + _exit(127); + default: /* Parent. */ + break; + } + + if (sscr_getprompt(sp)) + return (1); + + F_SET(sp, SC_SCRIPT); + F_SET(sp->gp, G_SCRWIN); + return (0); +} + +/* + * sscr_getprompt -- + * Eat lines printed by the shell until a line with no trailing + * carriage return comes; set the prompt from that line. + */ +static int +sscr_getprompt(SCR *sp) +{ + EX_PRIVATE *exp; + struct timeval tv; + char *endp, *p, *t, buf[1024]; + SCRIPT *sc; + fd_set fdset; + recno_t lline; + size_t llen, len; + int nr; + CHAR_T *wp; + size_t wlen; + + exp = EXP(sp); + + FD_ZERO(&fdset); + endp = buf; + len = sizeof(buf); + + /* Wait up to a second for characters to read. */ + tv.tv_sec = 5; + tv.tv_usec = 0; + sc = sp->script; + FD_SET(sc->sh_master, &fdset); + switch (select(sc->sh_master + 1, &fdset, NULL, NULL, &tv)) { + case -1: /* Error or interrupt. */ + msgq(sp, M_SYSERR, "select"); + goto prompterr; + case 0: /* Timeout */ + msgq(sp, M_ERR, "Error: timed out"); + goto prompterr; + case 1: /* Characters to read. */ + break; + } + + /* Read the characters. */ +more: len = sizeof(buf) - (endp - buf); + switch (nr = read(sc->sh_master, endp, len)) { + case 0: /* EOF. */ + msgq(sp, M_ERR, "Error: shell: EOF"); + goto prompterr; + case -1: /* Error or interrupt. */ + msgq(sp, M_SYSERR, "shell"); + goto prompterr; + default: + endp += nr; + break; + } + + /* If any complete lines, push them into the file. */ + for (p = t = buf; p < endp; ++p) { + if (*p == '\r' || *p == '\n') { + if (CHAR2INT5(sp, exp->ibcw, t, p - t, wp, wlen)) + goto conv_err; + if (db_last(sp, &lline) || + db_append(sp, 0, lline, wp, wlen)) + goto prompterr; + t = p + 1; + } + } + if (p > buf) { + memmove(buf, t, endp - t); + endp = buf + (endp - t); + } + if (endp == buf) + goto more; + + /* Wait up 1/10 of a second to make sure that we got it all. */ + tv.tv_sec = 0; + tv.tv_usec = 100000; + switch (select(sc->sh_master + 1, &fdset, NULL, NULL, &tv)) { + case -1: /* Error or interrupt. */ + msgq(sp, M_SYSERR, "select"); + goto prompterr; + case 0: /* Timeout */ + break; + case 1: /* Characters to read. */ + goto more; + } + + /* Timed out, so theoretically we have a prompt. */ + llen = endp - buf; + endp = buf; + + /* Append the line into the file. */ + if (CHAR2INT5(sp, exp->ibcw, buf, llen, wp, wlen)) + goto conv_err; + if (db_last(sp, &lline) || db_append(sp, 0, lline, wp, wlen)) { + if (0) +conv_err: msgq(sp, M_ERR, "323|Invalid input. Truncated."); +prompterr: sscr_end(sp); + return (1); + } + + return (sscr_setprompt(sp, buf, llen)); +} + +/* + * sscr_exec -- + * Take a line and hand it off to the shell. + * + * PUBLIC: int sscr_exec(SCR *, recno_t); + */ +int +sscr_exec(SCR *sp, recno_t lno) +{ + SCRIPT *sc; + recno_t last_lno; + size_t blen, len, last_len, tlen; + int isempty, matchprompt, nw, rval; + char *bp = NULL, *p; + CHAR_T *wp; + size_t wlen; + + /* If there's a prompt on the last line, append the command. */ + if (db_last(sp, &last_lno)) + return (1); + if (db_get(sp, last_lno, DBG_FATAL, &wp, &wlen)) + return (1); + INT2CHAR(sp, wp, wlen, p, last_len); + if (sscr_matchprompt(sp, p, last_len, &tlen) && tlen == 0) { + matchprompt = 1; + GET_SPACE_RETC(sp, bp, blen, last_len + 128); + memmove(bp, p, last_len); + } else + matchprompt = 0; + + /* Get something to execute. */ + if (db_eget(sp, lno, &wp, &wlen, &isempty)) { + if (isempty) + goto empty; + goto err1; + } + + /* Empty lines aren't interesting. */ + if (wlen == 0) + goto empty; + INT2CHAR(sp, wp, wlen, p, len); + + /* Delete any prompt. */ + if (sscr_matchprompt(sp, p, len, &tlen)) { + if (tlen == len) { +empty: msgq(sp, M_BERR, "151|No command to execute"); + goto err1; + } + p += (len - tlen); + len = tlen; + } + + /* Push the line to the shell. */ + sc = sp->script; + if ((nw = write(sc->sh_master, p, len)) != len) + goto err2; + rval = 0; + if (write(sc->sh_master, "\n", 1) != 1) { +err2: if (nw == 0) + errno = EIO; + msgq(sp, M_SYSERR, "shell"); + goto err1; + } + + if (matchprompt) { + ADD_SPACE_RETC(sp, bp, blen, last_len + len); + memmove(bp + last_len, p, len); + CHAR2INT(sp, bp, last_len + len, wp, wlen); + if (db_set(sp, last_lno, wp, wlen)) +err1: rval = 1; + } + if (matchprompt) + FREE_SPACE(sp, bp, blen); + return (rval); +} + +/* + * sscr_input -- + * Read any waiting shell input. + * + * PUBLIC: int sscr_input(SCR *); + */ +int +sscr_input(SCR *sp) +{ + GS *gp; + struct timeval poll; + fd_set rdfd; + int maxfd; + + gp = sp->gp; + +loop: maxfd = 0; + FD_ZERO(&rdfd); + poll.tv_sec = 0; + poll.tv_usec = 0; + + /* Set up the input mask. */ + TAILQ_FOREACH(sp, gp->dq, q) + if (F_ISSET(sp, SC_SCRIPT)) { + FD_SET(sp->script->sh_master, &rdfd); + if (sp->script->sh_master > maxfd) + maxfd = sp->script->sh_master; + } + + /* Check for input. */ + switch (select(maxfd + 1, &rdfd, NULL, NULL, &poll)) { + case -1: + msgq(sp, M_SYSERR, "select"); + return (1); + case 0: + return (0); + default: + break; + } + + /* Read the input. */ + TAILQ_FOREACH(sp, gp->dq, q) + if (F_ISSET(sp, SC_SCRIPT) && + FD_ISSET(sp->script->sh_master, &rdfd) && + sscr_insert(sp)) + return (1); + goto loop; +} + +/* + * sscr_insert -- + * Take a line from the shell and insert it into the file. + */ +static int +sscr_insert(SCR *sp) +{ + EX_PRIVATE *exp; + struct timeval tv; + char *endp, *p, *t; + SCRIPT *sc; + fd_set rdfd; + recno_t lno; + size_t blen, len, tlen; + int nr, rval; + char *bp; + CHAR_T *wp; + size_t wlen = 0; + + exp = EXP(sp); + + + /* Find out where the end of the file is. */ + if (db_last(sp, &lno)) + return (1); + +#define MINREAD 1024 + GET_SPACE_RETC(sp, bp, blen, MINREAD); + endp = bp; + + /* Read the characters. */ + rval = 1; + sc = sp->script; +more: switch (nr = read(sc->sh_master, endp, MINREAD)) { + case 0: /* EOF; shell just exited. */ + sscr_end(sp); + rval = 0; + goto ret; + case -1: /* Error or interrupt. */ + msgq(sp, M_SYSERR, "shell"); + goto ret; + default: + endp += nr; + break; + } + + /* Append the lines into the file. */ + for (p = t = bp; p < endp; ++p) { + if (*p == '\r' || *p == '\n') { + len = p - t; + if (CHAR2INT5(sp, exp->ibcw, t, len, wp, wlen)) + goto conv_err; + if (db_append(sp, 1, lno++, wp, wlen)) + goto ret; + t = p + 1; + } + } + if (p > t) { + len = p - t; + /* + * If the last thing from the shell isn't another prompt, wait + * up to 1/10 of a second for more stuff to show up, so that + * we don't break the output into two separate lines. Don't + * want to hang indefinitely because some program is hanging, + * confused the shell, or whatever. + */ + if (!sscr_matchprompt(sp, t, len, &tlen) || tlen != 0) { + tv.tv_sec = 0; + tv.tv_usec = 100000; + FD_ZERO(&rdfd); + FD_SET(sc->sh_master, &rdfd); + if (select(sc->sh_master + 1, + &rdfd, NULL, NULL, &tv) == 1) { + memmove(bp, t, len); + endp = bp + len; + goto more; + } + } + if (sscr_setprompt(sp, t, len)) + return (1); + if (CHAR2INT5(sp, exp->ibcw, t, len, wp, wlen)) + goto conv_err; + if (db_append(sp, 1, lno++, wp, wlen)) + goto ret; + } + + /* The cursor moves to EOF. */ + sp->lno = lno; + sp->cno = wlen ? wlen - 1 : 0; + rval = vs_refresh(sp, 1); + + if (0) +conv_err: msgq(sp, M_ERR, "323|Invalid input. Truncated."); + +ret: FREE_SPACE(sp, bp, blen); + return (rval); +} + +/* + * sscr_setprompt -- + * + * Set the prompt to the last line we got from the shell. + * + */ +static int +sscr_setprompt(SCR *sp, char *buf, size_t len) +{ + SCRIPT *sc; + + sc = sp->script; + free(sc->sh_prompt); + MALLOC(sp, sc->sh_prompt, len + 1); + if (sc->sh_prompt == NULL) { + sscr_end(sp); + return (1); + } + memmove(sc->sh_prompt, buf, len); + sc->sh_prompt_len = len; + sc->sh_prompt[len] = '\0'; + return (0); +} + +/* + * sscr_matchprompt -- + * Check to see if a line matches the prompt. Nul's indicate + * parts that can change, in both content and size. + */ +static int +sscr_matchprompt(SCR *sp, char *lp, size_t line_len, size_t *lenp) +{ + SCRIPT *sc; + size_t prompt_len; + char *pp; + + sc = sp->script; + if (line_len < (prompt_len = sc->sh_prompt_len)) + return (0); + + for (pp = sc->sh_prompt; + prompt_len && line_len; --prompt_len, --line_len) { + if (*pp == '\0') { + for (; prompt_len && *pp == '\0'; --prompt_len, ++pp); + if (!prompt_len) + return (0); + for (; line_len && *lp != *pp; --line_len, ++lp); + if (!line_len) + return (0); + } + if (*pp++ != *lp++) + break; + } + + if (prompt_len) + return (0); + if (lenp != NULL) + *lenp = line_len; + return (1); +} + +/* + * sscr_end -- + * End the pipe to a shell. + * + * PUBLIC: int sscr_end(SCR *); + */ +int +sscr_end(SCR *sp) +{ + SCRIPT *sc; + + if ((sc = sp->script) == NULL) + return (0); + + /* Turn off the script flags. */ + F_CLR(sp, SC_SCRIPT); + sscr_check(sp); + + /* Close down the parent's file descriptors. */ + if (sc->sh_master != -1) + (void)close(sc->sh_master); + if (sc->sh_slave != -1) + (void)close(sc->sh_slave); + + /* This should have killed the child. */ + (void)proc_wait(sp, (long)sc->sh_pid, "script-shell", 0, 0); + + /* Free memory. */ + free(sc->sh_prompt); + free(sc); + sp->script = NULL; + + return (0); +} + +/* + * sscr_check -- + * Set/clear the global scripting bit. + */ +static void +sscr_check(SCR *sp) +{ + GS *gp; + + gp = sp->gp; + TAILQ_FOREACH(sp, gp->dq, q) + if (F_ISSET(sp, SC_SCRIPT)) { + F_SET(gp, G_SCRWIN); + return; + } + F_CLR(gp, G_SCRWIN); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_script.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_shell.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_shell.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_shell.c (revision 366308) @@ -0,0 +1,222 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../common/common.h" + +static const char *sigmsg(int); + +/* + * ex_shell -- :sh[ell] + * Invoke the program named in the SHELL environment variable + * with the argument -i. + * + * PUBLIC: int ex_shell(SCR *, EXCMD *); + */ +int +ex_shell(SCR *sp, EXCMD *cmdp) +{ + int rval; + char *buf; + + /* We'll need a shell. */ + if (opts_empty(sp, O_SHELL, 0)) + return (1); + + /* + * XXX + * Assumes all shells use -i. + */ + if (asprintf(&buf, "%s -i", O_STR(sp, O_SHELL)) == -1) { + msgq(sp, M_SYSERR, NULL); + return (1); + } + + /* Restore the window name. */ + (void)sp->gp->scr_rename(sp, NULL, 0); + + /* If we're still in a vi screen, move out explicitly. */ + rval = ex_exec_proc(sp, cmdp, buf, NULL, !F_ISSET(sp, SC_SCR_EXWROTE)); + free(buf); + + /* Set the window name. */ + (void)sp->gp->scr_rename(sp, sp->frp->name, 1); + + /* + * !!! + * Historically, vi didn't require a continue message after the + * return of the shell. Match it. + */ + F_SET(sp, SC_EX_WAIT_NO); + + return (rval); +} + +/* + * ex_exec_proc -- + * Run a separate process. + * + * PUBLIC: int ex_exec_proc(SCR *, EXCMD *, char *, const char *, int); + */ +int +ex_exec_proc(SCR *sp, EXCMD *cmdp, char *cmd, const char *msg, int need_newline) +{ + GS *gp; + const char *name; + pid_t pid; + + gp = sp->gp; + + /* We'll need a shell. */ + if (opts_empty(sp, O_SHELL, 0)) + return (1); + + /* Enter ex mode. */ + if (F_ISSET(sp, SC_VI)) { + if (gp->scr_screen(sp, SC_EX)) { + ex_wemsg(sp, cmdp->cmd->name, EXM_NOCANON); + return (1); + } + (void)gp->scr_attr(sp, SA_ALTERNATE, 0); + F_SET(sp, SC_SCR_EX | SC_SCR_EXWROTE); + } + + /* Put out additional newline, message. */ + if (need_newline) + (void)ex_puts(sp, "\n"); + if (msg != NULL) { + (void)ex_puts(sp, msg); + (void)ex_puts(sp, "\n"); + } + (void)ex_fflush(sp); + + switch (pid = vfork()) { + case -1: /* Error. */ + msgq(sp, M_SYSERR, "vfork"); + return (1); + case 0: /* Utility. */ + if (gp->scr_child) + gp->scr_child(sp); + if ((name = strrchr(O_STR(sp, O_SHELL), '/')) == NULL) + name = O_STR(sp, O_SHELL); + else + ++name; + execl(O_STR(sp, O_SHELL), name, "-c", cmd, (char *)NULL); + msgq_str(sp, M_SYSERR, O_STR(sp, O_SHELL), "execl: %s"); + _exit(127); + /* NOTREACHED */ + default: /* Parent. */ + return (proc_wait(sp, (long)pid, cmd, 0, 0)); + } + /* NOTREACHED */ +} + +/* + * proc_wait -- + * Wait for one of the processes. + * + * !!! + * The pid_t type varies in size from a short to a long depending on the + * system. It has to be cast into something or the standard promotion + * rules get you. I'm using a long based on the belief that nobody is + * going to make it unsigned and it's unlikely to be a quad. + * + * PUBLIC: int proc_wait(SCR *, long, const char *, int, int); + */ +int +proc_wait(SCR *sp, long int pid, const char *cmd, int silent, int okpipe) +{ + size_t len; + int nf, pstat; + char *p; + + /* Wait for the utility, ignoring interruptions. */ + for (;;) { + errno = 0; + if (waitpid((pid_t)pid, &pstat, 0) != -1) + break; + if (errno != EINTR) { + msgq(sp, M_SYSERR, "waitpid"); + return (1); + } + } + + /* + * Display the utility's exit status. Ignore SIGPIPE from the + * parent-writer, as that only means that the utility chose to + * exit before reading all of its input. + */ + if (WIFSIGNALED(pstat) && (!okpipe || WTERMSIG(pstat) != SIGPIPE)) { + for (; cmdskip(*cmd); ++cmd); + p = msg_print(sp, cmd, &nf); + len = strlen(p); + msgq(sp, M_ERR, "%.*s%s: received signal: %s%s", + (int)MIN(len, 20), p, len > 20 ? " ..." : "", + sigmsg(WTERMSIG(pstat)), + WCOREDUMP(pstat) ? "; core dumped" : ""); + if (nf) + FREE_SPACE(sp, p, 0); + return (1); + } + + if (WIFEXITED(pstat) && WEXITSTATUS(pstat)) { + /* + * Remain silent for "normal" errors when doing shell file + * name expansions, they almost certainly indicate nothing + * more than a failure to match. + * + * Remain silent for vi read filter errors. It's historic + * practice. + */ + if (!silent) { + for (; cmdskip(*cmd); ++cmd); + p = msg_print(sp, cmd, &nf); + len = strlen(p); + msgq(sp, M_ERR, "%.*s%s: exited with status %d", + (int)MIN(len, 20), p, len > 20 ? " ..." : "", + WEXITSTATUS(pstat)); + if (nf) + FREE_SPACE(sp, p, 0); + } + return (1); + } + return (0); +} + +/* + * sigmsg -- + * Return a pointer to a message describing a signal. + */ +static const char * +sigmsg(int signo) +{ + static char buf[40]; + char *message; + + /* POSIX.1-2008 leaves strsignal(3)'s return value unspecified. */ + if ((message = strsignal(signo)) != NULL) + return message; + (void)snprintf(buf, sizeof(buf), "Unknown signal: %d", signo); + return (buf); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_shell.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_subst.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_subst.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_subst.c (revision 366308) @@ -0,0 +1,1434 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../common/common.h" +#include "../vi/vi.h" + +#define SUB_FIRST 0x01 /* The 'r' flag isn't reasonable. */ +#define SUB_MUSTSETR 0x02 /* The 'r' flag is required. */ + +static int re_conv(SCR *, CHAR_T **, size_t *, int *); +static int re_cscope_conv(SCR *, CHAR_T **, size_t *, int *); +static int re_sub(SCR *, + CHAR_T *, CHAR_T **, size_t *, size_t *, regmatch_t [10]); +static int re_tag_conv(SCR *, CHAR_T **, size_t *, int *); +static int s(SCR *, EXCMD *, CHAR_T *, regex_t *, u_int); + +/* + * ex_s -- + * [line [,line]] s[ubstitute] [[/;]pat[/;]/repl[/;] [cgr] [count] [#lp]] + * + * Substitute on lines matching a pattern. + * + * PUBLIC: int ex_s(SCR *, EXCMD *); + */ +int +ex_s(SCR *sp, EXCMD *cmdp) +{ + regex_t *re; + size_t blen, len; + u_int flags; + int delim; + CHAR_T *bp, *p, *ptrn, *rep, *t; + + /* + * Skip leading white space. + * + * !!! + * Historic vi allowed any non-alphanumeric to serve as the + * substitution command delimiter. + * + * !!! + * If the arguments are empty, it's the same as &, i.e. we + * repeat the last substitution. + */ + if (cmdp->argc == 0) + goto subagain; + for (p = cmdp->argv[0]->bp, + len = cmdp->argv[0]->len; len > 0; --len, ++p) { + if (!cmdskip(*p)) + break; + } + if (len == 0) +subagain: return (ex_subagain(sp, cmdp)); + + delim = *p++; + if (is09azAZ(delim) || delim == '\\') + return (s(sp, cmdp, p, &sp->subre_c, SUB_MUSTSETR)); + + /* + * !!! + * The full-blown substitute command reset the remembered + * state of the 'c' and 'g' suffices. + */ + sp->c_suffix = sp->g_suffix = 0; + + /* + * Get the pattern string, toss escaping characters. + * + * !!! + * Historic vi accepted any of the following forms: + * + * :s/abc/def/ change "abc" to "def" + * :s/abc/def change "abc" to "def" + * :s/abc/ delete "abc" + * :s/abc delete "abc" + * + * QUOTING NOTE: + * + * Only toss an escaping character if it escapes a delimiter. + * This means that "s/A/\\\\f" replaces "A" with "\\f". It + * would be nice to be more regular, i.e. for each layer of + * escaping a single escaping character is removed, but that's + * not how the historic vi worked. + */ + for (ptrn = t = p;;) { + if (p[0] == '\0' || p[0] == delim) { + if (p[0] == delim) + ++p; + /* + * !!! + * Nul terminate the pattern string -- it's passed + * to regcomp which doesn't understand anything else. + */ + *t = '\0'; + break; + } + if (p[0] == '\\') { + if (p[1] == delim) + ++p; + else if (p[1] == '\\') + *t++ = *p++; + } + *t++ = *p++; + } + + /* + * If the pattern string is empty, use the last RE (not just the + * last substitution RE). + */ + if (*ptrn == '\0') { + if (sp->re == NULL) { + ex_emsg(sp, NULL, EXM_NOPREVRE); + return (1); + } + + /* Re-compile the RE if necessary. */ + if (!F_ISSET(sp, SC_RE_SEARCH) && + re_compile(sp, sp->re, sp->re_len, + NULL, NULL, &sp->re_c, RE_C_SEARCH)) + return (1); + flags = 0; + } else { + /* + * !!! + * Compile the RE. Historic practice is that substitutes set + * the search direction as well as both substitute and search + * RE's. We compile the RE twice, as we don't want to bother + * ref counting the pattern string and (opaque) structure. + */ + if (re_compile(sp, ptrn, t - ptrn, &sp->re, + &sp->re_len, &sp->re_c, RE_C_SEARCH)) + return (1); + if (re_compile(sp, ptrn, t - ptrn, &sp->subre, + &sp->subre_len, &sp->subre_c, RE_C_SUBST)) + return (1); + + flags = SUB_FIRST; + sp->searchdir = FORWARD; + } + re = &sp->re_c; + + /* + * Get the replacement string. + * + * The special character & (\& if O_MAGIC not set) matches the + * entire RE. No handling of & is required here, it's done by + * re_sub(). + * + * The special character ~ (\~ if O_MAGIC not set) inserts the + * previous replacement string into this replacement string. + * Count ~'s to figure out how much space we need. We could + * special case nonexistent last patterns or whether or not + * O_MAGIC is set, but it's probably not worth the effort. + * + * QUOTING NOTE: + * + * Only toss an escaping character if it escapes a delimiter or + * if O_MAGIC is set and it escapes a tilde. + * + * !!! + * If the entire replacement pattern is "%", then use the last + * replacement pattern. This semantic was added to vi in System + * V and then percolated elsewhere, presumably around the time + * that it was added to their version of ed(1). + */ + if (p[0] == '\0' || p[0] == delim) { + if (p[0] == delim) + ++p; + free(sp->repl); + sp->repl = NULL; + sp->repl_len = 0; + } else if (p[0] == '%' && (p[1] == '\0' || p[1] == delim)) + p += p[1] == delim ? 2 : 1; + else { + for (rep = p, len = 0; + p[0] != '\0' && p[0] != delim; ++p, ++len) + if (p[0] == '~') + len += sp->repl_len; + GET_SPACE_RETW(sp, bp, blen, len); + for (t = bp, len = 0, p = rep;;) { + if (p[0] == '\0' || p[0] == delim) { + if (p[0] == delim) + ++p; + break; + } + if (p[0] == '\\') { + if (p[1] == delim) + ++p; + else if (p[1] == '\\') { + *t++ = *p++; + ++len; + } else if (p[1] == '~') { + ++p; + if (!O_ISSET(sp, O_MAGIC)) + goto tilde; + } + } else if (p[0] == '~' && O_ISSET(sp, O_MAGIC)) { +tilde: ++p; + MEMCPY(t, sp->repl, sp->repl_len); + t += sp->repl_len; + len += sp->repl_len; + continue; + } + *t++ = *p++; + ++len; + } + if ((sp->repl_len = len) != 0) { + free(sp->repl); + MALLOC(sp, sp->repl, len * sizeof(CHAR_T)); + if (sp->repl == NULL) { + FREE_SPACEW(sp, bp, blen); + return (1); + } + MEMCPY(sp->repl, bp, len); + } + FREE_SPACEW(sp, bp, blen); + } + return (s(sp, cmdp, p, re, flags)); +} + +/* + * ex_subagain -- + * [line [,line]] & [cgr] [count] [#lp]] + * + * Substitute using the last substitute RE and replacement pattern. + * + * PUBLIC: int ex_subagain(SCR *, EXCMD *); + */ +int +ex_subagain(SCR *sp, EXCMD *cmdp) +{ + if (sp->subre == NULL) { + ex_emsg(sp, NULL, EXM_NOPREVRE); + return (1); + } + if (!F_ISSET(sp, SC_RE_SUBST) && + re_compile(sp, sp->subre, sp->subre_len, + NULL, NULL, &sp->subre_c, RE_C_SUBST)) + return (1); + return (s(sp, + cmdp, cmdp->argc ? cmdp->argv[0]->bp : NULL, &sp->subre_c, 0)); +} + +/* + * ex_subtilde -- + * [line [,line]] ~ [cgr] [count] [#lp]] + * + * Substitute using the last RE and last substitute replacement pattern. + * + * PUBLIC: int ex_subtilde(SCR *, EXCMD *); + */ +int +ex_subtilde(SCR *sp, EXCMD *cmdp) +{ + if (sp->re == NULL) { + ex_emsg(sp, NULL, EXM_NOPREVRE); + return (1); + } + if (!F_ISSET(sp, SC_RE_SEARCH) && re_compile(sp, sp->re, + sp->re_len, NULL, NULL, &sp->re_c, RE_C_SEARCH)) + return (1); + return (s(sp, + cmdp, cmdp->argc ? cmdp->argv[0]->bp : NULL, &sp->re_c, 0)); +} + +/* + * s -- + * Do the substitution. This stuff is *really* tricky. There are lots of + * special cases, and general nastiness. Don't mess with it unless you're + * pretty confident. + * + * The nasty part of the substitution is what happens when the replacement + * string contains newlines. It's a bit tricky -- consider the information + * that has to be retained for "s/f\(o\)o/^M\1^M\1/". The solution here is + * to build a set of newline offsets which we use to break the line up later, + * when the replacement is done. Don't change it unless you're *damned* + * confident. + */ +#define NEEDNEWLINE(sp) do { \ + if (sp->newl_len == sp->newl_cnt) { \ + sp->newl_len += 25; \ + REALLOC(sp, sp->newl, size_t *, \ + sp->newl_len * sizeof(size_t)); \ + if (sp->newl == NULL) { \ + sp->newl_len = 0; \ + return (1); \ + } \ + } \ +} while (0) + +#define BUILD(sp, l, len) do { \ + if (lbclen + (len) > lblen) { \ + lblen = p2roundup(MAX(lbclen + (len), 256)); \ + REALLOC(sp, lb, CHAR_T *, lblen * sizeof(CHAR_T)); \ + if (lb == NULL) { \ + lbclen = 0; \ + return (1); \ + } \ + } \ + MEMCPY(lb + lbclen, l, len); \ + lbclen += len; \ +} while (0) + +#define NEEDSP(sp, len, pnt) do { \ + if (lbclen + (len) > lblen) { \ + lblen = p2roundup(MAX(lbclen + (len), 256)); \ + REALLOC(sp, lb, CHAR_T *, lblen * sizeof(CHAR_T)); \ + if (lb == NULL) { \ + lbclen = 0; \ + return (1); \ + } \ + pnt = lb + lbclen; \ + } \ +} while (0) + +static int +s(SCR *sp, EXCMD *cmdp, CHAR_T *s, regex_t *re, u_int flags) +{ + EVENT ev; + MARK from, to; + TEXTH tiq[] = {{ 0 }}; + recno_t elno, lno, slno; + u_long ul; + regmatch_t match[10]; + size_t blen, cnt, last, lbclen, lblen, len, llen; + size_t offset, saved_offset, scno; + int cflag, lflag, nflag, pflag, rflag; + int didsub, do_eol_match, eflags, empty_ok, eval; + int linechanged, matched, quit, rval; + CHAR_T *bp, *lb; + enum nresult nret; + + NEEDFILE(sp, cmdp); + + slno = sp->lno; + scno = sp->cno; + + /* + * !!! + * Historically, the 'g' and 'c' suffices were always toggled as flags, + * so ":s/A/B/" was the same as ":s/A/B/ccgg". If O_EDCOMPATIBLE was + * not set, they were initialized to 0 for all substitute commands. If + * O_EDCOMPATIBLE was set, they were initialized to 0 only if the user + * specified substitute/replacement patterns (see ex_s()). + */ + if (!O_ISSET(sp, O_EDCOMPATIBLE)) + sp->c_suffix = sp->g_suffix = 0; + + /* + * Historic vi permitted the '#', 'l' and 'p' options in vi mode, but + * it only displayed the last change. I'd disallow them, but they are + * useful in combination with the [v]global commands. In the current + * model the problem is combining them with the 'c' flag -- the screen + * would have to flip back and forth between the confirm screen and the + * ex print screen, which would be pretty awful. We do display all + * changes, though, for what that's worth. + * + * !!! + * Historic vi was fairly strict about the order of "options", the + * count, and "flags". I'm somewhat fuzzy on the difference between + * options and flags, anyway, so this is a simpler approach, and we + * just take it them in whatever order the user gives them. (The ex + * usage statement doesn't reflect this.) + */ + cflag = lflag = nflag = pflag = rflag = 0; + if (s == NULL) + goto noargs; + for (lno = OOBLNO; *s != '\0'; ++s) + switch (*s) { + case ' ': + case '\t': + continue; + case '+': + ++cmdp->flagoff; + break; + case '-': + --cmdp->flagoff; + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + if (lno != OOBLNO) + goto usage; + errno = 0; + nret = nget_uslong(&ul, s, &s, 10); + lno = ul; + if (*s == '\0') /* Loop increment correction. */ + --s; + if (nret != NUM_OK) { + if (nret == NUM_OVER) + msgq(sp, M_ERR, "153|Count overflow"); + else if (nret == NUM_UNDER) + msgq(sp, M_ERR, "154|Count underflow"); + else + msgq(sp, M_SYSERR, NULL); + return (1); + } + /* + * In historic vi, the count was inclusive from the + * second address. + */ + cmdp->addr1.lno = cmdp->addr2.lno; + cmdp->addr2.lno += lno - 1; + if (!db_exist(sp, cmdp->addr2.lno) && + db_last(sp, &cmdp->addr2.lno)) + return (1); + break; + case '#': + nflag = 1; + break; + case 'c': + sp->c_suffix = !sp->c_suffix; + + /* Ex text structure initialization. */ + if (F_ISSET(sp, SC_EX)) + TAILQ_INIT(tiq); + break; + case 'g': + sp->g_suffix = !sp->g_suffix; + break; + case 'l': + lflag = 1; + break; + case 'p': + pflag = 1; + break; + case 'r': + if (LF_ISSET(SUB_FIRST)) { + msgq(sp, M_ERR, + "155|Regular expression specified; r flag meaningless"); + return (1); + } + if (!F_ISSET(sp, SC_RE_SEARCH)) { + ex_emsg(sp, NULL, EXM_NOPREVRE); + return (1); + } + rflag = 1; + re = &sp->re_c; + break; + default: + goto usage; + } + + if (*s != '\0' || (!rflag && LF_ISSET(SUB_MUSTSETR))) { +usage: ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE); + return (1); + } + +noargs: if (F_ISSET(sp, SC_VI) && sp->c_suffix && (lflag || nflag || pflag)) { + msgq(sp, M_ERR, +"156|The #, l and p flags may not be combined with the c flag in vi mode"); + return (1); + } + + /* + * bp: if interactive, line cache + * blen: if interactive, line cache length + * lb: build buffer pointer. + * lbclen: current length of built buffer. + * lblen; length of build buffer. + */ + bp = lb = NULL; + blen = lbclen = lblen = 0; + + /* For each line... */ + lno = cmdp->addr1.lno == 0 ? 1 : cmdp->addr1.lno; + for (matched = quit = 0, + elno = cmdp->addr2.lno; !quit && lno <= elno; ++lno) { + + /* Someone's unhappy, time to stop. */ + if (INTERRUPTED(sp)) + break; + + /* Get the line. */ + if (db_get(sp, lno, DBG_FATAL, &s, &llen)) + goto err; + + /* + * Make a local copy if doing confirmation -- when calling + * the confirm routine we're likely to lose the cached copy. + */ + if (sp->c_suffix) { + if (bp == NULL) { + GET_SPACE_RETW(sp, bp, blen, llen); + } else + ADD_SPACE_RETW(sp, bp, blen, llen); + MEMCPY(bp, s, llen); + s = bp; + } + + /* Start searching from the beginning. */ + offset = 0; + len = llen; + + /* Reset the build buffer offset. */ + lbclen = 0; + + /* Reset empty match flag. */ + empty_ok = 1; + + /* + * We don't want to have to do a setline if the line didn't + * change -- keep track of whether or not this line changed. + * If doing confirmations, don't want to keep setting the + * line if change is refused -- keep track of substitutions. + */ + didsub = linechanged = 0; + + /* New line, do an EOL match. */ + do_eol_match = 1; + + /* It's not nul terminated, but we pretend it is. */ + eflags = REG_STARTEND; + + /* + * The search area is from s + offset to the EOL. + * + * Generally, match[0].rm_so is the offset of the start + * of the match from the start of the search, and offset + * is the offset of the start of the last search. + */ +nextmatch: match[0].rm_so = 0; + match[0].rm_eo = len; + + /* Get the next match. */ + eval = regexec(re, s + offset, 10, match, eflags); + + /* + * There wasn't a match or if there was an error, deal with + * it. If there was a previous match in this line, resolve + * the changes into the database. Otherwise, just move on. + */ + if (eval == REG_NOMATCH) + goto endmatch; + if (eval != 0) { + re_error(sp, eval, re); + goto err; + } + matched = 1; + + /* Only the first search can match an anchored expression. */ + eflags |= REG_NOTBOL; + + /* + * !!! + * It's possible to match 0-length strings -- for example, the + * command s;a*;X;, when matched against the string "aabb" will + * result in "XbXbX", i.e. the matches are "aa", the space + * between the b's and the space between the b's and the end of + * the string. There is a similar space between the beginning + * of the string and the a's. The rule that we use (because vi + * historically used it) is that any 0-length match, occurring + * immediately after a match, is ignored. Otherwise, the above + * example would have resulted in "XXbXbX". Another example is + * incorrectly using " *" to replace groups of spaces with one + * space. + * + * The way we do this is that if we just had a successful match, + * the starting offset does not skip characters, and the match + * is empty, ignore the match and move forward. If there's no + * more characters in the string, we were attempting to match + * after the last character, so quit. + */ + if (!empty_ok && match[0].rm_so == 0 && match[0].rm_eo == 0) { + empty_ok = 1; + if (len == 0) + goto endmatch; + BUILD(sp, s + offset, 1); + ++offset; + --len; + goto nextmatch; + } + + /* Confirm change. */ + if (sp->c_suffix) { + /* + * Set the cursor position for confirmation. Note, + * if we matched on a '$', the cursor may be past + * the end of line. + */ + from.lno = to.lno = lno; + from.cno = match[0].rm_so + offset; + to.cno = match[0].rm_eo + offset; + /* + * Both ex and vi have to correct for a change before + * the first character in the line. + */ + if (llen == 0) + from.cno = to.cno = 0; + if (F_ISSET(sp, SC_VI)) { + /* + * Only vi has to correct for a change after + * the last character in the line. + * + * XXX + * It would be nice to change the vi code so + * that we could display a cursor past EOL. + */ + if (to.cno >= llen) + to.cno = llen - 1; + if (from.cno >= llen) + from.cno = llen - 1; + + sp->lno = from.lno; + sp->cno = from.cno; + if (vs_refresh(sp, 1)) + goto err; + + vs_update(sp, msg_cat(sp, + "169|Confirm change? [n]", NULL), NULL); + + if (v_event_get(sp, &ev, 0, 0)) + goto err; + switch (ev.e_event) { + case E_CHARACTER: + break; + case E_EOF: + case E_ERR: + case E_INTERRUPT: + goto lquit; + default: + v_event_err(sp, &ev); + goto lquit; + } + } else { + if (ex_print(sp, cmdp, &from, &to, 0) || + ex_scprint(sp, &from, &to)) + goto lquit; + if (ex_txt(sp, tiq, 0, TXT_CR)) + goto err; + ev.e_c = TAILQ_FIRST(tiq)->lb[0]; + } + + switch (ev.e_c) { + case CH_YES: + break; + default: + case CH_NO: + didsub = 0; + BUILD(sp, s +offset, match[0].rm_eo); + goto skip; + case CH_QUIT: + /* Set the quit/interrupted flags. */ +lquit: quit = 1; + F_SET(sp->gp, G_INTERRUPTED); + + /* + * Resolve any changes, then return to (and + * exit from) the main loop. + */ + goto endmatch; + } + } + + /* + * Set the cursor to the last position changed, converting + * from 1-based to 0-based. + */ + sp->lno = lno; + sp->cno = match[0].rm_so; + + /* Copy the bytes before the match into the build buffer. */ + BUILD(sp, s + offset, match[0].rm_so); + + /* Substitute the matching bytes. */ + didsub = 1; + if (re_sub(sp, s + offset, &lb, &lbclen, &lblen, match)) + goto err; + + /* Set the change flag so we know this line was modified. */ + linechanged = 1; + + /* Move past the matched bytes. */ +skip: offset += match[0].rm_eo; + len -= match[0].rm_eo; + + /* A match cannot be followed by an empty pattern. */ + empty_ok = 0; + + /* + * If doing a global change with confirmation, we have to + * update the screen. The basic idea is to store the line + * so the screen update routines can find it, and restart. + */ + if (didsub && sp->c_suffix && sp->g_suffix) { + /* + * The new search offset will be the end of the + * modified line. + */ + saved_offset = lbclen; + + /* Copy the rest of the line. */ + if (len) + BUILD(sp, s + offset, len); + + /* Set the new offset. */ + offset = saved_offset; + + /* Store inserted lines, adjusting the build buffer. */ + last = 0; + if (sp->newl_cnt) { + for (cnt = 0; + cnt < sp->newl_cnt; ++cnt, ++lno, ++elno) { + if (db_insert(sp, lno, + lb + last, sp->newl[cnt] - last)) + goto err; + last = sp->newl[cnt] + 1; + ++sp->rptlines[L_ADDED]; + } + lbclen -= last; + offset -= last; + sp->newl_cnt = 0; + } + + /* Store and retrieve the line. */ + if (db_set(sp, lno, lb + last, lbclen)) + goto err; + if (db_get(sp, lno, DBG_FATAL, &s, &llen)) + goto err; + ADD_SPACE_RETW(sp, bp, blen, llen); + MEMCPY(bp, s, llen); + s = bp; + len = llen - offset; + + /* Restart the build. */ + lbclen = 0; + BUILD(sp, s, offset); + + /* + * If we haven't already done the after-the-string + * match, do one. Set REG_NOTEOL so the '$' pattern + * only matches once. + */ + if (!do_eol_match) + goto endmatch; + if (offset == len) { + do_eol_match = 0; + eflags |= REG_NOTEOL; + } + goto nextmatch; + } + + /* + * If it's a global: + * + * If at the end of the string, do a test for the after + * the string match. Set REG_NOTEOL so the '$' pattern + * only matches once. + */ + if (sp->g_suffix && do_eol_match) { + if (len == 0) { + do_eol_match = 0; + eflags |= REG_NOTEOL; + } + goto nextmatch; + } + +endmatch: if (!linechanged) + continue; + + /* Copy any remaining bytes into the build buffer. */ + if (len) + BUILD(sp, s + offset, len); + + /* Store inserted lines, adjusting the build buffer. */ + last = 0; + if (sp->newl_cnt) { + for (cnt = 0; + cnt < sp->newl_cnt; ++cnt, ++lno, ++elno) { + if (db_insert(sp, + lno, lb + last, sp->newl[cnt] - last)) + goto err; + last = sp->newl[cnt] + 1; + ++sp->rptlines[L_ADDED]; + } + lbclen -= last; + sp->newl_cnt = 0; + } + + /* Store the changed line. */ + if (db_set(sp, lno, lb + last, lbclen)) + goto err; + + /* Update changed line counter. */ + if (sp->rptlchange != lno) { + sp->rptlchange = lno; + ++sp->rptlines[L_CHANGED]; + } + + /* + * !!! + * Display as necessary. Historic practice is to only + * display the last line of a line split into multiple + * lines. + */ + if (lflag || nflag || pflag) { + from.lno = to.lno = lno; + from.cno = to.cno = 0; + if (lflag) + (void)ex_print(sp, cmdp, &from, &to, E_C_LIST); + if (nflag) + (void)ex_print(sp, cmdp, &from, &to, E_C_HASH); + if (pflag) + (void)ex_print(sp, cmdp, &from, &to, E_C_PRINT); + } + } + + /* + * !!! + * Historically, vi attempted to leave the cursor at the same place if + * the substitution was done at the current cursor position. Otherwise + * it moved it to the first non-blank of the last line changed. There + * were some problems: for example, :s/$/foo/ with the cursor on the + * last character of the line left the cursor on the last character, or + * the & command with multiple occurrences of the matching string in the + * line usually left the cursor in a fairly random position. + * + * We try to do the same thing, with the exception that if the user is + * doing substitution with confirmation, we move to the last line about + * which the user was consulted, as opposed to the last line that they + * actually changed. This prevents a screen flash if the user doesn't + * change many of the possible lines. + */ + if (!sp->c_suffix && (sp->lno != slno || sp->cno != scno)) { + sp->cno = 0; + (void)nonblank(sp, sp->lno, &sp->cno); + } + + /* + * If not in a global command, and nothing matched, say so. + * Else, if none of the lines displayed, put something up. + */ + rval = 0; + if (!matched) { + if (!F_ISSET(sp, SC_EX_GLOBAL)) { + msgq(sp, M_ERR, "157|No match found"); + goto err; + } + } else if (!lflag && !nflag && !pflag) + F_SET(cmdp, E_AUTOPRINT); + + if (0) { +err: rval = 1; + } + + if (bp != NULL) + FREE_SPACEW(sp, bp, blen); + free(lb); + return (rval); +} + +/* + * re_compile -- + * Compile the RE. + * + * PUBLIC: int re_compile(SCR *, + * PUBLIC: CHAR_T *, size_t, CHAR_T **, size_t *, regex_t *, u_int); + */ +int +re_compile(SCR *sp, CHAR_T *ptrn, size_t plen, CHAR_T **ptrnp, size_t *lenp, regex_t *rep, u_int flags) +{ + size_t len; + int reflags, replaced, rval; + CHAR_T *p; + + /* Set RE flags. */ + reflags = 0; + if (!LF_ISSET(RE_C_CSCOPE | RE_C_TAG)) { + if (O_ISSET(sp, O_EXTENDED)) + reflags |= REG_EXTENDED; + if (O_ISSET(sp, O_IGNORECASE)) + reflags |= REG_ICASE; + if (O_ISSET(sp, O_ICLOWER)) { + for (p = ptrn, len = plen; len > 0; ++p, --len) + if (ISUPPER(*p)) + break; + if (len == 0) + reflags |= REG_ICASE; + } + } + + /* If we're replacing a saved value, clear the old one. */ + if (LF_ISSET(RE_C_SEARCH) && F_ISSET(sp, SC_RE_SEARCH)) { + regfree(&sp->re_c); + F_CLR(sp, SC_RE_SEARCH); + } + if (LF_ISSET(RE_C_SUBST) && F_ISSET(sp, SC_RE_SUBST)) { + regfree(&sp->subre_c); + F_CLR(sp, SC_RE_SUBST); + } + + /* + * If we're saving the string, it's a pattern we haven't seen before, + * so convert the vi-style RE's to POSIX 1003.2 RE's. Save a copy for + * later recompilation. Free any previously saved value. + */ + if (ptrnp != NULL) { + replaced = 0; + if (LF_ISSET(RE_C_CSCOPE)) { + if (re_cscope_conv(sp, &ptrn, &plen, &replaced)) + return (1); + /* + * XXX + * Currently, the match-any- expression used in + * re_cscope_conv() requires extended RE's. This may + * not be right or safe. + */ + reflags |= REG_EXTENDED; + } else if (LF_ISSET(RE_C_TAG)) { + if (re_tag_conv(sp, &ptrn, &plen, &replaced)) + return (1); + } else + if (re_conv(sp, &ptrn, &plen, &replaced)) + return (1); + + /* Discard previous pattern. */ + free(*ptrnp); + *ptrnp = NULL; + + if (lenp != NULL) + *lenp = plen; + + /* + * Copy the string into allocated memory. + * + * XXX + * Regcomp isn't 8-bit clean, so the pattern is nul-terminated + * for now. There's just no other solution. + */ + MALLOC(sp, *ptrnp, (plen + 1) * sizeof(CHAR_T)); + if (*ptrnp != NULL) { + MEMCPY(*ptrnp, ptrn, plen); + (*ptrnp)[plen] = '\0'; + } + + /* Free up conversion-routine-allocated memory. */ + if (replaced) + FREE_SPACEW(sp, ptrn, 0); + + if (*ptrnp == NULL) + return (1); + + ptrn = *ptrnp; + } + + /* + * XXX + * Regcomp isn't 8-bit clean, so we just lost if the pattern + * contained a nul. Bummer! + */ + if ((rval = regcomp(rep, ptrn, /* plen, */ reflags)) != 0) { + if (!LF_ISSET(RE_C_SILENT)) + re_error(sp, rval, rep); + return (1); + } + + if (LF_ISSET(RE_C_SEARCH)) + F_SET(sp, SC_RE_SEARCH); + if (LF_ISSET(RE_C_SUBST)) + F_SET(sp, SC_RE_SUBST); + + return (0); +} + +/* + * re_conv -- + * Convert vi's regular expressions into something that the + * the POSIX 1003.2 RE functions can handle. + * + * There are three conversions we make to make vi's RE's (specifically + * the global, search, and substitute patterns) work with POSIX RE's. + * + * 1: If O_MAGIC is not set, strip backslashes from the magic character + * set (.[*~) that have them, and add them to the ones that don't. + * 2: If O_MAGIC is not set, the string "\~" is replaced with the text + * from the last substitute command's replacement string. If O_MAGIC + * is set, it's the string "~". + * 3: The pattern \ does "word" searches, convert it to use the + * new RE escapes. + * + * !!!/XXX + * This doesn't exactly match the historic behavior of vi because we do + * the ~ substitution before calling the RE engine, so magic characters + * in the replacement string will be expanded by the RE engine, and they + * weren't historically. It's a bug. + */ +static int +re_conv(SCR *sp, CHAR_T **ptrnp, size_t *plenp, int *replacedp) +{ + size_t blen, len, needlen; + int magic; + CHAR_T *bp, *p, *t; + + /* + * First pass through, we figure out how much space we'll need. + * We do it in two passes, on the grounds that most of the time + * the user is doing a search and won't have magic characters. + * That way we can skip most of the memory allocation and copies. + */ + magic = 0; + for (p = *ptrnp, len = *plenp, needlen = 0; len > 0; ++p, --len) + switch (*p) { + case '\\': + if (len > 1) { + --len; + switch (*++p) { + case '<': + magic = 1; + needlen += RE_WSTART_LEN + 1; + break; + case '>': + magic = 1; + needlen += RE_WSTOP_LEN + 1; + break; + case '~': + if (!O_ISSET(sp, O_MAGIC)) { + magic = 1; + needlen += sp->repl_len; + } + break; + case '.': + case '[': + case '*': + if (!O_ISSET(sp, O_MAGIC)) { + magic = 1; + needlen += 1; + } + break; + default: + needlen += 2; + } + } else + needlen += 1; + break; + case '~': + if (O_ISSET(sp, O_MAGIC)) { + magic = 1; + needlen += sp->repl_len; + } + break; + case '.': + case '[': + case '*': + if (!O_ISSET(sp, O_MAGIC)) { + magic = 1; + needlen += 2; + } + break; + default: + needlen += 1; + break; + } + + if (!magic) { + *replacedp = 0; + return (0); + } + + /* Get enough memory to hold the final pattern. */ + *replacedp = 1; + GET_SPACE_RETW(sp, bp, blen, needlen); + + for (p = *ptrnp, len = *plenp, t = bp; len > 0; ++p, --len) + switch (*p) { + case '\\': + if (len > 1) { + --len; + switch (*++p) { + case '<': + MEMCPY(t, + RE_WSTART, RE_WSTART_LEN); + t += RE_WSTART_LEN; + break; + case '>': + MEMCPY(t, + RE_WSTOP, RE_WSTOP_LEN); + t += RE_WSTOP_LEN; + break; + case '~': + if (O_ISSET(sp, O_MAGIC)) + *t++ = '~'; + else { + MEMCPY(t, + sp->repl, sp->repl_len); + t += sp->repl_len; + } + break; + case '.': + case '[': + case '*': + if (O_ISSET(sp, O_MAGIC)) + *t++ = '\\'; + *t++ = *p; + break; + default: + *t++ = '\\'; + *t++ = *p; + } + } else + *t++ = '\\'; + break; + case '~': + if (O_ISSET(sp, O_MAGIC)) { + MEMCPY(t, sp->repl, sp->repl_len); + t += sp->repl_len; + } else + *t++ = '~'; + break; + case '.': + case '[': + case '*': + if (!O_ISSET(sp, O_MAGIC)) + *t++ = '\\'; + *t++ = *p; + break; + default: + *t++ = *p; + break; + } + + *ptrnp = bp; + *plenp = t - bp; + return (0); +} + +/* + * re_tag_conv -- + * Convert a tags search path into something that the POSIX + * 1003.2 RE functions can handle. + */ +static int +re_tag_conv(SCR *sp, CHAR_T **ptrnp, size_t *plenp, int *replacedp) +{ + size_t blen, len; + int lastdollar; + CHAR_T *bp, *p, *t; + + len = *plenp; + + /* Max memory usage is 2 times the length of the string. */ + *replacedp = 1; + GET_SPACE_RETW(sp, bp, blen, len * 2); + + p = *ptrnp; + t = bp; + + /* If the last character is a '/' or '?', we just strip it. */ + if (len > 0 && (p[len - 1] == '/' || p[len - 1] == '?')) + --len; + + /* If the next-to-last or last character is a '$', it's magic. */ + if (len > 0 && p[len - 1] == '$') { + --len; + lastdollar = 1; + } else + lastdollar = 0; + + /* If the first character is a '/' or '?', we just strip it. */ + if (len > 0 && (p[0] == '/' || p[0] == '?')) { + ++p; + --len; + } + + /* If the first or second character is a '^', it's magic. */ + if (p[0] == '^') { + *t++ = *p++; + --len; + } + + /* + * Escape every other magic character we can find, meanwhile stripping + * the backslashes ctags inserts when escaping the search delimiter + * characters. + */ + for (; len > 0; --len) { + if (p[0] == '\\' && (p[1] == '/' || p[1] == '?')) { + ++p; + --len; + } else if (STRCHR(L("^.[]$*"), p[0])) + *t++ = '\\'; + *t++ = *p++; + } + if (lastdollar) + *t++ = '$'; + + *ptrnp = bp; + *plenp = t - bp; + return (0); +} + +/* + * re_cscope_conv -- + * Convert a cscope search path into something that the POSIX + * 1003.2 RE functions can handle. + */ +static int +re_cscope_conv(SCR *sp, CHAR_T **ptrnp, size_t *plenp, int *replacedp) +{ + size_t blen, len, nspaces; + CHAR_T *bp, *t; + CHAR_T *p; + CHAR_T *wp; + size_t wlen; + + /* + * Each space in the source line printed by cscope represents an + * arbitrary sequence of spaces, tabs, and comments. + */ +#define CSCOPE_RE_SPACE "([ \t]|/\\*([^*]|\\*/)*\\*/)*" +#define CSCOPE_LEN sizeof(CSCOPE_RE_SPACE) - 1 + CHAR2INT(sp, CSCOPE_RE_SPACE, CSCOPE_LEN, wp, wlen); + for (nspaces = 0, p = *ptrnp, len = *plenp; len > 0; ++p, --len) + if (*p == ' ') + ++nspaces; + + /* + * Allocate plenty of space: + * the string, plus potential escaping characters; + * nspaces + 2 copies of CSCOPE_RE_SPACE; + * ^, $, nul terminator characters. + */ + *replacedp = 1; + len = (p - *ptrnp) * 2 + (nspaces + 2) * sizeof(CSCOPE_RE_SPACE) + 3; + GET_SPACE_RETW(sp, bp, blen, len); + + p = *ptrnp; + t = bp; + + *t++ = '^'; + MEMCPY(t, wp, wlen); + t += wlen; + + for (len = *plenp; len > 0; ++p, --len) + if (*p == ' ') { + MEMCPY(t, wp, wlen); + t += wlen; + } else { + if (STRCHR(L("\\^.[]$*+?()|{}"), *p)) + *t++ = '\\'; + *t++ = *p; + } + + MEMCPY(t, wp, wlen); + t += wlen; + *t++ = '$'; + + *ptrnp = bp; + *plenp = t - bp; + return (0); +} + +/* + * re_error -- + * Report a regular expression error. + * + * PUBLIC: void re_error(SCR *, int, regex_t *); + */ +void +re_error(SCR *sp, int errcode, regex_t *preg) +{ + size_t s; + char *oe; + + s = regerror(errcode, preg, "", 0); + MALLOC(sp, oe, s); + if (oe != NULL) { + (void)regerror(errcode, preg, oe, s); + msgq(sp, M_ERR, "RE error: %s", oe); + free(oe); + } +} + +/* + * re_sub -- + * Do the substitution for a regular expression. + */ +static int +re_sub( + SCR *sp, + CHAR_T *ip, /* Input line. */ + CHAR_T **lbp, + size_t *lbclenp, + size_t *lblenp, + regmatch_t match[10]) +{ + enum { C_NOTSET, C_LOWER, C_ONELOWER, C_ONEUPPER, C_UPPER } conv; + size_t lbclen, lblen; /* Local copies. */ + size_t mlen; /* Match length. */ + size_t rpl; /* Remaining replacement length. */ + CHAR_T *rp; /* Replacement pointer. */ + int ch; + int no; /* Match replacement offset. */ + CHAR_T *p, *t; /* Buffer pointers. */ + CHAR_T *lb; /* Local copies. */ + + lb = *lbp; /* Get local copies. */ + lbclen = *lbclenp; + lblen = *lblenp; + + /* + * QUOTING NOTE: + * + * There are some special sequences that vi provides in the + * replacement patterns. + * & string the RE matched (\& if nomagic set) + * \# n-th regular subexpression + * \E end \U, \L conversion + * \e end \U, \L conversion + * \l convert the next character to lower-case + * \L convert to lower-case, until \E, \e, or end of replacement + * \u convert the next character to upper-case + * \U convert to upper-case, until \E, \e, or end of replacement + * + * Otherwise, since this is the lowest level of replacement, discard + * all escaping characters. This (hopefully) matches historic practice. + */ +#define OUTCH(ch, nltrans) do { \ + ARG_CHAR_T __ch = (ch); \ + e_key_t __value = KEY_VAL(sp, __ch); \ + if (nltrans && (__value == K_CR || __value == K_NL)) { \ + NEEDNEWLINE(sp); \ + sp->newl[sp->newl_cnt++] = lbclen; \ + } else if (conv != C_NOTSET) { \ + switch (conv) { \ + case C_ONELOWER: \ + conv = C_NOTSET; \ + /* FALLTHROUGH */ \ + case C_LOWER: \ + if (ISUPPER(__ch)) \ + __ch = TOLOWER(__ch); \ + break; \ + case C_ONEUPPER: \ + conv = C_NOTSET; \ + /* FALLTHROUGH */ \ + case C_UPPER: \ + if (ISLOWER(__ch)) \ + __ch = TOUPPER(__ch); \ + break; \ + default: \ + abort(); \ + } \ + } \ + NEEDSP(sp, 1, p); \ + *p++ = __ch; \ + ++lbclen; \ +} while (0) + conv = C_NOTSET; + for (rp = sp->repl, rpl = sp->repl_len, p = lb + lbclen; rpl--;) { + switch (ch = *rp++) { + case '&': + if (O_ISSET(sp, O_MAGIC)) { + no = 0; + goto subzero; + } + break; + case '\\': + if (rpl == 0) + break; + --rpl; + switch (ch = *rp) { + case '&': + ++rp; + if (!O_ISSET(sp, O_MAGIC)) { + no = 0; + goto subzero; + } + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + no = *rp++ - '0'; +subzero: if (match[no].rm_so == -1 || + match[no].rm_eo == -1) + break; + mlen = match[no].rm_eo - match[no].rm_so; + for (t = ip + match[no].rm_so; mlen--; ++t) + OUTCH(*t, 0); + continue; + case 'e': + case 'E': + ++rp; + conv = C_NOTSET; + continue; + case 'l': + ++rp; + conv = C_ONELOWER; + continue; + case 'L': + ++rp; + conv = C_LOWER; + continue; + case 'u': + ++rp; + conv = C_ONEUPPER; + continue; + case 'U': + ++rp; + conv = C_UPPER; + continue; + case '\r': + OUTCH(ch, 0); + continue; + default: + ++rp; + break; + } + } + OUTCH(ch, 1); + } + + *lbp = lb; /* Update caller's information. */ + *lbclenp = lbclen; + *lblenp = lblen; + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_subst.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_def.h =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_def.h (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_def.h (revision 366308) @@ -0,0 +1,76 @@ +#define C_SCROLL 0 +#define C_BANG 1 +#define C_HASH 2 +#define C_SUBAGAIN 3 +#define C_STAR 4 +#define C_SHIFTL 5 +#define C_EQUAL 6 +#define C_SHIFTR 7 +#define C_AT 8 +#define C_APPEND 9 +#define C_ABBR 10 +#define C_ARGS 11 +#define C_BG 12 +#define C_CHANGE 13 +#define C_CD 14 +#define C_CHDIR 15 +#define C_COPY 16 +#define C_CSCOPE 17 +#define C_DELETE 18 +#define C_DISPLAY 19 +#define C_EDIT 20 +#define C_EX 21 +#define C_EXUSAGE 22 +#define C_FILE 23 +#define C_FG 24 +#define C_GLOBAL 25 +#define C_HELP 26 +#define C_INSERT 27 +#define C_JOIN 28 +#define C_K 29 +#define C_LIST 30 +#define C_MOVE 31 +#define C_MARK 32 +#define C_MAP 33 +#define C_MKEXRC 34 +#define C_NEXT 35 +#define C_NUMBER 36 +#define C_OPEN 37 +#define C_PRINT 38 +#define C_PRESERVE 39 +#define C_PREVIOUS 40 +#define C_PUT 41 +#define C_QUIT 42 +#define C_READ 43 +#define C_RECOVER 44 +#define C_RESIZE 45 +#define C_REWIND 46 +#define C_SUBSTITUTE 47 +#define C_SCRIPT 48 +#define C_SET 49 +#define C_SHELL 50 +#define C_SOURCE 51 +#define C_STOP 52 +#define C_SUSPEND 53 +#define C_T 54 +#define C_TAG 55 +#define C_TAGNEXT 56 +#define C_TAGPOP 57 +#define C_TAGPREV 58 +#define C_TAGTOP 59 +#define C_UNDO 60 +#define C_UNABBREVIATE 61 +#define C_UNMAP 62 +#define C_V 63 +#define C_VERSION 64 +#define C_VISUAL_EX 65 +#define C_VISUAL_VI 66 +#define C_VIUSAGE 67 +#define C_VSPLIT 68 +#define C_WRITE 69 +#define C_WN 70 +#define C_WQ 71 +#define C_XIT 72 +#define C_YANK 73 +#define C_Z 74 +#define C_SUBTILDE 75 Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_def.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/extern.h =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/extern.h (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/extern.h (revision 366308) @@ -0,0 +1,131 @@ +int ex(SCR **); +int ex_cmd(SCR *); +int ex_range(SCR *, EXCMD *, int *); +int ex_is_abbrev(CHAR_T *, size_t); +int ex_is_unmap(CHAR_T *, size_t); +void ex_badaddr + (SCR *, EXCMDLIST const *, enum badaddr, enum nresult); +int ex_abbr(SCR *, EXCMD *); +int ex_unabbr(SCR *, EXCMD *); +int ex_append(SCR *, EXCMD *); +int ex_change(SCR *, EXCMD *); +int ex_insert(SCR *, EXCMD *); +int ex_next(SCR *, EXCMD *); +int ex_prev(SCR *, EXCMD *); +int ex_rew(SCR *, EXCMD *); +int ex_args(SCR *, EXCMD *); +char **ex_buildargv(SCR *, EXCMD *, char *); +int argv_init(SCR *, EXCMD *); +int argv_exp0(SCR *, EXCMD *, CHAR_T *, size_t); +int argv_exp1(SCR *, EXCMD *, CHAR_T *, size_t, int); +int argv_exp2(SCR *, EXCMD *, CHAR_T *, size_t); +int argv_exp3(SCR *, EXCMD *, CHAR_T *, size_t); +int argv_flt_ex(SCR *, EXCMD *, CHAR_T *, size_t); +int argv_free(SCR *); +int argv_flt_path(SCR *, EXCMD *, CHAR_T *, size_t); +CHAR_T *argv_esc(SCR *, EXCMD *, CHAR_T *, size_t); +CHAR_T *argv_uesc(SCR *, EXCMD *, CHAR_T *, size_t); +int ex_at(SCR *, EXCMD *); +int ex_bang(SCR *, EXCMD *); +int ex_cd(SCR *, EXCMD *); +int ex_cscope(SCR *, EXCMD *); +int cscope_end(SCR *); +int cscope_display(SCR *); +int cscope_search(SCR *, TAGQ *, TAG *); +int ex_delete(SCR *, EXCMD *); +int ex_display(SCR *, EXCMD *); +int ex_edit(SCR *, EXCMD *); +int ex_equal(SCR *, EXCMD *); +int ex_file(SCR *, EXCMD *); +int ex_filter(SCR *, + EXCMD *, MARK *, MARK *, MARK *, CHAR_T *, enum filtertype); +int ex_global(SCR *, EXCMD *); +int ex_v(SCR *, EXCMD *); +int ex_g_insdel(SCR *, lnop_t, recno_t); +int ex_screen_copy(SCR *, SCR *); +int ex_screen_end(SCR *); +int ex_optchange(SCR *, int, char *, u_long *); +int ex_exrc(SCR *); +int ex_run_str(SCR *, char *, CHAR_T *, size_t, int, int); +int ex_join(SCR *, EXCMD *); +int ex_map(SCR *, EXCMD *); +int ex_unmap(SCR *, EXCMD *); +int ex_mark(SCR *, EXCMD *); +int ex_mkexrc(SCR *, EXCMD *); +int ex_copy(SCR *, EXCMD *); +int ex_move(SCR *, EXCMD *); +int ex_open(SCR *, EXCMD *); +int ex_preserve(SCR *, EXCMD *); +int ex_recover(SCR *, EXCMD *); +int ex_list(SCR *, EXCMD *); +int ex_number(SCR *, EXCMD *); +int ex_pr(SCR *, EXCMD *); +int ex_print(SCR *, EXCMD *, MARK *, MARK *, u_int32_t); +int ex_ldisplay(SCR *, const CHAR_T *, size_t, size_t, u_int); +int ex_scprint(SCR *, MARK *, MARK *); +int ex_printf(SCR *, const char *, ...); +int ex_puts(SCR *, const char *); +int ex_fflush(SCR *sp); +int ex_put(SCR *, EXCMD *); +int ex_quit(SCR *, EXCMD *); +int ex_read(SCR *, EXCMD *); +int ex_readfp(SCR *, char *, FILE *, MARK *, recno_t *, int); +int ex_bg(SCR *, EXCMD *); +int ex_fg(SCR *, EXCMD *); +int ex_resize(SCR *, EXCMD *); +int ex_sdisplay(SCR *); +int ex_script(SCR *, EXCMD *); +int sscr_exec(SCR *, recno_t); +int sscr_input(SCR *); +int sscr_end(SCR *); +int ex_set(SCR *, EXCMD *); +int ex_shell(SCR *, EXCMD *); +int ex_exec_proc(SCR *, EXCMD *, char *, const char *, int); +int proc_wait(SCR *, long, const char *, int, int); +int ex_shiftl(SCR *, EXCMD *); +int ex_shiftr(SCR *, EXCMD *); +int ex_retab(SCR *, EXCMD *); +int ex_source(SCR *, EXCMD *); +int ex_stop(SCR *, EXCMD *); +int ex_s(SCR *, EXCMD *); +int ex_subagain(SCR *, EXCMD *); +int ex_subtilde(SCR *, EXCMD *); +int re_compile(SCR *, + CHAR_T *, size_t, CHAR_T **, size_t *, regex_t *, u_int); +void re_error(SCR *, int, regex_t *); +int ex_tag_first(SCR *, CHAR_T *); +int ex_tag_push(SCR *, EXCMD *); +int ex_tag_next(SCR *, EXCMD *); +int ex_tag_prev(SCR *, EXCMD *); +int ex_tag_nswitch(SCR *, TAG *, int); +int ex_tag_Nswitch(SCR *, TAG *, int); +int ex_tag_pop(SCR *, EXCMD *); +int ex_tag_top(SCR *, EXCMD *); +int ex_tag_display(SCR *); +int ex_tag_copy(SCR *, SCR *); +int tagq_free(SCR *, TAGQ *); +int tagq_push(SCR*, TAGQ*, int, int ); +void tag_msg(SCR *, tagmsg_t, char *); +int ex_tagf_alloc(SCR *, char *); +int ex_tag_free(SCR *); +int ex_txt(SCR *, TEXTH *, ARG_CHAR_T, u_int32_t); +int ex_undo(SCR *, EXCMD *); +int ex_help(SCR *, EXCMD *); +int ex_usage(SCR *, EXCMD *); +int ex_viusage(SCR *, EXCMD *); +void ex_cinit(SCR *, EXCMD *, int, int, recno_t, recno_t, int); +int ex_getline(SCR *, FILE *, size_t *); +int ex_ncheck(SCR *, int); +int ex_init(SCR *); +void ex_wemsg(SCR *, CHAR_T *, exm_t); +void ex_emsg(SCR *, char *, exm_t); +int ex_version(SCR *, EXCMD *); +int ex_visual(SCR *, EXCMD *); +int ex_wn(SCR *, EXCMD *); +int ex_wq(SCR *, EXCMD *); +int ex_write(SCR *, EXCMD *); +int ex_xit(SCR *, EXCMD *); +int ex_writefp(SCR *, + char *, FILE *, MARK *, MARK *, u_long *, u_long *, int); +int ex_yank(SCR *, EXCMD *); +int ex_z(SCR *, EXCMD *); Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/extern.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/version.h =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/version.h (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/version.h (revision 366308) @@ -0,0 +1 @@ +#define VI_VERSION "2.2.0 (2020-08-01)" Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/version.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_abbrev.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_abbrev.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_abbrev.c (revision 366308) @@ -0,0 +1,109 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "../common/common.h" +#include "../vi/vi.h" + +/* + * ex_abbr -- :abbreviate [key replacement] + * Create an abbreviation or display abbreviations. + * + * PUBLIC: int ex_abbr(SCR *, EXCMD *); + */ +int +ex_abbr(SCR *sp, EXCMD *cmdp) +{ + CHAR_T *p; + size_t len; + + switch (cmdp->argc) { + case 0: + if (seq_dump(sp, SEQ_ABBREV, 0) == 0) + msgq(sp, M_INFO, "105|No abbreviations to display"); + return (0); + case 2: + break; + default: + abort(); + } + + /* + * Check for illegal characters. + * + * !!! + * Another fun one, historically. See vi/v_ntext.c:txt_abbrev() for + * details. The bottom line is that all abbreviations have to end + * with a "word" character, because it's the transition from word to + * non-word characters that triggers the test for an abbreviation. In + * addition, because of the way the test is done, there can't be any + * transitions from word to non-word character (or vice-versa) other + * than between the next-to-last and last characters of the string, + * and there can't be any characters. Warn the user. + */ + if (!inword(cmdp->argv[0]->bp[cmdp->argv[0]->len - 1])) { + msgq(sp, M_ERR, + "106|Abbreviations must end with a \"word\" character"); + return (1); + } + for (p = cmdp->argv[0]->bp; *p != '\0'; ++p) + if (ISBLANK(p[0])) { + msgq(sp, M_ERR, + "107|Abbreviations may not contain tabs or spaces"); + return (1); + } + if (cmdp->argv[0]->len > 2) + for (p = cmdp->argv[0]->bp, + len = cmdp->argv[0]->len - 2; len; --len, ++p) + if (inword(p[0]) != inword(p[1])) { + msgq(sp, M_ERR, +"108|Abbreviations may not mix word/non-word characters, except at the end"); + return (1); + } + + if (seq_set(sp, NULL, 0, cmdp->argv[0]->bp, cmdp->argv[0]->len, + cmdp->argv[1]->bp, cmdp->argv[1]->len, SEQ_ABBREV, SEQ_USERDEF)) + return (1); + + F_SET(sp->gp, G_ABBREV); + return (0); +} + +/* + * ex_unabbr -- :unabbreviate key + * Delete an abbreviation. + * + * PUBLIC: int ex_unabbr(SCR *, EXCMD *); + */ +int +ex_unabbr(SCR *sp, EXCMD *cmdp) +{ + ARGS *ap; + + ap = cmdp->argv[0]; + if (!F_ISSET(sp->gp, G_ABBREV) || + seq_delete(sp, ap->bp, ap->len, SEQ_ABBREV)) { + msgq_wstr(sp, M_ERR, ap->bp, + "109|\"%s\" is not an abbreviation"); + return (1); + } + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_abbrev.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_append.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_append.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_append.c (revision 366308) @@ -0,0 +1,265 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "../common/common.h" + +enum which {APPEND, CHANGE, INSERT}; + +static int ex_aci(SCR *, EXCMD *, enum which); + +/* + * ex_append -- :[line] a[ppend][!] + * Append one or more lines of new text after the specified line, + * or the current line if no address is specified. + * + * PUBLIC: int ex_append(SCR *, EXCMD *); + */ +int +ex_append(SCR *sp, EXCMD *cmdp) +{ + return (ex_aci(sp, cmdp, APPEND)); +} + +/* + * ex_change -- :[line[,line]] c[hange][!] [count] + * Change one or more lines to the input text. + * + * PUBLIC: int ex_change(SCR *, EXCMD *); + */ +int +ex_change(SCR *sp, EXCMD *cmdp) +{ + return (ex_aci(sp, cmdp, CHANGE)); +} + +/* + * ex_insert -- :[line] i[nsert][!] + * Insert one or more lines of new text before the specified line, + * or the current line if no address is specified. + * + * PUBLIC: int ex_insert(SCR *, EXCMD *); + */ +int +ex_insert(SCR *sp, EXCMD *cmdp) +{ + return (ex_aci(sp, cmdp, INSERT)); +} + +/* + * ex_aci -- + * Append, change, insert in ex. + */ +static int +ex_aci(SCR *sp, EXCMD *cmdp, enum which cmd) +{ + CHAR_T *p, *t; + GS *gp; + TEXT *tp; + TEXTH tiq[] = {{ 0 }}; + recno_t cnt = 0, lno; + size_t len; + u_int32_t flags; + int need_newline; + + gp = sp->gp; + NEEDFILE(sp, cmdp); + + /* + * If doing a change, replace lines for as long as possible. Then, + * append more lines or delete remaining lines. Changes to an empty + * file are appends, inserts are the same as appends to the previous + * line. + * + * !!! + * Set the address to which we'll append. We set sp->lno to this + * address as well so that autoindent works correctly when get text + * from the user. + */ + lno = cmdp->addr1.lno; + sp->lno = lno; + if ((cmd == CHANGE || cmd == INSERT) && lno != 0) + --lno; + + /* + * !!! + * If the file isn't empty, cut changes into the unnamed buffer. + */ + if (cmd == CHANGE && cmdp->addr1.lno != 0 && + (cut(sp, NULL, &cmdp->addr1, &cmdp->addr2, CUT_LINEMODE) || + del(sp, &cmdp->addr1, &cmdp->addr2, 1))) + return (1); + + /* + * !!! + * Anything that was left after the command separator becomes part + * of the inserted text. Apparently, it was common usage to enter: + * + * :g/pattern/append|stuff1 + * + * and append the line of text "stuff1" to the lines containing the + * pattern. It was also historically legal to enter: + * + * :append|stuff1 + * stuff2 + * . + * + * and the text on the ex command line would be appended as well as + * the text inserted after it. There was an historic bug however, + * that the user had to enter *two* terminating lines (the '.' lines) + * to terminate text input mode, in this case. This whole thing + * could be taken too far, however. Entering: + * + * :append|stuff1\ + * stuff2 + * stuff3 + * . + * + * i.e. mixing and matching the forms confused the historic vi, and, + * not only did it take two terminating lines to terminate text input + * mode, but the trailing backslashes were retained on the input. We + * match historic practice except that we discard the backslashes. + * + * Input lines specified on the ex command line lines are separated by + * s. If there is a trailing delimiter an empty line was + * inserted. There may also be a leading delimiter, which is ignored + * unless it's also a trailing delimiter. It is possible to encounter + * a termination line, i.e. a single '.', in a global command, but not + * necessary if the text insert command was the last of the global + * commands. + */ + if (cmdp->save_cmdlen != 0) { + for (p = cmdp->save_cmd, + len = cmdp->save_cmdlen; len > 0; p = t) { + for (t = p; len > 0 && t[0] != '\n'; ++t, --len); + if (t != p || len == 0) { + if (F_ISSET(sp, SC_EX_GLOBAL) && + t - p == 1 && p[0] == '.') { + ++t; + if (len > 0) + --len; + break; + } + if (db_append(sp, 1, lno++, p, t - p)) + return (1); + } + if (len != 0) { + ++t; + if (--len == 0 && + db_append(sp, 1, lno++, NULL, 0)) + return (1); + } + } + /* + * If there's any remaining text, we're in a global, and + * there's more command to parse. + * + * !!! + * We depend on the fact that non-global commands will eat the + * rest of the command line as text input, and before getting + * any text input from the user. Otherwise, we'd have to save + * off the command text before or during the call to the text + * input function below. + */ + if (len != 0) + cmdp->save_cmd = t; + cmdp->save_cmdlen = len; + } + + if (F_ISSET(sp, SC_EX_GLOBAL)) { + if ((sp->lno = lno) == 0 && db_exist(sp, 1)) + sp->lno = 1; + return (0); + } + + /* + * If not in a global command, read from the terminal. + * + * If this code is called by vi, we want to reset the terminal and use + * ex's line get routine. It actually works fine if we use vi's get + * routine, but it doesn't look as nice. Maybe if we had a separate + * window or something, but getting a line at a time looks awkward. + * However, depending on the screen that we're using, that may not + * be possible. + */ + if (F_ISSET(sp, SC_VI)) { + if (gp->scr_screen(sp, SC_EX)) { + ex_wemsg(sp, cmdp->cmd->name, EXM_NOCANON); + return (1); + } + + /* If we're still in the vi screen, move out explicitly. */ + need_newline = !F_ISSET(sp, SC_SCR_EXWROTE); + F_SET(sp, SC_SCR_EX | SC_SCR_EXWROTE); + if (need_newline) + (void)ex_puts(sp, "\n"); + + /* + * !!! + * Users of historical versions of vi sometimes get confused + * when they enter append mode, and can't seem to get out of + * it. Give them an informational message. + */ + (void)ex_puts(sp, + msg_cat(sp, "273|Entering ex input mode.", NULL)); + (void)ex_puts(sp, "\n"); + (void)ex_fflush(sp); + } + + /* + * Set input flags; the ! flag turns off autoindent for append, + * change and insert. + */ + LF_INIT(TXT_DOTTERM | TXT_NUMBER); + if (!FL_ISSET(cmdp->iflags, E_C_FORCE) && O_ISSET(sp, O_AUTOINDENT)) + LF_SET(TXT_AUTOINDENT); + if (O_ISSET(sp, O_BEAUTIFY)) + LF_SET(TXT_BEAUTIFY); + + /* + * This code can't use the common screen TEXTH structure (sp->tiq), + * as it may already be in use, e.g. ":append|s/abc/ABC/" would fail + * as we are only halfway through the text when the append code fires. + * Use a local structure instead. (The ex code would have to use a + * local structure except that we're guaranteed to finish remaining + * characters in the common TEXTH structure when they were inserted + * into the file, above.) + */ + TAILQ_INIT(tiq); + + if (ex_txt(sp, tiq, 0, flags)) + return (1); + + TAILQ_FOREACH(tp, tiq, q) { + if (db_append(sp, 1, lno++, tp->lb, tp->len)) + return (1); + ++cnt; + } + + /* + * Set sp->lno to the final line number value (correcting for a + * possible 0 value) as that's historically correct for the final + * line value, whether or not the user entered any text. + */ + if ((sp->lno = lno) == 0 && db_exist(sp, 1)) + sp->lno = 1; + + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_append.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_args.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_args.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_args.c (revision 366308) @@ -0,0 +1,325 @@ +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1991, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "../common/common.h" +#include "../vi/vi.h" + +static int ex_N_next(SCR *, EXCMD *); + +/* + * ex_next -- :next [+cmd] [files] + * Edit the next file, optionally setting the list of files. + * + * !!! + * The :next command behaved differently from the :rewind command in + * historic vi. See nvi/docs/autowrite for details, but the basic + * idea was that it ignored the force flag if the autowrite flag was + * set. This implementation handles them all identically. + * + * PUBLIC: int ex_next(SCR *, EXCMD *); + */ +int +ex_next(SCR *sp, EXCMD *cmdp) +{ + ARGS **argv; + FREF *frp; + int noargs; + char **ap; + CHAR_T *wp; + size_t wlen; + char *np; + size_t nlen; + + /* Check for file to move to. */ + if (cmdp->argc == 0 && (sp->cargv == NULL || sp->cargv[1] == NULL)) { + msgq(sp, M_ERR, "111|No more files to edit"); + return (1); + } + + if (F_ISSET(cmdp, E_NEWSCREEN)) { + /* By default, edit the next file in the old argument list. */ + if (cmdp->argc == 0) { + CHAR2INT(sp, sp->cargv[1], strlen(sp->cargv[1]) + 1, + wp, wlen); + if (argv_exp0(sp, cmdp, wp, wlen - 1)) + return (1); + return (ex_edit(sp, cmdp)); + } + return (ex_N_next(sp, cmdp)); + } + + /* Check modification. */ + if (file_m1(sp, + FL_ISSET(cmdp->iflags, E_C_FORCE), FS_ALL | FS_POSSIBLE)) + return (1); + + /* Any arguments are a replacement file list. */ + if (cmdp->argc) { + /* Free the current list. */ + if (!F_ISSET(sp, SC_ARGNOFREE) && sp->argv != NULL) { + for (ap = sp->argv; *ap != NULL; ++ap) + free(*ap); + free(sp->argv); + } + F_CLR(sp, SC_ARGNOFREE | SC_ARGRECOVER); + sp->cargv = NULL; + + /* Create a new list. */ + CALLOC_RET(sp, sp->argv, cmdp->argc + 1, sizeof(char *)); + for (ap = sp->argv, + argv = cmdp->argv; argv[0]->len != 0; ++ap, ++argv) { + INT2CHAR(sp, argv[0]->bp, argv[0]->len, np, nlen); + if ((*ap = v_strdup(sp, np, nlen)) == NULL) + return (1); + } + *ap = NULL; + + /* Switch to the first file. */ + sp->cargv = sp->argv; + if ((frp = file_add(sp, *sp->cargv)) == NULL) + return (1); + noargs = 0; + + /* Display a file count with the welcome message. */ + F_SET(sp, SC_STATUS_CNT); + } else { + if ((frp = file_add(sp, sp->cargv[1])) == NULL) + return (1); + if (F_ISSET(sp, SC_ARGRECOVER)) + F_SET(frp, FR_RECOVER); + noargs = 1; + } + + if (file_init(sp, frp, NULL, FS_SETALT | + (FL_ISSET(cmdp->iflags, E_C_FORCE) ? FS_FORCE : 0))) + return (1); + if (noargs) + ++sp->cargv; + + F_SET(sp, SC_FSWITCH); + return (0); +} + +/* + * ex_N_next -- + * New screen version of ex_next. + */ +static int +ex_N_next(SCR *sp, EXCMD *cmdp) +{ + SCR *new; + FREF *frp; + char *np; + size_t nlen; + + /* Get a new screen. */ + if (screen_init(sp->gp, sp, &new)) + return (1); + if (vs_split(sp, new, 0)) { + (void)screen_end(new); + return (1); + } + + /* Get a backing file. */ + INT2CHAR(sp, cmdp->argv[0]->bp, cmdp->argv[0]->len + 1, np, nlen); + if ((frp = file_add(new, np)) == NULL || + file_init(new, frp, NULL, + (FL_ISSET(cmdp->iflags, E_C_FORCE) ? FS_FORCE : 0))) { + (void)vs_discard(new, NULL); + (void)screen_end(new); + return (1); + } + + /* The arguments are a replacement file list. */ + new->cargv = new->argv = ex_buildargv(sp, cmdp, NULL); + + /* Display a file count with the welcome message. */ + F_SET(new, SC_STATUS_CNT); + + /* Set up the switch. */ + sp->nextdisp = new; + F_SET(sp, SC_SSWITCH); + + return (0); +} + +/* + * ex_prev -- :prev + * Edit the previous file. + * + * PUBLIC: int ex_prev(SCR *, EXCMD *); + */ +int +ex_prev(SCR *sp, EXCMD *cmdp) +{ + FREF *frp; + size_t wlen; + CHAR_T *wp; + + if (sp->cargv == sp->argv) { + msgq(sp, M_ERR, "112|No previous files to edit"); + return (1); + } + + if (F_ISSET(cmdp, E_NEWSCREEN)) { + CHAR2INT(sp, sp->cargv[-1], strlen(sp->cargv[-1]) + 1, + wp, wlen); + if (argv_exp0(sp, cmdp, wp, wlen - 1)) + return (1); + return (ex_edit(sp, cmdp)); + } + + if (file_m1(sp, + FL_ISSET(cmdp->iflags, E_C_FORCE), FS_ALL | FS_POSSIBLE)) + return (1); + + if ((frp = file_add(sp, sp->cargv[-1])) == NULL) + return (1); + + if (file_init(sp, frp, NULL, FS_SETALT | + (FL_ISSET(cmdp->iflags, E_C_FORCE) ? FS_FORCE : 0))) + return (1); + --sp->cargv; + + F_SET(sp, SC_FSWITCH); + return (0); +} + +/* + * ex_rew -- :rew + * Re-edit the list of files. + * + * !!! + * Historic practice was that all files would start editing at the beginning + * of the file. We don't get this right because we may have multiple screens + * and we can't clear the FR_CURSORSET bit for a single screen. I don't see + * anyone noticing, but if they do, we'll have to put information into the SCR + * structure so we can keep track of it. + * + * PUBLIC: int ex_rew(SCR *, EXCMD *); + */ +int +ex_rew(SCR *sp, EXCMD *cmdp) +{ + FREF *frp; + + /* + * !!! + * Historic practice -- you can rewind to the current file. + */ + if (sp->argv == NULL) { + msgq(sp, M_ERR, "113|No previous files to rewind"); + return (1); + } + + if (file_m1(sp, + FL_ISSET(cmdp->iflags, E_C_FORCE), FS_ALL | FS_POSSIBLE)) + return (1); + + /* Switch to the first one. */ + sp->cargv = sp->argv; + if ((frp = file_add(sp, *sp->cargv)) == NULL) + return (1); + if (file_init(sp, frp, NULL, FS_SETALT | + (FL_ISSET(cmdp->iflags, E_C_FORCE) ? FS_FORCE : 0))) + return (1); + + /* Switch and display a file count with the welcome message. */ + F_SET(sp, SC_FSWITCH | SC_STATUS_CNT); + + return (0); +} + +/* + * ex_args -- :args + * Display the list of files. + * + * PUBLIC: int ex_args(SCR *, EXCMD *); + */ +int +ex_args(SCR *sp, EXCMD *cmdp) +{ + GS *gp; + int cnt, col, len, sep; + char **ap; + + if (sp->argv == NULL) { + (void)msgq(sp, M_ERR, "114|No file list to display"); + return (0); + } + + gp = sp->gp; + col = len = sep = 0; + for (cnt = 1, ap = sp->argv; *ap != NULL; ++ap) { + col += len = strlen(*ap) + sep + (ap == sp->cargv ? 2 : 0); + if (col >= sp->cols - 1) { + col = len; + sep = 0; + (void)ex_puts(sp, "\n"); + } else if (cnt != 1) { + sep = 1; + (void)ex_puts(sp, " "); + } + ++cnt; + + (void)ex_printf(sp, "%s%s%s", ap == sp->cargv ? "[" : "", + *ap, ap == sp->cargv ? "]" : ""); + if (INTERRUPTED(sp)) + break; + } + (void)ex_puts(sp, "\n"); + return (0); +} + +/* + * ex_buildargv -- + * Build a new file argument list. + * + * PUBLIC: char **ex_buildargv(SCR *, EXCMD *, char *); + */ +char ** +ex_buildargv(SCR *sp, EXCMD *cmdp, char *name) +{ + ARGS **argv; + int argc; + char **ap, **s_argv; + char *np; + size_t nlen; + + argc = cmdp == NULL ? 1 : cmdp->argc; + CALLOC(sp, s_argv, argc + 1, sizeof(char *)); + if ((ap = s_argv) == NULL) + return (NULL); + + if (cmdp == NULL) { + if ((*ap = v_strdup(sp, name, strlen(name))) == NULL) + return (NULL); + ++ap; + } else + for (argv = cmdp->argv; argv[0]->len != 0; ++ap, ++argv) { + INT2CHAR(sp, argv[0]->bp, argv[0]->len, np, nlen); + if ((*ap = v_strdup(sp, np, nlen)) == NULL) + return (NULL); + } + *ap = NULL; + return (s_argv); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_args.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_at.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_at.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_at.c (revision 366308) @@ -0,0 +1,120 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "../common/common.h" + +/* + * ex_at -- :@[@ | buffer] + * :*[* | buffer] + * + * Execute the contents of the buffer. + * + * PUBLIC: int ex_at(SCR *, EXCMD *); + */ +int +ex_at(SCR *sp, EXCMD *cmdp) +{ + CB *cbp; + CHAR_T name; + EXCMD *ecp; + RANGE *rp; + TEXT *tp; + size_t len = 0; + CHAR_T *p; + + /* + * !!! + * Historically, [@*] and [@*][@*] executed the most + * recently executed buffer in ex mode. + */ + name = FL_ISSET(cmdp->iflags, E_C_BUFFER) ? cmdp->buffer : '@'; + if (name == '@' || name == '*') { + if (!F_ISSET(sp, SC_AT_SET)) { + ex_emsg(sp, NULL, EXM_NOPREVBUF); + return (1); + } + name = sp->at_lbuf; + } + sp->at_lbuf = name; + F_SET(sp, SC_AT_SET); + + CBNAME(sp, cbp, name); + if (cbp == NULL) { + ex_emsg(sp, KEY_NAME(sp, name), EXM_EMPTYBUF); + return (1); + } + + /* + * !!! + * Historically the @ command took a range of lines, and the @ buffer + * was executed once per line. The historic vi could be trashed by + * this because it didn't notice if the underlying file changed, or, + * for that matter, if there were no more lines on which to operate. + * For example, take a 10 line file, load "%delete" into a buffer, + * and enter :8,10@. + * + * The solution is a bit tricky. If the user specifies a range, take + * the same approach as for global commands, and discard the command + * if exit or switch to a new file/screen. If the user doesn't specify + * the range, continue to execute after a file/screen switch, which + * means @ buffers are still useful in a multi-screen environment. + */ + CALLOC_RET(sp, ecp, 1, sizeof(EXCMD)); + TAILQ_INIT(ecp->rq); + CALLOC_RET(sp, rp, 1, sizeof(RANGE)); + rp->start = cmdp->addr1.lno; + if (F_ISSET(cmdp, E_ADDR_DEF)) { + rp->stop = rp->start; + FL_SET(ecp->agv_flags, AGV_AT_NORANGE); + } else { + rp->stop = cmdp->addr2.lno; + FL_SET(ecp->agv_flags, AGV_AT); + } + TAILQ_INSERT_HEAD(ecp->rq, rp, q); + + /* + * Buffers executed in ex mode or from the colon command line in vi + * were ex commands. We can't push it on the terminal queue, since + * it has to be executed immediately, and we may be in the middle of + * an ex command already. Push the command on the ex command stack. + * Build two copies of the command. We need two copies because the + * ex parser may step on the command string when it's parsing it. + */ + TAILQ_FOREACH_REVERSE(tp, cbp->textq, _texth, q) + len += tp->len + 1; + + MALLOC_RET(sp, ecp->cp, len * 2 * sizeof(CHAR_T)); + ecp->o_cp = ecp->cp; + ecp->o_clen = len; + ecp->cp[len] = '\0'; + + /* Copy the buffer into the command space. */ + p = ecp->cp + len; + TAILQ_FOREACH_REVERSE(tp, cbp->textq, _texth, q) { + MEMCPY(p, tp->lb, tp->len); + p += tp->len; + *p++ = '\n'; + } + + SLIST_INSERT_HEAD(sp->gp->ecq, ecp, q); + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_at.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_cd.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_cd.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_cd.c (revision 366308) @@ -0,0 +1,127 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../common/common.h" + +/* + * ex_cd -- :cd[!] [directory] + * Change directories. + * + * PUBLIC: int ex_cd(SCR *, EXCMD *); + */ +int +ex_cd(SCR *sp, EXCMD *cmdp) +{ + struct passwd *pw; + ARGS *ap; + int savech; + char *dir, *p, *t; + char *buf; + size_t dlen; + + /* + * !!! + * Historic practice is that the cd isn't attempted if the file has + * been modified, unless its name begins with a leading '/' or the + * force flag is set. + */ + if (F_ISSET(sp->ep, F_MODIFIED) && + !FL_ISSET(cmdp->iflags, E_C_FORCE) && sp->frp->name[0] != '/') { + msgq(sp, M_ERR, + "120|File modified since last complete write; write or use ! to override"); + return (1); + } + + switch (cmdp->argc) { + case 0: + /* If no argument, change to the user's home directory. */ + if ((dir = getenv("HOME")) == NULL) { + if ((pw = getpwuid(getuid())) == NULL || + pw->pw_dir == NULL || pw->pw_dir[0] == '\0') { + msgq(sp, M_ERR, + "121|Unable to find home directory location"); + return (1); + } + dir = pw->pw_dir; + } + break; + case 1: + INT2CHAR(sp, cmdp->argv[0]->bp, cmdp->argv[0]->len + 1, + dir, dlen); + break; + default: + abort(); + } + + /* + * Try the current directory first. If this succeeds, don't display + * a message, vi didn't historically, and it should be obvious to the + * user where they are. + */ + if (!chdir(dir)) + return (0); + + /* + * If moving to the user's home directory, or, the path begins with + * "/", "./" or "../", it's the only place we try. + */ + if (cmdp->argc == 0 || + (ap = cmdp->argv[0])->bp[0] == '/' || + (ap->len == 1 && ap->bp[0] == '.') || + (ap->len >= 2 && ap->bp[0] == '.' && ap->bp[1] == '.' && + (ap->bp[2] == '/' || ap->bp[2] == '\0'))) + goto err; + + /* Try the O_CDPATH option values. */ + for (p = t = O_STR(sp, O_CDPATH);; ++p) + if (*p == '\0' || *p == ':') { + /* + * Ignore the empty strings and ".", since we've already + * tried the current directory. + */ + if (t < p && (p - t != 1 || *t != '.')) { + savech = *p; + *p = '\0'; + if ((buf = join(t, dir)) == NULL) { + msgq(sp, M_SYSERR, NULL); + return (1); + } + *p = savech; + if (!chdir(buf)) { + free(buf); + if ((buf = getcwd(NULL, 0)) != NULL) { + msgq_str(sp, M_INFO, buf, "122|New current directory: %s"); + free(buf); + } + return (0); + } + free(buf); + } + t = p + 1; + if (*p == '\0') + break; + } + +err: msgq_str(sp, M_SYSERR, dir, "%s"); + return (1); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_cd.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_cmd.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_cmd.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_cmd.c (revision 366308) @@ -0,0 +1,441 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include + +#include "../common/common.h" + +/* + * This array maps ex command names to command functions. + * + * The order in which command names are listed below is important -- + * ambiguous abbreviations are resolved to be the first possible match, + * e.g. "r" means "read", not "rewind", because "read" is listed before + * "rewind". + * + * The syntax of the ex commands is unbelievably irregular, and a special + * case from beginning to end. Each command has an associated "syntax + * script" which describes the "arguments" that are possible. The script + * syntax is as follows: + * + * ! -- ! flag + * 1 -- flags: [+-]*[pl#][+-]* + * 2 -- flags: [-.+^] + * 3 -- flags: [-.+^=] + * b -- buffer + * c[01+a] -- count (0-N, 1-N, signed 1-N, address offset) + * f[N#][or] -- file (a number or N, optional or required) + * l -- line + * S -- string with file name expansion + * s -- string + * W -- word string + * w[N#][or] -- word (a number or N, optional or required) + */ +EXCMDLIST const cmds[] = { +/* C_SCROLL */ + {L("\004"), ex_pr, E_ADDR2, + "", + "^D", + "scroll lines"}, +/* C_BANG */ + {L("!"), ex_bang, E_ADDR2_NONE|E_SECURE, + "S", + "[line [,line]] ! command", + "filter lines through commands or run commands"}, +/* C_HASH */ + {L("#"), ex_number, E_ADDR2|E_CLRFLAG, + "ca1", + "[line [,line]] # [count] [l]", + "display numbered lines"}, +/* C_SUBAGAIN */ + {L("&"), ex_subagain, E_ADDR2|E_ADDR_ZERO, + "s", + "[line [,line]] & [cgr] [count] [#lp]", + "repeat the last subsitution"}, +/* C_STAR */ + {L("*"), ex_at, 0, + "b", + "* [buffer]", + "execute a buffer"}, +/* C_SHIFTL */ + {L("<"), ex_shiftl, E_ADDR2|E_AUTOPRINT, + "ca1", + "[line [,line]] <[<...] [count] [flags]", + "shift lines left"}, +/* C_EQUAL */ + {L("="), ex_equal, E_ADDR1|E_ADDR_ZERO|E_ADDR_ZERODEF, + "1", + "[line] = [flags]", + "display line number"}, +/* C_SHIFTR */ + {L(">"), ex_shiftr, E_ADDR2|E_AUTOPRINT, + "ca1", + "[line [,line]] >[>...] [count] [flags]", + "shift lines right"}, +/* C_AT */ + {L("@"), ex_at, E_ADDR2, + "b", + "@ [buffer]", + "execute a buffer"}, +/* C_APPEND */ + {L("append"), ex_append, E_ADDR1|E_ADDR_ZERO|E_ADDR_ZERODEF, + "!", + "[line] a[ppend][!]", + "append input to a line"}, +/* C_ABBR */ + {L("abbreviate"), ex_abbr, 0, + "W", + "ab[brev] [word replace]", + "specify an input abbreviation"}, +/* C_ARGS */ + {L("args"), ex_args, 0, + "", + "ar[gs]", + "display file argument list"}, +/* C_BG */ + {L("bg"), ex_bg, E_VIONLY, + "", + "bg", + "put a foreground screen into the background"}, +/* C_CHANGE */ + {L("change"), ex_change, E_ADDR2|E_ADDR_ZERODEF, + "!ca", + "[line [,line]] c[hange][!] [count]", + "change lines to input"}, +/* C_CD */ + {L("cd"), ex_cd, 0, + "!f1o", + "cd[!] [directory]", + "change the current directory"}, +/* C_CHDIR */ + {L("chdir"), ex_cd, 0, + "!f1o", + "chd[ir][!] [directory]", + "change the current directory"}, +/* C_COPY */ + {L("copy"), ex_copy, E_ADDR2|E_AUTOPRINT, + "l1", + "[line [,line]] co[py] line [flags]", + "copy lines elsewhere in the file"}, +/* C_CSCOPE */ + {L("cscope"), ex_cscope, 0, + "!s", + "cs[cope] command [args]", + "create a set of tags using a cscope command"}, +/* + * !!! + * Adding new commands starting with 'd' may break the delete command code + * in ex_cmd() (the ex parser). Read through the comments there, first. + */ +/* C_DELETE */ + {L("delete"), ex_delete, E_ADDR2|E_AUTOPRINT, + "bca1", + "[line [,line]] d[elete][flags] [buffer] [count] [flags]", + "delete lines from the file"}, +/* C_DISPLAY */ + {L("display"), ex_display, 0, + "w1r", + "display b[uffers] | c[onnections] | s[creens] | t[ags]", + "display buffers, connections, screens or tags"}, +/* C_EDIT */ + {L("edit"), ex_edit, E_NEWSCREEN, + "f1o", + "[Ee][dit][!] [+cmd] [file]", + "begin editing another file"}, +/* C_EX */ + {L("ex"), ex_edit, E_NEWSCREEN, + "f1o", + "[Ee]x[!] [+cmd] [file]", + "begin editing another file"}, +/* C_EXUSAGE */ + {L("exusage"), ex_usage, 0, + "w1o", + "[exu]sage [command]", + "display ex command usage statement"}, +/* C_FILE */ + {L("file"), ex_file, 0, + "f1o", + "f[ile] [name]", + "display (and optionally set) file name"}, +/* C_FG */ + {L("fg"), ex_fg, E_NEWSCREEN|E_VIONLY, + "f1o", + "[Ff]g [file]", + "bring a backgrounded screen into the foreground"}, +/* C_GLOBAL */ + {L("global"), ex_global, E_ADDR2_ALL, + "!s", + "[line [,line]] g[lobal][!] [;/]RE[;/] [commands]", + "execute a global command on lines matching an RE"}, +/* C_HELP */ + {L("help"), ex_help, 0, + "", + "he[lp]", + "display help statement"}, +/* C_INSERT */ + {L("insert"), ex_insert, E_ADDR1|E_ADDR_ZERO|E_ADDR_ZERODEF, + "!", + "[line] i[nsert][!]", + "insert input before a line"}, +/* C_JOIN */ + {L("join"), ex_join, E_ADDR2|E_AUTOPRINT, + "!ca1", + "[line [,line]] j[oin][!] [count] [flags]", + "join lines into a single line"}, +/* C_K */ + {L("k"), ex_mark, E_ADDR1, + "w1r", + "[line] k key", + "mark a line position"}, +/* C_LIST */ + {L("list"), ex_list, E_ADDR2|E_CLRFLAG, + "ca1", + "[line [,line]] l[ist] [count] [#]", + "display lines in an unambiguous form"}, +/* C_MOVE */ + {L("move"), ex_move, E_ADDR2|E_AUTOPRINT, + "l", + "[line [,line]] m[ove] line", + "move lines elsewhere in the file"}, +/* C_MARK */ + {L("mark"), ex_mark, E_ADDR1, + "w1r", + "[line] ma[rk] key", + "mark a line position"}, +/* C_MAP */ + {L("map"), ex_map, 0, + "!W", + "map[!] [keys replace]", + "map input or commands to one or more keys"}, +/* C_MKEXRC */ + {L("mkexrc"), ex_mkexrc, 0, + "!f1r", + "mkexrc[!] file", + "write a .exrc file"}, +/* C_NEXT */ + {L("next"), ex_next, E_NEWSCREEN, + "!fN", + "[Nn][ext][!] [+cmd] [file ...]", + "edit (and optionally specify) the next file"}, +/* C_NUMBER */ + {L("number"), ex_number, E_ADDR2|E_CLRFLAG, + "ca1", + "[line [,line]] nu[mber] [count] [l]", + "change display to number lines"}, +/* C_OPEN */ + {L("open"), ex_open, E_ADDR1, + "s", + "[line] o[pen] [/RE/] [flags]", + "enter \"open\" mode (not implemented)"}, +/* C_PRINT */ + {L("print"), ex_pr, E_ADDR2|E_CLRFLAG, + "ca1", + "[line [,line]] p[rint] [count] [#l]", + "display lines"}, +/* C_PRESERVE */ + {L("preserve"), ex_preserve, 0, + "", + "pre[serve]", + "preserve an edit session for recovery"}, +/* C_PREVIOUS */ + {L("previous"), ex_prev, E_NEWSCREEN, + "!", + "[Pp]rev[ious][!]", + "edit the previous file in the file argument list"}, +/* C_PUT */ + {L("put"), ex_put, + E_ADDR1|E_AUTOPRINT|E_ADDR_ZERO|E_ADDR_ZERODEF, + "b", + "[line] pu[t] [buffer]", + "append a cut buffer to the line"}, +/* C_QUIT */ + {L("quit"), ex_quit, 0, + "!", + "q[uit][!]", + "exit ex/vi"}, +/* C_READ */ + {L("read"), ex_read, E_ADDR1|E_ADDR_ZERO|E_ADDR_ZERODEF, + "s", + "[line] r[ead] [!cmd | [file]]", + "append input from a command or file to the line"}, +/* C_RECOVER */ + {L("recover"), ex_recover, 0, + "!f1r", + "recover[!] file", + "recover a saved file"}, +/* C_RESIZE */ + {L("resize"), ex_resize, E_VIONLY, + "c+", + "resize [+-]rows", + "grow or shrink the current screen"}, +/* C_REWIND */ + {L("rewind"), ex_rew, 0, + "!", + "rew[ind][!]", + "re-edit all the files in the file argument list"}, +/* + * !!! + * Adding new commands starting with 's' may break the substitute command code + * in ex_cmd() (the ex parser). Read through the comments there, first. + */ +/* C_SUBSTITUTE */ + {L("s"), ex_s, E_ADDR2|E_ADDR_ZERO, + "s", + "[line [,line]] s [[/;]RE[/;]repl[/;] [cgr] [count] [#lp]]", + "substitute on lines matching an RE"}, +/* C_SCRIPT */ + {L("script"), ex_script, E_SECURE, + "!f1o", + "sc[ript][!] [file]", + "run a shell in a screen"}, +/* C_SET */ + {L("set"), ex_set, 0, + "wN", + "se[t] [option[=[value]]...] [nooption ...] [option? ...] [all]", + "set options (use \":set all\" to see all options)"}, +/* C_SHELL */ + {L("shell"), ex_shell, E_SECURE, + "", + "sh[ell]", + "suspend editing and run a shell"}, +/* C_SOURCE */ + {L("source"), ex_source, 0, + "f1r", + "so[urce] file", + "read a file of ex commands"}, +/* C_STOP */ + {L("stop"), ex_stop, E_SECURE, + "!", + "st[op][!]", + "suspend the edit session"}, +/* C_SUSPEND */ + {L("suspend"), ex_stop, E_SECURE, + "!", + "su[spend][!]", + "suspend the edit session"}, +/* C_T */ + {L("t"), ex_copy, E_ADDR2|E_AUTOPRINT, + "l1", + "[line [,line]] t line [flags]", + "copy lines elsewhere in the file"}, +/* C_TAG */ + {L("tag"), ex_tag_push, E_NEWSCREEN, + "!w1o", + "[Tt]a[g][!] [string]", + "edit the file containing the tag"}, +/* C_TAGNEXT */ + {L("tagnext"), ex_tag_next, 0, + "!", + "tagn[ext][!]", + "move to the next tag"}, +/* C_TAGPOP */ + {L("tagpop"), ex_tag_pop, 0, + "!w1o", + "tagp[op][!] [number | file]", + "return to the previous group of tags"}, +/* C_TAGPREV */ + {L("tagprev"), ex_tag_prev, 0, + "!", + "tagpr[ev][!]", + "move to the previous tag"}, +/* C_TAGTOP */ + {L("tagtop"), ex_tag_top, 0, + "!", + "tagt[op][!]", + "discard all tags"}, +/* C_UNDO */ + {L("undo"), ex_undo, E_AUTOPRINT, + "", + "u[ndo]", + "undo the most recent change"}, +/* C_UNABBREVIATE */ + {L("unabbreviate"),ex_unabbr, 0, + "w1r", + "una[bbrev] word", + "delete an abbreviation"}, +/* C_UNMAP */ + {L("unmap"), ex_unmap, 0, + "!w1r", + "unm[ap][!] word", + "delete an input or command map"}, +/* C_V */ + {L("v"), ex_v, E_ADDR2_ALL, + "s", + "[line [,line]] v [;/]RE[;/] [commands]", + "execute a global command on lines NOT matching an RE"}, +/* C_VERSION */ + {L("version"), ex_version, 0, + "", + "version", + "display the program version information"}, +/* C_VISUAL_EX */ + {L("visual"), ex_visual, E_ADDR1|E_ADDR_ZERODEF, + "2c11", + "[line] vi[sual] [-|.|+|^] [window_size] [flags]", + "enter visual (vi) mode from ex mode"}, +/* C_VISUAL_VI */ + {L("visual"), ex_edit, E_NEWSCREEN, + "f1o", + "[Vv]i[sual][!] [+cmd] [file]", + "edit another file (from vi mode only)"}, +/* C_VIUSAGE */ + {L("viusage"), ex_viusage, 0, + "w1o", + "[viu]sage [key]", + "display vi key usage statement"}, +/* C_VSPLIT */ + {L("vsplit"), ex_edit, E_VIONLY, + "f1o", + "vs[plit] [+cmd] [file]", + "split the current screen vertically"}, +/* C_WRITE */ + {L("write"), ex_write, E_ADDR2_ALL|E_ADDR_ZERODEF, + "!s", + "[line [,line]] w[rite][!] [ !cmd | [>>] [file]]", + "write the file"}, +/* C_WN */ + {L("wn"), ex_wn, E_ADDR2_ALL|E_ADDR_ZERODEF, + "!s", + "[line [,line]] wn[!] [>>] [file]", + "write the file and switch to the next file"}, +/* C_WQ */ + {L("wq"), ex_wq, E_ADDR2_ALL|E_ADDR_ZERODEF, + "!s", + "[line [,line]] wq[!] [>>] [file]", + "write the file and exit"}, +/* C_XIT */ + {L("xit"), ex_xit, E_ADDR2_ALL|E_ADDR_ZERODEF, + "!f1o", + "[line [,line]] x[it][!] [file]", + "exit"}, +/* C_YANK */ + {L("yank"), ex_yank, E_ADDR2, + "bca", + "[line [,line]] ya[nk] [buffer] [count]", + "copy lines to a cut buffer"}, +/* C_Z */ + {L("z"), ex_z, E_ADDR1, + "3c01", + "[line] z [-|.|+|^|=] [count] [flags]", + "display different screens of the file"}, +/* C_SUBTILDE */ + {L("~"), ex_subtilde, E_ADDR2|E_ADDR_ZERO, + "s", + "[line [,line]] ~ [cgr] [count] [#lp]", + "replace previous RE with previous replacement string,"}, + {NULL}, +}; Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_cmd.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_delete.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_delete.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_delete.c (revision 366308) @@ -0,0 +1,60 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include + +#include "../common/common.h" + +/* + * ex_delete: [line [,line]] d[elete] [buffer] [count] [flags] + * + * Delete lines from the file. + * + * PUBLIC: int ex_delete(SCR *, EXCMD *); + */ +int +ex_delete(SCR *sp, EXCMD *cmdp) +{ + recno_t lno; + + NEEDFILE(sp, cmdp); + + /* + * !!! + * Historically, lines deleted in ex were not placed in the numeric + * buffers. We follow historic practice so that we don't overwrite + * vi buffers accidentally. + */ + if (cut(sp, + FL_ISSET(cmdp->iflags, E_C_BUFFER) ? &cmdp->buffer : NULL, + &cmdp->addr1, &cmdp->addr2, CUT_LINEMODE)) + return (1); + + /* Delete the lines. */ + if (del(sp, &cmdp->addr1, &cmdp->addr2, 1)) + return (1); + + /* Set the cursor to the line after the last line deleted. */ + sp->lno = cmdp->addr1.lno; + + /* Or the last line in the file if deleted to the end of the file. */ + if (db_last(sp, &lno)) + return (1); + if (sp->lno > lno) + sp->lno = lno; + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_delete.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_display.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_display.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_display.c (revision 366308) @@ -0,0 +1,139 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "../common/common.h" +#include "tag.h" + +static int is_prefix(ARGS *, CHAR_T *); +static int bdisplay(SCR *); +static void db(SCR *, CB *, const char *); + +/* + * ex_display -- :display b[uffers] | c[onnections] | s[creens] | t[ags] + * + * Display cscope connections, buffers, tags or screens. + * + * PUBLIC: int ex_display(SCR *, EXCMD *); + */ +int +ex_display(SCR *sp, EXCMD *cmdp) +{ + ARGS *arg; + + arg = cmdp->argv[0]; + + switch (arg->bp[0]) { + case 'b': + if (!is_prefix(arg, L("buffers"))) + break; + return (bdisplay(sp)); + case 'c': + if (!is_prefix(arg, L("connections"))) + break; + return (cscope_display(sp)); + case 's': + if (!is_prefix(arg, L("screens"))) + break; + return (ex_sdisplay(sp)); + case 't': + if (!is_prefix(arg, L("tags"))) + break; + return (ex_tag_display(sp)); + } + ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE); + return (1); +} + +/* + * is_prefix -- + * + * Check that a command argument matches a prefix of a given string. + */ +static int +is_prefix(ARGS *arg, CHAR_T *str) +{ + return arg->len <= STRLEN(str) && !MEMCMP(arg->bp, str, arg->len); +} + +/* + * bdisplay -- + * + * Display buffers. + */ +static int +bdisplay(SCR *sp) +{ + CB *cbp; + + if (SLIST_EMPTY(sp->gp->cutq) && sp->gp->dcbp == NULL) { + msgq(sp, M_INFO, "123|No cut buffers to display"); + return (0); + } + + /* Display regular cut buffers. */ + SLIST_FOREACH(cbp, sp->gp->cutq, q) { + if (isdigit(cbp->name)) + continue; + if (!TAILQ_EMPTY(cbp->textq)) + db(sp, cbp, NULL); + if (INTERRUPTED(sp)) + return (0); + } + /* Display numbered buffers. */ + SLIST_FOREACH(cbp, sp->gp->cutq, q) { + if (!isdigit(cbp->name)) + continue; + if (!TAILQ_EMPTY(cbp->textq)) + db(sp, cbp, NULL); + if (INTERRUPTED(sp)) + return (0); + } + /* Display default buffer. */ + if ((cbp = sp->gp->dcbp) != NULL) + db(sp, cbp, "default buffer"); + return (0); +} + +/* + * db -- + * Display a buffer. + */ +static void +db(SCR *sp, CB *cbp, const char *name) +{ + CHAR_T *p; + GS *gp; + TEXT *tp; + size_t len; + + gp = sp->gp; + (void)ex_printf(sp, "********** %s%s\n", + name == NULL ? KEY_NAME(sp, cbp->name) : name, + F_ISSET(cbp, CB_LMODE) ? " (line mode)" : " (character mode)"); + TAILQ_FOREACH(tp, cbp->textq, q) { + for (len = tp->len, p = tp->lb; len--; ++p) { + (void)ex_puts(sp, KEY_NAME(sp, *p)); + if (INTERRUPTED(sp)) + return; + } + (void)ex_puts(sp, "\n"); + } +} Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_display.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_edit.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_edit.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_edit.c (revision 366308) @@ -0,0 +1,155 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "../common/common.h" +#include "../vi/vi.h" + +static int ex_N_edit(SCR *, EXCMD *, FREF *, int); + +/* + * ex_edit -- :e[dit][!] [+cmd] [file] + * :ex[!] [+cmd] [file] + * :vi[sual][!] [+cmd] [file] + * + * Edit a file; if none specified, re-edit the current file. The third + * form of the command can only be executed while in vi mode. See the + * hack in ex.c:ex_cmd(). + * + * !!! + * Historic vi didn't permit the '+' command form without specifying + * a file name as well. This seems unreasonable, so we support it + * regardless. + * + * PUBLIC: int ex_edit(SCR *, EXCMD *); + */ +int +ex_edit(SCR *sp, EXCMD *cmdp) +{ + FREF *frp; + int attach, setalt; + char *np; + size_t nlen; + + switch (cmdp->argc) { + case 0: + /* + * If the name has been changed, we edit that file, not the + * original name. If the user was editing a temporary file + * (or wasn't editing any file), create another one. The + * reason for not reusing temporary files is that there is + * special exit processing of them, and reuse is tricky. + */ + frp = sp->frp; + if (sp->ep == NULL || F_ISSET(frp, FR_TMPFILE)) { + if ((frp = file_add(sp, NULL)) == NULL) + return (1); + attach = 0; + } else + attach = 1; + setalt = 0; + break; + case 1: + INT2CHAR(sp, cmdp->argv[0]->bp, cmdp->argv[0]->len + 1, + np, nlen); + if ((frp = file_add(sp, np)) == NULL) + return (1); + attach = 0; + setalt = 1; + set_alt_name(sp, np); + break; + default: + abort(); + } + + if (F_ISSET(cmdp, E_NEWSCREEN) || cmdp->cmd == &cmds[C_VSPLIT]) + return (ex_N_edit(sp, cmdp, frp, attach)); + + /* + * Check for modifications. + * + * !!! + * Contrary to POSIX 1003.2-1992, autowrite did not affect :edit. + */ + if (file_m2(sp, FL_ISSET(cmdp->iflags, E_C_FORCE))) + return (1); + + /* Switch files. */ + if (file_init(sp, frp, NULL, (setalt ? FS_SETALT : 0) | + (FL_ISSET(cmdp->iflags, E_C_FORCE) ? FS_FORCE : 0))) + return (1); + + F_SET(sp, SC_FSWITCH); + return (0); +} + +/* + * ex_N_edit -- + * New screen version of ex_edit. + */ +static int +ex_N_edit(SCR *sp, EXCMD *cmdp, FREF *frp, int attach) +{ + SCR *new; + + /* Get a new screen. */ + if (screen_init(sp->gp, sp, &new)) + return (1); + if ((cmdp->cmd == &cmds[C_VSPLIT] && vs_vsplit(sp, new)) || + (cmdp->cmd != &cmds[C_VSPLIT] && vs_split(sp, new, 0))) { + (void)screen_end(new); + return (1); + } + + /* Get a backing file. */ + if (attach) { + /* Copy file state, keep the screen and cursor the same. */ + new->ep = sp->ep; + ++new->ep->refcnt; + + new->frp = frp; + new->frp->flags = sp->frp->flags; + + new->lno = sp->lno; + new->cno = sp->cno; + +#if defined(USE_WIDECHAR) && defined(USE_ICONV) + /* Synchronize the iconv environments. */ + o_set(new, O_FILEENCODING, OS_STRDUP, + O_STR(sp, O_FILEENCODING), 0); + conv_enc(new, O_FILEENCODING, 0); +#endif + } else if (file_init(new, frp, NULL, + (FL_ISSET(cmdp->iflags, E_C_FORCE) ? FS_FORCE : 0))) { + (void)vs_discard(new, NULL); + (void)screen_end(new); + return (1); + } + + /* Create the argument list. */ + new->cargv = new->argv = ex_buildargv(sp, NULL, frp->name); + + /* Set up the switch. */ + sp->nextdisp = new; + F_SET(sp, SC_SSWITCH); + + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_edit.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_equal.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_equal.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_equal.c (revision 366308) @@ -0,0 +1,54 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include + +#include "../common/common.h" + +/* + * ex_equal -- :address = + * + * PUBLIC: int ex_equal(SCR *, EXCMD *); + */ +int +ex_equal(SCR *sp, EXCMD *cmdp) +{ + recno_t lno; + + NEEDFILE(sp, cmdp); + + /* + * Print out the line number matching the specified address, + * or the number of the last line in the file if no address + * specified. + * + * !!! + * Historically, ":0=" displayed 0, and ":=" or ":1=" in an + * empty file displayed 1. Until somebody complains loudly, + * we're going to do it right. The tables in excmd.c permit + * lno to get away with any address from 0 to the end of the + * file, which, in an empty file, is 0. + */ + if (F_ISSET(cmdp, E_ADDR_DEF)) { + if (db_last(sp, &lno)) + return (1); + } else + lno = cmdp->addr1.lno; + + (void)ex_printf(sp, "%ld\n", lno); + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_equal.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_file.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_file.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_file.c (revision 366308) @@ -0,0 +1,78 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "../common/common.h" + +/* + * ex_file -- :f[ile] [name] + * Change the file's name and display the status line. + * + * PUBLIC: int ex_file(SCR *, EXCMD *); + */ +int +ex_file(SCR *sp, EXCMD *cmdp) +{ + char *p; + FREF *frp; + char *np; + size_t nlen; + + NEEDFILE(sp, cmdp); + + switch (cmdp->argc) { + case 0: + break; + case 1: + frp = sp->frp; + + /* Make sure can allocate enough space. */ + INT2CHAR(sp, cmdp->argv[0]->bp, cmdp->argv[0]->len + 1, + np, nlen); + if ((p = v_strdup(sp, np, nlen - 1)) == NULL) + return (1); + + /* If already have a file name, it becomes the alternate. */ + if (!F_ISSET(frp, FR_TMPFILE)) + set_alt_name(sp, frp->name); + + /* Free the previous name. */ + free(frp->name); + frp->name = p; + + /* + * The file has a real name, it's no longer a temporary, + * clear the temporary file flags. + */ + F_CLR(frp, FR_TMPEXIT | FR_TMPFILE); + + /* Have to force a write if the file exists, next time. */ + F_SET(frp, FR_NAMECHANGE); + + /* Notify the screen. */ + (void)sp->gp->scr_rename(sp, sp->frp->name, 1); + break; + default: + abort(); + } + msgq_status(sp, sp->lno, MSTAT_SHOWLAST); + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_file.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_init.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_init.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_init.c (revision 366308) @@ -0,0 +1,423 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "../common/common.h" +#include "tag.h" +#include "pathnames.h" + +enum rc { NOEXIST, NOPERM, RCOK }; +static enum rc exrc_isok(SCR *, struct stat *, char *, int, int); + +static int ex_run_file(SCR *, char *); + +/* + * ex_screen_copy -- + * Copy ex screen. + * + * PUBLIC: int ex_screen_copy(SCR *, SCR *); + */ +int +ex_screen_copy(SCR *orig, SCR *sp) +{ + EX_PRIVATE *oexp, *nexp; + + /* Create the private ex structure. */ + CALLOC_RET(orig, nexp, 1, sizeof(EX_PRIVATE)); + sp->ex_private = nexp; + + /* Initialize queues. */ + TAILQ_INIT(nexp->tq); + TAILQ_INIT(nexp->tagfq); + SLIST_INIT(nexp->cscq); + + if (orig == NULL) { + } else { + oexp = EXP(orig); + + if (oexp->lastbcomm != NULL && + (nexp->lastbcomm = v_wstrdup(sp, oexp->lastbcomm, + STRLEN(oexp->lastbcomm))) == NULL) { + msgq(sp, M_SYSERR, NULL); + return(1); + } + if (ex_tag_copy(orig, sp)) + return (1); + } + return (0); +} + +/* + * ex_screen_end -- + * End a vi screen. + * + * PUBLIC: int ex_screen_end(SCR *); + */ +int +ex_screen_end(SCR *sp) +{ + EX_PRIVATE *exp; + int rval; + + if ((exp = EXP(sp)) == NULL) + return (0); + + rval = 0; + + /* Close down script connections. */ + if (F_ISSET(sp, SC_SCRIPT) && sscr_end(sp)) + rval = 1; + + if (argv_free(sp)) + rval = 1; + + free(exp->ibp); + + free(exp->lastbcomm); + + free(exp->ibcw.bp1.c); + + if (ex_tag_free(sp)) + rval = 1; + + if (cscope_end(sp)) + rval = 1; + + /* Free private memory. */ + free(exp); + sp->ex_private = NULL; + + return (rval); +} + +/* + * ex_optchange -- + * Handle change of options for ex. + * + * PUBLIC: int ex_optchange(SCR *, int, char *, u_long *); + */ +int +ex_optchange(SCR *sp, int offset, char *str, u_long *valp) +{ + switch (offset) { + case O_TAGS: + return (ex_tagf_alloc(sp, str)); + } + return (0); +} + +/* + * ex_exrc -- + * Read the EXINIT environment variable and the startup exrc files, + * and execute their commands. + * + * PUBLIC: int ex_exrc(SCR *); + */ +int +ex_exrc(SCR *sp) +{ + struct stat hsb, lsb; + char *p, *path; + CHAR_T *wp; + size_t wlen; + + /* + * Source the system, environment, $HOME and local .exrc values. + * Vi historically didn't check $HOME/.exrc if the environment + * variable EXINIT was set. This is all done before the file is + * read in, because things in the .exrc information can set, for + * example, the recovery directory. + * + * !!! + * While nvi can handle any of the options settings of historic vi, + * the converse is not true. Since users are going to have to have + * files and environmental variables that work with both, we use nvi + * versions of both the $HOME and local startup files if they exist, + * otherwise the historic ones. + * + * !!! + * For a discussion of permissions and when what .exrc files are + * read, see the comment above the exrc_isok() function below. + * + * !!! + * If the user started the historic of vi in $HOME, vi read the user's + * .exrc file twice, as $HOME/.exrc and as ./.exrc. We avoid this, as + * it's going to make some commands behave oddly, and I can't imagine + * anyone depending on it. + */ + switch (exrc_isok(sp, &hsb, _PATH_SYSEXRC, 1, 0)) { + case NOEXIST: + case NOPERM: + break; + case RCOK: + if (ex_run_file(sp, _PATH_SYSEXRC)) + return (1); + break; + } + + /* Run the commands. */ + if (EXCMD_RUNNING(sp->gp)) + (void)ex_cmd(sp); + if (F_ISSET(sp, SC_EXIT | SC_EXIT_FORCE)) + return (0); + + if ((p = getenv("NEXINIT")) != NULL) { + CHAR2INT(sp, p, strlen(p) + 1, wp, wlen); + if (ex_run_str(sp, "NEXINIT", wp, wlen - 1, 1, 0)) + return (1); + } else if ((p = getenv("EXINIT")) != NULL) { + CHAR2INT(sp, p, strlen(p) + 1, wp, wlen); + if (ex_run_str(sp, "EXINIT", wp, wlen - 1, 1, 0)) + return (1); + } else if ((p = getenv("HOME")) != NULL && *p) { + int st = 0; + + if ((path = join(p, _PATH_NEXRC)) == NULL) { + msgq(sp, M_SYSERR, NULL); + return (1); + } + switch (exrc_isok(sp, &hsb, path, 0, 1)) { + case NOEXIST: + free(path); + if ((path = join(p, _PATH_EXRC)) == NULL) { + msgq(sp, M_SYSERR, NULL); + return (1); + } + if (exrc_isok(sp, + &hsb, path, 0, 1) == RCOK && ex_run_file(sp, path)) + st = 1; + break; + case NOPERM: + break; + case RCOK: + if (ex_run_file(sp, path)) + st = 1; + break; + } + free(path); + if (st) + return st; + } + + /* Run the commands. */ + if (EXCMD_RUNNING(sp->gp)) + (void)ex_cmd(sp); + if (F_ISSET(sp, SC_EXIT | SC_EXIT_FORCE)) + return (0); + + /* Previous commands may have set the exrc option. */ + if (O_ISSET(sp, O_EXRC)) { + switch (exrc_isok(sp, &lsb, _PATH_NEXRC, 0, 0)) { + case NOEXIST: + if (exrc_isok(sp, &lsb, _PATH_EXRC, 0, 0) == RCOK && + (lsb.st_dev != hsb.st_dev || + lsb.st_ino != hsb.st_ino) && + ex_run_file(sp, _PATH_EXRC)) + return (1); + break; + case NOPERM: + break; + case RCOK: + if ((lsb.st_dev != hsb.st_dev || + lsb.st_ino != hsb.st_ino) && + ex_run_file(sp, _PATH_NEXRC)) + return (1); + break; + } + /* Run the commands. */ + if (EXCMD_RUNNING(sp->gp)) + (void)ex_cmd(sp); + if (F_ISSET(sp, SC_EXIT | SC_EXIT_FORCE)) + return (0); + } + + return (0); +} + +/* + * ex_run_file -- + * Set up a file of ex commands to run. + */ +static int +ex_run_file(SCR *sp, char *name) +{ + EXCMD cmd; + CHAR_T *wp; + size_t wlen; + + ex_cinit(sp, &cmd, C_SOURCE, 0, OOBLNO, OOBLNO, 0); + CHAR2INT(sp, name, strlen(name)+1, wp, wlen); + argv_exp0(sp, &cmd, wp, wlen - 1); + return (ex_source(sp, &cmd)); +} + +/* + * ex_run_str -- + * Set up a string of ex commands to run. + * + * PUBLIC: int ex_run_str(SCR *, char *, CHAR_T *, size_t, int, int); + */ +int +ex_run_str(SCR *sp, char *name, CHAR_T *str, size_t len, int ex_flags, int nocopy) +{ + GS *gp; + EXCMD *ecp; + + gp = sp->gp; + if (EXCMD_RUNNING(gp)) { + CALLOC_RET(sp, ecp, 1, sizeof(EXCMD)); + SLIST_INSERT_HEAD(gp->ecq, ecp, q); + } else + ecp = &gp->excmd; + + F_INIT(ecp, + ex_flags ? E_BLIGNORE | E_NOAUTO | E_NOPRDEF | E_VLITONLY : 0); + + if (nocopy) + ecp->cp = str; + else + if ((ecp->cp = v_wstrdup(sp, str, len)) == NULL) + return (1); + ecp->clen = len; + + if (name == NULL) + ecp->if_name = NULL; + else { + if ((ecp->if_name = v_strdup(sp, name, strlen(name))) == NULL) + return (1); + ecp->if_lno = 1; + F_SET(ecp, E_NAMEDISCARD); + } + + return (0); +} + +/* + * exrc_isok -- + * Check a .exrc file for source-ability. + * + * !!! + * Historically, vi read the $HOME and local .exrc files if they were owned + * by the user's real ID, or the "sourceany" option was set, regardless of + * any other considerations. We no longer support the sourceany option as + * it's a security problem of mammoth proportions. We require the system + * .exrc file to be owned by root, the $HOME .exrc file to be owned by the + * user's effective ID (or that the user's effective ID be root) and the + * local .exrc files to be owned by the user's effective ID. In all cases, + * the file cannot be writeable by anyone other than its owner. + * + * In O'Reilly ("Learning the VI Editor", Fifth Ed., May 1992, page 106), + * it notes that System V release 3.2 and later has an option "[no]exrc". + * The behavior is that local .exrc files are read only if the exrc option + * is set. The default for the exrc option was off, so, by default, local + * .exrc files were not read. The problem this was intended to solve was + * that System V permitted users to give away files, so there's no possible + * ownership or writeability test to ensure that the file is safe. + * + * POSIX 1003.2-1992 standardized exrc as an option. It required the exrc + * option to be off by default, thus local .exrc files are not to be read + * by default. The Rationale noted (incorrectly) that this was a change + * to historic practice, but correctly noted that a default of off improves + * system security. POSIX also required that vi check the effective user + * ID instead of the real user ID, which is why we've switched from historic + * practice. + * + * We initialize the exrc variable to off. If it's turned on by the system + * or $HOME .exrc files, and the local .exrc file passes the ownership and + * writeability tests, then we read it. This breaks historic 4BSD practice, + * but it gives us a measure of security on systems where users can give away + * files. + */ +static enum rc +exrc_isok(SCR *sp, struct stat *sbp, char *path, int rootown, int rootid) +{ + enum { ROOTOWN, OWN, WRITER } etype; + uid_t euid; + int nf1, nf2; + char *a, *b, *buf; + + /* Check for the file's existence. */ + if (stat(path, sbp)) + return (NOEXIST); + + /* Check ownership permissions. */ + euid = geteuid(); + if (!(rootown && sbp->st_uid == 0) && + !(rootid && euid == 0) && sbp->st_uid != euid) { + etype = rootown ? ROOTOWN : OWN; + goto denied; + } + + /* Check writeability. */ + if (sbp->st_mode & (S_IWGRP | S_IWOTH)) { + etype = WRITER; + goto denied; + } + return (RCOK); + +denied: a = msg_print(sp, path, &nf1); + if (strchr(path, '/') == NULL && (buf = getcwd(NULL, 0)) != NULL) { + char *p; + + b = msg_print(sp, buf, &nf2); + if ((p = join(b, a)) == NULL) { + msgq(sp, M_SYSERR, NULL); + goto err; + } + switch (etype) { + case ROOTOWN: + msgq(sp, M_ERR, + "128|%s: not sourced: not owned by you or root", p); + break; + case OWN: + msgq(sp, M_ERR, + "129|%s: not sourced: not owned by you", p); + break; + case WRITER: + msgq(sp, M_ERR, + "130|%s: not sourced: writeable by a user other than the owner", p); + break; + } + free(p); +err: free(buf); + if (nf2) + FREE_SPACE(sp, b, 0); + } else + switch (etype) { + case ROOTOWN: + msgq(sp, M_ERR, + "128|%s: not sourced: not owned by you or root", a); + break; + case OWN: + msgq(sp, M_ERR, + "129|%s: not sourced: not owned by you", a); + break; + case WRITER: + msgq(sp, M_ERR, + "130|%s: not sourced: writeable by a user other than the owner", a); + break; + } + + if (nf1) + FREE_SPACE(sp, a, 0); + return (NOPERM); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_init.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_join.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_join.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_join.c (revision 366308) @@ -0,0 +1,166 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "../common/common.h" + +/* + * ex_join -- :[line [,line]] j[oin][!] [count] [flags] + * Join lines. + * + * PUBLIC: int ex_join(SCR *, EXCMD *); + */ +int +ex_join(SCR *sp, EXCMD *cmdp) +{ + recno_t from, to; + size_t blen, clen, len, tlen; + int echar = 0, extra, first; + CHAR_T *bp, *tbp = NULL; + CHAR_T *p; + + NEEDFILE(sp, cmdp); + + from = cmdp->addr1.lno; + to = cmdp->addr2.lno; + + /* Check for no lines to join. */ + if (!db_exist(sp, from + 1)) { + msgq(sp, M_ERR, "131|No following lines to join"); + return (1); + } + + GET_SPACE_RETW(sp, bp, blen, 256); + + /* + * The count for the join command was off-by-one, + * historically, to other counts for other commands. + */ + if (F_ISSET(cmdp, E_ADDR_DEF) || cmdp->addrcnt == 1) + ++cmdp->addr2.lno; + + clen = tlen = 0; + for (first = 1, + from = cmdp->addr1.lno, to = cmdp->addr2.lno; from <= to; ++from) { + /* + * Get next line. Historic versions of vi allowed "10J" while + * less than 10 lines from the end-of-file, so we do too. + */ + if (db_get(sp, from, 0, &p, &len)) { + cmdp->addr2.lno = from - 1; + break; + } + + /* Empty lines just go away. */ + if (len == 0) + continue; + + /* + * Get more space if necessary. Note, tlen isn't the length + * of the new line, it's roughly the amount of space needed. + * tbp - bp is the length of the new line. + */ + tlen += len + 2; + ADD_SPACE_RETW(sp, bp, blen, tlen); + tbp = bp + clen; + + /* + * Historic practice: + * + * If force specified, join without modification. + * If the current line ends with whitespace, strip leading + * whitespace from the joined line. + * If the next line starts with a ), do nothing. + * If the current line ends with ., insert two spaces. + * Else, insert one space. + * + * One change -- add ? and ! to the list of characters for + * which we insert two spaces. I expect that POSIX 1003.2 + * will require this as well. + * + * Echar is the last character in the last line joined. + */ + extra = 0; + if (!first && !FL_ISSET(cmdp->iflags, E_C_FORCE)) { + if (isblank(echar)) + for (; len && isblank(*p); --len, ++p); + else if (p[0] != ')') { + if (STRCHR(L(".?!"), echar)) { + *tbp++ = ' '; + ++clen; + extra = 1; + } + *tbp++ = ' '; + ++clen; + for (; len && isblank(*p); --len, ++p); + } + } + + if (len != 0) { + MEMCPY(tbp, p, len); + tbp += len; + clen += len; + echar = p[len - 1]; + } else + echar = ' '; + + /* + * Historic practice for vi was to put the cursor at the first + * inserted whitespace character, if there was one, or the + * first character of the joined line, if there wasn't, or the + * last character of the line if joined to an empty line. If + * a count was specified, the cursor was moved as described + * for the first line joined, ignoring subsequent lines. If + * the join was a ':' command, the cursor was placed at the + * first non-blank character of the line unless the cursor was + * "attracted" to the end of line when the command was executed + * in which case it moved to the new end of line. There are + * probably several more special cases, but frankly, my dear, + * I don't give a damn. This implementation puts the cursor + * on the first inserted whitespace character, the first + * character of the joined line, or the last character of the + * line regardless. Note, if the cursor isn't on the joined + * line (possible with : commands), it is reset to the starting + * line. + */ + if (first) { + sp->cno = (tbp - bp) - (1 + extra); + first = 0; + } else + sp->cno = (tbp - bp) - len - (1 + extra); + } + sp->lno = cmdp->addr1.lno; + + /* Delete the joined lines. */ + for (from = cmdp->addr1.lno, to = cmdp->addr2.lno; to > from; --to) + if (db_delete(sp, to)) + goto err; + + /* If the original line changed, reset it. */ + if (!first && db_set(sp, from, bp, tbp - bp)) { +err: FREE_SPACEW(sp, bp, blen); + return (1); + } + FREE_SPACEW(sp, bp, blen); + + sp->rptlines[L_JOINED] += (cmdp->addr2.lno - cmdp->addr1.lno) + 1; + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_join.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_map.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_map.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_map.c (revision 366308) @@ -0,0 +1,114 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "../common/common.h" + +/* + * ex_map -- :map[!] [input] [replacement] + * Map a key/string or display mapped keys. + * + * Historical note: + * Historic vi maps were fairly bizarre, and likely to differ in + * very subtle and strange ways from this implementation. Two + * things worth noting are that vi would often hang or drop core + * if the map was strange enough (ex: map X "xy$@x^V), or, simply + * not work. One trick worth remembering is that if you put a + * mark at the start of the map, e.g. map X mx"xy ...), or if you + * put the map in a .exrc file, things would often work much better. + * No clue why. + * + * PUBLIC: int ex_map(SCR *, EXCMD *); + */ +int +ex_map(SCR *sp, EXCMD *cmdp) +{ + seq_t stype; + CHAR_T *input, *p; + + stype = FL_ISSET(cmdp->iflags, E_C_FORCE) ? SEQ_INPUT : SEQ_COMMAND; + + switch (cmdp->argc) { + case 0: + if (seq_dump(sp, stype, 1) == 0) + msgq(sp, M_INFO, stype == SEQ_INPUT ? + "132|No input map entries" : + "133|No command map entries"); + return (0); + case 2: + input = cmdp->argv[0]->bp; + break; + default: + abort(); + } + + /* + * If the mapped string is #[0-9]* (and wasn't quoted) then store the + * function key mapping. If the screen specific routine has been set, + * call it as well. Note, the SEQ_FUNCMAP type is persistent across + * screen types, maybe the next screen type will get it right. + */ + if (input[0] == '#' && isdigit(input[1])) { + for (p = input + 2; isdigit(*p); ++p); + if (p[0] != '\0') + goto nofunc; + + if (seq_set(sp, NULL, 0, input, cmdp->argv[0]->len, + cmdp->argv[1]->bp, cmdp->argv[1]->len, stype, + SEQ_FUNCMAP | SEQ_USERDEF)) + return (1); + return (sp->gp->scr_fmap == NULL ? 0 : + sp->gp->scr_fmap(sp, stype, input, cmdp->argv[0]->len, + cmdp->argv[1]->bp, cmdp->argv[1]->len)); + } + + /* Some single keys may not be remapped in command mode. */ +nofunc: if (stype == SEQ_COMMAND && input[1] == '\0') + switch (KEY_VAL(sp, input[0])) { + case K_COLON: + case K_ESCAPE: + case K_NL: + msgq(sp, M_ERR, + "134|The %s character may not be remapped", + KEY_NAME(sp, input[0])); + return (1); + } + return (seq_set(sp, NULL, 0, input, cmdp->argv[0]->len, + cmdp->argv[1]->bp, cmdp->argv[1]->len, stype, SEQ_USERDEF)); +} + +/* + * ex_unmap -- (:unmap[!] key) + * Unmap a key. + * + * PUBLIC: int ex_unmap(SCR *, EXCMD *); + */ +int +ex_unmap(SCR *sp, EXCMD *cmdp) +{ + if (seq_delete(sp, cmdp->argv[0]->bp, cmdp->argv[0]->len, + FL_ISSET(cmdp->iflags, E_C_FORCE) ? SEQ_INPUT : SEQ_COMMAND)) { + msgq_wstr(sp, M_INFO, + cmdp->argv[0]->bp, "135|\"%s\" isn't currently mapped"); + return (1); + } + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_map.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_mark.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_mark.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_mark.c (revision 366308) @@ -0,0 +1,40 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include + +#include "../common/common.h" + +/* + * ex_mark -- :mark char + * :k char + * Mark lines. + * + * + * PUBLIC: int ex_mark(SCR *, EXCMD *); + */ +int +ex_mark(SCR *sp, EXCMD *cmdp) +{ + NEEDFILE(sp, cmdp); + + if (cmdp->argv[0]->len != 1) { + msgq(sp, M_ERR, "136|Mark names must be a single character"); + return (1); + } + return (mark_set(sp, cmdp->argv[0]->bp[0], &cmdp->addr1, 1)); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_mark.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_mkexrc.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_mkexrc.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_mkexrc.c (revision 366308) @@ -0,0 +1,97 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../common/common.h" +#include "pathnames.h" + +/* + * ex_mkexrc -- :mkexrc[!] [file] + * + * Create (or overwrite) a .exrc file with the current info. + * + * PUBLIC: int ex_mkexrc(SCR *, EXCMD *); + */ +int +ex_mkexrc(SCR *sp, EXCMD *cmdp) +{ + struct stat sb; + FILE *fp; + int fd, sverrno; + char *fname; + size_t flen; + + switch (cmdp->argc) { + case 0: + fname = _PATH_EXRC; + break; + case 1: + INT2CHAR(sp, cmdp->argv[0]->bp, cmdp->argv[0]->len + 1, + fname, flen); + set_alt_name(sp, fname); + break; + default: + abort(); + } + + if (!FL_ISSET(cmdp->iflags, E_C_FORCE) && !stat(fname, &sb)) { + msgq_str(sp, M_ERR, fname, + "137|%s exists, not written; use ! to override"); + return (1); + } + + /* Create with max permissions of rw-r--r--. */ + if ((fd = open(fname, O_CREAT | O_TRUNC | O_WRONLY, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) { + msgq_str(sp, M_SYSERR, fname, "%s"); + return (1); + } + + if ((fp = fdopen(fd, "w")) == NULL) { + sverrno = errno; + (void)close(fd); + goto e2; + } + + if (seq_save(sp, fp, "abbreviate ", SEQ_ABBREV) || ferror(fp)) + goto e1; + if (seq_save(sp, fp, "map ", SEQ_COMMAND) || ferror(fp)) + goto e1; + if (seq_save(sp, fp, "map! ", SEQ_INPUT) || ferror(fp)) + goto e1; + if (opts_save(sp, fp) || ferror(fp)) + goto e1; + if (fclose(fp)) { + sverrno = errno; + goto e2; + } + + msgq_str(sp, M_INFO, fname, "138|New exrc file: %s"); + return (0); + +e1: sverrno = errno; + (void)fclose(fp); +e2: errno = sverrno; + msgq_str(sp, M_SYSERR, fname, "%s"); + return (1); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_mkexrc.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_move.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_move.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_move.c (revision 366308) @@ -0,0 +1,188 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "../common/common.h" + +/* + * ex_copy -- :[line [,line]] co[py] line [flags] + * Copy selected lines. + * + * PUBLIC: int ex_copy(SCR *, EXCMD *); + */ +int +ex_copy(SCR *sp, EXCMD *cmdp) +{ + CB cb = {{ 0 }}; + MARK fm1, fm2, m, tm; + recno_t cnt; + int rval; + + rval = 0; + + NEEDFILE(sp, cmdp); + + /* + * It's possible to copy things into the area that's being + * copied, e.g. "2,5copy3" is legitimate. Save the text to + * a cut buffer. + */ + fm1 = cmdp->addr1; + fm2 = cmdp->addr2; + TAILQ_INIT(cb.textq); + for (cnt = fm1.lno; cnt <= fm2.lno; ++cnt) + if (cut_line(sp, cnt, 0, ENTIRE_LINE, &cb)) { + rval = 1; + goto err; + } + cb.flags |= CB_LMODE; + + /* Put the text into place. */ + tm.lno = cmdp->lineno; + tm.cno = 0; + if (put(sp, &cb, NULL, &tm, &m, 1)) + rval = 1; + else { + /* + * Copy puts the cursor on the last line copied. The cursor + * returned by the put routine is the first line put, not the + * last, because that's the historic semantic of vi. + */ + cnt = (fm2.lno - fm1.lno) + 1; + sp->lno = m.lno + (cnt - 1); + sp->cno = 0; + } +err: text_lfree(cb.textq); + return (rval); +} + +/* + * ex_move -- :[line [,line]] mo[ve] line + * Move selected lines. + * + * PUBLIC: int ex_move(SCR *, EXCMD *); + */ +int +ex_move(SCR *sp, EXCMD *cmdp) +{ + LMARK *lmp; + MARK fm1, fm2; + recno_t cnt, diff, fl, tl, mfl, mtl; + size_t blen, len; + int mark_reset; + CHAR_T *bp; + CHAR_T *p; + + NEEDFILE(sp, cmdp); + + /* + * It's not possible to move things into the area that's being + * moved. + */ + fm1 = cmdp->addr1; + fm2 = cmdp->addr2; + if (cmdp->lineno >= fm1.lno && cmdp->lineno <= fm2.lno) { + msgq(sp, M_ERR, "139|Destination line is inside move range"); + return (1); + } + + /* + * Log the positions of any marks in the to-be-deleted lines. This + * has to work with the logging code. What happens is that we log + * the old mark positions, make the changes, then log the new mark + * positions. Then the marks end up in the right positions no matter + * which way the log is traversed. + * + * XXX + * Reset the MARK_USERSET flag so that the log can undo the mark. + * This isn't very clean, and should probably be fixed. + */ + fl = fm1.lno; + tl = cmdp->lineno; + + /* Log the old positions of the marks. */ + mark_reset = 0; + SLIST_FOREACH(lmp, sp->ep->marks, q) + if (lmp->name != ABSMARK1 && + lmp->lno >= fl && lmp->lno <= tl) { + mark_reset = 1; + F_CLR(lmp, MARK_USERSET); + (void)log_mark(sp, lmp); + } + + /* Get memory for the copy. */ + GET_SPACE_RETW(sp, bp, blen, 256); + + /* Move the lines. */ + diff = (fm2.lno - fm1.lno) + 1; + if (tl > fl) { /* Destination > source. */ + mfl = tl - diff; + mtl = tl; + for (cnt = diff; cnt--;) { + if (db_get(sp, fl, DBG_FATAL, &p, &len)) + return (1); + BINC_RETW(sp, bp, blen, len); + MEMCPY(bp, p, len); + if (db_append(sp, 1, tl, bp, len)) + return (1); + if (mark_reset) + SLIST_FOREACH(lmp, sp->ep->marks, q) + if (lmp->name != ABSMARK1 && + lmp->lno == fl) + lmp->lno = tl + 1; + if (db_delete(sp, fl)) + return (1); + } + } else { /* Destination < source. */ + mfl = tl; + mtl = tl + diff; + for (cnt = diff; cnt--;) { + if (db_get(sp, fl, DBG_FATAL, &p, &len)) + return (1); + BINC_RETW(sp, bp, blen, len); + MEMCPY(bp, p, len); + if (db_append(sp, 1, tl++, bp, len)) + return (1); + if (mark_reset) + SLIST_FOREACH(lmp, sp->ep->marks, q) + if (lmp->name != ABSMARK1 && + lmp->lno == fl) + lmp->lno = tl; + ++fl; + if (db_delete(sp, fl)) + return (1); + } + } + FREE_SPACEW(sp, bp, blen); + + sp->lno = tl; /* Last line moved. */ + sp->cno = 0; + + /* Log the new positions of the marks. */ + if (mark_reset) + SLIST_FOREACH(lmp, sp->ep->marks, q) + if (lmp->name != ABSMARK1 && + lmp->lno >= mfl && lmp->lno <= mtl) + (void)log_mark(sp, lmp); + + + sp->rptlines[L_MOVED] += diff; + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_move.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_open.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_open.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_open.c (revision 366308) @@ -0,0 +1,41 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include + +#include "../common/common.h" + +/* + * ex_open -- :[line] o[pen] [/pattern/] [flags] + * + * Switch to single line "open" mode. + * + * PUBLIC: int ex_open(SCR *, EXCMD *); + */ +int +ex_open(SCR *sp, EXCMD *cmdp) +{ + /* If open option off, disallow open command. */ + if (!O_ISSET(sp, O_OPEN)) { + msgq(sp, M_ERR, + "140|The open command requires that the open option be set"); + return (1); + } + + msgq(sp, M_ERR, "141|The open command is not yet implemented"); + return (1); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_open.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_preserve.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_preserve.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_preserve.c (revision 366308) @@ -0,0 +1,100 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "../common/common.h" + +/* + * ex_preserve -- :pre[serve] + * Push the file to recovery. + * + * PUBLIC: int ex_preserve(SCR *, EXCMD *); + */ +int +ex_preserve(SCR *sp, EXCMD *cmdp) +{ + recno_t lno; + + NEEDFILE(sp, cmdp); + + if (!F_ISSET(sp->ep, F_RCV_ON)) { + msgq(sp, M_ERR, "142|Preservation of this file not possible"); + return (1); + } + + /* If recovery not initialized, do so. */ + if (F_ISSET(sp->ep, F_FIRSTMODIFY) && rcv_init(sp)) + return (1); + + /* Force the file to be read in, in case it hasn't yet. */ + if (db_last(sp, &lno)) + return (1); + + /* Sync to disk. */ + if (rcv_sync(sp, RCV_SNAPSHOT)) + return (1); + + msgq(sp, M_INFO, "143|File preserved"); + return (0); +} + +/* + * ex_recover -- :rec[over][!] file + * Recover the file. + * + * PUBLIC: int ex_recover(SCR *, EXCMD *); + */ +int +ex_recover(SCR *sp, EXCMD *cmdp) +{ + ARGS *ap; + FREF *frp; + char *np; + size_t nlen; + + ap = cmdp->argv[0]; + + /* Set the alternate file name. */ + INT2CHAR(sp, ap->bp, ap->len+1, np, nlen); + set_alt_name(sp, np); + + /* + * Check for modifications. Autowrite did not historically + * affect :recover. + */ + if (file_m2(sp, FL_ISSET(cmdp->iflags, E_C_FORCE))) + return (1); + + /* Get a file structure for the file. */ + INT2CHAR(sp, ap->bp, ap->len+1, np, nlen); + if ((frp = file_add(sp, np)) == NULL) + return (1); + + /* Set the recover bit. */ + F_SET(frp, FR_RECOVER); + + /* Switch files. */ + if (file_init(sp, frp, NULL, FS_SETALT | + (FL_ISSET(cmdp->iflags, E_C_FORCE) ? FS_FORCE : 0))) + return (1); + + F_SET(sp, SC_FSWITCH); + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_preserve.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_print.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_print.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_print.c (revision 366308) @@ -0,0 +1,327 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "../common/common.h" + +static int ex_prchars(SCR *, + const CHAR_T *, size_t *, size_t, u_int, int); + +/* + * ex_list -- :[line [,line]] l[ist] [count] [flags] + * + * Display the addressed lines such that the output is unambiguous. + * + * PUBLIC: int ex_list(SCR *, EXCMD *); + */ +int +ex_list(SCR *sp, EXCMD *cmdp) +{ + if (ex_print(sp, cmdp, + &cmdp->addr1, &cmdp->addr2, cmdp->iflags | E_C_LIST)) + return (1); + sp->lno = cmdp->addr2.lno; + sp->cno = cmdp->addr2.cno; + return (0); +} + +/* + * ex_number -- :[line [,line]] nu[mber] [count] [flags] + * + * Display the addressed lines with a leading line number. + * + * PUBLIC: int ex_number(SCR *, EXCMD *); + */ +int +ex_number(SCR *sp, EXCMD *cmdp) +{ + if (ex_print(sp, cmdp, + &cmdp->addr1, &cmdp->addr2, cmdp->iflags | E_C_HASH)) + return (1); + sp->lno = cmdp->addr2.lno; + sp->cno = cmdp->addr2.cno; + return (0); +} + +/* + * ex_pr -- :[line [,line]] p[rint] [count] [flags] + * + * Display the addressed lines. + * + * PUBLIC: int ex_pr(SCR *, EXCMD *); + */ +int +ex_pr(SCR *sp, EXCMD *cmdp) +{ + if (ex_print(sp, cmdp, &cmdp->addr1, &cmdp->addr2, cmdp->iflags)) + return (1); + sp->lno = cmdp->addr2.lno; + sp->cno = cmdp->addr2.cno; + return (0); +} + +/* + * ex_print -- + * Print the selected lines. + * + * PUBLIC: int ex_print(SCR *, EXCMD *, MARK *, MARK *, u_int32_t); + */ +int +ex_print(SCR *sp, EXCMD *cmdp, MARK *fp, MARK *tp, u_int32_t flags) +{ + GS *gp; + recno_t from, to; + size_t col, len; + CHAR_T *p; + CHAR_T buf[10]; + + NEEDFILE(sp, cmdp); + + gp = sp->gp; + for (from = fp->lno, to = tp->lno; from <= to; ++from) { + col = 0; + + /* + * Display the line number. The %6 format is specified + * by POSIX 1003.2, and is almost certainly large enough. + * Check, though, just in case. + */ + if (LF_ISSET(E_C_HASH)) { + if (from <= 999999) { + SPRINTF(buf, SIZE(buf), L("%6u "), from); + p = buf; + } else + p = L("TOOBIG "); + if (ex_prchars(sp, p, &col, 8, 0, 0)) + return (1); + } + + /* + * Display the line. The format for E_C_PRINT isn't very good, + * especially in handling end-of-line tabs, but they're almost + * backward compatible. + */ + if (db_get(sp, from, DBG_FATAL, &p, &len)) + return (1); + + if (len == 0 && !LF_ISSET(E_C_LIST)) + (void)ex_puts(sp, "\n"); + else if (ex_ldisplay(sp, p, len, col, flags)) + return (1); + + if (INTERRUPTED(sp)) + break; + } + return (0); +} + +/* + * ex_ldisplay -- + * Display a line without any preceding number. + * + * PUBLIC: int ex_ldisplay(SCR *, const CHAR_T *, size_t, size_t, u_int); + */ +int +ex_ldisplay(SCR *sp, const CHAR_T *p, size_t len, size_t col, u_int flags) +{ + if (len > 0 && ex_prchars(sp, p, &col, len, LF_ISSET(E_C_LIST), 0)) + return (1); + if (!INTERRUPTED(sp) && LF_ISSET(E_C_LIST)) { + p = L("$"); + if (ex_prchars(sp, p, &col, 1, LF_ISSET(E_C_LIST), 0)) + return (1); + } + if (!INTERRUPTED(sp)) + (void)ex_puts(sp, "\n"); + return (0); +} + +/* + * ex_scprint -- + * Display a line for the substitute with confirmation routine. + * + * PUBLIC: int ex_scprint(SCR *, MARK *, MARK *); + */ +int +ex_scprint(SCR *sp, MARK *fp, MARK *tp) +{ + CHAR_T *p; + size_t col, len; + + col = 0; + if (O_ISSET(sp, O_NUMBER)) { + p = L(" "); + if (ex_prchars(sp, p, &col, 8, 0, 0)) + return (1); + } + + if (db_get(sp, fp->lno, DBG_FATAL, &p, &len)) + return (1); + + if (ex_prchars(sp, p, &col, fp->cno, 0, ' ')) + return (1); + p += fp->cno; + if (ex_prchars(sp, + p, &col, tp->cno == fp->cno ? 1 : tp->cno - fp->cno, 0, '^')) + return (1); + if (INTERRUPTED(sp)) + return (1); + p = L("[ynq]"); /* XXX: should be msg_cat. */ + if (ex_prchars(sp, p, &col, 5, 0, 0)) + return (1); + (void)ex_fflush(sp); + return (0); +} + +/* + * ex_prchars -- + * Local routine to dump characters to the screen. + */ +static int +ex_prchars(SCR *sp, const CHAR_T *p, size_t *colp, size_t len, + u_int flags, int repeatc) +{ + CHAR_T ch; + char *kp; + GS *gp; + size_t col, tlen, ts; + + if (O_ISSET(sp, O_LIST)) + LF_SET(E_C_LIST); + gp = sp->gp; + ts = O_VAL(sp, O_TABSTOP); + for (col = *colp; len--;) + if ((ch = *p++) == '\t' && !LF_ISSET(E_C_LIST)) + for (tlen = ts - col % ts; + col < sp->cols && tlen--; ++col) { + (void)ex_printf(sp, + "%c", repeatc ? repeatc : ' '); + if (INTERRUPTED(sp)) + goto intr; + } + else { + kp = KEY_NAME(sp, ch); + tlen = KEY_COL(sp, ch); + + /* + * Start a new line if the last character does not fit + * into the current line. The implicit new lines are + * not interruptible. + */ + if (col + tlen > sp->cols) { + col = 0; + (void)ex_puts(sp, "\n"); + } + + col += tlen; + if (!repeatc) { + (void)ex_puts(sp, kp); + if (INTERRUPTED(sp)) + goto intr; + } else while (tlen--) { + (void)ex_printf(sp, "%c", repeatc); + if (INTERRUPTED(sp)) + goto intr; + } + if (col == sp->cols) { + col = 0; + (void)ex_puts(sp, "\n"); + } + } +intr: *colp = col; + return (0); +} + +/* + * ex_printf -- + * Ex's version of printf. + * + * PUBLIC: int ex_printf(SCR *, const char *, ...); + */ +int +ex_printf( + SCR *sp, + const char *fmt, + ...) +{ + EX_PRIVATE *exp; + va_list ap; + size_t n; + + exp = EXP(sp); + + va_start(ap, fmt); + exp->obp_len += n = vsnprintf(exp->obp + exp->obp_len, + sizeof(exp->obp) - exp->obp_len, fmt, ap); + va_end(ap); + + /* Flush when reach a or half the buffer. */ + if (exp->obp[exp->obp_len - 1] == '\n' || + exp->obp_len > sizeof(exp->obp) / 2) + (void)ex_fflush(sp); + return (n); +} + +/* + * ex_puts -- + * Ex's version of puts. + * + * PUBLIC: int ex_puts(SCR *, const char *); + */ +int +ex_puts(SCR *sp, const char *str) +{ + EX_PRIVATE *exp; + int doflush, n; + + exp = EXP(sp); + + /* Flush when reach a or the end of the buffer. */ + for (doflush = n = 0; *str != '\0'; ++n) { + if (exp->obp_len > sizeof(exp->obp)) + (void)ex_fflush(sp); + if ((exp->obp[exp->obp_len++] = *str++) == '\n') + doflush = 1; + } + if (doflush) + (void)ex_fflush(sp); + return (n); +} + +/* + * ex_fflush -- + * Ex's version of fflush. + * + * PUBLIC: int ex_fflush(SCR *sp); + */ +int +ex_fflush(SCR *sp) +{ + EX_PRIVATE *exp; + + exp = EXP(sp); + + if (exp->obp_len != 0) { + sp->gp->scr_msg(sp, M_NONE, exp->obp, exp->obp_len); + exp->obp_len = 0; + } + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_print.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_put.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_put.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_put.c (revision 366308) @@ -0,0 +1,46 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "../common/common.h" + +/* + * ex_put -- [line] pu[t] [buffer] + * Append a cut buffer into the file. + * + * PUBLIC: int ex_put(SCR *, EXCMD *); + */ +int +ex_put(SCR *sp, EXCMD *cmdp) +{ + MARK m; + + NEEDFILE(sp, cmdp); + + m.lno = sp->lno; + m.cno = sp->cno; + if (put(sp, NULL, + FL_ISSET(cmdp->iflags, E_C_BUFFER) ? &cmdp->buffer : NULL, + &cmdp->addr1, &m, 1)) + return (1); + sp->lno = m.lno; + sp->cno = m.cno; + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_put.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_quit.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_quit.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_quit.c (revision 366308) @@ -0,0 +1,41 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include + +#include "../common/common.h" + +/* + * ex_quit -- :quit[!] + * Quit. + * + * PUBLIC: int ex_quit(SCR *, EXCMD *); + */ +int +ex_quit(SCR *sp, EXCMD *cmdp) +{ + int force; + + force = FL_ISSET(cmdp->iflags, E_C_FORCE); + + /* Check for file modifications, or more files to edit. */ + if (file_m2(sp, force) || ex_ncheck(sp, force)) + return (1); + + F_SET(sp, force ? SC_EXIT_FORCE : SC_EXIT); + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_quit.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_read.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_read.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_read.c (revision 366308) @@ -0,0 +1,356 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "../common/common.h" +#include "../vi/vi.h" + +/* + * ex_read -- :read [file] + * :read [!cmd] + * Read from a file or utility. + * + * !!! + * Historical vi wouldn't undo a filter read, for no apparent reason. + * + * PUBLIC: int ex_read(SCR *, EXCMD *); + */ +int +ex_read(SCR *sp, EXCMD *cmdp) +{ + enum { R_ARG, R_EXPANDARG, R_FILTER } which; + struct stat sb; + CHAR_T *arg = NULL; + char *name = NULL; + size_t nlen; + EX_PRIVATE *exp; + FILE *fp; + FREF *frp; + GS *gp; + MARK rm; + recno_t nlines; + size_t arglen = 0; + int argc, rval; + char *p; + + gp = sp->gp; + + /* + * 0 args: read the current pathname. + * 1 args: check for "read !arg". + */ + switch (cmdp->argc) { + case 0: + which = R_ARG; + break; + case 1: + arg = cmdp->argv[0]->bp; + arglen = cmdp->argv[0]->len; + if (*arg == '!') { + ++arg; + --arglen; + which = R_FILTER; + + /* Secure means no shell access. */ + if (O_ISSET(sp, O_SECURE)) { + ex_wemsg(sp, cmdp->cmd->name, EXM_SECURE_F); + return (1); + } + } else + which = R_EXPANDARG; + break; + default: + abort(); + /* NOTREACHED */ + } + + /* Load a temporary file if no file being edited. */ + if (sp->ep == NULL) { + if ((frp = file_add(sp, NULL)) == NULL) + return (1); + if (file_init(sp, frp, NULL, 0)) + return (1); + } + + switch (which) { + case R_FILTER: + /* + * File name and bang expand the user's argument. If + * we don't get an additional argument, it's illegal. + */ + argc = cmdp->argc; + if (argv_exp1(sp, cmdp, arg, arglen, 1)) + return (1); + if (argc == cmdp->argc) { + ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE); + return (1); + } + argc = cmdp->argc - 1; + + /* Set the last bang command. */ + exp = EXP(sp); + free(exp->lastbcomm); + if ((exp->lastbcomm = + v_wstrdup(sp, cmdp->argv[argc]->bp, + cmdp->argv[argc]->len)) == NULL) { + msgq(sp, M_SYSERR, NULL); + return (1); + } + + /* + * Vi redisplayed the user's argument if it changed, ex + * always displayed a !, plus the user's argument if it + * changed. + */ + if (F_ISSET(sp, SC_VI)) { + if (F_ISSET(cmdp, E_MODIFY)) + (void)vs_update(sp, "!", cmdp->argv[argc]->bp); + } else { + if (F_ISSET(cmdp, E_MODIFY)) + (void)ex_printf(sp, + "!"WS"\n", cmdp->argv[argc]->bp); + else + (void)ex_puts(sp, "!\n"); + (void)ex_fflush(sp); + } + + /* + * Historically, filter reads as the first ex command didn't + * wait for the user. If SC_SCR_EXWROTE not already set, set + * the don't-wait flag. + */ + if (!F_ISSET(sp, SC_SCR_EXWROTE)) + F_SET(sp, SC_EX_WAIT_NO); + + /* + * Switch into ex canonical mode. The reason to restore the + * original terminal modes for read filters is so that users + * can do things like ":r! cat /dev/tty". + * + * !!! + * We do not output an extra , so that we don't touch + * the screen on a normal read. + */ + if (F_ISSET(sp, SC_VI)) { + if (gp->scr_screen(sp, SC_EX)) { + ex_wemsg(sp, cmdp->cmd->name, EXM_NOCANON_F); + return (1); + } + /* + * !!! + * Historically, the read command doesn't switch to + * the alternate X11 xterm screen, if doing a filter + * read -- don't set SA_ALTERNATE. + */ + F_SET(sp, SC_SCR_EX | SC_SCR_EXWROTE); + } + + if (ex_filter(sp, cmdp, &cmdp->addr1, + NULL, &rm, cmdp->argv[argc]->bp, FILTER_READ)) + return (1); + + /* The filter version of read set the autoprint flag. */ + F_SET(cmdp, E_AUTOPRINT); + + /* + * If in vi mode, move to the first nonblank. Might have + * switched into ex mode, so saved the original SC_VI value. + */ + sp->lno = rm.lno; + if (F_ISSET(sp, SC_VI)) { + sp->cno = 0; + (void)nonblank(sp, sp->lno, &sp->cno); + } + return (0); + case R_ARG: + name = sp->frp->name; + break; + case R_EXPANDARG: + if (argv_exp2(sp, cmdp, arg, arglen)) + return (1); + /* + * 0 args: impossible. + * 1 args: impossible (I hope). + * 2 args: read it. + * >2 args: object, too many args. + * + * The 1 args case depends on the argv_sexp() function refusing + * to return success without at least one non-blank character. + */ + switch (cmdp->argc) { + case 0: + case 1: + abort(); + /* NOTREACHED */ + case 2: + INT2CHAR(sp, cmdp->argv[1]->bp, cmdp->argv[1]->len + 1, + name, nlen); + /* + * !!! + * Historically, the read and write commands renamed + * "unnamed" files, or, if the file had a name, set + * the alternate file name. + */ + if (F_ISSET(sp->frp, FR_TMPFILE) && + !F_ISSET(sp->frp, FR_EXNAMED)) { + if ((p = strdup(name)) != NULL) { + free(sp->frp->name); + sp->frp->name = p; + } + /* + * The file has a real name, it's no longer a + * temporary, clear the temporary file flags. + */ + F_CLR(sp->frp, FR_TMPEXIT | FR_TMPFILE); + F_SET(sp->frp, FR_NAMECHANGE | FR_EXNAMED); + + /* Notify the screen. */ + (void)sp->gp->scr_rename(sp, sp->frp->name, 1); + name = sp->frp->name; + } else { + set_alt_name(sp, name); + name = sp->alt_name; + } + break; + default: + ex_wemsg(sp, cmdp->argv[0]->bp, EXM_FILECOUNT); + return (1); + + } + break; + } + + /* + * !!! + * Historically, vi did not permit reads from non-regular files, nor + * did it distinguish between "read !" and "read!", so there was no + * way to "force" it. We permit reading from named pipes too, since + * they didn't exist when the original implementation of vi was done + * and they seem a reasonable addition. + */ + if ((fp = fopen(name, "r")) == NULL || fstat(fileno(fp), &sb)) { + msgq_str(sp, M_SYSERR, name, "%s"); + return (1); + } + if (!S_ISFIFO(sb.st_mode) && !S_ISREG(sb.st_mode)) { + (void)fclose(fp); + msgq(sp, M_ERR, + "145|Only regular files and named pipes may be read"); + return (1); + } + + /* Try and get a lock. */ + if (file_lock(sp, NULL, fileno(fp), 0) == LOCK_UNAVAIL) + msgq(sp, M_ERR, "146|%s: read lock was unavailable", name); + + rval = ex_readfp(sp, name, fp, &cmdp->addr1, &nlines, 0); + + /* + * In vi, set the cursor to the first line read in, if anything read + * in, otherwise, the address. (Historic vi set it to the line after + * the address regardless, but since that line may not exist we don't + * bother.) + * + * In ex, set the cursor to the last line read in, if anything read in, + * otherwise, the address. + */ + if (F_ISSET(sp, SC_VI)) { + sp->lno = cmdp->addr1.lno; + if (nlines) + ++sp->lno; + } else + sp->lno = cmdp->addr1.lno + nlines; + return (rval); +} + +/* + * ex_readfp -- + * Read lines into the file. + * + * PUBLIC: int ex_readfp(SCR *, char *, FILE *, MARK *, recno_t *, int); + */ +int +ex_readfp(SCR *sp, char *name, FILE *fp, MARK *fm, recno_t *nlinesp, int silent) +{ + EX_PRIVATE *exp; + GS *gp; + recno_t lcnt, lno; + size_t len; + u_long ccnt; /* XXX: can't print off_t portably. */ + int nf, rval; + char *p; + size_t wlen; + CHAR_T *wp; + + gp = sp->gp; + exp = EXP(sp); + + /* + * Add in the lines from the output. Insertion starts at the line + * following the address. + */ + ccnt = 0; + lcnt = 0; + p = "147|Reading..."; + for (lno = fm->lno; !ex_getline(sp, fp, &len); ++lno, ++lcnt) { + if ((lcnt + 1) % INTERRUPT_CHECK == 0) { + if (INTERRUPTED(sp)) + break; + if (!silent) { + gp->scr_busy(sp, p, + p == NULL ? BUSY_UPDATE : BUSY_ON); + p = NULL; + } + } + FILE2INT5(sp, exp->ibcw, exp->ibp, len, wp, wlen); + if (db_append(sp, 1, lno, wp, wlen)) + goto err; + ccnt += len; + } + + if (ferror(fp) || fclose(fp)) + goto err; + + /* Return the number of lines read in. */ + if (nlinesp != NULL) + *nlinesp = lcnt; + + if (!silent) { + p = msg_print(sp, name, &nf); + msgq(sp, M_INFO, + "148|%s: %lu lines, %lu characters", p, + (u_long)lcnt, ccnt); + if (nf) + FREE_SPACE(sp, p, 0); + } + + rval = 0; + if (0) { +err: msgq_str(sp, M_SYSERR, name, "%s"); + (void)fclose(fp); + rval = 1; + } + + if (!silent) + gp->scr_busy(sp, NULL, BUSY_OFF); + return (rval); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_read.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_screen.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_screen.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_screen.c (revision 366308) @@ -0,0 +1,127 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "../common/common.h" +#include "../vi/vi.h" + +/* + * ex_bg -- :bg + * Hide the screen. + * + * PUBLIC: int ex_bg(SCR *, EXCMD *); + */ +int +ex_bg(SCR *sp, EXCMD *cmdp) +{ + return (vs_bg(sp)); +} + +/* + * ex_fg -- :fg [file] + * Show the screen. + * + * PUBLIC: int ex_fg(SCR *, EXCMD *); + */ +int +ex_fg(SCR *sp, EXCMD *cmdp) +{ + SCR *nsp; + int newscreen; + + newscreen = F_ISSET(cmdp, E_NEWSCREEN); + if (vs_fg(sp, &nsp, cmdp->argc ? cmdp->argv[0]->bp : NULL, newscreen)) + return (1); + + /* Set up the switch. */ + if (newscreen) { + sp->nextdisp = nsp; + F_SET(sp, SC_SSWITCH); + } + return (0); +} + +/* + * ex_resize -- :resize [+-]rows + * Change the screen size. + * + * PUBLIC: int ex_resize(SCR *, EXCMD *); + */ +int +ex_resize(SCR *sp, EXCMD *cmdp) +{ + adj_t adj; + + switch (FL_ISSET(cmdp->iflags, + E_C_COUNT | E_C_COUNT_NEG | E_C_COUNT_POS)) { + case E_C_COUNT: + adj = A_SET; + break; + case E_C_COUNT | E_C_COUNT_NEG: + adj = A_DECREASE; + break; + case E_C_COUNT | E_C_COUNT_POS: + adj = A_INCREASE; + break; + default: + ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE); + return (1); + } + return (vs_resize(sp, cmdp->count, adj)); +} + +/* + * ex_sdisplay -- + * Display the list of screens. + * + * PUBLIC: int ex_sdisplay(SCR *); + */ +int +ex_sdisplay(SCR *sp) +{ + GS *gp; + SCR *tsp; + int cnt, col, len, sep; + + gp = sp->gp; + if ((tsp = TAILQ_FIRST(gp->hq)) == NULL) { + msgq(sp, M_INFO, "149|No background screens to display"); + return (0); + } + + col = len = sep = 0; + for (cnt = 1; tsp != NULL && !INTERRUPTED(sp); + tsp = TAILQ_NEXT(tsp, q)) { + col += len = strlen(tsp->frp->name) + sep; + if (col >= sp->cols - 1) { + col = len; + sep = 0; + (void)ex_puts(sp, "\n"); + } else if (cnt != 1) { + sep = 1; + (void)ex_puts(sp, " "); + } + (void)ex_puts(sp, tsp->frp->name); + ++cnt; + } + if (!INTERRUPTED(sp)) + (void)ex_puts(sp, "\n"); + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_screen.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_set.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_set.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_set.c (revision 366308) @@ -0,0 +1,41 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include + +#include "../common/common.h" + +/* + * ex_set -- :set + * Ex set option. + * + * PUBLIC: int ex_set(SCR *, EXCMD *); + */ +int +ex_set(SCR *sp, EXCMD *cmdp) +{ + switch(cmdp->argc) { + case 0: + opts_dump(sp, CHANGED_DISPLAY); + break; + default: + if (opts_set(sp, cmdp->argv, cmdp->cmd->usage)) + return (1); + break; + } + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_set.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_shift.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_shift.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_shift.c (revision 366308) @@ -0,0 +1,199 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "../common/common.h" + +enum which {RETAB, LEFT, RIGHT}; +static int shift(SCR *, EXCMD *, enum which); + +/* + * ex_shiftl -- :<[<...] + * + * + * PUBLIC: int ex_shiftl(SCR *, EXCMD *); + */ +int +ex_shiftl(SCR *sp, EXCMD *cmdp) +{ + return (shift(sp, cmdp, LEFT)); +} + +/* + * ex_shiftr -- :>[>...] + * + * PUBLIC: int ex_shiftr(SCR *, EXCMD *); + */ +int +ex_shiftr(SCR *sp, EXCMD *cmdp) +{ + return (shift(sp, cmdp, RIGHT)); +} + +/* + * ex_retab -- Expand tabs (if enabled) + * + * + * PUBLIC: int ex_retab(SCR *, EXCMD *); + */ +int +ex_retab(SCR *sp, EXCMD *cmdp) +{ + return (shift(sp, cmdp, RETAB)); +} + +/* + * shift -- + * Ex shift support. + */ +static int +shift(SCR *sp, EXCMD *cmdp, enum which rl) +{ + recno_t from, to; + size_t blen, len, newcol, newidx, oldcol, oldidx, sw; + int curset; + CHAR_T *p; + CHAR_T *bp, *tbp; + + NEEDFILE(sp, cmdp); + + if (O_VAL(sp, O_SHIFTWIDTH) == 0) { + msgq(sp, M_INFO, "152|shiftwidth option set to 0"); + return (0); + } + + /* Copy the lines being shifted into the unnamed buffer. */ + if (cut(sp, NULL, &cmdp->addr1, &cmdp->addr2, CUT_LINEMODE)) + return (1); + + /* + * The historic version of vi permitted the user to string any number + * of '>' or '<' characters together, resulting in an indent of the + * appropriate levels. There's a special hack in ex_cmd() so that + * cmdp->argv[0] points to the string of '>' or '<' characters. + * + * Q: What's the difference between the people adding features + * to vi and the Girl Scouts? + * A: The Girl Scouts have mint cookies and adult supervision. + */ + for (p = cmdp->argv[0]->bp, sw = 0; *p == '>' || *p == '<'; ++p) + sw += O_VAL(sp, O_SHIFTWIDTH); + + GET_SPACE_RETW(sp, bp, blen, 256); + + curset = 0; + for (from = cmdp->addr1.lno, to = cmdp->addr2.lno; from <= to; ++from) { + if (db_get(sp, from, DBG_FATAL, &p, &len)) + goto err; + if (!len) { + if (sp->lno == from) + curset = 1; + continue; + } + + /* + * Calculate the old indent amount and the number of + * characters it used. + */ + for (oldidx = 0, oldcol = 0; oldidx < len; ++oldidx) + if (p[oldidx] == ' ') + ++oldcol; + else if (p[oldidx] == '\t') + oldcol += O_VAL(sp, O_TABSTOP) - + oldcol % O_VAL(sp, O_TABSTOP); + else + break; + + /* Calculate the new indent amount. */ + if (rl == RETAB) + newcol = oldcol; + else if (rl == RIGHT) + newcol = oldcol + sw; + else { + newcol = oldcol < sw ? 0 : oldcol - sw; + if (newcol == oldcol) { + if (sp->lno == from) + curset = 1; + continue; + } + } + + /* Get a buffer that will hold the new line. */ + ADD_SPACE_RETW(sp, bp, blen, newcol + len); + + /* + * Build a new indent string and count the number of + * characters it uses. + */ + tbp = bp; + newidx = 0; + if (!O_ISSET(sp, O_EXPANDTAB)) { + for (; newcol >= O_VAL(sp, O_TABSTOP); ++newidx) { + *tbp++ = '\t'; + newcol -= O_VAL(sp, O_TABSTOP); + } + } + for (; newcol > 0; --newcol, ++newidx) + *tbp++ = ' '; + + /* Add the original line. */ + MEMCPY(tbp, p + oldidx, len - oldidx); + + /* Set the replacement line. */ + if (db_set(sp, from, bp, (tbp + (len - oldidx)) - bp)) { +err: FREE_SPACEW(sp, bp, blen); + return (1); + } + + /* + * !!! + * The shift command in historic vi had the usual bizarre + * collection of cursor semantics. If called from vi, the + * cursor was repositioned to the first non-blank character + * of the lowest numbered line shifted. If called from ex, + * the cursor was repositioned to the first non-blank of the + * highest numbered line shifted. Here, if the cursor isn't + * part of the set of lines that are moved, move it to the + * first non-blank of the last line shifted. (This makes + * ":3>>" in vi work reasonably.) If the cursor is part of + * the shifted lines, it doesn't get moved at all. This + * permits shifting of marked areas, i.e. ">'a." shifts the + * marked area twice, something that couldn't be done with + * historic vi. + */ + if (sp->lno == from) { + curset = 1; + if (newidx > oldidx) + sp->cno += newidx - oldidx; + else if (sp->cno >= oldidx - newidx) + sp->cno -= oldidx - newidx; + } + } + if (!curset) { + sp->lno = to; + sp->cno = 0; + (void)nonblank(sp, to, &sp->cno); + } + + FREE_SPACEW(sp, bp, blen); + + sp->rptlines[L_SHIFT] += cmdp->addr2.lno - cmdp->addr1.lno + 1; + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_shift.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_source.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_source.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_source.c (revision 366308) @@ -0,0 +1,90 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../common/common.h" + +/* + * ex_source -- :source file + * Execute ex commands from a file. + * + * PUBLIC: int ex_source(SCR *, EXCMD *); + */ +int +ex_source(SCR *sp, EXCMD *cmdp) +{ + struct stat sb; + int fd, len; + char *bp; + char *name, *np; + size_t nlen; + CHAR_T *wp; + size_t wlen; + int rc; + + INT2CHAR(sp, cmdp->argv[0]->bp, cmdp->argv[0]->len + 1, name, nlen); + if ((fd = open(name, O_RDONLY, 0)) < 0 || fstat(fd, &sb)) + goto err; + + /* + * XXX + * I'd like to test to see if the file is too large to malloc. Since + * we don't know what size or type off_t's or size_t's are, what the + * largest unsigned integral type is, or what random insanity the local + * C compiler will perpetrate, doing the comparison in a portable way + * is flatly impossible. So, put an fairly unreasonable limit on it, + * I don't want to be dropping core here. + */ +#define MEGABYTE 1048576 + if (sb.st_size > MEGABYTE) { + errno = ENOMEM; + goto err; + } + + MALLOC(sp, bp, (size_t)sb.st_size + 1); + if (bp == NULL) { + (void)close(fd); + return (1); + } + bp[sb.st_size] = '\0'; + + /* Read the file into memory. */ + len = read(fd, bp, (int)sb.st_size); + (void)close(fd); + if (len == -1 || len != sb.st_size) { + if (len != sb.st_size) + errno = EIO; + free(bp); +err: msgq_str(sp, M_SYSERR, name, "%s"); + return (1); + } + + np = strdup(name); + if (CHAR2INT(sp, bp, (size_t)sb.st_size + 1, wp, wlen)) + msgq(sp, M_ERR, "323|Invalid input. Truncated."); + /* Put it on the ex queue. */ + rc = ex_run_str(sp, np, wp, wlen - 1, 1, 0); + free(np); + free(bp); + return (rc); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_source.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_stop.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_stop.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_stop.c (revision 366308) @@ -0,0 +1,46 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "../common/common.h" + +/* + * ex_stop -- :stop[!] + * :suspend[!] + * Suspend execution. + * + * PUBLIC: int ex_stop(SCR *, EXCMD *); + */ +int +ex_stop(SCR *sp, EXCMD *cmdp) +{ + int allowed; + + /* For some strange reason, the force flag turns off autowrite. */ + if (!FL_ISSET(cmdp->iflags, E_C_FORCE) && file_aw(sp, FS_ALL)) + return (1); + + if (sp->gp->scr_suspend(sp, &allowed)) + return (1); + if (!allowed) + ex_emsg(sp, NULL, EXM_NOSUSPEND); + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_stop.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_tag.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_tag.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_tag.c (revision 366308) @@ -0,0 +1,1307 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * David Hitz of Auspex Systems, Inc. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../common/common.h" +#include "../vi/vi.h" +#include "tag.h" + +static char *binary_search(char *, char *, char *); +static int compare(char *, char *, char *); +static void ctag_file(SCR *, TAGF *, char *, char **, size_t *); +static int ctag_search(SCR *, CHAR_T *, size_t, char *); +static int ctag_sfile(SCR *, TAGF *, TAGQ *, char *); +static TAGQ *ctag_slist(SCR *, CHAR_T *); +static char *linear_search(char *, char *, char *, long); +static int tag_copy(SCR *, TAG *, TAG **); +static int tag_pop(SCR *, TAGQ *, int); +static int tagf_copy(SCR *, TAGF *, TAGF **); +static int tagf_free(SCR *, TAGF *); +static int tagq_copy(SCR *, TAGQ *, TAGQ **); + +/* + * ex_tag_first -- + * The tag code can be entered from main, e.g., "vi -t tag". + * + * PUBLIC: int ex_tag_first(SCR *, CHAR_T *); + */ +int +ex_tag_first(SCR *sp, CHAR_T *tagarg) +{ + EXCMD cmd; + + /* Build an argument for the ex :tag command. */ + ex_cinit(sp, &cmd, C_TAG, 0, OOBLNO, OOBLNO, 0); + argv_exp0(sp, &cmd, tagarg, STRLEN(tagarg)); + + /* + * XXX + * Historic vi went ahead and created a temporary file when it failed + * to find the tag. We match historic practice, but don't distinguish + * between real error and failure to find the tag. + */ + if (ex_tag_push(sp, &cmd)) + return (0); + + /* Display tags in the center of the screen. */ + F_CLR(sp, SC_SCR_TOP); + F_SET(sp, SC_SCR_CENTER); + + return (0); +} + +/* + * ex_tag_push -- ^] + * :tag[!] [string] + * + * Enter a new TAGQ context based on a ctag string. + * + * PUBLIC: int ex_tag_push(SCR *, EXCMD *); + */ +int +ex_tag_push(SCR *sp, EXCMD *cmdp) +{ + EX_PRIVATE *exp; + TAGQ *tqp; + long tl; + + exp = EXP(sp); + switch (cmdp->argc) { + case 1: + free(exp->tag_last); + + if ((exp->tag_last = v_wstrdup(sp, cmdp->argv[0]->bp, + cmdp->argv[0]->len)) == NULL) { + msgq(sp, M_SYSERR, NULL); + return (1); + } + + /* Taglength may limit the number of characters. */ + if ((tl = + O_VAL(sp, O_TAGLENGTH)) != 0 && STRLEN(exp->tag_last) > tl) + exp->tag_last[tl] = '\0'; + break; + case 0: + if (exp->tag_last == NULL) { + msgq(sp, M_ERR, "158|No previous tag entered"); + return (1); + } + break; + default: + abort(); + } + + /* Get the tag information. */ + if ((tqp = ctag_slist(sp, exp->tag_last)) == NULL) + return (1); + + if (tagq_push(sp, tqp, F_ISSET(cmdp, E_NEWSCREEN), + FL_ISSET(cmdp->iflags, E_C_FORCE))) + return 1; + + return 0; +} + +/* + * ex_tag_next -- + * Switch context to the next TAG. + * + * PUBLIC: int ex_tag_next(SCR *, EXCMD *); + */ +int +ex_tag_next(SCR *sp, EXCMD *cmdp) +{ + EX_PRIVATE *exp; + TAG *tp; + TAGQ *tqp; + char *np; + size_t nlen; + + exp = EXP(sp); + if ((tqp = TAILQ_FIRST(exp->tq)) == NULL) { + tag_msg(sp, TAG_EMPTY, NULL); + return (1); + } + if ((tp = TAILQ_NEXT(tqp->current, q)) == NULL) { + msgq(sp, M_ERR, "282|Already at the last tag of this group"); + return (1); + } + if (ex_tag_nswitch(sp, tp, FL_ISSET(cmdp->iflags, E_C_FORCE))) + return (1); + tqp->current = tp; + + if (F_ISSET(tqp, TAG_CSCOPE)) + (void)cscope_search(sp, tqp, tp); + else + (void)ctag_search(sp, tp->search, tp->slen, tqp->tag); + if (tqp->current->msg) { + INT2CHAR(sp, tqp->current->msg, tqp->current->mlen + 1, + np, nlen); + msgq(sp, M_INFO, "%s", np); + } + return (0); +} + +/* + * ex_tag_prev -- + * Switch context to the next TAG. + * + * PUBLIC: int ex_tag_prev(SCR *, EXCMD *); + */ +int +ex_tag_prev(SCR *sp, EXCMD *cmdp) +{ + EX_PRIVATE *exp; + TAG *tp; + TAGQ *tqp; + char *np; + size_t nlen; + + exp = EXP(sp); + if ((tqp = TAILQ_FIRST(exp->tq)) == NULL) { + tag_msg(sp, TAG_EMPTY, NULL); + return (0); + } + if ((tp = TAILQ_PREV(tqp->current, _tagqh, q)) == NULL) { + msgq(sp, M_ERR, "255|Already at the first tag of this group"); + return (1); + } + if (ex_tag_nswitch(sp, tp, FL_ISSET(cmdp->iflags, E_C_FORCE))) + return (1); + tqp->current = tp; + + if (F_ISSET(tqp, TAG_CSCOPE)) + (void)cscope_search(sp, tqp, tp); + else + (void)ctag_search(sp, tp->search, tp->slen, tqp->tag); + if (tqp->current->msg) { + INT2CHAR(sp, tqp->current->msg, tqp->current->mlen + 1, + np, nlen); + msgq(sp, M_INFO, "%s", np); + } + return (0); +} + +/* + * ex_tag_nswitch -- + * Switch context to the specified TAG. + * + * PUBLIC: int ex_tag_nswitch(SCR *, TAG *, int); + */ +int +ex_tag_nswitch(SCR *sp, TAG *tp, int force) +{ + /* Get a file structure. */ + if (tp->frp == NULL && (tp->frp = file_add(sp, tp->fname)) == NULL) + return (1); + + /* If not changing files, return, we're done. */ + if (tp->frp == sp->frp) + return (0); + + /* Check for permission to leave. */ + if (file_m1(sp, force, FS_ALL | FS_POSSIBLE)) + return (1); + + /* Initialize the new file. */ + if (file_init(sp, tp->frp, NULL, FS_SETALT)) + return (1); + + /* Display tags in the center of the screen. */ + F_CLR(sp, SC_SCR_TOP); + F_SET(sp, SC_SCR_CENTER); + + /* Switch. */ + F_SET(sp, SC_FSWITCH); + return (0); +} + +/* + * ex_tag_Nswitch -- + * Switch context to the specified TAG in a new screen. + * + * PUBLIC: int ex_tag_Nswitch(SCR *, TAG *, int); + */ +int +ex_tag_Nswitch(SCR *sp, TAG *tp, int force) +{ + SCR *new; + + /* Get a file structure. */ + if (tp->frp == NULL && (tp->frp = file_add(sp, tp->fname)) == NULL) + return (1); + + /* Get a new screen. */ + if (screen_init(sp->gp, sp, &new)) + return (1); + if (vs_split(sp, new, 0)) { + (void)file_end(new, new->ep, 1); + (void)screen_end(new); + return (1); + } + + /* Get a backing file. */ + if (tp->frp == sp->frp) { + /* Copy file state. */ + new->ep = sp->ep; + ++new->ep->refcnt; + + new->frp = tp->frp; + new->frp->flags = sp->frp->flags; + } else if (file_init(new, tp->frp, NULL, force)) { + (void)vs_discard(new, NULL); + (void)screen_end(new); + return (1); + } + + /* Create the argument list. */ + new->cargv = new->argv = ex_buildargv(sp, NULL, tp->frp->name); + + /* Display tags in the center of the screen. */ + F_CLR(new, SC_SCR_TOP); + F_SET(new, SC_SCR_CENTER); + + /* Switch. */ + sp->nextdisp = new; + F_SET(sp, SC_SSWITCH); + + return (0); +} + +/* + * ex_tag_pop -- ^T + * :tagp[op][!] [number | file] + * + * Pop to a previous TAGQ context. + * + * PUBLIC: int ex_tag_pop(SCR *, EXCMD *); + */ +int +ex_tag_pop(SCR *sp, EXCMD *cmdp) +{ + EX_PRIVATE *exp; + TAGQ *tqp, *dtqp; + size_t arglen; + long off; + char *arg, *p, *t; + size_t nlen; + + /* Check for an empty stack. */ + exp = EXP(sp); + if (TAILQ_EMPTY(exp->tq)) { + tag_msg(sp, TAG_EMPTY, NULL); + return (1); + } + + /* Find the last TAG structure that we're going to DISCARD! */ + switch (cmdp->argc) { + case 0: /* Pop one tag. */ + dtqp = TAILQ_FIRST(exp->tq); + break; + case 1: /* Name or number. */ + INT2CHAR(sp, cmdp->argv[0]->bp, cmdp->argv[0]->len+1, + arg, nlen); + off = strtol(arg, &p, 10); + if (*p != '\0') + goto filearg; + + /* Number: pop that many queue entries. */ + if (off < 1) + return (0); + TAILQ_FOREACH(tqp, exp->tq, q) + if (--off <= 1) break; + if (tqp == NULL) { + msgq(sp, M_ERR, + "159|Less than %s entries on the tags stack; use :display t[ags]", + arg); + return (1); + } + dtqp = tqp; + break; + + /* File argument: pop to that queue entry. */ +filearg: arglen = strlen(arg); + for (tqp = TAILQ_FIRST(exp->tq); tqp; + dtqp = tqp, tqp = TAILQ_NEXT(tqp, q)) { + /* Don't pop to the current file. */ + if (tqp == TAILQ_FIRST(exp->tq)) + continue; + p = tqp->current->frp->name; + if ((t = strrchr(p, '/')) == NULL) + t = p; + else + ++t; + if (!strncmp(arg, t, arglen)) + break; + } + if (tqp == NULL) { + msgq_str(sp, M_ERR, arg, + "160|No file %s on the tags stack to return to; use :display t[ags]"); + return (1); + } + if (tqp == TAILQ_FIRST(exp->tq)) + return (0); + break; + default: + abort(); + } + + return (tag_pop(sp, dtqp, FL_ISSET(cmdp->iflags, E_C_FORCE))); +} + +/* + * ex_tag_top -- :tagt[op][!] + * Clear the tag stack. + * + * PUBLIC: int ex_tag_top(SCR *, EXCMD *); + */ +int +ex_tag_top(SCR *sp, EXCMD *cmdp) +{ + EX_PRIVATE *exp; + + exp = EXP(sp); + + /* Check for an empty stack. */ + if (TAILQ_EMPTY(exp->tq)) { + tag_msg(sp, TAG_EMPTY, NULL); + return (1); + } + + /* Return to the oldest information. */ + return (tag_pop(sp, TAILQ_PREV(TAILQ_LAST(exp->tq, _tqh), _tqh, q), + FL_ISSET(cmdp->iflags, E_C_FORCE))); +} + +/* + * tag_pop -- + * Pop up to and including the specified TAGQ context. + */ +static int +tag_pop(SCR *sp, TAGQ *dtqp, int force) +{ + EX_PRIVATE *exp; + TAG *tp; + TAGQ *tqp; + + exp = EXP(sp); + + /* + * Update the cursor from the saved TAG information of the TAG + * structure we're moving to. + */ + tp = TAILQ_NEXT(dtqp, q)->current; + if (tp->frp == sp->frp) { + sp->lno = tp->lno; + sp->cno = tp->cno; + } else { + if (file_m1(sp, force, FS_ALL | FS_POSSIBLE)) + return (1); + + tp->frp->lno = tp->lno; + tp->frp->cno = tp->cno; + F_SET(sp->frp, FR_CURSORSET); + if (file_init(sp, tp->frp, NULL, FS_SETALT)) + return (1); + + F_SET(sp, SC_FSWITCH); + } + + /* Pop entries off the queue up to and including dtqp. */ + do { + tqp = TAILQ_FIRST(exp->tq); + if (tagq_free(sp, tqp)) + return (0); + } while (tqp != dtqp); + + /* + * If only a single tag left, we've returned to the first tag point, + * and the stack is now empty. + */ + if (TAILQ_NEXT(TAILQ_FIRST(exp->tq), q) == NULL) + tagq_free(sp, TAILQ_FIRST(exp->tq)); + + return (0); +} + +/* + * ex_tag_display -- + * Display the list of tags. + * + * PUBLIC: int ex_tag_display(SCR *); + */ +int +ex_tag_display(SCR *sp) +{ + EX_PRIVATE *exp; + TAG *tp; + TAGQ *tqp; + int cnt; + size_t len; + char *p; + + exp = EXP(sp); + if (TAILQ_EMPTY(exp->tq)) { + tag_msg(sp, TAG_EMPTY, NULL); + return (0); + } + + /* + * We give the file name 20 columns and the search string the rest. + * If there's not enough room, we don't do anything special, it's + * not worth the effort, it just makes the display more confusing. + * + * We also assume that characters in file names map 1-1 to printing + * characters. This might not be true, but I don't think it's worth + * fixing. (The obvious fix is to pass the filenames through the + * msg_print function.) + */ +#define L_NAME 30 /* Name. */ +#define L_SLOP 4 /* Leading number plus trailing *. */ +#define L_SPACE 5 /* Spaces after name, before tag. */ +#define L_TAG 20 /* Tag. */ + if (sp->cols <= L_NAME + L_SLOP) { + msgq(sp, M_ERR, "292|Display too small."); + return (0); + } + + /* + * Display the list of tags for each queue entry. The first entry + * is numbered, and the current tag entry has an asterisk appended. + */ + for (cnt = 1, tqp = TAILQ_FIRST(exp->tq); !INTERRUPTED(sp) && + tqp != NULL; ++cnt, tqp = TAILQ_NEXT(tqp, q)) + TAILQ_FOREACH(tp, tqp->tagq, q) { + if (tp == TAILQ_FIRST(tqp->tagq)) + (void)ex_printf(sp, "%2d ", cnt); + else + (void)ex_printf(sp, " "); + p = tp->frp == NULL ? tp->fname : tp->frp->name; + if ((len = strlen(p)) > L_NAME) { + len = len - (L_NAME - 4); + (void)ex_printf(sp, " ... %*.*s", + L_NAME - 4, L_NAME - 4, p + len); + } else + (void)ex_printf(sp, + " %*.*s", L_NAME, L_NAME, p); + if (tqp->current == tp) + (void)ex_printf(sp, "*"); + + if (tp == TAILQ_FIRST(tqp->tagq) && tqp->tag != NULL && + (sp->cols - L_NAME) >= L_TAG + L_SPACE) { + len = strlen(tqp->tag); + if (len > sp->cols - (L_NAME + L_SPACE)) + len = sp->cols - (L_NAME + L_SPACE); + (void)ex_printf(sp, "%s%.*s", + tqp->current == tp ? " " : " ", + (int)len, tqp->tag); + } + (void)ex_printf(sp, "\n"); + } + return (0); +} + +/* + * ex_tag_copy -- + * Copy a screen's tag structures. + * + * PUBLIC: int ex_tag_copy(SCR *, SCR *); + */ +int +ex_tag_copy(SCR *orig, SCR *sp) +{ + EX_PRIVATE *oexp, *nexp; + TAGQ *aqp, *tqp; + TAG *ap, *tp; + TAGF *atfp, *tfp; + + oexp = EXP(orig); + nexp = EXP(sp); + + /* Copy tag queue and tags stack. */ + TAILQ_FOREACH(aqp, oexp->tq, q) { + if (tagq_copy(sp, aqp, &tqp)) + return (1); + TAILQ_FOREACH(ap, aqp->tagq, q) { + if (tag_copy(sp, ap, &tp)) + return (1); + /* Set the current pointer. */ + if (aqp->current == ap) + tqp->current = tp; + TAILQ_INSERT_TAIL(tqp->tagq, tp, q); + } + TAILQ_INSERT_TAIL(nexp->tq, tqp, q); + } + + /* Copy list of tag files. */ + TAILQ_FOREACH(atfp, oexp->tagfq, q) { + if (tagf_copy(sp, atfp, &tfp)) + return (1); + TAILQ_INSERT_TAIL(nexp->tagfq, tfp, q); + } + + /* Copy the last tag. */ + if (oexp->tag_last != NULL && + (nexp->tag_last = v_wstrdup(sp, oexp->tag_last, + STRLEN(oexp->tag_last))) == NULL) { + msgq(sp, M_SYSERR, NULL); + return (1); + } + return (0); +} + +/* + * tagf_copy -- + * Copy a TAGF structure and return it in new memory. + */ +static int +tagf_copy(SCR *sp, TAGF *otfp, TAGF **tfpp) +{ + TAGF *tfp; + + MALLOC_RET(sp, tfp, sizeof(TAGF)); + *tfp = *otfp; + + /* XXX: Allocate as part of the TAGF structure!!! */ + if ((tfp->name = strdup(otfp->name)) == NULL) { + free(tfp); + return (1); + } + + *tfpp = tfp; + return (0); +} + +/* + * tagq_copy -- + * Copy a TAGQ structure and return it in new memory. + */ +static int +tagq_copy(SCR *sp, TAGQ *otqp, TAGQ **tqpp) +{ + TAGQ *tqp; + size_t len; + + len = sizeof(TAGQ); + if (otqp->tag != NULL) + len += otqp->tlen + 1; + MALLOC_RET(sp, tqp, len); + memcpy(tqp, otqp, len); + + TAILQ_INIT(tqp->tagq); + tqp->current = NULL; + if (otqp->tag != NULL) + tqp->tag = tqp->buf; + + *tqpp = tqp; + return (0); +} + +/* + * tag_copy -- + * Copy a TAG structure and return it in new memory. + */ +static int +tag_copy(SCR *sp, TAG *otp, TAG **tpp) +{ + TAG *tp; + size_t len; + + len = sizeof(TAG); + if (otp->fname != NULL) + len += otp->fnlen + 1; + if (otp->search != NULL) + len += otp->slen + 1; + if (otp->msg != NULL) + len += otp->mlen + 1; + MALLOC_RET(sp, tp, len); + memcpy(tp, otp, len); + + if (otp->fname != NULL) + tp->fname = (char *)tp->buf; + if (otp->search != NULL) + tp->search = tp->buf + (otp->search - otp->buf); + if (otp->msg != NULL) + tp->msg = tp->buf + (otp->msg - otp->buf); + + *tpp = tp; + return (0); +} + +/* + * tagf_free -- + * Free a TAGF structure. + */ +static int +tagf_free(SCR *sp, TAGF *tfp) +{ + EX_PRIVATE *exp; + + exp = EXP(sp); + TAILQ_REMOVE(exp->tagfq, tfp, q); + free(tfp->name); + free(tfp); + return (0); +} + +/* + * tagq_free -- + * Free a TAGQ structure (and associated TAG structures). + * + * PUBLIC: int tagq_free(SCR *, TAGQ *); + */ +int +tagq_free(SCR *sp, TAGQ *tqp) +{ + EX_PRIVATE *exp; + TAG *tp; + + exp = EXP(sp); + while ((tp = TAILQ_FIRST(tqp->tagq)) != NULL) { + TAILQ_REMOVE(tqp->tagq, tp, q); + free(tp); + } + /* + * !!! + * If allocated and then the user failed to switch files, the TAGQ + * structure was never attached to any list. + */ + if (TAILQ_ENTRY_ISVALID(tqp, q)) + TAILQ_REMOVE(exp->tq, tqp, q); + free(tqp); + return (0); +} + +/* + * PUBLIC: int tagq_push(SCR*, TAGQ*, int, int ); + */ +int +tagq_push(SCR *sp, TAGQ *tqp, int new_screen, int force) +{ + EX_PRIVATE *exp; + FREF *frp; + TAG *rtp; + TAGQ *rtqp; + recno_t lno; + size_t cno; + int istmp; + char *np; + size_t nlen; + + exp = EXP(sp); + + /* + * Allocate all necessary memory before swapping screens. Initialize + * flags so we know what to free. + */ + rtp = NULL; + rtqp = NULL; + if (TAILQ_EMPTY(exp->tq)) { + /* Initialize the `local context' tag queue structure. */ + CALLOC_GOTO(sp, rtqp, 1, sizeof(TAGQ)); + TAILQ_INIT(rtqp->tagq); + + /* Initialize and link in its tag structure. */ + CALLOC_GOTO(sp, rtp, 1, sizeof(TAG)); + TAILQ_INSERT_HEAD(rtqp->tagq, rtp, q); + rtqp->current = rtp; + } + + /* + * Stick the current context information in a convenient place, we're + * about to lose it. Note, if we're called on editor startup, there + * will be no FREF structure. + */ + frp = sp->frp; + lno = sp->lno; + cno = sp->cno; + istmp = frp == NULL || + (F_ISSET(frp, FR_TMPFILE) && !new_screen); + + /* Try to switch to the preset tag. */ + if (new_screen) { + if (ex_tag_Nswitch(sp, tqp->current, force)) + goto err; + + /* Everything else gets done in the new screen. */ + sp = sp->nextdisp; + exp = EXP(sp); + } else + if (ex_tag_nswitch(sp, tqp->current, force)) + goto err; + + /* + * If this is the first tag, put a `current location' queue entry + * in place, so we can pop all the way back to the current mark. + * Note, it doesn't point to much of anything, it's a placeholder. + */ + if (TAILQ_EMPTY(exp->tq)) { + TAILQ_INSERT_HEAD(exp->tq, rtqp, q); + } else + rtqp = TAILQ_FIRST(exp->tq); + + /* Link the new TAGQ structure into place. */ + TAILQ_INSERT_HEAD(exp->tq, tqp, q); + + (void)ctag_search(sp, + tqp->current->search, tqp->current->slen, tqp->tag); + if (tqp->current->msg) { + INT2CHAR(sp, tqp->current->msg, tqp->current->mlen + 1, + np, nlen); + msgq(sp, M_INFO, "%s", np); + } + + /* + * Move the current context from the temporary save area into the + * right structure. + * + * If we were in a temporary file, we don't have a context to which + * we can return, so just make it be the same as what we're moving + * to. It will be a little odd that ^T doesn't change anything, but + * I don't think it's a big deal. + */ + if (istmp) { + rtqp->current->frp = sp->frp; + rtqp->current->lno = sp->lno; + rtqp->current->cno = sp->cno; + } else { + rtqp->current->frp = frp; + rtqp->current->lno = lno; + rtqp->current->cno = cno; + } + return (0); + +err: +alloc_err: + free(rtqp); + free(rtp); + tagq_free(sp, tqp); + return (1); +} + +/* + * tag_msg + * A few common messages. + * + * PUBLIC: void tag_msg(SCR *, tagmsg_t, char *); + */ +void +tag_msg(SCR *sp, tagmsg_t msg, char *tag) +{ + switch (msg) { + case TAG_BADLNO: + msgq_str(sp, M_ERR, tag, + "164|%s: the tag's line number is past the end of the file"); + break; + case TAG_EMPTY: + msgq(sp, M_INFO, "165|The tags stack is empty"); + break; + case TAG_SEARCH: + msgq_str(sp, M_ERR, tag, "166|%s: search pattern not found"); + break; + default: + abort(); + } +} + +/* + * ex_tagf_alloc -- + * Create a new list of ctag files. + * + * PUBLIC: int ex_tagf_alloc(SCR *, char *); + */ +int +ex_tagf_alloc(SCR *sp, char *str) +{ + EX_PRIVATE *exp; + TAGF *tfp; + size_t len; + char *p, *t; + + /* Free current queue. */ + exp = EXP(sp); + while ((tfp = TAILQ_FIRST(exp->tagfq)) != NULL) + tagf_free(sp, tfp); + + /* Create new queue. */ + for (p = t = str;; ++p) { + if (*p == '\0' || cmdskip(*p)) { + if ((len = p - t)) { + MALLOC_RET(sp, tfp, sizeof(TAGF)); + MALLOC(sp, tfp->name, len + 1); + if (tfp->name == NULL) { + free(tfp); + return (1); + } + memcpy(tfp->name, t, len); + tfp->name[len] = '\0'; + tfp->flags = 0; + TAILQ_INSERT_TAIL(exp->tagfq, tfp, q); + } + t = p + 1; + } + if (*p == '\0') + break; + } + return (0); +} + /* Free previous queue. */ +/* + * ex_tag_free -- + * Free the ex tag information. + * + * PUBLIC: int ex_tag_free(SCR *); + */ +int +ex_tag_free(SCR *sp) +{ + EX_PRIVATE *exp; + TAGF *tfp; + TAGQ *tqp; + + /* Free up tag information. */ + exp = EXP(sp); + while ((tqp = TAILQ_FIRST(exp->tq)) != NULL) + tagq_free(sp, tqp); + while ((tfp = TAILQ_FIRST(exp->tagfq)) != NULL) + tagf_free(sp, tfp); + free(exp->tag_last); + return (0); +} + +/* + * ctag_search -- + * Search a file for a tag. + */ +static int +ctag_search(SCR *sp, CHAR_T *search, size_t slen, char *tag) +{ + MARK m; + char *p; + char *np; + size_t nlen; + + /* + * !!! + * The historic tags file format (from a long, long time ago...) + * used a line number, not a search string. I got complaints, so + * people are still using the format. POSIX 1003.2 permits it. + */ + if (ISDIGIT(search[0])) { + INT2CHAR(sp, search, slen+1, np, nlen); + m.lno = atoi(np); + if (!db_exist(sp, m.lno)) { + tag_msg(sp, TAG_BADLNO, tag); + return (1); + } + } else { + /* + * Search for the tag; cheap fallback for C functions + * if the name is the same but the arguments have changed. + */ + m.lno = 1; + m.cno = 0; + if (f_search(sp, &m, &m, + search, slen, NULL, SEARCH_FILE | SEARCH_TAG)) { + INT2CHAR(sp, search, slen, np, nlen); + if ((p = strrchr(np, '(')) != NULL) { + slen = p - np; + if (f_search(sp, &m, &m, search, slen, + NULL, SEARCH_FILE | SEARCH_TAG)) + goto notfound; + } else { +notfound: tag_msg(sp, TAG_SEARCH, tag); + return (1); + } + } + /* + * !!! + * Historically, tags set the search direction if it wasn't + * already set. + */ + if (sp->searchdir == NOTSET) + sp->searchdir = FORWARD; + } + + /* + * !!! + * Tags move to the first non-blank, NOT the search pattern start. + */ + sp->lno = m.lno; + sp->cno = 0; + (void)nonblank(sp, sp->lno, &sp->cno); + return (0); +} + +/* + * ctag_slist -- + * Search the list of tags files for a tag, and return tag queue. + */ +static TAGQ * +ctag_slist(SCR *sp, CHAR_T *tag) +{ + EX_PRIVATE *exp; + TAGF *tfp; + TAGQ *tqp; + size_t len; + int echk = 0; + char *np; + size_t nlen; + + exp = EXP(sp); + + /* Allocate and initialize the tag queue structure. */ + INT2CHAR(sp, tag, STRLEN(tag) + 1, np, nlen); + len = nlen - 1; + CALLOC_GOTO(sp, tqp, 1, sizeof(TAGQ) + len + 1); + TAILQ_INIT(tqp->tagq); + tqp->tag = tqp->buf; + memcpy(tqp->tag, np, (tqp->tlen = len) + 1); + + /* + * Find the tag, only display missing file messages once, and + * then only if we didn't find the tag. + */ + TAILQ_FOREACH(tfp, exp->tagfq, q) + if (ctag_sfile(sp, tfp, tqp, tqp->tag)) { + echk = 1; + F_SET(tfp, TAGF_ERR); + } else + F_CLR(tfp, TAGF_ERR | TAGF_ERR_WARN); + + /* Check to see if we found anything. */ + if (TAILQ_EMPTY(tqp->tagq)) { + msgq_str(sp, M_ERR, tqp->tag, "162|%s: tag not found"); + if (echk) + TAILQ_FOREACH(tfp, exp->tagfq, q) + if (F_ISSET(tfp, TAGF_ERR) && + !F_ISSET(tfp, TAGF_ERR_WARN)) { + errno = tfp->errnum; + msgq_str(sp, M_SYSERR, tfp->name, "%s"); + F_SET(tfp, TAGF_ERR_WARN); + } + free(tqp); + return (NULL); + } + + return (tqp); + +alloc_err: + return (NULL); +} + +/* + * ctag_sfile -- + * Search a tags file for a tag, adding any found to the tag queue. + */ +static int +ctag_sfile(SCR *sp, TAGF *tfp, TAGQ *tqp, char *tname) +{ + struct stat sb; + TAG *tp; + size_t dlen, nlen = 0, slen; + int fd, i, nf1, nf2; + char *back, *front, *map, *p, *search, *t; + char *cname = NULL, *dname = NULL, *name = NULL; + CHAR_T *wp; + size_t wlen; + long tl; + + if ((fd = open(tfp->name, O_RDONLY, 0)) < 0) { + tfp->errnum = errno; + return (1); + } + + if (fstat(fd, &sb) != 0 || + (map = mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE, fd, 0)) == MAP_FAILED) { + tfp->errnum = errno; + (void)close(fd); + return (1); + } + + tl = O_VAL(sp, O_TAGLENGTH); + front = map; + back = front + sb.st_size; + front = binary_search(tname, front, back); + front = linear_search(tname, front, back, tl); + if (front == NULL) + goto done; + + /* + * Initialize and link in the tag structure(s). The historic ctags + * file format only permitted a single tag location per tag. The + * obvious extension to permit multiple tags locations per tag is to + * output multiple records in the standard format. Unfortunately, + * this won't work correctly with historic ex/vi implementations, + * because their binary search assumes that there's only one record + * per tag, and so will use a random tag entry if there si more than + * one. This code handles either format. + * + * The tags file is in the following format: + * + * | + * + * Figure out how long everything is so we can allocate in one swell + * foop, but discard anything that looks wrong. + */ + for (;;) { + /* Nul-terminate the end of the line. */ + for (p = front; p < back && *p != '\n'; ++p); + if (p == back || *p != '\n') + break; + *p = '\0'; + + /* Update the pointers for the next time. */ + t = p + 1; + p = front; + front = t; + + /* Break the line into tokens. */ + for (i = 0; i < 2 && (t = strsep(&p, "\t ")) != NULL; ++i) + switch (i) { + case 0: /* Tag. */ + cname = t; + break; + case 1: /* Filename. */ + name = t; + nlen = strlen(name); + break; + } + + /* Check for corruption. */ + if (i != 2 || p == NULL || t == NULL) + goto corrupt; + + /* The rest of the string is the search pattern. */ + search = p; + if ((slen = strlen(p)) == 0) { +corrupt: p = msg_print(sp, tname, &nf1); + t = msg_print(sp, tfp->name, &nf2); + msgq(sp, M_ERR, "163|%s: corrupted tag in %s", p, t); + if (nf1) + FREE_SPACE(sp, p, 0); + if (nf2) + FREE_SPACE(sp, t, 0); + continue; + } + + /* Check for passing the last entry. */ + if (tl ? strncmp(tname, cname, tl) : strcmp(tname, cname)) + break; + + /* Resolve the file name. */ + ctag_file(sp, tfp, name, &dname, &dlen); + + CALLOC_GOTO(sp, tp, 1, + sizeof(TAG) + dlen + 2 + nlen + 1 + (slen + 1) * sizeof(CHAR_T)); + tp->fname = (char *)tp->buf; + if (dlen == 1 && *dname == '.') + --dlen; + else if (dlen != 0) { + memcpy(tp->fname, dname, dlen); + tp->fname[dlen] = '/'; + ++dlen; + } + memcpy(tp->fname + dlen, name, nlen + 1); + tp->fnlen = dlen + nlen; + tp->search = (CHAR_T*)(tp->fname + tp->fnlen + 1); + CHAR2INT(sp, search, slen + 1, wp, wlen); + MEMCPY(tp->search, wp, (tp->slen = slen) + 1); + TAILQ_INSERT_TAIL(tqp->tagq, tp, q); + + /* Try to preset the tag within the current file. */ + if (sp->frp != NULL && sp->frp->name != NULL && + tqp->current == NULL && !strcmp(tp->fname, sp->frp->name)) + tqp->current = tp; + } + + if (tqp->current == NULL) + tqp->current = TAILQ_FIRST(tqp->tagq); + +alloc_err: +done: if (munmap(map, sb.st_size)) + msgq(sp, M_SYSERR, "munmap"); + if (close(fd)) + msgq(sp, M_SYSERR, "close"); + return (0); +} + +/* + * ctag_file -- + * Search for the right path to this file. + */ +static void +ctag_file(SCR *sp, TAGF *tfp, char *name, char **dirp, size_t *dlenp) +{ + struct stat sb; + char *p, *buf; + + /* + * !!! + * If the tag file path is a relative path, see if it exists. If it + * doesn't, look relative to the tags file path. It's okay for a tag + * file to not exist, and historically, vi simply displayed a "new" + * file. However, if the path exists relative to the tag file, it's + * pretty clear what's happening, so we may as well get it right. + */ + *dlenp = 0; + if (name[0] != '/' && + stat(name, &sb) && (p = strrchr(tfp->name, '/')) != NULL) { + *p = '\0'; + if ((buf = join(tfp->name, name)) == NULL) { + msgq(sp, M_SYSERR, NULL); + return; + } + if (stat(buf, &sb) == 0) { + *dirp = tfp->name; + *dlenp = strlen(*dirp); + } + free(buf); + *p = '/'; + } +} + +/* + * Binary search for "string" in memory between "front" and "back". + * + * This routine is expected to return a pointer to the start of a line at + * *or before* the first word matching "string". Relaxing the constraint + * this way simplifies the algorithm. + * + * Invariants: + * front points to the beginning of a line at or before the first + * matching string. + * + * back points to the beginning of a line at or after the first + * matching line. + * + * Base of the Invariants. + * front = NULL; + * back = EOF; + * + * Advancing the Invariants: + * + * p = first newline after halfway point from front to back. + * + * If the string at "p" is not greater than the string to match, + * p is the new front. Otherwise it is the new back. + * + * Termination: + * + * The definition of the routine allows it return at any point, + * since front is always at or before the line to print. + * + * In fact, it returns when the chosen "p" equals "back". This + * implies that there exists a string is least half as long as + * (back - front), which in turn implies that a linear search will + * be no more expensive than the cost of simply printing a string or two. + * + * Trying to continue with binary search at this point would be + * more trouble than it's worth. + */ +#define EQUAL 0 +#define GREATER 1 +#define LESS (-1) + +#define SKIP_PAST_NEWLINE(p, back) \ + while (p < back && *p++ != '\n') continue; + +static char * +binary_search(char *string, char *front, char *back) +{ + char *p; + + p = front + (back - front) / 2; + SKIP_PAST_NEWLINE(p, back); + + while (p != back) { + if (compare(string, p, back) == GREATER) + front = p; + else + back = p; + p = front + (back - front) / 2; + SKIP_PAST_NEWLINE(p, back); + } + return (front); +} + +/* + * Find the first line that starts with string, linearly searching from front + * to back. + * + * Return NULL for no such line. + * + * This routine assumes: + * + * o front points at the first character in a line. + * o front is before or at the first line to be printed. + */ +static char * +linear_search(char *string, char *front, char *back, long tl) +{ + char *end; + while (front < back) { + end = tl && back-front > tl ? front+tl : back; + switch (compare(string, front, end)) { + case EQUAL: /* Found it. */ + return (front); + case LESS: /* No such string. */ + return (NULL); + case GREATER: /* Keep going. */ + break; + } + SKIP_PAST_NEWLINE(front, back); + } + return (NULL); +} + +/* + * Return LESS, GREATER, or EQUAL depending on how the string1 compares + * with string2 (s1 ??? s2). + * + * o Matches up to len(s1) are EQUAL. + * o Matches up to len(s2) are GREATER. + * + * The string "s1" is null terminated. The string s2 is '\t', space, (or + * "back") terminated. + * + * !!! + * Reasonably modern ctags programs use tabs as separators, not spaces. + * However, historic programs did use spaces, and, I got complaints. + */ +static int +compare(char *s1, char *s2, char *back) +{ + for (; *s1 && s2 < back && (*s2 != '\t' && *s2 != ' '); ++s1, ++s2) + if (*s1 != *s2) + return (*s1 < *s2 ? LESS : GREATER); + return (*s1 ? GREATER : s2 < back && + (*s2 != '\t' && *s2 != ' ') ? LESS : EQUAL); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_tag.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_txt.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_txt.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_txt.c (revision 366308) @@ -0,0 +1,425 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "../common/common.h" +#include "../vi/vi.h" + +/* + * !!! + * The backslash characters was special when it preceded a newline as part of + * a substitution replacement pattern. For example, the input ":a\" would + * failed immediately with an error, as the wasn't part of a substitution + * replacement pattern. This implies a frightening integration of the editor + * and the parser and/or the RE engine. There's no way I'm going to reproduce + * those semantics. + * + * So, if backslashes are special, this code inserts the backslash and the next + * character into the string, without regard for the character or the command + * being entered. Since "\" was illegal historically (except for the one + * special case), and the command will fail eventually, no historical scripts + * should break (presuming they didn't depend on the failure mode itself or the + * characters remaining when failure occurred. + */ + +static int txt_dent(SCR *, TEXT *); +static void txt_prompt(SCR *, TEXT *, ARG_CHAR_T, u_int32_t); + +/* + * ex_txt -- + * Get lines from the terminal for ex. + * + * PUBLIC: int ex_txt(SCR *, TEXTH *, ARG_CHAR_T, u_int32_t); + */ +int +ex_txt(SCR *sp, TEXTH *tiqh, ARG_CHAR_T prompt, u_int32_t flags) +{ + EVENT ev; + GS *gp; + TEXT ait, *ntp, *tp; + carat_t carat_st; + size_t cnt; + int rval; + int nochange; + + rval = 0; + + /* + * Get a TEXT structure with some initial buffer space, reusing the + * last one if it's big enough. (All TEXT bookkeeping fields default + * to 0 -- text_init() handles this.) + */ + if (!TAILQ_EMPTY(tiqh)) { + tp = TAILQ_FIRST(tiqh); + if (TAILQ_NEXT(tp, q) != NULL || tp->lb_len < 32) { + text_lfree(tiqh); + goto newtp; + } + tp->len = 0; + } else { +newtp: if ((tp = text_init(sp, NULL, 0, 32)) == NULL) + goto err; + TAILQ_INSERT_HEAD(tiqh, tp, q); + } + + /* Set the starting line number. */ + tp->lno = sp->lno + 1; + + /* + * If it's a terminal, set up autoindent, put out the prompt, and + * set it up so we know we were suspended. Otherwise, turn off + * the autoindent flag, as that requires less special casing below. + * + * XXX + * Historic practice is that ^Z suspended command mode (but, because + * it ran in cooked mode, it was unaffected by the autowrite option.) + * On restart, any "current" input was discarded, whether in insert + * mode or not, and ex was in command mode. This code matches historic + * practice, but not 'cause it's easier. + */ + gp = sp->gp; + if (F_ISSET(gp, G_SCRIPTED)) + LF_CLR(TXT_AUTOINDENT); + else { + if (LF_ISSET(TXT_AUTOINDENT)) { + LF_SET(TXT_EOFCHAR); + if (v_txt_auto(sp, sp->lno, NULL, 0, tp)) + goto err; + } + txt_prompt(sp, tp, prompt, flags); + } + + for (carat_st = C_NOTSET, nochange = 0;;) { + if (v_event_get(sp, &ev, 0, 0)) + goto err; + + /* Deal with all non-character events. */ + switch (ev.e_event) { + case E_CHARACTER: + break; + case E_ERR: + goto err; + case E_REPAINT: + case E_WRESIZE: + continue; + case E_EOF: + rval = 1; + /* FALLTHROUGH */ + case E_INTERRUPT: + /* + * Handle EOF/SIGINT events by discarding partially + * entered text and returning. EOF returns failure, + * E_INTERRUPT returns success. + */ + goto notlast; + default: + v_event_err(sp, &ev); + goto notlast; + } + + /* + * Deal with character events. + * + * Check to see if the character fits into the input buffer. + * (Use tp->len, ignore overwrite and non-printable chars.) + */ + BINC_GOTOW(sp, tp->lb, tp->lb_len, tp->len + 1); + + switch (ev.e_value) { + case K_CR: + /* + * !!! + * Historically, 's in the command + * weren't special, so the ex parser would return an + * unknown command error message. However, if they + * terminated the command if they were in a map. I'm + * pretty sure this still isn't right, but it handles + * what I've seen so far. + */ + if (!F_ISSET(&ev.e_ch, CH_MAPPED)) + goto ins_ch; + /* FALLTHROUGH */ + case K_NL: + /* + * '\' can escape /. We + * don't discard the backslash because we need it + * to get the through the ex parser. + */ + if (LF_ISSET(TXT_BACKSLASH) && + tp->len != 0 && tp->lb[tp->len - 1] == '\\') + goto ins_ch; + + /* + * CR returns from the ex command line. + * + * XXX + * Terminate with a nul, needed by filter. + */ + if (LF_ISSET(TXT_CR)) { + tp->lb[tp->len] = '\0'; + goto done; + } + + /* + * '.' may terminate text input mode; free the current + * TEXT. + */ + if (LF_ISSET(TXT_DOTTERM) && tp->len == tp->ai + 1 && + tp->lb[tp->len - 1] == '.') { +notlast: TAILQ_REMOVE(tiqh, tp, q); + text_free(tp); + goto done; + } + + /* Set up bookkeeping for the new line. */ + if ((ntp = text_init(sp, NULL, 0, 32)) == NULL) + goto err; + ntp->lno = tp->lno + 1; + + /* + * Reset the autoindent line value. 0^D keeps the ai + * line from changing, ^D changes the level, even if + * there were no characters in the old line. Note, if + * using the current tp structure, use the cursor as + * the length, the autoindent characters may have been + * erased. + */ + if (LF_ISSET(TXT_AUTOINDENT)) { + if (nochange) { + nochange = 0; + if (v_txt_auto(sp, + OOBLNO, &ait, ait.ai, ntp)) + goto err; + free(ait.lb); + } else + if (v_txt_auto(sp, + OOBLNO, tp, tp->len, ntp)) + goto err; + carat_st = C_NOTSET; + } + txt_prompt(sp, ntp, prompt, flags); + + /* + * Swap old and new TEXT's, and insert the new TEXT + * into the queue. + */ + tp = ntp; + TAILQ_INSERT_TAIL(tiqh, tp, q); + break; + case K_CARAT: /* Delete autoindent chars. */ + if (tp->len <= tp->ai && LF_ISSET(TXT_AUTOINDENT)) + carat_st = C_CARATSET; + goto ins_ch; + case K_ZERO: /* Delete autoindent chars. */ + if (tp->len <= tp->ai && LF_ISSET(TXT_AUTOINDENT)) + carat_st = C_ZEROSET; + goto ins_ch; + case K_CNTRLD: /* Delete autoindent char. */ + /* + * !!! + * Historically, the ^D command took (but then ignored) + * a count. For simplicity, we don't return it unless + * it's the first character entered. The check for len + * equal to 0 is okay, TXT_AUTOINDENT won't be set. + */ + if (LF_ISSET(TXT_CNTRLD)) { + for (cnt = 0; cnt < tp->len; ++cnt) + if (!isblank(tp->lb[cnt])) + break; + if (cnt == tp->len) { + tp->len = 1; + tp->lb[0] = ev.e_c; + tp->lb[1] = '\0'; + + /* + * Put out a line separator, in case + * the command fails. + */ + (void)putchar('\n'); + goto done; + } + } + + /* + * POSIX 1003.1b-1993, paragraph 7.1.1.9, states that + * the EOF characters are discarded if there are other + * characters to process in the line, i.e. if the EOF + * is not the first character in the line. For this + * reason, historic ex discarded the EOF characters, + * even if occurring in the middle of the input line. + * We match that historic practice. + * + * !!! + * The test for discarding in the middle of the line is + * done in the switch, because the CARAT forms are N+1, + * not N. + * + * !!! + * There's considerable magic to make the terminal code + * return the EOF character at all. See that code for + * details. + */ + if (!LF_ISSET(TXT_AUTOINDENT) || tp->len == 0) + continue; + switch (carat_st) { + case C_CARATSET: /* ^^D */ + if (tp->len > tp->ai + 1) + continue; + + /* Save the ai string for later. */ + ait.lb = NULL; + ait.lb_len = 0; + BINC_GOTOW(sp, ait.lb, ait.lb_len, tp->ai); + MEMCPY(ait.lb, tp->lb, tp->ai); + ait.ai = ait.len = tp->ai; + + carat_st = C_NOTSET; + nochange = 1; + goto leftmargin; + case C_ZEROSET: /* 0^D */ + if (tp->len > tp->ai + 1) + continue; + + carat_st = C_NOTSET; +leftmargin: (void)gp->scr_ex_adjust(sp, EX_TERM_CE); + tp->ai = tp->len = 0; + break; + case C_NOTSET: /* ^D */ + if (tp->len > tp->ai) + continue; + + if (txt_dent(sp, tp)) + goto err; + break; + default: + abort(); + } + + /* Clear and redisplay the line. */ + (void)gp->scr_ex_adjust(sp, EX_TERM_CE); + txt_prompt(sp, tp, prompt, flags); + break; + default: + /* + * See the TXT_BEAUTIFY comment in vi/v_txt_ev.c. + * + * Silently eliminate any iscntrl() character that was + * not already handled specially, except for and + * . + */ +ins_ch: if (LF_ISSET(TXT_BEAUTIFY) && ISCNTRL(ev.e_c) && + ev.e_value != K_FORMFEED && ev.e_value != K_TAB) + break; + + tp->lb[tp->len++] = ev.e_c; + break; + } + } + /* NOTREACHED */ + +done: return (rval); + +err: +alloc_err: + return (1); +} + +/* + * txt_prompt -- + * Display the ex prompt, line number, ai characters. Characters had + * better be printable by the terminal driver, but that's its problem, + * not ours. + */ +static void +txt_prompt(SCR *sp, TEXT *tp, ARG_CHAR_T prompt, u_int32_t flags) +{ + /* Display the prompt. */ + if (LF_ISSET(TXT_PROMPT)) + (void)ex_printf(sp, "%c", prompt); + + /* Display the line number. */ + if (LF_ISSET(TXT_NUMBER) && O_ISSET(sp, O_NUMBER)) + (void)ex_printf(sp, "%6lu ", (u_long)tp->lno); + + /* Print out autoindent string. */ + if (LF_ISSET(TXT_AUTOINDENT)) + (void)ex_printf(sp, WVS, (int)tp->ai, tp->lb); + (void)ex_fflush(sp); +} + +/* + * txt_dent -- + * Handle ^D outdents. + * + * Ex version of vi/v_ntext.c:txt_dent(). See that code for the (usual) + * ranting and raving. This is a fair bit simpler as ^T isn't special. + */ +static int +txt_dent(SCR *sp, TEXT *tp) +{ + u_long sw, ts; + size_t cno, off, scno, spaces, tabs; + + ts = O_VAL(sp, O_TABSTOP); + sw = O_VAL(sp, O_SHIFTWIDTH); + + /* Get the current screen column. */ + for (off = scno = 0; off < tp->len; ++off) + if (tp->lb[off] == '\t') + scno += COL_OFF(scno, ts); + else + ++scno; + + /* Get the previous shiftwidth column. */ + cno = scno--; + scno -= scno % sw; + + /* + * Since we don't know what comes before the character(s) being + * deleted, we have to resolve the autoindent characters . The + * example is a , which doesn't take up a full shiftwidth + * number of columns because it's preceded by s. This is + * easy to get if the user sets shiftwidth to a value less than + * tabstop, and then uses ^T to indent, and ^D to outdent. + * + * Count up spaces/tabs needed to get to the target. + */ + cno = 0; + tabs = 0; + if (!O_ISSET(sp, O_EXPANDTAB)) { + for (; cno + COL_OFF(cno, ts) <= scno; ++tabs) + cno += COL_OFF(cno, ts); + } + spaces = scno - cno; + + /* Make sure there's enough room. */ + BINC_RETW(sp, tp->lb, tp->lb_len, tabs + spaces + 1); + + /* Adjust the final ai character count. */ + tp->ai = tabs + spaces; + + /* Enter the replacement characters. */ + for (tp->len = 0; tabs > 0; --tabs) + tp->lb[tp->len++] = '\t'; + for (; spaces > 0; --spaces) + tp->lb[tp->len++] = ' '; + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_txt.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_undo.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_undo.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_undo.c (revision 366308) @@ -0,0 +1,72 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include + +#include "../common/common.h" + +/* + * ex_undo -- u + * Undo the last change. + * + * PUBLIC: int ex_undo(SCR *, EXCMD *); + */ +int +ex_undo(SCR *sp, EXCMD *cmdp) +{ + EXF *ep; + MARK m; + + /* + * !!! + * Historic undo always set the previous context mark. + */ + m.lno = sp->lno; + m.cno = sp->cno; + if (mark_set(sp, ABSMARK1, &m, 1)) + return (1); + + /* + * !!! + * Multiple undo isn't available in ex, as there's no '.' command. + * Whether 'u' is undo or redo is toggled each time, unless there + * was a change since the last undo, in which case it's an undo. + */ + ep = sp->ep; + if (!F_ISSET(ep, F_UNDO)) { + F_SET(ep, F_UNDO); + ep->lundo = FORWARD; + } + switch (ep->lundo) { + case BACKWARD: + if (log_forward(sp, &m)) + return (1); + ep->lundo = FORWARD; + break; + case FORWARD: + if (log_backward(sp, &m)) + return (1); + ep->lundo = BACKWARD; + break; + case NOTSET: + abort(); + } + sp->lno = m.lno; + sp->cno = m.cno; + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_undo.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_usage.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_usage.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_usage.c (revision 366308) @@ -0,0 +1,187 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "../common/common.h" +#include "../vi/vi.h" + +/* + * ex_help -- :help + * Display help message. + * + * PUBLIC: int ex_help(SCR *, EXCMD *); + */ +int +ex_help(SCR *sp, EXCMD *cmdp) +{ + (void)ex_puts(sp, + "To see the list of vi commands, enter \":viusage\"\n"); + (void)ex_puts(sp, + "To see the list of ex commands, enter \":exusage\"\n"); + (void)ex_puts(sp, + "For an ex command usage statement enter \":exusage [cmd]\"\n"); + (void)ex_puts(sp, + "For a vi key usage statement enter \":viusage [key]\"\n"); + (void)ex_puts(sp, "To exit, enter \":q!\"\n"); + return (0); +} + +/* + * ex_usage -- :exusage [cmd] + * Display ex usage strings. + * + * PUBLIC: int ex_usage(SCR *, EXCMD *); + */ +int +ex_usage(SCR *sp, EXCMD *cmdp) +{ + ARGS *ap; + EXCMDLIST const *cp; + int newscreen; + CHAR_T *name, *p, nb[MAXCMDNAMELEN + 5]; + + switch (cmdp->argc) { + case 1: + ap = cmdp->argv[0]; + if (ISUPPER(ap->bp[0])) { + newscreen = 1; + ap->bp[0] = TOLOWER(ap->bp[0]); + } else + newscreen = 0; + for (cp = cmds; cp->name != NULL && + MEMCMP(ap->bp, cp->name, ap->len); ++cp); + if (cp->name == NULL || + (newscreen && !F_ISSET(cp, E_NEWSCREEN))) { + if (newscreen) + ap->bp[0] = TOUPPER(ap->bp[0]); + (void)ex_printf(sp, "The "WVS" command is unknown\n", + (int)ap->len, ap->bp); + } else { + (void)ex_printf(sp, + "Command: %s\n Usage: %s\n", cp->help, cp->usage); + /* + * !!! + * The "visual" command has two modes, one from ex, + * one from the vi colon line. Don't ask. + */ + if (cp != &cmds[C_VISUAL_EX] && + cp != &cmds[C_VISUAL_VI]) + break; + if (cp == &cmds[C_VISUAL_EX]) + cp = &cmds[C_VISUAL_VI]; + else + cp = &cmds[C_VISUAL_EX]; + (void)ex_printf(sp, + "Command: %s\n Usage: %s\n", cp->help, cp->usage); + } + break; + case 0: + for (cp = cmds; cp->name != NULL && !INTERRUPTED(sp); ++cp) { + /* + * The ^D command has an unprintable name. + * + * XXX + * We display both capital and lower-case versions of + * the appropriate commands -- no need to add in extra + * room, they're all short names. + */ + if (cp == &cmds[C_SCROLL]) + name = L("^D"); + else if (F_ISSET(cp, E_NEWSCREEN)) { + nb[0] = '['; + nb[1] = TOUPPER(cp->name[0]); + nb[2] = cp->name[0]; + nb[3] = ']'; + for (name = cp->name + 1, + p = nb + 4; (*p++ = *name++) != '\0';); + name = nb; + } else + name = cp->name; + (void)ex_printf(sp, + WVS": %s\n", MAXCMDNAMELEN, name, cp->help); + } + break; + default: + abort(); + } + return (0); +} + +/* + * ex_viusage -- :viusage [key] + * Display vi usage strings. + * + * PUBLIC: int ex_viusage(SCR *, EXCMD *); + */ +int +ex_viusage(SCR *sp, EXCMD *cmdp) +{ + GS *gp; + VIKEYS const *kp; + int key; + + gp = sp->gp; + switch (cmdp->argc) { + case 1: + if (cmdp->argv[0]->len != 1) { + ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE); + return (1); + } + key = cmdp->argv[0]->bp[0]; + if (key > MAXVIKEY) + goto nokey; + + /* Special case: '[' and ']' commands. */ + if ((key == '[' || key == ']') && cmdp->argv[0]->bp[1] != key) + goto nokey; + + /* Special case: ~ command. */ + if (key == '~' && O_ISSET(sp, O_TILDEOP)) + kp = &tmotion; + else + kp = &vikeys[key]; + + if (kp->usage == NULL) +nokey: (void)ex_printf(sp, + "The %s key has no current meaning\n", + KEY_NAME(sp, key)); + else + (void)ex_printf(sp, + " Key:%s%s\nUsage: %s\n", + isblank((u_char)*kp->help) ? "" : " ", + kp->help, kp->usage); + break; + case 0: + for (key = 0; key <= MAXVIKEY && !INTERRUPTED(sp); ++key) { + /* Special case: ~ command. */ + if (key == '~' && O_ISSET(sp, O_TILDEOP)) + kp = &tmotion; + else + kp = &vikeys[key]; + if (kp->help != NULL) + (void)ex_printf(sp, "%s\n", kp->help); + } + break; + default: + abort(); + } + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_usage.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_util.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_util.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_util.c (revision 366308) @@ -0,0 +1,212 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "../common/common.h" + +/* + * ex_cinit -- + * Create an EX command structure. + * + * PUBLIC: void ex_cinit(SCR *, EXCMD *, int, int, recno_t, recno_t, int); + */ +void +ex_cinit(SCR *sp, EXCMD *cmdp, int cmd_id, int naddr, recno_t lno1, recno_t lno2, int force) +{ + memset(cmdp, 0, sizeof(EXCMD)); + cmdp->cmd = &cmds[cmd_id]; + cmdp->addrcnt = naddr; + cmdp->addr1.lno = lno1; + cmdp->addr2.lno = lno2; + cmdp->addr1.cno = cmdp->addr2.cno = 1; + if (force) + cmdp->iflags |= E_C_FORCE; + (void)argv_init(sp, cmdp); +} + +/* + * ex_getline -- + * Return a line from the file. + * + * PUBLIC: int ex_getline(SCR *, FILE *, size_t *); + */ +int +ex_getline(SCR *sp, FILE *fp, size_t *lenp) +{ + EX_PRIVATE *exp; + size_t off; + int ch; + char *p; + + exp = EXP(sp); + for (errno = 0, off = 0, p = exp->ibp;;) { + if (off >= exp->ibp_len) { + BINC_RETC(sp, exp->ibp, exp->ibp_len, off + 1); + p = exp->ibp + off; + } + if ((ch = getc(fp)) == EOF && !feof(fp)) { + if (errno == EINTR) { + errno = 0; + clearerr(fp); + continue; + } + return (1); + } + if (ch == EOF || ch == '\n') { + if (ch == EOF && !off) + return (1); + *lenp = off; + return (0); + } + *p++ = ch; + ++off; + } + /* NOTREACHED */ +} + +/* + * ex_ncheck -- + * Check for more files to edit. + * + * PUBLIC: int ex_ncheck(SCR *, int); + */ +int +ex_ncheck(SCR *sp, int force) +{ + char **ap; + + /* + * !!! + * Historic practice: quit! or two quit's done in succession + * (where ZZ counts as a quit) didn't check for other files. + */ + if (!force && sp->ccnt != sp->q_ccnt + 1 && + sp->cargv != NULL && sp->cargv[1] != NULL) { + sp->q_ccnt = sp->ccnt; + + for (ap = sp->cargv + 1; *ap != NULL; ++ap); + msgq(sp, M_ERR, + "167|%d more files to edit", (int)(ap - sp->cargv) - 1); + + return (1); + } + return (0); +} + +/* + * ex_init -- + * Init the screen for ex. + * + * PUBLIC: int ex_init(SCR *); + */ +int +ex_init(SCR *sp) +{ + GS *gp; + + gp = sp->gp; + + if (gp->scr_screen(sp, SC_EX)) + return (1); + (void)gp->scr_attr(sp, SA_ALTERNATE, 0); + + sp->rows = O_VAL(sp, O_LINES); + sp->cols = O_VAL(sp, O_COLUMNS); + + F_CLR(sp, SC_VI); + F_SET(sp, SC_EX | SC_SCR_EX); + return (0); +} + +/* + * ex_emsg -- + * Display a few common ex and vi error messages. + * + * PUBLIC: void ex_wemsg(SCR *, CHAR_T *, exm_t); + */ +void +ex_wemsg(SCR* sp, CHAR_T *p, exm_t which) +{ + char *np; + size_t nlen; + + if (p) INT2CHAR(sp, p, STRLEN(p), np, nlen); + else np = NULL; + ex_emsg(sp, np, which); +} + +/* + * ex_emsg -- + * Display a few common ex and vi error messages. + * + * PUBLIC: void ex_emsg(SCR *, char *, exm_t); + */ +void +ex_emsg(SCR *sp, char *p, exm_t which) +{ + switch (which) { + case EXM_EMPTYBUF: + msgq(sp, M_ERR, "168|Buffer %s is empty", p); + break; + case EXM_FILECOUNT: + msgq_str(sp, M_ERR, p, + "144|%s: expanded into too many file names"); + break; + case EXM_NOCANON: + msgq(sp, M_ERR, + "283|The %s command requires the ex terminal interface", p); + break; + case EXM_NOCANON_F: + msgq(sp, M_ERR, + "272|That form of %s requires the ex terminal interface", + p); + break; + case EXM_NOFILEYET: + if (p == NULL) + msgq(sp, M_ERR, + "274|Command failed, no file read in yet."); + else + msgq(sp, M_ERR, + "173|The %s command requires that a file have already been read in", p); + break; + case EXM_NOPREVBUF: + msgq(sp, M_ERR, "171|No previous buffer to execute"); + break; + case EXM_NOPREVRE: + msgq(sp, M_ERR, "172|No previous regular expression"); + break; + case EXM_NOSUSPEND: + msgq(sp, M_ERR, "230|This screen may not be suspended"); + break; + case EXM_SECURE: + msgq(sp, M_ERR, +"290|The %s command is not supported when the secure edit option is set", p); + break; + case EXM_SECURE_F: + msgq(sp, M_ERR, +"284|That form of %s is not supported when the secure edit option is set", p); + break; + case EXM_USAGE: + msgq(sp, M_ERR, "174|Usage: %s", p); + break; + } +} Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_util.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_version.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_version.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_version.c (revision 366308) @@ -0,0 +1,35 @@ +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1991, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include + +#include "../common/common.h" +#include "version.h" + +/* + * ex_version -- :version + * Display the program version. + * + * PUBLIC: int ex_version(SCR *, EXCMD *); + */ +int +ex_version(SCR *sp, EXCMD *cmdp) +{ + msgq(sp, M_INFO, "Version "VI_VERSION + " The CSRG, University of California, Berkeley."); + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_version.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_visual.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_visual.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_visual.c (revision 366308) @@ -0,0 +1,159 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "../common/common.h" +#include "../vi/vi.h" + +/* + * ex_visual -- :[line] vi[sual] [^-.+] [window_size] [flags] + * Switch to visual mode. + * + * PUBLIC: int ex_visual(SCR *, EXCMD *); + */ +int +ex_visual(SCR *sp, EXCMD *cmdp) +{ + SCR *tsp; + size_t len; + int pos; + char buf[256]; + size_t wlen; + CHAR_T *wp; + + /* If open option off, disallow visual command. */ + if (!O_ISSET(sp, O_OPEN)) { + msgq(sp, M_ERR, + "175|The visual command requires that the open option be set"); + return (1); + } + + /* Move to the address. */ + sp->lno = cmdp->addr1.lno == 0 ? 1 : cmdp->addr1.lno; + + /* + * Push a command based on the line position flags. If no + * flag specified, the line goes at the top of the screen. + */ + switch (FL_ISSET(cmdp->iflags, + E_C_CARAT | E_C_DASH | E_C_DOT | E_C_PLUS)) { + case E_C_CARAT: + pos = '^'; + break; + case E_C_DASH: + pos = '-'; + break; + case E_C_DOT: + pos = '.'; + break; + case E_C_PLUS: + pos = '+'; + break; + default: + sp->frp->lno = sp->lno; + sp->frp->cno = 0; + (void)nonblank(sp, sp->lno, &sp->cno); + F_SET(sp->frp, FR_CURSORSET); + goto nopush; + } + + if (FL_ISSET(cmdp->iflags, E_C_COUNT)) + len = snprintf(buf, sizeof(buf), + "%luz%c%lu", (u_long)sp->lno, pos, cmdp->count); + else + len = snprintf(buf, sizeof(buf), "%luz%c", (u_long)sp->lno, pos); + CHAR2INT(sp, buf, len, wp, wlen); + (void)v_event_push(sp, NULL, wp, wlen, CH_NOMAP | CH_QUOTED); + + /* + * !!! + * Historically, if no line address was specified, the [p#l] flags + * caused the cursor to be moved to the last line of the file, which + * was then positioned as described above. This seems useless, so + * I haven't implemented it. + */ + switch (FL_ISSET(cmdp->iflags, E_C_HASH | E_C_LIST | E_C_PRINT)) { + case E_C_HASH: + O_SET(sp, O_NUMBER); + break; + case E_C_LIST: + O_SET(sp, O_LIST); + break; + case E_C_PRINT: + break; + } + +nopush: /* + * !!! + * You can call the visual part of the editor from within an ex + * global command. + * + * XXX + * Historically, undoing a visual session was a single undo command, + * i.e. you could undo all of the changes you made in visual mode. + * We don't get this right; I'm waiting for the new logging code to + * be available. + * + * It's explicit, don't have to wait for the user, unless there's + * already a reason to wait. + */ + if (!F_ISSET(sp, SC_SCR_EXWROTE)) + F_SET(sp, SC_EX_WAIT_NO); + + if (F_ISSET(sp, SC_EX_GLOBAL)) { + /* + * When the vi screen(s) exit, we don't want to lose our hold + * on this screen or this file, otherwise we're going to fail + * fairly spectacularly. + */ + ++sp->refcnt; + ++sp->ep->refcnt; + /* XXXX where is this decremented ? */ + + /* + * Fake up a screen pointer -- vi doesn't get to change our + * underlying file, regardless. + */ + tsp = sp; + if (vi(&tsp)) + return (1); + + /* + * !!! + * Historically, if the user exited the vi screen(s) using an + * ex quit command (e.g. :wq, :q) ex/vi exited, it was only if + * they exited vi using the Q command that ex continued. Some + * early versions of nvi continued in ex regardless, but users + * didn't like the semantic. + * + * Reset the screen. + */ + if (ex_init(sp)) + return (1); + + /* Move out of the vi screen. */ + (void)ex_puts(sp, "\n"); + } else { + F_CLR(sp, SC_EX | SC_SCR_EX); + F_SET(sp, SC_VI); + } + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_visual.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_write.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_write.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_write.c (revision 366308) @@ -0,0 +1,371 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../common/common.h" + +enum which {WN, WQ, WRITE, XIT}; +static int exwr(SCR *, EXCMD *, enum which); + +/* + * ex_wn -- :wn[!] [>>] [file] + * Write to a file and switch to the next one. + * + * PUBLIC: int ex_wn(SCR *, EXCMD *); + */ +int +ex_wn(SCR *sp, EXCMD *cmdp) +{ + if (exwr(sp, cmdp, WN)) + return (1); + if (file_m3(sp, 0)) + return (1); + + /* The file name isn't a new file to edit. */ + cmdp->argc = 0; + + return (ex_next(sp, cmdp)); +} + +/* + * ex_wq -- :wq[!] [>>] [file] + * Write to a file and quit. + * + * PUBLIC: int ex_wq(SCR *, EXCMD *); + */ +int +ex_wq(SCR *sp, EXCMD *cmdp) +{ + int force; + + if (exwr(sp, cmdp, WQ)) + return (1); + if (file_m3(sp, 0)) + return (1); + + force = FL_ISSET(cmdp->iflags, E_C_FORCE); + + if (ex_ncheck(sp, force)) + return (1); + + F_SET(sp, force ? SC_EXIT_FORCE : SC_EXIT); + return (0); +} + +/* + * ex_write -- :write[!] [>>] [file] + * :write [!] [cmd] + * Write to a file. + * + * PUBLIC: int ex_write(SCR *, EXCMD *); + */ +int +ex_write(SCR *sp, EXCMD *cmdp) +{ + return (exwr(sp, cmdp, WRITE)); +} + + +/* + * ex_xit -- :x[it]! [file] + * Write out any modifications and quit. + * + * PUBLIC: int ex_xit(SCR *, EXCMD *); + */ +int +ex_xit(SCR *sp, EXCMD *cmdp) +{ + int force; + + NEEDFILE(sp, cmdp); + + if (F_ISSET(sp->ep, F_MODIFIED) && exwr(sp, cmdp, XIT)) + return (1); + if (file_m3(sp, 0)) + return (1); + + force = FL_ISSET(cmdp->iflags, E_C_FORCE); + + if (ex_ncheck(sp, force)) + return (1); + + F_SET(sp, force ? SC_EXIT_FORCE : SC_EXIT); + return (0); +} + +/* + * exwr -- + * The guts of the ex write commands. + */ +static int +exwr(SCR *sp, EXCMD *cmdp, enum which cmd) +{ + MARK rm; + int flags; + char *name; + CHAR_T *p = NULL; + size_t nlen; + char *n; + int rc; + EX_PRIVATE *exp; + + NEEDFILE(sp, cmdp); + + /* All write commands can have an associated '!'. */ + LF_INIT(FS_POSSIBLE); + if (FL_ISSET(cmdp->iflags, E_C_FORCE)) + LF_SET(FS_FORCE); + + /* Skip any leading whitespace. */ + if (cmdp->argc != 0) + for (p = cmdp->argv[0]->bp; *p != '\0' && cmdskip(*p); ++p); + + /* If "write !" it's a pipe to a utility. */ + if (cmdp->argc != 0 && cmd == WRITE && *p == '!') { + /* Secure means no shell access. */ + if (O_ISSET(sp, O_SECURE)) { + ex_wemsg(sp, cmdp->cmd->name, EXM_SECURE_F); + return (1); + } + + /* Expand the argument. */ + for (++p; *p && cmdskip(*p); ++p); + if (*p == '\0') { + ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE); + return (1); + } + if (argv_exp1(sp, cmdp, p, STRLEN(p), 1)) + return (1); + + /* Set the last bang command */ + exp = EXP(sp); + free(exp->lastbcomm); + exp->lastbcomm = v_wstrdup(sp, cmdp->argv[1]->bp, + cmdp->argv[1]->len); + + /* + * Historically, vi waited after a write filter even if there + * wasn't any output from the command. People complained when + * nvi waited only if there was output, wanting the visual cue + * that the program hadn't written anything. + */ + F_SET(sp, SC_EX_WAIT_YES); + + /* + * !!! + * Ignore the return cursor position, the cursor doesn't + * move. + */ + if (ex_filter(sp, cmdp, &cmdp->addr1, + &cmdp->addr2, &rm, cmdp->argv[1]->bp, FILTER_WRITE)) + return (1); + + /* Ex terminates with a bang, even if the command fails. */ + if (!F_ISSET(sp, SC_VI) && !F_ISSET(sp, SC_EX_SILENT)) + (void)ex_puts(sp, "!\n"); + + return (0); + } + + /* Set the FS_ALL flag if we're writing the entire file. */ + if (cmdp->addr1.lno <= 1 && !db_exist(sp, cmdp->addr2.lno + 1)) + LF_SET(FS_ALL); + + /* If "write >>" it's an append to a file. */ + if (cmdp->argc != 0 && cmd != XIT && p[0] == '>' && p[1] == '>') { + LF_SET(FS_APPEND); + + /* Skip ">>" and whitespace. */ + for (p += 2; *p && cmdskip(*p); ++p); + } + + /* If no other arguments, just write the file back. */ + if (cmdp->argc == 0 || *p == '\0') + return (file_write(sp, + &cmdp->addr1, &cmdp->addr2, NULL, flags)); + + /* Build an argv so we get an argument count and file expansion. */ + if (argv_exp2(sp, cmdp, p, STRLEN(p))) + return (1); + + /* + * 0 args: impossible. + * 1 args: impossible (I hope). + * 2 args: read it. + * >2 args: object, too many args. + * + * The 1 args case depends on the argv_sexp() function refusing + * to return success without at least one non-blank character. + */ + switch (cmdp->argc) { + case 0: + case 1: + abort(); + /* NOTREACHED */ + case 2: + INT2CHAR(sp, cmdp->argv[1]->bp, cmdp->argv[1]->len+1, + n, nlen); + name = v_strdup(sp, n, nlen - 1); + + /* + * !!! + * Historically, the read and write commands renamed + * "unnamed" files, or, if the file had a name, set + * the alternate file name. + */ + if (F_ISSET(sp->frp, FR_TMPFILE) && + !F_ISSET(sp->frp, FR_EXNAMED)) { + if ((n = v_strdup(sp, name, nlen - 1)) != NULL) { + free(sp->frp->name); + sp->frp->name = n; + } + /* + * The file has a real name, it's no longer a + * temporary, clear the temporary file flags. + * + * !!! + * If we're writing the whole file, FR_NAMECHANGE + * will be cleared by the write routine -- this is + * historic practice. + */ + F_CLR(sp->frp, FR_TMPEXIT | FR_TMPFILE); + F_SET(sp->frp, FR_NAMECHANGE | FR_EXNAMED); + + /* Notify the screen. */ + (void)sp->gp->scr_rename(sp, sp->frp->name, 1); + } else + set_alt_name(sp, name); + break; + default: + INT2CHAR(sp, p, STRLEN(p) + 1, n, nlen); + ex_emsg(sp, n, EXM_FILECOUNT); + return (1); + } + + rc = file_write(sp, &cmdp->addr1, &cmdp->addr2, name, flags); + + free(name); + + return rc; +} + +/* + * ex_writefp -- + * Write a range of lines to a FILE *. + * + * PUBLIC: int ex_writefp(SCR *, + * PUBLIC: char *, FILE *, MARK *, MARK *, u_long *, u_long *, int); + */ +int +ex_writefp(SCR *sp, char *name, FILE *fp, MARK *fm, MARK *tm, u_long *nlno, u_long *nch, int silent) +{ + struct stat sb; + GS *gp; + u_long ccnt; /* XXX: can't print off_t portably. */ + recno_t fline, tline, lcnt; + size_t len; + int rval; + char *msg, *p; + + gp = sp->gp; + fline = fm->lno; + tline = tm->lno; + + if (nlno != NULL) { + *nch = 0; + *nlno = 0; + } + + /* + * The vi filter code has multiple processes running simultaneously, + * and one of them calls ex_writefp(). The "unsafe" function calls + * in this code are to db_get() and msgq(). Db_get() is safe, see + * the comment in ex_filter.c:ex_filter() for details. We don't call + * msgq if the multiple process bit in the EXF is set. + * + * !!! + * Historic vi permitted files of 0 length to be written. However, + * since the way vi got around dealing with "empty" files was to + * always have a line in the file no matter what, it wrote them as + * files of a single, empty line. We write empty files. + * + * "Alex, I'll take vi trivia for $1000." + */ + ccnt = 0; + lcnt = 0; + msg = "253|Writing..."; + if (tline != 0) + for (; fline <= tline; ++fline, ++lcnt) { + /* Caller has to provide any interrupt message. */ + if ((lcnt + 1) % INTERRUPT_CHECK == 0) { + if (INTERRUPTED(sp)) + break; + if (!silent) { + gp->scr_busy(sp, msg, msg == NULL ? + BUSY_UPDATE : BUSY_ON); + msg = NULL; + } + } + if (db_rget(sp, fline, &p, &len)) + goto err; + if (fwrite(p, 1, len, fp) != len) + goto err; + ccnt += len; + if (putc('\n', fp) != '\n') + break; + ++ccnt; + } + + if (fflush(fp)) + goto err; + /* + * XXX + * I don't trust NFS -- check to make sure that we're talking to + * a regular file and sync so that NFS is forced to flush. + */ + if (!fstat(fileno(fp), &sb) && + S_ISREG(sb.st_mode) && fsync(fileno(fp))) + goto err; + + if (fclose(fp)) + goto err; + + rval = 0; + if (0) { +err: if (!F_ISSET(sp->ep, F_MULTILOCK)) + msgq_str(sp, M_SYSERR, name, "%s"); + (void)fclose(fp); + rval = 1; + } + + if (!silent) + gp->scr_busy(sp, NULL, BUSY_OFF); + + /* Report the possibly partial transfer. */ + if (nlno != NULL) { + *nch = ccnt; + *nlno = lcnt; + } + return (rval); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_write.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_yank.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_yank.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_yank.c (revision 366308) @@ -0,0 +1,41 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include + +#include "../common/common.h" + +/* + * ex_yank -- :[line [,line]] ya[nk] [buffer] [count] + * Yank the lines into a buffer. + * + * PUBLIC: int ex_yank(SCR *, EXCMD *); + */ +int +ex_yank(SCR *sp, EXCMD *cmdp) +{ + NEEDFILE(sp, cmdp); + + /* + * !!! + * Historically, yanking lines in ex didn't count toward the + * number-of-lines-yanked report. + */ + return (cut(sp, + FL_ISSET(cmdp->iflags, E_C_BUFFER) ? &cmdp->buffer : NULL, + &cmdp->addr1, &cmdp->addr2, CUT_LINEMODE)); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_yank.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex_z.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex_z.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex_z.c (revision 366308) @@ -0,0 +1,141 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "../common/common.h" + +/* + * ex_z -- :[line] z [^-.+=] [count] [flags] + * Adjust window. + * + * PUBLIC: int ex_z(SCR *, EXCMD *); + */ +int +ex_z(SCR *sp, EXCMD *cmdp) +{ + MARK abs; + recno_t cnt, equals, lno; + int eofcheck; + + NEEDFILE(sp, cmdp); + + /* + * !!! + * If no count specified, use either two times the size of the + * scrolling region, or the size of the window option. POSIX + * 1003.2 claims that the latter is correct, but historic ex/vi + * documentation and practice appear to use the scrolling region. + * I'm using the window size as it means that the entire screen + * is used instead of losing a line to roundoff. Note, we drop + * a line from the cnt if using the window size to leave room for + * the next ex prompt. + */ + if (FL_ISSET(cmdp->iflags, E_C_COUNT)) + cnt = cmdp->count; + else + cnt = O_VAL(sp, O_WINDOW) - 1; + + equals = 0; + eofcheck = 0; + lno = cmdp->addr1.lno; + + switch (FL_ISSET(cmdp->iflags, + E_C_CARAT | E_C_DASH | E_C_DOT | E_C_EQUAL | E_C_PLUS)) { + case E_C_CARAT: /* Display cnt * 2 before the line. */ + eofcheck = 1; + if (lno > cnt * 2) + cmdp->addr1.lno = (lno - cnt * 2) + 1; + else + cmdp->addr1.lno = 1; + cmdp->addr2.lno = (cmdp->addr1.lno + cnt) - 1; + break; + case E_C_DASH: /* Line goes at the bottom of the screen. */ + cmdp->addr1.lno = lno > cnt ? (lno - cnt) + 1 : 1; + cmdp->addr2.lno = lno; + break; + case E_C_DOT: /* Line goes in the middle of the screen. */ + /* + * !!! + * Historically, the "middleness" of the line overrode the + * count, so that "3z.19" or "3z.20" would display the first + * 12 lines of the file, i.e. (N - 1) / 2 lines before and + * after the specified line. + */ + eofcheck = 1; + cnt = (cnt - 1) / 2; + cmdp->addr1.lno = lno > cnt ? lno - cnt : 1; + cmdp->addr2.lno = lno + cnt; + + /* + * !!! + * Historically, z. set the absolute cursor mark. + */ + abs.lno = sp->lno; + abs.cno = sp->cno; + (void)mark_set(sp, ABSMARK1, &abs, 1); + break; + case E_C_EQUAL: /* Center with hyphens. */ + /* + * !!! + * Strangeness. The '=' flag is like the '.' flag (see the + * above comment, it applies here as well) but with a special + * little hack. Print out lines of hyphens before and after + * the specified line. Additionally, the cursor remains set + * on that line. + */ + eofcheck = 1; + cnt = (cnt - 1) / 2; + cmdp->addr1.lno = lno > cnt ? lno - cnt : 1; + cmdp->addr2.lno = lno - 1; + if (ex_pr(sp, cmdp)) + return (1); + (void)ex_puts(sp, "----------------------------------------\n"); + cmdp->addr2.lno = cmdp->addr1.lno = equals = lno; + if (ex_pr(sp, cmdp)) + return (1); + (void)ex_puts(sp, "----------------------------------------\n"); + cmdp->addr1.lno = lno + 1; + cmdp->addr2.lno = (lno + cnt) - 1; + break; + default: + /* If no line specified, move to the next one. */ + if (F_ISSET(cmdp, E_ADDR_DEF)) + ++lno; + /* FALLTHROUGH */ + case E_C_PLUS: /* Line goes at the top of the screen. */ + eofcheck = 1; + cmdp->addr1.lno = lno; + cmdp->addr2.lno = (lno + cnt) - 1; + break; + } + + if (eofcheck) { + if (db_last(sp, &lno)) + return (1); + if (cmdp->addr2.lno > lno) + cmdp->addr2.lno = lno; + } + + if (ex_pr(sp, cmdp)) + return (1); + if (equals) + sp->lno = equals; + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex_z.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/script.h =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/script.h (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/script.h (revision 366308) @@ -0,0 +1,19 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +struct _script { + pid_t sh_pid; /* Shell pid. */ + int sh_master; /* Master pty fd. */ + int sh_slave; /* Slave pty fd. */ + char *sh_prompt; /* Prompt. */ + size_t sh_prompt_len; /* Prompt length. */ + char sh_name[64]; /* Pty name */ + struct winsize sh_win; /* Window size. */ + struct termios sh_term; /* Terminal information. */ +}; Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/script.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/tag.h =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/tag.h (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/tag.h (revision 366308) @@ -0,0 +1,107 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * Copyright (c) 1994, 1996 + * Rob Mayoff. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +/* + * Cscope connection information. One of these is maintained per cscope + * connection, linked from the EX_PRIVATE structure. + */ +struct _csc { + SLIST_ENTRY(_csc) q; /* Linked list of cscope connections. */ + + char *dname; /* Base directory of this cscope connection. */ + size_t dlen; /* Length of base directory. */ + pid_t pid; /* PID of the connected cscope process. */ + struct timespec mtim; /* Last modification time of cscope database. */ + + FILE *from_fp; /* from cscope: FILE. */ + int from_fd; /* from cscope: file descriptor. */ + FILE *to_fp; /* to cscope: FILE. */ + int to_fd; /* to cscope: file descriptor. */ + + char **paths; /* Array of search paths for this cscope. */ + char *pbuf; /* Search path buffer. */ + size_t pblen; /* Search path buffer length. */ + + char buf[1]; /* Variable length buffer. */ +}; + +/* + * Tag file information. One of these is maintained per tag file, linked + * from the EXPRIVATE structure. + */ +struct _tagf { /* Tag files. */ + TAILQ_ENTRY(_tagf) q; /* Linked list of tag files. */ + char *name; /* Tag file name. */ + int errnum; /* Errno. */ + +#define TAGF_ERR 0x01 /* Error occurred. */ +#define TAGF_ERR_WARN 0x02 /* Error reported. */ + u_int8_t flags; +}; + +/* + * Tags are structured internally as follows: + * + * +----+ +----+ +----+ +----+ + * | EP | -> | Q1 | <-- | T1 | <-- | T2 | + * +----+ +----+ --> +----+ --> +----+ + * | + * +----+ +----+ + * | Q2 | <-- | T1 | + * +----+ --> +----+ + * | + * +----+ +----+ + * | Q3 | <-- | T1 | + * +----+ --> +----+ + * + * Each Q is a TAGQ, or tag "query", which is the result of one tag or cscope + * command. Each Q references one or more TAG's, or tagged file locations. + * + * tag: put a new Q at the head (^]) + * tagnext: T1 -> T2 inside Q (^N) + * tagprev: T2 -> T1 inside Q (^P) + * tagpop: discard Q (^T) + * tagtop: discard all Q + */ +struct _tag { /* Tag list. */ + TAILQ_ENTRY(_tag) q; /* Linked list of tags. */ + + /* Tag pop/return information. */ + FREF *frp; /* Saved file. */ + recno_t lno; /* Saved line number. */ + size_t cno; /* Saved column number. */ + + char *fname; /* Filename. */ + size_t fnlen; /* Filename length. */ + recno_t slno; /* Search line number. */ + CHAR_T *search; /* Search string. */ + size_t slen; /* Search string length. */ + CHAR_T *msg; /* Message string. */ + size_t mlen; /* Message string length. */ + + CHAR_T buf[1]; /* Variable length buffer. */ +}; + +struct _tagq { /* Tag queue. */ + TAILQ_ENTRY(_tagq) q; /* Linked list of tag queues. */ + /* This queue's tag list. */ + TAILQ_HEAD(_tagqh, _tag) tagq[1]; + + TAG *current; /* Current TAG within the queue. */ + + char *tag; /* Tag string. */ + size_t tlen; /* Tag string length. */ + +#define TAG_CSCOPE 0x01 /* Cscope tag. */ + u_int8_t flags; + + char buf[1]; /* Variable length buffer. */ +}; Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/tag.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/ex/ex.awk =================================================================== --- vendor/nvi/2.2.0-05ed8b9/ex/ex.awk (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/ex/ex.awk (revision 366308) @@ -0,0 +1,6 @@ +# @(#)ex.awk 10.1 (Berkeley) 6/8/95 + +/^\/\* C_[0-9A-Z_]* \*\/$/ { + printf("#define %s %d\n", $2, cnt++); + next; +} Property changes on: vendor/nvi/2.2.0-05ed8b9/ex/ex.awk ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/files/config.h.in =================================================================== --- vendor/nvi/2.2.0-05ed8b9/files/config.h.in (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/files/config.h.in (revision 366308) @@ -0,0 +1,26 @@ +/* Define when using wide characters */ +#cmakedefine USE_WIDECHAR + +/* Define when iconv can be used */ +#cmakedefine USE_ICONV + +/* Define when the 2nd argument of iconv(3) is not const */ +#cmakedefine ICONV_TRADITIONAL + +/* Define if you have */ +#cmakedefine HAVE_LIBUTIL_H + +/* Define if you have */ +#cmakedefine HAVE_NCURSES_H + +/* Define if you have */ +#cmakedefine HAVE_NCURSESW_NCURSES_H + +/* Define if you have */ +#cmakedefine HAVE_PTY_H + +/* Define if you have */ +#cmakedefine HAVE_TERM_H + +/* Define if struct dirent has field d_namlen */ +#cmakedefine HAVE_DIRENT_D_NAMLEN Property changes on: vendor/nvi/2.2.0-05ed8b9/files/config.h.in ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/files/pathnames.h.in =================================================================== --- vendor/nvi/2.2.0-05ed8b9/files/pathnames.h.in (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/files/pathnames.h.in (revision 366308) @@ -0,0 +1,25 @@ +/* Read standard system paths first. */ +#include + +#ifndef _PATH_EXRC +#define _PATH_EXRC ".exrc" +#endif + +#ifndef _PATH_MSGCAT +#define _PATH_MSGCAT "@vi_cv_path_msgcat@" +#endif + +#ifndef _PATH_NEXRC +#define _PATH_NEXRC ".nexrc" +#endif + +/* On linux _PATH_PRESERVE is only writable by root */ +#define NVI_PATH_PRESERVE "@vi_cv_path_preserve@" + +#ifndef _PATH_SYSEXRC +#define _PATH_SYSEXRC "/etc/vi.exrc" +#endif + +#ifndef _PATH_TAGS +#define _PATH_TAGS "tags" +#endif Property changes on: vendor/nvi/2.2.0-05ed8b9/files/pathnames.h.in ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/files/recover.in =================================================================== --- vendor/nvi/2.2.0-05ed8b9/files/recover.in (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/files/recover.in (revision 366308) @@ -0,0 +1,53 @@ +#!/bin/sh +# +# Script to recover nvi edit sessions. + +RECDIR="@vi_cv_path_preserve@" + +[ -d ${RECDIR} ] || exit 1 +find ${RECDIR} ! -type f -a ! -type d -delete + +# Check editor backup files. +vibackup=`echo ${RECDIR}/vi.*` +if [ "${vibackup}" != '${RECDIR}/vi.*' ]; then + echo -n 'Recovering vi editor sessions:' + for i in ${RECDIR}/vi.*; do + # Only test files that are readable. + if [ ! -r "${i}" ]; then + continue + fi + + # Unmodified nvi editor backup files either have the + # execute bit set or are zero length. Delete them. + if [ -x "${i}" -o ! -s "${i}" ]; then + rm -f "${i}" + fi + done +else exit +fi + +# It is possible to get incomplete recovery files, if the editor crashes +# at the right time. +virecovery=`echo ${RECDIR}/recover.*` +if [ "${virecovery}" != "${RECDIR}/recover.*" ]; then + for i in ${RECDIR}/recover.*; do + # Only test files that are readable. + if [ ! -r "${i}" ]; then + continue + fi + + # Delete any recovery files that are zero length, corrupted, + # or that have no corresponding backup file. Else send mail + # to the user. + recfile=`awk '/^X-vi-data: *file;/ { sub(/^.*;/, " "); \ + do { if (substr($0,1,1) == " ") print; else exit } \ + while(getline) }' < "${i}" | uudecode -mr` + if [ -n "${recfile}" -a -s "${recfile}" ]; then + sendmail -odb -t < "${i}" + echo -n '.' + else + rm -f "${i}" + fi + done +fi +echo ' done.' Property changes on: vendor/nvi/2.2.0-05ed8b9/files/recover.in ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/man/vi.1 =================================================================== --- vendor/nvi/2.2.0-05ed8b9/man/vi.1 (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/man/vi.1 (revision 366308) @@ -0,0 +1,2772 @@ +.\" Copyright (c) 1994 +.\" The Regents of the University of California. All rights reserved. +.\" Copyright (c) 1994, 1995, 1996 +.\" Keith Bostic. All rights reserved. +.\" Copyright (c) 2011 +.\" Zhihao Yuan. All rights reserved. +.\" +.\" The vi program is freely redistributable. +.\" You are welcome to copy, modify and share it with others +.\" under the conditions listed in the LICENSE file. +.\" If any company (not individual!) finds vi sufficiently useful +.\" that you would have purchased it, or if any company wishes to +.\" redistribute it, contributions to the authors would be appreciated. +.\" +.Dd November 2, 2013 +.Dt VI 1 +.Os +.Sh NAME +.Nm ex , vi , view +.Nd text editors +.Sh SYNOPSIS +.Nm ex +.Op Fl FRrSsv +.Op Fl c Ar cmd +.Op Fl t Ar tag +.Op Fl w Ar size +.Op Ar +.Nm vi\ \& +.Op Fl eFRrS +.Op Fl c Ar cmd +.Op Fl t Ar tag +.Op Fl w Ar size +.Op Ar +.Nm view +.Op Fl eFrS +.Op Fl c Ar cmd +.Op Fl t Ar tag +.Op Fl w Ar size +.Op Ar +.Sh DESCRIPTION +.Nm vi +is a screen-oriented text editor. +.Nm ex +is a line-oriented text editor. +.Nm ex +and +.Nm vi +are different interfaces to the same program, +and it is possible to switch back and forth during an edit session. +.Nm view +is the equivalent of using the +.Fl R +.Pq read-only +option of +.Nm vi . +.Pp +This manual page is the one provided with the +.Nm nex Ns / Ns Nm nvi +versions of the +.Nm ex Ns / Ns Nm vi +text editors. +.Nm nex Ns / Ns Nm nvi +are intended as bug-for-bug compatible replacements for the original +Fourth Berkeley Software Distribution +.Pq 4BSD +.Nm ex +and +.Nm vi +programs. +For the rest of this manual page, +.Nm nex Ns / Ns Nm nvi +is used only when it's necessary to distinguish it from the historic +implementations of +.Nm ex Ns / Ns Nm vi . +.Pp +This manual page is intended for users already familiar with +.Nm ex Ns / Ns Nm vi . +Anyone else should almost certainly read a good tutorial on the +editor before this manual page. +If you're in an unfamiliar environment, +and you absolutely have to get work done immediately, +read the section after the options description, entitled +.Sx FAST STARTUP . +It's probably enough to get you going. +.Pp +The following options are available: +.Bl -tag -width "-w size " +.It Fl c Ar cmd +Execute +.Ar cmd +on the first file loaded. +Particularly useful for initial positioning in the file, although +.Ar cmd +is not limited to positioning commands. +This is the POSIX 1003.2 interface for the historic +.Dq +cmd +syntax. +.Nm nex Ns / Ns Nm nvi +supports both the old and new syntax. +.It Fl e +Start editing in ex mode, as if the command name were +.Nm ex . +.It Fl F +Don't copy the entire file when first starting to edit. +(The default is to make a copy in case someone else modifies +the file during your edit session.) +.\" .It Fl l +.\" Start editing with the lisp and showmatch options set. +.It Fl R +Start editing in read-only mode, as if the command name was +.Nm view , +or the +.Cm readonly +option was set. +.It Fl r +Recover the specified files, or, if no files are specified, +list the files that could be recovered. +If no recoverable files by the specified name exist, +the file is edited as if the +.Fl r +option had not been specified. +.It Fl S +Run with the +.Cm secure +edit option set, disallowing all access to external programs. +.It Fl s +Enter batch mode; applicable only to +.Nm ex +edit sessions. +Batch mode is useful when running +.Nm ex +scripts. +Prompts, informative messages and other user oriented messages are turned off, +and no startup files or environment variables are read. +This is the POSIX 1003.2 interface for the historic +.Dq - +argument. +.Nm nex Ns / Ns Nm nvi +supports both the old and new syntax. +.It Fl t Ar tag +Start editing at the specified +.Ar tag +.Pq see Xr ctags 1 . +.It Fl v +Start editing in vi mode, as if the command name was +.Nm vi . +.It Fl w Ar size +Set the initial window size to the specified number of lines. +.El +.Pp +Command input for +.Nm ex Ns / Ns Nm vi +is read from the standard input. +In the +.Nm vi +interface, it is an error if standard input is not a terminal. +In the +.Nm ex +interface, if standard input is not a terminal, +.Nm ex +will read commands from it regardless; however, the session will be a +batch mode session, exactly as if the +.Fl s +option had been specified. +.Sh FAST STARTUP +This section will tell you the minimum amount that you need to +do simple editing tasks using +.Nm vi . +If you've never used any screen editor before, +you're likely to have problems even with this simple introduction. +In that case you should find someone that already knows +.Nm vi +and have them walk you through this section. +.Pp +.Nm vi +is a screen editor. +This means that it takes up almost the entire screen, +displaying part of the file on each screen line, +except for the last line of the screen. +The last line of the screen is used for you to give commands to +.Nm vi , +and for +.Nm vi +to give information to you. +.Pp +The other fact that you need to understand is that +.Nm vi +is a modeful editor, +i.e., you are either entering text or you are executing commands, +and you have to be in the right mode to do one or the other. +You will be in command mode when you first start editing a file. +There are commands that switch you into input mode. +There is only one key that takes you out of input mode, +and that is the +.Aq escape +key. +.Pp +In this manual, +key names are denoted with \(la and \(ra, e.g., +.Aq escape +means the +.Dq escape +key, usually labeled +.Dq Esc +on your terminal's keyboard. +If you're ever confused as to which mode you're in, +keep entering the +.Aq escape +key until +.Nm vi +beeps at you. +Generally, +.Nm vi +will beep at you if you try and do something that's not allowed. +It will also display error messages. +.Pp +To start editing a file, enter the following command: +.Pp +.Dl $ vi file +.Pp +The command you should enter as soon as you start editing is: +.Pp +.Dl :set verbose showmode +.Pp +This will make the editor give you verbose error messages and display +the current mode at the bottom of the screen. +.Pp +The commands to move around the file are: +.Bl -tag -width Ds +.It Cm h +Move the cursor left one character. +.It Cm j +Move the cursor down one line. +.It Cm k +Move the cursor up one line. +.It Cm l +Move the cursor right one character. +.It Aq Cm cursor-arrows +The cursor arrow keys should work, too. +.It Cm / Ns Ar text +Search for the string +.Dq Ar text +in the file, +and move the cursor to its first character. +.El +.Pp +The commands to enter new text are: +.Bl -tag -width "" +.It Cm a +Append new text, after the cursor. +.It Cm i +Insert new text, before the cursor. +.It Cm o +Open a new line below the line the cursor is on, and start entering text. +.It Cm O +Open a new line above the line the cursor is on, and start entering text. +.It Aq Cm escape +Once you've entered input mode using one of the +.Cm a , +.Cm i , +.Cm o +or +.Cm O +commands, use +.Aq Cm escape +to quit entering text and return to command mode. +.El +.Pp +The commands to copy text are: +.Bl -tag -width Ds +.It Cm yy +Copy the line the cursor is on. +.It Cm p +Append the copied line after the line the cursor is on. +.El +.Pp +The commands to delete text are: +.Bl -tag -width Ds +.It Cm dd +Delete the line the cursor is on. +.It Cm x +Delete the character the cursor is on. +.El +.Pp +The commands to write the file are: +.Bl -tag -width Ds +.It Cm :w +Write the file back to the file with the name that you originally used +as an argument on the +.Nm vi +command line. +.It Cm :w Ar file_name +Write the file back to the file with the name +.Ar file_name . +.El +.Pp +The commands to quit editing and exit the editor are: +.Bl -tag -width Ds +.It Cm :q +Quit editing and leave +.Nm vi +(if you've modified the file, but not saved your changes, +.Nm vi +will refuse to quit). +.It Cm :q! +Quit, discarding any modifications that you may have made. +.El +.Pp +One final caution: +Unusual characters can take up more than one column on the screen, +and long lines can take up more than a single screen line. +The above commands work on +.Dq physical +characters and lines, +i.e., they affect the entire line no matter how many screen lines it takes up +and the entire character no matter how many screen columns it takes up. +.Sh REGULAR EXPRESSIONS +.Nm ex Ns / Ns Nm vi +supports regular expressions +.Pq REs , +as documented in +.Xr re_format 7 , +for line addresses, as the first part of the +.Nm ex Cm substitute , +.Cm global +and +.Cm v +commands, and in search patterns. +Basic regular expressions +.Pq BREs +are enabled by default; +extended regular expressions +.Pq EREs +are used if the +.Cm extended +option is enabled. +The use of regular expressions can be largely disabled using the +.Cm magic +option. +.Pp +The following strings have special meanings in the +.Nm ex Ns / Ns Nm vi +version of regular expressions: +.Bl -bullet -offset 6u +.It +An empty regular expression is equivalent to the last regular expression used. +.It +.Sq \e< +matches the beginning of the word. +.It +.Sq \e> +matches the end of the word. +.It +.Sq \(ti +matches the replacement part of the last +.Cm substitute +command. +.El +.Sh BUFFERS +A buffer is an area where commands can save changed or deleted text +for later use. +.Nm vi +buffers are named with a single character preceded by a double quote, +for example +.Cm \&" Ns Aq Ar c ; +.Nm ex +buffers are the same, +but without the double quote. +.Nm nex Ns / Ns Nm nvi +permits the use of any character without another meaning in the position where +a buffer name is expected. +.Pp +All buffers are either in +.Em line mode +or +.Em character mode . +Inserting a buffer in line mode into the text creates new lines for each of the +lines it contains, while a buffer in character mode creates new lines for any +lines +.Em other +than the first and last lines it contains. +The first and last lines are inserted at the current cursor position, becoming +part of the current line. +If there is more than one line in the buffer, +the current line itself will be split. +All +.Nm ex +commands which store text into buffers do so in line mode. +The behaviour of +.Nm vi +commands depend on their associated motion command: +.Bl -bullet -offset 6u +.It +.Aq Cm control-A , +.Cm h , +.Cm l , +.Cm ,\& , +.Cm 0 , +.Cm B , +.Cm E , +.Cm F , +.Cm T , +.Cm W , +.Cm \(ha , +.Cm b , +.Cm e , +.Cm f +and +.Cm t +make the destination buffer character-oriented. +.It +.Cm j , +.Aq Cm control-M , +.Cm k , +.Cm \(aq , +.Cm - , +.Cm G , +.Cm H , +.Cm L , +.Cm M , +.Cm _ +and +.Cm |\& +make the destination buffer line-oriented. +.It +.Cm $ , +.Cm % , +.Cm \` , +.Cm (\& , +.Cm )\& , +.Cm / , +.Cm ?\& , +.Cm [[ , +.Cm ]] , +.Cm { +and +.Cm } +make the destination buffer character-oriented, unless the starting and +end positions are the first and last characters on a line. +In that case, the buffer is line-oriented. +.El +.Pp +The +.Nm ex +command +.Cm display buffers +displays the current mode for each buffer. +.Pp +Buffers named +.Sq a +through +.Sq z +may be referred to using their uppercase equivalent, in which case new content +will be appended to the buffer, instead of replacing it. +.Pp +Buffers named +.Sq 1 +through +.Sq 9 +are special. +A region of text modified using the +.Cm c +.Pq change +or +.Cm d +.Pq delete +commands is placed into the numeric buffer +.Sq 1 +if no other buffer is specified and if it meets one of the following conditions: +.Bl -bullet -offset 6u +.It +It includes characters from more than one line. +.It +It is specified using a line-oriented motion. +.It +It is specified using one of the following motion commands: +.Aq Cm control-A , +.Cm \` Ns Aq Ar character , +.Cm n , +.Cm N , +.Cm % , +.Cm / , +.Cm { , +.Cm } , +.Cm \&( , +.Cm \&) , +and +.Cm \&? . +.El +.Pp +Before this copy is done, the previous contents of buffer +.Sq 1 +are moved into buffer +.Sq 2 , +.Sq 2 +into buffer +.Sq 3 , +and so on. +The contents of buffer +.Sq 9 +are discarded. +Note that this rotation occurs +.Em regardless +of the user specifying another buffer. +In +.Nm vi , +text may be explicitly stored into the numeric buffers. +In this case, the buffer rotation occurs before the replacement of the buffer's +contents. +The numeric buffers are only available in +.Nm vi +mode. +.Sh VI COMMANDS +The following section describes the commands available in the command +mode of the +.Nm vi +editor. +The following words have a special meaning in the commands description: +.Pp +.Bl -tag -width bigword -compact -offset 3u +.It Ar bigword +A set of non-whitespace characters. +.It Ar buffer +Temporary area where commands may place text. +If not specified, the default buffer is used. +See also +.Sx BUFFERS , +above. +.It Ar count +A positive number used to specify the desired number of iterations +of a command. +It defaults to 1 if not specified. +.It Ar motion +A cursor movement command which indicates the other end of the affected region +of text, the first being the current cursor position. +Repeating the command character makes it affect the whole current line. +.It Ar word +A sequence of letters, digits or underscores. +.El +.Pp +.Ar buffer +and +.Ar count , +if both present, may be specified in any order. +.Ar motion +and +.Ar count , +if both present, are effectively multiplied together +and considered part of the motion. +.Pp +.Bl -tag -width Ds -compact +.It Xo +.Aq Cm control-A +.Xc +Search forward +for the word starting at the cursor position. +.Pp +.It Xo +.Op Ar count +.Aq Cm control-B +.Xc +Page backwards +.Ar count +screens. +Two lines of overlap are maintained, if possible. +.Pp +.It Xo +.Op Ar count +.Aq Cm control-D +.Xc +Scroll forward +.Ar count +lines. +If +.Ar count +is not given, scroll forward the number of lines specified by the last +.Aq Cm control-D +or +.Aq Cm control-U +command. +If this is the first +.Aq Cm control-D +command, scroll half the number of lines in the current screen. +.Pp +.It Xo +.Op Ar count +.Aq Cm control-E +.Xc +Scroll forward +.Ar count +lines, leaving the current line and column as is, if possible. +.Pp +.It Xo +.Op Ar count +.Aq Cm control-F +.Xc +Page forward +.Ar count +screens. +Two lines of overlap are maintained, if possible. +.Pp +.It Aq Cm control-G +Display the following file information: +the file name +.Pq as given to Nm vi ; +whether the file has been modified since it was last written; +if the file is read-only; +the current line number; +the total number of lines in the file; +and the current line number as a percentage of the total lines in the file. +.Pp +.It Xo +.Op Ar count +.Aq Cm control-H +.Xc +.It Xo +.Op Ar count +.Cm h +.Xc +Move the cursor back +.Ar count +characters in the current line. +.Pp +.It Xo +.Op Ar count +.Aq Cm control-J +.Xc +.It Xo +.Op Ar count +.Aq Cm control-N +.Xc +.It Xo +.Op Ar count +.Cm j +.Xc +Move the cursor down +.Ar count +lines without changing the current column. +.Pp +.It Aq Cm control-L +.It Aq Cm control-R +Repaint the screen. +.Pp +.It Xo +.Op Ar count +.Aq Cm control-M +.Xc +.It Xo +.Op Ar count +.Cm + +.Xc +Move the cursor down +.Ar count +lines to the first non-blank character of that line. +.Pp +.It Xo +.Op Ar count +.Aq Cm control-P +.Xc +.It Xo +.Op Ar count +.Cm k +.Xc +Move the cursor up +.Ar count +lines, without changing the current column. +.Pp +.It Aq Cm control-T +Return to the most recent tag context. +.Pp +.It Xo +.Op Ar count +.Aq Cm control-U +.Xc +Scroll backwards +.Ar count +lines. +If +.Ar count +is not given, scroll backwards the number of lines specified by the last +.Aq Cm control-D +or +.Aq Cm control-U +command. +If this is the first +.Aq Cm control-U +command, scroll half the number of lines in the current screen. +.Pp +.It Aq Cm control-W +Switch to the next lower screen in the window, +or to the first screen if there are no lower screens in the window. +.Pp +.It Xo +.Op Ar count +.Aq Cm control-Y +.Xc +Scroll backwards +.Ar count +lines, leaving the current line and column as is, if possible. +.Pp +.It Aq Cm control-Z +Suspend the current editor session. +.Pp +.It Aq Cm escape +Execute the +.Nm ex +command being entered, or cancel it if it is only partial. +.Pp +.It Aq Cm control-] +Push a tag reference onto the tag stack. +.Pp +.It Aq Cm control-\(ha +Switch to the most recently edited file. +.Pp +.It Xo +.Op Ar count +.Aq Cm space +.Xc +.It Xo +.Op Ar count +.Cm l +.Xc +Move the cursor forward +.Ar count +characters without changing the current line. +.Pp +.It Xo +.Op Ar count +.Cm !\& +.Ar motion shell-argument(s) +.Aq Li carriage-return +.Xc +Replace the lines spanned by +.Ar count +and +.Ar motion +with the output +.Pq standard output and standard error +of the program named by the +.Cm shell +option, called with a +.Fl c +flag followed by the +.Ar shell-argument(s) +.Pq bundled into a single argument . +Within +.Ar shell-argument(s) , +the +.Sq % , +.Sq # +and +.Sq !\& +characters are expanded to the current file name, +the previous current file name, +and the command text of the previous +.Cm !\& +or +.Cm :! +commands, respectively. +The special meaning of +.Sq % , +.Sq # +and +.Sq !\& +can be overridden by escaping them with a backslash. +.Pp +.It Xo +.Op Ar count +.Cm # +.Sm off +.Cm # | + | - +.Sm on +.Xc +Increment +.Pq trailing So # Sc or So + Sc +or decrement +.Pq trailing Sq - +the number under the cursor by +.Ar count , +starting at the cursor position or at the first non-blank +character following it. +Numbers with a leading +.Sq 0x +or +.Sq 0X +are interpreted as hexadecimal numbers. +Numbers with a leading +.Sq 0 +are interpreted as octal numbers unless they contain a non-octal digit. +Other numbers may be prefixed with a +.Sq + +or +.Sq - +sign. +.Pp +.It Xo +.Op Ar count +.Cm $ +.Xc +Move the cursor to the end of a line. +If +.Ar count +is specified, additionally move the cursor down +.Ar count +\(mi 1 lines. +.Pp +.It Cm % +Move to the +.Cm matchchars +character matching +the one found at the cursor position or the closest to the right of it. +.Pp +.It Cm & +Repeat the previous substitution command on the current line. +.Pp +.It Xo +.Cm \(aq Ns Aq Ar character +.Xc +.It Xo +.Cm \` Ns Aq Ar character +.Xc +Return to the cursor position marked by the character +.Ar character , +or, if +.Ar character +is +.Sq \(aq +or +.Sq \` , +to the position of the cursor before the last of the following commands: +.Aq Cm control-A , +.Aq Cm control-T , +.Aq Cm control-] , +.Cm % , +.Cm \(aq , +.Cm \` , +.Cm (\& , +.Cm )\& , +.Cm / , +.Cm ?\& , +.Cm G , +.Cm H , +.Cm L , +.Cm [[ , +.Cm ]] , +.Cm { , +.Cm } . +The first form returns to the first non-blank character of the line marked by +.Ar character . +The second form returns to the line and column marked by +.Ar character . +.Pp +.It Xo +.Op Ar count +.Cm \&( +.Xc +.It Xo +.Op Ar count +.Cm \&) +.Xc +Move +.Ar count +sentences backward or forward, respectively. +A sentence is an area of text that begins with the first nonblank character +following the previous sentence, paragraph, or section +boundary and continues until the next period, exclamation point, +or question mark character, followed by any number of closing parentheses, +brackets, double or single quote characters, followed by +either an end-of-line or two whitespace characters. +Groups of empty lines +.Pq or lines containing only whitespace characters +are treated as a single sentence. +.Pp +.It Xo +.Op Ar count +.Cm ,\& +.Xc +Reverse find character +.Pq i.e., the last Cm F , f , T No or Cm t No command +.Ar count +times. +.Pp +.It Xo +.Op Ar count +.Cm - +.Xc +Move to the first non-blank character of the previous line, +.Ar count +times. +.Pp +.It Xo +.Op Ar count +.Cm .\& +.Xc +Repeat the last +.Nm vi +command that modified text. +.Ar count +replaces both the +.Ar count +argument of the repeated command and that of the associated +.Ar motion . +If the +.Cm .\& +command repeats the +.Cm u +command, the change log is rolled forward or backward, depending on the action +of the +.Cm u +command. +.Pp +.It Xo +.Pf / Ns Ar RE +.Aq Li carriage-return +.Xc +.It Xo +.Pf / Ns Ar RE Ns / +.Op Ar offset +.Op Cm z +.Aq Li carriage-return +.Xc +.It Xo +.Pf ?\& Ns Ar RE +.Aq Li carriage-return +.Xc +.It Xo +.Pf ?\& Ns Ar RE Ns ?\& +.Op Ar offset +.Op Cm z +.Aq Li carriage-return +.Xc +.It Cm N +.It Cm n +Search forward +.Pq Sq / +or backward +.Pq Sq ?\& +for a regular expression. +.Cm n +and +.Cm N +repeat the last search in the same or opposite directions, respectively. +If +.Ar RE +is empty, the last search regular expression is used. +If +.Ar offset +is specified, the cursor is placed +.Ar offset +lines before or after the matched regular expression. +If either +.Cm n +or +.Cm N +commands are used as motion components for the +.Cm !\& +command, there will be no prompt for the text of the command and the previous +.Cm !\& +will be executed. +Multiple search patterns may be grouped together by delimiting them with +semicolons and zero or more whitespace characters. +These patterns are evaluated from left to right with the final cursor position +determined by the last search pattern. +A +.Cm z +command may be appended to the closed search expressions to reposition the +result line. +.Pp +.It Cm 0 +Move to the first character in the current line. +.Pp +.It Cm :\& +Execute an +.Nm ex +command. +.Pp +.It Xo +.Op Ar count +.Cm ;\& +.Xc +Repeat the last character find +(i.e., the last +.Cm F , f , T +or +.Cm t +command) +.Ar count +times. +.Pp +.It Xo +.Op Ar count +.Cm < +.Ar motion +.Xc +.It Xo +.Op Ar count +.Cm > +.Ar motion +.Xc +Shift +.Ar count +lines left or right, respectively, by an amount of +.Cm shiftwidth . +.Pp +.It Cm @ Ar buffer +Execute a named +.Ar buffer +as +.Nm vi +commands. +The buffer may include +.Nm ex +commands too, but they must be expressed as a +.Cm \&: +command. +If +.Ar buffer +is +.Sq @ +or +.Sq * , +then the last buffer executed shall be used. +.Pp +.It Xo +.Op Ar count +.Cm A +.Xc +Enter input mode, appending the text after the end of the line. +If a +.Ar count +argument is given, the characters input are repeated +.Ar count +\(mi 1 times after input mode is exited. +.Pp +.It Xo +.Op Ar count +.Cm B +.Xc +Move backwards +.Ar count +bigwords. +.Pp +.It Xo +.Op Ar buffer +.Cm C +.Xc +Change text from the current position to the end-of-line. +If +.Ar buffer +is specified, +.Dq yank +the deleted text into +.Ar buffer . +.Pp +.It Xo +.Op Ar buffer +.Cm D +.Xc +Delete text from the current position to the end-of-line. +If +.Ar buffer +is specified, +.Dq yank +the deleted text into +.Ar buffer . +.Pp +.It Xo +.Op Ar count +.Cm E +.Xc +Move forward +.Ar count +end-of-bigwords. +.Pp +.It Xo +.Op Ar count +.Cm F Aq Ar character +.Xc +Search +.Ar count +times backward through the current line for +.Aq Ar character . +.Pp +.It Xo +.Op Ar count +.Cm G +.Xc +Move to line +.Ar count , +or the last line of the file if +.Ar count +is not specified. +.Pp +.It Xo +.Op Ar count +.Cm H +.Xc +Move to the screen line +.Ar count +\(mi 1 lines below the top of the screen. +.Pp +.It Xo +.Op Ar count +.Cm I +.Xc +Enter input mode, inserting the text at the beginning of the line. +If a +.Ar count +argument is given, +the characters input are repeated +.Ar count +\(mi 1 more times. +.Pp +.It Xo +.Op Ar count +.Cm J +.Xc +Join +.Ar count +lines with the current line. +The spacing between two joined lines is set to two whitespace characters if the +former ends with a question mark, a period or an exclamation point. +It is set to one whitespace character otherwise. +.Pp +.It Xo +.Op Ar count +.Cm L +.Xc +Move to the screen line +.Ar count +\(mi 1 lines above the bottom of the screen. +.Pp +.It Cm M +Move to the screen line in the middle of the screen. +.Pp +.It Xo +.Op Ar count +.Cm O +.Xc +Enter input mode, appending text in a new line above the current line. +If a +.Ar count +argument is given, +the characters input are repeated +.Ar count +\(mi 1 more times. +.Pp +.It Xo +.Op Ar buffer +.Cm P +.Xc +Insert text from +.Ar buffer +before the current column if +.Ar buffer +is character-oriented or before the current line if it is line-oriented. +.Pp +.It Cm Q +Exit +.Nm vi +.Pq or visual +mode and switch to +.Nm ex +mode. +.Pp +.It Xo +.Op Ar count +.Cm R +.Xc +Enter input mode, replacing the characters in the current line. +If a +.Ar count +argument is given, +the characters input are repeated +.Ar count +\(mi 1 more times upon exit from insert mode. +.Pp +.It Xo +.Op Ar buffer +.Op Ar count +.Cm S +.Xc +Substitute +.Ar count +lines. +If +.Ar buffer +is specified, +.Dq yank +the deleted text into +.Ar buffer . +.Pp +.It Xo +.Op Ar count +.Cm T +.Aq Ar character +.Xc +Search backwards, +.Ar count +times, through the current line for the character after the specified +.Aq Ar character . +.Pp +.It Cm U +Restore the current line to its state before the cursor last moved to it. +.Pp +.It Xo +.Op Ar count +.Cm W +.Xc +Move forward +.Ar count +bigwords. +.Pp +.It Xo +.Op Ar buffer +.Op Ar count +.Cm X +.Xc +Delete +.Ar count +characters before the cursor, on the current line. +If +.Ar buffer +is specified, +.Dq yank +the deleted text into +.Ar buffer . +.Pp +.It Xo +.Op Ar buffer +.Op Ar count +.Cm Y +.Xc +Copy +.Pq or Dq yank +.Ar count +lines into +.Ar buffer . +.Pp +.It Cm ZZ +Write the file and exit +.Nm vi +if there are no more files to edit. +Entering two +.Dq quit +commands in a row ignores any remaining file to edit. +.Pp +.It Xo +.Op Ar count +.Cm [[ +.Xc +Back up +.Ar count +section boundaries. +.Pp +.It Xo +.Op Ar count +.Cm ]] +.Xc +Move forward +.Ar count +section boundaries. +.Pp +.It Cm \(ha +Move to the first non-blank character on the current line. +.Pp +.It Xo +.Op Ar count +.Cm _ +.Xc +Move down +.Ar count +\(mi 1 lines, to the first non-blank character. +.Pp +.It Xo +.Op Ar count +.Cm a +.Xc +Enter input mode, appending the text after the cursor. +If a +.Ar count +argument is given, +the characters input are repeated +.Ar count +number of times. +.Pp +.It Xo +.Op Ar count +.Cm b +.Xc +Move backwards +.Ar count +words. +.Pp +.It Xo +.Op Ar buffer +.Op Ar count +.Cm c +.Ar motion +.Xc +Change the region of text described by +.Ar count +and +.Ar motion . +If +.Ar buffer +is specified, +.Dq yank +the changed text into +.Ar buffer . +.Pp +.It Xo +.Op Ar buffer +.Op Ar count +.Cm d +.Ar motion +.Xc +Delete the region of text described by +.Ar count +and +.Ar motion . +If +.Ar buffer +is specified, +.Dq yank +the deleted text into +.Ar buffer . +.Pp +.It Xo +.Op Ar count +.Cm e +.Xc +Move forward +.Ar count +end-of-words. +.Pp +.It Xo +.Op Ar count +.Cm f Aq Ar character +.Xc +Search forward, +.Ar count +times, through the rest of the current line for +.Aq Ar character . +.Pp +.It Xo +.Op Ar count +.Cm i +.Xc +Enter input mode, inserting the text before the cursor. +If a +.Ar count +argument is given, +the characters input are repeated +.Ar count +number of times. +.Pp +.It Xo +.Cm m +.Aq Ar character +.Xc +Save the current context +.Pq line and column +as +.Aq Ar character . +.Pp +.It Xo +.Op Ar count +.Cm o +.Xc +Enter input mode, appending text in a new line under the current line. +If a +.Ar count +argument is given, +the characters input are repeated +.Ar count +\(mi 1 more times. +.Pp +.It Xo +.Op Ar buffer +.Cm p +.Xc +Append text from +.Ar buffer . +Text is appended after the current column if +.Ar buffer +is character oriented, or after the current line otherwise. +.Pp +.It Xo +.Op Ar count +.Cm r +.Aq Ar character +.Xc +Replace +.Ar count +characters with +.Ar character . +.Pp +.It Xo +.Op Ar buffer +.Op Ar count +.Cm s +.Xc +Substitute +.Ar count +characters in the current line starting with the current character. +If +.Ar buffer +is specified, +.Dq yank +the substituted text into +.Ar buffer . +.Pp +.It Xo +.Op Ar count +.Cm t +.Aq Ar character +.Xc +Search forward, +.Ar count +times, through the current line for the character immediately before +.Aq Ar character . +.Pp +.It Cm u +Undo the last change made to the file. +If repeated, the +.Cm u +command alternates between these two states. +The +.Cm .\& +command, when used immediately after +.Cm u , +causes the change log to be rolled forward or backward, depending on the action +of the +.Cm u +command. +.Pp +.It Xo +.Op Ar count +.Cm w +.Xc +Move forward +.Ar count +words. +.Pp +.It Xo +.Op Ar buffer +.Op Ar count +.Cm x +.Xc +Delete +.Ar count +characters at the current cursor position, but no more than there are till the +end of the line. +.Pp +.It Xo +.Op Ar buffer +.Op Ar count +.Cm y +.Ar motion +.Xc +Copy +.Pq or Dq yank +a text region specified by +.Ar count +and +.Ar motion +into a buffer. +.Pp +.It Xo +.Op Ar count1 +.Cm z +.Op Ar count2 +.Cm type +.Xc +Redraw, optionally repositioning and resizing the screen. +If +.Ar count2 +is specified, limit the screen size to +.Ar count2 +lines. +The following +.Cm type +characters may be used: +.Bl -tag -width Ds +.It Cm + +If +.Ar count1 +is specified, place the line +.Ar count1 +at the top of the screen. +Otherwise, display the screen after the current screen. +.It Aq Cm carriage-return +Place the line +.Ar count1 +at the top of the screen. +.It Cm .\& +Place the line +.Ar count1 +in the center of the screen. +.It Cm - +Place the line +.Ar count1 +at the bottom of the screen. +.It Cm \(ha +If +.Ar count1 +is given, +display the screen before the screen before +.Ar count1 +.Pq i.e., 2 screens before . +Otherwise, display the screen before the current screen. +.El +.Pp +.It Xo +.Op Ar count +.Cm {\& +.Xc +Move backward +.Ar count +paragraphs. +.Pp +.It Xo +.Op Ar column +.Cm |\& +.Xc +Move to a specific +.Ar column +position on the current line. +If +.Ar column +is omitted, +move to the start of the current line. +.Pp +.It Xo +.Op Ar count +.Cm }\& +.Xc +Move forward +.Ar count +paragraphs. +.Pp +.It Xo +.Op Ar count +.Cm \(ti +.Ar motion +.Xc +If the +.Cm tildeop +option is not set, reverse the case of the next +.Ar count +character(s) and no +.Ar motion +can be specified. +Otherwise +.Ar motion +is mandatory and +.Cm \(ti +reverses the case of the characters in a text region specified by the +.Ar count +and +.Ar motion . +.Pp +.It Aq Cm interrupt +Interrupt the current operation. +The +.Aq interrupt +character is usually +.Aq control-C . +.El +.Sh VI TEXT INPUT COMMANDS +The following section describes the commands available in the text input mode +of the +.Nm vi +editor. +.Pp +.Bl -tag -width Ds -compact +.It Aq Cm nul +Replay the previous input. +.Pp +.It Aq Cm control-D +Erase to the previous +.Ar shiftwidth +column boundary. +.Pp +.It Cm \(ha Ns Aq Cm control-D +Erase all of the autoindent characters, and reset the autoindent level. +.Pp +.It Cm 0 Ns Aq Cm control-D +Erase all of the autoindent characters. +.Pp +.It Aq Cm control-T +Insert sufficient +.Aq tab +and +.Aq space +characters to move forward to the next +.Ar shiftwidth +column boundary. +If the +.Cm expandtab +option is set, only insert +.Aq space +characters. +.Pp +.It Aq Cm erase +.It Aq Cm control-H +Erase the last character. +.Pp +.It Aq Cm literal next +Escape the next character from any special meaning. +The +.Aq literal\ \&next +character is usually +.Aq control-V . +.Pp +.It Aq Cm escape +Resolve all text input into the file, and return to command mode. +.Pp +.It Aq Cm line erase +Erase the current line. +.Pp +.It Aq Cm control-W +.It Aq Cm word erase +Erase the last word. +The definition of word is dependent on the +.Cm altwerase +and +.Cm ttywerase +options. +.Pp +.Sm off +.It Xo +.Aq Cm control-X +.Bq Cm 0-9A-Fa-f +.Cm + +.Xc +.Sm on +Insert a character with the specified hexadecimal value into the text. +.Pp +.It Aq Cm interrupt +Interrupt text input mode, returning to command mode. +The +.Aq interrupt +character is usually +.Aq control-C . +.El +.Sh EX COMMANDS +The following section describes the commands available in the +.Nm ex +editor. +In each entry below, the tag line is a usage synopsis for the command. +.Pp +.Bl -tag -width Ds -compact +.It Aq Cm end-of-file +Scroll the screen. +.Pp +.It Cm !\& Ar argument(s) +.It Xo +.Op Ar range +.Cm !\& +.Ar argument(s) +.Xc +Execute a shell command, or filter lines through a shell command. +.Pp +.It Cm \&" +A comment. +.Pp +.It Xo +.Op Ar range +.Cm nu Ns Op Cm mber +.Op Ar count +.Op Ar flags +.Xc +.It Xo +.Op Ar range +.Cm # +.Op Ar count +.Op Ar flags +.Xc +Display the selected lines, each preceded with its line number. +.Pp +.It Cm @ Ar buffer +.It Cm * Ar buffer +Execute a buffer. +.Pp +.It Xo +.Op Ar range +.Cm < Ns Op Cm < ... +.Op Ar count +.Op Ar flags +.Xc +Shift lines left. +.Pp +.It Xo +.Op Ar line +.Cm = +.Op Ar flags +.Xc +Display the line number of +.Ar line . +If +.Ar line +is not specified, display the line number of the last line in the file. +.Pp +.It Xo +.Op Ar range +.Cm > Ns Op Cm > ... +.Op Ar count +.Op Ar flags +.Xc +Shift lines right. +.Pp +.It Xo +.Cm ab Ns Op Cm breviate +.Ar lhs rhs +.Xc +.Nm vi +only. +Add +.Ar lhs +as an abbreviation for +.Ar rhs +to the abbreviation list. +.Pp +.It Xo +.Op Ar line +.Cm a Ns Op Cm ppend Ns +.Op Cm !\& +.Xc +The input text is appended after the specified line. +.Pp +.It Cm ar Ns Op Cm gs +Display the argument list. +.Pp +.It Cm bg +.Nm vi +only. +Background the current screen. +.Pp +.It Xo +.Op Ar range +.Cm c Ns Op Cm hange Ns +.Op Cm !\& +.Op Ar count +.Xc +The input text replaces the specified range. +.Pp +.It Xo +.Cm chd Ns Op Cm ir Ns +.Op Cm !\& +.Op Ar directory +.Xc +.It Xo +.Cm cd Ns Op Cm !\& +.Op Ar directory +.Xc +Change the current working directory. +.Pp +.It Xo +.Op Ar range +.Cm co Ns Op Cm py +.Ar line +.Op Ar flags +.Xc +.It Xo +.Op Ar range +.Cm t +.Ar line +.Op Ar flags +.Xc +Copy the specified lines after the destination +.Ar line . +.Pp +.It Xo +.Cm cs Ns Op Cm cope +.Cm add | find | help | kill | reset +.Xc +Execute a Cscope command. +.Pp +.It Xo +.Op Ar range +.Cm d Ns Op Cm elete +.Op Ar buffer +.Op Ar count +.Op Ar flags +.Xc +Delete the lines from the file. +.Pp +.It Xo +.Cm di Ns Op Cm splay +.Cm b Ns Oo Cm uffers Oc | +.Cm c Ns Oo Cm onnections Oc | +.Cm s Ns Oo Cm creens Oc | +.Cm t Ns Op Cm ags +.Xc +Display buffers, Cscope connections, screens or tags. +.Pp +.It Xo +.Op Cm Ee Ns +.Op Cm dit Ns +.Op Cm !\& +.Op Ar +cmd +.Op Ar file +.Xc +.It Xo +.Op Cm Ee Ns +.Cm x Ns Op Cm !\& +.Op Ar +cmd +.Op Ar file +.Xc +Edit a different file. +.Pp +.It Xo +.Cm exu Ns Op Cm sage +.Op Ar command +.Xc +Display usage for an +.Nm ex +command. +.Pp +.It Xo +.Cm f Ns Op Cm ile +.Op Ar file +.Xc +Display and optionally change the file name. +.Pp +.It Xo +.Op Cm Ff Ns +.Cm g +.Op Ar name +.Xc +.Nm vi +mode only. +Foreground the specified screen. +.Pp +.It Xo +.Op Ar range +.Cm g Ns Op Cm lobal +.No / Ns Ar pattern Ns / +.Op Ar commands +.Xc +.It Xo +.Op Ar range +.Cm v +.No / Ns Ar pattern Ns / +.Op Ar commands +.Xc +Apply commands to lines matching +.Pq Sq global +or not matching +.Pq Sq v +a pattern. +.Pp +.It Cm he Ns Op Cm lp +Display a help message. +.Pp +.It Xo +.Op Ar line +.Cm i Ns Op Cm nsert Ns +.Op Cm !\& +.Xc +The input text is inserted before the specified line. +.Pp +.It Xo +.Op Ar range +.Cm j Ns Op Cm oin Ns +.Op Cm !\& +.Op Ar count +.Op Ar flags +.Xc +Join lines of text together. +.Pp +.It Xo +.Op Ar range +.Cm l Ns Op Cm ist +.Op Ar count +.Op Ar flags +.Xc +Display the lines unambiguously. +.Pp +.It Xo +.Cm map Ns Op Cm !\& +.Op Ar lhs rhs +.Xc +Define or display maps +.Pq for Nm vi No only . +.Pp +.It Xo +.Op Ar line +.Cm ma Ns Op Cm rk +.Aq Ar character +.Xc +.It Xo +.Op Ar line +.Cm k Aq Ar character +.Xc +Mark the line with the mark +.Aq Ar character . +.Pp +.It Xo +.Op Ar range +.Cm m Ns Op Cm ove +.Ar line +.Xc +Move the specified lines after the target line. +.Pp +.It Xo +.Cm mk Ns Op Cm exrc Ns +.Op Cm !\& +.Ar file +.Xc +Write the abbreviations, editor options and maps to the specified +.Ar file . +.Pp +.It Xo +.Op Cm Nn Ns +.Op Cm ext Ns +.Op Cm !\& +.Op Ar +.Xc +Edit the next file from the argument list. +.\" .Pp +.\" .It Xo +.\" .Op Ar line +.\" .Cm o Ns Op Cm pen +.\" .No / Ns Ar pattern Ns / +.\" .Op Ar flags +.\" .Xc +.\" Enter open mode. +.Pp +.It Cm pre Ns Op Cm serve +Save the file in a form that can later be recovered using the +.Nm ex +.Fl r +option. +.Pp +.It Xo +.Op Cm \&Pp Ns +.Cm rev Ns Op Cm ious Ns +.Op Cm !\& +.Xc +Edit the previous file from the argument list. +.Pp +.It Xo +.Op Ar range +.Cm p Ns Op Cm rint +.Op Ar count +.Op Ar flags +.Xc +Display the specified lines. +.Pp +.It Xo +.Op Ar line +.Cm pu Ns Op Cm t +.Op Ar buffer +.Xc +Append buffer contents to the current line. +.Pp +.It Xo +.Cm q Ns Op Cm uit Ns +.Op Cm !\& +.Xc +End the editing session. +.Pp +.It Xo +.Op Ar line +.Cm r Ns Op Cm ead Ns +.Op Cm !\& +.Op Ar file +.Xc +Read a file. +.Pp +.It Xo +.Cm rec Ns Op Cm over +.Ar file +.Xc +Recover +.Ar file +if it was previously saved. +.Pp +.It Xo +.Cm res Ns Op Cm ize +.Op Cm + Ns | Ns Cm - Ns +.Ar size +.Xc +.Nm vi +mode only. +Grow or shrink the current screen. +.Pp +.It Xo +.Cm rew Ns Op Cm ind Ns +.Op Cm !\& +.Xc +Rewind the argument list. +.Pp +.It Xo +.Cm se Ns Op Cm t +.Sm off +.Op option Oo = Oo value Oc Oc \ \&... +.Sm on +.Pf \ \& Op nooption ... +.Op option? ... +.Op Ar all +.Xc +Display or set editor options. +.Pp +.It Cm sh Ns Op Cm ell +Run a shell program. +.Pp +.It Xo +.Cm so Ns Op Cm urce +.Ar file +.Xc +Read and execute +.Nm ex +commands from a file. +.Pp +.It Xo +.Op Ar range +.Cm s Ns Op Cm ubstitute +.Sm off +.Op / Ar pattern No / Ar replace No / +.Sm on +.Pf \ \& Op Ar options +.Op Ar count +.Op Ar flags +.Xc +.It Xo +.Op Ar range +.Cm & +.Op Ar options +.Op Ar count +.Op Ar flags +.Xc +.It Xo +.Op Ar range +.Cm \(ti +.Op Ar options +.Op Ar count +.Op Ar flags +.Xc +Make substitutions. +The +.Ar replace +field may contain any of the following sequences: +.Bl -tag -width Ds +.It Sq \*(Am +The text matched by +.Ar pattern . +.It Sq \(ti +The replacement part of the previous +.Cm substitute +command. +.It Sq % +If this is the entire +.Ar replace +pattern, the replacement part of the previous +.Cm substitute +command. +.It Sq \e Ns Ar \(sh +Where +.Sq Ar \(sh +is an integer from 1 to 9, the text matched by the +.Ar # Ns 'th subexpression in +.Ar pattern . +.It Sq \eL +Causes the characters up to the end of the line of the next occurrence of +.Sq \eE +or +.Sq \ee +to be converted to lowercase. +.It Sq \el +Causes the next character to be converted to lowercase. +.It Sq \eU +Causes the characters up to the end of the line of the next occurrence of +.Sq \eE +or +.Sq \ee +to be converted to uppercase. +.It Sq \eu +Causes the next character to be converted to uppercase. +.El +.Pp +.It Xo +.Cm su Ns Op Cm spend Ns +.Op Cm !\& +.Xc +.It Xo +.Cm st Ns Op Cm op Ns +.Op Cm !\& +.Xc +.It Aq Cm suspend +Suspend the edit session. +The +.Aq suspend +character is usually +.Aq control-Z . +.Pp +.It Xo +.Op Cm Tt Ns +.Cm a Ns Op Cm g Ns +.Op Cm !\& +.Ar tagstring +.Xc +Edit the file containing the specified tag. +.Pp +.It Xo +.Cm tagn Ns Op Cm ext Ns +.Op Cm !\& +.Xc +Edit the file containing the next context for the current tag. +.Pp +.It Xo +.Cm tagp Ns Op Cm op Ns +.Op Cm !\& +.Op Ar file | number +.Xc +Pop to the specified tag in the tags stack. +.Pp +.It Xo +.Cm tagpr Ns Op Cm ev Ns +.Op Cm !\& +.Xc +Edit the file containing the previous context for the current tag. +.Pp +.It Xo +.Cm tagt Ns Op Cm op Ns +.Op Cm !\& +.Xc +Pop to the least recent tag on the tags stack, clearing the stack. +.Pp +.It Xo +.Cm una Ns Op Cm bbreviate +.Ar lhs +.Xc +.Nm vi +only. +Delete an abbreviation. +.Pp +.It Cm u Ns Op Cm ndo +Undo the last change made to the file. +.Pp +.It Xo +.Cm unm Ns Op Cm ap Ns +.Op Cm !\& +.Ar lhs +.Xc +Unmap a mapped string. +.Pp +.It Cm ve Ns Op Cm rsion +Display the version of the +.Nm ex Ns / Ns Nm vi +editor. +.Pp +.It Xo +.Op Ar line +.Cm vi Ns Op Cm sual +.Op Ar type +.Op Ar count +.Op Ar flags +.Xc +.Nm ex +mode only. +Enter +.Nm vi . +.Pp +.It Xo +.Op Cm Vi Ns +.Cm i Ns Op Cm sual Ns +.Op Cm !\& +.Op Ar +cmd +.Op Ar file +.Xc +.Nm vi +mode only. +Edit a new file. +.Pp +.It Xo +.Cm viu Ns Op Cm sage +.Op Ar command +.Xc +Display usage for a +.Nm vi +command. +.Pp +.It Xo +.Op Ar range +.Cm w Ns Op Cm rite Ns +.Op Cm !\& +.Op >> +.Op Ar file +.Xc +.It Xo +.Op Ar range +.Cm w Ns Op Cm rite +.Op Cm !\& +.Op Ar file +.Xc +.It Xo +.Op Ar range +.Cm wn Ns Op Cm !\& +.Op >> +.Op Ar file +.Xc +.It Xo +.Op Ar range +.Cm wq Ns Op Cm !\& +.Op >> +.Op Ar file +.Xc +Write the file. +.Pp +.It Xo +.Op Ar range +.Cm x Ns Op Cm it Ns +.Op Cm !\& +.Op Ar file +.Xc +Exit the editor, +writing the file if it has been modified. +.Pp +.It Xo +.Op Ar range +.Cm ya Ns Op Cm nk +.Op Ar buffer +.Op Ar count +.Xc +Copy the specified lines to a buffer. +.Pp +.It Xo +.Op Ar line +.Cm z +.Op Ar type +.Op Ar count +.Op Ar flags +.Xc +Adjust the window. +.El +.Sh SET OPTIONS +There are a large number of options that may be set +.Pq or unset +to change the editor's behavior. +This section describes the options, their abbreviations and their +default values. +.Pp +In each entry below, the first part of the tag line is the full name +of the option, followed by any equivalent abbreviations. +The part in square brackets is the default value of the option. +Most of the options are boolean, i.e., they are either on or off, +and do not have an associated value. +.Pp +Options apply to both +.Nm ex +and +.Nm vi +modes, unless otherwise specified. +.Bl -tag -width Ds +.It Cm altwerase Bq off +.Nm vi +only. +Select an alternate word erase algorithm. +.It Cm autoindent , ai Bq off +Automatically indent new lines. +.It Cm autoprint , ap Bq on +.Nm ex +only. +Display the current line automatically. +.It Cm autowrite , aw Bq off +Write modified files automatically when changing files or suspending the editor +session. +.It Cm backup Bq \&"\&" +Back up files before they are overwritten. +.It Cm beautify , bf Bq off +Discard control characters. +.It Cm cdpath Bo environment variable Ev CDPATH , or current directory Bc +The directory paths used as path prefixes for the +.Cm cd +command. +.It Cm cedit Bq no default +Set the character to edit the colon command-line history. +.It Cm columns , co Bq 80 +Set the number of columns in the screen. +.It Cm comment Bq off +.Nm vi +only. +Skip leading comments in shell, C and C++ language files. +.It Cm directory , dir Bo environment variable Ev TMPDIR , or Pa /tmp Bc +The directory where temporary files are created. +.It Cm edcompatible , ed Bq off +Remember the values of the +.Sq c +and +.Sq g +suffixes to the +.Cm substitute +commands, instead of initializing them as unset for each new command. +.It Cm errorbells , eb Bq off +.Nm ex +only. +Announce error messages with a bell. +.It Cm escapetime Bq 1 +The tenths of a second +.Nm ex Ns / Ns Nm vi +waits for a subsequent key to complete an +.Aq escape +key mapping. +.It Cm expandtab , et Bq off +Expand +.Aq tab +characters to +.Aq space +when inserting, replacing or shifting text, autoindenting, +indenting with +.Aq Ic control-T , +outdenting with +.Aq Ic control-D , +or +when filtering lines with the +.Cm !\& +command. +.It Cm exrc , ex Bq off +Read the startup files in the local directory. +.It Cm extended Bq off +Use extended regular expressions +.Pq EREs +rather than basic regular expressions +.Pq BREs . +See +.Xr re_format 7 +for more information on regular expressions. +.It Cm filec Bq Aq tab +Set the character to perform file path completion on the colon command line. +.It Cm fileencoding , fe Bq auto detect +Set the encoding of the current file. +.It Cm flash Bq on +Flash the screen instead of beeping the keyboard on error. +.It Cm hardtabs, ht Bq 0 +Set the spacing between hardware tab settings. +This option currently has no effect. +.It Cm iclower Bq off +Makes all regular expressions case-insensitive, +as long as an upper-case letter does not appear in the search string. +.It Cm ignorecase , ic Bq off +Ignore case differences in regular expressions. +.It Cm inputencoding , ie Bq locale +Set the encoding of your input characters. +.It Cm keytime Bq 6 +The tenths of a second +.Nm ex Ns / Ns Nm vi +waits for a subsequent key to complete a key mapping. +.It Cm leftright Bq off +.Nm vi +only. +Do left-right scrolling. +.It Cm lines , li Bq 24 +.Nm vi +only. +Set the number of lines in the screen. +.It Cm lisp Bq off +.Nm vi +only. +Modify various search commands and options to work with Lisp. +This option is not yet implemented. +.It Cm list Bq off +Display lines in an unambiguous fashion. +.It Cm lock Bq on +Attempt to get an exclusive lock on any file being edited, read or written. +.It Cm magic Bq on +When turned off, all regular expression characters except for +.Sq \(ha +and +.Sq \(Do +are treated as ordinary characters. +Preceding individual characters by +.Sq \e +re-enables them. +.It Cm matchchars Bq []{}() +Character pairs looked for by the +.Cm % +command. +.It Cm matchtime Bq 7 +.Nm vi +only. +The tenths of a second +.Nm ex Ns / Ns Nm vi +pauses on the matching character when the +.Cm showmatch +option is set. +.It Cm mesg Bq on +Permit messages from other users. +.It Cm msgcat Bq /usr/share/vi/catalog/ +Selects a message catalog to be used to display error and informational +messages in a specified language. +.It Cm modelines , modeline Bq off +Read the first and last few lines of each file for +.Nm ex +commands. +This option will never be implemented. +.It Cm noprint Bq \&"\&" +Characters that are never handled as printable characters. +.It Cm number , nu Bq off +Precede each line displayed with its current line number. +.It Cm octal Bq off +Display unknown characters as octal numbers, instead of the default +hexadecimal. +.It Cm open Bq on +.Nm ex +only. +If this option is not set, the +.Cm open +and +.Cm visual +commands are disallowed. +.It Cm optimize , opt Bq on +.Nm vi +only. +Optimize text throughput to dumb terminals. +This option is not yet implemented. +.It Cm paragraphs , para Bq "IPLPPPQPP LIpplpipbp" +.Nm vi +only. +Define additional paragraph boundaries for the +.Cm {\& +and +.Cm }\& +commands. +.It Cm path Bq \&"\&" +Define additional directories to search for files being edited. +.It Cm print Bq \&"\&" +Characters that are always handled as printable characters. +.It Cm prompt Bq on +.Nm ex +only. +Display a command prompt. +.It Cm readonly , ro Bq off +Mark the file and session as read-only. +.It Cm recdir Bq /var/tmp/vi.recover +The directory where recovery files are stored. +.It Cm redraw , re Bq off +.Nm vi +only. +Simulate an intelligent terminal on a dumb one. +This option is not yet implemented. +.It Cm remap Bq on +Remap keys until resolved. +.It Cm report Bq 5 +Set the number of lines about which the editor reports changes or yanks. +.It Cm ruler Bq off +.Nm vi +only. +Display a row/column ruler on the colon command line. +.It Cm scroll , scr Bq "window size / 2" +Set the number of lines scrolled. +.It Cm searchincr Bq off +Makes the +.Cm / +and +.Cm ?\& +commands incremental. +.It Cm sections , sect Bq "NHSHH HUnhsh" +.Nm vi +only. +Define additional section boundaries for the +.Cm [[ +and +.Cm ]] +commands. +.It Cm secure Bq off +Turns off all access to external programs. +.It Cm shell , sh Bo environment variable Ev SHELL , or Pa /bin/sh Bc +Select the shell used by the editor. +.It Cm shellmeta Bq \(ti{[*?$\`\(aq\&"\e +Set the meta characters checked to determine if file name expansion +is necessary. +.It Cm shiftwidth , sw Bq 8 +Set the autoindent and shift command indentation width. +.It Cm showmatch , sm Bq off +.Nm vi +only. +Note the left matching characters when the right ones are inserted. +.It Cm showmode , smd Bq off +.Nm vi +only. +Display the current editor mode and a +.Dq modified +flag. +.It Cm sidescroll Bq 16 +.Nm vi +only. +Set the amount a left-right scroll will shift. +.It Cm slowopen , slow Bq off +Delay display updating during text input. +This option is not yet implemented. +.It Cm sourceany Bq off +Read startup files not owned by the current user. +This option will never be implemented. +.It Cm tabstop , ts Bq 8 +This option sets tab widths for the editor display. +.It Cm taglength , tl Bq 0 +Set the number of significant characters in tag names. +.It Cm tags , tag Bq tags +Set the list of tags files. +.It Xo +.Cm term , ttytype , tty +.Bq environment variable Ev TERM +.Xc +Set the terminal type. +.It Cm terse Bq off +This option has historically made editor messages less verbose. +It has no effect in this implementation. +.It Cm tildeop Bq off +Modify the +.Cm \(ti +command to take an associated motion. +.It Cm timeout , to Bq on +Time out on keys which may be mapped. +.It Cm ttywerase Bq off +.Nm vi +only. +Select an alternate erase algorithm. +.It Cm verbose Bq off +.Nm vi +only. +Display an error message for every error. +.It Cm w300 Bq no default +.Nm vi +only. +Set the window size if the baud rate is less than 1200 baud. +.It Cm w1200 Bq no default +.Nm vi +only. +Set the window size if the baud rate is equal to 1200 baud. +.It Cm w9600 Bq no default +.Nm vi +only. +Set the window size if the baud rate is greater than 1200 baud. +.It Cm warn Bq on +.Nm ex +only. +This option causes a warning message to be printed on the terminal +if the file has been modified since it was last written, before a +.Cm !\& +command. +.It Xo +.Cm window , w , wi +.Bq environment variable Ev LINES No \(mi 1 +.Xc +Set the window size for the screen. +.It Cm windowname Bq off +Change the icon/window name to the current file name. +.It Cm wraplen , wl Bq 0 +.Nm vi +only. +Break lines automatically, +the specified number of columns from the left-hand margin. +If both the +.Cm wraplen +and +.Cm wrapmargin +edit options are set, the +.Cm wrapmargin +value is used. +.It Cm wrapmargin , wm Bq 0 +.Nm vi +only. +Break lines automatically, +the specified number of columns from the right-hand margin. +If both the +.Cm wraplen +and +.Cm wrapmargin +edit options are set, the +.Cm wrapmargin +value is used. +.It Cm wrapscan , ws Bq on +Set searches to wrap around the end or beginning of the file. +.It Cm writeany , wa Bq off +Turn off file-overwriting checks. +.El +.Sh ENVIRONMENT +.Bl -tag -width "COLUMNS" +.It Ev COLUMNS +The number of columns on the screen. +This value overrides any system or terminal specific values. +If the +.Ev COLUMNS +environment variable is not set when +.Nm ex Ns / Ns Nm vi +runs, or the +.Cm columns +option is explicitly reset by the user, +.Nm ex Ns / Ns Nm vi +enters the value into the environment. +.It Ev EXINIT +A list of +.Nm ex +startup commands, read after +.Pa /etc/vi.exrc +unless the variable +.Ev NEXINIT +is also set. +.It Ev HOME +The user's home directory, used as the initial directory path for the startup +.Pa $HOME/.nexrc +and +.Pa $HOME/.exrc +files. +This value is also used as the default directory for the +.Cm cd +command. +.It Ev LINES +The number of rows on the screen. +This value overrides any system or terminal specific values. +If the +.Ev LINES +environment variable is not set when +.Nm ex Ns / Ns Nm vi +runs, or the +.Cm lines +option is explicitly reset by the user, +.Nm ex Ns / Ns Nm vi +enters the value into the environment. +.It Ev NEXINIT +A list of +.Nm ex +startup commands, read after +.Pa /etc/vi.exrc . +.It Ev SHELL +The user's shell of choice +.Pq see also the Cm shell No option . +.It Ev TERM +The user's terminal type. +The default is the type +.Dq unknown . +If the +.Ev TERM +environment variable is not set when +.Nm ex Ns / Ns Nm vi +runs, or the +.Cm term +option is explicitly reset by the user, +.Nm ex Ns / Ns Nm vi +enters the value into the environment. +.It Ev TMPDIR +The location used to store temporary files +.Pq see also the Cm directory No edit option . +.El +.Sh ASYNCHRONOUS EVENTS +.Bl -tag -width "SIGWINCH" -compact +.It Dv SIGALRM +.Nm vi Ns / Ns Nm ex +uses this signal for periodic backups of file modifications and to display +.Dq busy +messages when operations are likely to take a long time. +.Pp +.It Dv SIGHUP +.It Dv SIGTERM +If the current buffer has changed since it was last written in its entirety, +the editor attempts to save the modified file so it can be later recovered. +See the +.Nm vi Ns / Ns Nm ex +reference manual section +.Sx Recovery +for more information. +.Pp +.It Dv SIGINT +When an interrupt occurs, the current operation is halted +and the editor returns to the command level. +If interrupted during text input, +the text already input is resolved into the file as if the text +input had been normally terminated. +.Pp +.It Dv SIGWINCH +The screen is resized. +See the +.Nm vi Ns / Ns Nm ex +reference manual section +.Sx Sizing the Screen +for more information. +.\" .Pp +.\" .It Dv SIGCONT +.\" .It Dv SIGTSTP +.\" .Nm vi Ns / Ns Nm ex +.\" ignores these signals. +.El +.Sh FILES +.Bl -tag -width "/var/tmp/vi.recover" +.It Pa /bin/sh +The default user shell. +.It Pa /etc/vi.exrc +System-wide +.Nm vi +startup file. +It is read for +.Nm ex +commands first in the startup sequence. +Must be owned by root or the user, +and writable only by the owner. +.It Pa /tmp +Temporary file directory. +.It Pa /var/tmp/vi.recover +The default recovery file directory. +.It Pa $HOME/.nexrc +First choice for user's home directory startup file, read for +.Nm ex +commands right after +.Pa /etc/vi.exrc +unless either +.Ev NEXINIT +or +.Ev EXINIT +are set. +Must be owned by root or the user, +and writable only by the owner. +.It Pa $HOME/.exrc +Second choice for user's home directory startup file, read for +.Nm ex +commands under the same conditions as +.Pa $HOME/.nexrc . +.It Pa .nexrc +First choice for local directory startup file, read for +.Nm ex +commands at the end of the startup sequence if the +.Cm exrc +option was turned on earlier. +Must be owned by the user +and writable only by the owner. +.It Pa .exrc +Second choice for local directory startup file, read for +.Nm ex +commands under the same conditions as +.Pa .nexrc . +.El +.Sh EXIT STATUS +The +.Nm ex +and +.Nm vi +utilities exit 0 on success, +and \*(Gt0 if an error occurs. +.Sh SEE ALSO +.Xr ctags 1 , +.Xr iconv 1 , +.Xr re_format 7 +.Rs +.%T vi/ex reference manual +.%U https://docs.freebsd.org/44doc/usd/13.viref/paper.pdf +.Re +.Sh STANDARDS +.Nm nex Ns / Ns Nm nvi +is close to +.St -p1003.1-2008 . +That document differs from historical +.Nm ex Ns / Ns Nm vi +practice in several places; there are changes to be made on both sides. +.Sh HISTORY +The +.Nm ex +editor first appeared in +.Bx 1 . +The +.Nm nex Ns / Ns Nm nvi +replacements for the +.Nm ex Ns / Ns Nm vi +editor first appeared in +.Bx 4.4 . +.Sh AUTHORS +.An Bill Joy +wrote the original version of +.Nm ex +in 1977. Property changes on: vendor/nvi/2.2.0-05ed8b9/man/vi.1 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/regex/engine.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/regex/engine.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/regex/engine.c (revision 366308) @@ -0,0 +1,1036 @@ +/* $NetBSD: engine.c,v 1.7 2011/11/19 17:45:11 tnozaki Exp $ */ + +/*- + * Copyright (c) 1992, 1993, 1994 Henry Spencer. + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Henry Spencer of the University of Toronto. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)engine.c 8.4 (Berkeley) 3/19/94 + */ + +/* + * The matching engine and friends. This file is #included by regexec.c + * after suitable #defines of a variety of macros used herein, so that + * different state representations can be used without duplicating masses + * of code. + */ + +#ifdef SNAMES +#define matcher smatcher +#define fast sfast +#define slow sslow +#define dissect sdissect +#define backref sbackref +#define step sstep +#define print sprint +#define at sat +#define match smat +#endif +#ifdef LNAMES +#define matcher lmatcher +#define fast lfast +#define slow lslow +#define dissect ldissect +#define backref lbackref +#define step lstep +#define print lprint +#define at lat +#define match lmat +#endif + +/* another structure passed up and down to avoid zillions of parameters */ +struct match { + struct re_guts *g; + int eflags; + regmatch_t *pmatch; /* [nsub+1] (0 element unused) */ + const RCHAR_T *offp; /* offsets work from here */ + const RCHAR_T *beginp; /* start of string -- virtual NUL precedes */ + const RCHAR_T *endp; /* end of string -- virtual NUL here */ + const RCHAR_T *coldp; /* can be no match starting before here */ + const RCHAR_T **lastpos; /* [nplus+1] */ + STATEVARS; + states st; /* current states */ + states fresh; /* states for a fresh start */ + states tmp; /* temporary */ + states empty; /* empty set of states */ +}; + +/* ========= begin header generated by ./mkh ========= */ +#ifdef __cplusplus +extern "C" { +#endif + +/* === engine.c === */ +static int matcher(struct re_guts *g, const RCHAR_T *string, size_t nmatch, regmatch_t pmatch[], int eflags); +static const RCHAR_T *dissect(struct match *m, const RCHAR_T *start, const RCHAR_T *stop, sopno startst, sopno stopst); +static const RCHAR_T *backref(struct match *m, const RCHAR_T *start, const RCHAR_T *stop, sopno startst, sopno stopst, sopno lev); +static const RCHAR_T *fast(struct match *m, const RCHAR_T *start, const RCHAR_T *stop, sopno startst, sopno stopst); +static const RCHAR_T *slow(struct match *m, const RCHAR_T *start, const RCHAR_T *stop, sopno startst, sopno stopst); +static states step(struct re_guts *g, sopno start, sopno stop, states bef, int flag, RCHAR_T ch, states aft); +#define BOL (1) +#define EOL (BOL+1) +#define BOLEOL (BOL+2) +#define NOTHING (BOL+3) +#define BOW (BOL+4) +#define EOW (BOL+5) +#ifdef REDEBUG +static void print(struct match *m, char *caption, states st, int ch, FILE *d); +#endif +#ifdef REDEBUG +static void at(struct match *m, char *title, char *start, char *stop, sopno startst, sopno stopst); +#endif +#ifdef REDEBUG +static char *pchar(int ch); +#endif + +#ifdef __cplusplus +} +#endif +/* ========= end header generated by ./mkh ========= */ + +#ifdef REDEBUG +#define SP(t, s, c) print(m, t, s, c, stdout) +#define AT(t, p1, p2, s1, s2) at(m, t, p1, p2, s1, s2) +#define NOTE(str) do { if (m->eflags®_TRACE) printf("=%s\n", (str)); } while(0); +#else +#define SP(t, s, c) /* nothing */ +#define AT(t, p1, p2, s1, s2) /* nothing */ +#define NOTE(s) /* nothing */ +#endif + +/* + - matcher - the actual matching engine + */ +static int /* 0 success, REG_NOMATCH failure */ +matcher(struct re_guts *g, const RCHAR_T *string, size_t nmatch, + regmatch_t pmatch[], int eflags) +{ + const RCHAR_T *endp; + size_t i; + struct match mv; + struct match *m = &mv; + const RCHAR_T *dp; + const sopno gf = g->firststate+1; /* +1 for OEND */ + const sopno gl = g->laststate; + const RCHAR_T *start; + const RCHAR_T *stop; + + /* simplify the situation where possible */ + if (g->cflags®_NOSUB) + nmatch = 0; + if (eflags®_STARTEND) { + start = string + pmatch[0].rm_so; + stop = string + pmatch[0].rm_eo; + } else { + start = string; + stop = start + STRLEN(start); + } + if (stop < start) + return(REG_INVARG); + + /* prescreening; this does wonders for this rather slow code */ + if (g->must != NULL) { + for (dp = start; dp < stop; dp++) + if (*dp == g->must[0] && (size_t)(stop - dp) >= g->mlen && + MEMCMP(dp, g->must, g->mlen) == 0) + break; + if (dp == stop) /* we didn't find g->must */ + return(REG_NOMATCH); + } + + /* match struct setup */ + m->g = g; + m->eflags = eflags; + m->pmatch = NULL; + m->lastpos = NULL; + m->offp = string; + m->beginp = start; + m->endp = stop; + STATESETUP(m, 4); + SETUP(m->st); + SETUP(m->fresh); + SETUP(m->tmp); + SETUP(m->empty); + CLEAR(m->empty); + + /* this loop does only one repetition except for backrefs */ + for (;;) { + endp = fast(m, start, stop, gf, gl); + if (endp == NULL) { /* a miss */ + STATETEARDOWN(m); + return(REG_NOMATCH); + } + if (nmatch == 0 && !g->backrefs) + break; /* no further info needed */ + + /* where? */ + assert(m->coldp != NULL); + for (;;) { + NOTE("finding start"); + endp = slow(m, m->coldp, stop, gf, gl); + if (endp != NULL) + break; + assert(m->coldp < m->endp); + m->coldp++; + } + if (nmatch == 1 && !g->backrefs) + break; /* no further info needed */ + + /* oh my, he wants the subexpressions... */ + if (m->pmatch == NULL) + m->pmatch = (regmatch_t *)malloc((m->g->nsub + 1) * + sizeof(regmatch_t)); + if (m->pmatch == NULL) { + STATETEARDOWN(m); + return(REG_ESPACE); + } + for (i = 1; i <= m->g->nsub; i++) + m->pmatch[i].rm_so = m->pmatch[i].rm_eo = -1; + if (!g->backrefs && !(m->eflags®_BACKR)) { + NOTE("dissecting"); + dp = dissect(m, m->coldp, endp, gf, gl); + } else { + if (g->nplus > 0 && m->lastpos == NULL) + m->lastpos = (const RCHAR_T **)malloc((g->nplus+1) * + sizeof(const RCHAR_T *)); + if (g->nplus > 0 && m->lastpos == NULL) { + free(m->pmatch); + STATETEARDOWN(m); + return(REG_ESPACE); + } + NOTE("backref dissect"); + dp = backref(m, m->coldp, endp, gf, gl, (sopno)0); + } + if (dp != NULL) + break; + + /* uh-oh... we couldn't find a subexpression-level match */ + assert(g->backrefs); /* must be back references doing it */ + assert(g->nplus == 0 || m->lastpos != NULL); + for (;;) { + if (dp != NULL || endp <= m->coldp) + break; /* defeat */ + NOTE("backoff"); + endp = slow(m, m->coldp, endp-1, gf, gl); + if (endp == NULL) + break; /* defeat */ + /* try it on a shorter possibility */ +#ifndef NDEBUG + for (i = 1; i <= m->g->nsub; i++) { + assert(m->pmatch[i].rm_so == -1); + assert(m->pmatch[i].rm_eo == -1); + } +#endif + NOTE("backoff dissect"); + dp = backref(m, m->coldp, endp, gf, gl, (sopno)0); + } + assert(dp == NULL || dp == endp); + if (dp != NULL) /* found a shorter one */ + break; + + /* despite initial appearances, there is no match here */ + NOTE("false alarm"); + start = m->coldp + 1; /* recycle starting later */ + assert(start <= stop); + } + + /* fill in the details if requested */ + if (nmatch > 0) { + pmatch[0].rm_so = m->coldp - m->offp; + pmatch[0].rm_eo = endp - m->offp; + } + if (nmatch > 1) { + assert(m->pmatch != NULL); + for (i = 1; i < nmatch; i++) + if (i <= m->g->nsub) + pmatch[i] = m->pmatch[i]; + else { + pmatch[i].rm_so = -1; + pmatch[i].rm_eo = -1; + } + } + + if (m->pmatch != NULL) + free((char *)m->pmatch); + if (m->lastpos != NULL) + free((char *)m->lastpos); + STATETEARDOWN(m); + return(0); +} + +/* + - dissect - figure out what matched what, no back references + */ +static const RCHAR_T * /* == stop (success) always */ +dissect(struct match *m, const RCHAR_T *start, const RCHAR_T *stop, + sopno startst, sopno stopst) +{ + int i; + sopno ss; /* start sop of current subRE */ + sopno es; /* end sop of current subRE */ + const RCHAR_T *sp; /* start of string matched by it */ + const RCHAR_T *stp; /* string matched by it cannot pass here */ + const RCHAR_T *rest; /* start of rest of string */ + const RCHAR_T *tail; /* string unmatched by rest of RE */ + sopno ssub; /* start sop of subsubRE */ + sopno esub; /* end sop of subsubRE */ + const RCHAR_T *ssp; /* start of string matched by subsubRE */ + const RCHAR_T *sep; /* end of string matched by subsubRE */ + const RCHAR_T *oldssp; /* previous ssp */ + const RCHAR_T *dp; + + AT("diss", start, stop, startst, stopst); + sp = start; + for (ss = startst; ss < stopst; ss = es) { + /* identify end of subRE */ + es = ss; + switch (m->g->strip[es]) { + case OPLUS_: + case OQUEST_: + es += m->g->stripdata[es]; + break; + case OCH_: + while (m->g->strip[es] != O_CH) + es += m->g->stripdata[es]; + break; + } + es++; + + /* figure out what it matched */ + switch (m->g->strip[ss]) { + case OEND: + assert(nope); + break; + case OCHAR: + sp++; + break; + case OBOL: + case OEOL: + case OBOW: + case OEOW: + break; + case OANY: + case OANYOF: + sp++; + break; + case OBACK_: + case O_BACK: + assert(nope); + break; + /* cases where length of match is hard to find */ + case OQUEST_: + stp = stop; + for (;;) { + /* how long could this one be? */ + rest = slow(m, sp, stp, ss, es); + assert(rest != NULL); /* it did match */ + /* could the rest match the rest? */ + tail = slow(m, rest, stop, es, stopst); + if (tail == stop) + break; /* yes! */ + /* no -- try a shorter match for this one */ + stp = rest - 1; + assert(stp >= sp); /* it did work */ + } + ssub = ss + 1; + esub = es - 1; + /* did innards match? */ + if (slow(m, sp, rest, ssub, esub) != NULL) { + dp = dissect(m, sp, rest, ssub, esub); + assert(dp == rest); + } else /* no */ + assert(sp == rest); + sp = rest; + break; + case OPLUS_: + stp = stop; + for (;;) { + /* how long could this one be? */ + rest = slow(m, sp, stp, ss, es); + assert(rest != NULL); /* it did match */ + /* could the rest match the rest? */ + tail = slow(m, rest, stop, es, stopst); + if (tail == stop) + break; /* yes! */ + /* no -- try a shorter match for this one */ + stp = rest - 1; + assert(stp >= sp); /* it did work */ + } + ssub = ss + 1; + esub = es - 1; + ssp = sp; + oldssp = ssp; + for (;;) { /* find last match of innards */ + sep = slow(m, ssp, rest, ssub, esub); + if (sep == NULL || sep == ssp) + break; /* failed or matched null */ + oldssp = ssp; /* on to next try */ + ssp = sep; + } + if (sep == NULL) { + /* last successful match */ + sep = ssp; + ssp = oldssp; + } + assert(sep == rest); /* must exhaust substring */ + assert(slow(m, ssp, sep, ssub, esub) == rest); + dp = dissect(m, ssp, sep, ssub, esub); + assert(dp == sep); + sp = rest; + break; + case OCH_: + stp = stop; + for (;;) { + /* how long could this one be? */ + rest = slow(m, sp, stp, ss, es); + assert(rest != NULL); /* it did match */ + /* could the rest match the rest? */ + tail = slow(m, rest, stop, es, stopst); + if (tail == stop) + break; /* yes! */ + /* no -- try a shorter match for this one */ + stp = rest - 1; + assert(stp >= sp); /* it did work */ + } + ssub = ss + 1; + esub = ss + m->g->stripdata[ss] - 1; + assert(m->g->strip[esub] == OOR1); + for (;;) { /* find first matching branch */ + if (slow(m, sp, rest, ssub, esub) == rest) + break; /* it matched all of it */ + /* that one missed, try next one */ + assert(m->g->strip[esub] == OOR1); + esub++; + assert(m->g->strip[esub] == OOR2); + ssub = esub + 1; + esub += m->g->stripdata[esub]; + if (m->g->strip[esub] == OOR2) + esub--; + else + assert(m->g->strip[esub] == O_CH); + } + dp = dissect(m, sp, rest, ssub, esub); + assert(dp == rest); + sp = rest; + break; + case O_PLUS: + case O_QUEST: + case OOR1: + case OOR2: + case O_CH: + assert(nope); + break; + case OLPAREN: + i = m->g->stripdata[ss]; + assert(0 < i && i <= m->g->nsub); + m->pmatch[i].rm_so = sp - m->offp; + break; + case ORPAREN: + i = m->g->stripdata[ss]; + assert(0 < i && i <= m->g->nsub); + m->pmatch[i].rm_eo = sp - m->offp; + break; + default: /* uh oh */ + assert(nope); + break; + } + } + + assert(sp == stop); + return(sp); +} + +/* + - backref - figure out what matched what, figuring in back references + */ +static const RCHAR_T * /* == stop (success) or NULL (failure) */ +backref(struct match *m, const RCHAR_T *start, const RCHAR_T *stop, + sopno startst, sopno stopst, sopno lev) /* PLUS nesting level */ +{ + int i; + sopno ss; /* start sop of current subRE */ + const RCHAR_T *sp; /* start of string matched by it */ + sopno ssub; /* start sop of subsubRE */ + sopno esub; /* end sop of subsubRE */ + const RCHAR_T *ssp; /* start of string matched by subsubRE */ + const RCHAR_T *dp; + size_t len; + int hard; + sop s; + RCHAR_T d; + regoff_t offsave; + cset *cs; + + AT("back", start, stop, startst, stopst); + sp = start; + + /* get as far as we can with easy stuff */ + hard = 0; + for (ss = startst; !hard && ss < stopst; ss++) { + s = m->g->strip[ss]; + d = m->g->stripdata[ss]; + switch (s) { + case OCHAR: + if (sp == stop || *sp++ != d) + return(NULL); + break; + case OANY: + if (sp == stop) + return(NULL); + sp++; + break; + case OANYOF: + cs = &m->g->sets[d]; + if (sp == stop || !CHIN(cs, *sp++)) + return(NULL); + break; + case OBOL: + if ( (sp == m->beginp && !(m->eflags®_NOTBOL)) || + (sp < m->endp && *(sp-1) == '\n' && + (m->g->cflags®_NEWLINE)) ) + { /* yes */ } + else + return(NULL); + break; + case OEOL: + if ( (sp == m->endp && !(m->eflags®_NOTEOL)) || + (sp < m->endp && *sp == '\n' && + (m->g->cflags®_NEWLINE)) ) + { /* yes */ } + else + return(NULL); + break; + case OBOW: + if (( (sp == m->beginp && !(m->eflags®_NOTBOL)) || + (sp < m->endp && *(sp-1) == '\n' && + (m->g->cflags®_NEWLINE)) || + (sp > m->beginp && + !ISWORD(*(sp-1))) ) && + (sp < m->endp && ISWORD(*sp)) ) + { /* yes */ } + else + return(NULL); + break; + case OEOW: + if (( (sp == m->endp && !(m->eflags®_NOTEOL)) || + (sp < m->endp && *sp == '\n' && + (m->g->cflags®_NEWLINE)) || + (sp < m->endp && !ISWORD(*sp)) ) && + (sp > m->beginp && ISWORD(*(sp-1))) ) + { /* yes */ } + else + return(NULL); + break; + case O_QUEST: + break; + case OOR1: /* matches null but needs to skip */ + ss++; + s = m->g->strip[ss]; + d = m->g->stripdata[ss]; + do { + assert(s == OOR2); + ss += d; + s = m->g->strip[ss]; + d = m->g->stripdata[ss]; + } while (s != O_CH); + /* note that the ss++ gets us past the O_CH */ + break; + default: /* have to make a choice */ + hard = 1; + break; + } + } + if (!hard) { /* that was it! */ + if (sp != stop) + return(NULL); + return(sp); + } + ss--; /* adjust for the for's final increment */ + + /* the hard stuff */ + AT("hard", sp, stop, ss, stopst); + s = m->g->strip[ss]; + d = m->g->stripdata[ss]; + switch (s) { + case OBACK_: /* the vilest depths */ + i = d; + assert(0 < i && i <= m->g->nsub); + if (m->pmatch[i].rm_eo == -1) + return(NULL); + assert(m->pmatch[i].rm_so != -1); + len = m->pmatch[i].rm_eo - m->pmatch[i].rm_so; + assert(stop - m->beginp >= len); + if (sp > stop - len) + return(NULL); /* not enough left to match */ + ssp = m->offp + m->pmatch[i].rm_so; + if (memcmp(sp, ssp, len) != 0) + return(NULL); + while (m->g->strip[ss] != O_BACK || m->g->stripdata[ss] != i) + ss++; + return(backref(m, sp+len, stop, ss+1, stopst, lev)); + break; + case OQUEST_: /* to null or not */ + dp = backref(m, sp, stop, ss+1, stopst, lev); + if (dp != NULL) + return(dp); /* not */ + return(backref(m, sp, stop, ss+d+1, stopst, lev)); + break; + case OPLUS_: + assert(m->lastpos != NULL); + assert(lev+1 <= m->g->nplus); + m->lastpos[lev+1] = sp; + return(backref(m, sp, stop, ss+1, stopst, lev+1)); + break; + case O_PLUS: + if (sp == m->lastpos[lev]) /* last pass matched null */ + return(backref(m, sp, stop, ss+1, stopst, lev-1)); + /* try another pass */ + m->lastpos[lev] = sp; + dp = backref(m, sp, stop, ss-d+1, stopst, lev); + if (dp == NULL) + return(backref(m, sp, stop, ss+1, stopst, lev-1)); + else + return(dp); + break; + case OCH_: /* find the right one, if any */ + ssub = ss + 1; + esub = ss + d - 1; + assert(m->g->strip[esub] == OOR1); + for (;;) { /* find first matching branch */ + dp = backref(m, sp, stop, ssub, esub, lev); + if (dp != NULL) + return(dp); + /* that one missed, try next one */ + if (m->g->strip[esub] == O_CH) + return(NULL); /* there is none */ + esub++; + assert(m->g->strip[esub] == OOR2); + ssub = esub + 1; + esub += m->g->stripdata[esub]; + if (m->g->strip[esub] == OOR2) + esub--; + else + assert(m->g->strip[esub] == O_CH); + } + break; + case OLPAREN: /* must undo assignment if rest fails */ + i = d; + assert(0 < i && i <= m->g->nsub); + offsave = m->pmatch[i].rm_so; + m->pmatch[i].rm_so = sp - m->offp; + dp = backref(m, sp, stop, ss+1, stopst, lev); + if (dp != NULL) + return(dp); + m->pmatch[i].rm_so = offsave; + return(NULL); + break; + case ORPAREN: /* must undo assignment if rest fails */ + i = d; + assert(0 < i && i <= m->g->nsub); + offsave = m->pmatch[i].rm_eo; + m->pmatch[i].rm_eo = sp - m->offp; + dp = backref(m, sp, stop, ss+1, stopst, lev); + if (dp != NULL) + return(dp); + m->pmatch[i].rm_eo = offsave; + return(NULL); + break; + default: /* uh oh */ + assert(nope); + break; + } + + /* "can't happen" */ + assert(nope); + /* NOTREACHED */ + return NULL; +} + +/* + - fast - step through the string at top speed + */ +static const RCHAR_T * /* where tentative match ended, or NULL */ +fast(struct match *m, const RCHAR_T *start, const RCHAR_T *stop, sopno startst, + sopno stopst) +{ + states st = m->st; + states fresh = m->fresh; + states tmp = m->tmp; + const RCHAR_T *p = start; + RCHAR_T c = (start == m->beginp) ? OUT : *(start-1); + RCHAR_T lastc; /* previous c */ + int flag; + int i; + const RCHAR_T *coldp; /* last p after which no match was underway */ + + CLEAR(st); + SET1(st, startst); + st = step(m->g, startst, stopst, st, NOTHING, OUT, st); + ASSIGN(fresh, st); + SP("start", st, *p); + coldp = NULL; + for (;;) { + /* next character */ + lastc = c; + c = (p == m->endp) ? OUT : *p; + if (EQ(st, fresh)) + coldp = p; + + /* is there an EOL and/or BOL between lastc and c? */ + flag = 0; + i = 0; + if ( (lastc == '\n' && m->g->cflags®_NEWLINE) || + (lastc == OUT && !(m->eflags®_NOTBOL)) ) { + flag = BOL; + i = m->g->nbol; + } + if ( (c == '\n' && m->g->cflags®_NEWLINE) || + (c == OUT && !(m->eflags®_NOTEOL)) ) { + flag = (flag == BOL) ? BOLEOL : EOL; + i += m->g->neol; + } + if (i != 0) { + for (; i > 0; i--) + st = step(m->g, startst, stopst, st, flag, OUT, st); + SP("boleol", st, c); + } + + /* how about a word boundary? */ + if ( (flag == BOL || (lastc != OUT && !ISWORD(lastc))) && + (c != OUT && ISWORD(c)) ) { + flag = BOW; + } + if ( (lastc != OUT && ISWORD(lastc)) && + (flag == EOL || (c != OUT && !ISWORD(c))) ) { + flag = EOW; + } + if (flag == BOW || flag == EOW) { + st = step(m->g, startst, stopst, st, flag, OUT, st); + SP("boweow", st, c); + } + + /* are we done? */ + if (ISSET(st, stopst) || p == stop) + break; /* NOTE BREAK OUT */ + + /* no, we must deal with this character */ + ASSIGN(tmp, st); + ASSIGN(st, fresh); + assert(c != OUT); + st = step(m->g, startst, stopst, tmp, 0, c, st); + SP("aft", st, c); + assert(EQ(step(m->g, startst, stopst, st, NOTHING, OUT, st), st)); + p++; + } + + assert(coldp != NULL); + m->coldp = coldp; + if (ISSET(st, stopst)) + return(p+1); + else + return(NULL); +} + +/* + - slow - step through the string more deliberately + */ +static const RCHAR_T * /* where it ended */ +slow(struct match *m, const RCHAR_T *start, const RCHAR_T *stop, sopno startst, + sopno stopst) +{ + states st = m->st; + states empty = m->empty; + states tmp = m->tmp; + const RCHAR_T *p = start; + RCHAR_T c = (start == m->beginp) ? OUT : *(start-1); + RCHAR_T lastc; /* previous c */ + int flag; + int i; + const RCHAR_T *matchp; /* last p at which a match ended */ + + AT("slow", start, stop, startst, stopst); + CLEAR(st); + SET1(st, startst); + SP("sstart", st, *p); + st = step(m->g, startst, stopst, st, NOTHING, OUT, st); + matchp = NULL; + for (;;) { + /* next character */ + lastc = c; + c = (p == m->endp) ? OUT : *p; + + /* is there an EOL and/or BOL between lastc and c? */ + flag = 0; + i = 0; + if ( (lastc == '\n' && m->g->cflags®_NEWLINE) || + (lastc == OUT && !(m->eflags®_NOTBOL)) ) { + flag = BOL; + i = m->g->nbol; + } + if ( (c == '\n' && m->g->cflags®_NEWLINE) || + (c == OUT && !(m->eflags®_NOTEOL)) ) { + flag = (flag == BOL) ? BOLEOL : EOL; + i += m->g->neol; + } + if (i != 0) { + for (; i > 0; i--) + st = step(m->g, startst, stopst, st, flag, OUT, st); + SP("sboleol", st, c); + } + + /* how about a word boundary? */ + if ( (flag == BOL || (lastc != OUT && !ISWORD(lastc))) && + (c != OUT && ISWORD(c)) ) { + flag = BOW; + } + if ( (lastc != OUT && ISWORD(lastc)) && + (flag == EOL || (c != OUT && !ISWORD(c))) ) { + flag = EOW; + } + if (flag == BOW || flag == EOW) { + st = step(m->g, startst, stopst, st, flag, OUT, st); + SP("sboweow", st, c); + } + + /* are we done? */ + if (ISSET(st, stopst)) + matchp = p; + if (EQ(st, empty) || p == stop) + break; /* NOTE BREAK OUT */ + + /* no, we must deal with this character */ + ASSIGN(tmp, st); + ASSIGN(st, empty); + assert(c != OUT); + st = step(m->g, startst, stopst, tmp, 0, c, st); + SP("saft", st, c); + assert(EQ(step(m->g, startst, stopst, st, NOTHING, OUT, st), st)); + p++; + } + + return(matchp); +} + + +/* + - step - map set of states reachable before char to set reachable after + */ +static states +step(struct re_guts *g, + sopno start, /* start state within strip */ + sopno stop, /* state after stop state within strip */ + states bef, /* states reachable before */ + int flag, /* NONCHAR flag */ + RCHAR_T ch, /* character code */ + states aft) /* states already known reachable after */ +{ + cset *cs; + sop s; + RCHAR_T d; + sopno pc; + onestate here; /* note, macros know this name */ + sopno look; + int i; + + for (pc = start, INIT(here, pc); pc != stop; pc++, INC(here)) { + s = g->strip[pc]; + d = g->stripdata[pc]; + switch (s) { + case OEND: + assert(pc == stop-1); + break; + case OCHAR: + /* only characters can match */ + assert(!flag || ch != d); + if (ch == d) + FWD(aft, bef, 1); + break; + case OBOL: + if (flag == BOL || flag == BOLEOL) + FWD(aft, bef, 1); + break; + case OEOL: + if (flag == EOL || flag == BOLEOL) + FWD(aft, bef, 1); + break; + case OBOW: + if (flag == BOW) + FWD(aft, bef, 1); + break; + case OEOW: + if (flag == EOW) + FWD(aft, bef, 1); + break; + case OANY: + if (!flag) + FWD(aft, bef, 1); + break; + case OANYOF: + cs = &g->sets[d]; + if (!flag && CHIN(cs, ch)) + FWD(aft, bef, 1); + break; + case OBACK_: /* ignored here */ + case O_BACK: + FWD(aft, aft, 1); + break; + case OPLUS_: /* forward, this is just an empty */ + FWD(aft, aft, 1); + break; + case O_PLUS: /* both forward and back */ + FWD(aft, aft, 1); + i = ISSETBACK(aft, d); + BACK(aft, aft, d); + if (!i && ISSETBACK(aft, d)) { + /* oho, must reconsider loop body */ + pc -= d + 1; + INIT(here, pc); + } + break; + case OQUEST_: /* two branches, both forward */ + FWD(aft, aft, 1); + FWD(aft, aft, d); + break; + case O_QUEST: /* just an empty */ + FWD(aft, aft, 1); + break; + case OLPAREN: /* not significant here */ + case ORPAREN: + FWD(aft, aft, 1); + break; + case OCH_: /* mark the first two branches */ + FWD(aft, aft, 1); + assert(OP(g->strip[pc+d]) == OOR2); + FWD(aft, aft, d); + break; + case OOR1: /* done a branch, find the O_CH */ + if (ISSTATEIN(aft, here)) { + for (look = 1; /**/; look += d) { + s = g->strip[pc+look]; + d = g->stripdata[pc+look]; + if (s == O_CH) + break; + assert(s == OOR2); + } + FWD(aft, aft, look); + } + break; + case OOR2: /* propagate OCH_'s marking */ + FWD(aft, aft, 1); + if (g->strip[pc+d] != O_CH) { + assert(g->strip[pc+d] == OOR2); + FWD(aft, aft, d); + } + break; + case O_CH: /* just empty */ + FWD(aft, aft, 1); + break; + default: /* ooooops... */ + assert(nope); + break; + } + } + + return(aft); +} + +#ifdef REDEBUG +/* + - print - print a set of states + */ +static void +print(struct match *m, char *caption, states st, int ch, FILE *d) +{ + struct re_guts *g = m->g; + int i; + int first = 1; + + if (!(m->eflags®_TRACE)) + return; + + fprintf(d, "%s", caption); + if (ch != '\0') + fprintf(d, " %s", pchar(ch)); + for (i = 0; i < g->nstates; i++) + if (ISSET(st, i)) { + fprintf(d, "%s%d", (first) ? "\t" : ", ", i); + first = 0; + } + fprintf(d, "\n"); +} + +/* + - at - print current situation + */ +static void +at(struct match *m, char *title, char *start, char *stop, sopno startst, + sopno stopst) +{ + if (!(m->eflags®_TRACE)) + return; + + printf("%s %s-", title, pchar(*start)); + printf("%s ", pchar(*stop)); + printf("%ld-%ld\n", (long)startst, (long)stopst); +} + +#ifndef PCHARDONE +#define PCHARDONE /* never again */ +/* + - pchar - make a character printable + * + * Is this identical to regchar() over in debug.c? Well, yes. But a + * duplicate here avoids having a debugging-capable regexec.o tied to + * a matching debug.o, and this is convenient. It all disappears in + * the non-debug compilation anyway, so it doesn't matter much. + */ +static char * /* -> representation */ +pchar(int ch) +{ + static char pbuf[10]; + + if (isprint(ch) || ch == ' ') + snprintf(pbuf, sizeof(pbuf), "%c", ch); + else + snprintf(pbuf, sizeof(pbuf), "\\%o", ch); + return(pbuf); +} +#endif +#endif + +#undef matcher +#undef fast +#undef slow +#undef dissect +#undef backref +#undef step +#undef print +#undef at +#undef match Property changes on: vendor/nvi/2.2.0-05ed8b9/regex/engine.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/regex/regexec.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/regex/regexec.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/regex/regexec.c (revision 366308) @@ -0,0 +1,173 @@ +/* $NetBSD: regexec.c,v 1.4 2009/10/31 20:11:53 dsl Exp $ */ + +/*- + * Copyright (c) 1992, 1993, 1994 Henry Spencer. + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Henry Spencer of the University of Toronto. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)regexec.c 8.2 (Berkeley) 3/16/94 + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)regexec.c 8.2 (Berkeley) 3/16/94"; +#endif /* LIBC_SCCS and not lint */ + +/* + * the outer shell of regexec() + * + * This file includes engine.c *twice*, after muchos fiddling with the + * macros that code uses. This lets the same code operate on two different + * representations for state sets. + */ +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" +#include "regex2.h" + +/* macros for manipulating states, small version */ +#define states int +#define states1 int /* for later use in regexec() decision */ +#define CLEAR(v) ((v) = 0) +#define SET0(v, n) ((v) &= ~(1 << (n))) +#define SET1(v, n) ((v) |= 1 << (n)) +#define ISSET(v, n) ((v) & (1 << (n))) +#define ASSIGN(d, s) ((d) = (s)) +#define EQ(a, b) ((a) == (b)) +#define STATEVARS int dummy /* dummy version */ +#define STATESETUP(m, n) /* nothing */ +#define STATETEARDOWN(m) /* nothing */ +#define SETUP(v) ((v) = 0) +#define onestate int +#define INIT(o, n) ((o) = (unsigned)1 << (n)) +#define INC(o) ((o) <<= 1) +#define ISSTATEIN(v, o) ((v) & (o)) +/* some abbreviations; note that some of these know variable names! */ +/* do "if I'm here, I can also be there" etc without branches */ +#define FWD(dst, src, n) ((dst) |= ((unsigned)(src)&(here)) << (n)) +#define BACK(dst, src, n) ((dst) |= ((unsigned)(src)&(here)) >> (n)) +#define ISSETBACK(v, n) ((v) & ((unsigned)here >> (n))) +/* function names */ +#define SNAMES /* engine.c looks after details */ + +#include "engine.c" + +/* now undo things */ +#undef states +#undef CLEAR +#undef SET0 +#undef SET1 +#undef ISSET +#undef ASSIGN +#undef EQ +#undef STATEVARS +#undef STATESETUP +#undef STATETEARDOWN +#undef SETUP +#undef onestate +#undef INIT +#undef INC +#undef ISSTATEIN +#undef FWD +#undef BACK +#undef ISSETBACK +#undef SNAMES + +/* macros for manipulating states, large version */ +#define states char * +#define CLEAR(v) memset(v, 0, m->g->nstates) +#define SET0(v, n) ((v)[n] = 0) +#define SET1(v, n) ((v)[n] = 1) +#define ISSET(v, n) ((v)[n]) +#define ASSIGN(d, s) memcpy(d, s, m->g->nstates) +#define EQ(a, b) (memcmp(a, b, m->g->nstates) == 0) +#define STATEVARS int vn; char *space +#define STATESETUP(m, nv) do { (m)->space = malloc((nv)*(m)->g->nstates); \ + if ((m)->space == NULL) return(REG_ESPACE); \ + (m)->vn = 0; } while (0) +#define STATETEARDOWN(m) free((m)->space) +#define SETUP(v) ((v) = &m->space[m->vn++ * m->g->nstates]) +#define onestate int +#define INIT(o, n) ((o) = (n)) +#define INC(o) ((o)++) +#define ISSTATEIN(v, o) ((v)[o]) +/* some abbreviations; note that some of these know variable names! */ +/* do "if I'm here, I can also be there" etc without branches */ +#define FWD(dst, src, n) ((dst)[here+(n)] |= (src)[here]) +#define BACK(dst, src, n) ((dst)[here-(n)] |= (src)[here]) +#define ISSETBACK(v, n) ((v)[here - (n)]) +/* function names */ +#define LNAMES /* flag */ + +#include "engine.c" + +/* + - regexec - interface for matching + = extern int regexec(const regex_t *, const char *, size_t, \ + = regmatch_t [], int); + = #define REG_NOTBOL 00001 + = #define REG_NOTEOL 00002 + = #define REG_STARTEND 00004 + = #define REG_TRACE 00400 // tracing of execution + = #define REG_LARGE 01000 // force large representation + = #define REG_BACKR 02000 // force use of backref code + * + * We put this here so we can exploit knowledge of the state representation + * when choosing which matcher to call. Also, by this point the matchers + * have been prototyped. + */ +int /* 0 success, REG_NOMATCH failure */ +regexec(const regex_t *preg, const RCHAR_T *string, size_t nmatch, + regmatch_t *pmatch, int eflags) +{ + struct re_guts *g = preg->re_g; +#ifdef REDEBUG +# define GOODFLAGS(f) (f) +#else +# define GOODFLAGS(f) ((f)&(REG_NOTBOL|REG_NOTEOL|REG_STARTEND)) +#endif + + if (preg->re_magic != MAGIC1 || g->magic != MAGIC2) + return(REG_BADPAT); + assert(!(g->iflags&BAD)); + if (g->iflags&BAD) /* backstop for no-debug case */ + return(REG_BADPAT); + eflags = GOODFLAGS(eflags); + + if (g->nstates <= (int)(CHAR_BIT*sizeof(states1)) && !(eflags®_LARGE)) + return(smatcher(g, string, nmatch, pmatch, eflags)); + else + return(lmatcher(g, string, nmatch, pmatch, eflags)); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/regex/regexec.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/regex/COPYRIGHT =================================================================== --- vendor/nvi/2.2.0-05ed8b9/regex/COPYRIGHT (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/regex/COPYRIGHT (revision 366308) @@ -0,0 +1,52 @@ +Copyright 1992, 1993, 1994 Henry Spencer. All rights reserved. +This software is not subject to any license of the American Telephone +and Telegraph Company or of the Regents of the University of California. + +Permission is granted to anyone to use this software for any purpose on +any computer system, and to alter it and redistribute it, subject +to the following restrictions: + +1. The author is not responsible for the consequences of use of this + software, no matter how awful, even if they arise from flaws in it. + +2. The origin of this software must not be misrepresented, either by + explicit claim or by omission. Since few users ever read sources, + credits must appear in the documentation. + +3. Altered versions must be plainly marked as such, and must not be + misrepresented as being the original software. Since few users + ever read sources, credits must appear in the documentation. + +4. This notice may not be removed or altered. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +/*- + * Copyright (c) 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)COPYRIGHT 8.1 (Berkeley) 3/16/94 + */ Index: vendor/nvi/2.2.0-05ed8b9/regex/cclass.h =================================================================== --- vendor/nvi/2.2.0-05ed8b9/regex/cclass.h (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/regex/cclass.h (revision 366308) @@ -0,0 +1,81 @@ +/* $NetBSD: cclass.h,v 1.2 2008/12/05 22:51:42 christos Exp $ */ + +/*- + * Copyright (c) 1992, 1993, 1994 Henry Spencer. + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Henry Spencer of the University of Toronto. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)cclass.h 8.2 (Berkeley) 3/16/94 + */ + +RCHAR_T ALNUM[] = {'a','l','n','u','m',0}; +RCHAR_T ALPHA[] = {'a','l','p','h','a',0}; +RCHAR_T BLANK[] = {'b','l','a','n','k',0}; +RCHAR_T CNTRL[] = {'c','n','t','r','l',0}; +RCHAR_T DIGIT[] = {'d','i','g','i','t',0}; +RCHAR_T GRAPH[] = {'g','r','a','p','h',0}; +RCHAR_T LOWER[] = {'l','o','w','e','r',0}; +RCHAR_T PRINT[] = {'p','r','i','n','t',0}; +RCHAR_T PUNCT[] = {'p','u','n','c','t',0}; +RCHAR_T SPACE[] = {'s','p','a','c','e',0}; +RCHAR_T UPPER[] = {'u','p','p','e','r',0}; +RCHAR_T XDIGIT[] = {'x','d','i','g','i','t',0}; + +/* character-class table */ +static struct cclass { + RCHAR_T *name; + const char *chars; + const char *multis; +} cclasses[] = { + { ALNUM, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\ +0123456789", "" }, + { ALPHA, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", + "" }, + { BLANK, " \t", "" }, + { CNTRL, "\007\b\t\n\v\f\r\1\2\3\4\5\6\16\17\20\21\22\23\24\ +\25\26\27\30\31\32\33\34\35\36\37\177", "" }, + { DIGIT, "0123456789", "" }, + { GRAPH, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\ +0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + "" }, + { LOWER, "abcdefghijklmnopqrstuvwxyz", + "" }, + { PRINT, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\ +0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~ ", + "" }, + { PUNCT, "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + "" }, + { SPACE, "\t\n\v\f\r ", "" }, + { UPPER, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", + "" }, + { XDIGIT, "0123456789ABCDEFabcdef", + "" }, + { NULL, 0, "" }, +}; Property changes on: vendor/nvi/2.2.0-05ed8b9/regex/cclass.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/regex/cname.h =================================================================== --- vendor/nvi/2.2.0-05ed8b9/regex/cname.h (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/regex/cname.h (revision 366308) @@ -0,0 +1,139 @@ +/* $NetBSD: cname.h,v 1.2 2008/12/05 22:51:42 christos Exp $ */ + +/*- + * Copyright (c) 1992, 1993, 1994 Henry Spencer. + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Henry Spencer of the University of Toronto. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)cname.h 8.2 (Berkeley) 3/16/94 + */ + +/* character-name table */ +static struct cname { + const RCHAR_T *name; + char code; +} cnames[] = { + { L("NUL"), '\0' }, + { L("SOH"), '\001' }, + { L("STX"), '\002' }, + { L("ETX"), '\003' }, + { L("EOT"), '\004' }, + { L("ENQ"), '\005' }, + { L("ACK"), '\006' }, + { L("BEL"), '\007' }, + { L("alert"), '\007' }, + { L("BS"), '\010' }, + { L("backspace"), '\b' }, + { L("HT"), '\011' }, + { L("tab"), '\t' }, + { L("LF"), '\012' }, + { L("newline"), '\n' }, + { L("VT"), '\013' }, + { L("vertical-tab"), '\v' }, + { L("FF"), '\014' }, + { L("form-feed"), '\f' }, + { L("CR"), '\015' }, + { L("carriage-return"), '\r' }, + { L("SO"), '\016' }, + { L("SI"), '\017' }, + { L("DLE"), '\020' }, + { L("DC1"), '\021' }, + { L("DC2"), '\022' }, + { L("DC3"), '\023' }, + { L("DC4"), '\024' }, + { L("NAK"), '\025' }, + { L("SYN"), '\026' }, + { L("ETB"), '\027' }, + { L("CAN"), '\030' }, + { L("EM"), '\031' }, + { L("SUB"), '\032' }, + { L("ESC"), '\033' }, + { L("IS4"), '\034' }, + { L("FS"), '\034' }, + { L("IS3"), '\035' }, + { L("GS"), '\035' }, + { L("IS2"), '\036' }, + { L("RS"), '\036' }, + { L("IS1"), '\037' }, + { L("US"), '\037' }, + { L("space"), ' ' }, + { L("exclamation-mark"),'!' }, + { L("quotation-mark"), '"' }, + { L("number-sign"), '#' }, + { L("dollar-sign"), '$' }, + { L("percent-sign"), '%' }, + { L("ampersand"), '&' }, + { L("apostrophe"), '\'' }, + { L("left-parenthesis"),'(' }, + { L("right-parenthesis"),')' }, + { L("asterisk"), '*' }, + { L("plus-sign"), '+' }, + { L("comma"), ',' }, + { L("hyphen"), '-' }, + { L("hyphen-minus"), '-' }, + { L("period"), '.' }, + { L("full-stop"), '.' }, + { L("slash"), '/' }, + { L("solidus"), '/' }, + { L("zero"), '0' }, + { L("one"), '1' }, + { L("two"), '2' }, + { L("three"), '3' }, + { L("four"), '4' }, + { L("five"), '5' }, + { L("six"), '6' }, + { L("seven"), '7' }, + { L("eight"), '8' }, + { L("nine"), '9' }, + { L("colon"), ':' }, + { L("semicolon"), ';' }, + { L("less-than-sign"), '<' }, + { L("equals-sign"), '=' }, + { L("greater-than-sign"),'>' }, + { L("question-mark"), '?' }, + { L("commercial-at"), '@' }, + { L("left-square-bracket"),'[' }, + { L("backslash"), '\\' }, + { L("reverse-solidus"), '\\' }, + { L("right-square-bracket"),']' }, + { L("circumflex"), '^' }, + { L("circumflex-accent"),'^' }, + { L("underscore"), '_' }, + { L("low-line"), '_' }, + { L("grave-accent"), '`' }, + { L("left-brace"), '{' }, + { L("left-curly-bracket"),'{' }, + { L("vertical-line"), '|' }, + { L("right-brace"), '}' }, + { L("right-curly-bracket"),'}' }, + { L("tilde"), '~' }, + { L("DEL"), '\177' }, + { NULL, 0 }, +}; Property changes on: vendor/nvi/2.2.0-05ed8b9/regex/cname.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/regex/re_format.7 =================================================================== --- vendor/nvi/2.2.0-05ed8b9/regex/re_format.7 (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/regex/re_format.7 (revision 366308) @@ -0,0 +1,267 @@ +.\" $NetBSD: re_format.7,v 1.1.1.2 2008/05/18 14:31:37 aymeric Exp $ +.\" +.\" Copyright (c) 1992, 1993, 1994 Henry Spencer. +.\" Copyright (c) 1992, 1993, 1994 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Henry Spencer of the University of Toronto. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)re_format.7 8.2 (Berkeley) 3/16/94 +.\" +.TH RE_FORMAT 7 "March 16, 1994" +.SH NAME +re_format \- POSIX 1003.2 regular expressions +.SH DESCRIPTION +Regular expressions (``RE''s), +as defined in POSIX 1003.2, come in two forms: +modern REs (roughly those of +.IR egrep ; +1003.2 calls these ``extended'' REs) +and obsolete REs (roughly those of +.IR ed ; +1003.2 ``basic'' REs). +Obsolete REs mostly exist for backward compatibility in some old programs; +they will be discussed at the end. +1003.2 leaves some aspects of RE syntax and semantics open; +`\(dg' marks decisions on these aspects that +may not be fully portable to other 1003.2 implementations. +.PP +A (modern) RE is one\(dg or more non-empty\(dg \fIbranches\fR, +separated by `|'. +It matches anything that matches one of the branches. +.PP +A branch is one\(dg or more \fIpieces\fR, concatenated. +It matches a match for the first, followed by a match for the second, etc. +.PP +A piece is an \fIatom\fR possibly followed +by a single\(dg `*', `+', `?', or \fIbound\fR. +An atom followed by `*' matches a sequence of 0 or more matches of the atom. +An atom followed by `+' matches a sequence of 1 or more matches of the atom. +An atom followed by `?' matches a sequence of 0 or 1 matches of the atom. +.PP +A \fIbound\fR is `{' followed by an unsigned decimal integer, +possibly followed by `,' +possibly followed by another unsigned decimal integer, +always followed by `}'. +The integers must lie between 0 and RE_DUP_MAX (255\(dg) inclusive, +and if there are two of them, the first may not exceed the second. +An atom followed by a bound containing one integer \fIi\fR +and no comma matches +a sequence of exactly \fIi\fR matches of the atom. +An atom followed by a bound +containing one integer \fIi\fR and a comma matches +a sequence of \fIi\fR or more matches of the atom. +An atom followed by a bound +containing two integers \fIi\fR and \fIj\fR matches +a sequence of \fIi\fR through \fIj\fR (inclusive) matches of the atom. +.PP +An atom is a regular expression enclosed in `()' (matching a match for the +regular expression), +an empty set of `()' (matching the null string)\(dg, +a \fIbracket expression\fR (see below), `.' +(matching any single character), `^' (matching the null string at the +beginning of a line), `$' (matching the null string at the +end of a line), a `\e' followed by one of the characters +`^.[$()|*+?{\e' +(matching that character taken as an ordinary character), +a `\e' followed by any other character\(dg +(matching that character taken as an ordinary character, +as if the `\e' had not been present\(dg), +or a single character with no other significance (matching that character). +A `{' followed by a character other than a digit is an ordinary +character, not the beginning of a bound\(dg. +It is illegal to end an RE with `\e'. +.PP +A \fIbracket expression\fR is a list of characters enclosed in `[]'. +It normally matches any single character from the list (but see below). +If the list begins with `^', +it matches any single character +(but see below) \fInot\fR from the rest of the list. +If two characters in the list are separated by `\-', this is shorthand +for the full \fIrange\fR of characters between those two (inclusive) in the +collating sequence, +e.g. `[0-9]' in ASCII matches any decimal digit. +It is illegal\(dg for two ranges to share an +endpoint, e.g. `a-c-e'. +Ranges are very collating-sequence-dependent, +and portable programs should avoid relying on them. +.PP +To include a literal `]' in the list, make it the first character +(following a possible `^'). +To include a literal `\-', make it the first or last character, +or the second endpoint of a range. +To use a literal `\-' as the first endpoint of a range, +enclose it in `[.' and `.]' to make it a collating element (see below). +With the exception of these and some combinations using `[' (see next +paragraphs), all other special characters, including `\e', lose their +special significance within a bracket expression. +.PP +Within a bracket expression, a collating element (a character, +a multi-character sequence that collates as if it were a single character, +or a collating-sequence name for either) +enclosed in `[.' and `.]' stands for the +sequence of characters of that collating element. +The sequence is a single element of the bracket expression's list. +A bracket expression containing a multi-character collating element +can thus match more than one character, +e.g. if the collating sequence includes a `ch' collating element, +then the RE `[[.ch.]]*c' matches the first five characters +of `chchcc'. +.PP +Within a bracket expression, a collating element enclosed in `[=' and +`=]' is an equivalence class, standing for the sequences of characters +of all collating elements equivalent to that one, including itself. +(If there are no other equivalent collating elements, +the treatment is as if the enclosing delimiters were `[.' and `.]'.) +For example, if o and \o'o^' are the members of an equivalence class, +then `[[=o=]]', `[[=\o'o^'=]]', and `[o\o'o^']' are all synonymous. +An equivalence class may not\(dg be an endpoint +of a range. +.PP +Within a bracket expression, the name of a \fIcharacter class\fR enclosed +in `[:' and `:]' stands for the list of all characters belonging to that +class. +Standard character class names are: +.PP +.RS +.nf +.ta 3c 6c 9c +alnum digit punct +alpha graph space +blank lower upper +cntrl print xdigit +.fi +.RE +.PP +These stand for the character classes defined in +.IR ctype (3). +A locale may provide others. +A character class may not be used as an endpoint of a range. +.PP +There are two special cases\(dg of bracket expressions: +the bracket expressions `[[:<:]]' and `[[:>:]]' match the null string at +the beginning and end of a word respectively. +A word is defined as a sequence of +word characters +which is neither preceded nor followed by +word characters. +A word character is an +.I alnum +character (as defined by +.IR ctype (3)) +or an underscore. +This is an extension, +compatible with but not specified by POSIX 1003.2, +and should be used with +caution in software intended to be portable to other systems. +.PP +In the event that an RE could match more than one substring of a given +string, +the RE matches the one starting earliest in the string. +If the RE could match more than one substring starting at that point, +it matches the longest. +Subexpressions also match the longest possible substrings, subject to +the constraint that the whole match be as long as possible, +with subexpressions starting earlier in the RE taking priority over +ones starting later. +Note that higher-level subexpressions thus take priority over +their lower-level component subexpressions. +.PP +Match lengths are measured in characters, not collating elements. +A null string is considered longer than no match at all. +For example, +`bb*' matches the three middle characters of `abbbc', +`(wee|week)(knights|nights)' matches all ten characters of `weeknights', +when `(.*).*' is matched against `abc' the parenthesized subexpression +matches all three characters, and +when `(a*)*' is matched against `bc' both the whole RE and the parenthesized +subexpression match the null string. +.PP +If case-independent matching is specified, +the effect is much as if all case distinctions had vanished from the +alphabet. +When an alphabetic that exists in multiple cases appears as an +ordinary character outside a bracket expression, it is effectively +transformed into a bracket expression containing both cases, +e.g. `x' becomes `[xX]'. +When it appears inside a bracket expression, all case counterparts +of it are added to the bracket expression, so that (e.g.) `[x]' +becomes `[xX]' and `[^x]' becomes `[^xX]'. +.PP +No particular limit is imposed on the length of REs\(dg. +Programs intended to be portable should not employ REs longer +than 256 bytes, +as an implementation can refuse to accept such REs and remain +POSIX-compliant. +.PP +Obsolete (``basic'') regular expressions differ in several respects. +`|', `+', and `?' are ordinary characters and there is no equivalent +for their functionality. +The delimiters for bounds are `\e{' and `\e}', +with `{' and `}' by themselves ordinary characters. +The parentheses for nested subexpressions are `\e(' and `\e)', +with `(' and `)' by themselves ordinary characters. +`^' is an ordinary character except at the beginning of the +RE or\(dg the beginning of a parenthesized subexpression, +`$' is an ordinary character except at the end of the +RE or\(dg the end of a parenthesized subexpression, +and `*' is an ordinary character if it appears at the beginning of the +RE or the beginning of a parenthesized subexpression +(after a possible leading `^'). +Finally, there is one new type of atom, a \fIback reference\fR: +`\e' followed by a non-zero decimal digit \fId\fR +matches the same sequence of characters +matched by the \fId\fRth parenthesized subexpression +(numbering subexpressions by the positions of their opening parentheses, +left to right), +so that (e.g.) `\e([bc]\e)\e1' matches `bb' or `cc' but not `bc'. +.SH SEE ALSO +regex(3) +.PP +POSIX 1003.2, section 2.8 (Regular Expression Notation). +.SH BUGS +Having two kinds of REs is a botch. +.PP +The current 1003.2 spec says that `)' is an ordinary character in +the absence of an unmatched `('; +this was an unintentional result of a wording error, +and change is likely. +Avoid relying on it. +.PP +Back references are a dreadful botch, +posing major problems for efficient implementations. +They are also somewhat vaguely defined +(does +`a\e(\e(b\e)*\e2\e)*d' match `abbbd'?). +Avoid using them. +.PP +1003.2's specification of case-independent matching is vague. +The ``one case implies all cases'' definition given above +is current consensus among implementors as to the right interpretation. +.PP +The syntax for word boundaries is incredibly ugly. Property changes on: vendor/nvi/2.2.0-05ed8b9/regex/re_format.7 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/regex/regcomp.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/regex/regcomp.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/regex/regcomp.c (revision 366308) @@ -0,0 +1,1629 @@ +/* $NetBSD: regcomp.c,v 1.7 2011/11/19 17:45:11 tnozaki Exp $ */ + +/*- + * Copyright (c) 1992, 1993, 1994 Henry Spencer. + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Henry Spencer of the University of Toronto. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)regcomp.c 8.4 (Berkeley) 3/19/94 + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)regcomp.c 8.4 (Berkeley) 3/19/94"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" +#include "regex2.h" + +#include "cclass.h" +#include "cname.h" + +/* + * parse structure, passed up and down to avoid global variables and + * other clumsinesses + */ +struct parse { + RCHAR_T *next; /* next character in RE */ + RCHAR_T *end; /* end of string (-> NUL normally) */ + int error; /* has an error been seen? */ + sop *strip; /* malloced strip */ + RCHAR_T *stripdata; /* malloced stripdata */ + sopno ssize; /* malloced strip size (allocated) */ + sopno slen; /* malloced strip length (used) */ + int ncsalloc; /* number of csets allocated */ + struct re_guts *g; +# define NPAREN 10 /* we need to remember () 1-9 for back refs */ + sopno pbegin[NPAREN]; /* -> ( ([0] unused) */ + sopno pend[NPAREN]; /* -> ) ([0] unused) */ +}; + +/* ========= begin header generated by ./mkh ========= */ +#ifdef __cplusplus +extern "C" { +#endif + +/* === regcomp.c === */ +static void p_ere(struct parse *p, int stop, size_t reclimit); +static void p_ere_exp(struct parse *p, size_t reclimit); +static void p_str(struct parse *p); +static void p_bre(struct parse *p, int end1, int end2, size_t reclimit); +static int p_simp_re(struct parse *p, int starordinary, size_t reclimit); +static int p_count(struct parse *p); +static void p_bracket(struct parse *p); +static void p_b_term(struct parse *p, cset *cs); +static void p_b_cclass(struct parse *p, cset *cs); +static void p_b_eclass(struct parse *p, cset *cs); +static char p_b_symbol(struct parse *p); +static char p_b_coll_elem(struct parse *p, int endc); +static char othercase(int ch); +static void bothcases(struct parse *p, int ch); +static void ordinary(struct parse *p, int ch); +static void nonnewline(struct parse *p); +static void repeat(struct parse *p, sopno start, int from, int to, size_t reclimit); +static int seterr(struct parse *p, int e); +static cset *allocset(struct parse *p); +static void freeset(struct parse *p, cset *cs); +static int freezeset(struct parse *p, cset *cs); +static int firstch(struct parse *p, cset *cs); +static int nch(struct parse *p, cset *cs); +static void mcadd(struct parse *p, cset *cs, const char *cp); +#ifdef notdef +static void mcsub(cset *cs, char *cp); +static int mcin(cset *cs, char *cp); +static char *mcfind(cset *cs, char *cp); +#endif +static void mcinvert(struct parse *p, cset *cs); +static void mccase(struct parse *p, cset *cs); +#ifdef notdef +static int isinsets(struct re_guts *g, int c); +static int samesets(struct re_guts *g, int c1, int c2); +#endif +static void categorize(struct parse *p, struct re_guts *g); +static sopno dupl(struct parse *p, sopno start, sopno finish); +static void doemit(struct parse *p, sop op, size_t opnd); +static void doinsert(struct parse *p, sop op, size_t opnd, sopno pos); +static void dofwd(struct parse *p, sopno pos, sop value); +static int enlarge(struct parse *p, sopno size); +static void stripsnug(struct parse *p, struct re_guts *g); +static void findmust(struct parse *p, struct re_guts *g); +static sopno pluscount(struct parse *p, struct re_guts *g); + +#ifdef __cplusplus +} +#endif +/* ========= end header generated by ./mkh ========= */ + +static RCHAR_T nuls[10]; /* place to point scanner in event of error */ + +/* + * macros for use with parse structure + * BEWARE: these know that the parse structure is named `p' !!! + */ +#define PEEK() (*p->next) +#define PEEK2() (*(p->next+1)) +#define MORE() (p->next < p->end) +#define MORE2() (p->next+1 < p->end) +#define SEE(c) (MORE() && PEEK() == (c)) +#define SEETWO(a, b) (MORE() && MORE2() && PEEK() == (a) && PEEK2() == (b)) +#define EAT(c) ((SEE(c)) ? (NEXT(), 1) : 0) +#define EATTWO(a, b) ((SEETWO(a, b)) ? (NEXT2(), 1) : 0) +#define NEXT() (p->next++) +#define NEXT2() (p->next += 2) +#define NEXTn(n) (p->next += (n)) +#define GETNEXT() (*p->next++) +#define SETERROR(e) seterr(p, (e)) +#define REQUIRE(co, e) ((co) || SETERROR(e)) +#define MUSTSEE(c, e) (REQUIRE(MORE() && PEEK() == (c), e)) +#define MUSTEAT(c, e) (REQUIRE(MORE() && GETNEXT() == (c), e)) +#define MUSTNOTSEE(c, e) (REQUIRE(!MORE() || PEEK() != (c), e)) +#define EMIT(op, sopnd) doemit(p, (sop)(op), (size_t)(sopnd)) +#define INSERT(op, pos) doinsert(p, (sop)(op), HERE()-(pos)+1, pos) +#define AHEAD(pos) dofwd(p, pos, HERE()-(pos)) +#define ASTERN(sop, pos) EMIT(sop, HERE()-pos) +#define HERE() (p->slen) +#define THERE() (p->slen - 1) +#define THERETHERE() (p->slen - 2) +#define DROP(n) (p->slen -= (n)) + +#ifndef NDEBUG +static int never = 0; /* for use in asserts; shuts lint up */ +#else +#define never 0 /* some s have bugs too */ +#endif + +#define MEMLIMIT 0x8000000 +#define MEMSIZE(p) \ + ((p)->ncsalloc / CHAR_BIT * (p)->g->csetsize + \ + (p)->ncsalloc * sizeof(cset) + \ + (p)->ssize * sizeof(sop)) +#define RECLIMIT 256 + +/* + - regcomp - interface for parser and compilation + */ +int /* 0 success, otherwise REG_something */ +regcomp(regex_t *preg, const RCHAR_T *pattern, int cflags) +{ + struct parse pa; + struct re_guts *g; + struct parse *p = &pa; + int i; + size_t len; +#ifdef REDEBUG +# define GOODFLAGS(f) (f) +#else +# define GOODFLAGS(f) ((f)&~REG_DUMP) +#endif + + cflags = GOODFLAGS(cflags); + if ((cflags®_EXTENDED) && (cflags®_NOSPEC)) + return(REG_INVARG); + + if (cflags®_PEND) { + if (preg->re_endp < pattern) + return(REG_INVARG); + len = preg->re_endp - pattern; + } else + len = STRLEN(pattern); + + /* do the mallocs early so failure handling is easy */ + g = (struct re_guts *)malloc(sizeof(struct re_guts) + + (NC-1)*sizeof(cat_t)); + if (g == NULL) + return(REG_ESPACE); + p->ssize = len/(size_t)2*(size_t)3 + (size_t)1; /* ugh */ + p->strip = (sop *)malloc(p->ssize * sizeof(sop)); + if (p->strip == NULL) { + free((char *)g); + return(REG_ESPACE); + } + p->stripdata = (RCHAR_T *)malloc(p->ssize * sizeof(RCHAR_T)); + if (p->stripdata == NULL) { + free((char *)p->strip); + free((char *)g); + return(REG_ESPACE); + } + p->slen = 0; + + /* set things up */ + p->g = g; + p->next = (RCHAR_T *)pattern; /* convenience; we do not modify it */ + p->end = p->next + len; + p->error = 0; + p->ncsalloc = 0; + for (i = 0; i < NPAREN; i++) { + p->pbegin[i] = 0; + p->pend[i] = 0; + } + g->csetsize = NC; + g->sets = NULL; + g->setbits = NULL; + g->ncsets = 0; + g->cflags = cflags; + g->iflags = 0; + g->nbol = 0; + g->neol = 0; + g->must = NULL; + g->mlen = 0; + g->nsub = 0; +#if 0 + g->ncategories = 1; /* category 0 is "everything else" */ + g->categories = &g->catspace[-(CHAR_MIN)]; + memset((char *)g->catspace, 0, NC*sizeof(cat_t)); +#endif + g->backrefs = 0; + + /* do it */ + EMIT(OEND, 0); + g->firststate = THERE(); + if (cflags®_EXTENDED) + p_ere(p, OUT, 0); + else if (cflags®_NOSPEC) + p_str(p); + else + p_bre(p, OUT, OUT, 0); + EMIT(OEND, 0); + g->laststate = THERE(); + + /* tidy up loose ends and fill things in */ + categorize(p, g); + stripsnug(p, g); + findmust(p, g); + g->nplus = pluscount(p, g); + g->magic = MAGIC2; + preg->re_nsub = g->nsub; + preg->re_g = g; + preg->re_magic = MAGIC1; +#ifndef REDEBUG + /* not debugging, so can't rely on the assert() in regexec() */ + if (g->iflags&BAD) + SETERROR(REG_ASSERT); +#endif + + /* win or lose, we're done */ + if (p->error != 0) /* lose */ + regfree(preg); + return(p->error); +} + +/* + - p_ere - ERE parser top level, concatenation and alternation + */ +static void +p_ere(struct parse *p, int stop, size_t reclimit) + /* character this ERE should end at */ +{ + char c; + sopno prevback = 0; + sopno prevfwd = 0; + sopno conc; + int first = 1; /* is this the first alternative? */ + + if (reclimit++ > RECLIMIT || p->error == REG_ESPACE) { + p->error = REG_ESPACE; + return; + } + + for (;;) { + /* do a bunch of concatenated expressions */ + conc = HERE(); + while (MORE() && (c = PEEK()) != '|' && c != stop) + p_ere_exp(p, reclimit); + (void)REQUIRE(HERE() != conc, REG_EMPTY); /* require nonempty */ + + if (!EAT('|')) + break; /* NOTE BREAK OUT */ + + if (first) { + INSERT(OCH_, conc); /* offset is wrong */ + prevfwd = conc; + prevback = conc; + first = 0; + } + ASTERN(OOR1, prevback); + prevback = THERE(); + AHEAD(prevfwd); /* fix previous offset */ + prevfwd = HERE(); + EMIT(OOR2, 0); /* offset is very wrong */ + } + + if (!first) { /* tail-end fixups */ + AHEAD(prevfwd); + ASTERN(O_CH, prevback); + } + + assert(!MORE() || SEE(stop)); +} + +/* + - p_ere_exp - parse one subERE, an atom possibly followed by a repetition op + */ +static void +p_ere_exp(struct parse *p, size_t reclimit) +{ + char c; + sopno pos; + int count; + int count2; + sopno subno; + int wascaret = 0; + + assert(MORE()); /* caller should have ensured this */ + c = GETNEXT(); + + pos = HERE(); + switch (c) { + case '(': + (void)REQUIRE(MORE(), REG_EPAREN); + p->g->nsub++; + subno = p->g->nsub; + if (subno < NPAREN) + p->pbegin[subno] = HERE(); + EMIT(OLPAREN, subno); + if (!SEE(')')) + p_ere(p, ')', reclimit); + if (subno < NPAREN) { + p->pend[subno] = HERE(); + assert(p->pend[subno] != 0); + } + EMIT(ORPAREN, subno); + (void)MUSTEAT(')', REG_EPAREN); + break; +#ifndef POSIX_MISTAKE + case ')': /* happens only if no current unmatched ( */ + /* + * You may ask, why the ifndef? Because I didn't notice + * this until slightly too late for 1003.2, and none of the + * other 1003.2 regular-expression reviewers noticed it at + * all. So an unmatched ) is legal POSIX, at least until + * we can get it fixed. + */ + SETERROR(REG_EPAREN); + break; +#endif + case '^': + EMIT(OBOL, 0); + p->g->iflags |= USEBOL; + p->g->nbol++; + wascaret = 1; + break; + case '$': + EMIT(OEOL, 0); + p->g->iflags |= USEEOL; + p->g->neol++; + break; + case '|': + SETERROR(REG_EMPTY); + break; + case '*': + case '+': + case '?': + SETERROR(REG_BADRPT); + break; + case '.': + if (p->g->cflags®_NEWLINE) + nonnewline(p); + else + EMIT(OANY, 0); + break; + case '[': + p_bracket(p); + break; + case '\\': + (void)REQUIRE(MORE(), REG_EESCAPE); + c = GETNEXT(); + ordinary(p, c); + break; + case '{': /* okay as ordinary except if digit follows */ + (void)REQUIRE(!MORE() || !ISDIGIT((UCHAR_T)PEEK()), REG_BADRPT); + /* FALLTHROUGH */ + default: + ordinary(p, c); + break; + } + + if (!MORE()) + return; + c = PEEK(); + /* we call { a repetition if followed by a digit */ + if (!( c == '*' || c == '+' || c == '?' || + (c == '{' && MORE2() && ISDIGIT((UCHAR_T)PEEK2())) )) + return; /* no repetition, we're done */ + NEXT(); + + (void)REQUIRE(!wascaret, REG_BADRPT); + switch (c) { + case '*': /* implemented as +? */ + /* this case does not require the (y|) trick, noKLUDGE */ + INSERT(OPLUS_, pos); + ASTERN(O_PLUS, pos); + INSERT(OQUEST_, pos); + ASTERN(O_QUEST, pos); + break; + case '+': + INSERT(OPLUS_, pos); + ASTERN(O_PLUS, pos); + break; + case '?': + /* KLUDGE: emit y? as (y|) until subtle bug gets fixed */ + INSERT(OCH_, pos); /* offset slightly wrong */ + ASTERN(OOR1, pos); /* this one's right */ + AHEAD(pos); /* fix the OCH_ */ + EMIT(OOR2, 0); /* offset very wrong... */ + AHEAD(THERE()); /* ...so fix it */ + ASTERN(O_CH, THERETHERE()); + break; + case '{': + count = p_count(p); + if (EAT(',')) { + if (ISDIGIT((UCHAR_T)PEEK())) { + count2 = p_count(p); + (void)REQUIRE(count <= count2, REG_BADBR); + } else /* single number with comma */ + count2 = INFINITY; + } else /* just a single number */ + count2 = count; + repeat(p, pos, count, count2, 0); + if (!EAT('}')) { /* error heuristics */ + while (MORE() && PEEK() != '}') + NEXT(); + (void)REQUIRE(MORE(), REG_EBRACE); + SETERROR(REG_BADBR); + } + break; + } + + if (!MORE()) + return; + c = PEEK(); + if (!( c == '*' || c == '+' || c == '?' || + (c == '{' && MORE2() && ISDIGIT((UCHAR_T)PEEK2())) ) ) + return; + SETERROR(REG_BADRPT); +} + +/* + - p_str - string (no metacharacters) "parser" + */ +static void +p_str(struct parse *p) +{ + (void)REQUIRE(MORE(), REG_EMPTY); + while (MORE()) + ordinary(p, GETNEXT()); +} + +/* + - p_bre - BRE parser top level, anchoring and concatenation + * Giving end1 as OUT essentially eliminates the end1/end2 check. + * + * This implementation is a bit of a kludge, in that a trailing $ is first + * taken as an ordinary character and then revised to be an anchor. The + * only undesirable side effect is that '$' gets included as a character + * category in such cases. This is fairly harmless; not worth fixing. + * The amount of lookahead needed to avoid this kludge is excessive. + */ +static void +p_bre(struct parse *p, + int end1, /* first terminating character */ + int end2, /* second terminating character */ + size_t reclimit) +{ + sopno start; + int first = 1; /* first subexpression? */ + int wasdollar = 0; + + if (reclimit++ > RECLIMIT || p->error == REG_ESPACE) { + p->error = REG_ESPACE; + return; + } + + start = HERE(); + + if (EAT('^')) { + EMIT(OBOL, 0); + p->g->iflags |= USEBOL; + p->g->nbol++; + } + while (MORE() && !SEETWO(end1, end2)) { + wasdollar = p_simp_re(p, first, reclimit); + first = 0; + } + if (wasdollar) { /* oops, that was a trailing anchor */ + DROP(1); + EMIT(OEOL, 0); + p->g->iflags |= USEEOL; + p->g->neol++; + } + + (void)REQUIRE(HERE() != start, REG_EMPTY); /* require nonempty */ +} + +/* + - p_simp_re - parse a simple RE, an atom possibly followed by a repetition + */ +static int /* was the simple RE an unbackslashed $? */ +p_simp_re(struct parse *p, + int starordinary, /* is a leading * an ordinary character? */ + size_t reclimit) +{ + int c; + int count; + int count2; + sopno pos; + int i; + sopno subno; + int backsl; + + pos = HERE(); /* repetion op, if any, covers from here */ + + assert(MORE()); /* caller should have ensured this */ + c = GETNEXT(); + backsl = c == '\\'; + if (backsl) { + (void)REQUIRE(MORE(), REG_EESCAPE); + c = (unsigned char)GETNEXT(); + switch (c) { + case '{': + SETERROR(REG_BADRPT); + break; + case '(': + p->g->nsub++; + subno = p->g->nsub; + if (subno < NPAREN) + p->pbegin[subno] = HERE(); + EMIT(OLPAREN, subno); + /* the MORE here is an error heuristic */ + if (MORE() && !SEETWO('\\', ')')) + p_bre(p, '\\', ')', reclimit); + if (subno < NPAREN) { + p->pend[subno] = HERE(); + assert(p->pend[subno] != 0); + } + EMIT(ORPAREN, subno); + (void)REQUIRE(EATTWO('\\', ')'), REG_EPAREN); + break; + case ')': /* should not get here -- must be user */ + case '}': + SETERROR(REG_EPAREN); + break; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + i = c - '0'; + assert(i < NPAREN); + if (p->pend[i] != 0) { + assert(i <= p->g->nsub); + EMIT(OBACK_, i); + assert(p->pbegin[i] != 0); + assert(p->strip[p->pbegin[i]] == OLPAREN); + assert(p->strip[p->pend[i]] == ORPAREN); + (void) dupl(p, p->pbegin[i]+1, p->pend[i]); + EMIT(O_BACK, i); + } else + SETERROR(REG_ESUBREG); + p->g->backrefs = 1; + break; + default: + ordinary(p, c); + break; + } + } else { + switch (c) { + case '.': + if (p->g->cflags®_NEWLINE) + nonnewline(p); + else + EMIT(OANY, 0); + break; + case '[': + p_bracket(p); + break; + case '*': + (void)REQUIRE(starordinary, REG_BADRPT); + /* FALLTHROUGH */ + default: + ordinary(p, c); + break; + } + } + + if (EAT('*')) { /* implemented as +? */ + /* this case does not require the (y|) trick, noKLUDGE */ + INSERT(OPLUS_, pos); + ASTERN(O_PLUS, pos); + INSERT(OQUEST_, pos); + ASTERN(O_QUEST, pos); + } else if (EATTWO('\\', '{')) { + count = p_count(p); + if (EAT(',')) { + if (MORE() && ISDIGIT((UCHAR_T)PEEK())) { + count2 = p_count(p); + (void)REQUIRE(count <= count2, REG_BADBR); + } else /* single number with comma */ + count2 = INFINITY; + } else /* just a single number */ + count2 = count; + repeat(p, pos, count, count2, reclimit); + if (!EATTWO('\\', '}')) { /* error heuristics */ + while (MORE() && !SEETWO('\\', '}')) + NEXT(); + (void)REQUIRE(MORE(), REG_EBRACE); + SETERROR(REG_BADBR); + } + } else if (!backsl && c == (unsigned char)'$') /* $ (but not \$) ends it */ + return(1); + + return(0); +} + +/* + - p_count - parse a repetition count + */ +static int /* the value */ +p_count(struct parse *p) +{ + int count = 0; + int ndigits = 0; + + while (MORE() && ISDIGIT((UCHAR_T)PEEK()) && count <= DUPMAX) { + count = count*10 + (GETNEXT() - '0'); + ndigits++; + } + + (void)REQUIRE(ndigits > 0 && count <= DUPMAX, REG_BADBR); + return(count); +} + +/* + - p_bracket - parse a bracketed character list + * + * Note a significant property of this code: if the allocset() did SETERROR, + * no set operations are done. + */ +static void +p_bracket(struct parse *p) +{ + cset *cs; + int invert = 0; + static RCHAR_T bow[] = { '[', ':', '<', ':', ']', ']' }; + static RCHAR_T eow[] = { '[', ':', '>', ':', ']', ']' }; + + cs = allocset(p); + if (cs == NULL) + return; + + /* Dept of Truly Sickening Special-Case Kludges */ + if (p->next + 5 < p->end && MEMCMP(p->next, bow, 6) == 0) { + EMIT(OBOW, 0); + NEXTn(6); + return; + } + if (p->next + 5 < p->end && MEMCMP(p->next, eow, 6) == 0) { + EMIT(OEOW, 0); + NEXTn(6); + return; + } + + if (EAT('^')) + invert++; /* make note to invert set at end */ + if (EAT(']')) + CHadd(cs, ']'); + else if (EAT('-')) + CHadd(cs, '-'); + while (MORE() && PEEK() != ']' && !SEETWO('-', ']')) + p_b_term(p, cs); + if (EAT('-')) + CHadd(cs, '-'); + (void)MUSTEAT(']', REG_EBRACK); + + if (p->error != 0) /* don't mess things up further */ + return; + + if (p->g->cflags®_ICASE) { + int i; + int ci; + + for (i = p->g->csetsize - 1; i >= 0; i--) + if (CHIN(cs, i) && isalpha(i)) { + ci = othercase(i); + if (ci != i) + CHadd(cs, ci); + } + if (cs->multis != NULL) + mccase(p, cs); + } + if (invert) { + int i; + + for (i = p->g->csetsize - 1; i >= 0; i--) + if (CHIN(cs, i)) + CHsub(cs, i); + else + CHadd(cs, i); + if (p->g->cflags®_NEWLINE) + CHsub(cs, '\n'); + if (cs->multis != NULL) + mcinvert(p, cs); + } + + assert(cs->multis == NULL); /* xxx */ + + if (nch(p, cs) == 1) { /* optimize singleton sets */ + ordinary(p, firstch(p, cs)); + freeset(p, cs); + } else + EMIT(OANYOF, freezeset(p, cs)); +} + +/* + - p_b_term - parse one term of a bracketed character list + */ +static void +p_b_term(struct parse *p, cset *cs) +{ + char c; + char start, finish; + int i; + + /* classify what we've got */ + switch ((MORE()) ? PEEK() : '\0') { + case '[': + c = (MORE2()) ? PEEK2() : '\0'; + break; + case '-': + SETERROR(REG_ERANGE); + return; /* NOTE RETURN */ + break; + default: + c = '\0'; + break; + } + + switch (c) { + case ':': /* character class */ + NEXT2(); + (void)REQUIRE(MORE(), REG_EBRACK); + c = PEEK(); + (void)REQUIRE(c != '-' && c != ']', REG_ECTYPE); + p_b_cclass(p, cs); + (void)REQUIRE(MORE(), REG_EBRACK); + (void)REQUIRE(EATTWO(':', ']'), REG_ECTYPE); + break; + case '=': /* equivalence class */ + NEXT2(); + (void)REQUIRE(MORE(), REG_EBRACK); + c = PEEK(); + (void)REQUIRE(c != '-' && c != ']', REG_ECOLLATE); + p_b_eclass(p, cs); + (void)REQUIRE(MORE(), REG_EBRACK); + (void)REQUIRE(EATTWO('=', ']'), REG_ECOLLATE); + break; + default: /* symbol, ordinary character, or range */ +/* xxx revision needed for multichar stuff */ + start = p_b_symbol(p); + if (SEE('-') && MORE2() && PEEK2() != ']') { + /* range */ + NEXT(); + if (EAT('-')) + finish = '-'; + else + finish = p_b_symbol(p); + } else + finish = start; +/* xxx what about signed chars here... */ + (void)REQUIRE(start <= finish, REG_ERANGE); + for (i = start; i <= finish; i++) + CHadd(cs, i); + break; + } +} + +/* + - p_b_cclass - parse a character-class name and deal with it + */ +static void +p_b_cclass(struct parse *p, cset *cs) +{ + RCHAR_T *sp = p->next; + struct cclass *cp; + size_t len; + const char *u; + char c; + + while (MORE() && isalpha(PEEK())) + NEXT(); + len = p->next - sp; + for (cp = cclasses; cp->name != NULL; cp++) + if (STRLEN(cp->name) == len && !MEMCMP(cp->name, sp, len)) + break; + if (cp->name == NULL) { + /* oops, didn't find it */ + SETERROR(REG_ECTYPE); + return; + } + + u = cp->chars; + while ((c = *u++) != '\0') + CHadd(cs, c); + for (u = cp->multis; *u != '\0'; u += strlen(u) + 1) + MCadd(p, cs, u); +} + +/* + - p_b_eclass - parse an equivalence-class name and deal with it + * + * This implementation is incomplete. xxx + */ +static void +p_b_eclass(struct parse *p, cset *cs) +{ + char c; + + c = p_b_coll_elem(p, '='); + CHadd(cs, c); +} + +/* + - p_b_symbol - parse a character or [..]ed multicharacter collating symbol + */ +static char /* value of symbol */ +p_b_symbol(struct parse *p) +{ + char value; + + (void)REQUIRE(MORE(), REG_EBRACK); + if (!EATTWO('[', '.')) + return(GETNEXT()); + + /* collating symbol */ + value = p_b_coll_elem(p, '.'); + (void)REQUIRE(EATTWO('.', ']'), REG_ECOLLATE); + return(value); +} + +/* + - p_b_coll_elem - parse a collating-element name and look it up + */ +static char /* value of collating element */ +p_b_coll_elem(struct parse *p, int endc) + + /* name ended by endc,']' */ +{ + RCHAR_T *sp = p->next; + struct cname *cp; + size_t len; + + while (MORE() && !SEETWO(endc, ']')) + NEXT(); + if (!MORE()) { + SETERROR(REG_EBRACK); + return(0); + } + len = p->next - sp; + for (cp = cnames; cp->name != NULL; cp++) + if (STRLEN(cp->name) == len && MEMCMP(cp->name, sp, len)) + return(cp->code); /* known name */ + if (len == 1) + return(*sp); /* single character */ + SETERROR(REG_ECOLLATE); /* neither */ + return(0); +} + +/* + - othercase - return the case counterpart of an alphabetic + */ +static char /* if no counterpart, return ch */ +othercase(int ch) +{ + assert(isalpha(ch)); + if (isupper(ch)) + return(tolower(ch)); + else if (islower(ch)) + return(toupper(ch)); + else /* peculiar, but could happen */ + return(ch); +} + +/* + - bothcases - emit a dualcase version of a two-case character + * + * Boy, is this implementation ever a kludge... + */ +static void +bothcases(struct parse *p, int ch) +{ + RCHAR_T *oldnext = p->next; + RCHAR_T *oldend = p->end; + RCHAR_T bracket[3]; + + assert(othercase(ch) != ch); /* p_bracket() would recurse */ + p->next = bracket; + p->end = bracket+2; + bracket[0] = ch; + bracket[1] = ']'; + bracket[2] = '\0'; + p_bracket(p); + assert(p->next == bracket+2); + p->next = oldnext; + p->end = oldend; +} + +/* + - ordinary - emit an ordinary character + */ +static void +ordinary(struct parse *p, int ch) +{ +/* + cat_t *cap = p->g->categories; +*/ + + if ((p->g->cflags®_ICASE) && isalpha(ch) && othercase(ch) != ch) + bothcases(p, ch); + else { + EMIT(OCHAR, (UCHAR_T)ch); +/* + if (cap[ch] == 0) + cap[ch] = p->g->ncategories++; +*/ + } +} + +/* + - nonnewline - emit REG_NEWLINE version of OANY + * + * Boy, is this implementation ever a kludge... + */ +static void +nonnewline(struct parse *p) +{ + RCHAR_T *oldnext = p->next; + RCHAR_T *oldend = p->end; + RCHAR_T bracket[4]; + + p->next = bracket; + p->end = bracket+3; + bracket[0] = '^'; + bracket[1] = '\n'; + bracket[2] = ']'; + bracket[3] = '\0'; + p_bracket(p); + assert(p->next == bracket+3); + p->next = oldnext; + p->end = oldend; +} + +/* + - repeat - generate code for a bounded repetition, recursively if needed + */ +static void +repeat(struct parse *p, + sopno start, /* operand from here to end of strip */ + int from, /* repeated from this number */ + int to, /* to this number of times (maybe INFINITY) */ + size_t reclimit) +{ + sopno finish; +# define N 2 +# define INF 3 +# define REP(f, t) ((f)*8 + (t)) +# define MAP(n) (((n) <= 1) ? (n) : ((n) == INFINITY) ? INF : N) + sopno copy; + + if (reclimit++ > RECLIMIT) + p->error = REG_ESPACE; + if (p->error) + return; + + finish = HERE(); + + assert(from <= to); + + switch (REP(MAP(from), MAP(to))) { + case REP(0, 0): /* must be user doing this */ + DROP(finish-start); /* drop the operand */ + break; + case REP(0, 1): /* as x{1,1}? */ + case REP(0, N): /* as x{1,n}? */ + case REP(0, INF): /* as x{1,}? */ + /* KLUDGE: emit y? as (y|) until subtle bug gets fixed */ + INSERT(OCH_, start); /* offset is wrong... */ + repeat(p, start+1, 1, to, reclimit); + ASTERN(OOR1, start); + AHEAD(start); /* ... fix it */ + EMIT(OOR2, 0); + AHEAD(THERE()); + ASTERN(O_CH, THERETHERE()); + break; + case REP(1, 1): /* trivial case */ + /* done */ + break; + case REP(1, N): /* as x?x{1,n-1} */ + /* KLUDGE: emit y? as (y|) until subtle bug gets fixed */ + INSERT(OCH_, start); + ASTERN(OOR1, start); + AHEAD(start); + EMIT(OOR2, 0); /* offset very wrong... */ + AHEAD(THERE()); /* ...so fix it */ + ASTERN(O_CH, THERETHERE()); + copy = dupl(p, start+1, finish+1); + assert(copy == finish+4); + repeat(p, copy, 1, to-1, reclimit); + break; + case REP(1, INF): /* as x+ */ + INSERT(OPLUS_, start); + ASTERN(O_PLUS, start); + break; + case REP(N, N): /* as xx{m-1,n-1} */ + copy = dupl(p, start, finish); + repeat(p, copy, from-1, to-1, reclimit); + break; + case REP(N, INF): /* as xx{n-1,INF} */ + copy = dupl(p, start, finish); + repeat(p, copy, from-1, to, reclimit); + break; + default: /* "can't happen" */ + SETERROR(REG_ASSERT); /* just in case */ + break; + } +} + +/* + - seterr - set an error condition + */ +static int /* useless but makes type checking happy */ +seterr(struct parse *p, int e) +{ + if (p->error == 0) /* keep earliest error condition */ + p->error = e; + p->next = nuls; /* try to bring things to a halt */ + p->end = nuls; + return(0); /* make the return value well-defined */ +} + +/* + - allocset - allocate a set of characters for [] + */ +static cset * +allocset(struct parse *p) +{ + int no = p->g->ncsets++; + size_t nc; + size_t nbytes; + cset *cs; + size_t css = (size_t)p->g->csetsize; + int i; + + if (no >= p->ncsalloc) { /* need another column of space */ + p->ncsalloc += CHAR_BIT; + nc = p->ncsalloc; + assert(nc % CHAR_BIT == 0); + nbytes = nc / CHAR_BIT * css; + if (MEMSIZE(p) > MEMLIMIT) + goto oomem; + if (p->g->sets == NULL) + p->g->sets = (cset *)malloc(nc * sizeof(cset)); + else + p->g->sets = (cset *)realloc((char *)p->g->sets, + nc * sizeof(cset)); + if (p->g->setbits == NULL) + p->g->setbits = (uch *)malloc(nbytes); + else { + p->g->setbits = (uch *)realloc((char *)p->g->setbits, + nbytes); + /* xxx this isn't right if setbits is now NULL */ + for (i = 0; i < no; i++) + p->g->sets[i].ptr = p->g->setbits + css*(i/CHAR_BIT); + } + if (p->g->sets != NULL && p->g->setbits != NULL) + memset((char *)p->g->setbits + (nbytes - css), + 0, css); + else { +oomem: + no = 0; + SETERROR(REG_ESPACE); + /* caller's responsibility not to do set ops */ + return NULL; + } + } + + cs = &p->g->sets[no]; + cs->ptr = p->g->setbits + css*((no)/CHAR_BIT); + cs->mask = 1 << ((no) % CHAR_BIT); + cs->hash = 0; + cs->smultis = 0; + cs->multis = NULL; + + return(cs); +} + +/* + - freeset - free a now-unused set + */ +static void +freeset(struct parse *p, cset *cs) +{ + size_t i; + cset *top = &p->g->sets[p->g->ncsets]; + size_t css = (size_t)p->g->csetsize; + + for (i = 0; i < css; i++) + CHsub(cs, i); + if (cs == top-1) /* recover only the easy case */ + p->g->ncsets--; +} + +/* + - freezeset - final processing on a set of characters + * + * The main task here is merging identical sets. This is usually a waste + * of time (although the hash code minimizes the overhead), but can win + * big if REG_ICASE is being used. REG_ICASE, by the way, is why the hash + * is done using addition rather than xor -- all ASCII [aA] sets xor to + * the same value! + */ +static int /* set number */ +freezeset(struct parse *p, cset *cs) +{ + uch h = cs->hash; + size_t i; + cset *top = &p->g->sets[p->g->ncsets]; + cset *cs2; + size_t css = (size_t)p->g->csetsize; + + /* look for an earlier one which is the same */ + for (cs2 = &p->g->sets[0]; cs2 < top; cs2++) + if (cs2->hash == h && cs2 != cs) { + /* maybe */ + for (i = 0; i < css; i++) + if (!!CHIN(cs2, i) != !!CHIN(cs, i)) + break; /* no */ + if (i == css) + break; /* yes */ + } + + if (cs2 < top) { /* found one */ + freeset(p, cs); + cs = cs2; + } + + return((int)(cs - p->g->sets)); +} + +/* + - firstch - return first character in a set (which must have at least one) + */ +static int /* character; there is no "none" value */ +firstch(struct parse *p, cset *cs) +{ + size_t i; + size_t css = (size_t)p->g->csetsize; + + for (i = 0; i < css; i++) + if (CHIN(cs, i)) + return((char)i); + assert(never); + return(0); /* arbitrary */ +} + +/* + - nch - number of characters in a set + */ +static int +nch(struct parse *p, cset *cs) +{ + size_t i; + size_t css = (size_t)p->g->csetsize; + int n = 0; + + for (i = 0; i < css; i++) + if (CHIN(cs, i)) + n++; + return(n); +} + +/* + - mcadd - add a collating element to a cset + */ +static void +mcadd(struct parse *p, cset *cs, const char *cp) +{ + size_t oldend = cs->smultis; + void *np; + + cs->smultis += strlen(cp) + 1; + np = realloc(cs->multis, cs->smultis); + if (np == NULL) { + if (cs->multis) + free(cs->multis); + cs->multis = NULL; + SETERROR(REG_ESPACE); + return; + } + cs->multis = np; + + strlcpy(cs->multis + oldend - 1, cp, cs->smultis - oldend + 1); +} + +/* + - mcinvert - invert the list of collating elements in a cset + * + * This would have to know the set of possibilities. Implementation + * is deferred. + */ +static void +mcinvert(struct parse *p, cset *cs) +{ + assert(cs->multis == NULL); /* xxx */ +} + +/* + - mccase - add case counterparts of the list of collating elements in a cset + * + * This would have to know the set of possibilities. Implementation + * is deferred. + */ +static void +mccase(struct parse *p, cset *cs) +{ + assert(cs->multis == NULL); /* xxx */ +} + +#ifdef notdef +/* + - isinsets - is this character in any sets? + */ +static int /* predicate */ +isinsets(struct re_guts *g, int c) +{ + uch *col; + int i; + int ncols = (g->ncsets+(CHAR_BIT-1)) / CHAR_BIT; + unsigned uc = (unsigned char)c; + + for (i = 0, col = g->setbits; i < ncols; i++, col += g->csetsize) + if (col[uc] != 0) + return(1); + return(0); +} + +/* + - samesets - are these two characters in exactly the same sets? + */ +static int /* predicate */ +samesets(struct re_guts *g, int c1, int c2) +{ + uch *col; + int i; + int ncols = (g->ncsets+(CHAR_BIT-1)) / CHAR_BIT; + unsigned uc1 = (unsigned char)c1; + unsigned uc2 = (unsigned char)c2; + + for (i = 0, col = g->setbits; i < ncols; i++, col += g->csetsize) + if (col[uc1] != col[uc2]) + return(0); + return(1); +} +#endif + +/* + - categorize - sort out character categories + */ +static void +categorize(struct parse *p, struct re_guts *g) +{ +#ifdef notdef + cat_t *cats = g->categories; + int c; + int c2; + cat_t cat; + + /* avoid making error situations worse */ + if (p->error != 0) + return; + + for (c = CHAR_MIN; c <= CHAR_MAX; c++) + if (cats[c] == 0 && isinsets(g, c)) { + cat = g->ncategories++; + cats[c] = cat; + for (c2 = c+1; c2 <= CHAR_MAX; c2++) + if (cats[c2] == 0 && samesets(g, c, c2)) + cats[c2] = cat; + } +#endif +} + +/* + - dupl - emit a duplicate of a bunch of sops + */ +static sopno /* start of duplicate */ +dupl(struct parse *p, + sopno start, /* from here */ + sopno finish) /* to this less one */ +{ + sopno ret = HERE(); + sopno len = finish - start; + + assert(finish >= start); + if (len == 0) + return(ret); + if (!enlarge(p, p->ssize + len)) /* this many unexpected additions */ + return ret; + assert(p->ssize >= p->slen + len); + (void) memcpy((char *)(p->strip + p->slen), + (char *)(p->strip + start), (size_t)len*sizeof(sop)); + (void) memcpy((char *)(p->stripdata + p->slen), + (char *)(p->stripdata + start), (size_t)len*sizeof(RCHAR_T)); + p->slen += len; + return(ret); +} + +/* + - doemit - emit a strip operator + * + * It might seem better to implement this as a macro with a function as + * hard-case backup, but it's just too big and messy unless there are + * some changes to the data structures. Maybe later. + */ +static void +doemit(struct parse *p, sop op, size_t opnd) +{ + /* avoid making error situations worse */ + if (p->error != 0) + return; + + /* deal with oversize operands ("can't happen", more or less) */ + assert(opnd < 1); + + /* deal with undersized strip */ + if (p->slen >= p->ssize) + if (!enlarge(p, (p->ssize+1) / 2 * 3)) /* +50% */ + return; + + /* finally, it's all reduced to the easy case */ + p->strip[p->slen] = op; + p->stripdata[p->slen] = opnd; + p->slen++; +} + +/* + - doinsert - insert a sop into the strip + */ +static void +doinsert(struct parse *p, sop op, size_t opnd, sopno pos) +{ + sopno sn; + sop s; + RCHAR_T d; + int i; + + /* avoid making error situations worse */ + if (p->error != 0) + return; + + sn = HERE(); + EMIT(op, opnd); /* do checks, ensure space */ + assert(HERE() == sn+1); + s = p->strip[sn]; + d = p->stripdata[sn]; + + /* adjust paren pointers */ + assert(pos > 0); + for (i = 1; i < NPAREN; i++) { + if (p->pbegin[i] >= pos) { + p->pbegin[i]++; + } + if (p->pend[i] >= pos) { + p->pend[i]++; + } + } + + memmove((char *)&p->strip[pos+1], (char *)&p->strip[pos], + (HERE()-pos-1)*sizeof(sop)); + memmove((char *)&p->stripdata[pos+1], (char *)&p->stripdata[pos], + (HERE()-pos-1)*sizeof(RCHAR_T)); + p->strip[pos] = s; + p->stripdata[pos] = d; +} + +/* + - dofwd - complete a forward reference + */ +static void +dofwd(struct parse *p, sopno pos, sop value) +{ + /* avoid making error situations worse */ + if (p->error != 0) + return; + + assert(value < 1); + p->stripdata[pos] = value; +} + +/* + - enlarge - enlarge the strip + */ +static int +enlarge(struct parse *p, sopno size) +{ + sop *sp; + RCHAR_T *dp; + sopno osize; + + if (p->ssize >= size) + return 1; + + osize = p->ssize; + p->ssize = size; + if (MEMSIZE(p) > MEMLIMIT) + goto oomem; + sp = realloc(p->strip, p->ssize * sizeof(sop)); + if (sp == NULL) + goto oomem; + p->strip = sp; + dp = realloc(p->stripdata, p->ssize * sizeof(RCHAR_T)); + if (dp == NULL) { +oomem: + p->ssize = osize; + SETERROR(REG_ESPACE); + return 0; + } + p->stripdata = dp; + return 1; +} + +/* + - stripsnug - compact the strip + */ +static void +stripsnug(struct parse *p, struct re_guts *g) +{ + g->nstates = p->slen; + g->strip = (sop *)realloc((char *)p->strip, + p->slen * sizeof(sop)); + if (g->strip == NULL) { + SETERROR(REG_ESPACE); + g->strip = p->strip; + } + g->stripdata = (RCHAR_T *)realloc((char *)p->stripdata, + p->slen * sizeof(RCHAR_T)); + if (g->stripdata == NULL) { + SETERROR(REG_ESPACE); + g->stripdata = p->stripdata; + } +} + +/* + - findmust - fill in must and mlen with longest mandatory literal string + * + * This algorithm could do fancy things like analyzing the operands of | + * for common subsequences. Someday. This code is simple and finds most + * of the interesting cases. + * + * Note that must and mlen got initialized during setup. + */ +static void +findmust(struct parse *p, struct re_guts *g) +{ + sop *scans; + RCHAR_T *scand; + sop *starts = 0; + RCHAR_T *startd = NULL; + sop *newstarts = 0; + RCHAR_T *newstartd = NULL; + sopno newlen; + sop s; + RCHAR_T d; + RCHAR_T *cp; + sopno i; + + /* avoid making error situations worse */ + if (p->error != 0) + return; + + /* find the longest OCHAR sequence in strip */ + newlen = 0; + scans = g->strip + 1; + scand = g->stripdata + 1; + do { + s = *scans++; + d = *scand++; + switch (s) { + case OCHAR: /* sequence member */ + if (newlen == 0) { /* new sequence */ + newstarts = scans - 1; + newstartd = scand - 1; + } + newlen++; + break; + case OPLUS_: /* things that don't break one */ + case OLPAREN: + case ORPAREN: + break; + case OQUEST_: /* things that must be skipped */ + case OCH_: + scans--; + scand--; + do { + scans += d; + scand += d; + s = *scans; + d = *scand; + /* assert() interferes w debug printouts */ + if (s != O_QUEST && s != O_CH && s != OOR2) { + g->iflags |= BAD; + return; + } + } while (s != O_QUEST && s != O_CH); + /* fallthrough */ + default: /* things that break a sequence */ + if (newlen > g->mlen) { /* ends one */ + starts = newstarts; + startd = newstartd; + g->mlen = newlen; + } + newlen = 0; + break; + } + } while (s != OEND); + + if (g->mlen == 0) /* there isn't one */ + return; + + /* turn it into a character string */ + g->must = malloc(((size_t)g->mlen + 1) * sizeof(RCHAR_T)); + if (g->must == NULL) { /* argh; just forget it */ + g->mlen = 0; + return; + } + cp = g->must; + scans = starts; + scand = startd; + for (i = g->mlen; i > 0; i--) { + for (;;) { + s = *scans++; + d = *scand++; + if (s == OCHAR) + break; + } + assert(cp < g->must + g->mlen); + *cp++ = d; + } + assert(cp == g->must + g->mlen); + *cp++ = '\0'; /* just on general principles */ +} + +/* + - pluscount - count + nesting + */ +static sopno /* nesting depth */ +pluscount(struct parse *p, struct re_guts *g) +{ + sop *scan; + sop s; + sopno plusnest = 0; + sopno maxnest = 0; + + if (p->error != 0) + return(0); /* there may not be an OEND */ + + scan = g->strip + 1; + do { + s = *scan++; + switch (s) { + case OPLUS_: + plusnest++; + break; + case O_PLUS: + if (plusnest > maxnest) + maxnest = plusnest; + plusnest--; + break; + } + } while (s != OEND); + if (plusnest != 0) + g->iflags |= BAD; + return(maxnest); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/regex/regcomp.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/regex/regerror.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/regex/regerror.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/regex/regerror.c (revision 366308) @@ -0,0 +1,171 @@ +/* $NetBSD: regerror.c,v 1.2 2008/12/05 22:51:43 christos Exp $ */ + +/*- + * Copyright (c) 1992, 1993, 1994 Henry Spencer. + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Henry Spencer of the University of Toronto. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)regerror.c 8.3 (Berkeley) 3/19/94 + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)regerror.c 8.3 (Berkeley) 3/19/94"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +/* ========= begin header generated by ./mkh ========= */ +#ifdef __cplusplus +extern "C" { +#endif + +/* === regerror.c === */ +static char *regatoi(const regex_t *preg, char *localbuf); + +#ifdef __cplusplus +} +#endif +/* ========= end header generated by ./mkh ========= */ +/* + = #define REG_NOMATCH 1 + = #define REG_BADPAT 2 + = #define REG_ECOLLATE 3 + = #define REG_ECTYPE 4 + = #define REG_EESCAPE 5 + = #define REG_ESUBREG 6 + = #define REG_EBRACK 7 + = #define REG_EPAREN 8 + = #define REG_EBRACE 9 + = #define REG_BADBR 10 + = #define REG_ERANGE 11 + = #define REG_ESPACE 12 + = #define REG_BADRPT 13 + = #define REG_EMPTY 14 + = #define REG_ASSERT 15 + = #define REG_INVARG 16 + = #define REG_ATOI 255 // convert name to number (!) + = #define REG_ITOA 0400 // convert number to name (!) + */ +static struct rerr { + int code; + const char *name; + const char *explain; +} rerrs[] = { + { REG_NOMATCH, "REG_NOMATCH", "regexec() failed to match" }, + { REG_BADPAT, "REG_BADPAT", "invalid regular expression" }, + { REG_ECOLLATE, "REG_ECOLLATE", "invalid collating element" }, + { REG_ECTYPE, "REG_ECTYPE", "invalid character class" }, + { REG_EESCAPE, "REG_EESCAPE", "trailing backslash (\\)" }, + { REG_ESUBREG, "REG_ESUBREG", "invalid backreference number" }, + { REG_EBRACK, "REG_EBRACK", "brackets ([ ]) not balanced" }, + { REG_EPAREN, "REG_EPAREN", "parentheses not balanced" }, + { REG_EBRACE, "REG_EBRACE", "braces not balanced" }, + { REG_BADBR, "REG_BADBR", "invalid repetition count(s)" }, + { REG_ERANGE, "REG_ERANGE", "invalid character range" }, + { REG_ESPACE, "REG_ESPACE", "out of memory" }, + { REG_BADRPT, "REG_BADRPT", "repetition-operator operand invalid" }, + { REG_EMPTY, "REG_EMPTY", "empty (sub)expression" }, + { REG_ASSERT, "REG_ASSERT", "\"can't happen\" -- you found a bug" }, + { REG_INVARG, "REG_INVARG", "invalid argument to regex routine" }, + { 0, "", "*** unknown regexp error code ***" }, +}; + +/* + - regerror - the interface to error numbers + = extern size_t regerror(int, const regex_t *, char *, size_t); + */ +/* ARGSUSED */ +size_t +regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size) +{ + struct rerr *r; + size_t len; + int target = errcode &~ REG_ITOA; + const char *s; + char convbuf[50]; + + if (errcode == REG_ATOI) + s = regatoi(preg, convbuf); + else { + for (r = rerrs; r->code != 0; r++) + if (r->code == target) + break; + + if (errcode®_ITOA) { + if (r->code != 0) { + assert(strlen(r->name) < sizeof(convbuf)); + (void) strlcpy(convbuf, r->name, sizeof(convbuf)); + } else + (void) snprintf(convbuf, sizeof(convbuf), + "REG_0x%x", target); + s = convbuf; + } else + s = r->explain; + } + + len = strlen(s) + 1; + if (errbuf_size > 0) { + strlcpy(errbuf, s, errbuf_size); + } + + return(len); +} + +/* + - regatoi - internal routine to implement REG_ATOI + */ +static char * +regatoi(const regex_t *preg, char *localbuf) +{ +#if 0 /* we don't seem to use this and it gives a warning. */ + struct rerr *r; + size_t siz; + char *p; + + for (r = rerrs; r->code != 0; r++) + if (strcmp(r->name, preg->re_endp) == 0) + break; + if (r->code == 0) + return("0"); + + sprintf(localbuf, "%d", r->code); +#else + *localbuf = '\0'; +#endif + return(localbuf); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/regex/regerror.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/regex/regex.3 =================================================================== --- vendor/nvi/2.2.0-05ed8b9/regex/regex.3 (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/regex/regex.3 (revision 366308) @@ -0,0 +1,536 @@ +.\" $NetBSD: regex.3,v 1.1.1.2 2008/05/18 14:31:38 aymeric Exp $ +.\" +.\" Copyright (c) 1992, 1993, 1994 Henry Spencer. +.\" Copyright (c) 1992, 1993, 1994 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Henry Spencer of the University of Toronto. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)regex.3 8.2 (Berkeley) 3/16/94 +.\" +.TH REGEX 3 "March 16, 1994" +.de ZR +.\" one other place knows this name: the SEE ALSO section +.IR re_format (7) \\$1 +.. +.SH NAME +regcomp, regexec, regerror, regfree \- regular-expression library +.SH SYNOPSIS +.ft B +.\".na +#include +.br +#include +.HP 10 +int regcomp(regex_t\ *preg, const\ char\ *pattern, int\ cflags); +.HP +int\ regexec(const\ regex_t\ *preg, const\ char\ *string, +size_t\ nmatch, regmatch_t\ pmatch[], int\ eflags); +.HP +size_t\ regerror(int\ errcode, const\ regex_t\ *preg, +char\ *errbuf, size_t\ errbuf_size); +.HP +void\ regfree(regex_t\ *preg); +.\".ad +.ft +.SH DESCRIPTION +These routines implement POSIX 1003.2 regular expressions (``RE''s); +see +.ZR . +.I Regcomp +compiles an RE written as a string into an internal form, +.I regexec +matches that internal form against a string and reports results, +.I regerror +transforms error codes from either into human-readable messages, +and +.I regfree +frees any dynamically-allocated storage used by the internal form +of an RE. +.PP +The header +.I +declares two structure types, +.I regex_t +and +.IR regmatch_t , +the former for compiled internal forms and the latter for match reporting. +It also declares the four functions, +a type +.IR regoff_t , +and a number of constants with names starting with ``REG_''. +.PP +.I Regcomp +compiles the regular expression contained in the +.I pattern +string, +subject to the flags in +.IR cflags , +and places the results in the +.I regex_t +structure pointed to by +.IR preg . +.I Cflags +is the bitwise OR of zero or more of the following flags: +.IP REG_EXTENDED \w'REG_EXTENDED'u+2n +Compile modern (``extended'') REs, +rather than the obsolete (``basic'') REs that +are the default. +.IP REG_BASIC +This is a synonym for 0, +provided as a counterpart to REG_EXTENDED to improve readability. +.IP REG_NOSPEC +Compile with recognition of all special characters turned off. +All characters are thus considered ordinary, +so the ``RE'' is a literal string. +This is an extension, +compatible with but not specified by POSIX 1003.2, +and should be used with +caution in software intended to be portable to other systems. +REG_EXTENDED and REG_NOSPEC may not be used +in the same call to +.IR regcomp . +.IP REG_ICASE +Compile for matching that ignores upper/lower case distinctions. +See +.ZR . +.IP REG_NOSUB +Compile for matching that need only report success or failure, +not what was matched. +.IP REG_NEWLINE +Compile for newline-sensitive matching. +By default, newline is a completely ordinary character with no special +meaning in either REs or strings. +With this flag, +`[^' bracket expressions and `.' never match newline, +a `^' anchor matches the null string after any newline in the string +in addition to its normal function, +and the `$' anchor matches the null string before any newline in the +string in addition to its normal function. +.IP REG_PEND +The regular expression ends, +not at the first NUL, +but just before the character pointed to by the +.I re_endp +member of the structure pointed to by +.IR preg . +The +.I re_endp +member is of type +.IR const\ char\ * . +This flag permits inclusion of NULs in the RE; +they are considered ordinary characters. +This is an extension, +compatible with but not specified by POSIX 1003.2, +and should be used with +caution in software intended to be portable to other systems. +.PP +When successful, +.I regcomp +returns 0 and fills in the structure pointed to by +.IR preg . +One member of that structure +(other than +.IR re_endp ) +is publicized: +.IR re_nsub , +of type +.IR size_t , +contains the number of parenthesized subexpressions within the RE +(except that the value of this member is undefined if the +REG_NOSUB flag was used). +If +.I regcomp +fails, it returns a non-zero error code; +see DIAGNOSTICS. +.PP +.I Regexec +matches the compiled RE pointed to by +.I preg +against the +.IR string , +subject to the flags in +.IR eflags , +and reports results using +.IR nmatch , +.IR pmatch , +and the returned value. +The RE must have been compiled by a previous invocation of +.IR regcomp . +The compiled form is not altered during execution of +.IR regexec , +so a single compiled RE can be used simultaneously by multiple threads. +.PP +By default, +the NUL-terminated string pointed to by +.I string +is considered to be the text of an entire line, minus any terminating +newline. +The +.I eflags +argument is the bitwise OR of zero or more of the following flags: +.IP REG_NOTBOL \w'REG_STARTEND'u+2n +The first character of +the string +is not the beginning of a line, so the `^' anchor should not match before it. +This does not affect the behavior of newlines under REG_NEWLINE. +.IP REG_NOTEOL +The NUL terminating +the string +does not end a line, so the `$' anchor should not match before it. +This does not affect the behavior of newlines under REG_NEWLINE. +.IP REG_STARTEND +The string is considered to start at +\fIstring\fR\ + \fIpmatch\fR[0].\fIrm_so\fR +and to have a terminating NUL located at +\fIstring\fR\ + \fIpmatch\fR[0].\fIrm_eo\fR +(there need not actually be a NUL at that location), +regardless of the value of +.IR nmatch . +See below for the definition of +.IR pmatch +and +.IR nmatch . +This is an extension, +compatible with but not specified by POSIX 1003.2, +and should be used with +caution in software intended to be portable to other systems. +Note that a non-zero \fIrm_so\fR does not imply REG_NOTBOL; +REG_STARTEND affects only the location of the string, +not how it is matched. +.PP +See +.ZR +for a discussion of what is matched in situations where an RE or a +portion thereof could match any of several substrings of +.IR string . +.PP +Normally, +.I regexec +returns 0 for success and the non-zero code REG_NOMATCH for failure. +Other non-zero error codes may be returned in exceptional situations; +see DIAGNOSTICS. +.PP +If REG_NOSUB was specified in the compilation of the RE, +or if +.I nmatch +is 0, +.I regexec +ignores the +.I pmatch +argument (but see below for the case where REG_STARTEND is specified). +Otherwise, +.I pmatch +points to an array of +.I nmatch +structures of type +.IR regmatch_t . +Such a structure has at least the members +.I rm_so +and +.IR rm_eo , +both of type +.I regoff_t +(a signed arithmetic type at least as large as an +.I off_t +and a +.IR ssize_t ), +containing respectively the offset of the first character of a substring +and the offset of the first character after the end of the substring. +Offsets are measured from the beginning of the +.I string +argument given to +.IR regexec . +An empty substring is denoted by equal offsets, +both indicating the character following the empty substring. +.PP +The 0th member of the +.I pmatch +array is filled in to indicate what substring of +.I string +was matched by the entire RE. +Remaining members report what substring was matched by parenthesized +subexpressions within the RE; +member +.I i +reports subexpression +.IR i , +with subexpressions counted (starting at 1) by the order of their opening +parentheses in the RE, left to right. +Unused entries in the array\(emcorresponding either to subexpressions that +did not participate in the match at all, or to subexpressions that do not +exist in the RE (that is, \fIi\fR\ > \fIpreg\fR\->\fIre_nsub\fR)\(emhave both +.I rm_so +and +.I rm_eo +set to \-1. +If a subexpression participated in the match several times, +the reported substring is the last one it matched. +(Note, as an example in particular, that when the RE `(b*)+' matches `bbb', +the parenthesized subexpression matches each of the three `b's and then +an infinite number of empty strings following the last `b', +so the reported substring is one of the empties.) +.PP +If REG_STARTEND is specified, +.I pmatch +must point to at least one +.I regmatch_t +(even if +.I nmatch +is 0 or REG_NOSUB was specified), +to hold the input offsets for REG_STARTEND. +Use for output is still entirely controlled by +.IR nmatch ; +if +.I nmatch +is 0 or REG_NOSUB was specified, +the value of +.IR pmatch [0] +will not be changed by a successful +.IR regexec . +.PP +.I Regerror +maps a non-zero +.I errcode +from either +.I regcomp +or +.I regexec +to a human-readable, printable message. +If +.I preg +is non-NULL, +the error code should have arisen from use of +the +.I regex_t +pointed to by +.IR preg , +and if the error code came from +.IR regcomp , +it should have been the result from the most recent +.I regcomp +using that +.IR regex_t . +.RI ( Regerror +may be able to supply a more detailed message using information +from the +.IR regex_t .) +.I Regerror +places the NUL-terminated message into the buffer pointed to by +.IR errbuf , +limiting the length (including the NUL) to at most +.I errbuf_size +bytes. +If the whole message won't fit, +as much of it as will fit before the terminating NUL is supplied. +In any case, +the returned value is the size of buffer needed to hold the whole +message (including terminating NUL). +If +.I errbuf_size +is 0, +.I errbuf +is ignored but the return value is still correct. +.PP +If the +.I errcode +given to +.I regerror +is first ORed with REG_ITOA, +the ``message'' that results is the printable name of the error code, +e.g. ``REG_NOMATCH'', +rather than an explanation thereof. +If +.I errcode +is REG_ATOI, +then +.I preg +shall be non-NULL and the +.I re_endp +member of the structure it points to +must point to the printable name of an error code; +in this case, the result in +.I errbuf +is the decimal digits of +the numeric value of the error code +(0 if the name is not recognized). +REG_ITOA and REG_ATOI are intended primarily as debugging facilities; +they are extensions, +compatible with but not specified by POSIX 1003.2, +and should be used with +caution in software intended to be portable to other systems. +Be warned also that they are considered experimental and changes are possible. +.PP +.I Regfree +frees any dynamically-allocated storage associated with the compiled RE +pointed to by +.IR preg . +The remaining +.I regex_t +is no longer a valid compiled RE +and the effect of supplying it to +.I regexec +or +.I regerror +is undefined. +.PP +None of these functions references global variables except for tables +of constants; +all are safe for use from multiple threads if the arguments are safe. +.SH IMPLEMENTATION CHOICES +There are a number of decisions that 1003.2 leaves up to the implementor, +either by explicitly saying ``undefined'' or by virtue of them being +forbidden by the RE grammar. +This implementation treats them as follows. +.PP +See +.ZR +for a discussion of the definition of case-independent matching. +.PP +There is no particular limit on the length of REs, +except insofar as memory is limited. +Memory usage is approximately linear in RE size, and largely insensitive +to RE complexity, except for bounded repetitions. +See BUGS for one short RE using them +that will run almost any system out of memory. +.PP +A backslashed character other than one specifically given a magic meaning +by 1003.2 (such magic meanings occur only in obsolete [``basic''] REs) +is taken as an ordinary character. +.PP +Any unmatched [ is a REG_EBRACK error. +.PP +Equivalence classes cannot begin or end bracket-expression ranges. +The endpoint of one range cannot begin another. +.PP +RE_DUP_MAX, the limit on repetition counts in bounded repetitions, is 255. +.PP +A repetition operator (?, *, +, or bounds) cannot follow another +repetition operator. +A repetition operator cannot begin an expression or subexpression +or follow `^' or `|'. +.PP +`|' cannot appear first or last in a (sub)expression or after another `|', +i.e. an operand of `|' cannot be an empty subexpression. +An empty parenthesized subexpression, `()', is legal and matches an +empty (sub)string. +An empty string is not a legal RE. +.PP +A `{' followed by a digit is considered the beginning of bounds for a +bounded repetition, which must then follow the syntax for bounds. +A `{' \fInot\fR followed by a digit is considered an ordinary character. +.PP +`^' and `$' beginning and ending subexpressions in obsolete (``basic'') +REs are anchors, not ordinary characters. +.SH SEE ALSO +grep(1), re_format(7) +.PP +POSIX 1003.2, sections 2.8 (Regular Expression Notation) +and +B.5 (C Binding for Regular Expression Matching). +.SH DIAGNOSTICS +Non-zero error codes from +.I regcomp +and +.I regexec +include the following: +.PP +.nf +.ta \w'REG_ECOLLATE'u+3n +REG_NOMATCH regexec() failed to match +REG_BADPAT invalid regular expression +REG_ECOLLATE invalid collating element +REG_ECTYPE invalid character class +REG_EESCAPE \e applied to unescapable character +REG_ESUBREG invalid backreference number +REG_EBRACK brackets [ ] not balanced +REG_EPAREN parentheses ( ) not balanced +REG_EBRACE braces { } not balanced +REG_BADBR invalid repetition count(s) in { } +REG_ERANGE invalid character range in [ ] +REG_ESPACE ran out of memory +REG_BADRPT ?, *, or + operand invalid +REG_EMPTY empty (sub)expression +REG_ASSERT ``can't happen''\(emyou found a bug +REG_INVARG invalid argument, e.g. negative-length string +.fi +.SH HISTORY +Originally written by Henry Spencer at University of Toronto. +Altered for inclusion in the 4.4BSD distribution. +.SH BUGS +This is an alpha release with known defects. +Please report problems. +.PP +There is one known functionality bug. +The implementation of internationalization is incomplete: +the locale is always assumed to be the default one of 1003.2, +and only the collating elements etc. of that locale are available. +.PP +The back-reference code is subtle and doubts linger about its correctness +in complex cases. +.PP +.I Regexec +performance is poor. +This will improve with later releases. +.I Nmatch +exceeding 0 is expensive; +.I nmatch +exceeding 1 is worse. +.I Regexec +is largely insensitive to RE complexity \fIexcept\fR that back +references are massively expensive. +RE length does matter; in particular, there is a strong speed bonus +for keeping RE length under about 30 characters, +with most special characters counting roughly double. +.PP +.I Regcomp +implements bounded repetitions by macro expansion, +which is costly in time and space if counts are large +or bounded repetitions are nested. +An RE like, say, +`((((a{1,100}){1,100}){1,100}){1,100}){1,100}' +will (eventually) run almost any existing machine out of swap space. +.PP +There are suspected problems with response to obscure error conditions. +Notably, +certain kinds of internal overflow, +produced only by truly enormous REs or by multiply nested bounded repetitions, +are probably not handled well. +.PP +Due to a mistake in 1003.2, things like `a)b' are legal REs because `)' is +a special character only in the presence of a previous unmatched `('. +This can't be fixed until the spec is fixed. +.PP +The standard's definition of back references is vague. +For example, does +`a\e(\e(b\e)*\e2\e)*d' match `abbbd'? +Until the standard is clarified, +behavior in such cases should not be relied on. +.PP +The implementation of word-boundary matching is a bit of a kludge, +and bugs may lurk in combinations of word-boundary matching and anchoring. Property changes on: vendor/nvi/2.2.0-05ed8b9/regex/regex.3 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/regex/regex.h =================================================================== --- vendor/nvi/2.2.0-05ed8b9/regex/regex.h (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/regex/regex.h (revision 366308) @@ -0,0 +1,105 @@ +/* $NetBSD: regex.h,v 1.1.1.2 2008/05/18 14:31:38 aymeric Exp $ */ + +/*- + * Copyright (c) 1992 Henry Spencer. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Henry Spencer of the University of Toronto. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)regex.h 8.1 (Berkeley) 6/2/93 + */ + +#ifndef _REGEX_H_ +#define _REGEX_H_ + +#ifdef __REGEX_PRIVATE +#include "config.h" +#include "../common/multibyte.h" +#endif + +/* types */ +typedef off_t regoff_t; + +typedef struct { + int re_magic; + size_t re_nsub; /* number of parenthesized subexpressions */ + const RCHAR_T *re_endp; /* end pointer for REG_PEND */ + struct re_guts *re_g; /* none of your business :-) */ +} regex_t; + +typedef struct { + regoff_t rm_so; /* start of match */ + regoff_t rm_eo; /* end of match */ +} regmatch_t; + +/* regcomp() flags */ +#define REG_BASIC 0000 +#define REG_EXTENDED 0001 +#define REG_ICASE 0002 +#define REG_NOSUB 0004 +#define REG_NEWLINE 0010 +#define REG_NOSPEC 0020 +#define REG_PEND 0040 +#define REG_DUMP 0200 + +/* regerror() flags */ +#define REG_NOMATCH 1 +#define REG_BADPAT 2 +#define REG_ECOLLATE 3 +#define REG_ECTYPE 4 +#define REG_EESCAPE 5 +#define REG_ESUBREG 6 +#define REG_EBRACK 7 +#define REG_EPAREN 8 +#define REG_EBRACE 9 +#define REG_BADBR 10 +#define REG_ERANGE 11 +#define REG_ESPACE 12 +#define REG_BADRPT 13 +#define REG_EMPTY 14 +#define REG_ASSERT 15 +#define REG_INVARG 16 +#define REG_ATOI 255 /* convert name to number (!) */ +#define REG_ITOA 0400 /* convert number to name (!) */ + +/* regexec() flags */ +#define REG_NOTBOL 00001 +#define REG_NOTEOL 00002 +#define REG_STARTEND 00004 +#define REG_TRACE 00400 /* tracing of execution */ +#define REG_LARGE 01000 /* force large representation */ +#define REG_BACKR 02000 /* force use of backref code */ + +int regcomp(regex_t *, const RCHAR_T *, int); +size_t regerror(int, const regex_t *, char *, size_t); +int regexec(const regex_t *, + const RCHAR_T *, size_t, regmatch_t [], int); +void regfree(regex_t *); + +#endif /* !_REGEX_H_ */ Property changes on: vendor/nvi/2.2.0-05ed8b9/regex/regex.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/regex/regex2.h =================================================================== --- vendor/nvi/2.2.0-05ed8b9/regex/regex2.h (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/regex/regex2.h (revision 366308) @@ -0,0 +1,170 @@ +/* $NetBSD: regex2.h,v 1.5 2011/11/23 15:43:39 tnozaki Exp $ */ + +/*- + * Copyright (c) 1992, 1993, 1994 Henry Spencer. + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Henry Spencer of the University of Toronto. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)regex2.h 8.3 (Berkeley) 3/16/94 + */ + +/* + * First, the stuff that ends up in the outside-world include file + = typedef off_t regoff_t; + = typedef struct { + = int re_magic; + = size_t re_nsub; // number of parenthesized subexpressions + = const char *re_endp; // end pointer for REG_PEND + = struct re_guts *re_g; // none of your business :-) + = } regex_t; + = typedef struct { + = regoff_t rm_so; // start of match + = regoff_t rm_eo; // end of match + = } regmatch_t; + */ +/* + * internals of regex_t + */ +#define MAGIC1 ((('r'^0200)<<8) | 'e') + +/* + * The internal representation is a *strip*, a sequence of + * operators ending with an endmarker. (Some terminology etc. is a + * historical relic of earlier versions which used multiple strips.) + * Certain oddities in the representation are there to permit running + * the machinery backwards; in particular, any deviation from sequential + * flow must be marked at both its source and its destination. Some + * fine points: + * + * - OPLUS_ and O_PLUS are *inside* the loop they create. + * - OQUEST_ and O_QUEST are *outside* the bypass they create. + * - OCH_ and O_CH are *outside* the multi-way branch they create, while + * OOR1 and OOR2 are respectively the end and the beginning of one of + * the branches. Note that there is an implicit OOR2 following OCH_ + * and an implicit OOR1 preceding O_CH. + * + * In state representations, an operator's bit is on to signify a state + * immediately *preceding* "execution" of that operator. + */ +typedef char sop; /* strip operator */ +typedef size_t sopno; +/* operators meaning operand */ +/* (back, fwd are offsets) */ +#define OEND (1) /* endmarker - */ +#define OCHAR (2) /* character unsigned char */ +#define OBOL (3) /* left anchor - */ +#define OEOL (4) /* right anchor - */ +#define OANY (5) /* . - */ +#define OANYOF (6) /* [...] set number */ +#define OBACK_ (7) /* begin \d paren number */ +#define O_BACK (8) /* end \d paren number */ +#define OPLUS_ (9) /* + prefix fwd to suffix */ +#define O_PLUS (10) /* + suffix back to prefix */ +#define OQUEST_ (11) /* ? prefix fwd to suffix */ +#define O_QUEST (12) /* ? suffix back to prefix */ +#define OLPAREN (13) /* ( fwd to ) */ +#define ORPAREN (14) /* ) back to ( */ +#define OCH_ (15) /* begin choice fwd to OOR2 */ +#define OOR1 (16) /* | pt. 1 back to OOR1 or OCH_ */ +#define OOR2 (17) /* | pt. 2 fwd to OOR2 or O_CH */ +#define O_CH (18) /* end choice back to OOR1 */ +#define OBOW (19) /* begin word - */ +#define OEOW (20) /* end word - */ + +/* + * Structure for [] character-set representation. Character sets are + * done as bit vectors, grouped 8 to a byte vector for compactness. + * The individual set therefore has both a pointer to the byte vector + * and a mask to pick out the relevant bit of each byte. A hash code + * simplifies testing whether two sets could be identical. + * + * This will get trickier for multicharacter collating elements. As + * preliminary hooks for dealing with such things, we also carry along + * a string of multi-character elements, and decide the size of the + * vectors at run time. + */ +typedef struct { + uch *ptr; /* -> uch [csetsize] */ + uch mask; /* bit within array */ + uch hash; /* hash code */ + size_t smultis; + char *multis; /* -> char[smulti] ab\0cd\0ef\0\0 */ +} cset; +/* note that CHadd and CHsub are unsafe, and CHIN doesn't yield 0/1 */ +#define CHadd(cs, c) ((cs)->ptr[(uch)(c)] |= (cs)->mask, (cs)->hash += (c)) +#define CHsub(cs, c) ((cs)->ptr[(uch)(c)] &= ~(cs)->mask, (cs)->hash -= (c)) +#define CHIN(cs, c) ((cs)->ptr[(uch)(c)] & (cs)->mask) +#define MCadd(p, cs, cp) mcadd(p, cs, cp) /* regcomp() internal fns */ +#define MCsub(p, cs, cp) mcsub(p, cs, cp) +#define MCin(p, cs, cp) mcin(p, cs, cp) + +/* stuff for character categories */ +typedef RCHAR_T cat_t; + +/* + * main compiled-expression structure + */ +struct re_guts { + int magic; +# define MAGIC2 ((('R'^0200)<<8)|'E') + sop *strip; /* malloced area for strip */ + RCHAR_T *stripdata; /* malloced area for stripdata */ + size_t csetsize; /* number of bits in a cset vector */ + size_t ncsets; /* number of csets in use */ + cset *sets; /* -> cset [ncsets] */ + uch *setbits; /* -> uch[csetsize][ncsets/CHAR_BIT] */ + int cflags; /* copy of regcomp() cflags argument */ + sopno nstates; /* = number of sops */ + sopno firststate; /* the initial OEND (normally 0) */ + sopno laststate; /* the final OEND */ + int iflags; /* internal flags */ +# define USEBOL 01 /* used ^ */ +# define USEEOL 02 /* used $ */ +# define BAD 04 /* something wrong */ + size_t nbol; /* number of ^ used */ + size_t neol; /* number of $ used */ +#if 0 + size_t ncategories; /* how many character categories */ + cat_t *categories; /* ->catspace[-CHAR_MIN] */ +#endif + RCHAR_T *must; /* match must contain this string */ + size_t mlen; /* length of must */ + size_t nsub; /* copy of re_nsub */ + int backrefs; /* does it use back references? */ + sopno nplus; /* how deep does it nest +s? */ + /* catspace must be last */ +#if 0 + cat_t catspace[1]; /* actually [NC] */ +#endif +}; + +/* misc utilities */ +#define OUT REOF /* a non-character value */ +#define ISWORD(c) ((c) == '_' || (ISGRAPH((UCHAR_T)c) && !ISPUNCT((UCHAR_T)c))) Property changes on: vendor/nvi/2.2.0-05ed8b9/regex/regex2.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/regex/regfree.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/regex/regfree.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/regex/regfree.c (revision 366308) @@ -0,0 +1,78 @@ +/* $NetBSD: regfree.c,v 1.2 2009/01/02 00:32:11 tnozaki Exp $ */ + +/*- + * Copyright (c) 1992, 1993, 1994 Henry Spencer. + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Henry Spencer of the University of Toronto. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)regfree.c 8.2 (Berkeley) 3/16/94 + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)regfree.c 8.2 (Berkeley) 3/16/94"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include +#include + +#include "utils.h" +#include "regex2.h" + +/* + - regfree - free everything + */ +void +regfree(regex_t *preg) +{ + struct re_guts *g; + + if (preg->re_magic != MAGIC1) /* oops */ + return; /* nice to complain, but hard */ + + g = preg->re_g; + if (g == NULL || g->magic != MAGIC2) /* oops again */ + return; + preg->re_magic = 0; /* mark it invalid */ + g->magic = 0; /* mark it invalid */ + + if (g->strip != NULL) + free((char *)g->strip); + if (g->stripdata != NULL) + free((char *)g->stripdata); + if (g->sets != NULL) + free((char *)g->sets); + if (g->setbits != NULL) + free((char *)g->setbits); + if (g->must != NULL) + free(g->must); + free((char *)g); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/regex/regfree.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/regex/utils.h =================================================================== --- vendor/nvi/2.2.0-05ed8b9/regex/utils.h (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/regex/utils.h (revision 366308) @@ -0,0 +1,55 @@ +/* $NetBSD: utils.h,v 1.1.1.2 2008/05/18 14:31:39 aymeric Exp $ */ + +/*- + * Copyright (c) 1992, 1993, 1994 Henry Spencer. + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Henry Spencer of the University of Toronto. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)utils.h 8.2 (Berkeley) 3/16/94 + */ + +/* utility definitions */ +#define DUPMAX _POSIX2_RE_DUP_MAX /* xxx is this right? */ +#define INFINITY (DUPMAX + 1) +#define NC (CHAR_MAX - CHAR_MIN + 1) +typedef unsigned char uch; + +/* switch off assertions (if not already off) if no REDEBUG */ +#ifndef REDEBUG +#ifndef NDEBUG +#define NDEBUG /* no assertions please */ +#endif +#endif +#include + +/* for old systems with bcopy() but no memmove() */ +#ifdef USEBCOPY +#define memmove(d, s, c) bcopy(s, d, c) +#endif Property changes on: vendor/nvi/2.2.0-05ed8b9/regex/utils.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/regex/WHATSNEW =================================================================== --- vendor/nvi/2.2.0-05ed8b9/regex/WHATSNEW (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/regex/WHATSNEW (revision 366308) @@ -0,0 +1,94 @@ +# @(#)WHATSNEW 8.3 (Berkeley) 3/18/94 + +New in alpha3.4: The complex bug alluded to below has been fixed (in a +slightly kludgey temporary way that may hurt efficiency a bit; this is +another "get it out the door for 4.4" release). The tests at the end of +the tests file have accordingly been uncommented. The primary sign of +the bug was that something like a?b matching ab matched b rather than ab. +(The bug was essentially specific to this exact situation, else it would +have shown up earlier.) + +New in alpha3.3: The definition of word boundaries has been altered +slightly, to more closely match the usual programming notion that "_" +is an alphabetic. Stuff used for pre-ANSI systems is now in a subdir, +and the makefile no longer alludes to it in mysterious ways. The +makefile has generally been cleaned up some. Fixes have been made +(again!) so that the regression test will run without -DREDEBUG, at +the cost of weaker checking. A workaround for a bug in some folks' + has been added. And some more things have been added to +tests, including a couple right at the end which are commented out +because the code currently flunks them (complex bug; fix coming). +Plus the usual minor cleanup. + +New in alpha3.2: Assorted bits of cleanup and portability improvement +(the development base is now a BSDI system using GCC instead of an ancient +Sun system, and the newer compiler exposed some glitches). Fix for a +serious bug that affected REs using many [] (including REG_ICASE REs +because of the way they are implemented), *sometimes*, depending on +memory-allocation patterns. The header-file prototypes no longer name +the parameters, avoiding possible name conflicts. The possibility that +some clot has defined CHAR_MIN as (say) `-128' instead of `(-128)' is +now handled gracefully. "uchar" is no longer used as an internal type +name (too many people have the same idea). Still the same old lousy +performance, alas. + +New in alpha3.1: Basically nothing, this release is just a bookkeeping +convenience. Stay tuned. + +New in alpha3.0: Performance is no better, alas, but some fixes have been +made and some functionality has been added. (This is basically the "get +it out the door in time for 4.4" release.) One bug fix: regfree() didn't +free the main internal structure (how embarrassing). It is now possible +to put NULs in either the RE or the target string, using (resp.) a new +REG_PEND flag and the old REG_STARTEND flag. The REG_NOSPEC flag to +regcomp() makes all characters ordinary, so you can match a literal +string easily (this will become more useful when performance improves!). +There are now primitives to match beginnings and ends of words, although +the syntax is disgusting and so is the implementation. The REG_ATOI +debugging interface has changed a bit. And there has been considerable +internal cleanup of various kinds. + +New in alpha2.3: Split change list out of README, and moved flags notes +into Makefile. Macro-ized the name of regex(7) in regex(3), since it has +to change for 4.4BSD. Cleanup work in engine.c, and some new regression +tests to catch tricky cases thereof. + +New in alpha2.2: Out-of-date manpages updated. Regerror() acquires two +small extensions -- REG_ITOA and REG_ATOI -- which avoid debugging kludges +in my own test program and might be useful to others for similar purposes. +The regression test will now compile (and run) without REDEBUG. The +BRE \$ bug is fixed. Most uses of "uchar" are gone; it's all chars now. +Char/uchar parameters are now written int/unsigned, to avoid possible +portability problems with unpromoted parameters. Some unsigned casts have +been introduced to minimize portability problems with shifting into sign +bits. + +New in alpha2.1: Lots of little stuff, cleanup and fixes. The one big +thing is that regex.h is now generated, using mkh, rather than being +supplied in the distribution; due to circularities in dependencies, +you have to build regex.h explicitly by "make h". The two known bugs +have been fixed (and the regression test now checks for them), as has a +problem with assertions not being suppressed in the absence of REDEBUG. +No performance work yet. + +New in alpha2: Backslash-anything is an ordinary character, not an +error (except, of course, for the handful of backslashed metacharacters +in BREs), which should reduce script breakage. The regression test +checks *where* null strings are supposed to match, and has generally +been tightened up somewhat. Small bug fixes in parameter passing (not +harmful, but technically errors) and some other areas. Debugging +invoked by defining REDEBUG rather than not defining NDEBUG. + +New in alpha+3: full prototyping for internal routines, using a little +helper program, mkh, which extracts prototypes given in stylized comments. +More minor cleanup. Buglet fix: it's CHAR_BIT, not CHAR_BITS. Simple +pre-screening of input when a literal string is known to be part of the +RE; this does wonders for performance. + +New in alpha+2: minor bits of cleanup. Notably, the number "32" for the +word width isn't hardwired into regexec.c any more, the public header +file prototypes the functions if __STDC__ is defined, and some small typos +in the manpages have been fixed. + +New in alpha+1: improvements to the manual pages, and an important +extension, the REG_STARTEND option to regexec(). Index: vendor/nvi/2.2.0-05ed8b9/vi/v_itxt.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/vi/v_itxt.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/vi/v_itxt.c (revision 366308) @@ -0,0 +1,510 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "../common/common.h" +#include "vi.h" + +/* + * !!! + * Repeated input in the historic vi is mostly wrong and this isn't very + * backward compatible. For example, if the user entered "3Aab\ncd" in + * the historic vi, the "ab" was repeated 3 times, and the "\ncd" was then + * appended to the result. There was also a hack which I don't remember + * right now, where "3o" would open 3 lines and then let the user fill them + * in, to make screen movements on 300 baud modems more tolerable. I don't + * think it's going to be missed. + * + * !!! + * There's a problem with the way that we do logging for change commands with + * implied motions (e.g. A, I, O, cc, etc.). Since the main vi loop logs the + * starting cursor position before the change command "moves" the cursor, the + * cursor position to which we return on undo will be where the user entered + * the change command, not the start of the change. Several of the following + * routines re-log the cursor to make this work correctly. Historic vi tried + * to do the same thing, and mostly got it right. (The only spectacular way + * it fails is if the user entered 'o' from anywhere but the last character of + * the line, the undo returned the cursor to the start of the line. If the + * user was on the last character of the line, the cursor returned to that + * position.) We also check for mapped keys waiting, i.e. if we're in the + * middle of a map, don't bother logging the cursor. + */ +#define LOG_CORRECT do { \ + if (!MAPPED_KEYS_WAITING(sp)) \ + (void)log_cursor(sp); \ +} while (0) + +static u_int32_t set_txt_std(SCR *, VICMD *, u_int32_t); + +/* + * v_iA -- [count]A + * Append text to the end of the line. + * + * PUBLIC: int v_iA(SCR *, VICMD *); + */ +int +v_iA(SCR *sp, VICMD *vp) +{ + size_t len; + + if (!db_get(sp, vp->m_start.lno, 0, NULL, &len)) + sp->cno = len == 0 ? 0 : len - 1; + + LOG_CORRECT; + + return (v_ia(sp, vp)); +} + +/* + * v_ia -- [count]a + * [count]A + * Append text to the cursor position. + * + * PUBLIC: int v_ia(SCR *, VICMD *); + */ +int +v_ia(SCR *sp, VICMD *vp) +{ + size_t len; + u_int32_t flags; + int isempty; + CHAR_T *p; + + flags = set_txt_std(sp, vp, 0); + sp->showmode = SM_APPEND; + sp->lno = vp->m_start.lno; + + /* Move the cursor one column to the right and repaint the screen. */ + if (db_eget(sp, sp->lno, &p, &len, &isempty)) { + if (!isempty) + return (1); + len = 0; + LF_SET(TXT_APPENDEOL); + } else if (len) { + if (len == sp->cno + 1) { + sp->cno = len; + LF_SET(TXT_APPENDEOL); + } else + ++sp->cno; + } else + LF_SET(TXT_APPENDEOL); + + return (v_txt(sp, vp, NULL, p, len, + 0, OOBLNO, F_ISSET(vp, VC_C1SET) ? vp->count : 1, flags)); +} + +/* + * v_iI -- [count]I + * Insert text at the first nonblank. + * + * PUBLIC: int v_iI(SCR *, VICMD *); + */ +int +v_iI(SCR *sp, VICMD *vp) +{ + sp->cno = 0; + if (nonblank(sp, vp->m_start.lno, &sp->cno)) + return (1); + + LOG_CORRECT; + + return (v_ii(sp, vp)); +} + +/* + * v_ii -- [count]i + * [count]I + * Insert text at the cursor position. + * + * PUBLIC: int v_ii(SCR *, VICMD *); + */ +int +v_ii(SCR *sp, VICMD *vp) +{ + size_t len; + u_int32_t flags; + int isempty; + CHAR_T *p; + + flags = set_txt_std(sp, vp, 0); + sp->showmode = SM_INSERT; + sp->lno = vp->m_start.lno; + + if (db_eget(sp, sp->lno, &p, &len, &isempty)) { + if (!isempty) + return (1); + len = 0; + } + + if (len == 0) + LF_SET(TXT_APPENDEOL); + return (v_txt(sp, vp, NULL, p, len, + 0, OOBLNO, F_ISSET(vp, VC_C1SET) ? vp->count : 1, flags)); +} + +enum which { o_cmd, O_cmd }; +static int io(SCR *, VICMD *, enum which); + +/* + * v_iO -- [count]O + * Insert text above this line. + * + * PUBLIC: int v_iO(SCR *, VICMD *); + */ +int +v_iO(SCR *sp, VICMD *vp) +{ + return (io(sp, vp, O_cmd)); +} + +/* + * v_io -- [count]o + * Insert text after this line. + * + * PUBLIC: int v_io(SCR *, VICMD *); + */ +int +v_io(SCR *sp, VICMD *vp) +{ + return (io(sp, vp, o_cmd)); +} + +static int +io(SCR *sp, VICMD *vp, enum which cmd) +{ + recno_t ai_line, lno; + size_t len; + u_int32_t flags; + CHAR_T *p; + + flags = set_txt_std(sp, vp, TXT_ADDNEWLINE | TXT_APPENDEOL); + sp->showmode = SM_INSERT; + + if (sp->lno == 1) { + if (db_last(sp, &lno)) + return (1); + if (lno != 0) + goto insert; + p = NULL; + len = 0; + ai_line = OOBLNO; + } else { +insert: p = L(""); + sp->cno = 0; + LOG_CORRECT; + + if (cmd == O_cmd) { + if (db_insert(sp, sp->lno, p, 0)) + return (1); + if (db_get(sp, sp->lno, DBG_FATAL, &p, &len)) + return (1); + ai_line = sp->lno + 1; + } else { + if (db_append(sp, 1, sp->lno, p, 0)) + return (1); + if (db_get(sp, ++sp->lno, DBG_FATAL, &p, &len)) + return (1); + ai_line = sp->lno - 1; + } + } + return (v_txt(sp, vp, NULL, p, len, + 0, ai_line, F_ISSET(vp, VC_C1SET) ? vp->count : 1, flags)); +} + +/* + * v_change -- [buffer][count]c[count]motion + * [buffer][count]C + * [buffer][count]S + * Change command. + * + * PUBLIC: int v_change(SCR *, VICMD *); + */ +int +v_change(SCR *sp, VICMD *vp) +{ + size_t blen, len; + u_int32_t flags; + int isempty, lmode, rval; + CHAR_T *bp; + CHAR_T *p; + + /* + * 'c' can be combined with motion commands that set the resulting + * cursor position, i.e. "cG". Clear the VM_RCM flags and make the + * resulting cursor position stick, inserting text has its own rules + * for cursor positioning. + */ + F_CLR(vp, VM_RCM_MASK); + F_SET(vp, VM_RCM_SET); + + /* + * Find out if the file is empty, it's easier to handle it as a + * special case. + */ + if (vp->m_start.lno == vp->m_stop.lno && + db_eget(sp, vp->m_start.lno, &p, &len, &isempty)) { + if (!isempty) + return (1); + return (v_ia(sp, vp)); + } + + flags = set_txt_std(sp, vp, 0); + sp->showmode = SM_CHANGE; + + /* + * Move the cursor to the start of the change. Note, if autoindent + * is turned on, the cc command in line mode changes from the first + * *non-blank* character of the line, not the first character. And, + * to make it just a bit more exciting, the initial space is handled + * as auto-indent characters. + */ + lmode = F_ISSET(vp, VM_LMODE) ? CUT_LINEMODE : 0; + if (lmode) { + vp->m_start.cno = 0; + if (O_ISSET(sp, O_AUTOINDENT)) { + if (nonblank(sp, vp->m_start.lno, &vp->m_start.cno)) + return (1); + LF_SET(TXT_AICHARS); + } + } + sp->lno = vp->m_start.lno; + sp->cno = vp->m_start.cno; + + LOG_CORRECT; + + /* + * If not in line mode and changing within a single line, copy the + * text and overwrite it. + */ + if (!lmode && vp->m_start.lno == vp->m_stop.lno) { + /* + * !!! + * Historic practice, c did not cut into the numeric buffers, + * only the unnamed one. + */ + if (cut(sp, + F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL, + &vp->m_start, &vp->m_stop, lmode)) + return (1); + if (len == 0) + LF_SET(TXT_APPENDEOL); + LF_SET(TXT_EMARK | TXT_OVERWRITE); + return (v_txt(sp, vp, &vp->m_stop, p, len, + 0, OOBLNO, F_ISSET(vp, VC_C1SET) ? vp->count : 1, flags)); + } + + /* + * It's trickier if in line mode or changing over multiple lines. If + * we're in line mode delete all of the lines and insert a replacement + * line which the user edits. If there was leading whitespace in the + * first line being changed, we copy it and use it as the replacement. + * If we're not in line mode, we delete the text and start inserting. + * + * !!! + * Copy the text. Historic practice, c did not cut into the numeric + * buffers, only the unnamed one. + */ + if (cut(sp, + F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL, + &vp->m_start, &vp->m_stop, lmode)) + return (1); + + /* If replacing entire lines and there's leading text. */ + if (lmode && vp->m_start.cno) { + /* + * Get a copy of the first line changed, and copy out the + * leading text. + */ + if (db_get(sp, vp->m_start.lno, DBG_FATAL, &p, &len)) + return (1); + GET_SPACE_RETW(sp, bp, blen, vp->m_start.cno); + MEMMOVE(bp, p, vp->m_start.cno); + } else + bp = NULL; + + /* Delete the text. */ + if (del(sp, &vp->m_start, &vp->m_stop, lmode)) + return (1); + + /* If replacing entire lines, insert a replacement line. */ + if (lmode) { + if (db_insert(sp, vp->m_start.lno, bp, vp->m_start.cno)) + return (1); + sp->lno = vp->m_start.lno; + len = sp->cno = vp->m_start.cno; + } + + /* Get the line we're editing. */ + if (db_eget(sp, vp->m_start.lno, &p, &len, &isempty)) { + if (!isempty) + return (1); + len = 0; + } + + /* Check to see if we're appending to the line. */ + if (vp->m_start.cno >= len) + LF_SET(TXT_APPENDEOL); + + rval = v_txt(sp, vp, NULL, p, len, + 0, OOBLNO, F_ISSET(vp, VC_C1SET) ? vp->count : 1, flags); + + if (bp != NULL) + FREE_SPACEW(sp, bp, blen); + return (rval); +} + +/* + * v_Replace -- [count]R + * Overwrite multiple characters. + * + * PUBLIC: int v_Replace(SCR *, VICMD *); + */ +int +v_Replace(SCR *sp, VICMD *vp) +{ + size_t len; + u_int32_t flags; + int isempty; + CHAR_T *p; + + flags = set_txt_std(sp, vp, 0); + sp->showmode = SM_REPLACE; + + if (db_eget(sp, vp->m_start.lno, &p, &len, &isempty)) { + if (!isempty) + return (1); + len = 0; + LF_SET(TXT_APPENDEOL); + } else { + if (len == 0) + LF_SET(TXT_APPENDEOL); + LF_SET(TXT_OVERWRITE | TXT_REPLACE); + } + vp->m_stop.lno = vp->m_start.lno; + vp->m_stop.cno = len ? len - 1 : 0; + + return (v_txt(sp, vp, &vp->m_stop, p, len, + 0, OOBLNO, F_ISSET(vp, VC_C1SET) ? vp->count : 1, flags)); +} + +/* + * v_subst -- [buffer][count]s + * Substitute characters. + * + * PUBLIC: int v_subst(SCR *, VICMD *); + */ +int +v_subst(SCR *sp, VICMD *vp) +{ + size_t len; + u_int32_t flags; + int isempty; + CHAR_T *p; + + flags = set_txt_std(sp, vp, 0); + sp->showmode = SM_CHANGE; + + if (db_eget(sp, vp->m_start.lno, &p, &len, &isempty)) { + if (!isempty) + return (1); + len = 0; + LF_SET(TXT_APPENDEOL); + } else { + if (len == 0) + LF_SET(TXT_APPENDEOL); + LF_SET(TXT_EMARK | TXT_OVERWRITE); + } + + vp->m_stop.lno = vp->m_start.lno; + vp->m_stop.cno = + vp->m_start.cno + (F_ISSET(vp, VC_C1SET) ? vp->count - 1 : 0); + if (vp->m_stop.cno > len - 1) + vp->m_stop.cno = len - 1; + + if (p != NULL && cut(sp, + F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL, + &vp->m_start, &vp->m_stop, 0)) + return (1); + + return (v_txt(sp, vp, &vp->m_stop, p, len, 0, OOBLNO, 1, flags)); +} + +/* + * set_txt_std -- + * Initialize text processing flags. + */ +static u_int32_t +set_txt_std(SCR *sp, VICMD *vp, u_int32_t flags) +{ + LF_SET(TXT_CNTRLT | + TXT_ESCAPE | TXT_MAPINPUT | TXT_RECORD | TXT_RESOLVE); + + if (F_ISSET(vp, VC_ISDOT)) + LF_SET(TXT_REPLAY); + + if (O_ISSET(sp, O_ALTWERASE)) + LF_SET(TXT_ALTWERASE); + if (O_ISSET(sp, O_AUTOINDENT)) + LF_SET(TXT_AUTOINDENT); + if (O_ISSET(sp, O_BEAUTIFY)) + LF_SET(TXT_BEAUTIFY); + if (O_ISSET(sp, O_SHOWMATCH)) + LF_SET(TXT_SHOWMATCH); + if (F_ISSET(sp, SC_SCRIPT)) + LF_SET(TXT_CR); + if (O_ISSET(sp, O_TTYWERASE)) + LF_SET(TXT_TTYWERASE); + + /* + * !!! + * Mapped keys were sometimes unaffected by the wrapmargin option + * in the historic 4BSD vi. Consider the following commands, where + * each is executed on an empty line, in an 80 column screen, with + * the wrapmargin value set to 60. + * + * aABC DEF .... + * :map K aABC DEF ^VKKKKK + * :map K 5aABC DEF ^VK + * + * The first and second commands are affected by wrapmargin. The + * third is not. (If the inserted text is itself longer than the + * wrapmargin value, i.e. if the "ABC DEF " string is replaced by + * something that's longer than 60 columns from the beginning of + * the line, the first two commands behave as before, but the third + * command gets fairly strange.) The problem is that people wrote + * macros that depended on the third command NOT being affected by + * wrapmargin, as in this gem which centers lines: + * + * map #c $mq81a ^V^[81^V^V|D`qld0:s/ / /g^V^M$p + * + * For compatibility reasons, we try and make it all work here. I + * offer no hope that this is right, but it's probably pretty close. + * + * XXX + * Once I work my courage up, this is all gonna go away. It's too + * evil to survive. + */ + if ((O_ISSET(sp, O_WRAPLEN) || O_ISSET(sp, O_WRAPMARGIN)) && + (!MAPPED_KEYS_WAITING(sp) || !F_ISSET(vp, VC_C1SET))) + LF_SET(TXT_WRAPMARGIN); + return (flags); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/vi/v_itxt.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/vi/v_paragraph.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/vi/v_paragraph.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/vi/v_paragraph.c (revision 366308) @@ -0,0 +1,337 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "../common/common.h" +#include "vi.h" + +#define INTEXT_CHECK do { \ + if (len == 0 || v_isempty(p, len)) { \ + if (!--cnt) \ + goto found; \ + pstate = P_INBLANK; \ + } \ + /* \ + * !!! \ + * Historic documentation (USD:15-11, 4.2) said that formfeed \ + * characters (^L) in the first column delimited paragraphs. \ + * The historic vi code mentions formfeed characters, but never \ + * implements them. It seems reasonable, do it. \ + */ \ + if (p[0] == '\014') { \ + if (!--cnt) \ + goto found; \ + continue; \ + } \ + if (p[0] != '.' || len < 2) \ + continue; \ + for (lp = VIP(sp)->ps; *lp != '\0'; lp += 2) \ + if (lp[0] == p[1] && \ + (lp[1] == ' ' && len == 2 || lp[1] == p[2]) && \ + !--cnt) \ + goto found; \ +} while (0) + +/* + * v_paragraphf -- [count]} + * Move forward count paragraphs. + * + * Paragraphs are empty lines after text, formfeed characters, or values + * from the paragraph or section options. + * + * PUBLIC: int v_paragraphf(SCR *, VICMD *); + */ +int +v_paragraphf(SCR *sp, VICMD *vp) +{ + enum { P_INTEXT, P_INBLANK } pstate; + size_t lastlen, len; + recno_t cnt, lastlno, lno; + int isempty; + CHAR_T *p; + char *lp; + + /* + * !!! + * If the starting cursor position is at or before any non-blank + * characters in the line, i.e. the movement is cutting all of the + * line's text, the buffer is in line mode. It's a lot easier to + * check here, because we know that the end is going to be the start + * or end of a line. + * + * This was historical practice in vi, with a single exception. If + * the paragraph movement was from the start of the last line to EOF, + * then all the characters were deleted from the last line, but the + * line itself remained. If somebody complains, don't pause, don't + * hesitate, just hit them. + */ + if (ISMOTION(vp)) { + if (vp->m_start.cno == 0) + F_SET(vp, VM_LMODE); + else { + vp->m_stop = vp->m_start; + vp->m_stop.cno = 0; + if (nonblank(sp, vp->m_stop.lno, &vp->m_stop.cno)) + return (1); + if (vp->m_start.cno <= vp->m_stop.cno) + F_SET(vp, VM_LMODE); + } + } + + /* Figure out what state we're currently in. */ + lno = vp->m_start.lno; + if (db_get(sp, lno, 0, &p, &len)) + goto eof; + + /* + * If we start in text, we want to switch states + * (2 * N - 1) times, in non-text, (2 * N) times. + */ + cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; + cnt *= 2; + if (len == 0 || v_isempty(p, len)) + pstate = P_INBLANK; + else { + --cnt; + pstate = P_INTEXT; + } + + for (;;) { + lastlno = lno; + lastlen = len; + if (db_get(sp, ++lno, 0, &p, &len)) + goto eof; + switch (pstate) { + case P_INTEXT: + INTEXT_CHECK; + break; + case P_INBLANK: + if (len == 0 || v_isempty(p, len)) + break; + if (--cnt) { + pstate = P_INTEXT; + break; + } + /* + * !!! + * Non-motion commands move to the end of the range, + * delete and yank stay at the start. Ignore others. + * Adjust the end of the range for motion commands; + * historically, a motion component was to the end of + * the previous line, whereas the movement command was + * to the start of the new "paragraph". + */ +found: if (ISMOTION(vp)) { + vp->m_stop.lno = lastlno; + vp->m_stop.cno = lastlen ? lastlen - 1 : 0; + vp->m_final = vp->m_start; + } else { + vp->m_stop.lno = lno; + vp->m_stop.cno = 0; + vp->m_final = vp->m_stop; + } + return (0); + default: + abort(); + } + } + + /* + * !!! + * Adjust end of the range for motion commands; EOF is a movement + * sink. The } command historically moved to the end of the last + * line, not the beginning, from any position before the end of the + * last line. It also historically worked on empty files, so we + * have to make it okay. + */ +eof: if (vp->m_start.lno == lno || vp->m_start.lno == lno - 1) { + if (db_eget(sp, vp->m_start.lno, &p, &len, &isempty)) { + if (!isempty) + return (1); + vp->m_start.cno = 0; + return (0); + } + if (vp->m_start.cno == (len ? len - 1 : 0)) { + v_eof(sp, NULL); + return (1); + } + } + /* + * !!! + * Non-motion commands move to the end of the range, delete + * and yank stay at the start. Ignore others. + * + * If deleting the line (which happens if deleting to EOF), then + * cursor movement is to the first nonblank. + */ + if (ISMOTION(vp) && ISCMD(vp->rkp, 'd')) { + F_CLR(vp, VM_RCM_MASK); + F_SET(vp, VM_RCM_SETFNB); + } + vp->m_stop.lno = lno - 1; + vp->m_stop.cno = len ? len - 1 : 0; + vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop; + return (0); +} + +/* + * v_paragraphb -- [count]{ + * Move backward count paragraphs. + * + * PUBLIC: int v_paragraphb(SCR *, VICMD *); + */ +int +v_paragraphb(SCR *sp, VICMD *vp) +{ + enum { P_INTEXT, P_INBLANK } pstate; + size_t len; + recno_t cnt, lno; + CHAR_T *p; + char *lp; + + /* + * !!! + * Check for SOF. The historic vi didn't complain if users hit SOF + * repeatedly, unless it was part of a motion command. There is no + * question but that Emerson's editor of choice was vi. + * + * The { command historically moved to the beginning of the first + * line if invoked on the first line. + * + * !!! + * If the starting cursor position is in the first column (backward + * paragraph movements did NOT historically pay attention to non-blank + * characters) i.e. the movement is cutting the entire line, the buffer + * is in line mode. Cuts from the beginning of the line also did not + * cut the current line, but started at the previous EOL. + * + * Correct for a left motion component while we're thinking about it. + */ + lno = vp->m_start.lno; + + if (ISMOTION(vp)) { + if (vp->m_start.cno == 0) { + if (vp->m_start.lno == 1) { + v_sof(sp, &vp->m_start); + return (1); + } else + --vp->m_start.lno; + F_SET(vp, VM_LMODE); + } else + --vp->m_start.cno; + } + + if (vp->m_start.lno <= 1) + goto sof; + + /* Figure out what state we're currently in. */ + if (db_get(sp, lno, 0, &p, &len)) + goto sof; + + /* + * If we start in text, we want to switch states + * (2 * N - 1) times, in non-text, (2 * N) times. + */ + cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; + cnt *= 2; + if (len == 0 || v_isempty(p, len)) + pstate = P_INBLANK; + else { + --cnt; + pstate = P_INTEXT; + + /* + * !!! + * If the starting cursor is past the first column, + * the current line is checked for a paragraph. + */ + if (vp->m_start.cno > 0) + ++lno; + } + + for (;;) { + if (db_get(sp, --lno, 0, &p, &len)) + goto sof; + switch (pstate) { + case P_INTEXT: + INTEXT_CHECK; + break; + case P_INBLANK: + if (len != 0 && !v_isempty(p, len)) { + if (!--cnt) + goto found; + pstate = P_INTEXT; + } + break; + default: + abort(); + } + } + + /* SOF is a movement sink. */ +sof: lno = 1; + +found: vp->m_stop.lno = lno; + vp->m_stop.cno = 0; + + /* + * All commands move to the end of the range. (We already + * adjusted the start of the range for motion commands). + */ + vp->m_final = vp->m_stop; + return (0); +} + +/* + * v_buildps -- + * Build the paragraph command search pattern. + * + * PUBLIC: int v_buildps(SCR *, char *, char *); + */ +int +v_buildps(SCR *sp, char *p_p, char *s_p) +{ + VI_PRIVATE *vip; + size_t p_len, s_len; + char *p; + + /* + * The vi paragraph command searches for either a paragraph or + * section option macro. + */ + p_len = p_p == NULL ? 0 : strlen(p_p); + s_len = s_p == NULL ? 0 : strlen(s_p); + + if (p_len == 0 && s_len == 0) + return (0); + + MALLOC_RET(sp, p, p_len + s_len + 1); + + vip = VIP(sp); + free(vip->ps); + + if (p_p != NULL) + memmove(p, p_p, p_len + 1); + if (s_p != NULL) + memmove(p + p_len, s_p, s_len + 1); + vip->ps = p; + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/vi/v_paragraph.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/vi/v_section.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/vi/v_section.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/vi/v_section.c (revision 366308) @@ -0,0 +1,247 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include + +#include "../common/common.h" +#include "vi.h" + +/* + * !!! + * In historic vi, the section commands ignored empty lines, unlike the + * paragraph commands, which was probably okay. However, they also moved + * to the start of the last line when there where no more sections instead + * of the end of the last line like the paragraph commands. I've changed + * the latter behavior to match the paragraph commands. + * + * In historic vi, a section was defined as the first character(s) of the + * line matching, which could be followed by anything. This implementation + * follows that historic practice. + * + * !!! + * The historic vi documentation (USD:15-10) claimed: + * The section commands interpret a preceding count as a different + * window size in which to redraw the screen at the new location, + * and this window size is the base size for newly drawn windows + * until another size is specified. This is very useful if you are + * on a slow terminal ... + * + * I can't get the 4BSD vi to do this, it just beeps at me. For now, a + * count to the section commands simply repeats the command. + */ + +/* + * v_sectionf -- [count]]] + * Move forward count sections/functions. + * + * !!! + * Using ]] as a motion command was a bit special, historically. It could + * match } as well as the usual { and section values. If it matched a { or + * a section, it did NOT include the matched line. If it matched a }, it + * did include the line. No clue why. + * + * PUBLIC: int v_sectionf(SCR *, VICMD *); + */ +int +v_sectionf(SCR *sp, VICMD *vp) +{ + recno_t cnt, lno; + size_t len; + CHAR_T *p; + char *list, *lp; + + /* Get the macro list. */ + if ((list = O_STR(sp, O_SECTIONS)) == NULL) + return (1); + + /* + * !!! + * If the starting cursor position is at or before any non-blank + * characters in the line, i.e. the movement is cutting all of the + * line's text, the buffer is in line mode. It's a lot easier to + * check here, because we know that the end is going to be the start + * or end of a line. + */ + if (ISMOTION(vp)) { + if (vp->m_start.cno == 0) + F_SET(vp, VM_LMODE); + else { + vp->m_stop = vp->m_start; + vp->m_stop.cno = 0; + if (nonblank(sp, vp->m_stop.lno, &vp->m_stop.cno)) + return (1); + if (vp->m_start.cno <= vp->m_stop.cno) + F_SET(vp, VM_LMODE); + } + } + + cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; + for (lno = vp->m_start.lno; !db_get(sp, ++lno, 0, &p, &len);) { + if (len == 0) + continue; + if (p[0] == '{' || (ISMOTION(vp) && p[0] == '}')) { + if (!--cnt) { + if (p[0] == '{') + goto adjust1; + goto adjust2; + } + continue; + } + /* + * !!! + * Historic documentation (USD:15-11, 4.2) said that formfeed + * characters (^L) in the first column delimited sections. + * The historic code mentions formfeed characters, but never + * implements them. Seems reasonable, do it. + */ + if (p[0] == '\014') { + if (!--cnt) + goto adjust1; + continue; + } + if (p[0] != '.' || len < 2) + continue; + for (lp = list; *lp != '\0'; lp += 2 * sizeof(*lp)) + if (lp[0] == p[1] && + ((lp[1] == ' ' && len == 2) || lp[1] == p[2]) && + !--cnt) { + /* + * !!! + * If not cutting this line, adjust to the end + * of the previous one. Otherwise, position to + * column 0. + */ +adjust1: if (ISMOTION(vp)) + goto ret1; + +adjust2: vp->m_stop.lno = lno; + vp->m_stop.cno = 0; + goto ret2; + } + } + + /* If moving forward, reached EOF, check to see if we started there. */ + if (vp->m_start.lno == lno - 1) { + v_eof(sp, NULL); + return (1); + } + +ret1: if (db_get(sp, --lno, DBG_FATAL, NULL, &len)) + return (1); + vp->m_stop.lno = lno; + vp->m_stop.cno = len ? len - 1 : 0; + + /* + * Non-motion commands go to the end of the range. Delete and + * yank stay at the start of the range. Ignore others. + */ +ret2: if (ISMOTION(vp)) { + vp->m_final = vp->m_start; + if (F_ISSET(vp, VM_LMODE)) + vp->m_final.cno = 0; + } else + vp->m_final = vp->m_stop; + return (0); +} + +/* + * v_sectionb -- [count][[ + * Move backward count sections/functions. + * + * PUBLIC: int v_sectionb(SCR *, VICMD *); + */ +int +v_sectionb(SCR *sp, VICMD *vp) +{ + size_t len; + recno_t cnt, lno; + CHAR_T *p; + char *list, *lp; + + /* An empty file or starting from line 1 is always illegal. */ + if (vp->m_start.lno <= 1) { + v_sof(sp, NULL); + return (1); + } + + /* Get the macro list. */ + if ((list = O_STR(sp, O_SECTIONS)) == NULL) + return (1); + + cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; + for (lno = vp->m_start.lno; !db_get(sp, --lno, 0, &p, &len);) { + if (len == 0) + continue; + if (p[0] == '{') { + if (!--cnt) + goto adjust1; + continue; + } + /* + * !!! + * Historic documentation (USD:15-11, 4.2) said that formfeed + * characters (^L) in the first column delimited sections. + * The historic code mentions formfeed characters, but never + * implements them. Seems reasonable, do it. + */ + if (p[0] == '\014') { + if (!--cnt) + goto adjust1; + continue; + } + if (p[0] != '.' || len < 2) + continue; + for (lp = list; *lp != '\0'; lp += 2 * sizeof(*lp)) + if (lp[0] == p[1] && + ((lp[1] == ' ' && len == 2) || lp[1] == p[2]) && + !--cnt) { +adjust1: vp->m_stop.lno = lno; + vp->m_stop.cno = 0; + goto ret1; + } + } + + /* + * If moving backward, reached SOF, which is a movement sink. + * We already checked for starting there. + */ + vp->m_stop.lno = 1; + vp->m_stop.cno = 0; + + /* + * All commands move to the end of the range. + * + * !!! + * Historic practice is the section cut was in line mode if it started + * from column 0 and was in the backward direction. Otherwise, left + * motion commands adjust the starting point to the character before + * the current one. What makes this worse is that if it cut to line + * mode it also went to the first non-. + */ +ret1: if (vp->m_start.cno == 0) { + F_CLR(vp, VM_RCM_MASK); + F_SET(vp, VM_RCM_SETFNB); + + --vp->m_start.lno; + F_SET(vp, VM_LMODE); + } else + --vp->m_start.cno; + + vp->m_final = vp->m_stop; + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/vi/v_section.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/vi/v_sentence.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/vi/v_sentence.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/vi/v_sentence.c (revision 366308) @@ -0,0 +1,352 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include + +#include "../common/common.h" +#include "vi.h" + +/* + * !!! + * In historic vi, a sentence was delimited by a '.', '?' or '!' character + * followed by TWO spaces or a newline. One or more empty lines was also + * treated as a separate sentence. The Berkeley documentation for historical + * vi states that any number of ')', ']', '"' and '\'' characters can be + * between the delimiter character and the spaces or end of line, however, + * the historical implementation did not handle additional '"' characters. + * We follow the documentation here, not the implementation. + * + * Once again, historical vi didn't do sentence movements associated with + * counts consistently, mostly in the presence of lines containing only + * white-space characters. + * + * This implementation also permits a single tab to delimit sentences, and + * treats lines containing only white-space characters as empty lines. + * Finally, tabs are eaten (along with spaces) when skipping to the start + * of the text following a "sentence". + */ + +/* + * v_sentencef -- [count]) + * Move forward count sentences. + * + * PUBLIC: int v_sentencef(SCR *, VICMD *); + */ +int +v_sentencef(SCR *sp, VICMD *vp) +{ + enum { BLANK, NONE, PERIOD } state; + VCS cs; + size_t len; + u_long cnt; + + cs.cs_lno = vp->m_start.lno; + cs.cs_cno = vp->m_start.cno; + if (cs_init(sp, &cs)) + return (1); + + cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; + + /* + * !!! + * If in white-space, the next start of sentence counts as one. + * This may not handle " . " correctly, but it's real unclear + * what correctly means in that case. + */ + if (cs.cs_flags == CS_EMP || (cs.cs_flags == 0 && isblank(cs.cs_ch))) { + if (cs_fblank(sp, &cs)) + return (1); + if (--cnt == 0) { + if (vp->m_start.lno != cs.cs_lno || + vp->m_start.cno != cs.cs_cno) + goto okret; + return (1); + } + } + + for (state = NONE;;) { + if (cs_next(sp, &cs)) + return (1); + if (cs.cs_flags == CS_EOF) + break; + if (cs.cs_flags == CS_EOL) { + if ((state == PERIOD || state == BLANK) && --cnt == 0) { + if (cs_next(sp, &cs)) + return (1); + if (cs.cs_flags == 0 && + isblank(cs.cs_ch) && cs_fblank(sp, &cs)) + return (1); + goto okret; + } + state = NONE; + continue; + } + if (cs.cs_flags == CS_EMP) { /* An EMP is two sentences. */ + if (--cnt == 0) + goto okret; + if (cs_fblank(sp, &cs)) + return (1); + if (--cnt == 0) + goto okret; + state = NONE; + continue; + } + switch (cs.cs_ch) { + case '.': + case '?': + case '!': + state = PERIOD; + break; + case ')': + case ']': + case '"': + case '\'': + if (state != PERIOD) + state = NONE; + break; + case '\t': + if (state == PERIOD) + state = BLANK; + /* FALLTHROUGH */ + case ' ': + if (state == PERIOD) { + state = BLANK; + break; + } + if (state == BLANK && --cnt == 0) { + if (cs_fblank(sp, &cs)) + return (1); + goto okret; + } + /* FALLTHROUGH */ + default: + state = NONE; + break; + } + } + + /* EOF is a movement sink, but it's an error not to have moved. */ + if (vp->m_start.lno == cs.cs_lno && vp->m_start.cno == cs.cs_cno) { + v_eof(sp, NULL); + return (1); + } + +okret: vp->m_stop.lno = cs.cs_lno; + vp->m_stop.cno = cs.cs_cno; + + /* + * !!! + * Historic, uh, features, yeah, that's right, call 'em features. + * If the starting and ending cursor positions are at the first + * column in their lines, i.e. the movement is cutting entire lines, + * the buffer is in line mode, and the ending position is the last + * character of the previous line. Note check to make sure that + * it's not within a single line. + * + * Non-motion commands move to the end of the range. Delete and + * yank stay at the start. Ignore others. Adjust the end of the + * range for motion commands. + */ + if (ISMOTION(vp)) { + if (vp->m_start.cno == 0 && + (cs.cs_flags != 0 || vp->m_stop.cno == 0)) { + if (vp->m_start.lno < vp->m_stop.lno) { + if (db_get(sp, + --vp->m_stop.lno, DBG_FATAL, NULL, &len)) + return (1); + vp->m_stop.cno = len ? len - 1 : 0; + } + F_SET(vp, VM_LMODE); + } else + --vp->m_stop.cno; + vp->m_final = vp->m_start; + } else + vp->m_final = vp->m_stop; + return (0); +} + +/* + * v_sentenceb -- [count]( + * Move backward count sentences. + * + * PUBLIC: int v_sentenceb(SCR *, VICMD *); + */ +int +v_sentenceb(SCR *sp, VICMD *vp) +{ + VCS cs; + recno_t slno; + size_t len, scno; + u_long cnt; + int last; + + /* + * !!! + * Historic vi permitted the user to hit SOF repeatedly. + */ + if (vp->m_start.lno == 1 && vp->m_start.cno == 0) + return (0); + + cs.cs_lno = vp->m_start.lno; + cs.cs_cno = vp->m_start.cno; + if (cs_init(sp, &cs)) + return (1); + + cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; + + /* + * !!! + * In empty lines, skip to the previous non-white-space character. + * If in text, skip to the prevous white-space character. Believe + * it or not, in the paragraph: + * ab cd. + * AB CD. + * if the cursor is on the 'A' or 'B', ( moves to the 'a'. If it + * is on the ' ', 'C' or 'D', it moves to the 'A'. Yes, Virginia, + * Berkeley was once a major center of drug activity. + */ + if (cs.cs_flags == CS_EMP) { + if (cs_bblank(sp, &cs)) + return (1); + for (;;) { + if (cs_prev(sp, &cs)) + return (1); + if (cs.cs_flags != CS_EOL) + break; + } + } else if (cs.cs_flags == 0 && !isblank(cs.cs_ch)) + for (;;) { + if (cs_prev(sp, &cs)) + return (1); + if (cs.cs_flags != 0 || isblank(cs.cs_ch)) + break; + } + + for (last = 0;;) { + if (cs_prev(sp, &cs)) + return (1); + if (cs.cs_flags == CS_SOF) /* SOF is a movement sink. */ + break; + if (cs.cs_flags == CS_EOL) { + last = 1; + continue; + } + if (cs.cs_flags == CS_EMP) { + if (--cnt == 0) + goto ret; + if (cs_bblank(sp, &cs)) + return (1); + last = 0; + continue; + } + switch (cs.cs_ch) { + case '.': + case '?': + case '!': + if (!last || --cnt != 0) { + last = 0; + continue; + } + +ret: slno = cs.cs_lno; + scno = cs.cs_cno; + + /* + * Move to the start of the sentence, skipping blanks + * and special characters. + */ + do { + if (cs_next(sp, &cs)) + return (1); + } while (!cs.cs_flags && + (cs.cs_ch == ')' || cs.cs_ch == ']' || + cs.cs_ch == '"' || cs.cs_ch == '\'')); + if ((cs.cs_flags || isblank(cs.cs_ch)) && + cs_fblank(sp, &cs)) + return (1); + + /* + * If it was ". xyz", with the cursor on the 'x', or + * "end. ", with the cursor in the spaces, or the + * beginning of a sentence preceded by an empty line, + * we can end up where we started. Fix it. + */ + if (vp->m_start.lno != cs.cs_lno || + vp->m_start.cno > cs.cs_cno) + goto okret; + + /* + * Well, if an empty line preceded possible blanks + * and the sentence, it could be a real sentence. + */ + for (;;) { + if (cs_prev(sp, &cs)) + return (1); + if (cs.cs_flags == CS_EOL) + continue; + if (cs.cs_flags == 0 && isblank(cs.cs_ch)) + continue; + break; + } + if (cs.cs_flags == CS_EMP) + goto okret; + + /* But it wasn't; try again. */ + ++cnt; + cs.cs_lno = slno; + cs.cs_cno = scno; + last = 0; + break; + case '\t': + last = 1; + break; + default: + last = + cs.cs_flags == CS_EOL || isblank(cs.cs_ch) || + cs.cs_ch == ')' || cs.cs_ch == ']' || + cs.cs_ch == '"' || cs.cs_ch == '\'' ? 1 : 0; + } + } + +okret: vp->m_stop.lno = cs.cs_lno; + vp->m_stop.cno = cs.cs_cno; + + /* + * !!! + * If the starting and stopping cursor positions are at the first + * columns in the line, i.e. the movement is cutting an entire line, + * the buffer is in line mode, and the starting position is the last + * character of the previous line. + * + * All commands move to the end of the range. Adjust the start of + * the range for motion commands. + */ + if (ISMOTION(vp)) { + if (vp->m_start.cno == 0 && + (cs.cs_flags != 0 || vp->m_stop.cno == 0)) { + if (db_get(sp, + --vp->m_start.lno, DBG_FATAL, NULL, &len)) + return (1); + vp->m_start.cno = len ? len - 1 : 0; + F_SET(vp, VM_LMODE); + } else + --vp->m_start.cno; + } + vp->m_final = vp->m_stop; + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/vi/v_sentence.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/vi/v_txt.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/vi/v_txt.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/vi/v_txt.c (revision 366308) @@ -0,0 +1,2898 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../common/common.h" +#include "vi.h" + +static int txt_abbrev(SCR *, TEXT *, CHAR_T *, int, int *, int *); +static void txt_ai_resolve(SCR *, TEXT *, int *); +static TEXT *txt_backup(SCR *, TEXTH *, TEXT *, u_int32_t *); +static int txt_dent(SCR *, TEXT *, int, int); +static int txt_emark(SCR *, TEXT *, size_t); +static void txt_err(SCR *, TEXTH *); +static int txt_fc(SCR *, TEXT *, int *); +static int txt_fc_col(SCR *, int, ARGS **); +static int txt_hex(SCR *, TEXT *); +static int txt_insch(SCR *, TEXT *, CHAR_T *, u_int); +static int txt_isrch(SCR *, VICMD *, TEXT *, u_int8_t *); +static int txt_map_end(SCR *); +static int txt_map_init(SCR *); +static int txt_margin(SCR *, TEXT *, TEXT *, int *, u_int32_t); +static void txt_nomorech(SCR *); +static void txt_Rresolve(SCR *, TEXTH *, TEXT *, const size_t); +static int txt_resolve(SCR *, TEXTH *, u_int32_t); +static int txt_showmatch(SCR *, TEXT *); +static void txt_unmap(SCR *, TEXT *, u_int32_t *); + +/* Cursor character (space is hard to track on the screen). */ +#if defined(DEBUG) && 0 +#undef CH_CURSOR +#define CH_CURSOR '+' +#endif + +/* + * v_tcmd -- + * Fill a buffer from the terminal for vi. + * + * PUBLIC: int v_tcmd(SCR *, VICMD *, ARG_CHAR_T, u_int); + */ +int +v_tcmd(SCR *sp, VICMD *vp, ARG_CHAR_T prompt, u_int flags) +{ + /* Normally, we end up where we started. */ + vp->m_final.lno = sp->lno; + vp->m_final.cno = sp->cno; + + /* Initialize the map. */ + if (txt_map_init(sp)) + return (1); + + /* Move to the last line. */ + sp->lno = TMAP[0].lno; + sp->cno = 0; + + /* Don't update the modeline for now. */ + F_SET(sp, SC_TINPUT_INFO); + + /* Set the input flags. */ + LF_SET(TXT_APPENDEOL | + TXT_CR | TXT_ESCAPE | TXT_INFOLINE | TXT_MAPINPUT); + if (O_ISSET(sp, O_ALTWERASE)) + LF_SET(TXT_ALTWERASE); + if (O_ISSET(sp, O_TTYWERASE)) + LF_SET(TXT_TTYWERASE); + + /* Do the input thing. */ + if (v_txt(sp, vp, NULL, NULL, 0, prompt, 0, 1, flags)) + return (1); + + /* Reenable the modeline updates. */ + F_CLR(sp, SC_TINPUT_INFO); + + /* Clean up the map. */ + if (txt_map_end(sp)) + return (1); + + if (IS_ONELINE(sp)) + F_SET(sp, SC_SCR_REDRAW); /* XXX */ + + /* Set the cursor to the resulting position. */ + sp->lno = vp->m_final.lno; + sp->cno = vp->m_final.cno; + + return (0); +} + +/* + * txt_map_init + * Initialize the screen map for colon command-line input. + */ +static int +txt_map_init(SCR *sp) +{ + SMAP *esmp; + VI_PRIVATE *vip; + + vip = VIP(sp); + if (!IS_ONELINE(sp)) { + /* + * Fake like the user is doing input on the last line of the + * screen. This makes all of the scrolling work correctly, + * and allows us the use of the vi text editing routines, not + * to mention practically infinite length ex commands. + * + * Save the current location. + */ + vip->sv_tm_lno = TMAP->lno; + vip->sv_tm_soff = TMAP->soff; + vip->sv_tm_coff = TMAP->coff; + vip->sv_t_maxrows = sp->t_maxrows; + vip->sv_t_minrows = sp->t_minrows; + vip->sv_t_rows = sp->t_rows; + + /* + * If it's a small screen, TMAP may be small for the screen. + * Fix it, filling in fake lines as we go. + */ + if (IS_SMALL(sp)) + for (esmp = + HMAP + (sp->t_maxrows - 1); TMAP < esmp; ++TMAP) { + TMAP[1].lno = TMAP[0].lno + 1; + TMAP[1].coff = HMAP->coff; + TMAP[1].soff = 1; + } + + /* Build the fake entry. */ + TMAP[1].lno = TMAP[0].lno + 1; + TMAP[1].soff = 1; + TMAP[1].coff = 0; + SMAP_FLUSH(&TMAP[1]); + ++TMAP; + + /* Reset the screen information. */ + sp->t_rows = sp->t_minrows = ++sp->t_maxrows; + } + return (0); +} + +/* + * txt_map_end + * Reset the screen map for colon command-line input. + */ +static int +txt_map_end(SCR *sp) +{ + VI_PRIVATE *vip; + size_t cnt; + + vip = VIP(sp); + if (!IS_ONELINE(sp)) { + /* Restore the screen information. */ + sp->t_rows = vip->sv_t_rows; + sp->t_minrows = vip->sv_t_minrows; + sp->t_maxrows = vip->sv_t_maxrows; + + /* + * If it's a small screen, TMAP may be wrong. Clear any + * lines that might have been overwritten. + */ + if (IS_SMALL(sp)) { + for (cnt = sp->t_rows; cnt <= sp->t_maxrows; ++cnt) { + (void)sp->gp->scr_move(sp, cnt, 0); + (void)sp->gp->scr_clrtoeol(sp); + } + TMAP = HMAP + (sp->t_rows - 1); + } else + --TMAP; + + /* + * The map may be wrong if the user entered more than one + * (logical) line. Fix it. If the user entered a whole + * screen, this will be slow, but we probably don't care. + */ + if (!O_ISSET(sp, O_LEFTRIGHT)) + while (vip->sv_tm_lno != TMAP->lno || + vip->sv_tm_soff != TMAP->soff) + if (vs_sm_1down(sp)) + return (1); + } + + /* + * Invalidate the cursor and the line size cache, the line never + * really existed. This fixes bugs where the user searches for + * the last line on the screen + 1 and the refresh routine thinks + * that's where we just were. + */ + VI_SCR_CFLUSH(vip); + F_SET(vip, VIP_CUR_INVALID); + + return (0); +} + +/* + * If doing input mapping on the colon command line, may need to unmap + * based on the command. + */ +#define UNMAP_TST \ + FL_ISSET(ec_flags, EC_MAPINPUT) && LF_ISSET(TXT_INFOLINE) + +/* + * Internally, we maintain tp->lno and tp->cno, externally, everyone uses + * sp->lno and sp->cno. Make them consistent as necessary. + */ +#define UPDATE_POSITION(sp, tp) do { \ + (sp)->lno = (tp)->lno; \ + (sp)->cno = (tp)->cno; \ +} while (0) + +/* + * v_txt -- + * Vi text input. + * + * PUBLIC: int v_txt(SCR *, VICMD *, MARK *, + * PUBLIC: const CHAR_T *, size_t, ARG_CHAR_T, recno_t, u_long, u_int32_t); + */ +int +v_txt( + SCR *sp, + VICMD *vp, + MARK *tm, /* To MARK. */ + const CHAR_T *lp, /* Input line. */ + size_t len, /* Input line length. */ + ARG_CHAR_T prompt, /* Prompt to display. */ + recno_t ai_line, /* Line number to use for autoindent count. */ + u_long rcount, /* Replay count. */ + u_int32_t flags) /* TXT_* flags. */ +{ + EVENT ev, *evp = NULL; /* Current event. */ + EVENT fc; /* File name completion event. */ + GS *gp; + TEXT *ntp, *tp; /* Input text structures. */ + TEXT ait; /* Autoindent text structure. */ + TEXT wmt = {{ 0 }}; /* Wrapmargin text structure. */ + TEXTH *tiqh; + VI_PRIVATE *vip; + abb_t abb; /* State of abbreviation checks. */ + carat_t carat; /* State of the "[^0]^D" sequences. */ + quote_t quote; /* State of quotation. */ + size_t owrite, insert; /* Temporary copies of TEXT fields. */ + size_t margin; /* Wrapmargin value. */ + size_t rcol; /* 0-N: insert offset in the replay buffer. */ + size_t tcol; /* Temporary column. */ + u_int32_t ec_flags; /* Input mapping flags. */ +#define IS_RESTART 0x01 /* Reset the incremental search. */ +#define IS_RUNNING 0x02 /* Incremental search turned on. */ + u_int8_t is_flags; + int abcnt, ab_turnoff; /* Abbreviation character count, switch. */ + int filec_redraw; /* Redraw after the file completion routine. */ + int hexcnt; /* Hex character count. */ + int showmatch; /* Showmatch set on this character. */ + int wm_set, wm_skip; /* Wrapmargin happened, blank skip flags. */ + int max, tmp; + int nochange; + CHAR_T *p; + + gp = sp->gp; + vip = VIP(sp); + + /* + * Set the input flag, so tabs get displayed correctly + * and everyone knows that the text buffer is in use. + */ + F_SET(sp, SC_TINPUT); + + /* + * Get one TEXT structure with some initial buffer space, reusing + * the last one if it's big enough. (All TEXT bookkeeping fields + * default to 0 -- text_init() handles this.) If changing a line, + * copy it into the TEXT buffer. + */ + tiqh = sp->tiq; + if (!TAILQ_EMPTY(tiqh)) { + tp = TAILQ_FIRST(tiqh); + if (TAILQ_NEXT(tp, q) != NULL || + tp->lb_len < (len + 32) * sizeof(CHAR_T)) { + text_lfree(tiqh); + goto newtp; + } + tp->ai = tp->insert = tp->offset = tp->owrite = 0; + if (lp != NULL) { + tp->len = len; + BINC_RETW(sp, tp->lb, tp->lb_len, len); + MEMMOVE(tp->lb, lp, len); + } else + tp->len = 0; + } else { +newtp: if ((tp = text_init(sp, lp, len, len + 32)) == NULL) + return (1); + TAILQ_INSERT_HEAD(tiqh, tp, q); + } + + /* Set default termination condition. */ + tp->term = TERM_OK; + + /* Set the starting line, column. */ + tp->lno = sp->lno; + tp->cno = sp->cno; + + /* + * Set the insert and overwrite counts. If overwriting characters, + * do insertion afterward. If not overwriting characters, assume + * doing insertion. If change is to a mark, emphasize it with an + * CH_ENDMARK character. + */ + if (len) { + if (LF_ISSET(TXT_OVERWRITE)) { + tp->owrite = (tm->cno - tp->cno) + 1; + tp->insert = (len - tm->cno) - 1; + } else + tp->insert = len - tp->cno; + + if (LF_ISSET(TXT_EMARK) && txt_emark(sp, tp, tm->cno)) + return (1); + } + + /* + * Many of the special cases in text input are to handle autoindent + * support. Somebody decided that it would be a good idea if "^^D" + * and "0^D" deleted all of the autoindented characters. In an editor + * that takes single character input from the user, this beggars the + * imagination. Note also, "^^D" resets the next lines' autoindent, + * but "0^D" doesn't. + * + * We assume that autoindent only happens on empty lines, so insert + * and overwrite will be zero. If doing autoindent, figure out how + * much indentation we need and fill it in. Update input column and + * screen cursor as necessary. + */ + if (LF_ISSET(TXT_AUTOINDENT) && ai_line != OOBLNO) { + if (v_txt_auto(sp, ai_line, NULL, 0, tp)) + return (1); + tp->cno = tp->ai; + } else { + /* + * The cc and S commands have a special feature -- leading + * characters are handled as autoindent characters. + * Beauty! + */ + if (LF_ISSET(TXT_AICHARS)) { + tp->offset = 0; + tp->ai = tp->cno; + } else + tp->offset = tp->cno; + } + + /* If getting a command buffer from the user, there may be a prompt. */ + if (LF_ISSET(TXT_PROMPT)) { + tp->lb[tp->cno++] = prompt; + ++tp->len; + ++tp->offset; + } + + /* + * If appending after the end-of-line, add a space into the buffer + * and move the cursor right. This space is inserted, i.e. pushed + * along, and then deleted when the line is resolved. Assumes that + * the cursor is already positioned at the end of the line. This + * avoids the nastiness of having the cursor reside on a magical + * column, i.e. a column that doesn't really exist. The only down + * side is that we may wrap lines or scroll the screen before it's + * strictly necessary. Not a big deal. + */ + if (LF_ISSET(TXT_APPENDEOL)) { + tp->lb[tp->cno] = CH_CURSOR; + ++tp->len; + ++tp->insert; + (void)vs_change(sp, tp->lno, LINE_RESET); + } + + /* + * Historic practice is that the wrapmargin value was a distance + * from the RIGHT-HAND margin, not the left. It's more useful to + * us as a distance from the left-hand margin, i.e. the same as + * the wraplen value. The wrapmargin option is historic practice. + * Nvi added the wraplen option so that it would be possible to + * edit files with consistent margins without knowing the number of + * columns in the window. + * + * XXX + * Setting margin causes a significant performance hit. Normally + * we don't update the screen if there are keys waiting, but we + * have to if margin is set, otherwise the screen routines don't + * know where the cursor is. + * + * !!! + * Abbreviated keys were affected by the wrapmargin option in the + * historic 4BSD vi. Mapped keys were usually, but sometimes not. + * See the comment in vi/v_text():set_txt_std for more information. + * + * !!! + * One more special case. If an inserted character causes + * wrapmargin to split the line, the next user entered character is + * discarded if it's a character. + */ + wm_set = wm_skip = 0; + if (LF_ISSET(TXT_WRAPMARGIN)) + if ((margin = O_VAL(sp, O_WRAPMARGIN)) != 0) + margin = sp->cols - margin; + else + margin = O_VAL(sp, O_WRAPLEN); + else + margin = 0; + + /* Initialize abbreviation checks. */ + abcnt = ab_turnoff = 0; + abb = F_ISSET(gp, G_ABBREV) && + LF_ISSET(TXT_MAPINPUT) ? AB_INWORD : AB_NOTSET; + + /* + * Set up the dot command. Dot commands are done by saving the actual + * characters and then reevaluating them so that things like wrapmargin + * can change between the insert and the replay. + * + * !!! + * Historically, vi did not remap or reabbreviate replayed input. (It + * did beep at you if you changed an abbreviation and then replayed the + * input. We're not that compatible.) We don't have to do anything to + * avoid remapping, as we're not getting characters from the terminal + * routines. Turn the abbreviation check off. + * + * XXX + * It would be nice if we could swallow backspaces and such, but it's + * not all that easy to do. What we can do is turn off the common + * error messages during the replay. Otherwise, when the user enters + * an illegal command, e.g., "Iab", + * and then does a '.', they get a list of error messages after command + * completion. + */ + rcol = 0; + if (LF_ISSET(TXT_REPLAY)) { + abb = AB_NOTSET; + LF_CLR(TXT_RECORD); + } + + /* Other text input mode setup. */ + quote = Q_NOTSET; + carat = C_NOTSET; + nochange = 0; + FL_INIT(is_flags, + LF_ISSET(TXT_SEARCHINCR) ? IS_RESTART | IS_RUNNING : 0); + filec_redraw = hexcnt = showmatch = 0; + + /* Initialize input flags. */ + ec_flags = LF_ISSET(TXT_MAPINPUT) ? EC_MAPINPUT : 0; + + /* Refresh the screen. */ + UPDATE_POSITION(sp, tp); + if (vs_refresh(sp, 1)) + return (1); + + /* If it's dot, just do it now. */ + if (F_ISSET(vp, VC_ISDOT)) + goto replay; + + /* Get an event. */ + evp = &ev; +next: if (v_event_get(sp, evp, 0, ec_flags)) + return (1); + + /* + * If file completion overwrote part of the screen and nothing else has + * been displayed, clean up. We don't do this as part of the normal + * message resolution because we know the user is on the colon command + * line and there's no reason to enter explicit characters to continue. + */ + if (filec_redraw && !F_ISSET(sp, SC_SCR_EXWROTE)) { + filec_redraw = 0; + + fc.e_event = E_REPAINT; + fc.e_flno = vip->totalcount >= + sp->rows ? 1 : sp->rows - vip->totalcount; + fc.e_tlno = sp->rows; + vip->linecount = vip->lcontinue = vip->totalcount = 0; + (void)vs_repaint(sp, &fc); + (void)vs_refresh(sp, 1); + } + + /* Deal with all non-character events. */ + switch (evp->e_event) { + case E_CHARACTER: + break; + case E_ERR: + case E_EOF: + F_SET(sp, SC_EXIT_FORCE); + return (1); + case E_INTERRUPT: + /* + * !!! + * Historically, exited the user from text input + * mode or cancelled a colon command, and returned to command + * mode. It also beeped the terminal, but that seems a bit + * excessive. + */ + goto k_escape; + case E_REPAINT: + if (vs_repaint(sp, &ev)) + return (1); + goto next; + case E_WRESIZE: + /* interrupts the input mode. */ + v_emsg(sp, NULL, VIM_WRESIZE); + goto k_escape; + default: + v_event_err(sp, evp); + goto k_escape; + } + + /* + * !!! + * If the first character of the input is a nul, replay the previous + * input. (Historically, it's okay to replay non-existent input.) + * This was not documented as far as I know, and is a great test of vi + * clones. + */ + if (LF_ISSET(TXT_RECORD) && rcol == 0 && evp->e_c == '\0') { + if (vip->rep == NULL) + goto done; + + abb = AB_NOTSET; + LF_CLR(TXT_RECORD); + LF_SET(TXT_REPLAY); + goto replay; + } + + /* + * File name completion and colon command-line editing. We don't + * have enough meta characters, so we expect people to overload + * them. If the two characters are the same, then we do file name + * completion if the cursor is past the first column, and do colon + * command-line editing if it's not. + */ + if (quote == Q_NOTSET) { + int L__cedit, L__filec; + + L__cedit = L__filec = 0; + if (LF_ISSET(TXT_CEDIT) && O_STR(sp, O_CEDIT) != NULL && + O_STR(sp, O_CEDIT)[0] == evp->e_c) + L__cedit = 1; + if (LF_ISSET(TXT_FILEC) && O_STR(sp, O_FILEC) != NULL && + O_STR(sp, O_FILEC)[0] == evp->e_c) + L__filec = 1; + if (L__cedit == 1 && (L__filec == 0 || tp->cno == tp->offset)) { + tp->term = TERM_CEDIT; + goto k_escape; + } + if (L__filec == 1) { + if (txt_fc(sp, tp, &filec_redraw)) + goto err; + goto resolve; + } + } + + /* Abbreviation overflow check. See comment in txt_abbrev(). */ +#define MAX_ABBREVIATION_EXPANSION 256 + if (F_ISSET(&evp->e_ch, CH_ABBREVIATED)) { + if (++abcnt > MAX_ABBREVIATION_EXPANSION) { + if (v_event_flush(sp, CH_ABBREVIATED)) + msgq(sp, M_ERR, +"191|Abbreviation exceeded expansion limit: characters discarded"); + abcnt = 0; + if (LF_ISSET(TXT_REPLAY)) + goto done; + goto resolve; + } + } else + abcnt = 0; + + /* Check to see if the character fits into the replay buffers. */ + if (LF_ISSET(TXT_RECORD)) { + BINC_GOTO(sp, EVENT, vip->rep, + vip->rep_len, (rcol + 1) * sizeof(EVENT)); + vip->rep[rcol++] = *evp; + } + +replay: if (LF_ISSET(TXT_REPLAY)) { + if (rcol == vip->rep_cnt) + goto k_escape; + evp = vip->rep + rcol++; + } + + /* Wrapmargin check for leading space. */ + if (wm_skip) { + wm_skip = 0; + if (evp->e_c == ' ') + goto resolve; + } + + /* If quoted by someone else, simply insert the character. */ + if (F_ISSET(&evp->e_ch, CH_QUOTED)) + goto insq_ch; + + /* + * !!! + * If this character was quoted by a K_VLNEXT, replace the placeholder + * (a carat) with the new character. We've already adjusted the cursor + * because it has to appear on top of the placeholder character. + * Historic practice. + * + * Skip tests for abbreviations; ":ab xa XA" followed by "ixa^V" + * doesn't perform an abbreviation. Special case, ^V^J (not ^V^M) is + * the same as ^J, historically. + */ + if (quote == Q_VTHIS) { + FL_CLR(ec_flags, EC_QUOTED); + if (LF_ISSET(TXT_MAPINPUT)) + FL_SET(ec_flags, EC_MAPINPUT); + + if (evp->e_value != K_NL) { + quote = Q_NOTSET; + goto insl_ch; + } + quote = Q_NOTSET; + } + + /* + * !!! + * Translate "[isxdigit()]*" to a character with a hex value: + * this test delimits the value by any non-hex character. Offset by + * one, we use 0 to mean that we've found . + */ + if (hexcnt > 1 && !ISXDIGIT(evp->e_c)) { + hexcnt = 0; + if (txt_hex(sp, tp)) + goto err; + } + + switch (evp->e_value) { + case K_CR: /* Carriage return. */ + case K_NL: /* New line. */ + /* Return in script windows and the command line. */ +k_cr: if (LF_ISSET(TXT_CR)) { + /* + * If this was a map, we may have not displayed + * the line. Display it, just in case. + * + * If a script window and not the colon line, + * push a so it gets executed. + */ + if (LF_ISSET(TXT_INFOLINE)) { + if (vs_change(sp, tp->lno, LINE_RESET)) + goto err; + } else if (F_ISSET(sp, SC_SCRIPT)) + (void)v_event_push(sp, NULL, L("\r"), 1, CH_NOMAP); + + /* Set term condition: if empty. */ + if (tp->cno <= tp->offset) + tp->term = TERM_CR; + /* + * Set term condition: if searching incrementally and + * the user entered a pattern, return a completed + * search, regardless if the entire pattern was found. + */ + if (FL_ISSET(is_flags, IS_RUNNING) && + tp->cno >= tp->offset + 1) + tp->term = TERM_SEARCH; + + goto k_escape; + } + +#define LINE_RESOLVE do { \ + /* \ + * Handle abbreviations. If there was one, discard the \ + * replay characters. \ + */ \ + if (abb == AB_INWORD && \ + !LF_ISSET(TXT_REPLAY) && F_ISSET(gp, G_ABBREV)) { \ + if (txt_abbrev(sp, tp, &evp->e_c, \ + LF_ISSET(TXT_INFOLINE), &tmp, \ + &ab_turnoff)) \ + goto err; \ + if (tmp) { \ + if (LF_ISSET(TXT_RECORD)) \ + rcol -= tmp + 1; \ + goto resolve; \ + } \ + } \ + if (abb != AB_NOTSET) \ + abb = AB_NOTWORD; \ + if (UNMAP_TST) \ + txt_unmap(sp, tp, &ec_flags); \ + /* \ + * Delete any appended cursor. It's possible to get in \ + * situations where TXT_APPENDEOL is set but tp->insert \ + * is 0 when using the R command and all the characters \ + * are tp->owrite characters. \ + */ \ + if (LF_ISSET(TXT_APPENDEOL) && tp->insert > 0) { \ + --tp->len; \ + --tp->insert; \ + } \ +} while (0) + LINE_RESOLVE; + + /* + * Save the current line information for restoration in + * txt_backup(), and set the line final length. + */ + tp->sv_len = tp->len; + tp->sv_cno = tp->cno; + tp->len = tp->cno; + + /* Update the old line. */ + if (vs_change(sp, tp->lno, LINE_RESET)) + goto err; + + /* + * Historic practice, when the autoindent edit option was set, + * was to delete characters following the inserted + * newline. This affected the 'R', 'c', and 's' commands; 'c' + * and 's' retained the insert characters only, 'R' moved the + * overwrite and insert characters into the next TEXT structure. + * We keep track of the number of characters erased for the 'R' + * command so that the final resolution of the line is correct. + */ + tp->R_erase = 0; + owrite = tp->owrite; + insert = tp->insert; + if (LF_ISSET(TXT_REPLACE) && owrite != 0) { + for (p = tp->lb + tp->cno; owrite > 0 && isblank(*p); + ++p, --owrite, ++tp->R_erase); + if (owrite == 0) + for (; insert > 0 && isblank(*p); + ++p, ++tp->R_erase, --insert); + } else { + p = tp->lb + tp->cno + owrite; + if (O_ISSET(sp, O_AUTOINDENT)) + for (; insert > 0 && + isblank(*p); ++p, --insert); + owrite = 0; + } + + /* + * !!! + * Create a new line and insert the new TEXT into the queue. + * DON'T insert until the old line has been updated, or the + * inserted line count in line.c:db_get() will be wrong. + */ + if ((ntp = text_init(sp, p, + insert + owrite, insert + owrite + 32)) == NULL) + goto err; + TAILQ_INSERT_TAIL(sp->tiq, ntp, q); + + /* Set up bookkeeping for the new line. */ + ntp->insert = insert; + ntp->owrite = owrite; + ntp->lno = tp->lno + 1; + + /* + * Reset the autoindent line value. 0^D keeps the autoindent + * line from changing, ^D changes the level, even if there were + * no characters in the old line. Note, if using the current + * tp structure, use the cursor as the length, the autoindent + * characters may have been erased. + */ + if (LF_ISSET(TXT_AUTOINDENT)) { + if (nochange) { + nochange = 0; + if (v_txt_auto(sp, OOBLNO, &ait, ait.ai, ntp)) + goto err; + FREE_SPACEW(sp, ait.lb, ait.lb_len); + } else + if (v_txt_auto(sp, OOBLNO, tp, tp->cno, ntp)) + goto err; + carat = C_NOTSET; + } + + /* Reset the cursor. */ + ntp->cno = ntp->ai; + + /* + * If we're here because wrapmargin was set and we've broken a + * line, there may be additional information (i.e. the start of + * a line) in the wmt structure. + */ + if (wm_set) { + if (wmt.offset != 0 || + wmt.owrite != 0 || wmt.insert != 0) { +#define WMTSPACE wmt.offset + wmt.owrite + wmt.insert + BINC_GOTOW(sp, ntp->lb, + ntp->lb_len, ntp->len + WMTSPACE + 32); + MEMMOVE(ntp->lb + ntp->cno, wmt.lb, WMTSPACE); + ntp->len += WMTSPACE; + ntp->cno += wmt.offset; + ntp->owrite = wmt.owrite; + ntp->insert = wmt.insert; + } + wm_set = 0; + } + + /* New lines are TXT_APPENDEOL. */ + if (ntp->owrite == 0 && ntp->insert == 0) { + BINC_GOTOW(sp, ntp->lb, ntp->lb_len, ntp->len + 1); + LF_SET(TXT_APPENDEOL); + ntp->lb[ntp->cno] = CH_CURSOR; + ++ntp->insert; + ++ntp->len; + } + + /* Swap old and new TEXT's, and update the new line. */ + tp = ntp; + if (vs_change(sp, tp->lno, LINE_INSERT)) + goto err; + + goto resolve; + case K_ESCAPE: /* Escape. */ + if (!LF_ISSET(TXT_ESCAPE)) + goto ins_ch; + + /* If we have a count, start replaying the input. */ + if (rcount > 1) { + --rcount; + + vip->rep_cnt = rcol; + rcol = 0; + abb = AB_NOTSET; + LF_CLR(TXT_RECORD); + LF_SET(TXT_REPLAY); + + /* + * Some commands (e.g. 'o') need a for each + * repetition. + */ + if (LF_ISSET(TXT_ADDNEWLINE)) + goto k_cr; + + /* + * The R command turns into the 'a' command after the + * first repetition. + */ + if (LF_ISSET(TXT_REPLACE)) { + tp->insert = tp->owrite; + tp->owrite = 0; + LF_CLR(TXT_REPLACE); + } + goto replay; + } + + /* Set term condition: if empty. */ + if (tp->cno <= tp->offset) + tp->term = TERM_ESC; + /* + * Set term condition: if searching incrementally and the user + * entered a pattern, return a completed search, regardless if + * the entire pattern was found. + */ + if (FL_ISSET(is_flags, IS_RUNNING) && tp->cno >= tp->offset + 1) + tp->term = TERM_SEARCH; + +k_escape: LINE_RESOLVE; + + /* + * Clean up for the 'R' command, restoring overwrite + * characters, and making them into insert characters. + */ + if (LF_ISSET(TXT_REPLACE)) + txt_Rresolve(sp, sp->tiq, tp, len); + + /* + * If there are any overwrite characters, copy down + * any insert characters, and decrement the length. + */ + if (tp->owrite) { + if (tp->insert) + MEMMOVE(tp->lb + tp->cno, + tp->lb + tp->cno + tp->owrite, tp->insert); + tp->len -= tp->owrite; + } + + /* + * Optionally resolve the lines into the file. If not + * resolving the lines into the file, end the line with + * a nul. If the line is empty, then set the length to + * 0, the termination condition has already been set. + * + * XXX + * This is wrong, should pass back a length. + */ + if (LF_ISSET(TXT_RESOLVE)) { + if (txt_resolve(sp, sp->tiq, flags)) + goto err; + } else { + BINC_GOTOW(sp, tp->lb, tp->lb_len, tp->len + 1); + tp->lb[tp->len] = '\0'; + } + + /* + * Set the return cursor position to rest on the last + * inserted character. + */ + if (tp->cno != 0) + --tp->cno; + + /* Update the last line. */ + if (vs_change(sp, tp->lno, LINE_RESET)) + return (1); + goto done; + case K_CARAT: /* Delete autoindent chars. */ + if (tp->cno <= tp->ai && LF_ISSET(TXT_AUTOINDENT)) + carat = C_CARATSET; + goto ins_ch; + case K_ZERO: /* Delete autoindent chars. */ + if (tp->cno <= tp->ai && LF_ISSET(TXT_AUTOINDENT)) + carat = C_ZEROSET; + goto ins_ch; + case K_CNTRLD: /* Delete autoindent char. */ + /* + * If in the first column or no characters to erase, ignore + * the ^D (this matches historic practice). If not doing + * autoindent or already inserted non-ai characters, it's a + * literal. The latter test is done in the switch, as the + * CARAT forms are N + 1, not N. + */ + if (!LF_ISSET(TXT_AUTOINDENT)) + goto ins_ch; + if (tp->cno == 0) + goto resolve; + + switch (carat) { + case C_CARATSET: /* ^^D */ + if (tp->ai == 0 || tp->cno > tp->ai + tp->offset + 1) + goto ins_ch; + + /* Save the ai string for later. */ + ait.lb = NULL; + ait.lb_len = 0; + BINC_GOTOW(sp, ait.lb, ait.lb_len, tp->ai); + MEMMOVE(ait.lb, tp->lb, tp->ai); + ait.ai = ait.len = tp->ai; + + carat = C_NOTSET; + nochange = 1; + goto leftmargin; + case C_ZEROSET: /* 0^D */ + if (tp->ai == 0 || tp->cno > tp->ai + tp->offset + 1) + goto ins_ch; + + carat = C_NOTSET; +leftmargin: tp->lb[tp->cno - 1] = ' '; + tp->owrite += tp->cno - tp->offset; + tp->ai = 0; + tp->cno = tp->offset; + break; + case C_NOTSET: /* ^D */ + if (tp->ai == 0 || tp->cno > tp->ai + tp->offset) + goto ins_ch; + + (void)txt_dent(sp, tp, O_SHIFTWIDTH, 0); + break; + default: + abort(); + } + break; + case K_VERASE: /* Erase the last character. */ + /* If can erase over the prompt, return. */ + if (tp->cno <= tp->offset && LF_ISSET(TXT_BS)) { + tp->term = TERM_BS; + goto done; + } + + /* + * If at the beginning of the line, try and drop back to a + * previously inserted line. + */ + if (tp->cno == 0) { + if ((ntp = + txt_backup(sp, sp->tiq, tp, &flags)) == NULL) + goto err; + tp = ntp; + break; + } + + /* If nothing to erase, bell the user. */ + if (tp->cno <= tp->offset) { + if (!LF_ISSET(TXT_REPLAY)) + txt_nomorech(sp); + break; + } + + /* Drop back one character. */ + --tp->cno; + + /* + * Historically, vi didn't replace the erased characters with + * s, presumably because it's easier to fix a minor + * typing mistake and continue on if the previous letters are + * already there. This is a problem for incremental searching, + * because the user can no longer tell where they are in the + * colon command line because the cursor is at the last search + * point in the screen. So, if incrementally searching, erase + * the erased characters from the screen. + */ + if (FL_ISSET(is_flags, IS_RUNNING)) + tp->lb[tp->cno] = ' '; + + /* + * Increment overwrite, decrement ai if deleted. + * + * !!! + * Historic vi did not permit users to use erase characters + * to delete autoindent characters. We do. Eat hot death, + * POSIX. + */ + ++tp->owrite; + if (tp->cno < tp->ai) + --tp->ai; + + /* Reset if we deleted an incremental search character. */ + if (FL_ISSET(is_flags, IS_RUNNING)) + FL_SET(is_flags, IS_RESTART); + break; + case K_VWERASE: /* Skip back one word. */ + /* + * If at the beginning of the line, try and drop back to a + * previously inserted line. + */ + if (tp->cno == 0) { + if ((ntp = + txt_backup(sp, sp->tiq, tp, &flags)) == NULL) + goto err; + tp = ntp; + } + + /* + * If at offset, nothing to erase so bell the user. + */ + if (tp->cno <= tp->offset) { + if (!LF_ISSET(TXT_REPLAY)) + txt_nomorech(sp); + break; + } + + /* + * The first werase goes back to any autoindent column and the + * second werase goes back to the offset. + * + * !!! + * Historic vi did not permit users to use erase characters to + * delete autoindent characters. + */ + if (tp->ai && tp->cno > tp->ai) + max = tp->ai; + else { + tp->ai = 0; + max = tp->offset; + } + + /* Skip over trailing space characters. */ + while (tp->cno > max && ISBLANK(tp->lb[tp->cno - 1])) { + --tp->cno; + ++tp->owrite; + } + if (tp->cno == max) + break; + /* + * There are three types of word erase found on UNIX systems. + * They can be identified by how the string /a/b/c is treated + * -- as 1, 3, or 6 words. Historic vi had two classes of + * characters, and strings were delimited by them and + * 's, so, 6 words. The historic tty interface used + * 's to delimit strings, so, 1 word. The algorithm + * offered in the 4.4BSD tty interface (as stty altwerase) + * treats it as 3 words -- there are two classes of + * characters, and strings are delimited by them and + * 's. The difference is that the type of the first + * erased character erased is ignored, which is exactly right + * when erasing pathname components. The edit options + * TXT_ALTWERASE and TXT_TTYWERASE specify the 4.4BSD tty + * interface and the historic tty driver behavior, + * respectively, and the default is the same as the historic + * vi behavior. + * + * Overwrite erased characters if doing incremental search; + * see comment above. + */ + if (LF_ISSET(TXT_TTYWERASE)) + while (tp->cno > max) { + if (ISBLANK(tp->lb[tp->cno - 1])) + break; + --tp->cno; + ++tp->owrite; + if (FL_ISSET(is_flags, IS_RUNNING)) + tp->lb[tp->cno] = ' '; + } + else { + if (LF_ISSET(TXT_ALTWERASE)) { + --tp->cno; + ++tp->owrite; + if (FL_ISSET(is_flags, IS_RUNNING)) + tp->lb[tp->cno] = ' '; + } + if (tp->cno > max) + tmp = inword(tp->lb[tp->cno - 1]); + while (tp->cno > max) { + if (tmp != inword(tp->lb[tp->cno - 1]) + || ISBLANK(tp->lb[tp->cno - 1])) + break; + --tp->cno; + ++tp->owrite; + if (FL_ISSET(is_flags, IS_RUNNING)) + tp->lb[tp->cno] = ' '; + } + } + + /* Reset if we deleted an incremental search character. */ + if (FL_ISSET(is_flags, IS_RUNNING)) + FL_SET(is_flags, IS_RESTART); + break; + case K_VKILL: /* Restart this line. */ + /* + * !!! + * If at the beginning of the line, try and drop back to a + * previously inserted line. Historic vi did not permit + * users to go back to previous lines. + */ + if (tp->cno == 0) { + if ((ntp = + txt_backup(sp, sp->tiq, tp, &flags)) == NULL) + goto err; + tp = ntp; + } + + /* If at offset, nothing to erase so bell the user. */ + if (tp->cno <= tp->offset) { + if (!LF_ISSET(TXT_REPLAY)) + txt_nomorech(sp); + break; + } + + /* + * First kill goes back to any autoindent and second kill goes + * back to the offset. + * + * !!! + * Historic vi did not permit users to use erase characters to + * delete autoindent characters. + */ + if (tp->ai && tp->cno > tp->ai) + max = tp->ai; + else { + tp->ai = 0; + max = tp->offset; + } + tp->owrite += tp->cno - max; + + /* + * Overwrite erased characters if doing incremental search; + * see comment above. + */ + if (FL_ISSET(is_flags, IS_RUNNING)) + do { + tp->lb[--tp->cno] = ' '; + } while (tp->cno > max); + else + tp->cno = max; + + /* Reset if we deleted an incremental search character. */ + if (FL_ISSET(is_flags, IS_RUNNING)) + FL_SET(is_flags, IS_RESTART); + break; + case K_CNTRLT: /* Add autoindent characters. */ + if (!LF_ISSET(TXT_CNTRLT)) + goto ins_ch; + if (txt_dent(sp, tp, O_SHIFTWIDTH, 1)) + goto err; + goto ebuf_chk; + case K_VLNEXT: /* Quote next character. */ + evp->e_c = '^'; + quote = Q_VNEXT; + /* + * Turn on the quote flag so that the underlying routines + * quote the next character where it's possible. Turn off + * the input mapbiting flag so that we don't remap the next + * character. + */ + FL_SET(ec_flags, EC_QUOTED); + FL_CLR(ec_flags, EC_MAPINPUT); + + /* + * !!! + * Skip the tests for abbreviations, so ":ab xa XA", + * "ixa^V" doesn't perform the abbreviation. + */ + goto insl_ch; + case K_HEXCHAR: + hexcnt = 1; + goto insq_ch; + case K_TAB: + if (sp->showmode != SM_COMMAND && quote != Q_VTHIS && + O_ISSET(sp, O_EXPANDTAB)) { + if (txt_dent(sp, tp, O_TABSTOP, 1)) + goto err; + goto ebuf_chk; + } + goto insq_ch; + default: /* Insert the character. */ + if (LF_ISSET(TXT_SHOWMATCH)) { + CHAR_T *match_chars, *cp; + + match_chars = VIP(sp)->mcs; + cp = STRCHR(match_chars, evp->e_c); + if (cp != NULL && (cp - match_chars) & 1) + showmatch = 1; + } +ins_ch: /* + * Historically, vi eliminated nul's out of hand. If the + * beautify option was set, it also deleted any unknown + * ASCII value less than space (040) and the del character + * (0177), except for tabs. Unknown is a key word here. + * Most vi documentation claims that it deleted everything + * but , and , as that's what the original + * 4BSD documentation said. This is obviously wrong, + * however, as would be included in that list. What + * we do is eliminate any unquoted, iscntrl() character that + * wasn't a replay and wasn't handled specially, except + * or . + */ + if (LF_ISSET(TXT_BEAUTIFY) && ISCNTRL(evp->e_c) && + evp->e_value != K_FORMFEED && evp->e_value != K_TAB) { + msgq(sp, M_BERR, + "192|Illegal character; quote to enter"); + if (LF_ISSET(TXT_REPLAY)) + goto done; + break; + } + +insq_ch: /* + * If entering a non-word character after a word, check for + * abbreviations. If there was one, discard replay characters. + * If entering a blank character, check for unmap commands, + * as well. + */ + if (!inword(evp->e_c)) { + if (abb == AB_INWORD && + !LF_ISSET(TXT_REPLAY) && F_ISSET(gp, G_ABBREV)) { + if (txt_abbrev(sp, tp, &evp->e_c, + LF_ISSET(TXT_INFOLINE), &tmp, &ab_turnoff)) + goto err; + if (tmp) { + if (LF_ISSET(TXT_RECORD)) + rcol -= tmp + 1; + goto resolve; + } + } + if (isblank(evp->e_c) && UNMAP_TST) + txt_unmap(sp, tp, &ec_flags); + } + if (abb != AB_NOTSET) + abb = inword(evp->e_c) ? AB_INWORD : AB_NOTWORD; + +insl_ch: if (txt_insch(sp, tp, &evp->e_c, flags)) + goto err; + + /* + * If we're using K_VLNEXT to quote the next character, then + * we want the cursor to position itself on the ^ placeholder + * we're displaying, to match historic practice. + */ + if (quote == Q_VNEXT) { + --tp->cno; + ++tp->owrite; + } + + /* + * !!! + * Translate "[isxdigit()]*" to a character with + * a hex value: this test delimits the value by the max + * number of hex bytes. Offset by one, we use 0 to mean + * that we've found . + */ + if (hexcnt != 0 && hexcnt++ == 3) { + hexcnt = 0; + if (txt_hex(sp, tp)) + goto err; + } + + /* + * Check to see if we've crossed the margin. + * + * !!! + * In the historic vi, the wrapmargin value was figured out + * using the display widths of the characters, i.e. + * characters were counted as two characters if the list edit + * option is set, but as the tabstop edit option number of + * characters otherwise. That's what the vs_column() function + * gives us, so we use it. + */ + if (margin != 0) { + if (vs_column(sp, &tcol)) + goto err; + if (tcol >= margin) { + if (txt_margin(sp, tp, &wmt, &tmp, flags)) + goto err; + if (tmp) { + if (isblank(evp->e_c)) + wm_skip = 1; + wm_set = 1; + goto k_cr; + } + } + } + + /* + * If we've reached the end of the buffer, then we need to + * switch into insert mode. This happens when there's a + * change to a mark and the user puts in more characters than + * the length of the motion. + */ +ebuf_chk: if (tp->cno >= tp->len) { + BINC_GOTOW(sp, tp->lb, tp->lb_len, tp->len + 1); + LF_SET(TXT_APPENDEOL); + + tp->lb[tp->cno] = CH_CURSOR; + ++tp->insert; + ++tp->len; + } + + /* Step the quote state forward. */ + if (quote == Q_VNEXT) + quote = Q_VTHIS; + break; + } + +#ifdef DEBUG + if (tp->cno + tp->insert + tp->owrite != tp->len) { + msgq(sp, M_ERR, + "len %zu != cno: %zu ai: %zu insert %zu overwrite %zu", + tp->len, tp->cno, tp->ai, tp->insert, tp->owrite); + if (LF_ISSET(TXT_REPLAY)) + goto done; + tp->len = tp->cno + tp->insert + tp->owrite; + } +#endif + +resolve:/* + * 1: If we don't need to know where the cursor really is and we're + * replaying text, keep going. + */ + if (margin == 0 && LF_ISSET(TXT_REPLAY)) + goto replay; + + /* + * 2: Reset the line. Don't bother unless we're about to wait on + * a character or we need to know where the cursor really is. + * We have to do this before showing matching characters so the + * user can see what they're matching. + */ + if ((margin != 0 || !KEYS_WAITING(sp)) && + vs_change(sp, tp->lno, LINE_RESET)) + return (1); + + /* + * 3: If there aren't keys waiting, display the matching character. + * We have to do this before resolving any messages, otherwise + * the error message from a missing match won't appear correctly. + */ + if (showmatch) { + if (!KEYS_WAITING(sp) && txt_showmatch(sp, tp)) + return (1); + showmatch = 0; + } + + /* + * 4: If there have been messages and we're not editing on the colon + * command line or doing file name completion, resolve them. + */ + if ((vip->totalcount != 0 || F_ISSET(gp, G_BELLSCHED)) && + !F_ISSET(sp, SC_TINPUT_INFO) && !filec_redraw && + vs_resolve(sp, NULL, 0)) + return (1); + + /* + * 5: Refresh the screen if we're about to wait on a character or we + * need to know where the cursor really is. + */ + if (margin != 0 || !KEYS_WAITING(sp)) { + UPDATE_POSITION(sp, tp); + if (vs_refresh(sp, margin != 0)) + return (1); + } + + /* 6: Proceed with the incremental search. */ + if (FL_ISSET(is_flags, IS_RUNNING) && txt_isrch(sp, vp, tp, &is_flags)) + return (1); + + /* 7: Next character... */ + if (LF_ISSET(TXT_REPLAY)) + goto replay; + goto next; + +done: /* Leave input mode. */ + F_CLR(sp, SC_TINPUT); + + /* If recording for playback, save it. */ + if (LF_ISSET(TXT_RECORD)) + vip->rep_cnt = rcol; + + /* + * If not working on the colon command line, set the final cursor + * position. + */ + if (!F_ISSET(sp, SC_TINPUT_INFO)) { + vp->m_final.lno = tp->lno; + vp->m_final.cno = tp->cno; + } + return (0); + +err: +alloc_err: + F_CLR(sp, SC_TINPUT); + txt_err(sp, sp->tiq); + return (1); +} + +/* + * txt_abbrev -- + * Handle abbreviations. + */ +static int +txt_abbrev(SCR *sp, TEXT *tp, CHAR_T *pushcp, int isinfoline, int *didsubp, int *turnoffp) +{ + VI_PRIVATE *vip; + CHAR_T ch, *p; + SEQ *qp; + size_t len, off; + + /* Check to make sure we're not at the start of an append. */ + *didsubp = 0; + if (tp->cno == tp->offset) + return (0); + + vip = VIP(sp); + + /* + * Find the start of the "word". + * + * !!! + * We match historic practice, which, as far as I can tell, had an + * off-by-one error. The way this worked was that when the inserted + * text switched from a "word" character to a non-word character, + * vi would check for possible abbreviations. It would then take the + * type (i.e. word/non-word) of the character entered TWO characters + * ago, and move backward in the text until reaching a character that + * was not that type, or the beginning of the insert, the line, or + * the file. For example, in the string "abc", when the + * character triggered the abbreviation check, the type of the 'b' + * character was used for moving through the string. Maybe there's a + * reason for not using the first (i.e. 'c') character, but I can't + * think of one. + * + * Terminate at the beginning of the insert or the character after the + * offset character -- both can be tested for using tp->offset. + */ + off = tp->cno - 1; /* Previous character. */ + p = tp->lb + off; + len = 1; /* One character test. */ + if (off == tp->offset || isblank(p[-1])) + goto search; + if (inword(p[-1])) /* Move backward to change. */ + for (;;) { + --off; --p; ++len; + if (off == tp->offset || !inword(p[-1])) + break; + } + else + for (;;) { + --off; --p; ++len; + if (off == tp->offset || + inword(p[-1]) || isblank(p[-1])) + break; + } + + /* + * !!! + * Historic vi exploded abbreviations on the command line. This has + * obvious problems in that unabbreviating the string can be extremely + * tricky, particularly if the string has, say, an embedded escape + * character. Personally, I think it's a stunningly bad idea. Other + * examples of problems this caused in historic vi are: + * :ab foo bar + * :ab foo baz + * results in "bar" being abbreviated to "baz", which wasn't what the + * user had in mind at all. Also, the commands: + * :ab foo bar + * :unab foo + * resulted in an error message that "bar" wasn't mapped. Finally, + * since the string was already exploded by the time the unabbreviate + * command got it, all it knew was that an abbreviation had occurred. + * Cleverly, it checked the replacement string for its unabbreviation + * match, which meant that the commands: + * :ab foo1 bar + * :ab foo2 bar + * :unab foo2 + * unabbreviate "foo1", and the commands: + * :ab foo bar + * :ab bar baz + * unabbreviate "foo"! + * + * Anyway, people neglected to first ask my opinion before they wrote + * macros that depend on this stuff, so, we make this work as follows. + * When checking for an abbreviation on the command line, if we get a + * string which is terminated and which starts at the beginning + * of the line, we check to see it is the abbreviate or unabbreviate + * commands. If it is, turn abbreviations off and return as if no + * abbreviation was found. Note also, minor trickiness, so that if + * the user erases the line and starts another command, we turn the + * abbreviations back on. + * + * This makes the layering look like a Nachos Supreme. + */ +search: if (isinfoline) { + if (off == tp->ai || off == tp->offset) + if (ex_is_abbrev(p, len)) { + *turnoffp = 1; + return (0); + } else + *turnoffp = 0; + else + if (*turnoffp) + return (0); + } + + /* Check for any abbreviations. */ + if ((qp = seq_find(sp, NULL, NULL, p, len, SEQ_ABBREV, NULL)) == NULL) + return (0); + + /* + * Push the abbreviation onto the tty stack. Historically, characters + * resulting from an abbreviation expansion were themselves subject to + * map expansions, O_SHOWMATCH matching etc. This means the expanded + * characters will be re-tested for abbreviations. It's difficult to + * know what historic practice in this case was, since abbreviations + * were applied to :colon command lines, so entering abbreviations that + * looped was tricky, although possible. In addition, obvious loops + * didn't work as expected. (The command ':ab a b|ab b c|ab c a' will + * silently only implement and/or display the last abbreviation.) + * + * This implementation doesn't recover well from such abbreviations. + * The main input loop counts abbreviated characters, and, when it + * reaches a limit, discards any abbreviated characters on the queue. + * It's difficult to back up to the original position, as the replay + * queue would have to be adjusted, and the line state when an initial + * abbreviated character was received would have to be saved. + */ + ch = *pushcp; + if (v_event_push(sp, NULL, &ch, 1, CH_ABBREVIATED)) + return (1); + if (v_event_push(sp, NULL, qp->output, qp->olen, CH_ABBREVIATED)) + return (1); + + /* + * If the size of the abbreviation is larger than or equal to the size + * of the original text, move to the start of the replaced characters, + * and add their length to the overwrite count. + * + * If the abbreviation is smaller than the original text, we have to + * delete the additional overwrite characters and copy down any insert + * characters. + */ + tp->cno -= len; + if (qp->olen >= len) + tp->owrite += len; + else { + if (tp->insert) + MEMMOVE(tp->lb + tp->cno + qp->olen, + tp->lb + tp->cno + tp->owrite + len, tp->insert); + tp->owrite += qp->olen; + tp->len -= len - qp->olen; + } + + /* + * We return the length of the abbreviated characters. This is so + * the calling routine can replace the replay characters with the + * abbreviation. This means that subsequent '.' commands will produce + * the same text, regardless of intervening :[un]abbreviate commands. + * This is historic practice. + */ + *didsubp = len; + return (0); +} + +/* + * txt_unmap -- + * Handle the unmap command. + */ +static void +txt_unmap(SCR *sp, TEXT *tp, u_int32_t *ec_flagsp) +{ + size_t len, off; + CHAR_T *p; + + /* Find the beginning of this "word". */ + for (off = tp->cno - 1, p = tp->lb + off, len = 0;; --p, --off) { + if (isblank(*p)) { + ++p; + break; + } + ++len; + if (off == tp->ai || off == tp->offset) + break; + } + + /* + * !!! + * Historic vi exploded input mappings on the command line. See the + * txt_abbrev() routine for an explanation of the problems inherent + * in this. + * + * We make this work as follows. If we get a string which is + * terminated and which starts at the beginning of the line, we check + * to see it is the unmap command. If it is, we return that the input + * mapping should be turned off. Note also, minor trickiness, so that + * if the user erases the line and starts another command, we go ahead + * an turn mapping back on. + */ + if ((off == tp->ai || off == tp->offset) && ex_is_unmap(p, len)) + FL_CLR(*ec_flagsp, EC_MAPINPUT); + else + FL_SET(*ec_flagsp, EC_MAPINPUT); +} + +/* + * txt_ai_resolve -- + * When a line is resolved by , review autoindent characters. + */ +static void +txt_ai_resolve(SCR *sp, TEXT *tp, int *changedp) +{ + u_long ts; + int del; + size_t cno, len, new, old, scno, spaces, tab_after_sp, tabs; + CHAR_T *p; + + *changedp = 0; + + /* + * If the line is empty, has an offset, or no autoindent + * characters, we're done. + */ + if (!tp->len || tp->offset || !tp->ai) + return; + + /* + * If the length is less than or equal to the autoindent + * characters, delete them. + */ + if (tp->len <= tp->ai) { + tp->ai = tp->cno = tp->len = 0; + return; + } + + /* + * The autoindent characters plus any leading characters + * in the line are resolved into the minimum number of characters. + * Historic practice. + */ + ts = O_VAL(sp, O_TABSTOP); + + /* Figure out the last screen column. */ + for (p = tp->lb, scno = 0, len = tp->len, + spaces = tab_after_sp = 0; len-- && isblank(*p); ++p) + if (*p == '\t') { + if (spaces) + tab_after_sp = 1; + scno += COL_OFF(scno, ts); + } else { + ++spaces; + ++scno; + } + + /* + * If there are no spaces, or no tabs after spaces and less than + * ts spaces, it's already minimal. + * Keep analysing if expandtab is set. + */ + if ((!spaces || (!tab_after_sp && spaces < ts)) && + !O_ISSET(sp, O_EXPANDTAB)) + return; + + /* Count up spaces/tabs needed to get to the target. */ + cno = 0; + tabs = 0; + if (!O_ISSET(sp, O_EXPANDTAB)) { + for (; cno + COL_OFF(cno, ts) <= scno; ++tabs) + cno += COL_OFF(cno, ts); + } + spaces = scno - cno; + + /* + * Figure out how many characters we're dropping -- if we're not + * dropping any, it's already minimal, we're done. + */ + old = p - tp->lb; + new = spaces + tabs; + if (old == new) + return; + + /* Shift the rest of the characters down, adjust the counts. */ + del = old - new; + MEMMOVE(p - del, p, tp->len - old); + tp->len -= del; + tp->cno -= del; + + /* Fill in space/tab characters. */ + for (p = tp->lb; tabs--;) + *p++ = '\t'; + while (spaces--) + *p++ = ' '; + *changedp = 1; +} + +/* + * v_txt_auto -- + * Handle autoindent. If aitp isn't NULL, use it, otherwise, + * retrieve the line. + * + * PUBLIC: int v_txt_auto(SCR *, recno_t, TEXT *, size_t, TEXT *); + */ +int +v_txt_auto(SCR *sp, recno_t lno, TEXT *aitp, size_t len, TEXT *tp) +{ + size_t nlen; + CHAR_T *p, *t; + + if (aitp == NULL) { + /* + * If the ex append command is executed with an address of 0, + * it's possible to get here with a line number of 0. Return + * an indent of 0. + */ + if (lno == 0) { + tp->ai = 0; + return (0); + } + if (db_get(sp, lno, DBG_FATAL, &t, &len)) + return (1); + } else + t = aitp->lb; + + /* Count whitespace characters. */ + for (p = t; len > 0; ++p, --len) + if (!isblank(*p)) + break; + + /* Set count, check for no indentation. */ + if ((nlen = (p - t)) == 0) + return (0); + + /* Make sure the buffer's big enough. */ + BINC_RETW(sp, tp->lb, tp->lb_len, tp->len + nlen); + + /* Copy the buffer's current contents up. */ + if (tp->len != 0) + MEMMOVE(tp->lb + nlen, tp->lb, tp->len); + tp->len += nlen; + + /* Copy the indentation into the new buffer. */ + MEMMOVE(tp->lb, t, nlen); + + /* Set the autoindent count. */ + tp->ai = nlen; + return (0); +} + +/* + * txt_backup -- + * Back up to the previously edited line. + */ +static TEXT * +txt_backup(SCR *sp, TEXTH *tiqh, TEXT *tp, u_int32_t *flagsp) +{ + VI_PRIVATE *vip; + TEXT *ntp; + + /* Get a handle on the previous TEXT structure. */ + if ((ntp = TAILQ_PREV(tp, _texth, q)) == NULL) { + if (!FL_ISSET(*flagsp, TXT_REPLAY)) + msgq(sp, M_BERR, + "193|Already at the beginning of the insert"); + return (tp); + } + + /* Bookkeeping. */ + ntp->len = ntp->sv_len; + + /* Handle appending to the line. */ + vip = VIP(sp); + if (ntp->owrite == 0 && ntp->insert == 0) { + ntp->lb[ntp->len] = CH_CURSOR; + ++ntp->insert; + ++ntp->len; + FL_SET(*flagsp, TXT_APPENDEOL); + } else + FL_CLR(*flagsp, TXT_APPENDEOL); + + /* Release the current TEXT. */ + TAILQ_REMOVE(tiqh, tp, q); + text_free(tp); + + /* Update the old line on the screen. */ + if (vs_change(sp, ntp->lno + 1, LINE_DELETE)) + return (NULL); + + /* Return the new/current TEXT. */ + return (ntp); +} + +/* + * Text indentation is truly strange. ^T and ^D do movements to the next or + * previous shiftwidth value, i.e. for a 1-based numbering, with shiftwidth=3, + * ^T moves a cursor on the 7th, 8th or 9th column to the 10th column, and ^D + * moves it back. + * + * !!! + * The ^T and ^D characters in historical vi had special meaning only when they + * were the first characters entered after entering text input mode. As normal + * erase characters couldn't erase autoindent characters (^T in this case), it + * meant that inserting text into previously existing text was strange -- ^T + * only worked if it was the first keystroke(s), and then could only be erased + * using ^D. This implementation treats ^T specially anywhere it occurs in the + * input, and permits the standard erase characters to erase the characters it + * inserts. + * + * !!! + * A fun test is to try: + * :se sw=4 ai list + * i^Tx^Tx^Tx^Dx^Dx^Dx + * Historic vi loses some of the '$' marks on the line ends, but otherwise gets + * it right. + * + * XXX + * Technically, txt_dent should be part of the screen interface, as it requires + * knowledge of character sizes, including s, on the screen. It's here + * because it's a complicated little beast, and I didn't want to shove it down + * into the screen. It's probable that KEY_COL will call into the screen once + * there are screens with different character representations. + * + * txt_dent -- + * Handle ^T indents, ^D outdents. + * + * If anything changes here, check the ex version to see if it needs similar + * changes. + */ +static int +txt_dent(SCR *sp, TEXT *tp, int swopt, int isindent) +{ + CHAR_T ch; + u_long sw, ts; + size_t cno, current, spaces, target, tabs; + int ai_reset; + + ts = O_VAL(sp, O_TABSTOP); + sw = O_VAL(sp, swopt); + + /* + * Since we don't know what precedes the character(s) being inserted + * (or deleted), the preceding whitespace characters must be resolved. + * An example is a , which doesn't need a full shiftwidth number + * of columns because it's preceded by s. This is easy to get + * if the user sets shiftwidth to a value less than tabstop (or worse, + * something for which tabstop isn't a multiple) and then uses ^T to + * indent, and ^D to outdent. + * + * Figure out the current and target screen columns. In the historic + * vi, the autoindent column was NOT determined using display widths + * of characters as was the wrapmargin column. For that reason, we + * can't use the vs_column() function, but have to calculate it here. + * This is slow, but it's normally only on the first few characters of + * a line. + */ + for (current = cno = 0; cno < tp->cno; ++cno) + current += tp->lb[cno] == '\t' ? + COL_OFF(current, ts) : KEY_COL(sp, tp->lb[cno]); + + target = current; + if (isindent) + target += COL_OFF(target, sw); + else { + --target; + target -= target % sw; + } + + /* + * The AI characters will be turned into overwrite characters if the + * cursor immediately follows them. We test both the cursor position + * and the indent flag because there's no single test. (^T can only + * be detected by the cursor position, and while we know that the test + * is always true for ^D, the cursor can be in more than one place, as + * "0^D" and "^D" are different.) + */ + ai_reset = !isindent || tp->cno == tp->ai + tp->offset; + + /* + * Back up over any previous characters, changing them into + * overwrite characters (including any ai characters). Then figure + * out the current screen column. + */ + for (; tp->cno > tp->offset && + (tp->lb[tp->cno - 1] == ' ' || tp->lb[tp->cno - 1] == '\t'); + --tp->cno, ++tp->owrite); + for (current = cno = 0; cno < tp->cno; ++cno) + current += tp->lb[cno] == '\t' ? + COL_OFF(current, ts) : KEY_COL(sp, tp->lb[cno]); + + /* + * If we didn't move up to or past the target, it's because there + * weren't enough characters to delete, e.g. the first character + * of the line was a tp->offset character, and the user entered + * ^D to move to the beginning of a line. An example of this is: + * + * :set ai sw=4iai^T^D + * + * Otherwise, count up the total spaces/tabs needed to get from the + * beginning of the line (or the last non- character) to the + * target. + */ + if (current >= target) + spaces = tabs = 0; + else { + cno = current; + tabs = 0; + if (!O_ISSET(sp, O_EXPANDTAB)) { + for (; cno + COL_OFF(cno, ts) <= target; ++tabs) + cno += COL_OFF(cno, ts); + } + spaces = target - cno; + } + + /* If we overwrote ai characters, reset the ai count. */ + if (ai_reset) + tp->ai = tabs + spaces; + + /* + * Call txt_insch() to insert each character, so that we get the + * correct effect when we add a to replace N . + */ + for (ch = '\t'; tabs > 0; --tabs) + (void)txt_insch(sp, tp, &ch, 0); + for (ch = ' '; spaces > 0; --spaces) + (void)txt_insch(sp, tp, &ch, 0); + return (0); +} + +/* + * txt_fc -- + * File name and ex command completion. + */ +static int +txt_fc(SCR *sp, TEXT *tp, int *redrawp) +{ + struct stat sb; + ARGS **argv; + EXCMD cmd; + size_t indx, len, nlen, off; + int argc; + CHAR_T *p, *t, *bp; + char *np, *epd = NULL; + size_t nplen; + int fstwd = 1; + + *redrawp = 0; + ex_cinit(sp, &cmd, 0, 0, OOBLNO, OOBLNO, 0); + + /* + * Find the beginning of this "word" -- if we're at the beginning + * of the line, it's a special case. + */ + if (tp->cno == 1) { + len = 0; + p = tp->lb; + } else { + CHAR_T *ap; + + for (len = 0, + off = MAX(tp->ai, tp->offset), ap = tp->lb + off, p = ap; + off < tp->cno; ++off, ++ap) { + if (IS_ESCAPE(sp, &cmd, *ap)) { + if (++off == tp->cno) + break; + ++ap; + len += 2; + } else if (cmdskip(*ap)) { + p = ap + 1; + if (len > 0) + fstwd = 0; + len = 0; + } else + ++len; + } + } + + /* + * If we are at the first word, do ex command completion instead of + * file name completion. + */ + if (fstwd) + (void)argv_flt_ex(sp, &cmd, p, len); + else { + if ((bp = argv_uesc(sp, &cmd, p, len)) == NULL) + return (1); + if (argv_flt_path(sp, &cmd, bp, STRLEN(bp))) { + FREE_SPACEW(sp, bp, 0); + return (0); + } + FREE_SPACEW(sp, bp, 0); + } + argc = cmd.argc; + argv = cmd.argv; + + switch (argc) { + case 0: /* No matches. */ + (void)sp->gp->scr_bell(sp); + return (0); + case 1: /* One match. */ + /* Always overwrite the old text. */ + nlen = STRLEN(cmd.argv[0]->bp); + break; + default: /* Multiple matches. */ + *redrawp = 1; + if (txt_fc_col(sp, argc, argv)) + return (1); + + /* Find the length of the shortest match. */ + for (nlen = cmd.argv[0]->len; --argc > 0;) { + if (cmd.argv[argc]->len < nlen) + nlen = cmd.argv[argc]->len; + for (indx = 0; indx < nlen && + cmd.argv[argc]->bp[indx] == cmd.argv[0]->bp[indx]; + ++indx); + nlen = indx; + } + break; + } + + /* Escape the matched part of the path. */ + if (fstwd) + bp = cmd.argv[0]->bp; + else { + if ((bp = argv_esc(sp, &cmd, cmd.argv[0]->bp, nlen)) == NULL) + return (1); + nlen = STRLEN(bp); + } + + /* Overwrite the expanded text first. */ + for (t = bp; len > 0 && nlen > 0; --len, --nlen) + *p++ = *t++; + + /* If lost text, make the remaining old text overwrite characters. */ + if (len) { + tp->cno -= len; + tp->owrite += len; + } + + /* Overwrite any overwrite characters next. */ + for (; nlen > 0 && tp->owrite > 0; --nlen, --tp->owrite, ++tp->cno) + *p++ = *t++; + + /* Shift remaining text up, and move the cursor to the end. */ + if (nlen) { + off = p - tp->lb; + BINC_RETW(sp, tp->lb, tp->lb_len, tp->len + nlen); + p = tp->lb + off; + + tp->cno += nlen; + tp->len += nlen; + + if (tp->insert != 0) + (void)MEMMOVE(p + nlen, p, tp->insert); + while (nlen--) + *p++ = *t++; + } + + if (!fstwd) + FREE_SPACEW(sp, bp, 0); + + /* If not a single match of path, we've done. */ + if (argc != 1 || fstwd) + return (0); + + /* If a single match and it's a directory, append a '/'. */ + INT2CHAR(sp, cmd.argv[0]->bp, cmd.argv[0]->len + 1, np, nplen); + if ((epd = expanduser(np)) != NULL) + np = epd; + if (!stat(np, &sb) && S_ISDIR(sb.st_mode)) { + if (tp->owrite == 0) { + off = p - tp->lb; + BINC_RETW(sp, tp->lb, tp->lb_len, tp->len + 1); + p = tp->lb + off; + if (tp->insert != 0) + (void)MEMMOVE(p + 1, p, tp->insert); + ++tp->len; + } else + --tp->owrite; + + ++tp->cno; + *p++ = '/'; + } + free(epd); + return (0); +} + +/* + * txt_fc_col -- + * Display file names for file name completion. + */ +static int +txt_fc_col(SCR *sp, int argc, ARGS **argv) +{ + ARGS **av; + CHAR_T *p; + GS *gp; + size_t base, cnt, col, colwidth, numrows, numcols, prefix, row; + int ac, nf, reset; + char *np, *pp; + size_t nlen; + + gp = sp->gp; + + /* Trim any directory prefix common to all of the files. */ + INT2CHAR(sp, argv[0]->bp, argv[0]->len + 1, np, nlen); + if ((pp = strrchr(np, '/')) == NULL) + prefix = 0; + else { + prefix = (pp - np) + 1; + for (ac = argc - 1, av = argv + 1; ac > 0; --ac, ++av) + if (av[0]->len < prefix || + MEMCMP(av[0]->bp, argv[0]->bp, + prefix)) { + prefix = 0; + break; + } + } + + /* + * Figure out the column width for the longest name. Output is done on + * 6 character "tab" boundaries for no particular reason. (Since we + * don't output tab characters, we ignore the terminal's tab settings.) + * Ignore the user's tab setting because we have no idea how reasonable + * it is. + */ + for (ac = argc, av = argv, colwidth = 0; ac > 0; --ac, ++av) { + for (col = 0, p = av[0]->bp + prefix; *p != '\0'; ++p) + col += KEY_COL(sp, *p); + if (col > colwidth) + colwidth = col; + } + colwidth += COL_OFF(colwidth, 6); + + /* + * Writing to the bottom line of the screen is always turned off when + * SC_TINPUT_INFO is set. Turn it back on, we know what we're doing. + */ + if (F_ISSET(sp, SC_TINPUT_INFO)) { + reset = 1; + F_CLR(sp, SC_TINPUT_INFO); + } else + reset = 0; + +#define CHK_INTR \ + if (F_ISSET(gp, G_INTERRUPTED)) \ + goto intr; + + /* If the largest file name is too large, just print them. */ + if (colwidth >= sp->cols) { + for (ac = argc, av = argv; ac > 0; --ac, ++av) { + INT2CHAR(sp, av[0]->bp+prefix, av[0]->len+1-prefix, + np, nlen); + pp = msg_print(sp, np, &nf); + (void)ex_printf(sp, "%s\n", pp); + if (nf) + FREE_SPACE(sp, pp, 0); + if (F_ISSET(gp, G_INTERRUPTED)) + break; + } + CHK_INTR; + } else { + /* Figure out the number of columns. */ + numcols = (sp->cols - 1) / colwidth; + if (argc > numcols) { + numrows = argc / numcols; + if (argc % numcols) + ++numrows; + } else + numrows = 1; + + /* Display the files in sorted order. */ + for (row = 0; row < numrows; ++row) { + for (base = row, col = 0; col < numcols; ++col) { + INT2CHAR(sp, argv[base]->bp+prefix, + argv[base]->len+1-prefix, np, nlen); + pp = msg_print(sp, np, &nf); + cnt = ex_printf(sp, "%s", pp); + if (nf) + FREE_SPACE(sp, pp, 0); + CHK_INTR; + if ((base += numrows) >= argc) + break; + (void)ex_printf(sp, + "%*s", (int)(colwidth - cnt), ""); + CHK_INTR; + } + (void)ex_puts(sp, "\n"); + CHK_INTR; + } + (void)ex_puts(sp, "\n"); + CHK_INTR; + } + (void)ex_fflush(sp); + + if (0) { +intr: F_CLR(gp, G_INTERRUPTED); + } + if (reset) + F_SET(sp, SC_TINPUT_INFO); + + return (0); +} + +/* + * txt_emark -- + * Set the end mark on the line. + */ +static int +txt_emark(SCR *sp, TEXT *tp, size_t cno) +{ + CHAR_T ch; + u_char *kp; + size_t chlen, nlen, olen; + CHAR_T *p; + + ch = CH_ENDMARK; + + /* + * The end mark may not be the same size as the current character. + * Don't let the line shift. + */ + nlen = KEY_COL(sp, ch); + if (tp->lb[cno] == '\t') + (void)vs_columns(sp, tp->lb, tp->lno, &cno, &olen); + else + olen = KEY_COL(sp, tp->lb[cno]); + + /* + * If the line got longer, well, it's weird, but it's easy. If + * it's the same length, it's easy. If it got shorter, we have + * to fix it up. + */ + if (olen > nlen) { + BINC_RETW(sp, tp->lb, tp->lb_len, tp->len + olen); + chlen = olen - nlen; + if (tp->insert != 0) + MEMMOVE(tp->lb + cno + 1 + chlen, + tp->lb + cno + 1, tp->insert); + + tp->len += chlen; + tp->owrite += chlen; + p = tp->lb + cno; + if (tp->lb[cno] == '\t' || + KEY_NEEDSWIDE(sp, tp->lb[cno])) + for (cno += chlen; chlen--;) + *p++ = ' '; + else + for (kp = (u_char *) + KEY_NAME(sp, tp->lb[cno]), + cno += chlen; chlen--;) + *p++ = *kp++; + } + tp->lb[cno] = ch; + return (vs_change(sp, tp->lno, LINE_RESET)); +} + +/* + * txt_err -- + * Handle an error during input processing. + */ +static void +txt_err(SCR *sp, TEXTH *tiqh) +{ + recno_t lno; + + /* + * The problem with input processing is that the cursor is at an + * indeterminate position since some input may have been lost due + * to a malloc error. So, try to go back to the place from which + * the cursor started, knowing that it may no longer be available. + * + * We depend on at least one line number being set in the text + * chain. + */ + for (lno = TAILQ_FIRST(tiqh)->lno; + !db_exist(sp, lno) && lno > 0; --lno); + + sp->lno = lno == 0 ? 1 : lno; + sp->cno = 0; + + /* Redraw the screen, just in case. */ + F_SET(sp, SC_SCR_REDRAW); +} + +/* + * txt_hex -- + * Let the user insert any character value they want. + * + * !!! + * This is an extension. The pattern "^X[0-9a-fA-F]*" is a way + * for the user to specify a character value which their keyboard + * may not be able to enter. + */ +static int +txt_hex(SCR *sp, TEXT *tp) +{ + CHAR_T savec; + size_t len, off; + u_long value; + CHAR_T *p, *wp; + + /* + * Null-terminate the string. Since nul isn't a legal hex value, + * this should be okay, and lets us use a local routine, which + * presumably understands the character set, to convert the value. + */ + savec = tp->lb[tp->cno]; + tp->lb[tp->cno] = 0; + + /* Find the previous CH_HEX character. */ + for (off = tp->cno - 1, p = tp->lb + off, len = 0;; --p, --off, ++len) { + if (*p == CH_HEX) { + wp = p + 1; + break; + } + /* Not on this line? Shouldn't happen. */ + if (off == tp->ai || off == tp->offset) + goto nothex; + } + + /* If length of 0, then it wasn't a hex value. */ + if (len == 0) + goto nothex; + + /* Get the value. */ + errno = 0; + value = STRTOL(wp, NULL, 16); + if (errno || value > UCHAR_MAX) { +nothex: tp->lb[tp->cno] = savec; + return (0); + } + + /* Restore the original character. */ + tp->lb[tp->cno] = savec; + + /* Adjust the bookkeeping. */ + tp->cno -= len; + tp->len -= len; + tp->lb[tp->cno - 1] = value; + + /* Copy down any overwrite characters. */ + if (tp->owrite) + MEMMOVE(tp->lb + tp->cno, tp->lb + tp->cno + len, + tp->owrite); + + /* Copy down any insert characters. */ + if (tp->insert) + MEMMOVE(tp->lb + tp->cno + tp->owrite, + tp->lb + tp->cno + tp->owrite + len, + tp->insert); + + return (0); +} + +/* + * txt_insch -- + * + * !!! + * Historic vi did a special screen optimization for tab characters. As an + * example, for the keystrokes "iabcd0C", the tab overwrote the + * rest of the string when it was displayed. + * + * Because early versions of this implementation redisplayed the entire line + * on each keystroke, the "bcd" was pushed to the right as it ignored that + * the user had "promised" to change the rest of the characters. However, + * the historic vi implementation had an even worse bug: given the keystrokes + * "iabcd0R", the "bcd" disappears, and magically reappears + * on the second key. + * + * POSIX 1003.2 requires (will require) that this be fixed, specifying that + * vi overwrite characters the user has committed to changing, on the basis + * of the screen space they require, but that it not overwrite other characters. + */ +static int +txt_insch(SCR *sp, TEXT *tp, CHAR_T *chp, u_int flags) +{ + u_char *kp; + CHAR_T savech; + size_t chlen, cno, copydown, olen, nlen; + CHAR_T *p; + + /* + * The 'R' command does one-for-one replacement, because there's + * no way to know how many characters the user intends to replace. + */ + if (LF_ISSET(TXT_REPLACE)) { + if (tp->owrite) { + --tp->owrite; + tp->lb[tp->cno++] = *chp; + return (0); + } + } else if (tp->owrite) { /* Overwrite a character. */ + cno = tp->cno; + + /* + * If the old or new characters are tabs, then the length of the + * display depends on the character position in the display. We + * don't even try to handle this here, just ask the screen. + */ + if (*chp == '\t') { + savech = tp->lb[cno]; + tp->lb[cno] = '\t'; + (void)vs_columns(sp, tp->lb, tp->lno, &cno, &nlen); + tp->lb[cno] = savech; + } else + nlen = KEY_COL(sp, *chp); + + /* + * Eat overwrite characters until we run out of them or we've + * handled the length of the new character. If we only eat + * part of an overwrite character, break it into its component + * elements and display the remaining components. + */ + for (copydown = 0; nlen != 0 && tp->owrite != 0;) { + --tp->owrite; + + if (tp->lb[cno] == '\t') + (void)vs_columns(sp, + tp->lb, tp->lno, &cno, &olen); + else + olen = KEY_COL(sp, tp->lb[cno]); + + if (olen == nlen) { + nlen = 0; + break; + } + if (olen < nlen) { + ++copydown; + nlen -= olen; + } else { + BINC_RETW(sp, + tp->lb, tp->lb_len, tp->len + olen); + chlen = olen - nlen; + MEMMOVE(tp->lb + cno + 1 + chlen, + tp->lb + cno + 1, + tp->owrite + tp->insert); + + tp->len += chlen; + tp->owrite += chlen; + if (tp->lb[cno] == '\t' || + KEY_NEEDSWIDE(sp, tp->lb[cno])) + for (p = tp->lb + cno + 1; chlen--;) + *p++ = ' '; + else + for (kp = (u_char *) + KEY_NAME(sp, tp->lb[cno]) + nlen, + p = tp->lb + cno + 1; chlen--;) + *p++ = *kp++; + nlen = 0; + break; + } + } + + /* + * If had to erase several characters, we adjust the total + * count, and if there are any characters left, shift them + * into position. + */ + if (copydown != 0 && (tp->len -= copydown) != 0) + MEMMOVE(tp->lb + cno, tp->lb + cno + copydown, + tp->owrite + tp->insert + copydown); + + /* If we had enough overwrite characters, we're done. */ + if (nlen == 0) { + tp->lb[tp->cno++] = *chp; + return (0); + } + } + + /* Check to see if the character fits into the input buffer. */ + BINC_RETW(sp, tp->lb, tp->lb_len, tp->len + 1); + + ++tp->len; + if (tp->insert) { /* Insert a character. */ + if (tp->insert == 1) + tp->lb[tp->cno + 1] = tp->lb[tp->cno]; + else + MEMMOVE(tp->lb + tp->cno + 1, + tp->lb + tp->cno, tp->owrite + tp->insert); + } + tp->lb[tp->cno++] = *chp; + return (0); +} + +/* + * txt_isrch -- + * Do an incremental search. + */ +static int +txt_isrch(SCR *sp, VICMD *vp, TEXT *tp, u_int8_t *is_flagsp) +{ + MARK start; + recno_t lno; + u_int sf; + + /* If it's a one-line screen, we don't do incrementals. */ + if (IS_ONELINE(sp)) { + FL_CLR(*is_flagsp, IS_RUNNING); + return (0); + } + + /* + * If the user erases back to the beginning of the buffer, there's + * nothing to search for. Reset the cursor to the starting point. + */ + if (tp->cno <= 1) { + vp->m_final = vp->m_start; + return (0); + } + + /* + * If it's an RE quote character, and not quoted, ignore it until + * we get another character. + */ + if (tp->lb[tp->cno - 1] == '\\' && + (tp->cno == 2 || tp->lb[tp->cno - 2] != '\\')) + return (0); + + /* + * If it's a magic shell character, and not quoted, reset the cursor + * to the starting point. + */ + if (IS_SHELLMETA(sp, tp->lb[tp->cno - 1]) && + (tp->cno == 2 || tp->lb[tp->cno - 2] != '\\')) + vp->m_final = vp->m_start; + + /* + * If we see the search pattern termination character, then quit doing + * an incremental search. There may be more, e.g., ":/foo/;/bar/", + * and we can't handle that incrementally. Also, reset the cursor to + * the original location, the ex search routines don't know anything + * about incremental searches. + */ + if (tp->lb[0] == tp->lb[tp->cno - 1] && + (tp->cno == 2 || tp->lb[tp->cno - 2] != '\\')) { + vp->m_final = vp->m_start; + FL_CLR(*is_flagsp, IS_RUNNING); + return (0); + } + + /* + * Remember the input line and discard the special input map, + * but don't overwrite the input line on the screen. + */ + lno = tp->lno; + F_SET(VIP(sp), VIP_S_MODELINE); + F_CLR(sp, SC_TINPUT | SC_TINPUT_INFO); + if (txt_map_end(sp)) + return (1); + + /* + * Specify a starting point and search. If we find a match, move to + * it and refresh the screen. If we didn't find the match, then we + * beep the screen. When searching from the original cursor position, + * we have to move the cursor, otherwise, we don't want to move the + * cursor in case the text at the current position continues to match. + */ + if (FL_ISSET(*is_flagsp, IS_RESTART)) { + start = vp->m_start; + sf = SEARCH_SET; + } else { + start = vp->m_final; + sf = SEARCH_INCR | SEARCH_SET; + } + + if (tp->lb[0] == '/' ? + !f_search(sp, + &start, &vp->m_final, tp->lb + 1, tp->cno - 1, NULL, sf) : + !b_search(sp, + &start, &vp->m_final, tp->lb + 1, tp->cno - 1, NULL, sf)) { + sp->lno = vp->m_final.lno; + sp->cno = vp->m_final.cno; + FL_CLR(*is_flagsp, IS_RESTART); + + if (!KEYS_WAITING(sp) && vs_refresh(sp, 0)) + return (1); + } else + FL_SET(*is_flagsp, IS_RESTART); + + /* Reinstantiate the special input map. */ + if (txt_map_init(sp)) + return (1); + F_CLR(VIP(sp), VIP_S_MODELINE); + F_SET(sp, SC_TINPUT | SC_TINPUT_INFO); + + /* Reset the line number of the input line. */ + tp->lno = TMAP[0].lno; + + /* + * If the colon command-line moved, i.e. the screen scrolled, + * refresh the input line. + * + * XXX + * We shouldn't be calling vs_line, here -- we need dirty bits + * on entries in the SMAP array. + */ + if (lno != TMAP[0].lno) { + if (vs_line(sp, &TMAP[0], NULL, NULL)) + return (1); + (void)sp->gp->scr_refresh(sp, 0); + } + return (0); +} + +/* + * txt_resolve -- + * Resolve the input text chain into the file. + */ +static int +txt_resolve(SCR *sp, TEXTH *tiqh, u_int32_t flags) +{ + VI_PRIVATE *vip; + TEXT *tp; + recno_t lno; + int changed; + + /* + * The first line replaces a current line, and all subsequent lines + * are appended into the file. Resolve autoindented characters for + * each line before committing it. If the latter causes the line to + * change, we have to redisplay it, otherwise the information cached + * about the line will be wrong. + */ + vip = VIP(sp); + tp = TAILQ_FIRST(tiqh); + + if (LF_ISSET(TXT_AUTOINDENT)) + txt_ai_resolve(sp, tp, &changed); + else + changed = 0; + if (db_set(sp, tp->lno, tp->lb, tp->len) || + (changed && vs_change(sp, tp->lno, LINE_RESET))) + return (1); + + for (lno = tp->lno; (tp = TAILQ_NEXT(tp, q)) != NULL; ++lno) { + if (LF_ISSET(TXT_AUTOINDENT)) + txt_ai_resolve(sp, tp, &changed); + else + changed = 0; + if (db_append(sp, 0, lno, tp->lb, tp->len) || + (changed && vs_change(sp, tp->lno, LINE_RESET))) + return (1); + } + + /* + * Clear the input flag, the look-aside buffer is no longer valid. + * Has to be done as part of text resolution, or upon return we'll + * be looking at incorrect data. + */ + F_CLR(sp, SC_TINPUT); + + return (0); +} + +/* + * txt_showmatch -- + * Show a character match. + * + * !!! + * Historic vi tried to display matches even in the :colon command line. + * I think not. + */ +static int +txt_showmatch(SCR *sp, TEXT *tp) +{ + GS *gp; + VCS cs; + MARK m; + int cnt, endc, startc; + + gp = sp->gp; + + /* + * Do a refresh first, in case we haven't done one in awhile, + * so the user can see what we're complaining about. + */ + UPDATE_POSITION(sp, tp); + if (vs_refresh(sp, 1)) + return (1); + + /* + * We don't display the match if it's not on the screen. Find + * out what the first character on the screen is. + */ + if (vs_sm_position(sp, &m, 0, P_TOP)) + return (1); + + /* Initialize the getc() interface. */ + cs.cs_lno = tp->lno; + cs.cs_cno = tp->cno - 1; + if (cs_init(sp, &cs)) + return (1); + startc = STRCHR(VIP(sp)->mcs, endc = cs.cs_ch)[-1]; + + /* Search for the match. */ + for (cnt = 1;;) { + if (cs_prev(sp, &cs)) + return (1); + if (cs.cs_flags != 0) { + if (cs.cs_flags == CS_EOF || cs.cs_flags == CS_SOF) { + msgq(sp, M_BERR, + "Unmatched %s", KEY_NAME(sp, endc)); + return (0); + } + continue; + } + if (cs.cs_ch == endc) + ++cnt; + else if (cs.cs_ch == startc && --cnt == 0) + break; + } + + /* If the match is on the screen, move to it. */ + if (cs.cs_lno < m.lno || (cs.cs_lno == m.lno && cs.cs_cno < m.cno)) + return (0); + sp->lno = cs.cs_lno; + sp->cno = cs.cs_cno; + if (vs_refresh(sp, 1)) + return (1); + + /* Wait for timeout or character arrival. */ + return (v_event_get(sp, + NULL, O_VAL(sp, O_MATCHTIME) * 100, EC_TIMEOUT)); +} + +/* + * txt_margin -- + * Handle margin wrap. + */ +static int +txt_margin(SCR *sp, TEXT *tp, TEXT *wmtp, int *didbreak, u_int32_t flags) +{ + VI_PRIVATE *vip; + size_t len, off; + CHAR_T *p, *wp; + + /* Find the nearest previous blank. */ + for (off = tp->cno - 1, p = tp->lb + off, len = 0;; --off, --p, ++len) { + if (isblank(*p)) { + wp = p + 1; + break; + } + + /* + * If reach the start of the line, there's nowhere to break. + * + * !!! + * Historic vi belled each time a character was entered after + * crossing the margin until a space was entered which could + * be used to break the line. I don't as it tends to wake the + * cats. + */ + if (off == tp->ai || off == tp->offset) { + *didbreak = 0; + return (0); + } + } + + /* + * Store saved information about the rest of the line in the + * wrapmargin TEXT structure. + * + * !!! + * The offset field holds the length of the current characters + * that the user entered, but which are getting split to the new + * line -- it's going to be used to set the cursor value when we + * move to the new line. + */ + vip = VIP(sp); + wmtp->lb = p + 1; + wmtp->offset = len; + wmtp->insert = LF_ISSET(TXT_APPENDEOL) ? tp->insert - 1 : tp->insert; + wmtp->owrite = tp->owrite; + + /* Correct current bookkeeping information. */ + tp->cno -= len; + if (LF_ISSET(TXT_APPENDEOL)) { + tp->len -= len + tp->owrite + (tp->insert - 1); + tp->insert = 1; + } else { + tp->len -= len + tp->owrite + tp->insert; + tp->insert = 0; + } + tp->owrite = 0; + + /* + * !!! + * Delete any trailing whitespace from the current line. + */ + for (;; --p, --off) { + if (!isblank(*p)) + break; + --tp->cno; + --tp->len; + if (off == tp->ai || off == tp->offset) + break; + } + *didbreak = 1; + return (0); +} + +/* + * txt_Rresolve -- + * Resolve the input line for the 'R' command. + */ +static void +txt_Rresolve(SCR *sp, TEXTH *tiqh, TEXT *tp, const size_t orig_len) +{ + TEXT *ttp; + size_t input_len, retain; + CHAR_T *p; + + /* + * Check to make sure that the cursor hasn't moved beyond + * the end of the line. + */ + if (tp->owrite == 0) + return; + + /* + * Calculate how many characters the user has entered, + * plus the blanks erased by /s. + */ + for (ttp = TAILQ_FIRST(tiqh), input_len = 0;;) { + input_len += ttp == tp ? tp->cno : ttp->len + ttp->R_erase; + if ((ttp = TAILQ_NEXT(ttp, q)) == NULL) + break; + } + + /* + * If the user has entered less characters than the original line + * was long, restore any overwriteable characters to the original + * characters. These characters are entered as "insert characters", + * because they're after the cursor and we don't want to lose them. + * (This is okay because the R command has no insert characters.) + * We set owrite to 0 so that the insert characters don't get copied + * to somewhere else, which means that the line and the length have + * to be adjusted here as well. + * + * We have to retrieve the original line because the original pinned + * page has long since been discarded. If it doesn't exist, that's + * okay, the user just extended the file. + */ + if (input_len < orig_len) { + retain = MIN(tp->owrite, orig_len - input_len); + if (db_get(sp, + TAILQ_FIRST(tiqh)->lno, DBG_FATAL | DBG_NOCACHE, &p, NULL)) + return; + MEMCPY(tp->lb + tp->cno, p + input_len, retain); + tp->len -= tp->owrite - retain; + tp->owrite = 0; + tp->insert += retain; + } +} + +/* + * txt_nomorech -- + * No more characters message. + */ +static void +txt_nomorech(SCR *sp) +{ + msgq(sp, M_BERR, "194|No more characters to erase"); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/vi/v_txt.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/vi/vi.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/vi/vi.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/vi/vi.c (revision 366308) @@ -0,0 +1,1240 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../common/common.h" +#include "vi.h" + +typedef enum { + GC_ERR, GC_ERR_NOFLUSH, GC_EVENT, GC_FATAL, GC_INTERRUPT, GC_OK +} gcret_t; + +static VIKEYS const + *v_alias(SCR *, VICMD *, VIKEYS const *); +static gcret_t v_cmd(SCR *, VICMD *, VICMD *, VICMD *, int *, int *); +static int v_count(SCR *, ARG_CHAR_T, u_long *); +static void v_dtoh(SCR *); +static int v_init(SCR *); +static gcret_t v_key(SCR *, int, EVENT *, u_int32_t); +static int v_motion(SCR *, VICMD *, VICMD *, int *); + +#if defined(DEBUG) && defined(COMLOG) +static void v_comlog(SCR *, VICMD *); +#endif + +/* + * Side-effect: + * The dot structure can be set by the underlying vi functions, + * see v_Put() and v_put(). + */ +#define DOT (&VIP(sp)->sdot) +#define DOTMOTION (&VIP(sp)->sdotmotion) + +/* + * vi -- + * Main vi command loop. + * + * PUBLIC: int vi(SCR **); + */ +int +vi(SCR **spp) +{ + GS *gp; + MARK abs; + SCR *next, *sp; + VICMD cmd = { 0 }, *vp; + VI_PRIVATE *vip; + int comcount, mapped, rval; + + /* Get the first screen. */ + sp = *spp; + gp = sp->gp; + + /* Point to the command structure. */ + vp = &cmd; + + /* Reset strange attraction. */ + F_SET(vp, VM_RCM_SET); + + /* Initialize the vi screen. */ + if (v_init(sp)) + return (1); + + /* Set the focus. */ + (void)sp->gp->scr_rename(sp, sp->frp->name, 1); + + for (vip = VIP(sp), rval = 0;;) { + /* Resolve messages. */ + if (!MAPPED_KEYS_WAITING(sp) && vs_resolve(sp, NULL, 0)) + goto ret; + + /* + * If not skipping a refresh, return to command mode and + * refresh the screen. + */ + if (F_ISSET(vip, VIP_S_REFRESH)) + F_CLR(vip, VIP_S_REFRESH); + else { + sp->showmode = SM_COMMAND; + if (vs_refresh(sp, 0)) + goto ret; + } + + /* Set the new favorite position. */ + if (F_ISSET(vp, VM_RCM_SET | VM_RCM_SETFNB | VM_RCM_SETNNB)) { + F_CLR(vip, VIP_RCM_LAST); + (void)vs_column(sp, &sp->rcm); + } + + /* + * If not currently in a map, log the cursor position, + * and set a flag so that this command can become the + * DOT command. + */ + if (MAPPED_KEYS_WAITING(sp)) + mapped = 1; + else { + if (log_cursor(sp)) + goto err; + mapped = 0; + } + + /* + * There may be an ex command waiting, and we returned here + * only because we exited a screen or file. In this case, + * we simply go back into the ex parser. + */ + if (EXCMD_RUNNING(gp)) { + vp->kp = &vikeys[':']; + goto ex_continue; + } + + /* Refresh the command structure. */ + memset(vp, 0, sizeof(VICMD)); + + /* + * We get a command, which may or may not have an associated + * motion. If it does, we get it too, calling its underlying + * function to get the resulting mark. We then call the + * command setting the cursor to the resulting mark. + * + * !!! + * Vi historically flushed mapped characters on error, but + * entering extra characters at the beginning of + * a map wasn't considered an error -- in fact, users would + * put leading characters in maps to clean up vi + * state before the map was interpreted. Beauty! + */ + switch (v_cmd(sp, DOT, vp, NULL, &comcount, &mapped)) { + case GC_ERR: + goto err; + case GC_ERR_NOFLUSH: + goto gc_err_noflush; + case GC_EVENT: + goto gc_event; + case GC_FATAL: + goto ret; + case GC_INTERRUPT: + goto intr; + case GC_OK: + break; + } + + /* Check for security setting. */ + if (F_ISSET(vp->kp, V_SECURE) && O_ISSET(sp, O_SECURE)) { + ex_emsg(sp, KEY_NAME(sp, vp->key), EXM_SECURE); + goto err; + } + + /* + * Historical practice: if a dot command gets a new count, + * any motion component goes away, i.e. "d3w2." deletes a + * total of 5 words. + */ + if (F_ISSET(vp, VC_ISDOT) && comcount) + DOTMOTION->count = 1; + + /* Copy the key flags into the local structure. */ + F_SET(vp, vp->kp->flags); + + /* Prepare to set the previous context. */ + if (F_ISSET(vp, V_ABS | V_ABS_C | V_ABS_L)) { + abs.lno = sp->lno; + abs.cno = sp->cno; + } + + /* + * Set the three cursor locations to the current cursor. The + * underlying routines don't bother if the cursor doesn't move. + * This also handles line commands (e.g. Y) defaulting to the + * current line. + */ + vp->m_start.lno = vp->m_stop.lno = vp->m_final.lno = sp->lno; + vp->m_start.cno = vp->m_stop.cno = vp->m_final.cno = sp->cno; + + /* + * Do any required motion; v_motion sets the from MARK and the + * line mode flag, as well as the VM_RCM flags. + */ + if (F_ISSET(vp, V_MOTION) && + v_motion(sp, DOTMOTION, vp, &mapped)) { + if (INTERRUPTED(sp)) + goto intr; + goto err; + } + + /* + * If a count is set and the command is line oriented, set the + * to MARK here relative to the cursor/from MARK. This is for + * commands that take both counts and motions, i.e. "4yy" and + * "y%". As there's no way the command can know which the user + * did, we have to do it here. (There are commands that are + * line oriented and that take counts ("#G", "#H"), for which + * this calculation is either completely meaningless or wrong. + * Each command must validate the value for itself. + */ + if (F_ISSET(vp, VC_C1SET) && F_ISSET(vp, VM_LMODE)) + vp->m_stop.lno += vp->count - 1; + + /* Increment the command count. */ + ++sp->ccnt; + +#if defined(DEBUG) && defined(COMLOG) + v_comlog(sp, vp); +#endif + /* Call the function. */ +ex_continue: if (vp->kp->func(sp, vp)) + goto err; +gc_event: +#ifdef DEBUG + /* Make sure no function left the temporary space locked. */ + if (F_ISSET(gp, G_TMP_INUSE)) { + F_CLR(gp, G_TMP_INUSE); + msgq(sp, M_ERR, + "232|vi: temporary buffer not released"); + } +#endif + /* + * If we're exiting this screen, move to the next one, or, if + * there aren't any more, return to the main editor loop. The + * ordering is careful, don't discard the contents of sp until + * the end. + */ + if (F_ISSET(sp, SC_EXIT | SC_EXIT_FORCE)) { + if (file_end(sp, NULL, F_ISSET(sp, SC_EXIT_FORCE))) + goto ret; + if (vs_discard(sp, &next)) + goto ret; + if (next == NULL && vs_swap(sp, &next, NULL)) + goto ret; + *spp = next; + if (screen_end(sp)) + goto ret; + if (next == NULL) + break; + + /* Switch screens, change focus. */ + sp = next; + vip = VIP(sp); + (void)sp->gp->scr_rename(sp, sp->frp->name, 1); + + /* Don't trust the cursor. */ + F_SET(vip, VIP_CUR_INVALID); + + continue; + } + + /* + * Set the dot command structure. + * + * !!! + * Historically, commands which used mapped keys did not + * set the dot command, with the exception of the text + * input commands. + */ + if (F_ISSET(vp, V_DOT) && !mapped) { + *DOT = cmd; + F_SET(DOT, VC_ISDOT); + + /* + * If a count was supplied for both the command and + * its motion, the count was used only for the motion. + * Turn the count back on for the dot structure. + */ + if (F_ISSET(vp, VC_C1RESET)) + F_SET(DOT, VC_C1SET); + + /* VM flags aren't retained. */ + F_CLR(DOT, VM_COMMASK | VM_RCM_MASK); + } + + /* + * Some vi row movements are "attracted" to the last position + * set, i.e. the VM_RCM commands are moths to the VM_RCM_SET + * commands' candle. If the movement is to the EOL the vi + * command handles it. If it's to the beginning, we handle it + * here. + * + * Note, some commands (e.g. _, ^) don't set the VM_RCM_SETFNB + * flag, but do the work themselves. The reason is that they + * have to modify the column in case they're being used as a + * motion component. Other similar commands (e.g. +, -) don't + * have to modify the column because they are always line mode + * operations when used as motions, so the column number isn't + * of any interest. + * + * Does this totally violate the screen and editor layering? + * You betcha. As they say, if you think you understand it, + * you don't. + */ + switch (F_ISSET(vp, VM_RCM_MASK)) { + case 0: + case VM_RCM_SET: + break; + case VM_RCM: + vp->m_final.cno = vs_rcm(sp, + vp->m_final.lno, F_ISSET(vip, VIP_RCM_LAST)); + break; + case VM_RCM_SETLAST: + F_SET(vip, VIP_RCM_LAST); + break; + case VM_RCM_SETFNB: + vp->m_final.cno = 0; + /* FALLTHROUGH */ + case VM_RCM_SETNNB: + if (nonblank(sp, vp->m_final.lno, &vp->m_final.cno)) + goto err; + break; + default: + abort(); + } + + /* Update the cursor. */ + sp->lno = vp->m_final.lno; + sp->cno = vp->m_final.cno; + + /* + * Set the absolute mark -- set even if a tags or similar + * command, since the tag may be moving to the same file. + */ + if ((F_ISSET(vp, V_ABS) || + (F_ISSET(vp, V_ABS_L) && sp->lno != abs.lno) || + (F_ISSET(vp, V_ABS_C) && + (sp->lno != abs.lno || sp->cno != abs.cno))) && + mark_set(sp, ABSMARK1, &abs, 1)) + goto err; + + if (0) { +err: if (v_event_flush(sp, CH_MAPPED)) + msgq(sp, M_BERR, + "110|Vi command failed: mapped keys discarded"); + } + + /* + * Check and clear interrupts. There's an obvious race, but + * it's not worth fixing. + */ +gc_err_noflush: if (INTERRUPTED(sp)) { +intr: CLR_INTERRUPT(sp); + if (v_event_flush(sp, CH_MAPPED)) + msgq(sp, M_ERR, + "231|Interrupted: mapped keys discarded"); + else + msgq(sp, M_ERR, "236|Interrupted"); + } + + /* If the last command switched screens, update. */ + if (F_ISSET(sp, SC_SSWITCH)) { + F_CLR(sp, SC_SSWITCH); + + /* + * If the current screen is still displayed, it will + * need a new status line. + */ + F_SET(sp, SC_STATUS); + + /* Switch screens, change focus. */ + sp = sp->nextdisp; + vip = VIP(sp); + (void)sp->gp->scr_rename(sp, sp->frp->name, 1); + + /* Don't trust the cursor. */ + F_SET(vip, VIP_CUR_INVALID); + + /* Refresh so we can display messages. */ + if (vs_refresh(sp, 1)) + return (1); + } + + /* If the last command switched files, change focus. */ + if (F_ISSET(sp, SC_FSWITCH)) { + F_CLR(sp, SC_FSWITCH); + (void)sp->gp->scr_rename(sp, sp->frp->name, 1); + } + + /* If leaving vi, return to the main editor loop. */ + if (F_ISSET(gp, G_SRESTART) || F_ISSET(sp, SC_EX)) { + *spp = sp; + v_dtoh(sp); + gp->scr_discard(sp, NULL); + break; + } + } + if (0) +ret: rval = 1; + return (rval); +} + +#define KEY(key, ec_flags) do { \ + if ((gcret = v_key(sp, 0, &ev, ec_flags)) != GC_OK) \ + return (gcret); \ + if (ev.e_value == K_ESCAPE) \ + goto esc; \ + if (F_ISSET(&ev.e_ch, CH_MAPPED)) \ + *mappedp = 1; \ + key = ev.e_c; \ +} while (0) + +/* + * The O_TILDEOP option makes the ~ command take a motion instead + * of a straight count. This is the replacement structure we use + * instead of the one currently in the VIKEYS table. + * + * XXX + * This should probably be deleted -- it's not all that useful, and + * we get help messages wrong. + */ +VIKEYS const tmotion = { + v_mulcase, V_CNT|V_DOT|V_MOTION|VM_RCM_SET, + "[count]~[count]motion", + " ~ change case to motion" +}; + +/* + * v_cmd -- + * + * The command structure for vi is less complex than ex (and don't think + * I'm not grateful!) The command syntax is: + * + * [count] [buffer] [count] key [[motion] | [buffer] [character]] + * + * and there are several special cases. The motion value is itself a vi + * command, with the syntax: + * + * [count] key [character] + */ +static gcret_t +v_cmd( + SCR *sp, + VICMD *dp, + VICMD *vp, + VICMD *ismotion, /* Previous key if getting motion component. */ + int *comcountp, + int *mappedp) +{ + enum { COMMANDMODE, ISPARTIAL, NOTPARTIAL } cpart; + EVENT ev; + VIKEYS const *kp; + gcret_t gcret; + u_int flags; + CHAR_T key; + char *s; + + /* + * Get a key. + * + * cancels partial commands, i.e. a command where at least + * one non-numeric character has been entered. Otherwise, it beeps + * the terminal. + * + * !!! + * POSIX 1003.2-1992 explicitly disallows cancelling commands where + * all that's been entered is a number, requiring that the terminal + * be alerted. + */ + cpart = ismotion == NULL ? COMMANDMODE : ISPARTIAL; + if ((gcret = + v_key(sp, ismotion == NULL, &ev, EC_MAPCOMMAND)) != GC_OK) { + if (gcret == GC_EVENT) + vp->ev = ev; + return (gcret); + } + if (ev.e_value == K_ESCAPE) + goto esc; + if (F_ISSET(&ev.e_ch, CH_MAPPED)) + *mappedp = 1; + key = ev.e_c; + + if (ismotion == NULL) + cpart = NOTPARTIAL; + + /* Pick up an optional buffer. */ + if (key == '"') { + cpart = ISPARTIAL; + if (ismotion != NULL) { + v_emsg(sp, NULL, VIM_COMBUF); + return (GC_ERR); + } + KEY(vp->buffer, 0); + F_SET(vp, VC_BUFFER); + + KEY(key, EC_MAPCOMMAND); + } + + /* + * Pick up an optional count, where a leading 0 is not a count, + * it's a command. + */ + if (ISDIGIT(key) && key != '0') { + if (v_count(sp, key, &vp->count)) + return (GC_ERR); + F_SET(vp, VC_C1SET); + *comcountp = 1; + + KEY(key, EC_MAPCOMMAND); + } else + *comcountp = 0; + + /* Pick up optional buffer. */ + if (key == '"') { + cpart = ISPARTIAL; + if (F_ISSET(vp, VC_BUFFER)) { + msgq(sp, M_ERR, "234|Only one buffer may be specified"); + return (GC_ERR); + } + if (ismotion != NULL) { + v_emsg(sp, NULL, VIM_COMBUF); + return (GC_ERR); + } + KEY(vp->buffer, 0); + F_SET(vp, VC_BUFFER); + + KEY(key, EC_MAPCOMMAND); + } + + /* Check for an OOB command key. */ + cpart = ISPARTIAL; + if (key > MAXVIKEY) { + v_emsg(sp, KEY_NAME(sp, key), VIM_NOCOM); + return (GC_ERR); + } + kp = &vikeys[vp->key = key]; + + /* + * !!! + * Historically, D accepted and then ignored a count. Match it. + */ + if (vp->key == 'D' && F_ISSET(vp, VC_C1SET)) { + *comcountp = 0; + vp->count = 0; + F_CLR(vp, VC_C1SET); + } + + /* Check for command aliases. */ + if (kp->func == NULL && (kp = v_alias(sp, vp, kp)) == NULL) + return (GC_ERR); + + /* The tildeop option makes the ~ command take a motion. */ + if (key == '~' && O_ISSET(sp, O_TILDEOP)) + kp = &tmotion; + + vp->kp = kp; + + /* + * Find the command. The only legal command with no underlying + * function is dot. It's historic practice that doesn't + * just erase the preceding number, it beeps the terminal as well. + * It's a common problem, so just beep the terminal unless verbose + * was set. + */ + if (kp->func == NULL) { + if (key != '.') { + v_emsg(sp, KEY_NAME(sp, key), + ev.e_value == K_ESCAPE ? VIM_NOCOM_B : VIM_NOCOM); + return (GC_ERR); + } + + /* If called for a motion command, stop now. */ + if (dp == NULL) + goto usage; + + /* + * !!! + * If a '.' is immediately entered after an undo command, we + * replay the log instead of redoing the last command. This + * is necessary because 'u' can't set the dot command -- see + * vi/v_undo.c:v_undo for details. + */ + if (VIP(sp)->u_ccnt == sp->ccnt) { + vp->kp = &vikeys['u']; + F_SET(vp, VC_ISDOT); + return (GC_OK); + } + + /* Otherwise, a repeatable command must have been executed. */ + if (!F_ISSET(dp, VC_ISDOT)) { + msgq(sp, M_ERR, "208|No command to repeat"); + return (GC_ERR); + } + + /* Set new count/buffer, if any, and return. */ + if (F_ISSET(vp, VC_C1SET)) { + F_SET(dp, VC_C1SET); + dp->count = vp->count; + } + if (F_ISSET(vp, VC_BUFFER)) + dp->buffer = vp->buffer; + + *vp = *dp; + return (GC_OK); + } + + /* Set the flags based on the command flags. */ + flags = kp->flags; + + /* Check for illegal count. */ + if (F_ISSET(vp, VC_C1SET) && !LF_ISSET(V_CNT)) + goto usage; + + /* Illegal motion command. */ + if (ismotion == NULL) { + /* Illegal buffer. */ + if (!LF_ISSET(V_OBUF) && F_ISSET(vp, VC_BUFFER)) + goto usage; + + /* Required buffer. */ + if (LF_ISSET(V_RBUF)) { + KEY(vp->buffer, 0); + F_SET(vp, VC_BUFFER); + } + } + + /* + * Special case: '[', ']' and 'Z' commands. Doesn't the fact that + * the *single* characters don't mean anything but the *doubled* + * characters do, just frost your shorts? + */ + if (vp->key == '[' || vp->key == ']' || vp->key == 'Z') { + /* + * Historically, half entered [[, ]] or Z commands weren't + * cancelled by , the terminal was beeped instead. + * POSIX.2-1992 probably didn't notice, and requires that + * they be cancelled instead of beeping. Seems fine to me. + * + * Don't set the EC_MAPCOMMAND flag, apparently ] is a popular + * vi meta-character, and we don't want the user to wait while + * we time out a possible mapping. This *appears* to match + * historic vi practice, but with mapping characters, You Just + * Never Know. + */ + KEY(key, 0); + + if (vp->key != key) { +usage: if (ismotion == NULL) + s = kp->usage; + else if (ismotion->key == '~' && O_ISSET(sp, O_TILDEOP)) + s = tmotion.usage; + else + s = vikeys[ismotion->key].usage; + v_emsg(sp, s, VIM_USAGE); + return (GC_ERR); + } + } + /* Special case: 'z' command. */ + if (vp->key == 'z') { + KEY(vp->character, 0); + if (ISDIGIT(vp->character)) { + if (v_count(sp, vp->character, &vp->count2)) + return (GC_ERR); + F_SET(vp, VC_C2SET); + KEY(vp->character, 0); + } + } + + /* + * Commands that have motion components can be doubled to imply the + * current line. + */ + if (ismotion != NULL && ismotion->key != key && !LF_ISSET(V_MOVE)) { + msgq(sp, M_ERR, "210|%s may not be used as a motion command", + KEY_NAME(sp, key)); + return (GC_ERR); + } + + /* Pick up required trailing character. */ + if (LF_ISSET(V_CHAR)) + KEY(vp->character, 0); + + /* Get any associated cursor word. */ + if (F_ISSET(kp, V_KEYW) && v_curword(sp)) + return (GC_ERR); + + return (GC_OK); + +esc: switch (cpart) { + case COMMANDMODE: + msgq(sp, M_BERR, "211|Already in command mode"); + return (GC_ERR_NOFLUSH); + case ISPARTIAL: + break; + case NOTPARTIAL: + (void)sp->gp->scr_bell(sp); + break; + } + return (GC_ERR); +} + +/* + * v_motion -- + * + * Get resulting motion mark. + */ +static int +v_motion( + SCR *sp, + VICMD *dm, + VICMD *vp, + int *mappedp) +{ + VICMD motion; + size_t len; + u_long cnt; + u_int flags; + int tilde_reset, notused; + + /* + * If '.' command, use the dot motion, else get the motion command. + * Clear any line motion flags, the subsequent motion isn't always + * the same, i.e. "/aaa" may or may not be a line motion. + */ + if (F_ISSET(vp, VC_ISDOT)) { + motion = *dm; + F_SET(&motion, VC_ISDOT); + F_CLR(&motion, VM_COMMASK); + } else { + memset(&motion, 0, sizeof(VICMD)); + if (v_cmd(sp, NULL, &motion, vp, ¬used, mappedp) != GC_OK) + return (1); + } + + /* + * A count may be provided both to the command and to the motion, in + * which case the count is multiplicative. For example, "3y4y" is the + * same as "12yy". This count is provided to the motion command and + * not to the regular function. + */ + cnt = motion.count = F_ISSET(&motion, VC_C1SET) ? motion.count : 1; + if (F_ISSET(vp, VC_C1SET)) { + motion.count *= vp->count; + F_SET(&motion, VC_C1SET); + + /* + * Set flags to restore the original values of the command + * structure so dot commands can change the count values, + * e.g. "2dw" "3." deletes a total of five words. + */ + F_CLR(vp, VC_C1SET); + F_SET(vp, VC_C1RESET); + } + + /* + * Some commands can be repeated to indicate the current line. In + * this case, or if the command is a "line command", set the flags + * appropriately. If not a doubled command, run the function to get + * the resulting mark. + */ + if (vp->key == motion.key) { + F_SET(vp, VM_LDOUBLE | VM_LMODE); + + /* Set the origin of the command. */ + vp->m_start.lno = sp->lno; + vp->m_start.cno = 0; + + /* + * Set the end of the command. + * + * If the current line is missing, i.e. the file is empty, + * historic vi permitted a "cc" or "!!" command to insert + * text. + */ + vp->m_stop.lno = sp->lno + motion.count - 1; + if (db_get(sp, vp->m_stop.lno, 0, NULL, &len)) { + if (vp->m_stop.lno != 1 || + (vp->key != 'c' && vp->key != '!')) { + v_emsg(sp, NULL, VIM_EMPTY); + return (1); + } + vp->m_stop.cno = 0; + } else + vp->m_stop.cno = len ? len - 1 : 0; + } else { + /* + * Motion commands change the underlying movement (*snarl*). + * For example, "l" is illegal at the end of a line, but "dl" + * is not. Set flags so the function knows the situation. + */ + motion.rkp = vp->kp; + + /* + * XXX + * Use yank instead of creating a new motion command, it's a + * lot easier for now. + */ + if (vp->kp == &tmotion) { + tilde_reset = 1; + vp->kp = &vikeys['y']; + } else + tilde_reset = 0; + + /* + * Copy the key flags into the local structure, except for the + * RCM flags -- the motion command will set the RCM flags in + * the vp structure if necessary. This means that the motion + * command is expected to determine where the cursor ends up! + * However, we save off the current RCM mask and restore it if + * it no RCM flags are set by the motion command, with a small + * modification. + * + * We replace the VM_RCM_SET flag with the VM_RCM flag. This + * is so that cursor movement doesn't set the relative position + * unless the motion command explicitly specified it. This + * appears to match historic practice, but I've never been able + * to develop a hard-and-fast rule. + */ + flags = F_ISSET(vp, VM_RCM_MASK); + if (LF_ISSET(VM_RCM_SET)) { + LF_SET(VM_RCM); + LF_CLR(VM_RCM_SET); + } + F_CLR(vp, VM_RCM_MASK); + F_SET(&motion, motion.kp->flags & ~VM_RCM_MASK); + + /* + * Set the three cursor locations to the current cursor. This + * permits commands like 'j' and 'k', that are line oriented + * motions and have special cursor suck semantics when they are + * used as standalone commands, to ignore column positioning. + */ + motion.m_final.lno = + motion.m_stop.lno = motion.m_start.lno = sp->lno; + motion.m_final.cno = + motion.m_stop.cno = motion.m_start.cno = sp->cno; + + /* Run the function. */ + if ((motion.kp->func)(sp, &motion)) + return (1); + + /* + * If the current line is missing, i.e. the file is empty, + * historic vi allowed "c" or "!" to insert + * text. Otherwise fail -- most motion commands will have + * already failed, but some, e.g. G, succeed in empty files. + */ + if (!db_exist(sp, vp->m_stop.lno)) { + if (vp->m_stop.lno != 1 || + (vp->key != 'c' && vp->key != '!')) { + v_emsg(sp, NULL, VIM_EMPTY); + return (1); + } + vp->m_stop.cno = 0; + } + + /* + * XXX + * See above. + */ + if (tilde_reset) + vp->kp = &tmotion; + + /* + * Copy cut buffer, line mode and cursor position information + * from the motion command structure, i.e. anything that the + * motion command can set for us. The commands can flag the + * movement as a line motion (see v_sentence) as well as set + * the VM_RCM_* flags explicitly. + */ + F_SET(vp, F_ISSET(&motion, VM_COMMASK | VM_RCM_MASK)); + + /* + * If the motion command set no relative motion flags, use + * the (slightly) modified previous values. + */ + if (!F_ISSET(vp, VM_RCM_MASK)) + F_SET(vp, flags); + + /* + * Commands can change behaviors based on the motion command + * used, for example, the ! command repeated the last bang + * command if N or n was used as the motion. + */ + vp->rkp = motion.kp; + + /* + * Motion commands can reset all of the cursor information. + * If the motion is in the reverse direction, switch the + * from and to MARK's so that it's in a forward direction. + * Motions are from the from MARK to the to MARK (inclusive). + */ + if (motion.m_start.lno > motion.m_stop.lno || + (motion.m_start.lno == motion.m_stop.lno && + motion.m_start.cno > motion.m_stop.cno)) { + vp->m_start = motion.m_stop; + vp->m_stop = motion.m_start; + } else { + vp->m_start = motion.m_start; + vp->m_stop = motion.m_stop; + } + vp->m_final = motion.m_final; + } + + /* + * If the command sets dot, save the motion structure. The motion + * count was changed above and needs to be reset, that's why this + * is done here, and not in the calling routine. + */ + if (F_ISSET(vp->kp, V_DOT)) { + *dm = motion; + dm->count = cnt; + } + return (0); +} + +/* + * v_init -- + * Initialize the vi screen. + */ +static int +v_init(SCR *sp) +{ + GS *gp; + VI_PRIVATE *vip; + + gp = sp->gp; + vip = VIP(sp); + + /* Switch into vi. */ + if (gp->scr_screen(sp, SC_VI)) + return (1); + (void)gp->scr_attr(sp, SA_ALTERNATE, 1); + + F_CLR(sp, SC_EX | SC_SCR_EX); + F_SET(sp, SC_VI); + + /* + * Initialize screen values. + * + * Small windows: see vs_refresh(), section 6a. + * + * Setup: + * t_minrows is the minimum rows to display + * t_maxrows is the maximum rows to display (rows - 1) + * t_rows is the rows currently being displayed + */ + sp->rows = vip->srows = O_VAL(sp, O_LINES); + sp->cols = O_VAL(sp, O_COLUMNS); + sp->t_rows = sp->t_minrows = O_VAL(sp, O_WINDOW); + if (sp->rows != 1) { + if (sp->t_rows > sp->rows - 1) { + sp->t_minrows = sp->t_rows = sp->rows - 1; + msgq(sp, M_INFO, + "214|Windows option value is too large, max is %u", + (u_int)sp->t_rows); + } + sp->t_maxrows = sp->rows - 1; + } else + sp->t_maxrows = 1; + sp->roff = sp->coff = 0; + + /* Create a screen map. */ + CALLOC_RET(sp, HMAP, SIZE_HMAP(sp), sizeof(SMAP)); + TMAP = HMAP + (sp->t_rows - 1); + HMAP->lno = sp->lno; + HMAP->coff = 0; + HMAP->soff = 1; + + /* + * Fill the screen map from scratch -- try and center the line. That + * way if we're starting with a file we've seen before, we'll put the + * line in the middle, otherwise, it won't work and we'll end up with + * the line at the top. + */ + F_SET(sp, SC_SCR_REFORMAT | SC_SCR_CENTER); + + /* Invalidate the cursor. */ + F_SET(vip, VIP_CUR_INVALID); + + /* Paint the screen image from scratch. */ + F_SET(vip, VIP_N_EX_PAINT); + + return (0); +} + +/* + * v_dtoh -- + * Move all but the current screen to the hidden queue. + */ +static void +v_dtoh(SCR *sp) +{ + GS *gp; + SCR *tsp; + int hidden; + + /* Move all screens to the hidden queue, tossing screen maps. */ + for (hidden = 0, gp = sp->gp; + (tsp = TAILQ_FIRST(gp->dq)) != NULL; ++hidden) { + free(_HMAP(tsp)); + _HMAP(tsp) = NULL; + TAILQ_REMOVE(gp->dq, tsp, q); + TAILQ_INSERT_TAIL(gp->hq, tsp, q); + /* XXXX Change if hidden screens per window */ + gp->scr_discard(tsp, NULL); + } + + /* Move current screen back to the display queue. */ + TAILQ_REMOVE(gp->hq, sp, q); + TAILQ_INSERT_TAIL(gp->dq, sp, q); + + if (hidden > 1) + msgq(sp, M_INFO, + "319|%d screens backgrounded; use :display to list them", + hidden - 1); +} + +/* + * v_curword -- + * Get the word (tagstring, actually) the cursor is on. + * + * PUBLIC: int v_curword(SCR *); + */ +int +v_curword(SCR *sp) +{ + VI_PRIVATE *vip; + size_t beg, end, len; + int moved; + CHAR_T *p; + + if (db_get(sp, sp->lno, DBG_FATAL, &p, &len)) + return (1); + + /* + * !!! + * Historically, tag commands skipped over any leading whitespace + * characters. Make this true in general when using cursor words. + * If movement, getting a cursor word implies moving the cursor to + * its beginning. Refresh now. + * + * !!! + * Find the beginning/end of the keyword. Keywords are currently + * used for cursor-word searching and for tags. Historical vi + * only used the word in a tag search from the cursor to the end + * of the word, i.e. if the cursor was on the 'b' in " abc ", the + * tag was "bc". For consistency, we make cursor word searches + * follow the same rule. + */ + for (moved = 0, + beg = sp->cno; beg < len && ISSPACE(p[beg]); moved = 1, ++beg); + if (beg >= len) { + msgq(sp, M_BERR, "212|Cursor not in a word"); + return (1); + } + if (moved) { + sp->cno = beg; + (void)vs_refresh(sp, 0); + } + + /* + * Find the end of the word. + * + * !!! + * Historically, vi accepted any non-blank as initial character + * when building up a tagstring. Required by IEEE 1003.1-2001. + */ + for (end = beg; ++end < len && inword(p[end]);); + + vip = VIP(sp); + vip->klen = len = (end - beg); + BINC_RETW(sp, vip->keyw, vip->keywlen, len+1); + MEMMOVE(vip->keyw, p + beg, len); + vip->keyw[len] = '\0'; /* XXX */ + return (0); +} + +/* + * v_alias -- + * Check for a command alias. + */ +static VIKEYS const * +v_alias( + SCR *sp, + VICMD *vp, + VIKEYS const *kp) +{ + CHAR_T push; + + switch (vp->key) { + case 'C': /* C -> c$ */ + push = '$'; + vp->key = 'c'; + break; + case 'D': /* D -> d$ */ + push = '$'; + vp->key = 'd'; + break; + case 'S': /* S -> c_ */ + push = '_'; + vp->key = 'c'; + break; + case 'Y': /* Y -> y_ */ + push = '_'; + vp->key = 'y'; + break; + default: + return (kp); + } + return (v_event_push(sp, + NULL, &push, 1, CH_NOMAP | CH_QUOTED) ? NULL : &vikeys[vp->key]); +} + +/* + * v_count -- + * Return the next count. + */ +static int +v_count( + SCR *sp, + ARG_CHAR_T fkey, + u_long *countp) +{ + EVENT ev; + u_long count, tc; + + ev.e_c = fkey; + count = tc = 0; + do { + /* + * XXX + * Assume that overflow results in a smaller number. + */ + tc = count * 10 + ev.e_c - '0'; + if (count > tc) { + /* Toss to the next non-digit. */ + do { + if (v_key(sp, 0, &ev, + EC_MAPCOMMAND | EC_MAPNODIGIT) != GC_OK) + return (1); + } while (ISDIGIT(ev.e_c)); + msgq(sp, M_ERR, + "235|Number larger than %lu", ULONG_MAX); + return (1); + } + count = tc; + if (v_key(sp, 0, &ev, EC_MAPCOMMAND | EC_MAPNODIGIT) != GC_OK) + return (1); + } while (ISDIGIT(ev.e_c)); + *countp = count; + return (0); +} + +/* + * v_key -- + * Return the next event. + */ +static gcret_t +v_key( + SCR *sp, + int command_events, + EVENT *evp, + u_int32_t ec_flags) +{ + u_int32_t quote; + + for (quote = 0;;) { + if (v_event_get(sp, evp, 0, ec_flags | quote)) + return (GC_FATAL); + quote = 0; + + switch (evp->e_event) { + case E_CHARACTER: + /* + * !!! + * Historically, ^V was ignored in the command stream, + * although it had a useful side-effect of interrupting + * mappings. Adding a quoting bit to the call probably + * extends historic practice, but it feels right. + */ + if (evp->e_value == K_VLNEXT) { + quote = EC_QUOTED; + break; + } + return (GC_OK); + case E_ERR: + case E_EOF: + return (GC_FATAL); + case E_INTERRUPT: + /* + * !!! + * Historically, vi beeped on command level interrupts. + * + * Historically, vi exited to ex mode if no file was + * named on the command line, and two interrupts were + * generated in a row. (Just figured you might want + * to know that.) + */ + (void)sp->gp->scr_bell(sp); + return (GC_INTERRUPT); + case E_REPAINT: + if (vs_repaint(sp, evp)) + return (GC_FATAL); + break; + case E_WRESIZE: + return (GC_ERR); + default: + v_event_err(sp, evp); + return (GC_ERR); + } + } + /* NOTREACHED */ +} + +#if defined(DEBUG) && defined(COMLOG) +/* + * v_comlog -- + * Log the contents of the command structure. + */ +static void +v_comlog( + SCR *sp, + VICMD *vp) +{ + TRACE(sp, "vcmd: "WC, vp->key); + if (F_ISSET(vp, VC_BUFFER)) + TRACE(sp, " buffer: "WC, vp->buffer); + if (F_ISSET(vp, VC_C1SET)) + TRACE(sp, " c1: %lu", vp->count); + if (F_ISSET(vp, VC_C2SET)) + TRACE(sp, " c2: %lu", vp->count2); + TRACE(sp, " flags: 0x%x\n", vp->flags); +} +#endif Property changes on: vendor/nvi/2.2.0-05ed8b9/vi/vi.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/vi/vs_line.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/vi/vs_line.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/vi/vs_line.c (revision 366308) @@ -0,0 +1,536 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include + +#include "../common/common.h" +#include "vi.h" + +#ifdef VISIBLE_TAB_CHARS +#define TABCH '-' +#else +#define TABCH ' ' +#endif + +/* + * vs_line -- + * Update one line on the screen. + * + * PUBLIC: int vs_line(SCR *, SMAP *, size_t *, size_t *); + */ +int +vs_line(SCR *sp, SMAP *smp, size_t *yp, size_t *xp) +{ + u_char *kp; + GS *gp; + SMAP *tsmp; + size_t chlen = 0, cno_cnt, cols_per_screen, len, nlen; + size_t offset_in_char, offset_in_line, oldx, oldy; + size_t scno, skip_cols, skip_screens; + int dne, is_cached, is_partial, is_tab, no_draw; + int list_tab, list_dollar; + CHAR_T *p; + CHAR_T *cbp, *ecbp, cbuf[128]; + ARG_CHAR_T ch = '\0'; + +#if defined(DEBUG) && 0 + TRACE(sp, "vs_line: row %u: line: %u off: %u\n", + smp - HMAP, smp->lno, smp->off); +#endif + /* + * If ex modifies the screen after ex output is already on the screen, + * don't touch it -- we'll get scrolling wrong, at best. + */ + no_draw = 0; + if (!F_ISSET(sp, SC_TINPUT_INFO) && VIP(sp)->totalcount > 1) + no_draw = 1; + if (F_ISSET(sp, SC_SCR_EXWROTE) && smp - HMAP != LASTLINE(sp)) + no_draw = 1; + + /* + * Assume that, if the cache entry for the line is filled in, the + * line is already on the screen, and all we need to do is return + * the cursor position. If the calling routine doesn't need the + * cursor position, we can just return. + */ + is_cached = SMAP_CACHE(smp); + if (yp == NULL && (is_cached || no_draw)) + return (0); + + /* + * A nasty side effect of this routine is that it returns the screen + * position for the "current" character. Not pretty, but this is the + * only routine that really knows what's out there. + * + * Move to the line. This routine can be called by vs_sm_position(), + * which uses it to fill in the cache entry so it can figure out what + * the real contents of the screen are. Because of this, we have to + * return to whereever we started from. + */ + gp = sp->gp; + (void)gp->scr_cursor(sp, &oldy, &oldx); + (void)gp->scr_move(sp, smp - HMAP, 0); + + /* Get the line. */ + dne = db_get(sp, smp->lno, 0, &p, &len); + + /* + * Special case if we're printing the info/mode line. Skip printing + * the leading number, as well as other minor setup. The only time + * this code paints the mode line is when the user is entering text + * for a ":" command, so we can put the code here instead of dealing + * with the empty line logic below. This is a kludge, but it's pretty + * much confined to this module. + * + * Set the number of columns for this screen. + * Set the number of chars or screens to skip until a character is to + * be displayed. + */ + cols_per_screen = sp->cols; + if (O_ISSET(sp, O_LEFTRIGHT)) { + skip_screens = 0; + skip_cols = smp->coff; + } else { + skip_screens = smp->soff - 1; + skip_cols = skip_screens * cols_per_screen; + } + + list_tab = O_ISSET(sp, O_LIST); + if (F_ISSET(sp, SC_TINPUT_INFO)) + list_dollar = 0; + else { + list_dollar = list_tab; + + /* + * If O_NUMBER is set, the line doesn't exist and it's line + * number 1, i.e., an empty file, display the line number. + * + * If O_NUMBER is set, the line exists and the first character + * on the screen is the first character in the line, display + * the line number. + * + * !!! + * If O_NUMBER set, decrement the number of columns in the + * first screen. DO NOT CHANGE THIS -- IT'S RIGHT! The + * rest of the code expects this to reflect the number of + * columns in the first screen, regardless of the number of + * columns we're going to skip. + */ + if (O_ISSET(sp, O_NUMBER)) { + cols_per_screen -= O_NUMBER_LENGTH; + if ((!dne || smp->lno == 1) && skip_cols == 0) { + nlen = snprintf((char*)cbuf, + sizeof(cbuf), O_NUMBER_FMT, (u_long)smp->lno); + (void)gp->scr_addstr(sp, (char*)cbuf, nlen); + } + } + } + + /* + * Special case non-existent lines and the first line of an empty + * file. In both cases, the cursor position is 0, but corrected + * as necessary for the O_NUMBER field, if it was displayed. + */ + if (dne || len == 0) { + /* Fill in the cursor. */ + if (yp != NULL && smp->lno == sp->lno) { + *yp = smp - HMAP; + *xp = sp->cols - cols_per_screen; + } + + /* If the line is on the screen, quit. */ + if (is_cached || no_draw) + goto ret1; + + /* Set line cache information. */ + smp->c_sboff = smp->c_eboff = 0; + smp->c_scoff = smp->c_eclen = 0; + + /* + * Lots of special cases for empty lines, but they only apply + * if we're displaying the first screen of the line. + */ + if (skip_cols == 0) { + if (dne) { + if (smp->lno == 1) { + if (list_dollar) { + ch = '$'; + goto empty; + } + } else { + ch = '~'; + goto empty; + } + } else { + if (list_dollar) { + ch = '$'; +empty: (void)gp->scr_addstr(sp, + KEY_NAME(sp, ch), KEY_LEN(sp, ch)); + } + } + } + + (void)gp->scr_clrtoeol(sp); + (void)gp->scr_move(sp, oldy, oldx); + return (0); + } + + /* If we shortened this line in another screen, the cursor + * position may have fallen off. + */ + if (sp->lno == smp->lno && sp->cno >= len) + sp->cno = len - 1; + + /* + * If we just wrote this or a previous line, we cached the starting + * and ending positions of that line. The way it works is we keep + * information about the lines displayed in the SMAP. If we're + * painting the screen in the forward direction, this saves us from + * reformatting the physical line for every line on the screen. This + * wins big on binary files with 10K lines. + * + * Test for the first screen of the line, then the current screen line, + * then the line behind us, then do the hard work. Note, it doesn't + * do us any good to have a line in front of us -- it would be really + * hard to try and figure out tabs in the reverse direction, i.e. how + * many spaces a tab takes up in the reverse direction depends on + * what characters preceded it. + * + * Test for the first screen of the line. + */ + if (skip_cols == 0) { + smp->c_sboff = offset_in_line = 0; + smp->c_scoff = offset_in_char = 0; + p = &p[offset_in_line]; + goto display; + } + + /* Test to see if we've seen this exact line before. */ + if (is_cached) { + offset_in_line = smp->c_sboff; + offset_in_char = smp->c_scoff; + p = &p[offset_in_line]; + + /* Set cols_per_screen to 2nd and later line length. */ + if (O_ISSET(sp, O_LEFTRIGHT) || skip_cols > cols_per_screen) + cols_per_screen = sp->cols; + goto display; + } + + /* Test to see if we saw an earlier part of this line before. */ + if (smp != HMAP && + SMAP_CACHE(tsmp = smp - 1) && tsmp->lno == smp->lno) { + if (tsmp->c_eclen != tsmp->c_ecsize) { + offset_in_line = tsmp->c_eboff; + offset_in_char = tsmp->c_eclen; + } else { + offset_in_line = tsmp->c_eboff + 1; + offset_in_char = 0; + } + + /* Put starting info for this line in the cache. */ + smp->c_sboff = offset_in_line; + smp->c_scoff = offset_in_char; + p = &p[offset_in_line]; + + /* Set cols_per_screen to 2nd and later line length. */ + if (O_ISSET(sp, O_LEFTRIGHT) || skip_cols > cols_per_screen) + cols_per_screen = sp->cols; + goto display; + } + + scno = 0; + offset_in_line = 0; + offset_in_char = 0; + + /* Do it the hard way, for leftright scrolling screens. */ + if (O_ISSET(sp, O_LEFTRIGHT)) { + for (; offset_in_line < len; ++offset_in_line) { + chlen = (ch = *p++) == '\t' && !list_tab ? + TAB_OFF(scno) : KEY_COL(sp, ch); + if ((scno += chlen) >= skip_cols) + break; + } + + /* Set cols_per_screen to 2nd and later line length. */ + cols_per_screen = sp->cols; + + /* Put starting info for this line in the cache. */ + if (offset_in_line >= len) { + smp->c_sboff = offset_in_line; + smp->c_scoff = 255; + } else if (scno != skip_cols) { + smp->c_sboff = offset_in_line; + smp->c_scoff = + offset_in_char = chlen - (scno - skip_cols); + --p; + } else { + smp->c_sboff = ++offset_in_line; + smp->c_scoff = 0; + } + } + + /* Do it the hard way, for historic line-folding screens. */ + else { + for (; offset_in_line < len; ++offset_in_line) { + chlen = (ch = *p++) == '\t' && !list_tab ? + TAB_OFF(scno) : KEY_COL(sp, ch); + if ((scno += chlen) < cols_per_screen) + continue; + scno -= cols_per_screen; + + /* Set cols_per_screen to 2nd and later line length. */ + cols_per_screen = sp->cols; + + /* + * If crossed the last skipped screen boundary, start + * displaying the characters. + */ + if (--skip_screens == 0) + break; + } + + /* Put starting info for this line in the cache. */ + if (scno != 0) { + smp->c_sboff = offset_in_line; + smp->c_scoff = offset_in_char = chlen - scno; + --p; + } else { + smp->c_sboff = ++offset_in_line; + smp->c_scoff = 0; + } + } + +display: + /* + * Set the number of characters to skip before reaching the cursor + * character. Offset by 1 and use 0 as a flag value. Vs_line is + * called repeatedly with a valid pointer to a cursor position. + * Don't fill anything in unless it's the right line and the right + * character, and the right part of the character... + */ + if (yp == NULL || + smp->lno != sp->lno || sp->cno < offset_in_line || + offset_in_line + cols_per_screen < sp->cno) { + cno_cnt = 0; + /* If the line is on the screen, quit. */ + if (is_cached || no_draw) + goto ret1; + } else + cno_cnt = (sp->cno - offset_in_line) + 1; + + /* This is the loop that actually displays characters. */ + ecbp = (cbp = cbuf) + SIZE(cbuf) - 1; + for (is_partial = 0, scno = 0; + offset_in_line < len; ++offset_in_line, offset_in_char = 0) { + if ((ch = *p++) == '\t' && !list_tab) { + scno += chlen = TAB_OFF(scno) - offset_in_char; + is_tab = 1; + } else { + scno += chlen = KEY_COL(sp, ch) - offset_in_char; + is_tab = 0; + } + + /* + * Only display up to the right-hand column. Set a flag if + * the entire character wasn't displayed for use in setting + * the cursor. If reached the end of the line, set the cache + * info for the screen. Don't worry about there not being + * characters to display on the next screen, its lno/off won't + * match up in that case. + */ + if (scno >= cols_per_screen) { + if (is_tab == 1) { + chlen -= scno - cols_per_screen; + smp->c_ecsize = smp->c_eclen = chlen; + scno = cols_per_screen; + } else { + smp->c_ecsize = chlen; + chlen -= scno - cols_per_screen; + smp->c_eclen = chlen; + + if (scno > cols_per_screen) + is_partial = 1; + } + smp->c_eboff = offset_in_line; + + /* Terminate the loop. */ + offset_in_line = len; + } + + /* + * If the caller wants the cursor value, and this was the + * cursor character, set the value. There are two ways to + * put the cursor on a character -- if it's normal display + * mode, it goes on the last column of the character. If + * it's input mode, it goes on the first. In normal mode, + * set the cursor only if the entire character was displayed. + */ + if (cno_cnt && + --cno_cnt == 0 && (F_ISSET(sp, SC_TINPUT) || !is_partial)) { + *yp = smp - HMAP; + if (F_ISSET(sp, SC_TINPUT)) + if (is_partial) + *xp = scno - smp->c_ecsize; + else + *xp = scno - chlen; + else + *xp = scno - 1; + if (O_ISSET(sp, O_NUMBER) && + !F_ISSET(sp, SC_TINPUT_INFO) && skip_cols == 0) + *xp += O_NUMBER_LENGTH; + + /* If the line is on the screen, quit. */ + if (is_cached || no_draw) + goto ret1; + } + + /* If the line is on the screen, don't display anything. */ + if (is_cached || no_draw) + continue; + +#define FLUSH do { \ + *cbp = '\0'; \ + (void)gp->scr_waddstr(sp, cbuf, cbp - cbuf); \ + cbp = cbuf; \ +} while (0) + /* + * Display the character. We do tab expansion here because + * the screen interface doesn't have any way to set the tab + * length. Note, it's theoretically possible for chlen to + * be larger than cbuf, if the user set a impossibly large + * tabstop. + */ + if (is_tab) + while (chlen--) { + if (cbp >= ecbp) + FLUSH; + *cbp++ = TABCH; + } + else { + if (cbp + chlen >= ecbp) + FLUSH; + + /* don't display half a wide character */ + if (is_partial && CHAR_WIDTH(sp, ch) > 1) { + *cbp++ = ' '; + break; + } + + if (KEY_NEEDSWIDE(sp, ch)) + *cbp++ = ch; + else + for (kp = (u_char *) + KEY_NAME(sp, ch) + offset_in_char; + chlen--;) + *cbp++ = *kp++; + } + } + + if (scno < cols_per_screen) { + /* If didn't paint the whole line, update the cache. */ + smp->c_ecsize = smp->c_eclen = KEY_COL(sp, ch); + smp->c_eboff = len - 1; + + /* + * If not the info/mode line, and O_LIST set, and at the + * end of the line, and the line ended on this screen, + * add a trailing $. + */ + if (list_dollar) { + ++scno; + + chlen = KEY_LEN(sp, '$'); + if (cbp + chlen >= ecbp) + FLUSH; + for (kp = (u_char *) + KEY_NAME(sp, '$'); chlen--;) + *cbp++ = *kp++; + } + + /* If still didn't paint the whole line, clear the rest. */ + if (scno < cols_per_screen) + (void)gp->scr_clrtoeol(sp); + } + + /* Flush any buffered characters. */ + if (cbp > cbuf) + FLUSH; + +ret1: (void)gp->scr_move(sp, oldy, oldx); + return (0); +} + +/* + * vs_number -- + * Repaint the numbers on all the lines. + * + * PUBLIC: int vs_number(SCR *); + */ +int +vs_number(SCR *sp) +{ + GS *gp; + SMAP *smp; + VI_PRIVATE *vip; + size_t len, oldy, oldx; + int exist; + char nbuf[10]; + + gp = sp->gp; + vip = VIP(sp); + + /* No reason to do anything if we're in input mode on the info line. */ + if (F_ISSET(sp, SC_TINPUT_INFO)) + return (0); + + /* + * Try and avoid getting the last line in the file, by getting the + * line after the last line in the screen -- if it exists, we know + * we have to to number all the lines in the screen. Get the one + * after the last instead of the last, so that the info line doesn't + * fool us. (The problem is that file_lline will lie, and tell us + * that the info line is the last line in the file.) If that test + * fails, we have to check each line for existence. + */ + exist = db_exist(sp, TMAP->lno + 1); + + (void)gp->scr_cursor(sp, &oldy, &oldx); + for (smp = HMAP; smp <= TMAP; ++smp) { + /* Numbers are only displayed for the first screen line. */ + if (O_ISSET(sp, O_LEFTRIGHT)) { + if (smp->coff != 0) + continue; + } else + if (smp->soff != 1) + continue; + + /* + * The first line of an empty file gets numbered, otherwise + * number any existing line. + */ + if (smp->lno != 1 && !exist && !db_exist(sp, smp->lno)) + break; + + (void)gp->scr_move(sp, smp - HMAP, 0); + len = snprintf(nbuf, sizeof(nbuf), O_NUMBER_FMT, (u_long)smp->lno); + (void)gp->scr_addstr(sp, nbuf, len); + } + (void)gp->scr_move(sp, oldy, oldx); + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/vi/vs_line.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/vi/vs_msg.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/vi/vs_msg.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/vi/vs_msg.c (revision 366308) @@ -0,0 +1,898 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "../common/common.h" +#include "vi.h" + +typedef enum { + SCROLL_W, /* User wait. */ + SCROLL_W_EX, /* User wait, or enter : to continue. */ + SCROLL_W_QUIT /* User wait, or enter q to quit. */ + /* + * SCROLL_W_QUIT has another semantic + * -- only wait if the screen is full + */ +} sw_t; + +static void vs_divider(SCR *); +static void vs_msgsave(SCR *, mtype_t, char *, size_t); +static void vs_output(SCR *, mtype_t, const char *, int); +static void vs_scroll(SCR *, int *, sw_t); +static void vs_wait(SCR *, int *, sw_t); + +/* + * vs_busy -- + * Display, update or clear a busy message. + * + * This routine is the default editor interface for vi busy messages. It + * implements a standard strategy of stealing lines from the bottom of the + * vi text screen. Screens using an alternate method of displaying busy + * messages, e.g. X11 clock icons, should set their scr_busy function to the + * correct function before calling the main editor routine. + * + * PUBLIC: void vs_busy(SCR *, const char *, busy_t); + */ +void +vs_busy(SCR *sp, const char *msg, busy_t btype) +{ + GS *gp; + VI_PRIVATE *vip; + static const char flagc[] = "|/-\\"; + struct timespec ts, ts_diff; + const struct timespec ts_min = { 0, 125000000 }; + size_t len, notused; + const char *p; + + /* Ex doesn't display busy messages. */ + if (F_ISSET(sp, SC_EX | SC_SCR_EXWROTE)) + return; + + gp = sp->gp; + vip = VIP(sp); + + /* + * Most of this routine is to deal with the screen sharing real estate + * between the normal edit messages and the busy messages. Logically, + * all that's needed is something that puts up a message, periodically + * updates it, and then goes away. + */ + switch (btype) { + case BUSY_ON: + ++vip->busy_ref; + if (vip->totalcount != 0 || vip->busy_ref != 1) + break; + + /* Initialize state for updates. */ + vip->busy_ch = 0; + timepoint_steady(&vip->busy_ts); + + /* Save the current cursor. */ + (void)gp->scr_cursor(sp, &vip->busy_oldy, &vip->busy_oldx); + + /* Display the busy message. */ + p = msg_cat(sp, msg, &len); + (void)gp->scr_move(sp, LASTLINE(sp), 0); + (void)gp->scr_addstr(sp, p, len); + (void)gp->scr_cursor(sp, ¬used, &vip->busy_fx); + (void)gp->scr_clrtoeol(sp); + (void)gp->scr_move(sp, LASTLINE(sp), vip->busy_fx); + break; + case BUSY_OFF: + if (vip->busy_ref == 0) + break; + --vip->busy_ref; + + /* + * If the line isn't in use for another purpose, clear it. + * Always return to the original position. + */ + if (vip->totalcount == 0 && vip->busy_ref == 0) { + (void)gp->scr_move(sp, LASTLINE(sp), 0); + (void)gp->scr_clrtoeol(sp); + } + (void)gp->scr_move(sp, vip->busy_oldy, vip->busy_oldx); + break; + case BUSY_UPDATE: + if (vip->totalcount != 0 || vip->busy_ref == 0) + break; + + /* Update no more than every 1/8 of a second. */ + timepoint_steady(&ts); + ts_diff = ts; + timespecsub(&ts_diff, &vip->busy_ts); + if (timespeccmp(&ts_diff, &ts_min, <)) + return; + vip->busy_ts = ts; + + /* Display the update. */ + if (vip->busy_ch == sizeof(flagc) - 1) + vip->busy_ch = 0; + (void)gp->scr_move(sp, LASTLINE(sp), vip->busy_fx); + (void)gp->scr_addstr(sp, flagc + vip->busy_ch++, 1); + (void)gp->scr_move(sp, LASTLINE(sp), vip->busy_fx); + break; + } + (void)gp->scr_refresh(sp, 0); +} + +/* + * vs_home -- + * Home the cursor to the bottom row, left-most column. + * + * PUBLIC: void vs_home(SCR *); + */ +void +vs_home(SCR *sp) +{ + (void)sp->gp->scr_move(sp, LASTLINE(sp), 0); + (void)sp->gp->scr_refresh(sp, 0); +} + +/* + * vs_update -- + * Update a command. + * + * PUBLIC: void vs_update(SCR *, const char *, const CHAR_T *); + */ +void +vs_update(SCR *sp, const char *m1, const CHAR_T *m2) +{ + GS *gp; + size_t len, mlen, oldx, oldy; + CONST char *np; + size_t nlen; + + gp = sp->gp; + + /* + * This routine displays a message on the bottom line of the screen, + * without updating any of the command structures that would keep it + * there for any period of time, i.e. it is overwritten immediately. + * + * It's used by the ex read and ! commands when the user's command is + * expanded, and by the ex substitution confirmation prompt. + */ + if (F_ISSET(sp, SC_SCR_EXWROTE)) { + if (m2 != NULL) + INT2CHAR(sp, m2, STRLEN(m2) + 1, np, nlen); + (void)ex_printf(sp, + "%s\n", m1 == NULL? "" : m1, m2 == NULL ? "" : np); + (void)ex_fflush(sp); + } + + /* + * Save the cursor position, the substitute-with-confirmation code + * will have already set it correctly. + */ + (void)gp->scr_cursor(sp, &oldy, &oldx); + + /* Clear the bottom line. */ + (void)gp->scr_move(sp, LASTLINE(sp), 0); + (void)gp->scr_clrtoeol(sp); + + /* + * XXX + * Don't let long file names screw up the screen. + */ + if (m1 != NULL) { + mlen = len = strlen(m1); + if (len > sp->cols - 2) + mlen = len = sp->cols - 2; + (void)gp->scr_addstr(sp, m1, mlen); + } else + len = 0; + if (m2 != NULL) { + mlen = STRLEN(m2); + if (len + mlen > sp->cols - 2) + mlen = (sp->cols - 2) - len; + (void)gp->scr_waddstr(sp, m2, mlen); + } + + (void)gp->scr_move(sp, oldy, oldx); + (void)gp->scr_refresh(sp, 0); +} + +/* + * vs_msg -- + * Display ex output or error messages for the screen. + * + * This routine is the default editor interface for all ex output, and all ex + * and vi error/informational messages. It implements the standard strategy + * of stealing lines from the bottom of the vi text screen. Screens using an + * alternate method of displaying messages, e.g. dialog boxes, should set their + * scr_msg function to the correct function before calling the editor. + * + * PUBLIC: void vs_msg(SCR *, mtype_t, char *, size_t); + */ +void +vs_msg(SCR *sp, mtype_t mtype, char *line, size_t len) +{ + GS *gp; + VI_PRIVATE *vip; + size_t maxcols, oldx, oldy, padding; + const char *e, *s, *t; + + gp = sp->gp; + vip = VIP(sp); + + /* + * Ring the bell if it's scheduled. + * + * XXX + * Shouldn't we save this, too? + */ + if (F_ISSET(sp, SC_TINPUT_INFO) || F_ISSET(gp, G_BELLSCHED)) { + if (F_ISSET(sp, SC_SCR_VI)) { + F_CLR(gp, G_BELLSCHED); + (void)gp->scr_bell(sp); + } else + F_SET(gp, G_BELLSCHED); + } + + /* + * If vi is using the error line for text input, there's no screen + * real-estate for the error message. Nothing to do without some + * information as to how important the error message is. + */ + if (F_ISSET(sp, SC_TINPUT_INFO)) + return; + + /* + * Ex or ex controlled screen output. + * + * If output happens during startup, e.g., a .exrc file, we may be + * in ex mode but haven't initialized the screen. Initialize here, + * and in this case, stay in ex mode. + * + * If the SC_SCR_EXWROTE bit is set, then we're switching back and + * forth between ex and vi, but the screen is trashed and we have + * to respect that. Switch to ex mode long enough to put out the + * message. + * + * If the SC_EX_WAIT_NO bit is set, turn it off -- we're writing to + * the screen, so previous opinions are ignored. + */ + if (F_ISSET(sp, SC_EX | SC_SCR_EXWROTE)) { + if (!F_ISSET(sp, SC_SCR_EX)) { + if (F_ISSET(sp, SC_SCR_EXWROTE)) { + if (sp->gp->scr_screen(sp, SC_EX)) + return; + } else + if (ex_init(sp)) + return; + } + + if (mtype == M_ERR) + (void)gp->scr_attr(sp, SA_INVERSE, 1); + (void)printf("%.*s", (int)len, line); + if (mtype == M_ERR) + (void)gp->scr_attr(sp, SA_INVERSE, 0); + (void)fflush(stdout); + + F_CLR(sp, SC_EX_WAIT_NO); + + if (!F_ISSET(sp, SC_SCR_EX)) + (void)sp->gp->scr_screen(sp, SC_VI); + return; + } + + /* If the vi screen isn't ready, save the message. */ + if (!F_ISSET(sp, SC_SCR_VI)) { + (void)vs_msgsave(sp, mtype, line, len); + return; + } + + /* Save the cursor position. */ + (void)gp->scr_cursor(sp, &oldy, &oldx); + + /* If it's an ex output message, just write it out. */ + if (mtype == M_NONE) { + vs_output(sp, mtype, line, len); + goto ret; + } + + /* + * If it's a vi message, strip the trailing so we can + * try and paste messages together. + */ + if (line[len - 1] == '\n') + --len; + + /* + * If a message won't fit on a single line, try to split on a . + * If a subsequent message fits on the same line, write a separator + * and output it. Otherwise, put out a newline. + * + * Need up to two padding characters normally; a semi-colon and a + * separating space. If only a single line on the screen, add some + * more for the trailing continuation message. + * + * XXX + * Assume that periods and semi-colons take up a single column on the + * screen. + * + * XXX + * There are almost certainly pathological cases that will break this + * code. + */ + if (IS_ONELINE(sp)) + (void)msg_cmsg(sp, CMSG_CONT_S, &padding); + else + padding = 0; + padding += 2; + + maxcols = sp->cols - 1; + if (vip->lcontinue != 0) { + if (len + vip->lcontinue + padding > maxcols) + vs_output(sp, vip->mtype, ".\n", 2); + else { + vs_output(sp, vip->mtype, ";", 1); + vs_output(sp, M_NONE, " ", 1); + } + } + vip->mtype = mtype; + for (s = line;; s = t) { + for (; len > 0 && isblank((u_char)*s); --len, ++s); + if (len == 0) + break; + if (len + vip->lcontinue > maxcols) { + for (e = s + (maxcols - vip->lcontinue); + e > s && !isblank((u_char)*e); --e); + if (e == s) + e = t = s + (maxcols - vip->lcontinue); + else + for (t = e; isblank((u_char)e[-1]); --e); + } else + e = t = s + len; + + /* + * If the message ends in a period, discard it, we want to + * gang messages where possible. + */ + len -= t - s; + if (len == 0 && (e - s) > 1 && s[(e - s) - 1] == '.') + --e; + vs_output(sp, mtype, s, e - s); + + if (len != 0) + vs_output(sp, M_NONE, "\n", 1); + + if (INTERRUPTED(sp)) + break; + } + +ret: (void)gp->scr_move(sp, oldy, oldx); + (void)gp->scr_refresh(sp, 0); +} + +/* + * vs_output -- + * Output the text to the screen. + */ +static void +vs_output(SCR *sp, mtype_t mtype, const char *line, int llen) +{ + GS *gp; + VI_PRIVATE *vip; + size_t notused; + int len, rlen, tlen; + const char *p, *t; + char *cbp, *ecbp, cbuf[128]; + + gp = sp->gp; + vip = VIP(sp); + for (p = line, rlen = llen; llen > 0;) { + /* Get the next physical line. */ + if ((p = memchr(line, '\n', llen)) == NULL) + len = llen; + else + len = p - line; + + /* + * The max is sp->cols characters, and we may have already + * written part of the line. + */ + if (len + vip->lcontinue > sp->cols) + len = sp->cols - vip->lcontinue; + + /* + * If the first line output, do nothing. If the second line + * output, draw the divider line. If drew a full screen, we + * remove the divider line. If it's a continuation line, move + * to the continuation point, else, move the screen up. + */ + if (vip->lcontinue == 0) { + if (!IS_ONELINE(sp)) { + if (vip->totalcount == 1) { + (void)gp->scr_move(sp, + LASTLINE(sp) - 1, 0); + (void)gp->scr_clrtoeol(sp); + (void)vs_divider(sp); + F_SET(vip, VIP_DIVIDER); + ++vip->totalcount; + ++vip->linecount; + } + if (vip->totalcount == sp->t_maxrows && + F_ISSET(vip, VIP_DIVIDER)) { + --vip->totalcount; + --vip->linecount; + F_CLR(vip, VIP_DIVIDER); + } + } + if (vip->totalcount != 0) + vs_scroll(sp, NULL, SCROLL_W_QUIT); + + (void)gp->scr_move(sp, LASTLINE(sp), 0); + ++vip->totalcount; + ++vip->linecount; + + if (INTERRUPTED(sp)) + break; + } else + (void)gp->scr_move(sp, LASTLINE(sp), vip->lcontinue); + + /* Error messages are in inverse video. */ + if (mtype == M_ERR) + (void)gp->scr_attr(sp, SA_INVERSE, 1); + + /* Display the line, doing character translation. */ +#define FLUSH do { \ + *cbp = '\0'; \ + (void)gp->scr_addstr(sp, cbuf, cbp - cbuf); \ + cbp = cbuf; \ +} while (0) + ecbp = (cbp = cbuf) + sizeof(cbuf) - 1; + for (t = line, tlen = len; tlen--; ++t) { + /* + * Replace tabs with spaces, there are places in + * ex that do column calculations without looking + * at -- and all routines that care about + * do their own expansions. This catches + * in things like tag search strings. + */ + if (cbp + 1 >= ecbp) + FLUSH; + *cbp++ = *t == '\t' ? ' ' : *t; + } + if (cbp > cbuf) + FLUSH; + if (mtype == M_ERR) + (void)gp->scr_attr(sp, SA_INVERSE, 0); + + /* Clear the rest of the line. */ + (void)gp->scr_clrtoeol(sp); + + /* If we loop, it's a new line. */ + vip->lcontinue = 0; + + /* Reset for the next line. */ + line += len; + llen -= len; + if (p != NULL) { + ++line; + --llen; + } + } + + /* Set up next continuation line. */ + if (p == NULL) + gp->scr_cursor(sp, ¬used, &vip->lcontinue); +} + +/* + * vs_ex_resolve -- + * Deal with ex message output. + * + * This routine is called when exiting a colon command to resolve any ex + * output that may have occurred. + * + * PUBLIC: int vs_ex_resolve(SCR *, int *); + */ +int +vs_ex_resolve(SCR *sp, int *continuep) +{ + EVENT ev; + GS *gp; + VI_PRIVATE *vip; + sw_t wtype; + + gp = sp->gp; + vip = VIP(sp); + *continuep = 0; + + /* If we ran any ex command, we can't trust the cursor position. */ + F_SET(vip, VIP_CUR_INVALID); + + /* Terminate any partially written message. */ + if (vip->lcontinue != 0) { + vs_output(sp, vip->mtype, ".", 1); + vip->lcontinue = 0; + + vip->mtype = M_NONE; + } + + /* + * If we switched out of the vi screen into ex, switch back while we + * figure out what to do with the screen and potentially get another + * command to execute. + * + * If we didn't switch into ex, we're not required to wait, and less + * than 2 lines of output, we can continue without waiting for the + * wait. + * + * Note, all other code paths require waiting, so we leave the report + * of modified lines until later, so that we won't wait for no other + * reason than a threshold number of lines were modified. This means + * we display cumulative line modification reports for groups of ex + * commands. That seems right to me (well, at least not wrong). + */ + if (F_ISSET(sp, SC_SCR_EXWROTE)) { + if (sp->gp->scr_screen(sp, SC_VI)) + return (1); + } else + if (!F_ISSET(sp, SC_EX_WAIT_YES) && vip->totalcount < 2) { + F_CLR(sp, SC_EX_WAIT_NO); + return (0); + } + + /* Clear the required wait flag, it's no longer needed. */ + F_CLR(sp, SC_EX_WAIT_YES); + + /* + * Wait, unless explicitly told not to wait or the user interrupted + * the command. If the user is leaving the screen, for any reason, + * they can't continue with further ex commands. + */ + if (!F_ISSET(sp, SC_EX_WAIT_NO) && !INTERRUPTED(sp)) { + wtype = F_ISSET(sp, SC_EXIT | SC_EXIT_FORCE | + SC_FSWITCH | SC_SSWITCH) ? SCROLL_W : SCROLL_W_EX; + if (F_ISSET(sp, SC_SCR_EXWROTE)) + vs_wait(sp, continuep, wtype); + else + vs_scroll(sp, continuep, wtype); + if (*continuep) + return (0); + } + + /* If ex wrote on the screen, refresh the screen image. */ + if (F_ISSET(sp, SC_SCR_EXWROTE)) + F_SET(vip, VIP_N_EX_PAINT); + + /* + * If we're not the bottom of the split screen stack, the screen + * image itself is wrong, so redraw everything. + */ + if (TAILQ_NEXT(sp, q) != NULL) + F_SET(sp, SC_SCR_REDRAW); + + /* If ex changed the underlying file, the map itself is wrong. */ + if (F_ISSET(vip, VIP_N_EX_REDRAW)) + F_SET(sp, SC_SCR_REFORMAT); + + /* Ex may have switched out of the alternate screen, return. */ + (void)gp->scr_attr(sp, SA_ALTERNATE, 1); + + /* + * Whew. We're finally back home, after what feels like years. + * Kiss the ground. + */ + F_CLR(sp, SC_SCR_EXWROTE | SC_EX_WAIT_NO); + + /* + * We may need to repaint some of the screen, e.g.: + * + * :set + * :!ls + * + * gives us a combination of some lines that are "wrong", and a need + * for a full refresh. + */ + if (vip->totalcount > 1) { + /* Set up the redraw of the overwritten lines. */ + ev.e_event = E_REPAINT; + ev.e_flno = vip->totalcount >= + sp->rows ? 1 : sp->rows - vip->totalcount; + ev.e_tlno = sp->rows; + + /* Reset the count of overwriting lines. */ + vip->linecount = vip->lcontinue = vip->totalcount = 0; + + /* Redraw. */ + (void)vs_repaint(sp, &ev); + } else + /* Reset the count of overwriting lines. */ + vip->linecount = vip->lcontinue = vip->totalcount = 0; + + return (0); +} + +/* + * vs_resolve -- + * Deal with message output. + * + * PUBLIC: int vs_resolve(SCR *, SCR *, int); + */ +int +vs_resolve(SCR *sp, SCR *csp, int forcewait) +{ + EVENT ev; + GS *gp; + MSGS *mp; + VI_PRIVATE *vip; + size_t oldy, oldx; + int redraw; + + /* + * Vs_resolve is called from the main vi loop and the refresh function + * to periodically ensure that the user has seen any messages that have + * been displayed and that any status lines are correct. The sp screen + * is the screen we're checking, usually the current screen. When it's + * not, csp is the current screen, used for final cursor positioning. + */ + gp = sp->gp; + vip = VIP(sp); + if (csp == NULL) + csp = sp; + + /* Save the cursor position. */ + (void)gp->scr_cursor(csp, &oldy, &oldx); + + /* Ring the bell if it's scheduled. */ + if (F_ISSET(gp, G_BELLSCHED)) { + F_CLR(gp, G_BELLSCHED); + (void)gp->scr_bell(sp); + } + + /* Display new file status line. */ + if (F_ISSET(sp, SC_STATUS)) { + F_CLR(sp, SC_STATUS); + msgq_status(sp, sp->lno, MSTAT_TRUNCATE); + } + + /* Report on line modifications. */ + mod_rpt(sp); + + /* + * Flush any saved messages. If the screen isn't ready, refresh + * it. (A side-effect of screen refresh is that we can display + * messages.) Once this is done, don't trust the cursor. That + * extra refresh screwed the pooch. + */ + if (!SLIST_EMPTY(gp->msgq)) { + if (!F_ISSET(sp, SC_SCR_VI) && vs_refresh(sp, 1)) + return (1); + while ((mp = SLIST_FIRST(gp->msgq)) != NULL) { + gp->scr_msg(sp, mp->mtype, mp->buf, mp->len); + SLIST_REMOVE_HEAD(gp->msgq, q); + free(mp->buf); + free(mp); + } + F_SET(vip, VIP_CUR_INVALID); + } + + switch (vip->totalcount) { + case 0: + redraw = 0; + break; + case 1: + /* + * If we're switching screens, we have to wait for messages, + * regardless. If we don't wait, skip updating the modeline. + */ + if (forcewait) + vs_scroll(sp, NULL, SCROLL_W); + else + F_SET(vip, VIP_S_MODELINE); + + redraw = 0; + break; + default: + /* + * If >1 message line in use, prompt the user to continue and + * repaint overwritten lines. + */ + vs_scroll(sp, NULL, SCROLL_W); + + ev.e_event = E_REPAINT; + ev.e_flno = vip->totalcount >= + sp->rows ? 1 : sp->rows - vip->totalcount; + ev.e_tlno = sp->rows; + + redraw = 1; + break; + } + + /* Reset the count of overwriting lines. */ + vip->linecount = vip->lcontinue = vip->totalcount = 0; + + /* Redraw. */ + if (redraw) + (void)vs_repaint(sp, &ev); + + /* Restore the cursor position. */ + (void)gp->scr_move(csp, oldy, oldx); + + return (0); +} + +/* + * vs_scroll -- + * Scroll the screen for output. + */ +static void +vs_scroll(SCR *sp, int *continuep, sw_t wtype) +{ + GS *gp; + VI_PRIVATE *vip; + + gp = sp->gp; + vip = VIP(sp); + if (!IS_ONELINE(sp)) { + /* + * Scroll the screen. Instead of scrolling the entire screen, + * delete the line above the first line output so preserve the + * maximum amount of the screen. + */ + (void)gp->scr_move(sp, vip->totalcount < + sp->rows ? LASTLINE(sp) - vip->totalcount : 0, 0); + (void)gp->scr_deleteln(sp); + + /* If there are screens below us, push them back into place. */ + if (TAILQ_NEXT(sp, q) != NULL) { + (void)gp->scr_move(sp, LASTLINE(sp), 0); + (void)gp->scr_insertln(sp); + } + } + if (wtype == SCROLL_W_QUIT && vip->linecount < sp->t_maxrows) + return; + vs_wait(sp, continuep, wtype); +} + +/* + * vs_wait -- + * Prompt the user to continue. + */ +static void +vs_wait(SCR *sp, int *continuep, sw_t wtype) +{ + EVENT ev; + VI_PRIVATE *vip; + const char *p; + GS *gp; + size_t len; + + gp = sp->gp; + vip = VIP(sp); + + (void)gp->scr_move(sp, LASTLINE(sp), 0); + if (IS_ONELINE(sp)) + p = msg_cmsg(sp, CMSG_CONT_S, &len); + else + switch (wtype) { + case SCROLL_W_QUIT: + p = msg_cmsg(sp, CMSG_CONT_Q, &len); + break; + case SCROLL_W_EX: + p = msg_cmsg(sp, CMSG_CONT_EX, &len); + break; + case SCROLL_W: + p = msg_cmsg(sp, CMSG_CONT, &len); + break; + default: + abort(); + /* NOTREACHED */ + } + (void)gp->scr_addstr(sp, p, len); + + ++vip->totalcount; + vip->linecount = 0; + + (void)gp->scr_clrtoeol(sp); + (void)gp->scr_refresh(sp, 0); + + /* Get a single character from the terminal. */ + if (continuep != NULL) + *continuep = 0; + for (;;) { + if (v_event_get(sp, &ev, 0, 0)) + return; + if (ev.e_event == E_CHARACTER) + break; + if (ev.e_event == E_INTERRUPT) { + ev.e_c = CH_QUIT; + F_SET(gp, G_INTERRUPTED); + break; + } + (void)gp->scr_bell(sp); + } + switch (wtype) { + case SCROLL_W_QUIT: + if (ev.e_c == CH_QUIT) + F_SET(gp, G_INTERRUPTED); + break; + case SCROLL_W_EX: + if (ev.e_c == ':' && continuep != NULL) + *continuep = 1; + break; + case SCROLL_W: + break; + } +} + +/* + * vs_divider -- + * Draw a dividing line between the screen and the output. + */ +static void +vs_divider(SCR *sp) +{ + GS *gp; + size_t len; + +#define DIVIDESTR "+=+=+=+=+=+=+=+" + len = + sizeof(DIVIDESTR) - 1 > sp->cols ? sp->cols : sizeof(DIVIDESTR) - 1; + gp = sp->gp; + (void)gp->scr_attr(sp, SA_INVERSE, 1); + (void)gp->scr_addstr(sp, DIVIDESTR, len); + (void)gp->scr_attr(sp, SA_INVERSE, 0); +} + +/* + * vs_msgsave -- + * Save a message for later display. + */ +static void +vs_msgsave(SCR *sp, mtype_t mt, char *p, size_t len) +{ + GS *gp; + MSGS *mp_c, *mp_n; + + /* + * We have to handle messages before we have any place to put them. + * If there's no screen support yet, allocate a msg structure, copy + * in the message, and queue it on the global structure. If we can't + * allocate memory here, we're genuinely screwed, dump the message + * to stderr in the (probably) vain hope that someone will see it. + */ + CALLOC_GOTO(sp, mp_n, 1, sizeof(MSGS)); + MALLOC_GOTO(sp, mp_n->buf, len); + + memmove(mp_n->buf, p, len); + mp_n->len = len; + mp_n->mtype = mt; + + gp = sp->gp; + if (SLIST_EMPTY(gp->msgq)) { + SLIST_INSERT_HEAD(gp->msgq, mp_n, q); + } else { + SLIST_FOREACH(mp_c, gp->msgq, q) + if (SLIST_NEXT(mp_c, q) == NULL) + break; + SLIST_INSERT_AFTER(mp_c, mp_n, q); + } + return; + +alloc_err: + free(mp_n); + (void)fprintf(stderr, "%.*s\n", (int)len, p); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/vi/vs_msg.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/vi/vs_refresh.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/vi/vs_refresh.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/vi/vs_refresh.c (revision 366308) @@ -0,0 +1,886 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "../common/common.h" +#include "vi.h" + +#define UPDATE_CURSOR 0x01 /* Update the cursor. */ +#define UPDATE_SCREEN 0x02 /* Flush to screen. */ + +static void vs_modeline(SCR *); +static int vs_paint(SCR *, u_int); + +/* + * v_repaint -- + * Repaint selected lines from the screen. + * + * PUBLIC: int vs_repaint(SCR *, EVENT *); + */ +int +vs_repaint( + SCR *sp, + EVENT *evp) +{ + SMAP *smp; + + for (; evp->e_flno <= evp->e_tlno; ++evp->e_flno) { + smp = HMAP + evp->e_flno - 1; + SMAP_FLUSH(smp); + if (vs_line(sp, smp, NULL, NULL)) + return (1); + } + return (0); +} + +/* + * vs_refresh -- + * Refresh all screens. + * + * PUBLIC: int vs_refresh(SCR *, int); + */ +int +vs_refresh( + SCR *sp, + int forcepaint) +{ + GS *gp; + SCR *tsp; + int need_refresh = 0; + u_int priv_paint, pub_paint; + + gp = sp->gp; + + /* + * 1: Refresh the screen. + * + * If SC_SCR_REDRAW is set in the current screen, repaint everything + * that we can find, including status lines. + */ + if (F_ISSET(sp, SC_SCR_REDRAW)) + TAILQ_FOREACH(tsp, gp->dq, q) + if (tsp != sp) + F_SET(tsp, SC_SCR_REDRAW | SC_STATUS); + + /* + * 2: Related or dirtied screens, or screens with messages. + * + * If related screens share a view into a file, they may have been + * modified as well. Refresh any screens that aren't exiting that + * have paint or dirty bits set. Always update their screens, we + * are not likely to get another chance. Finally, if we refresh any + * screens other than the current one, the cursor will be trashed. + */ + pub_paint = SC_SCR_REFORMAT | SC_SCR_REDRAW; + priv_paint = VIP_CUR_INVALID | VIP_N_REFRESH; + if (O_ISSET(sp, O_NUMBER)) + priv_paint |= VIP_N_RENUMBER; + TAILQ_FOREACH(tsp, gp->dq, q) + if (tsp != sp && !F_ISSET(tsp, SC_EXIT | SC_EXIT_FORCE) && + (F_ISSET(tsp, pub_paint) || + F_ISSET(VIP(tsp), priv_paint))) { + (void)vs_paint(tsp, + (F_ISSET(VIP(tsp), VIP_CUR_INVALID) ? + UPDATE_CURSOR : 0) | UPDATE_SCREEN); + F_SET(VIP(sp), VIP_CUR_INVALID); + } + + /* + * 3: Refresh the current screen. + * + * Always refresh the current screen, it may be a cursor movement. + * Also, always do it last -- that way, SC_SCR_REDRAW can be set + * in the current screen only, and the screen won't flash. + */ + if (vs_paint(sp, UPDATE_CURSOR | (!forcepaint && + F_ISSET(sp, SC_SCR_VI) && KEYS_WAITING(sp) ? 0 : UPDATE_SCREEN))) + return (1); + + /* + * 4: Paint any missing status lines. + * + * XXX + * This is fairly evil. Status lines are written using the vi message + * mechanism, since we have no idea how long they are. Since we may be + * painting screens other than the current one, we don't want to make + * the user wait. We depend heavily on there not being any other lines + * currently waiting to be displayed and the message truncation code in + * the msgq_status routine working. + * + * And, finally, if we updated any status lines, make sure the cursor + * gets back to where it belongs. + */ + TAILQ_FOREACH(tsp, gp->dq, q) + if (F_ISSET(tsp, SC_STATUS)) { + need_refresh = 1; + vs_resolve(tsp, sp, 0); + } + if (need_refresh) + (void)gp->scr_refresh(sp, 0); + + /* + * A side-effect of refreshing the screen is that it's now ready + * for everything else, i.e. messages. + */ + F_SET(sp, SC_SCR_VI); + return (0); +} + +/* + * vs_paint -- + * This is the guts of the vi curses screen code. The idea is that + * the SCR structure passed in contains the new coordinates of the + * screen. What makes this hard is that we don't know how big + * characters are, doing input can put the cursor in illegal places, + * and we're frantically trying to avoid repainting unless it's + * absolutely necessary. If you change this code, you'd better know + * what you're doing. It's subtle and quick to anger. + */ +static int +vs_paint( + SCR *sp, + u_int flags) +{ + GS *gp; + SMAP *smp, tmp; + VI_PRIVATE *vip; + recno_t lastline, lcnt; + size_t cwtotal, cnt, len, notused, off, y; + int ch = 0, didpaint, isempty, leftright_warp; + CHAR_T *p; + +#define LNO sp->lno /* Current file line. */ +#define OLNO vip->olno /* Remembered file line. */ +#define CNO sp->cno /* Current file column. */ +#define OCNO vip->ocno /* Remembered file column. */ +#define SCNO vip->sc_col /* Current screen column. */ + + gp = sp->gp; + vip = VIP(sp); + didpaint = leftright_warp = 0; + + /* + * 5: Reformat the lines. + * + * If the lines themselves have changed (:set list, for example), + * fill in the map from scratch. Adjust the screen that's being + * displayed if the leftright flag is set. + */ + if (F_ISSET(sp, SC_SCR_REFORMAT)) { + /* Invalidate the line size cache. */ + VI_SCR_CFLUSH(vip); + + /* Toss vs_line() cached information. */ + if (F_ISSET(sp, SC_SCR_TOP)) { + if (vs_sm_fill(sp, LNO, P_TOP)) + return (1); + } + else if (F_ISSET(sp, SC_SCR_CENTER)) { + if (vs_sm_fill(sp, LNO, P_MIDDLE)) + return (1); + } else + if (vs_sm_fill(sp, OOBLNO, P_TOP)) + return (1); + F_SET(sp, SC_SCR_REDRAW); + } + + /* + * 6: Line movement. + * + * Line changes can cause the top line to change as well. As + * before, if the movement is large, the screen is repainted. + * + * 6a: Small screens. + * + * Users can use the window, w300, w1200 and w9600 options to make + * the screen artificially small. The behavior of these options + * in the historic vi wasn't all that consistent, and, in fact, it + * was never documented how various screen movements affected the + * screen size. Generally, one of three things would happen: + * 1: The screen would expand in size, showing the line + * 2: The screen would scroll, showing the line + * 3: The screen would compress to its smallest size and + * repaint. + * In general, scrolling didn't cause compression (200^D was handled + * the same as ^D), movement to a specific line would (:N where N + * was 1 line below the screen caused a screen compress), and cursor + * movement would scroll if it was 11 lines or less, and compress if + * it was more than 11 lines. (And, no, I have no idea where the 11 + * comes from.) + * + * What we do is try and figure out if the line is less than half of + * a full screen away. If it is, we expand the screen if there's + * room, and then scroll as necessary. The alternative is to compress + * and repaint. + * + * !!! + * This code is a special case from beginning to end. Unfortunately, + * home modems are still slow enough that it's worth having. + * + * XXX + * If the line a really long one, i.e. part of the line is on the + * screen but the column offset is not, we'll end up in the adjust + * code, when we should probably have compressed the screen. + */ + if (IS_SMALL(sp)) { + if (LNO < HMAP->lno) { + lcnt = vs_sm_nlines(sp, HMAP, LNO, sp->t_maxrows); + if (lcnt <= HALFSCREEN(sp)) + for (; lcnt && sp->t_rows != sp->t_maxrows; + --lcnt, ++sp->t_rows) { + ++TMAP; + if (vs_sm_1down(sp)) + return (1); + } + else + goto small_fill; + } else if (LNO > TMAP->lno) { + lcnt = vs_sm_nlines(sp, TMAP, LNO, sp->t_maxrows); + if (lcnt <= HALFSCREEN(sp)) + for (; lcnt && sp->t_rows != sp->t_maxrows; + --lcnt, ++sp->t_rows) { + if (vs_sm_next(sp, TMAP, TMAP + 1)) + return (1); + ++TMAP; + if (vs_line(sp, TMAP, NULL, NULL)) + return (1); + } + else { +small_fill: (void)gp->scr_move(sp, LASTLINE(sp), 0); + (void)gp->scr_clrtoeol(sp); + for (; sp->t_rows > sp->t_minrows; + --sp->t_rows, --TMAP) { + (void)gp->scr_move(sp, TMAP - HMAP, 0); + (void)gp->scr_clrtoeol(sp); + } + if (vs_sm_fill(sp, LNO, P_FILL)) + return (1); + F_SET(sp, SC_SCR_REDRAW); + goto adjust; + } + } + } + + /* + * 6b: Line down, or current screen. + */ + if (LNO >= HMAP->lno) { + /* Current screen. */ + if (LNO <= TMAP->lno) + goto adjust; + if (F_ISSET(sp, SC_SCR_TOP)) + goto top; + if (F_ISSET(sp, SC_SCR_CENTER)) + goto middle; + + /* + * If less than half a screen above the line, scroll down + * until the line is on the screen. + */ + lcnt = vs_sm_nlines(sp, TMAP, LNO, HALFTEXT(sp)); + if (lcnt < HALFTEXT(sp)) { + while (lcnt--) + if (vs_sm_1up(sp)) + return (1); + goto adjust; + } + goto bottom; + } + + /* + * 6c: If not on the current screen, may request center or top. + */ + if (F_ISSET(sp, SC_SCR_TOP)) + goto top; + if (F_ISSET(sp, SC_SCR_CENTER)) + goto middle; + + /* + * 6d: Line up. + */ + lcnt = vs_sm_nlines(sp, HMAP, LNO, HALFTEXT(sp)); + if (lcnt < HALFTEXT(sp)) { + /* + * If less than half a screen below the line, scroll up until + * the line is the first line on the screen. Special check so + * that if the screen has been emptied, we refill it. + */ + if (db_exist(sp, HMAP->lno)) { + while (lcnt--) + if (vs_sm_1down(sp)) + return (1); + goto adjust; + } else + goto top; /* XXX No such line. */ + + /* + * If less than a half screen from the bottom of the file, + * put the last line of the file on the bottom of the screen. + */ +bottom: if (db_last(sp, &lastline)) + return (1); + tmp.lno = LNO; + tmp.coff = HMAP->coff; + tmp.soff = 1; + lcnt = vs_sm_nlines(sp, &tmp, lastline, sp->t_rows); + if (lcnt < HALFTEXT(sp)) { + if (vs_sm_fill(sp, lastline, P_BOTTOM)) + return (1); + F_SET(sp, SC_SCR_REDRAW); + goto adjust; + } + /* It's not close, just put the line in the middle. */ + goto middle; + } + + /* + * If less than half a screen from the top of the file, put the first + * line of the file at the top of the screen. Otherwise, put the line + * in the middle of the screen. + */ + tmp.lno = 1; + tmp.coff = HMAP->coff; + tmp.soff = 1; + lcnt = vs_sm_nlines(sp, &tmp, LNO, HALFTEXT(sp)); + if (lcnt < HALFTEXT(sp)) { + if (vs_sm_fill(sp, 1, P_TOP)) + return (1); + } else +middle: if (vs_sm_fill(sp, LNO, P_MIDDLE)) + return (1); + if (0) { +top: if (vs_sm_fill(sp, LNO, P_TOP)) + return (1); + } + F_SET(sp, SC_SCR_REDRAW); + + /* + * At this point we know part of the line is on the screen. Since + * scrolling is done using logical lines, not physical, all of the + * line may not be on the screen. While that's not necessarily bad, + * if the part the cursor is on isn't there, we're going to lose. + * This can be tricky; if the line covers the entire screen, lno + * may be the same as both ends of the map, that's why we test BOTH + * the top and the bottom of the map. This isn't a problem for + * left-right scrolling, the cursor movement code handles the problem. + * + * There's a performance issue here if editing *really* long lines. + * This gets to the right spot by scrolling, and, in a binary, by + * scrolling hundreds of lines. If the adjustment looks like it's + * going to be a serious problem, refill the screen and repaint. + */ +adjust: if (!O_ISSET(sp, O_LEFTRIGHT) && + (LNO == HMAP->lno || LNO == TMAP->lno)) { + cnt = vs_screens(sp, LNO, &CNO); + if (LNO == HMAP->lno && cnt < HMAP->soff) { + if ((HMAP->soff - cnt) > HALFTEXT(sp)) { + HMAP->soff = cnt; + vs_sm_fill(sp, OOBLNO, P_TOP); + F_SET(sp, SC_SCR_REDRAW); + } else + while (cnt < HMAP->soff) + if (vs_sm_1down(sp)) + return (1); + } + if (LNO == TMAP->lno && cnt > TMAP->soff) { + if ((cnt - TMAP->soff) > HALFTEXT(sp)) { + TMAP->soff = cnt; + vs_sm_fill(sp, OOBLNO, P_BOTTOM); + F_SET(sp, SC_SCR_REDRAW); + } else + while (cnt > TMAP->soff) + if (vs_sm_1up(sp)) + return (1); + } + } + + /* + * If the screen needs to be repainted, skip cursor optimization. + * However, in the code above we skipped leftright scrolling on + * the grounds that the cursor code would handle it. Make sure + * the right screen is up. + */ + if (F_ISSET(sp, SC_SCR_REDRAW)) { + if (O_ISSET(sp, O_LEFTRIGHT)) + goto slow; + goto paint; + } + + /* + * 7: Cursor movements (current screen only). + */ + if (!LF_ISSET(UPDATE_CURSOR)) + goto number; + + /* + * Decide cursor position. If the line has changed, the cursor has + * moved over a tab, or don't know where the cursor was, reparse the + * line. Otherwise, we've just moved over fixed-width characters, + * and can calculate the left/right scrolling and cursor movement + * without reparsing the line. Note that we don't know which (if any) + * of the characters between the old and new cursor positions changed. + * + * XXX + * With some work, it should be possible to handle tabs quickly, at + * least in obvious situations, like moving right and encountering + * a tab, without reparsing the whole line. + * + * If the line we're working with has changed, reread it.. + */ + if (F_ISSET(vip, VIP_CUR_INVALID) || LNO != OLNO) + goto slow; + + /* Otherwise, if nothing's changed, ignore the cursor. */ + if (CNO == OCNO) + goto fast; + + /* + * Get the current line. If this fails, we either have an empty + * file and can just repaint, or there's a real problem. This + * isn't a performance issue because there aren't any ways to get + * here repeatedly. + */ + if (db_eget(sp, LNO, &p, &len, &isempty)) { + if (isempty) + goto slow; + return (1); + } + +#ifdef DEBUG + /* Sanity checking. */ + if (CNO >= len && len != 0) { + msgq(sp, M_ERR, "Error: %s/%d: cno (%zu) >= len (%zu)", + basename(__FILE__), __LINE__, CNO, len); + return (1); + } +#endif + /* + * The basic scheme here is to look at the characters in between + * the old and new positions and decide how big they are on the + * screen, and therefore, how many screen positions to move. + */ + if (CNO < OCNO) { + /* + * 7a: Cursor moved left. + * + * Point to the old character. The old cursor position can + * be past EOL if, for example, we just deleted the rest of + * the line. In this case, since we don't know the width of + * the characters we traversed, we have to do it slowly. + */ + p += OCNO; + cnt = (OCNO - CNO) + 1; + if (OCNO >= len) + goto slow; + + /* + * Quick sanity check -- it's hard to figure out exactly when + * we cross a screen boundary as we do in the cursor right + * movement. If cnt is so large that we're going to cross the + * boundary no matter what, stop now. + */ + if (SCNO + 1 + MAX_CHARACTER_COLUMNS < cnt) + goto slow; + + /* + * Count up the widths of the characters. If it's a tab + * character, go do it the slow way. + */ + for (cwtotal = 0; cnt--; cwtotal += KEY_COL(sp, ch)) + if ((ch = *(UCHAR_T *)p--) == '\t') + goto slow; + + /* + * Decrement the screen cursor by the total width of the + * characters minus 1. + */ + cwtotal -= 1; + + /* + * If we're moving left, and there's a wide character in the + * current position, go to the end of the character. + */ + if (KEY_COL(sp, ch) > 1) + cwtotal -= KEY_COL(sp, ch) - 1; + + /* + * If the new column moved us off of the current logical line, + * calculate a new one. If doing leftright scrolling, we've + * moved off of the current screen, as well. + */ + if (SCNO < cwtotal) + goto slow; + SCNO -= cwtotal; + } else { + /* + * 7b: Cursor moved right. + * + * Point to the first character to the right. + */ + p += OCNO + 1; + cnt = CNO - OCNO; + + /* + * Count up the widths of the characters. If it's a tab + * character, go do it the slow way. If we cross a + * screen boundary, we can quit. + */ + for (cwtotal = SCNO; cnt--;) { + if ((ch = *(UCHAR_T *)p++) == '\t') + goto slow; + if ((cwtotal += KEY_COL(sp, ch)) >= SCREEN_COLS(sp)) + break; + } + + /* + * Increment the screen cursor by the total width of the + * characters. + */ + SCNO = cwtotal; + + /* See screen change comment in section 6a. */ + if (SCNO >= SCREEN_COLS(sp)) + goto slow; + } + + /* + * 7c: Fast cursor update. + * + * We have the current column, retrieve the current row. + */ +fast: (void)gp->scr_cursor(sp, &y, ¬used); + goto done_cursor; + + /* + * 7d: Slow cursor update. + * + * Walk through the map and find the current line. + */ +slow: for (smp = HMAP; smp->lno != LNO; ++smp); + + /* + * 7e: Leftright scrolling adjustment. + * + * If doing left-right scrolling and the cursor movement has changed + * the displayed screen, scroll the screen left or right, unless we're + * updating the info line in which case we just scroll that one line. + * We adjust the offset up or down until we have a window that covers + * the current column, making sure that we adjust differently for the + * first screen as compared to subsequent ones. + */ + if (O_ISSET(sp, O_LEFTRIGHT)) { + /* + * Get the screen column for this character, and correct + * for the number option offset. + */ + cnt = vs_columns(sp, NULL, LNO, &CNO, NULL); + if (O_ISSET(sp, O_NUMBER)) + cnt -= O_NUMBER_LENGTH; + + /* Adjust the window towards the beginning of the line. */ + off = smp->coff; + if (off >= cnt) { + do { + if (off >= O_VAL(sp, O_SIDESCROLL)) + off -= O_VAL(sp, O_SIDESCROLL); + else { + off = 0; + break; + } + } while (off >= cnt); + goto shifted; + } + + /* Adjust the window towards the end of the line. */ + if ((off == 0 && off + SCREEN_COLS(sp) < cnt) || + (off != 0 && off + sp->cols < cnt)) { + do { + off += O_VAL(sp, O_SIDESCROLL); + } while (off + sp->cols < cnt); + +shifted: /* Fill in screen map with the new offset. */ + if (F_ISSET(sp, SC_TINPUT_INFO)) + smp->coff = off; + else { + for (smp = HMAP; smp <= TMAP; ++smp) + smp->coff = off; + leftright_warp = 1; + } + goto paint; + } + + /* + * We may have jumped here to adjust a leftright screen because + * redraw was set. If so, we have to paint the entire screen. + */ + if (F_ISSET(sp, SC_SCR_REDRAW)) + goto paint; + } + + /* + * Update the screen lines for this particular file line until we + * have a new screen cursor position. + */ + for (y = -1, + vip->sc_smap = NULL; smp <= TMAP && smp->lno == LNO; ++smp) { + if (vs_line(sp, smp, &y, &SCNO)) + return (1); + if (y != -1) { + vip->sc_smap = smp; + break; + } + } + goto done_cursor; + + /* + * 8: Repaint the entire screen. + * + * Lost big, do what you have to do. We flush the cache, since + * SC_SCR_REDRAW gets set when the screen isn't worth fixing, and + * it's simpler to repaint. So, don't trust anything that we + * think we know about it. + */ +paint: for (smp = HMAP; smp <= TMAP; ++smp) + SMAP_FLUSH(smp); + for (y = -1, vip->sc_smap = NULL, smp = HMAP; smp <= TMAP; ++smp) { + if (vs_line(sp, smp, &y, &SCNO)) + return (1); + if (y != -1 && vip->sc_smap == NULL) + vip->sc_smap = smp; + } + /* + * If it's a small screen and we're redrawing, clear the unused lines, + * ex may have overwritten them. + */ + if (F_ISSET(sp, SC_SCR_REDRAW) && IS_SMALL(sp)) + for (cnt = sp->t_rows; cnt <= sp->t_maxrows; ++cnt) { + (void)gp->scr_move(sp, cnt, 0); + (void)gp->scr_clrtoeol(sp); + } + + didpaint = 1; + +done_cursor: + /* + * Sanity checking. When the repainting code messes up, the usual + * result is we don't repaint the cursor and so sc_smap will be + * NULL. If we're debugging, die, otherwise restart from scratch. + */ +#ifdef DEBUG + if (vip->sc_smap == NULL) + abort(); +#else + if (vip->sc_smap == NULL) { + F_SET(sp, SC_SCR_REFORMAT); + return (vs_paint(sp, flags)); + } +#endif + + /* + * 9: Set the remembered cursor values. + */ + OCNO = CNO; + OLNO = LNO; + + /* + * 10: Repaint the line numbers. + * + * If O_NUMBER is set and the VIP_N_RENUMBER bit is set, and we + * didn't repaint the screen, repaint all of the line numbers, + * they've changed. + */ +number: if (O_ISSET(sp, O_NUMBER) && + F_ISSET(vip, VIP_N_RENUMBER) && !didpaint && vs_number(sp)) + return (1); + + /* + * 11: Update the mode line, position the cursor, and flush changes. + * + * If we warped the screen, we have to refresh everything. + */ + if (leftright_warp) + LF_SET(UPDATE_CURSOR | UPDATE_SCREEN); + + if (LF_ISSET(UPDATE_SCREEN) && !IS_ONELINE(sp) && + !F_ISSET(vip, VIP_S_MODELINE) && !F_ISSET(sp, SC_TINPUT_INFO)) + vs_modeline(sp); + + if (LF_ISSET(UPDATE_CURSOR)) { + (void)gp->scr_move(sp, y, SCNO); + + /* + * XXX + * If the screen shifted, we recalculate the "most favorite" + * cursor position. Vi won't know that we've warped the + * screen, so it's going to have a wrong idea about where the + * cursor should be. This is vi's problem, and fixing it here + * is a gross layering violation. + */ + if (leftright_warp) + (void)vs_column(sp, &sp->rcm); + } + + if (LF_ISSET(UPDATE_SCREEN)) + (void)gp->scr_refresh(sp, F_ISSET(vip, VIP_N_EX_PAINT)); + + /* 12: Clear the flags that are handled by this routine. */ + F_CLR(sp, SC_SCR_CENTER | SC_SCR_REDRAW | SC_SCR_REFORMAT | SC_SCR_TOP); + F_CLR(vip, VIP_CUR_INVALID | + VIP_N_EX_PAINT | VIP_N_REFRESH | VIP_N_RENUMBER | VIP_S_MODELINE); + + return (0); + +#undef LNO +#undef OLNO +#undef CNO +#undef OCNO +#undef SCNO +} + +/* + * vs_modeline -- + * Update the mode line. + */ +static void +vs_modeline(SCR *sp) +{ + static char * const modes[] = { + "215|Append", /* SM_APPEND */ + "216|Change", /* SM_CHANGE */ + "217|Command", /* SM_COMMAND */ + "218|Insert", /* SM_INSERT */ + "219|Replace", /* SM_REPLACE */ + }; + GS *gp; + size_t cols, curcol, curlen, endpoint, len, midpoint; + const char *t = NULL; + int ellipsis; + char buf[20]; + + gp = sp->gp; + + /* + * We put down the file name, the ruler, the mode and the dirty flag. + * If there's not enough room, there's not enough room, we don't play + * any special games. We try to put the ruler in the middle and the + * mode and dirty flag at the end. + * + * !!! + * Leave the last character blank, in case it's a really dumb terminal + * with hardware scroll. Second, don't paint the last character in the + * screen, SunOS 4.1.1 and Ultrix 4.2 curses won't let you. + * + * Move to the last line on the screen. + */ + (void)gp->scr_move(sp, LASTLINE(sp), 0); + + /* If more than one screen in the display, show the file name. */ + curlen = 0; + if (IS_SPLIT(sp)) { + CHAR_T *wp, *p; + size_t l; + + CHAR2INT(sp, sp->frp->name, strlen(sp->frp->name) + 1, wp, l); + p = wp + l; + for (ellipsis = 0, cols = sp->cols / 2; --p > wp;) { + if (*p == '/') { + ++p; + break; + } + if ((curlen += KEY_COL(sp, *p)) > cols) { + ellipsis = 3; + curlen += + KEY_LEN(sp, '.') * 3 + KEY_LEN(sp, ' '); + while (curlen > cols) { + ++p; + curlen -= KEY_COL(sp, *p); + } + break; + } + } + if (ellipsis) { + while (ellipsis--) + (void)gp->scr_addstr(sp, + KEY_NAME(sp, '.'), KEY_LEN(sp, '.')); + (void)gp->scr_addstr(sp, + KEY_NAME(sp, ' '), KEY_LEN(sp, ' ')); + } + for (; *p != '\0'; ++p) + (void)gp->scr_addstr(sp, + KEY_NAME(sp, *p), KEY_COL(sp, *p)); + } + + /* Clear the rest of the line. */ + (void)gp->scr_clrtoeol(sp); + + /* + * Display the ruler. If we're not at the midpoint yet, move there. + * Otherwise, add in two extra spaces. + * + * Adjust the current column for the fact that the editor uses it as + * a zero-based number. + * + * XXX + * Assume that numbers, commas, and spaces only take up a single + * column on the screen. + */ + cols = sp->cols - 1; + if (O_ISSET(sp, O_RULER)) { + vs_column(sp, &curcol); + len = snprintf(buf, sizeof(buf), "%lu,%lu", + (u_long)sp->lno, (u_long)(curcol + 1)); + + midpoint = (cols - ((len + 1) / 2)) / 2; + if (curlen < midpoint) { + (void)gp->scr_move(sp, LASTLINE(sp), midpoint); + curlen += len; + } else if (curlen + 2 + len < cols) { + (void)gp->scr_addstr(sp, " ", 2); + curlen += 2 + len; + } + (void)gp->scr_addstr(sp, buf, len); + } + + /* + * Display the mode and the modified flag, as close to the end of the + * line as possible, but guaranteeing at least two spaces between the + * ruler and the modified flag. + */ +#define MODESIZE 9 + endpoint = cols; + if (O_ISSET(sp, O_SHOWMODE)) { + if (F_ISSET(sp->ep, F_MODIFIED)) + --endpoint; + t = msg_cat(sp, modes[sp->showmode], &len); + endpoint -= len; + } + + if (endpoint > curlen + 2) { + (void)gp->scr_move(sp, LASTLINE(sp), endpoint); + if (O_ISSET(sp, O_SHOWMODE)) { + if (F_ISSET(sp->ep, F_MODIFIED)) + (void)gp->scr_addstr(sp, + KEY_NAME(sp, '*'), KEY_LEN(sp, '*')); + (void)gp->scr_addstr(sp, t, len); + } + } +} Property changes on: vendor/nvi/2.2.0-05ed8b9/vi/vs_refresh.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/vi/vs_relative.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/vi/vs_relative.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/vi/vs_relative.c (revision 366308) @@ -0,0 +1,291 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include + +#include "../common/common.h" +#include "vi.h" + +/* + * vs_column -- + * Return the logical column of the cursor in the line. + * + * PUBLIC: int vs_column(SCR *, size_t *); + */ +int +vs_column(SCR *sp, size_t *colp) +{ + VI_PRIVATE *vip; + + vip = VIP(sp); + + *colp = (O_ISSET(sp, O_LEFTRIGHT) ? + vip->sc_smap->coff : (vip->sc_smap->soff - 1) * sp->cols) + + vip->sc_col - (O_ISSET(sp, O_NUMBER) ? O_NUMBER_LENGTH : 0); + return (0); +} + +/* + * vs_screens -- + * Return the screens necessary to display the line, or if specified, + * the physical character column within the line, including space + * required for the O_NUMBER and O_LIST options. + * + * PUBLIC: size_t vs_screens(SCR *, recno_t, size_t *); + */ +size_t +vs_screens(SCR *sp, recno_t lno, size_t *cnop) +{ + size_t cols, screens; + + /* Left-right screens are simple, it's always 1. */ + if (O_ISSET(sp, O_LEFTRIGHT)) + return (1); + + /* + * Check for a cached value. We maintain a cache because, if the + * line is large, this routine gets called repeatedly. One other + * hack, lots of time the cursor is on column one, which is an easy + * one. + */ + if (cnop == NULL) { + if (VIP(sp)->ss_lno == lno) + return (VIP(sp)->ss_screens); + } else if (*cnop == 0) + return (1); + + /* Figure out how many columns the line/column needs. */ + cols = vs_columns(sp, NULL, lno, cnop, NULL); + + screens = (cols / sp->cols + (cols % sp->cols ? 1 : 0)); + if (screens == 0) + screens = 1; + + /* Cache the value. */ + if (cnop == NULL) { + VIP(sp)->ss_lno = lno; + VIP(sp)->ss_screens = screens; + } + return (screens); +} + +/* + * vs_columns -- + * Return the screen columns necessary to display the line, or, + * if specified, the physical character column within the line. + * + * PUBLIC: size_t vs_columns(SCR *, CHAR_T *, recno_t, size_t *, size_t *); + */ +size_t +vs_columns(SCR *sp, CHAR_T *lp, recno_t lno, size_t *cnop, size_t *diffp) +{ + size_t chlen, cno, curoff, last = 0, len, scno; + int ch, leftright, listset; + CHAR_T *p; + + /* + * Initialize the screen offset. + */ + scno = 0; + + /* Leading number if O_NUMBER option set. */ + if (O_ISSET(sp, O_NUMBER)) + scno += O_NUMBER_LENGTH; + + /* Need the line to go any further. */ + if (lp == NULL) { + (void)db_get(sp, lno, 0, &lp, &len); + if (len == 0) + goto done; + } + + /* Missing or empty lines are easy. */ + if (lp == NULL) { +done: if (diffp != NULL) /* XXX */ + *diffp = 0; + return scno; + } + + /* Store away the values of the list and leftright edit options. */ + listset = O_ISSET(sp, O_LIST); + leftright = O_ISSET(sp, O_LEFTRIGHT); + + /* + * Initialize the pointer into the buffer and current offset. + */ + p = lp; + curoff = scno; + + /* Macro to return the display length of any signal character. */ +#define CHLEN(val) (ch = *(UCHAR_T *)p++) == '\t' && \ + !listset ? TAB_OFF(val) : KEY_COL(sp, ch); + + /* + * If folding screens (the historic vi screen format), past the end + * of the current screen, and the character was a tab, reset the + * current screen column to 0, and the total screen columns to the + * last column of the screen. Otherwise, display the rest of the + * character in the next screen. + */ +#define TAB_RESET do { \ + curoff += chlen; \ + if (!leftright && curoff >= sp->cols) { \ + if (ch == '\t') { \ + curoff = 0; \ + scno -= scno % sp->cols; \ + } else \ + curoff -= sp->cols; \ + } \ +} while (0) + if (cnop == NULL) + while (len--) { + chlen = CHLEN(curoff); + last = scno; + scno += chlen; + TAB_RESET; + } + else + for (cno = *cnop;; --cno) { + chlen = CHLEN(curoff); + last = scno; + scno += chlen; + TAB_RESET; + if (cno == 0) + break; + } + + /* Add the trailing '$' if the O_LIST option set. */ + if (listset && cnop == NULL) + scno += KEY_LEN(sp, '$'); + + /* + * The text input screen code needs to know how much additional + * room the last two characters required, so that it can handle + * tab character displays correctly. + */ + if (diffp != NULL) + *diffp = scno - last; + return (scno); +} + +/* + * vs_rcm -- + * Return the physical column from the line that will display a + * character closest to the currently most attractive character + * position (which is stored as a screen column). + * + * PUBLIC: size_t vs_rcm(SCR *, recno_t, int); + */ +size_t +vs_rcm(SCR *sp, recno_t lno, int islast) +{ + size_t len; + + /* Last character is easy, and common. */ + if (islast) { + if (db_get(sp, lno, 0, NULL, &len) || len == 0) + return (0); + return (len - 1); + } + + /* First character is easy, and common. */ + if (sp->rcm == 0) + return (0); + + return (vs_colpos(sp, lno, sp->rcm)); +} + +/* + * vs_colpos -- + * Return the physical column from the line that will display a + * character closest to the specified screen column. + * + * PUBLIC: size_t vs_colpos(SCR *, recno_t, size_t); + */ +size_t +vs_colpos(SCR *sp, recno_t lno, size_t cno) +{ + size_t chlen, curoff, len, llen, off, scno; + int ch = 0, leftright, listset; + CHAR_T *lp, *p; + + /* Need the line to go any further. */ + (void)db_get(sp, lno, 0, &lp, &llen); + + /* Missing or empty lines are easy. */ + if (lp == NULL || llen == 0) + return (0); + + /* Store away the values of the list and leftright edit options. */ + listset = O_ISSET(sp, O_LIST); + leftright = O_ISSET(sp, O_LEFTRIGHT); + + /* Discard screen (logical) lines. */ + off = cno / sp->cols; + cno %= sp->cols; + for (scno = 0, p = lp, len = llen; off--;) { + for (; len && scno < sp->cols; --len) + scno += CHLEN(scno); + + /* + * If reached the end of the physical line, return the last + * physical character in the line. + */ + if (len == 0) + return (llen - 1); + + /* + * If folding screens (the historic vi screen format), past + * the end of the current screen, and the character was a tab, + * reset the current screen column to 0. Otherwise, the rest + * of the character is displayed in the next screen. + */ + if (leftright && ch == '\t') + scno = 0; + else + scno -= sp->cols; + } + + /* Step through the line until reach the right character or EOL. */ + for (curoff = scno; len--;) { + chlen = CHLEN(curoff); + + /* + * If we've reached the specific character, there are three + * cases. + * + * 1: scno == cno, i.e. the current character ends at the + * screen character we care about. + * a: off < llen - 1, i.e. not the last character in + * the line, return the offset of the next character. + * b: else return the offset of the last character. + * 2: scno != cno, i.e. this character overruns the character + * we care about, return the offset of this character. + */ + if ((scno += chlen) >= cno) { + off = p - lp; + return (scno == cno ? + (off < llen - 1 ? off : llen - 1) : off - 1); + } + + TAB_RESET; + } + + /* No such character; return the start of the last character. */ + return (llen - 1); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/vi/vs_relative.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/vi/vs_smap.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/vi/vs_smap.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/vi/vs_smap.c (revision 366308) @@ -0,0 +1,1238 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "../common/common.h" +#include "vi.h" + +static int vs_deleteln(SCR *, int); +static int vs_insertln(SCR *, int); +static int vs_sm_delete(SCR *, recno_t); +static int vs_sm_down(SCR *, MARK *, recno_t, scroll_t, SMAP *); +static int vs_sm_erase(SCR *); +static int vs_sm_insert(SCR *, recno_t); +static int vs_sm_reset(SCR *, recno_t); +static int vs_sm_up(SCR *, MARK *, recno_t, scroll_t, SMAP *); + +/* + * vs_change -- + * Make a change to the screen. + * + * PUBLIC: int vs_change(SCR *, recno_t, lnop_t); + */ +int +vs_change(SCR *sp, recno_t lno, lnop_t op) +{ + VI_PRIVATE *vip; + SMAP *p; + size_t cnt, oldy, oldx; + + vip = VIP(sp); + + /* + * XXX + * Very nasty special case. The historic vi code displays a single + * space (or a '$' if the list option is set) for the first line in + * an "empty" file. If we "insert" a line, that line gets scrolled + * down, not repainted, so it's incorrect when we refresh the screen. + * The vi text input functions detect it explicitly and don't insert + * a new line. + * + * Check for line #2 before going to the end of the file. + */ + if (((op == LINE_APPEND && lno == 0) || + (op == LINE_INSERT && lno == 1)) && + !db_exist(sp, 2)) { + lno = 1; + op = LINE_RESET; + } + + /* Appending is the same as inserting, if the line is incremented. */ + if (op == LINE_APPEND) { + ++lno; + op = LINE_INSERT; + } + + /* Ignore the change if the line is after the map. */ + if (lno > TMAP->lno) + return (0); + + /* + * If the line is before the map, and it's a decrement, decrement + * the map. If it's an increment, increment the map. Otherwise, + * ignore it. + */ + if (lno < HMAP->lno) { + switch (op) { + case LINE_APPEND: + abort(); + /* NOTREACHED */ + case LINE_DELETE: + for (p = HMAP, cnt = sp->t_rows; cnt--; ++p) + --p->lno; + if (sp->lno >= lno) + --sp->lno; + F_SET(vip, VIP_N_RENUMBER); + break; + case LINE_INSERT: + for (p = HMAP, cnt = sp->t_rows; cnt--; ++p) + ++p->lno; + if (sp->lno >= lno) + ++sp->lno; + F_SET(vip, VIP_N_RENUMBER); + break; + case LINE_RESET: + break; + } + return (0); + } + + F_SET(vip, VIP_N_REFRESH); + + /* + * Invalidate the line size cache, and invalidate the cursor if it's + * on this line, + */ + VI_SCR_CFLUSH(vip); + if (sp->lno == lno) + F_SET(vip, VIP_CUR_INVALID); + + /* + * If ex modifies the screen after ex output is already on the screen + * or if we've switched into ex canonical mode, don't touch it -- we'll + * get scrolling wrong, at best. + */ + if (!F_ISSET(sp, SC_TINPUT_INFO) && + (F_ISSET(sp, SC_SCR_EXWROTE) || VIP(sp)->totalcount > 1)) { + F_SET(vip, VIP_N_EX_REDRAW); + return (0); + } + + /* Save and restore the cursor for these routines. */ + (void)sp->gp->scr_cursor(sp, &oldy, &oldx); + + switch (op) { + case LINE_DELETE: + if (vs_sm_delete(sp, lno)) + return (1); + if (sp->lno > lno) + --sp->lno; + F_SET(vip, VIP_N_RENUMBER); + break; + case LINE_INSERT: + if (vs_sm_insert(sp, lno)) + return (1); + if (sp->lno > lno) + ++sp->lno; + F_SET(vip, VIP_N_RENUMBER); + break; + case LINE_RESET: + if (vs_sm_reset(sp, lno)) + return (1); + break; + default: + abort(); + } + + (void)sp->gp->scr_move(sp, oldy, oldx); + return (0); +} + +/* + * vs_sm_fill -- + * Fill in the screen map, placing the specified line at the + * right position. There isn't any way to tell if an SMAP + * entry has been filled in, so this routine had better be + * called with P_FILL set before anything else is done. + * + * !!! + * Unexported interface: if lno is OOBLNO, P_TOP means that the HMAP + * slot is already filled in, P_BOTTOM means that the TMAP slot is + * already filled in, and we just finish up the job. + * + * PUBLIC: int vs_sm_fill(SCR *, recno_t, pos_t); + */ +int +vs_sm_fill(SCR *sp, recno_t lno, pos_t pos) +{ + SMAP *p, tmp; + size_t cnt; + + /* Flush all cached information from the SMAP. */ + for (p = HMAP, cnt = sp->t_rows; cnt--; ++p) + SMAP_FLUSH(p); + + /* + * If the map is filled, the screen must be redrawn. + * + * XXX + * This is a bug. We should try and figure out if the desired line + * is already in the map or close by -- scrolling the screen would + * be a lot better than redrawing. + */ + F_SET(sp, SC_SCR_REDRAW); + + switch (pos) { + case P_FILL: + tmp.lno = 1; + tmp.coff = 0; + tmp.soff = 1; + + /* See if less than half a screen from the top. */ + if (vs_sm_nlines(sp, + &tmp, lno, HALFTEXT(sp)) <= HALFTEXT(sp)) { + lno = 1; + goto top; + } + + /* See if less than half a screen from the bottom. */ + if (db_last(sp, &tmp.lno)) + return (1); + tmp.coff = 0; + tmp.soff = vs_screens(sp, tmp.lno, NULL); + if (vs_sm_nlines(sp, + &tmp, lno, HALFTEXT(sp)) <= HALFTEXT(sp)) { + TMAP->lno = tmp.lno; + TMAP->coff = tmp.coff; + TMAP->soff = tmp.soff; + goto bottom; + } + goto middle; + case P_TOP: + if (lno != OOBLNO) { +top: HMAP->lno = lno; + HMAP->coff = 0; + HMAP->soff = 1; + } else { + /* + * If number of lines HMAP->lno (top line) spans + * changed due to, say reformatting, and now is + * fewer than HMAP->soff, reset so the line is + * redrawn at the top of the screen. + */ + cnt = vs_screens(sp, HMAP->lno, NULL); + if (cnt < HMAP->soff) + HMAP->soff = 1; + } + /* If we fail, just punt. */ + for (p = HMAP, cnt = sp->t_rows; --cnt; ++p) + if (vs_sm_next(sp, p, p + 1)) + goto err; + break; + case P_MIDDLE: + /* If we fail, guess that the file is too small. */ +middle: p = HMAP + sp->t_rows / 2; + p->lno = lno; + p->coff = 0; + p->soff = 1; + for (; p > HMAP; --p) + if (vs_sm_prev(sp, p, p - 1)) { + lno = 1; + goto top; + } + + /* If we fail, just punt. */ + p = HMAP + sp->t_rows / 2; + for (; p < TMAP; ++p) + if (vs_sm_next(sp, p, p + 1)) + goto err; + break; + case P_BOTTOM: + if (lno != OOBLNO) { + TMAP->lno = lno; + TMAP->coff = 0; + TMAP->soff = vs_screens(sp, lno, NULL); + } + /* If we fail, guess that the file is too small. */ +bottom: for (p = TMAP; p > HMAP; --p) + if (vs_sm_prev(sp, p, p - 1)) { + lno = 1; + goto top; + } + break; + default: + abort(); + } + return (0); + + /* + * Try and put *something* on the screen. If this fails, we have a + * serious hard error. + */ +err: HMAP->lno = 1; + HMAP->coff = 0; + HMAP->soff = 1; + for (p = HMAP; p < TMAP; ++p) + if (vs_sm_next(sp, p, p + 1)) + return (1); + return (0); +} + +/* + * For the routines vs_sm_reset, vs_sm_delete and vs_sm_insert: if the + * screen contains only a single line (whether because the screen is small + * or the line large), it gets fairly exciting. Skip the fun, set a flag + * so the screen map is refilled and the screen redrawn, and return. This + * is amazingly slow, but it's not clear that anyone will care. + */ +#define HANDLE_WEIRDNESS(cnt) do { \ + if (cnt >= sp->t_rows) { \ + F_SET(sp, SC_SCR_REFORMAT); \ + return (0); \ + } \ +} while (0) + +/* + * vs_sm_delete -- + * Delete a line out of the SMAP. + */ +static int +vs_sm_delete(SCR *sp, recno_t lno) +{ + SMAP *p, *t; + size_t cnt_orig; + + /* + * Find the line in the map, and count the number of screen lines + * which display any part of the deleted line. + */ + for (p = HMAP; p->lno != lno; ++p); + if (O_ISSET(sp, O_LEFTRIGHT)) + cnt_orig = 1; + else + for (cnt_orig = 1, t = p + 1; + t <= TMAP && t->lno == lno; ++cnt_orig, ++t); + + HANDLE_WEIRDNESS(cnt_orig); + + /* Delete that many lines from the screen. */ + (void)sp->gp->scr_move(sp, p - HMAP, 0); + if (vs_deleteln(sp, cnt_orig)) + return (1); + + /* Shift the screen map up. */ + memmove(p, p + cnt_orig, (((TMAP - p) - cnt_orig) + 1) * sizeof(SMAP)); + + /* Decrement the line numbers for the rest of the map. */ + for (t = TMAP - cnt_orig; p <= t; ++p) + --p->lno; + + /* Display the new lines. */ + for (p = TMAP - cnt_orig;;) { + if (p < TMAP && vs_sm_next(sp, p, p + 1)) + return (1); + /* vs_sm_next() flushed the cache. */ + if (vs_line(sp, ++p, NULL, NULL)) + return (1); + if (p == TMAP) + break; + } + return (0); +} + +/* + * vs_sm_insert -- + * Insert a line into the SMAP. + */ +static int +vs_sm_insert(SCR *sp, recno_t lno) +{ + SMAP *p, *t; + size_t cnt_orig, cnt, coff; + + /* Save the offset. */ + coff = HMAP->coff; + + /* + * Find the line in the map, find out how many screen lines + * needed to display the line. + */ + for (p = HMAP; p->lno != lno; ++p); + + cnt_orig = vs_screens(sp, lno, NULL); + HANDLE_WEIRDNESS(cnt_orig); + + /* + * The lines left in the screen override the number of screen + * lines in the inserted line. + */ + cnt = (TMAP - p) + 1; + if (cnt_orig > cnt) + cnt_orig = cnt; + + /* Push down that many lines. */ + (void)sp->gp->scr_move(sp, p - HMAP, 0); + if (vs_insertln(sp, cnt_orig)) + return (1); + + /* Shift the screen map down. */ + memmove(p + cnt_orig, p, (((TMAP - p) - cnt_orig) + 1) * sizeof(SMAP)); + + /* Increment the line numbers for the rest of the map. */ + for (t = p + cnt_orig; t <= TMAP; ++t) + ++t->lno; + + /* Fill in the SMAP for the new lines, and display. */ + for (cnt = 1, t = p; cnt <= cnt_orig; ++t, ++cnt) { + t->lno = lno; + t->coff = coff; + t->soff = cnt; + SMAP_FLUSH(t); + if (vs_line(sp, t, NULL, NULL)) + return (1); + } + return (0); +} + +/* + * vs_sm_reset -- + * Reset a line in the SMAP. + */ +static int +vs_sm_reset(SCR *sp, recno_t lno) +{ + SMAP *p, *t; + size_t cnt_orig, cnt_new, cnt, diff; + + /* + * See if the number of on-screen rows taken up by the old display + * for the line is the same as the number needed for the new one. + * If so, repaint, otherwise do it the hard way. + */ + for (p = HMAP; p->lno != lno; ++p); + if (O_ISSET(sp, O_LEFTRIGHT)) { + t = p; + cnt_orig = cnt_new = 1; + } else { + for (cnt_orig = 0, + t = p; t <= TMAP && t->lno == lno; ++cnt_orig, ++t); + cnt_new = vs_screens(sp, lno, NULL); + } + + HANDLE_WEIRDNESS(cnt_orig); + + if (cnt_orig == cnt_new) { + do { + SMAP_FLUSH(p); + if (vs_line(sp, p, NULL, NULL)) + return (1); + } while (++p < t); + return (0); + } + + if (cnt_orig < cnt_new) { + /* Get the difference. */ + diff = cnt_new - cnt_orig; + + /* + * The lines left in the screen override the number of screen + * lines in the inserted line. + */ + cnt = (TMAP - p) + 1; + if (diff > cnt) + diff = cnt; + + /* If there are any following lines, push them down. */ + if (cnt > 1) { + (void)sp->gp->scr_move(sp, p - HMAP, 0); + if (vs_insertln(sp, diff)) + return (1); + + /* Shift the screen map down. */ + memmove(p + diff, p, + (((TMAP - p) - diff) + 1) * sizeof(SMAP)); + } + + /* Fill in the SMAP for the replaced line, and display. */ + for (cnt = 1, t = p; cnt_new-- && t <= TMAP; ++t, ++cnt) { + t->lno = lno; + t->soff = cnt; + SMAP_FLUSH(t); + if (vs_line(sp, t, NULL, NULL)) + return (1); + } + } else { + /* Get the difference. */ + diff = cnt_orig - cnt_new; + + /* Delete that many lines from the screen. */ + (void)sp->gp->scr_move(sp, p - HMAP, 0); + if (vs_deleteln(sp, diff)) + return (1); + + /* Shift the screen map up. */ + memmove(p, p + diff, (((TMAP - p) - diff) + 1) * sizeof(SMAP)); + + /* Fill in the SMAP for the replaced line, and display. */ + for (cnt = 1, t = p; cnt_new--; ++t, ++cnt) { + t->lno = lno; + t->soff = cnt; + SMAP_FLUSH(t); + if (vs_line(sp, t, NULL, NULL)) + return (1); + } + + /* Display the new lines at the bottom of the screen. */ + for (t = TMAP - diff;;) { + if (t < TMAP && vs_sm_next(sp, t, t + 1)) + return (1); + /* vs_sm_next() flushed the cache. */ + if (vs_line(sp, ++t, NULL, NULL)) + return (1); + if (t == TMAP) + break; + } + } + return (0); +} + +/* + * vs_sm_scroll + * Scroll the SMAP up/down count logical lines. Different + * semantics based on the vi command, *sigh*. + * + * PUBLIC: int vs_sm_scroll(SCR *, MARK *, recno_t, scroll_t); + */ +int +vs_sm_scroll(SCR *sp, MARK *rp, recno_t count, scroll_t scmd) +{ + SMAP *smp; + + /* + * Invalidate the cursor. The line is probably going to change, + * (although for ^E and ^Y it may not). In any case, the scroll + * routines move the cursor to draw things. + */ + F_SET(VIP(sp), VIP_CUR_INVALID); + + /* Find the cursor in the screen. */ + if (vs_sm_cursor(sp, &smp)) + return (1); + + switch (scmd) { + case CNTRL_B: + case CNTRL_U: + case CNTRL_Y: + case Z_CARAT: + if (vs_sm_down(sp, rp, count, scmd, smp)) + return (1); + break; + case CNTRL_D: + case CNTRL_E: + case CNTRL_F: + case Z_PLUS: + if (vs_sm_up(sp, rp, count, scmd, smp)) + return (1); + break; + default: + abort(); + } + + /* + * !!! + * If we're at the start of a line, go for the first non-blank. + * This makes it look like the old vi, even though we're moving + * around by logical lines, not physical ones. + * + * XXX + * In the presence of a long line, which has more than a screen + * width of leading spaces, this code can cause a cursor warp. + * Live with it. + */ + if (scmd != CNTRL_E && scmd != CNTRL_Y && + rp->cno == 0 && nonblank(sp, rp->lno, &rp->cno)) + return (1); + + return (0); +} + +/* + * vs_sm_up -- + * Scroll the SMAP up count logical lines. + */ +static int +vs_sm_up(SCR *sp, MARK *rp, recno_t count, scroll_t scmd, SMAP *smp) +{ + int cursor_set, echanged, zset; + SMAP *ssmp, s1, s2; + + /* + * Check to see if movement is possible. + * + * Get the line after the map. If that line is a new one (and if + * O_LEFTRIGHT option is set, this has to be true), and the next + * line doesn't exist, and the cursor doesn't move, or the cursor + * isn't even on the screen, or the cursor is already at the last + * line in the map, it's an error. If that test succeeded because + * the cursor wasn't at the end of the map, test to see if the map + * is mostly empty. + */ + if (vs_sm_next(sp, TMAP, &s1)) + return (1); + if (s1.lno > TMAP->lno && !db_exist(sp, s1.lno)) { + if (scmd == CNTRL_E || scmd == Z_PLUS || smp == TMAP) { + v_eof(sp, NULL); + return (1); + } + if (vs_sm_next(sp, smp, &s1)) + return (1); + if (s1.lno > smp->lno && !db_exist(sp, s1.lno)) { + v_eof(sp, NULL); + return (1); + } + } + + /* + * Small screens: see vs_refresh.c section 6a. + * + * If it's a small screen, and the movement isn't larger than a + * screen, i.e some context will remain, open up the screen and + * display by scrolling. In this case, the cursor moves down one + * line for each line displayed. Otherwise, erase/compress and + * repaint, and move the cursor to the first line in the screen. + * Note, the ^F command is always in the latter case, for historical + * reasons. + */ + cursor_set = 0; + if (IS_SMALL(sp)) { + if (count >= sp->t_maxrows || scmd == CNTRL_F) { + s1 = TMAP[0]; + if (vs_sm_erase(sp)) + return (1); + for (; count--; s1 = s2) { + if (vs_sm_next(sp, &s1, &s2)) + return (1); + if (s2.lno != s1.lno && !db_exist(sp, s2.lno)) + break; + } + TMAP[0] = s2; + if (vs_sm_fill(sp, OOBLNO, P_BOTTOM)) + return (1); + return (vs_sm_position(sp, rp, 0, P_TOP)); + } + cursor_set = scmd == CNTRL_E || vs_sm_cursor(sp, &ssmp); + for (; count && + sp->t_rows != sp->t_maxrows; --count, ++sp->t_rows) { + if (vs_sm_next(sp, TMAP, &s1)) + return (1); + if (TMAP->lno != s1.lno && !db_exist(sp, s1.lno)) + break; + *++TMAP = s1; + /* vs_sm_next() flushed the cache. */ + if (vs_line(sp, TMAP, NULL, NULL)) + return (1); + + if (!cursor_set) + ++ssmp; + } + if (!cursor_set) { + rp->lno = ssmp->lno; + rp->cno = ssmp->c_sboff; + } + if (count == 0) + return (0); + } + + for (echanged = zset = 0; count; --count) { + /* Decide what would show up on the screen. */ + if (vs_sm_next(sp, TMAP, &s1)) + return (1); + + /* If the line doesn't exist, we're done. */ + if (TMAP->lno != s1.lno && !db_exist(sp, s1.lno)) + break; + + /* Scroll the screen cursor up one logical line. */ + if (vs_sm_1up(sp)) + return (1); + switch (scmd) { + case CNTRL_E: + if (smp > HMAP) + --smp; + else + echanged = 1; + break; + case Z_PLUS: + if (zset) { + if (smp > HMAP) + --smp; + } else { + smp = TMAP; + zset = 1; + } + /* FALLTHROUGH */ + default: + break; + } + } + + if (cursor_set) + return(0); + + switch (scmd) { + case CNTRL_E: + /* + * On a ^E that was forced to change lines, try and keep the + * cursor as close as possible to the last position, but also + * set it up so that the next "real" movement will return the + * cursor to the closest position to the last real movement. + */ + if (echanged) { + rp->lno = smp->lno; + rp->cno = vs_colpos(sp, smp->lno, + (O_ISSET(sp, O_LEFTRIGHT) ? + smp->coff : (smp->soff - 1) * sp->cols) + + sp->rcm % sp->cols); + } + return (0); + case CNTRL_F: + /* + * If there are more lines, the ^F command is positioned at + * the first line of the screen. + */ + if (!count) { + smp = HMAP; + break; + } + /* FALLTHROUGH */ + case CNTRL_D: + /* + * The ^D and ^F commands move the cursor towards EOF + * if there are more lines to move. Check to be sure + * the lines actually exist. (They may not if the + * file is smaller than the screen.) + */ + for (; count; --count, ++smp) + if (smp == TMAP || !db_exist(sp, smp[1].lno)) + break; + break; + case Z_PLUS: + /* The z+ command moves the cursor to the first new line. */ + break; + default: + abort(); + } + + if (!SMAP_CACHE(smp) && vs_line(sp, smp, NULL, NULL)) + return (1); + rp->lno = smp->lno; + rp->cno = smp->c_scoff == 255 ? 0 : smp->c_sboff; + return (0); +} + +/* + * vs_sm_1up -- + * Scroll the SMAP up one. + * + * PUBLIC: int vs_sm_1up(SCR *); + */ +int +vs_sm_1up(SCR *sp) +{ + /* + * Delete the top line of the screen. Shift the screen map + * up and display a new line at the bottom of the screen. + */ + (void)sp->gp->scr_move(sp, 0, 0); + if (vs_deleteln(sp, 1)) + return (1); + + /* One-line screens can fail. */ + if (IS_ONELINE(sp)) { + if (vs_sm_next(sp, TMAP, TMAP)) + return (1); + } else { + memmove(HMAP, HMAP + 1, (sp->rows - 1) * sizeof(SMAP)); + if (vs_sm_next(sp, TMAP - 1, TMAP)) + return (1); + } + /* vs_sm_next() flushed the cache. */ + return (vs_line(sp, TMAP, NULL, NULL)); +} + +/* + * vs_deleteln -- + * Delete a line a la curses, make sure to put the information + * line and other screens back. + */ +static int +vs_deleteln(SCR *sp, int cnt) +{ + GS *gp; + size_t oldy, oldx; + + gp = sp->gp; + + /* If the screen is vertically split, we can't scroll it. */ + if (IS_VSPLIT(sp)) { + F_SET(sp, SC_SCR_REDRAW); + return (0); + } + + if (IS_ONELINE(sp)) + (void)gp->scr_clrtoeol(sp); + else { + (void)gp->scr_cursor(sp, &oldy, &oldx); + while (cnt--) { + (void)gp->scr_deleteln(sp); + (void)gp->scr_move(sp, LASTLINE(sp), 0); + (void)gp->scr_insertln(sp); + (void)gp->scr_move(sp, oldy, oldx); + } + } + return (0); +} + +/* + * vs_sm_down -- + * Scroll the SMAP down count logical lines. + */ +static int +vs_sm_down(SCR *sp, MARK *rp, recno_t count, scroll_t scmd, SMAP *smp) +{ + SMAP *ssmp, s1, s2; + int cursor_set, ychanged, zset; + + /* Check to see if movement is possible. */ + if (HMAP->lno == 1 && + (O_ISSET(sp, O_LEFTRIGHT) || HMAP->soff == 1) && + (scmd == CNTRL_Y || scmd == Z_CARAT || smp == HMAP)) { + v_sof(sp, NULL); + return (1); + } + + /* + * Small screens: see vs_refresh.c section 6a. + * + * If it's a small screen, and the movement isn't larger than a + * screen, i.e some context will remain, open up the screen and + * display by scrolling. In this case, the cursor moves up one + * line for each line displayed. Otherwise, erase/compress and + * repaint, and move the cursor to the first line in the screen. + * Note, the ^B command is always in the latter case, for historical + * reasons. + */ + cursor_set = scmd == CNTRL_Y; + if (IS_SMALL(sp)) { + if (count >= sp->t_maxrows || scmd == CNTRL_B) { + s1 = HMAP[0]; + if (vs_sm_erase(sp)) + return (1); + for (; count--; s1 = s2) { + if (vs_sm_prev(sp, &s1, &s2)) + return (1); + if (s2.lno == 1 && + (O_ISSET(sp, O_LEFTRIGHT) || s2.soff == 1)) + break; + } + HMAP[0] = s2; + if (vs_sm_fill(sp, OOBLNO, P_TOP)) + return (1); + return (vs_sm_position(sp, rp, 0, P_BOTTOM)); + } + cursor_set = scmd == CNTRL_Y || vs_sm_cursor(sp, &ssmp); + for (; count && + sp->t_rows != sp->t_maxrows; --count, ++sp->t_rows) { + if (HMAP->lno == 1 && + (O_ISSET(sp, O_LEFTRIGHT) || HMAP->soff == 1)) + break; + ++TMAP; + if (vs_sm_1down(sp)) + return (1); + } + if (!cursor_set) { + rp->lno = ssmp->lno; + rp->cno = ssmp->c_sboff; + } + if (count == 0) + return (0); + } + + for (ychanged = zset = 0; count; --count) { + /* If the line doesn't exist, we're done. */ + if (HMAP->lno == 1 && + (O_ISSET(sp, O_LEFTRIGHT) || HMAP->soff == 1)) + break; + + /* Scroll the screen and cursor down one logical line. */ + if (vs_sm_1down(sp)) + return (1); + switch (scmd) { + case CNTRL_Y: + if (smp < TMAP) + ++smp; + else + ychanged = 1; + break; + case Z_CARAT: + if (zset) { + if (smp < TMAP) + ++smp; + } else { + smp = HMAP; + zset = 1; + } + /* FALLTHROUGH */ + default: + break; + } + } + + if (scmd != CNTRL_Y && cursor_set) + return(0); + + switch (scmd) { + case CNTRL_B: + /* + * If there are more lines, the ^B command is positioned at + * the last line of the screen. However, the line may not + * exist. + */ + if (!count) { + for (smp = TMAP; smp > HMAP; --smp) + if (db_exist(sp, smp->lno)) + break; + break; + } + /* FALLTHROUGH */ + case CNTRL_U: + /* + * The ^B and ^U commands move the cursor towards SOF + * if there are more lines to move. + */ + if (count < smp - HMAP) + smp -= count; + else + smp = HMAP; + break; + case CNTRL_Y: + /* + * On a ^Y that was forced to change lines, try and keep the + * cursor as close as possible to the last position, but also + * set it up so that the next "real" movement will return the + * cursor to the closest position to the last real movement. + */ + if (ychanged) { + rp->lno = smp->lno; + rp->cno = vs_colpos(sp, smp->lno, + (O_ISSET(sp, O_LEFTRIGHT) ? + smp->coff : (smp->soff - 1) * sp->cols) + + sp->rcm % sp->cols); + } + return (0); + case Z_CARAT: + /* The z^ command moves the cursor to the first new line. */ + break; + default: + abort(); + } + + if (!SMAP_CACHE(smp) && vs_line(sp, smp, NULL, NULL)) + return (1); + rp->lno = smp->lno; + rp->cno = smp->c_scoff == 255 ? 0 : smp->c_sboff; + return (0); +} + +/* + * vs_sm_erase -- + * Erase the small screen area for the scrolling functions. + */ +static int +vs_sm_erase(SCR *sp) +{ + GS *gp; + + gp = sp->gp; + (void)gp->scr_move(sp, LASTLINE(sp), 0); + (void)gp->scr_clrtoeol(sp); + for (; sp->t_rows > sp->t_minrows; --sp->t_rows, --TMAP) { + (void)gp->scr_move(sp, TMAP - HMAP, 0); + (void)gp->scr_clrtoeol(sp); + } + return (0); +} + +/* + * vs_sm_1down -- + * Scroll the SMAP down one. + * + * PUBLIC: int vs_sm_1down(SCR *); + */ +int +vs_sm_1down(SCR *sp) +{ + /* + * Insert a line at the top of the screen. Shift the screen map + * down and display a new line at the top of the screen. + */ + (void)sp->gp->scr_move(sp, 0, 0); + if (vs_insertln(sp, 1)) + return (1); + + /* One-line screens can fail. */ + if (IS_ONELINE(sp)) { + if (vs_sm_prev(sp, HMAP, HMAP)) + return (1); + } else { + memmove(HMAP + 1, HMAP, (sp->rows - 1) * sizeof(SMAP)); + if (vs_sm_prev(sp, HMAP + 1, HMAP)) + return (1); + } + /* vs_sm_prev() flushed the cache. */ + return (vs_line(sp, HMAP, NULL, NULL)); +} + +/* + * vs_insertln -- + * Insert a line a la curses, make sure to put the information + * line and other screens back. + */ +static int +vs_insertln(SCR *sp, int cnt) +{ + GS *gp; + size_t oldy, oldx; + + gp = sp->gp; + + /* If the screen is vertically split, we can't scroll it. */ + if (IS_VSPLIT(sp)) { + F_SET(sp, SC_SCR_REDRAW); + return (0); + } + + if (IS_ONELINE(sp)) { + (void)gp->scr_move(sp, LASTLINE(sp), 0); + (void)gp->scr_clrtoeol(sp); + } else { + (void)gp->scr_cursor(sp, &oldy, &oldx); + while (cnt--) { + (void)gp->scr_move(sp, LASTLINE(sp) - 1, 0); + (void)gp->scr_deleteln(sp); + (void)gp->scr_move(sp, oldy, oldx); + (void)gp->scr_insertln(sp); + } + } + return (0); +} + +/* + * vs_sm_next -- + * Fill in the next entry in the SMAP. + * + * PUBLIC: int vs_sm_next(SCR *, SMAP *, SMAP *); + */ +int +vs_sm_next(SCR *sp, SMAP *p, SMAP *t) +{ + size_t lcnt; + + SMAP_FLUSH(t); + if (O_ISSET(sp, O_LEFTRIGHT)) { + t->lno = p->lno + 1; + t->coff = p->coff; + } else { + lcnt = vs_screens(sp, p->lno, NULL); + if (lcnt == p->soff) { + t->lno = p->lno + 1; + t->soff = 1; + } else { + t->lno = p->lno; + t->soff = p->soff + 1; + } + } + return (0); +} + +/* + * vs_sm_prev -- + * Fill in the previous entry in the SMAP. + * + * PUBLIC: int vs_sm_prev(SCR *, SMAP *, SMAP *); + */ +int +vs_sm_prev(SCR *sp, SMAP *p, SMAP *t) +{ + SMAP_FLUSH(t); + if (O_ISSET(sp, O_LEFTRIGHT)) { + t->lno = p->lno - 1; + t->coff = p->coff; + } else { + if (p->soff != 1) { + t->lno = p->lno; + t->soff = p->soff - 1; + } else { + t->lno = p->lno - 1; + t->soff = vs_screens(sp, t->lno, NULL); + } + } + return (t->lno == 0); +} + +/* + * vs_sm_cursor -- + * Return the SMAP entry referenced by the cursor. + * + * PUBLIC: int vs_sm_cursor(SCR *, SMAP **); + */ +int +vs_sm_cursor(SCR *sp, SMAP **smpp) +{ + SMAP *p; + + /* See if the cursor is not in the map. */ + if (sp->lno < HMAP->lno || sp->lno > TMAP->lno) + return (1); + + /* Find the first occurence of the line. */ + for (p = HMAP; p->lno != sp->lno; ++p); + + /* Fill in the map information until we find the right line. */ + for (; p <= TMAP; ++p) { + /* Short lines are common and easy to detect. */ + if (p != TMAP && (p + 1)->lno != p->lno) { + *smpp = p; + return (0); + } + if (!SMAP_CACHE(p) && vs_line(sp, p, NULL, NULL)) + return (1); + if (p->c_eboff >= sp->cno) { + *smpp = p; + return (0); + } + } + + /* It was past the end of the map after all. */ + return (1); +} + +/* + * vs_sm_position -- + * Return the line/column of the top, middle or last line on the screen. + * (The vi H, M and L commands.) Here because only the screen routines + * know what's really out there. + * + * PUBLIC: int vs_sm_position(SCR *, MARK *, u_long, pos_t); + */ +int +vs_sm_position(SCR *sp, MARK *rp, u_long cnt, pos_t pos) +{ + SMAP *smp; + recno_t last; + + switch (pos) { + case P_TOP: + /* + * !!! + * Historically, an invalid count to the H command failed. + * We do nothing special here, just making sure that H in + * an empty screen works. + */ + if (cnt > TMAP - HMAP) + goto sof; + smp = HMAP + cnt; + if (cnt && !db_exist(sp, smp->lno)) { +sof: msgq(sp, M_BERR, "220|Movement past the end-of-screen"); + return (1); + } + break; + case P_MIDDLE: + /* + * !!! + * Historically, a count to the M command was ignored. + * If the screen isn't filled, find the middle of what's + * real and move there. + */ + if (!db_exist(sp, TMAP->lno)) { + if (db_last(sp, &last)) + return (1); + for (smp = TMAP; smp->lno > last && smp > HMAP; --smp); + if (smp > HMAP) + smp -= (smp - HMAP) / 2; + } else + smp = (HMAP + (TMAP - HMAP) / 2) + cnt; + break; + case P_BOTTOM: + /* + * !!! + * Historically, an invalid count to the L command failed. + * If the screen isn't filled, find the bottom of what's + * real and try to offset from there. + */ + if (cnt > TMAP - HMAP) + goto eof; + smp = TMAP - cnt; + if (!db_exist(sp, smp->lno)) { + if (db_last(sp, &last)) + return (1); + for (; smp->lno > last && smp > HMAP; --smp); + if (cnt > smp - HMAP) { +eof: msgq(sp, M_BERR, + "221|Movement past the beginning-of-screen"); + return (1); + } + smp -= cnt; + } + break; + default: + abort(); + } + + /* Make sure that the cached information is valid. */ + if (!SMAP_CACHE(smp) && vs_line(sp, smp, NULL, NULL)) + return (1); + rp->lno = smp->lno; + rp->cno = smp->c_sboff; + + return (0); +} + +/* + * vs_sm_nlines -- + * Return the number of screen lines from an SMAP entry to the + * start of some file line, less than a maximum value. + * + * PUBLIC: recno_t vs_sm_nlines(SCR *, SMAP *, recno_t, size_t); + */ +recno_t +vs_sm_nlines(SCR *sp, SMAP *from_sp, recno_t to_lno, size_t max) +{ + recno_t lno, lcnt; + + if (O_ISSET(sp, O_LEFTRIGHT)) + return (from_sp->lno > to_lno ? + from_sp->lno - to_lno : to_lno - from_sp->lno); + + if (from_sp->lno == to_lno) + return (from_sp->soff - 1); + + if (from_sp->lno > to_lno) { + lcnt = from_sp->soff - 1; /* Correct for off-by-one. */ + for (lno = from_sp->lno; --lno >= to_lno && lcnt <= max;) + lcnt += vs_screens(sp, lno, NULL); + } else { + lno = from_sp->lno; + lcnt = (vs_screens(sp, lno, NULL) - from_sp->soff) + 1; + for (; ++lno < to_lno && lcnt <= max;) + lcnt += vs_screens(sp, lno, NULL); + } + return (lcnt); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/vi/vs_smap.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/vi/extern.h =================================================================== --- vendor/nvi/2.2.0-05ed8b9/vi/extern.h (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/vi/extern.h (revision 366308) @@ -0,0 +1,145 @@ +int cs_init(SCR *, VCS *); +int cs_next(SCR *, VCS *); +int cs_fspace(SCR *, VCS *); +int cs_fblank(SCR *, VCS *); +int cs_prev(SCR *, VCS *); +int cs_bblank(SCR *, VCS *); +int v_at(SCR *, VICMD *); +int v_chrepeat(SCR *, VICMD *); +int v_chrrepeat(SCR *, VICMD *); +int v_cht(SCR *, VICMD *); +int v_chf(SCR *, VICMD *); +int v_chT(SCR *, VICMD *); +int v_chF(SCR *, VICMD *); +int v_delete(SCR *, VICMD *); +int v_again(SCR *, VICMD *); +int v_exmode(SCR *, VICMD *); +int v_join(SCR *, VICMD *); +int v_shiftl(SCR *, VICMD *); +int v_shiftr(SCR *, VICMD *); +int v_suspend(SCR *, VICMD *); +int v_switch(SCR *, VICMD *); +int v_tagpush(SCR *, VICMD *); +int v_tagpop(SCR *, VICMD *); +int v_filter(SCR *, VICMD *); +int v_ex(SCR *, VICMD *); +int v_ecl_exec(SCR *); +int v_increment(SCR *, VICMD *); +int v_screen_copy(SCR *, SCR *); +int v_screen_end(SCR *); +int v_optchange(SCR *, int, char *, u_long *); +int v_iA(SCR *, VICMD *); +int v_ia(SCR *, VICMD *); +int v_iI(SCR *, VICMD *); +int v_ii(SCR *, VICMD *); +int v_iO(SCR *, VICMD *); +int v_io(SCR *, VICMD *); +int v_change(SCR *, VICMD *); +int v_Replace(SCR *, VICMD *); +int v_subst(SCR *, VICMD *); +int v_left(SCR *, VICMD *); +int v_cfirst(SCR *, VICMD *); +int v_first(SCR *, VICMD *); +int v_ncol(SCR *, VICMD *); +int v_zero(SCR *, VICMD *); +int v_mark(SCR *, VICMD *); +int v_bmark(SCR *, VICMD *); +int v_fmark(SCR *, VICMD *); +int v_emark(SCR *, VICMD *); +int v_match(SCR *, VICMD *); +int v_buildmcs(SCR *, char *); +int v_paragraphf(SCR *, VICMD *); +int v_paragraphb(SCR *, VICMD *); +int v_buildps(SCR *, char *, char *); +int v_Put(SCR *, VICMD *); +int v_put(SCR *, VICMD *); +int v_redraw(SCR *, VICMD *); +int v_replace(SCR *, VICMD *); +int v_right(SCR *, VICMD *); +int v_dollar(SCR *, VICMD *); +int v_screen(SCR *, VICMD *); +int v_lgoto(SCR *, VICMD *); +int v_home(SCR *, VICMD *); +int v_middle(SCR *, VICMD *); +int v_bottom(SCR *, VICMD *); +int v_up(SCR *, VICMD *); +int v_cr(SCR *, VICMD *); +int v_down(SCR *, VICMD *); +int v_hpageup(SCR *, VICMD *); +int v_hpagedown(SCR *, VICMD *); +int v_pagedown(SCR *, VICMD *); +int v_pageup(SCR *, VICMD *); +int v_lineup(SCR *, VICMD *); +int v_linedown(SCR *, VICMD *); +int v_searchb(SCR *, VICMD *); +int v_searchf(SCR *, VICMD *); +int v_searchN(SCR *, VICMD *); +int v_searchn(SCR *, VICMD *); +int v_searchw(SCR *, VICMD *); +int v_correct(SCR *, VICMD *, int); +int v_sectionf(SCR *, VICMD *); +int v_sectionb(SCR *, VICMD *); +int v_sentencef(SCR *, VICMD *); +int v_sentenceb(SCR *, VICMD *); +int v_status(SCR *, VICMD *); +int v_tcmd(SCR *, VICMD *, ARG_CHAR_T, u_int); +int v_txt(SCR *, VICMD *, MARK *, + const CHAR_T *, size_t, ARG_CHAR_T, recno_t, u_long, u_int32_t); +int v_txt_auto(SCR *, recno_t, TEXT *, size_t, TEXT *); +int v_ulcase(SCR *, VICMD *); +int v_mulcase(SCR *, VICMD *); +int v_Undo(SCR *, VICMD *); +int v_undo(SCR *, VICMD *); +void v_eof(SCR *, MARK *); +void v_eol(SCR *, MARK *); +void v_nomove(SCR *); +void v_sof(SCR *, MARK *); +void v_sol(SCR *); +int v_isempty(CHAR_T *, size_t); +void v_emsg(SCR *, char *, vim_t); +int v_wordW(SCR *, VICMD *); +int v_wordw(SCR *, VICMD *); +int v_wordE(SCR *, VICMD *); +int v_worde(SCR *, VICMD *); +int v_wordB(SCR *, VICMD *); +int v_wordb(SCR *, VICMD *); +int v_xchar(SCR *, VICMD *); +int v_Xchar(SCR *, VICMD *); +int v_yank(SCR *, VICMD *); +int v_z(SCR *, VICMD *); +int vs_crel(SCR *, long); +int v_zexit(SCR *, VICMD *); +int vi(SCR **); +int v_curword(SCR *); +int vs_line(SCR *, SMAP *, size_t *, size_t *); +int vs_number(SCR *); +void vs_busy(SCR *, const char *, busy_t); +void vs_home(SCR *); +void vs_update(SCR *, const char *, const CHAR_T *); +void vs_msg(SCR *, mtype_t, char *, size_t); +int vs_ex_resolve(SCR *, int *); +int vs_resolve(SCR *, SCR *, int); +int vs_repaint(SCR *, EVENT *); +int vs_refresh(SCR *, int); +int vs_column(SCR *, size_t *); +size_t vs_screens(SCR *, recno_t, size_t *); +size_t vs_columns(SCR *, CHAR_T *, recno_t, size_t *, size_t *); +size_t vs_rcm(SCR *, recno_t, int); +size_t vs_colpos(SCR *, recno_t, size_t); +int vs_change(SCR *, recno_t, lnop_t); +int vs_sm_fill(SCR *, recno_t, pos_t); +int vs_sm_scroll(SCR *, MARK *, recno_t, scroll_t); +int vs_sm_1up(SCR *); +int vs_sm_1down(SCR *); +int vs_sm_next(SCR *, SMAP *, SMAP *); +int vs_sm_prev(SCR *, SMAP *, SMAP *); +int vs_sm_cursor(SCR *, SMAP **); +int vs_sm_position(SCR *, MARK *, u_long, pos_t); +recno_t vs_sm_nlines(SCR *, SMAP *, recno_t, size_t); +int vs_split(SCR *, SCR *, int); +int vs_vsplit(SCR *, SCR *); +int vs_discard(SCR *, SCR **); +int vs_fg(SCR *, SCR **, CHAR_T *, int); +int vs_bg(SCR *); +int vs_swap(SCR *, SCR **, char *); +int vs_resize(SCR *, long, adj_t); Property changes on: vendor/nvi/2.2.0-05ed8b9/vi/extern.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/vi/getc.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/vi/getc.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/vi/getc.c (revision 366308) @@ -0,0 +1,218 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "../common/common.h" +#include "vi.h" + +/* + * Character stream routines -- + * These routines return the file a character at a time. There are two + * special cases. First, the end of a line, end of a file, start of a + * file and empty lines are returned as special cases, and no character + * is returned. Second, empty lines include lines that have only white + * space in them, because the vi search functions don't care about white + * space, and this makes it easier for them to be consistent. + */ + +/* + * cs_init -- + * Initialize character stream routines. + * + * PUBLIC: int cs_init(SCR *, VCS *); + */ +int +cs_init(SCR *sp, VCS *csp) +{ + int isempty; + + if (db_eget(sp, csp->cs_lno, &csp->cs_bp, &csp->cs_len, &isempty)) { + if (isempty) + msgq(sp, M_BERR, "177|Empty file"); + return (1); + } + if (csp->cs_len == 0 || v_isempty(csp->cs_bp, csp->cs_len)) { + csp->cs_cno = 0; + csp->cs_flags = CS_EMP; + } else { + csp->cs_flags = 0; + csp->cs_ch = csp->cs_bp[csp->cs_cno]; + } + return (0); +} + +/* + * cs_next -- + * Retrieve the next character. + * + * PUBLIC: int cs_next(SCR *, VCS *); + */ +int +cs_next(SCR *sp, VCS *csp) +{ + CHAR_T *p; + + switch (csp->cs_flags) { + case CS_EMP: /* EMP; get next line. */ + case CS_EOL: /* EOL; get next line. */ + if (db_get(sp, ++csp->cs_lno, 0, &p, &csp->cs_len)) { + --csp->cs_lno; + csp->cs_flags = CS_EOF; + } else { + csp->cs_bp = p; + if (csp->cs_len == 0 || + v_isempty(csp->cs_bp, csp->cs_len)) { + csp->cs_cno = 0; + csp->cs_flags = CS_EMP; + } else { + csp->cs_flags = 0; + csp->cs_ch = csp->cs_bp[csp->cs_cno = 0]; + } + } + break; + case 0: + if (csp->cs_cno == csp->cs_len - 1) + csp->cs_flags = CS_EOL; + else + csp->cs_ch = csp->cs_bp[++csp->cs_cno]; + break; + case CS_EOF: /* EOF. */ + break; + default: + abort(); + /* NOTREACHED */ + } + return (0); +} + +/* + * cs_fspace -- + * If on a space, eat forward until something other than a + * whitespace character. + * + * XXX + * Semantics of checking the current character were coded for the fword() + * function -- once the other word routines are converted, they may have + * to change. + * + * PUBLIC: int cs_fspace(SCR *, VCS *); + */ +int +cs_fspace(SCR *sp, VCS *csp) +{ + if (csp->cs_flags != 0 || !ISBLANK(csp->cs_ch)) + return (0); + for (;;) { + if (cs_next(sp, csp)) + return (1); + if (csp->cs_flags != 0 || !ISBLANK(csp->cs_ch)) + break; + } + return (0); +} + +/* + * cs_fblank -- + * Eat forward to the next non-whitespace character. + * + * PUBLIC: int cs_fblank(SCR *, VCS *); + */ +int +cs_fblank(SCR *sp, VCS *csp) +{ + for (;;) { + if (cs_next(sp, csp)) + return (1); + if (csp->cs_flags == CS_EOL || csp->cs_flags == CS_EMP || + (csp->cs_flags == 0 && ISBLANK(csp->cs_ch))) + continue; + break; + } + return (0); +} + +/* + * cs_prev -- + * Retrieve the previous character. + * + * PUBLIC: int cs_prev(SCR *, VCS *); + */ +int +cs_prev(SCR *sp, VCS *csp) +{ + switch (csp->cs_flags) { + case CS_EMP: /* EMP; get previous line. */ + case CS_EOL: /* EOL; get previous line. */ + if (csp->cs_lno == 1) { /* SOF. */ + csp->cs_flags = CS_SOF; + break; + } + if (db_get(sp, /* The line should exist. */ + --csp->cs_lno, DBG_FATAL, &csp->cs_bp, &csp->cs_len)) { + ++csp->cs_lno; + return (1); + } + if (csp->cs_len == 0 || v_isempty(csp->cs_bp, csp->cs_len)) { + csp->cs_cno = 0; + csp->cs_flags = CS_EMP; + } else { + csp->cs_flags = 0; + csp->cs_cno = csp->cs_len - 1; + csp->cs_ch = csp->cs_bp[csp->cs_cno]; + } + break; + case CS_EOF: /* EOF: get previous char. */ + case 0: + if (csp->cs_cno == 0) + if (csp->cs_lno == 1) + csp->cs_flags = CS_SOF; + else + csp->cs_flags = CS_EOL; + else + csp->cs_ch = csp->cs_bp[--csp->cs_cno]; + break; + case CS_SOF: /* SOF. */ + break; + default: + abort(); + /* NOTREACHED */ + } + return (0); +} + +/* + * cs_bblank -- + * Eat backward to the next non-whitespace character. + * + * PUBLIC: int cs_bblank(SCR *, VCS *); + */ +int +cs_bblank(SCR *sp, VCS *csp) +{ + for (;;) { + if (cs_prev(sp, csp)) + return (1); + if (csp->cs_flags == CS_EOL || csp->cs_flags == CS_EMP || + (csp->cs_flags == 0 && ISBLANK(csp->cs_ch))) + continue; + break; + } + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/vi/getc.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/vi/v_at.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/vi/v_at.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/vi/v_at.c (revision 366308) @@ -0,0 +1,109 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "../common/common.h" +#include "vi.h" + +/* + * v_at -- @ + * Execute a buffer. + * + * PUBLIC: int v_at(SCR *, VICMD *); + */ +int +v_at(SCR *sp, VICMD *vp) +{ + CB *cbp; + CHAR_T name; + TEXT *tp; + size_t len; + char nbuf[20]; + CHAR_T wbuf[20]; + CHAR_T *wp; + size_t wlen; + + /* + * !!! + * Historically, [@*] and [@*][@*] executed the most + * recently executed buffer in ex mode. In vi mode, only @@ repeated + * the last buffer. We change historic practice and make @* work from + * vi mode as well, it's simpler and more consistent. + * + * My intent is that *[buffer] will, in the future, pass the buffer to + * whatever interpreter is loaded. + */ + name = F_ISSET(vp, VC_BUFFER) ? vp->buffer : '@'; + if (name == '@' || name == '*') { + if (!F_ISSET(sp, SC_AT_SET)) { + ex_emsg(sp, NULL, EXM_NOPREVBUF); + return (1); + } + name = sp->at_lbuf; + } + F_SET(sp, SC_AT_SET); + + CBNAME(sp, cbp, name); + if (cbp == NULL) { + ex_emsg(sp, KEY_NAME(sp, name), EXM_EMPTYBUF); + return (1); + } + + /* Save for reuse. */ + sp->at_lbuf = name; + + /* + * The buffer is executed in vi mode, while in vi mode, so simply + * push it onto the terminal queue and continue. + * + * !!! + * Historic practice is that if the buffer was cut in line mode, + * were appended to each line as it was pushed onto + * the stack. If the buffer was cut in character mode, + * were appended to all lines but the last one. + * + * XXX + * Historic practice is that execution of an @ buffer could be + * undone by a single 'u' command, i.e. the changes were grouped + * together. We don't get this right; I'm waiting for the new DB + * logging code to be available. + */ + TAILQ_FOREACH_REVERSE(tp, cbp->textq, _texth, q) { + if (((F_ISSET(cbp, CB_LMODE) || + TAILQ_NEXT(tp, q) != NULL) && + v_event_push(sp, NULL, L("\n"), 1, 0)) || + v_event_push(sp, NULL, tp->lb, tp->len, 0)) + return (1); + } + + /* + * !!! + * If any count was supplied, it applies to the first command in the + * at buffer. + */ + if (F_ISSET(vp, VC_C1SET)) { + len = snprintf(nbuf, sizeof(nbuf), "%lu", vp->count); + CHAR2INT(sp, nbuf, len, wp, wlen); + MEMCPY(wbuf, wp, wlen); + if (v_event_push(sp, NULL, wp, wlen, 0)) + return (1); + } + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/vi/v_at.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/vi/v_ch.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/vi/v_ch.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/vi/v_ch.c (revision 366308) @@ -0,0 +1,287 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include + +#include "../common/common.h" +#include "vi.h" + +static void notfound(SCR *, ARG_CHAR_T); +static void noprev(SCR *); + +/* + * v_chrepeat -- [count]; + * Repeat the last F, f, T or t search. + * + * PUBLIC: int v_chrepeat(SCR *, VICMD *); + */ +int +v_chrepeat(SCR *sp, VICMD *vp) +{ + vp->character = VIP(sp)->lastckey; + + switch (VIP(sp)->csearchdir) { + case CNOTSET: + noprev(sp); + return (1); + case FSEARCH: + return (v_chF(sp, vp)); + case fSEARCH: + return (v_chf(sp, vp)); + case TSEARCH: + return (v_chT(sp, vp)); + case tSEARCH: + return (v_cht(sp, vp)); + default: + abort(); + } + /* NOTREACHED */ +} + +/* + * v_chrrepeat -- [count], + * Repeat the last F, f, T or t search in the reverse direction. + * + * PUBLIC: int v_chrrepeat(SCR *, VICMD *); + */ +int +v_chrrepeat(SCR *sp, VICMD *vp) +{ + cdir_t savedir; + int rval; + + vp->character = VIP(sp)->lastckey; + savedir = VIP(sp)->csearchdir; + + switch (VIP(sp)->csearchdir) { + case CNOTSET: + noprev(sp); + return (1); + case FSEARCH: + rval = v_chf(sp, vp); + break; + case fSEARCH: + rval = v_chF(sp, vp); + break; + case TSEARCH: + rval = v_cht(sp, vp); + break; + case tSEARCH: + rval = v_chT(sp, vp); + break; + default: + abort(); + } + VIP(sp)->csearchdir = savedir; + return (rval); +} + +/* + * v_cht -- [count]tc + * Search forward in the line for the character before the next + * occurrence of the specified character. + * + * PUBLIC: int v_cht(SCR *, VICMD *); + */ +int +v_cht(SCR *sp, VICMD *vp) +{ + if (v_chf(sp, vp)) + return (1); + + /* + * v_chf places the cursor on the character, where the 't' + * command wants it to its left. We know this is safe since + * we had to move right for v_chf() to have succeeded. + */ + --vp->m_stop.cno; + + /* + * Make any necessary correction to the motion decision made + * by the v_chf routine. + */ + if (!ISMOTION(vp)) + vp->m_final = vp->m_stop; + + VIP(sp)->csearchdir = tSEARCH; + return (0); +} + +/* + * v_chf -- [count]fc + * Search forward in the line for the next occurrence of the + * specified character. + * + * PUBLIC: int v_chf(SCR *, VICMD *); + */ +int +v_chf(SCR *sp, VICMD *vp) +{ + size_t len; + u_long cnt; + int isempty; + ARG_CHAR_T key; + CHAR_T *endp, *p, *startp; + + /* + * !!! + * If it's a dot command, it doesn't reset the key for which we're + * searching, e.g. in "df1|f2|.|;", the ';' searches for a '2'. + */ + key = vp->character; + if (!F_ISSET(vp, VC_ISDOT)) + VIP(sp)->lastckey = key; + VIP(sp)->csearchdir = fSEARCH; + + if (db_eget(sp, vp->m_start.lno, &p, &len, &isempty)) { + if (isempty) + goto empty; + return (1); + } + + if (len == 0) { +empty: notfound(sp, key); + return (1); + } + + endp = (startp = p) + len; + p += vp->m_start.cno; + for (cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) { + while (++p < endp && *p != key); + if (p == endp) { + notfound(sp, key); + return (1); + } + } + + vp->m_stop.cno = p - startp; + + /* + * Non-motion commands move to the end of the range. + * Delete and yank stay at the start, ignore others. + */ + vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop; + return (0); +} + +/* + * v_chT -- [count]Tc + * Search backward in the line for the character after the next + * occurrence of the specified character. + * + * PUBLIC: int v_chT(SCR *, VICMD *); + */ +int +v_chT(SCR *sp, VICMD *vp) +{ + if (v_chF(sp, vp)) + return (1); + + /* + * Check whether the matching character is to the immediate left + * of the original cursor position, offset adjusted for a motion + * command. If so, no movement is required. + */ + if (vp->m_start.cno == vp->m_stop.cno) { + return (1); + } + + /* + * v_chF places the cursor on the character, where the 'T' + * command wants it to its right. We know this is safe since + * we had to move left for v_chF() to have succeeded. + */ + ++vp->m_stop.cno; + vp->m_final = vp->m_stop; + + VIP(sp)->csearchdir = TSEARCH; + return (0); +} + +/* + * v_chF -- [count]Fc + * Search backward in the line for the next occurrence of the + * specified character. + * + * PUBLIC: int v_chF(SCR *, VICMD *); + */ +int +v_chF(SCR *sp, VICMD *vp) +{ + size_t len; + u_long cnt; + int isempty; + ARG_CHAR_T key; + CHAR_T *endp, *p; + + /* + * !!! + * If it's a dot command, it doesn't reset the key for which + * we're searching, e.g. in "df1|f2|.|;", the ';' searches + * for a '2'. + */ + key = vp->character; + if (!F_ISSET(vp, VC_ISDOT)) + VIP(sp)->lastckey = key; + VIP(sp)->csearchdir = FSEARCH; + + if (db_eget(sp, vp->m_start.lno, &p, &len, &isempty)) { + if (isempty) + goto empty; + return (1); + } + + if (len == 0) { +empty: notfound(sp, key); + return (1); + } + + endp = p - 1; + p += vp->m_start.cno; + for (cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) { + while (--p > endp && *p != key); + if (p == endp) { + notfound(sp, key); + return (1); + } + } + + vp->m_stop.cno = (p - endp) - 1; + + /* + * All commands move to the end of the range. Motion commands + * adjust the starting point to the character before the current + * one. + */ + vp->m_final = vp->m_stop; + if (ISMOTION(vp)) + --vp->m_start.cno; + return (0); +} + +static void +noprev(SCR *sp) +{ + msgq(sp, M_BERR, "178|No previous F, f, T or t search"); +} + +static void +notfound(SCR *sp, ARG_CHAR_T ch) +{ + msgq(sp, M_BERR, "179|%s not found", KEY_NAME(sp, ch)); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/vi/v_ch.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/vi/v_cmd.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/vi/v_cmd.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/vi/v_cmd.c (revision 366308) @@ -0,0 +1,501 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include + +#include "../common/common.h" +#include "vi.h" + +/* + * This array maps keystrokes to vi command functions. It is known + * in ex/ex_usage.c that it takes four columns to name a vi character. + */ +VIKEYS const vikeys [MAXVIKEY + 1] = { +/* 000 NUL -- The code in vi.c expects key 0 to be undefined. */ + {NULL}, +/* 001 ^A */ + {v_searchw, V_ABS|V_CNT|V_MOVE|V_KEYW|VM_CUTREQ|VM_RCM_SET, + "[count]^A", + "^A search forward for cursor word"}, +/* 002 ^B */ + {v_pageup, V_CNT|VM_RCM_SET, + "[count]^B", + "^B scroll up by screens"}, +/* 003 ^C */ + {NULL, 0, + "^C", + "^C interrupt an operation (e.g. read, write, search)"}, +/* 004 ^D */ + {v_hpagedown, V_CNT|VM_RCM_SET, + "[count]^D", + "^D scroll down by half screens (setting count)"}, +/* 005 ^E */ + {v_linedown, V_CNT, + "[count]^E", + "^E scroll down by lines"}, +/* 006 ^F */ + {v_pagedown, V_CNT|VM_RCM_SET, + "[count]^F", + "^F scroll down by screens"}, +/* 007 ^G */ + {v_status, 0, + "^G", + "^G file status"}, +/* 010 ^H */ + {v_left, V_CNT|V_MOVE|VM_RCM_SET, + "[count]^H", + "^H move left by characters"}, +/* 011 ^I */ + {NULL}, +/* 012 ^J */ + {v_down, V_CNT|V_MOVE|VM_LMODE|VM_RCM, + "[count]^J", + "^J move down by lines"}, +/* 013 ^K */ + {NULL}, +/* 014 ^L */ + {v_redraw, 0, + "^L", + "^L redraw screen"}, +/* 015 ^M */ + {v_cr, V_CNT|V_MOVE|VM_LMODE|VM_RCM_SETFNB, + "[count]^M", + "^M move down by lines (to first non-blank)"}, +/* 016 ^N */ + {v_down, V_CNT|V_MOVE|VM_LMODE|VM_RCM, + "[count]^N", + "^N move down by lines"}, +/* 017 ^O */ + {NULL}, +/* 020 ^P */ + {v_up, V_CNT|V_MOVE|VM_LMODE|VM_RCM, + "[count]^P", + "^P move up by lines"}, +/* 021 ^Q -- same as ^V if not used for hardware flow control. */ + {NULL}, +/* 022 ^R */ + {v_redraw, 0, + "^R", + "^R redraw screen"}, +/* 023 ^S -- not available, used for hardware flow control. */ + {NULL}, +/* 024 ^T */ + {v_tagpop, V_ABS|VM_RCM_SET, + "^T", + "^T tag pop"}, +/* 025 ^U */ + {v_hpageup, V_CNT|VM_RCM_SET, + "[count]^U", + "^U half page up (set count)"}, +/* 026 ^V */ + {NULL, 0, + "^V", + "^V input a literal character"}, +/* 027 ^W */ + {v_screen, 0, + "^W", + "^W move to next screen"}, +/* 030 ^X */ + {NULL}, +/* 031 ^Y */ + {v_lineup, V_CNT, + "[count]^Y", + "^Y page up by lines"}, +/* 032 ^Z */ + {v_suspend, V_SECURE, + "^Z", + "^Z suspend editor"}, +/* 033 ^[ */ + {NULL, 0, + "^[ ", + "^[ exit input mode, cancel partial commands"}, +/* 034 ^\ */ + {v_exmode, 0, + "^\\", + "^\\ switch to ex mode"}, +/* 035 ^] */ + {v_tagpush, V_ABS|V_KEYW|VM_RCM_SET, + "^]", + "^] tag push cursor word"}, +/* 036 ^^ */ + {v_switch, 0, + "^^", + "^^ switch to previous file"}, +/* 037 ^_ */ + {NULL}, +/* 040 ' ' */ + {v_right, V_CNT|V_MOVE|VM_RCM_SET, + "[count]' '", + " move right by columns"}, +/* 041 ! */ + {v_filter, V_CNT|V_DOT|V_MOTION|V_SECURE|VM_RCM_SET, + "[count]![count]motion command(s)", + " ! filter through command(s) to motion"}, +/* 042 " */ + {NULL}, +/* 043 # */ + {v_increment, V_CHAR|V_CNT|V_DOT|VM_RCM_SET, + "[count]# +|-|#", + " # number increment/decrement"}, +/* 044 $ */ + {v_dollar, V_CNT|V_MOVE|VM_RCM_SETLAST, + " [count]$", + " $ move to last column"}, +/* 045 % */ + {v_match, V_ABS|V_CNT|V_MOVE|VM_CUTREQ|VM_RCM_SET, + "%", + " % move to match"}, +/* 046 & */ + {v_again, 0, + "&", + " & repeat substitution"}, +/* 047 ' */ + {v_fmark, V_ABS_L|V_CHAR|V_MOVE|VM_LMODE|VM_RCM_SET, + "'['a-z]", + " ' move to mark (to first non-blank)"}, +/* 050 ( */ + {v_sentenceb, V_ABS|V_CNT|V_MOVE|VM_CUTREQ|VM_RCM_SET, + "[count](", + " ( move back sentence"}, +/* 051 ) */ + {v_sentencef, V_ABS|V_CNT|V_MOVE|VM_CUTREQ|VM_RCM_SET, + "[count])", + " ) move forward sentence"}, +/* 052 * */ + {NULL}, +/* 053 + */ + {v_down, V_CNT|V_MOVE|VM_LMODE|VM_RCM_SETFNB, + "[count]+", + " + move down by lines (to first non-blank)"}, +/* 054 , */ + {v_chrrepeat, V_CNT|V_MOVE|VM_RCM_SET, + "[count],", + " , reverse last F, f, T or t search"}, +/* 055 - */ + {v_up, V_CNT|V_MOVE|VM_LMODE|VM_RCM_SETFNB, + "[count]-", + " - move up by lines (to first non-blank)"}, +/* 056 . */ + {NULL, 0, + ".", + " . repeat the last command"}, +/* 057 / */ + {v_searchf, V_ABS_C|V_MOVE|VM_CUTREQ|VM_RCM_SET, + "/RE[/ offset]", + " / search forward"}, +/* 060 0 */ + {v_zero, V_MOVE|VM_RCM_SET, + "0", + " 0 move to first character"}, +/* 061 1 */ + {NULL}, +/* 062 2 */ + {NULL}, +/* 063 3 */ + {NULL}, +/* 064 4 */ + {NULL}, +/* 065 5 */ + {NULL}, +/* 066 6 */ + {NULL}, +/* 067 7 */ + {NULL}, +/* 070 8 */ + {NULL}, +/* 071 9 */ + {NULL}, +/* 072 : */ + {v_ex, 0, + ":command [| command] ...", + " : ex command"}, +/* 073 ; */ + {v_chrepeat, V_CNT|V_MOVE|VM_RCM_SET, + "[count];", + " ; repeat last F, f, T or t search"}, +/* 074 < */ + {v_shiftl, V_CNT|V_DOT|V_MOTION|VM_RCM_SET, + "[count]<[count]motion", + " < shift lines left to motion"}, +/* 075 = */ + {NULL}, +/* 076 > */ + {v_shiftr, V_CNT|V_DOT|V_MOTION|VM_RCM_SET, + "[count]>[count]motion", + " > shift lines right to motion"}, +/* 077 ? */ + {v_searchb, V_ABS_C|V_MOVE|VM_CUTREQ|VM_RCM_SET, + "?RE[? offset]", + " ? search backward"}, +/* 100 @ */ + {v_at, V_CNT|V_RBUF|VM_RCM_SET, + "@buffer", + " @ execute buffer"}, +/* 101 A */ + {v_iA, V_CNT|V_DOT|VM_RCM_SET, + "[count]A", + " A append to the line"}, +/* 102 B */ + {v_wordB, V_CNT|V_MOVE|VM_RCM_SET, + "[count]B", + " B move back bigword"}, +/* 103 C */ + {NULL, 0, + "[buffer][count]C", + " C change to end-of-line"}, +/* 104 D */ + {NULL, 0, + "[buffer]D", + " D delete to end-of-line"}, +/* 105 E */ + {v_wordE, V_CNT|V_MOVE|VM_RCM_SET, + "[count]E", + " E move to end of bigword"}, +/* 106 F */ + {v_chF, V_CHAR|V_CNT|V_MOVE|VM_RCM_SET, + "[count]F character", + " F character in line backward search"}, +/* 107 G */ + {v_lgoto, V_ABS_L|V_CNT|V_MOVE|VM_LMODE|VM_RCM_SETFNB, + "[count]G", + " G move to line"}, +/* 110 H */ + {v_home, V_ABS_L|V_CNT|V_MOVE|VM_LMODE|VM_RCM_SETNNB, + "[count]H", + " H move to count lines from screen top"}, +/* 111 I */ + {v_iI, V_CNT|V_DOT|VM_RCM_SET, + "[count]I", + " I insert before first nonblank"}, +/* 112 J */ + {v_join, V_CNT|V_DOT|VM_RCM_SET, + "[count]J", + " J join lines"}, +/* 113 K */ + {NULL}, +/* 114 L */ + {v_bottom, V_ABS_L|V_CNT|V_MOVE|VM_LMODE|VM_RCM_SETNNB, + "[count]L", + " L move to screen bottom"}, +/* 115 M */ + {v_middle, V_ABS_L|V_CNT|V_MOVE|VM_LMODE|VM_RCM_SETNNB, + "M", + " M move to screen middle"}, +/* 116 N */ + {v_searchN, V_ABS_C|V_MOVE|VM_CUTREQ|VM_RCM_SET, + "n", + " N reverse last search"}, +/* 117 O */ + {v_iO, V_CNT|V_DOT|VM_RCM_SET, + "[count]O", + " O insert above line"}, +/* 120 P */ + {v_Put, V_CNT|V_DOT|V_OBUF|VM_RCM_SET, + "[buffer]P", + " P insert before cursor from buffer"}, +/* 121 Q */ + {v_exmode, 0, + "Q", + " Q switch to ex mode"}, +/* 122 R */ + {v_Replace, V_CNT|V_DOT|VM_RCM_SET, + "[count]R", + " R replace characters"}, +/* 123 S */ + {NULL, 0, + "[buffer][count]S", + " S substitute for the line(s)"}, +/* 124 T */ + {v_chT, V_CHAR|V_CNT|V_MOVE|VM_RCM_SET, + "[count]T character", + " T before character in line backward search"}, +/* 125 U */ + {v_Undo, VM_RCM_SET, + "U", + " U Restore the current line"}, +/* 126 V */ + {NULL}, +/* 127 W */ + {v_wordW, V_CNT|V_MOVE|VM_RCM_SET, + "[count]W", + " W move to next bigword"}, +/* 130 X */ + {v_Xchar, V_CNT|V_DOT|V_OBUF|VM_RCM_SET, + "[buffer][count]X", + " X delete character before cursor"}, +/* 131 Y */ + {NULL, 0, + "[buffer][count]Y", + " Y copy line"}, +/* 132 Z */ + {v_zexit, 0, + "ZZ", + "ZZ save file and exit"}, +/* 133 [ */ + {v_sectionb, V_ABS|V_CNT|V_MOVE|VM_RCM_SET, + "[[", + "[[ move back section"}, +/* 134 \ */ + {NULL}, +/* 135 ] */ + {v_sectionf, V_ABS|V_CNT|V_MOVE|VM_RCM_SET, + "]]", + "]] move forward section"}, +/* 136 ^ */ + /* + * DON'T set the VM_RCM_SETFNB flag, the function has to do the work + * anyway, in case it's a motion component. DO set VM_RCM_SET, so + * that any motion that's part of a command is preserved. + */ + {v_first, V_CNT|V_MOVE|VM_RCM_SET, + "^", + " ^ move to first non-blank"}, +/* 137 _ */ + /* + * Needs both to set the VM_RCM_SETFNB flag, and to do the work + * in the function, in case it's a delete. + */ + {v_cfirst, V_CNT|V_MOVE|VM_RCM_SETFNB, + "_", + " _ move to first non-blank"}, +/* 140 ` */ + {v_bmark, V_ABS_C|V_CHAR|V_MOVE|VM_CUTREQ|VM_RCM_SET, + "`[`a-z]", + " ` move to mark"}, +/* 141 a */ + {v_ia, V_CNT|V_DOT|VM_RCM_SET, + "[count]a", + " a append after cursor"}, +/* 142 b */ + {v_wordb, V_CNT|V_MOVE|VM_RCM_SET, + "[count]b", + " b move back word"}, +/* 143 c */ + {v_change, V_CNT|V_DOT|V_MOTION|V_OBUF|VM_RCM_SET, + "[buffer][count]c[count]motion", + " c change to motion"}, +/* 144 d */ + {v_delete, V_CNT|V_DOT|V_MOTION|V_OBUF|VM_RCM_SET, + "[buffer][count]d[count]motion", + " d delete to motion"}, +/* 145 e */ + {v_worde, V_CNT|V_MOVE|VM_RCM_SET, + "[count]e", + " e move to end of word"}, +/* 146 f */ + {v_chf, V_CHAR|V_CNT|V_MOVE|VM_RCM_SET, + "[count]f character", + " f character in line forward search"}, +/* 147 g */ + {NULL}, +/* 150 h */ + {v_left, V_CNT|V_MOVE|VM_RCM_SET, + "[count]h", + " h move left by columns"}, +/* 151 i */ + {v_ii, V_CNT|V_DOT|VM_RCM_SET, + "[count]i", + " i insert before cursor"}, +/* 152 j */ + {v_down, V_CNT|V_MOVE|VM_LMODE|VM_RCM, + "[count]j", + " j move down by lines"}, +/* 153 k */ + {v_up, V_CNT|V_MOVE|VM_LMODE|VM_RCM, + "[count]k", + " k move up by lines"}, +/* 154 l */ + {v_right, V_CNT|V_MOVE|VM_RCM_SET, + "[count]l", + " l move right by columns"}, +/* 155 m */ + {v_mark, V_CHAR, + "m[a-z]", + " m set mark"}, +/* 156 n */ + {v_searchn, V_ABS_C|V_MOVE|VM_CUTREQ|VM_RCM_SET, + "n", + " n repeat last search"}, +/* 157 o */ + {v_io, V_CNT|V_DOT|VM_RCM_SET, + "[count]o", + " o append after line"}, +/* 160 p */ + {v_put, V_CNT|V_DOT|V_OBUF|VM_RCM_SET, + "[buffer]p", + " p insert after cursor from buffer"}, +/* 161 q */ + {NULL}, +/* 162 r */ + {v_replace, V_CNT|V_DOT|VM_RCM_SET, + "[count]r character", + " r replace character"}, +/* 163 s */ + {v_subst, V_CNT|V_DOT|V_OBUF|VM_RCM_SET, + "[buffer][count]s", + " s substitute character"}, +/* 164 t */ + {v_cht, V_CHAR|V_CNT|V_MOVE|VM_RCM_SET, + "[count]t character", + " t before character in line forward search"}, +/* 165 u */ + /* + * DON'T set the V_DOT flag, it' more complicated than that. + * See vi/vi.c for details. + */ + {v_undo, VM_RCM_SET, + "u", + " u undo last change"}, +/* 166 v */ + {NULL}, +/* 167 w */ + {v_wordw, V_CNT|V_MOVE|VM_RCM_SET, + "[count]w", + " w move to next word"}, +/* 170 x */ + {v_xchar, V_CNT|V_DOT|V_OBUF|VM_RCM_SET, + "[buffer][count]x", + " x delete character"}, +/* 171 y */ + {v_yank, V_CNT|V_DOT|V_MOTION|V_OBUF|VM_RCM_SET, + "[buffer][count]y[count]motion", + " y copy text to motion into a cut buffer"}, +/* 172 z */ + /* + * DON'T set the V_CHAR flag, the char isn't required, + * so it's handled specially in getcmd(). + */ + {v_z, V_ABS_L|V_CNT|VM_RCM_SETFNB, + "[line]z[window_size][-|.|+|^|]", + " z reposition the screen"}, +/* 173 { */ + {v_paragraphb, V_ABS|V_CNT|V_MOVE|VM_CUTREQ|VM_RCM_SET, + "[count]{", + " { move back paragraph"}, +/* 174 | */ + {v_ncol, V_CNT|V_MOVE|VM_RCM_SET, + "[count]|", + " | move to column"}, +/* 175 } */ + {v_paragraphf, V_ABS|V_CNT|V_MOVE|VM_CUTREQ|VM_RCM_SET, + "[count]}", + " } move forward paragraph"}, +/* 176 ~ */ + {v_ulcase, V_CNT|V_DOT|VM_RCM_SET, + "[count]~", + " ~ reverse case"}, +}; Property changes on: vendor/nvi/2.2.0-05ed8b9/vi/v_cmd.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/vi/v_delete.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/vi/v_delete.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/vi/v_delete.c (revision 366308) @@ -0,0 +1,101 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include + +#include "../common/common.h" +#include "vi.h" + +/* + * v_delete -- [buffer][count]d[count]motion + * [buffer][count]D + * Delete a range of text. + * + * PUBLIC: int v_delete(SCR *, VICMD *); + */ +int +v_delete(SCR *sp, VICMD *vp) +{ + recno_t nlines; + size_t len; + int lmode; + + lmode = F_ISSET(vp, VM_LMODE) ? CUT_LINEMODE : 0; + + /* Yank the lines. */ + if (cut(sp, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL, + &vp->m_start, &vp->m_stop, + lmode | (F_ISSET(vp, VM_CUTREQ) ? CUT_NUMREQ : CUT_NUMOPT))) + return (1); + + /* Delete the lines. */ + if (del(sp, &vp->m_start, &vp->m_stop, lmode)) + return (1); + + /* + * Check for deletion of the entire file. Try to check a close + * by line so we don't go to the end of the file unnecessarily. + */ + if (!db_exist(sp, vp->m_final.lno + 1)) { + if (db_last(sp, &nlines)) + return (1); + if (nlines == 0) { + vp->m_final.lno = 1; + vp->m_final.cno = 0; + return (0); + } + } + + /* + * One special correction, in case we've deleted the current line or + * character. We check it here instead of checking in every command + * that can be a motion component. + */ + if (db_get(sp, vp->m_final.lno, 0, NULL, &len)) { + if (db_get(sp, nlines, DBG_FATAL, NULL, &len)) + return (1); + vp->m_final.lno = nlines; + } + + /* + * !!! + * Cursor movements, other than those caused by a line mode command + * moving to another line, historically reset the relative position. + * + * This currently matches the check made in v_yank(), I'm hoping that + * they should be consistent... + */ + if (!F_ISSET(vp, VM_LMODE)) { + F_CLR(vp, VM_RCM_MASK); + F_SET(vp, VM_RCM_SET); + + /* Make sure the set cursor position exists. */ + if (vp->m_final.cno >= len) + vp->m_final.cno = len ? len - 1 : 0; + } + + /* + * !!! + * The "dd" command moved to the first non-blank; "d" + * didn't. + */ + if (F_ISSET(vp, VM_LDOUBLE)) { + F_CLR(vp, VM_RCM_MASK); + F_SET(vp, VM_RCM_SETFNB); + } + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/vi/v_delete.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/vi/v_ex.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/vi/v_ex.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/vi/v_ex.c (revision 366308) @@ -0,0 +1,646 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "../common/common.h" +#include "vi.h" + +static int v_ecl(SCR *); +static int v_ecl_init(SCR *); +static int v_ecl_log(SCR *, TEXT *); +static int v_ex_done(SCR *, VICMD *); +static int v_exec_ex(SCR *, VICMD *, EXCMD *); + +/* + * v_again -- & + * Repeat the previous substitution. + * + * PUBLIC: int v_again(SCR *, VICMD *); + */ +int +v_again(SCR *sp, VICMD *vp) +{ + EXCMD cmd; + + ex_cinit(sp, &cmd, C_SUBAGAIN, 2, vp->m_start.lno, vp->m_start.lno, 1); + argv_exp0(sp, &cmd, L(""), 1); + return (v_exec_ex(sp, vp, &cmd)); +} + +/* + * v_exmode -- Q + * Switch the editor into EX mode. + * + * PUBLIC: int v_exmode(SCR *, VICMD *); + */ +int +v_exmode(SCR *sp, VICMD *vp) +{ + GS *gp; + + gp = sp->gp; + + /* Try and switch screens -- the screen may not permit it. */ + if (gp->scr_screen(sp, SC_EX)) { + msgq(sp, M_ERR, + "207|The Q command requires the ex terminal interface"); + return (1); + } + (void)gp->scr_attr(sp, SA_ALTERNATE, 0); + + /* Save the current cursor position. */ + sp->frp->lno = sp->lno; + sp->frp->cno = sp->cno; + F_SET(sp->frp, FR_CURSORSET); + + /* Switch to ex mode. */ + F_CLR(sp, SC_VI | SC_SCR_VI); + F_SET(sp, SC_EX); + + /* Move out of the vi screen. */ + (void)ex_puts(sp, "\n"); + + return (0); +} + +/* + * v_join -- [count]J + * Join lines together. + * + * PUBLIC: int v_join(SCR *, VICMD *); + */ +int +v_join(SCR *sp, VICMD *vp) +{ + EXCMD cmd; + int lno; + + /* + * YASC. + * The general rule is that '#J' joins # lines, counting the current + * line. However, 'J' and '1J' are the same as '2J', i.e. join the + * current and next lines. This doesn't map well into the ex command + * (which takes two line numbers), so we handle it here. Note that + * we never test for EOF -- historically going past the end of file + * worked just fine. + */ + lno = vp->m_start.lno + 1; + if (F_ISSET(vp, VC_C1SET) && vp->count > 2) + lno = vp->m_start.lno + (vp->count - 1); + + ex_cinit(sp, &cmd, C_JOIN, 2, vp->m_start.lno, lno, 0); + return (v_exec_ex(sp, vp, &cmd)); +} + +/* + * v_shiftl -- [count]m_start.lno, vp->m_stop.lno, 0); + argv_exp0(sp, &cmd, L("<"), 2); + return (v_exec_ex(sp, vp, &cmd)); +} + +/* + * v_shiftr -- [count]>motion + * Shift lines right. + * + * PUBLIC: int v_shiftr(SCR *, VICMD *); + */ +int +v_shiftr(SCR *sp, VICMD *vp) +{ + EXCMD cmd; + + ex_cinit(sp, &cmd, C_SHIFTR, 2, vp->m_start.lno, vp->m_stop.lno, 0); + argv_exp0(sp, &cmd, L(">"), 2); + return (v_exec_ex(sp, vp, &cmd)); +} + +/* + * v_suspend -- ^Z + * Suspend vi. + * + * PUBLIC: int v_suspend(SCR *, VICMD *); + */ +int +v_suspend(SCR *sp, VICMD *vp) +{ + EXCMD cmd; + + ex_cinit(sp, &cmd, C_STOP, 0, OOBLNO, OOBLNO, 0); + argv_exp0(sp, &cmd, L("suspend"), SIZE(L("suspend"))); + return (v_exec_ex(sp, vp, &cmd)); +} + +/* + * v_switch -- ^^ + * Switch to the previous file. + * + * PUBLIC: int v_switch(SCR *, VICMD *); + */ +int +v_switch(SCR *sp, VICMD *vp) +{ + EXCMD cmd; + char *name; + CHAR_T *wp; + size_t wlen; + + /* + * Try the alternate file name, then the previous file + * name. Use the real name, not the user's current name. + */ + if ((name = sp->alt_name) == NULL) { + msgq(sp, M_ERR, "180|No previous file to edit"); + return (1); + } + + /* If autowrite is set, write out the file. */ + if (file_m1(sp, 0, FS_ALL)) + return (1); + + ex_cinit(sp, &cmd, C_EDIT, 0, OOBLNO, OOBLNO, 0); + CHAR2INT(sp, name, strlen(name) + 1, wp, wlen); + argv_exp0(sp, &cmd, wp, wlen); + return (v_exec_ex(sp, vp, &cmd)); +} + +/* + * v_tagpush -- ^[ + * Do a tag search on the cursor keyword. + * + * PUBLIC: int v_tagpush(SCR *, VICMD *); + */ +int +v_tagpush(SCR *sp, VICMD *vp) +{ + EXCMD cmd; + + ex_cinit(sp, &cmd, C_TAG, 0, OOBLNO, 0, 0); + argv_exp0(sp, &cmd, VIP(sp)->keyw, STRLEN(VIP(sp)->keyw) + 1); + return (v_exec_ex(sp, vp, &cmd)); +} + +/* + * v_tagpop -- ^T + * Pop the tags stack. + * + * PUBLIC: int v_tagpop(SCR *, VICMD *); + */ +int +v_tagpop(SCR *sp, VICMD *vp) +{ + EXCMD cmd; + + ex_cinit(sp, &cmd, C_TAGPOP, 0, OOBLNO, 0, 0); + return (v_exec_ex(sp, vp, &cmd)); +} + +/* + * v_filter -- [count]!motion command(s) + * Run range through shell commands, replacing text. + * + * PUBLIC: int v_filter(SCR *, VICMD *); + */ +int +v_filter(SCR *sp, VICMD *vp) +{ + EXCMD cmd; + TEXT *tp; + + /* + * !!! + * Historical vi permitted "!!" in an empty file, and it's handled + * as a special case in the ex_bang routine. Don't modify this setup + * without understanding that one. In particular, note that we're + * manipulating the ex argument structures behind ex's back. + * + * !!! + * Historical vi did not permit the '!' command to be associated with + * a non-line oriented motion command, in general, although it did + * with search commands. So, !f; and !w would fail, but !/; + * would succeed, even if they all moved to the same location in the + * current line. I don't see any reason to disallow '!' using any of + * the possible motion commands. + * + * !!! + * Historical vi ran the last bang command if N or n was used as the + * search motion. + */ + if (F_ISSET(vp, VC_ISDOT) || + ISCMD(vp->rkp, 'N') || ISCMD(vp->rkp, 'n')) { + ex_cinit(sp, + &cmd, C_BANG, 2, vp->m_start.lno, vp->m_stop.lno, 0); + EXP(sp)->argsoff = 0; /* XXX */ + + if (argv_exp1(sp, &cmd, L("!"), 1, 1)) + return (1); + cmd.argc = EXP(sp)->argsoff; /* XXX */ + cmd.argv = EXP(sp)->args; /* XXX */ + return (v_exec_ex(sp, vp, &cmd)); + } + + /* Get the command from the user. */ + if (v_tcmd(sp, vp, + '!', TXT_BS | TXT_CR | TXT_ESCAPE | TXT_FILEC | TXT_PROMPT)) + return (1); + + /* + * Check to see if the user changed their mind. + * + * !!! + * Entering on an empty line was historically an error, + * this implementation doesn't bother. + */ + tp = TAILQ_FIRST(sp->tiq); + if (tp->term != TERM_OK) { + vp->m_final.lno = sp->lno; + vp->m_final.cno = sp->cno; + return (0); + } + + /* Home the cursor. */ + vs_home(sp); + + ex_cinit(sp, &cmd, C_BANG, 2, vp->m_start.lno, vp->m_stop.lno, 0); + EXP(sp)->argsoff = 0; /* XXX */ + + if (argv_exp1(sp, &cmd, tp->lb + 1, tp->len - 1, 1)) + return (1); + cmd.argc = EXP(sp)->argsoff; /* XXX */ + cmd.argv = EXP(sp)->args; /* XXX */ + return (v_exec_ex(sp, vp, &cmd)); +} + +/* + * v_exec_ex -- + * Execute an ex command. + */ +static int +v_exec_ex(SCR *sp, VICMD *vp, EXCMD *exp) +{ + int rval; + + rval = exp->cmd->fn(sp, exp); + return (v_ex_done(sp, vp) || rval); +} + +/* + * v_ex -- : + * Execute a colon command line. + * + * PUBLIC: int v_ex(SCR *, VICMD *); + */ +int +v_ex(SCR *sp, VICMD *vp) +{ + GS *gp; + TEXT *tp; + int do_cedit, do_resolution, ifcontinue; + + gp = sp->gp; + + /* + * !!! + * If we put out more than a single line of messages, or ex trashes + * the screen, the user may continue entering ex commands. We find + * this out when we do the screen/message resolution. We can't enter + * completely into ex mode however, because the user can elect to + * return into vi mode by entering any key, i.e. we have to be in raw + * mode. + */ + for (do_cedit = do_resolution = 0;;) { + /* + * !!! + * There may already be an ex command waiting to run. If + * so, we continue with it. + */ + if (!EXCMD_RUNNING(gp)) { + /* Get a command. */ + if (v_tcmd(sp, vp, ':', + TXT_BS | TXT_CEDIT | TXT_FILEC | TXT_PROMPT)) + return (1); + tp = TAILQ_FIRST(sp->tiq); + + /* + * If the user entered a single , they want to + * edit their colon command history. If they already + * entered some text, move it into the edit history. + */ + if (tp->term == TERM_CEDIT) { + if (tp->len > 1 && v_ecl_log(sp, tp)) + return (1); + do_cedit = 1; + break; + } + + /* If the user didn't enter anything, return. */ + if (tp->term == TERM_BS) + break; + + /* If the user changed their mind, return. */ + if (tp->term != TERM_OK) + break; + + /* Log the command. */ + if (O_STR(sp, O_CEDIT) != NULL && v_ecl_log(sp, tp)) + return (1); + + /* Push a command on the command stack. */ + if (ex_run_str(sp, NULL, tp->lb, tp->len, 0, 1)) + return (1); + } + + /* Home the cursor. */ + vs_home(sp); + + /* + * !!! + * If the editor wrote the screen behind curses back, put out + * a so that we don't overwrite the user's command + * with its output or the next want-to-continue? message. This + * doesn't belong here, but I can't find another place to put + * it. See, we resolved the output from the last ex command, + * and the user entered another one. This is the only place + * where we have control before the ex command writes output. + * We could get control in vs_msg(), but we have no way to know + * if command didn't put out any output when we try and resolve + * this command. This fixes a bug where combinations of ex + * commands, e.g. ":set:!date:set" didn't look right. + */ + if (F_ISSET(sp, SC_SCR_EXWROTE)) + (void)putchar('\n'); + + /* Call the ex parser. */ + (void)ex_cmd(sp); + + /* Flush ex messages. */ + (void)ex_fflush(sp); + + /* Resolve any messages. */ + if (vs_ex_resolve(sp, &ifcontinue)) + return (1); + + /* + * Continue or return. If continuing, make sure that we + * eventually do resolution. + */ + if (!ifcontinue) + break; + do_resolution = 1; + + /* If we're continuing, it's a new command. */ + ++sp->ccnt; + } + + /* + * If the user previously continued an ex command, we have to do + * resolution to clean up the screen. Don't wait, we already did + * that. + */ + if (do_resolution) { + F_SET(sp, SC_EX_WAIT_NO); + if (vs_ex_resolve(sp, &ifcontinue)) + return (1); + } + + /* Cleanup from the ex command. */ + if (v_ex_done(sp, vp)) + return (1); + + /* The user may want to edit their colon command history. */ + if (do_cedit) + return (v_ecl(sp)); + + return (0); +} + +/* + * v_ex_done -- + * Cleanup from an ex command. + */ +static int +v_ex_done(SCR *sp, VICMD *vp) +{ + size_t len; + + /* + * The only cursor modifications are real, however, the underlying + * line may have changed; don't trust anything. This code has been + * a remarkably fertile place for bugs. Do a reality check on a + * cursor value, and make sure it's okay. If necessary, change it. + * Ex keeps track of the line number, but it cares less about the + * column and it may have disappeared. + * + * Don't trust ANYTHING. + * + * XXX + * Ex will soon have to start handling the column correctly; see + * the POSIX 1003.2 standard. + */ + if (db_eget(sp, sp->lno, NULL, &len, NULL)) { + sp->lno = 1; + sp->cno = 0; + } else if (sp->cno >= len) + sp->cno = len ? len - 1 : 0; + + vp->m_final.lno = sp->lno; + vp->m_final.cno = sp->cno; + + /* + * Don't re-adjust the cursor after executing an ex command, + * and ex movements are permanent. + */ + F_CLR(vp, VM_RCM_MASK); + F_SET(vp, VM_RCM_SET); + + return (0); +} + +/* + * v_ecl -- + * Start an edit window on the colon command-line commands. + */ +static int +v_ecl(SCR *sp) +{ + GS *gp; + SCR *new; + + /* Initialize the screen, if necessary. */ + gp = sp->gp; + if (gp->ccl_sp == NULL && v_ecl_init(sp)) + return (1); + + /* Get a new screen. */ + if (screen_init(gp, sp, &new)) + return (1); + if (vs_split(sp, new, 1)) { + (void)screen_end(new); + return (1); + } + + /* Attach to the screen. */ + new->ep = gp->ccl_sp->ep; + ++new->ep->refcnt; + + new->frp = gp->ccl_sp->frp; + new->frp->flags = sp->frp->flags; + + /* Move the cursor to the end. */ + (void)db_last(new, &new->lno); + if (new->lno == 0) + new->lno = 1; + + /* Remember the originating window. */ + sp->ccl_parent = sp; + + /* It's a special window. */ + F_SET(new, SC_COMEDIT); + +#if defined(USE_WIDECHAR) && defined(USE_ICONV) + /* Bypass iconv on writing to DB. */ + o_set(new, O_FILEENCODING, OS_STRDUP, codeset(), 0); +#endif + + /* Set up the switch. */ + sp->nextdisp = new; + F_SET(sp, SC_SSWITCH); + return (0); +} + +/* + * v_ecl_exec -- + * Execute a command from a colon command-line window. + * + * PUBLIC: int v_ecl_exec(SCR *); + */ +int +v_ecl_exec(SCR *sp) +{ + size_t len; + CHAR_T *p; + + if (db_get(sp, sp->lno, 0, &p, &len) && sp->lno == 1) { + v_emsg(sp, NULL, VIM_EMPTY); + return (1); + } + if (len == 0) { + msgq(sp, M_BERR, "307|No ex command to execute"); + return (1); + } + + /* Push the command on the command stack. */ + if (ex_run_str(sp, NULL, p, len, 0, 0)) + return (1); + + /* Set up the switch. */ + sp->nextdisp = sp->ccl_parent; + F_SET(sp, SC_EXIT); + return (0); +} + +/* + * v_ecl_log -- + * Log a command into the colon command-line log file. + */ +static int +v_ecl_log(SCR *sp, TEXT *tp) +{ + recno_t lno; + int rval; + CHAR_T *p; + size_t len; + SCR *ccl_sp; + + /* Initialize the screen, if necessary. */ + if (sp->gp->ccl_sp == NULL && v_ecl_init(sp)) + return (1); + + ccl_sp = sp->gp->ccl_sp; + + /* + * Don't log colon command window commands into the colon command + * window... + */ + if (sp->ep == ccl_sp->ep) + return (0); + + if (db_last(ccl_sp, &lno)) { + return (1); + } + /* Don't log line that is identical to previous one */ + if (lno > 0 && + !db_get(ccl_sp, lno, 0, &p, &len) && + len == tp->len && + !MEMCMP(tp->lb, p, len)) + rval = 0; + else { + rval = db_append(ccl_sp, 0, lno, tp->lb, tp->len); + /* XXXX end "transaction" on ccl */ + /* Is this still necessary now that we no longer hijack sp ? */ + log_cursor(ccl_sp); + } + + return (rval); +} + +/* + * v_ecl_init -- + * Initialize the colon command-line log file. + */ +static int +v_ecl_init(SCR *sp) +{ + FREF *frp; + GS *gp; + + gp = sp->gp; + + /* Get a temporary file. */ + if ((frp = file_add(sp, NULL)) == NULL) + return (1); + + /* + * XXX + * Create a screen -- the file initialization code wants one. + */ + if (screen_init(gp, sp, &gp->ccl_sp)) + return (1); + if (file_init(gp->ccl_sp, frp, NULL, 0)) { + (void)screen_end(gp->ccl_sp); + gp->ccl_sp = NULL; + return (1); + } + + /* The underlying file isn't recoverable. */ + F_CLR(gp->ccl_sp->ep, F_RCV_ON); + + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/vi/v_ex.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/vi/v_increment.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/vi/v_increment.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/vi/v_increment.c (revision 366308) @@ -0,0 +1,260 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "../common/common.h" +#include "vi.h" + +static CHAR_T * const fmt[] = { +#define DEC 0 + L("%ld"), +#define SDEC 1 + L("%+ld"), +#define HEXC 2 + L("0X%0*lX"), +#define HEXL 3 + L("0x%0*lx"), +#define OCTAL 4 + L("%#0*lo"), +}; + +static void inc_err(SCR *, enum nresult); + +/* + * v_increment -- [count]#[#+-] + * Increment/decrement a keyword number. + * + * PUBLIC: int v_increment(SCR *, VICMD *); + */ +int +v_increment(SCR *sp, VICMD *vp) +{ + enum nresult nret; + u_long ulval; + long change, ltmp, lval; + size_t beg, blen, end, len, nlen, wlen; + int base, isempty, rval; + CHAR_T *ntype, nbuf[100]; + CHAR_T *bp, *p, *t; + + /* Validate the operator. */ + if (vp->character == '#') + vp->character = '+'; + if (vp->character != '+' && vp->character != '-') { + v_emsg(sp, vp->kp->usage, VIM_USAGE); + return (1); + } + + /* If new value set, save it off, but it has to fit in a long. */ + if (F_ISSET(vp, VC_C1SET)) { + if (vp->count > LONG_MAX) { + inc_err(sp, NUM_OVER); + return (1); + } + change = vp->count; + } else + change = 1; + + /* Get the line. */ + if (db_eget(sp, vp->m_start.lno, &p, &len, &isempty)) { + if (isempty) + goto nonum; + return (1); + } + + /* + * Skip any leading space before the number. Getting a cursor word + * implies moving the cursor to its beginning, if we moved, refresh + * now. + */ + for (beg = vp->m_start.cno; beg < len && ISSPACE(p[beg]); ++beg); + if (beg >= len) + goto nonum; + if (beg != vp->m_start.cno) { + sp->cno = beg; + (void)vs_refresh(sp, 0); + } + +#undef ishex +#define ishex(c) (ISXDIGIT(c)) +#undef isoctal +#define isoctal(c) ((c) >= '0' && (c) <= '7') + + /* + * Look for 0[Xx], or leading + or - signs, guess at the base. + * The character after that must be a number. Wlen is set to + * the remaining characters in the line that could be part of + * the number. + */ + wlen = len - beg; + if (p[beg] == '0' && wlen > 2 && + (p[beg + 1] == 'X' || p[beg + 1] == 'x')) { + base = 16; + end = beg + 2; + if (!ishex(p[end])) + goto decimal; + ntype = p[beg + 1] == 'X' ? fmt[HEXC] : fmt[HEXL]; + } else if (p[beg] == '0' && wlen > 1) { + base = 8; + end = beg + 1; + if (!isoctal(p[end])) + goto decimal; + ntype = fmt[OCTAL]; + } else if (wlen >= 1 && (p[beg] == '+' || p[beg] == '-')) { + base = 10; + end = beg + 1; + ntype = fmt[SDEC]; + if (!isdigit(p[end])) + goto nonum; + } else { +decimal: base = 10; + end = beg; + ntype = fmt[DEC]; + if (!isdigit(p[end])) { +nonum: msgq(sp, M_ERR, "181|Cursor not in a number"); + return (1); + } + } + + /* Find the end of the word, possibly correcting the base. */ + while (++end < len) { + switch (base) { + case 8: + if (isoctal(p[end])) + continue; + if (p[end] == '8' || p[end] == '9') { + base = 10; + ntype = fmt[DEC]; + continue; + } + break; + case 10: + if (isdigit(p[end])) + continue; + break; + case 16: + if (ishex(p[end])) + continue; + break; + default: + abort(); + /* NOTREACHED */ + } + break; + } + wlen = (end - beg); + + /* + * XXX + * If the line was at the end of the buffer, we have to copy it + * so we can guarantee that it's NULL-terminated. We make the + * buffer big enough to fit the line changes as well, and only + * allocate once. + */ + GET_SPACE_RETW(sp, bp, blen, len + 50); + if (end == len) { + MEMMOVE(bp, &p[beg], wlen); + bp[wlen] = '\0'; + t = bp; + } else + t = &p[beg]; + + /* + * Octal or hex deal in unsigned longs, everything else is done + * in signed longs. + */ + if (base == 10) { + if ((nret = nget_slong(&lval, t, NULL, 10)) != NUM_OK) + goto err; + ltmp = vp->character == '-' ? -change : change; + if (lval > 0 && ltmp > 0 && !NPFITS(LONG_MAX, lval, ltmp)) { + nret = NUM_OVER; + goto err; + } + if (lval < 0 && ltmp < 0 && !NNFITS(LONG_MIN, lval, ltmp)) { + nret = NUM_UNDER; + goto err; + } + lval += ltmp; + /* If we cross 0, signed numbers lose their sign. */ + if (lval == 0 && ntype == fmt[SDEC]) + ntype = fmt[DEC]; + nlen = SPRINTF(nbuf, sizeof(nbuf), ntype, lval); + } else { + if ((nret = nget_uslong(&ulval, t, NULL, base)) != NUM_OK) + goto err; + if (vp->character == '+') { + if (!NPFITS(ULONG_MAX, ulval, change)) { + nret = NUM_OVER; + goto err; + } + ulval += change; + } else { + if (ulval < change) { + nret = NUM_UNDER; + goto err; + } + ulval -= change; + } + + /* Correct for literal "0[Xx]" in format. */ + if (base == 16) + wlen -= 2; + + nlen = SPRINTF(nbuf, sizeof(nbuf), ntype, wlen, ulval); + } + + /* Build the new line. */ + MEMMOVE(bp, p, beg); + MEMMOVE(bp + beg, nbuf, nlen); + MEMMOVE(bp + beg + nlen, p + end, len - beg - (end - beg)); + len = beg + nlen + (len - beg - (end - beg)); + + nret = NUM_OK; + rval = db_set(sp, vp->m_start.lno, bp, len); + + if (0) { +err: rval = 1; + inc_err(sp, nret); + } + if (bp != NULL) + FREE_SPACEW(sp, bp, blen); + return (rval); +} + +static void +inc_err(SCR *sp, enum nresult nret) +{ + switch (nret) { + case NUM_ERR: + break; + case NUM_OK: + abort(); + /* NOREACHED */ + case NUM_OVER: + msgq(sp, M_ERR, "182|Resulting number too large"); + break; + case NUM_UNDER: + msgq(sp, M_ERR, "183|Resulting number too small"); + break; + } +} Property changes on: vendor/nvi/2.2.0-05ed8b9/vi/v_increment.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/vi/v_init.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/vi/v_init.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/vi/v_init.c (revision 366308) @@ -0,0 +1,120 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "../common/common.h" +#include "vi.h" + +/* + * v_screen_copy -- + * Copy vi screen. + * + * PUBLIC: int v_screen_copy(SCR *, SCR *); + */ +int +v_screen_copy(SCR *orig, SCR *sp) +{ + VI_PRIVATE *ovip, *nvip; + + /* Create the private vi structure. */ + CALLOC_RET(orig, nvip, 1, sizeof(VI_PRIVATE)); + sp->vi_private = nvip; + + /* Invalidate the line size cache. */ + VI_SCR_CFLUSH(nvip); + + if (orig == NULL) { + nvip->csearchdir = CNOTSET; + } else { + ovip = VIP(orig); + + /* User can replay the last input, but nothing else. */ + if (ovip->rep_len != 0) { + MALLOC_RET(orig, nvip->rep, ovip->rep_len); + memmove(nvip->rep, ovip->rep, ovip->rep_len); + nvip->rep_len = ovip->rep_len; + } + + /* Copy the match characters information. */ + if (ovip->mcs != NULL && (nvip->mcs = + v_wstrdup(sp, ovip->mcs, STRLEN(ovip->mcs))) == NULL) + return (1); + + /* Copy the paragraph/section information. */ + if (ovip->ps != NULL && (nvip->ps = + v_strdup(sp, ovip->ps, strlen(ovip->ps))) == NULL) + return (1); + + nvip->lastckey = ovip->lastckey; + nvip->csearchdir = ovip->csearchdir; + + nvip->srows = ovip->srows; + } + return (0); +} + +/* + * v_screen_end -- + * End a vi screen. + * + * PUBLIC: int v_screen_end(SCR *); + */ +int +v_screen_end(SCR *sp) +{ + VI_PRIVATE *vip; + + if ((vip = VIP(sp)) == NULL) + return (0); + free(vip->keyw); + free(vip->rep); + free(vip->mcs); + free(vip->ps); + + free(HMAP); + + free(vip); + sp->vi_private = NULL; + + return (0); +} + +/* + * v_optchange -- + * Handle change of options for vi. + * + * PUBLIC: int v_optchange(SCR *, int, char *, u_long *); + */ +int +v_optchange(SCR *sp, int offset, char *str, u_long *valp) +{ + switch (offset) { + case O_MATCHCHARS: + return (v_buildmcs(sp, str)); + case O_PARAGRAPHS: + return (v_buildps(sp, str, O_STR(sp, O_SECTIONS))); + case O_SECTIONS: + return (v_buildps(sp, O_STR(sp, O_PARAGRAPHS), str)); + case O_WINDOW: + return (vs_crel(sp, *valp)); + } + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/vi/v_init.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/vi/v_left.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/vi/v_left.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/vi/v_left.c (revision 366308) @@ -0,0 +1,279 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include + +#include "../common/common.h" +#include "vi.h" + +/* + * v_left -- [count]^H, [count]h + * Move left by columns. + * + * PUBLIC: int v_left(SCR *, VICMD *); + */ +int +v_left(SCR *sp, VICMD *vp) +{ + recno_t cnt; + + /* + * !!! + * The ^H and h commands always failed in the first column. + */ + if (vp->m_start.cno == 0) { + v_sol(sp); + return (1); + } + + /* Find the end of the range. */ + cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; + if (vp->m_start.cno > cnt) + vp->m_stop.cno = vp->m_start.cno - cnt; + else + vp->m_stop.cno = 0; + + /* + * All commands move to the end of the range. Motion commands + * adjust the starting point to the character before the current + * one. + */ + if (ISMOTION(vp)) + --vp->m_start.cno; + vp->m_final = vp->m_stop; + return (0); +} + +/* + * v_cfirst -- [count]_ + * Move to the first non-blank character in a line. + * + * PUBLIC: int v_cfirst(SCR *, VICMD *); + */ +int +v_cfirst(SCR *sp, VICMD *vp) +{ + recno_t cnt, lno; + + /* + * !!! + * If the _ is a motion component, it makes the command a line motion + * e.g. "d_" deletes the line. It also means that the cursor doesn't + * move. + * + * The _ command never failed in the first column. + */ + if (ISMOTION(vp)) + F_SET(vp, VM_LMODE); + /* + * !!! + * Historically a specified count makes _ move down count - 1 + * rows, so, "3_" is the same as "2j_". + */ + cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; + if (cnt != 1) { + --vp->count; + return (v_down(sp, vp)); + } + + /* + * Move to the first non-blank. + * + * Can't just use RCM_SET_FNB, in case _ is used as the motion + * component of another command. + */ + vp->m_stop.cno = 0; + if (nonblank(sp, vp->m_stop.lno, &vp->m_stop.cno)) + return (1); + + /* + * !!! + * The _ command has to fail if the file is empty and we're doing + * a delete. If deleting line 1, and 0 is the first nonblank, + * make the check. + */ + if (vp->m_stop.lno == 1 && + vp->m_stop.cno == 0 && ISCMD(vp->rkp, 'd')) { + if (db_last(sp, &lno)) + return (1); + if (lno == 0) { + v_sol(sp); + return (1); + } + } + + /* + * Delete and non-motion commands move to the end of the range, + * yank stays at the start. Ignore others. + */ + vp->m_final = + ISMOTION(vp) && ISCMD(vp->rkp, 'y') ? vp->m_start : vp->m_stop; + return (0); +} + +/* + * v_first -- ^ + * Move to the first non-blank character in this line. + * + * PUBLIC: int v_first(SCR *, VICMD *); + */ +int +v_first(SCR *sp, VICMD *vp) +{ + /* + * !!! + * Yielding to none in our quest for compatibility with every + * historical blemish of vi, no matter how strange it might be, + * we permit the user to enter a count and then ignore it. + */ + + /* + * Move to the first non-blank. + * + * Can't just use RCM_SET_FNB, in case ^ is used as the motion + * component of another command. + */ + vp->m_stop.cno = 0; + if (nonblank(sp, vp->m_stop.lno, &vp->m_stop.cno)) + return (1); + + /* + * !!! + * The ^ command succeeded if used as a command when the cursor was + * on the first non-blank in the line, but failed if used as a motion + * component in the same situation. + */ + if (ISMOTION(vp) && vp->m_start.cno == vp->m_stop.cno) { + v_sol(sp); + return (1); + } + + /* + * If moving right, non-motion commands move to the end of the range. + * Delete and yank stay at the start. Motion commands adjust the + * ending point to the character before the current ending charcter. + * + * If moving left, all commands move to the end of the range. Motion + * commands adjust the starting point to the character before the + * current starting character. + */ + if (vp->m_start.cno < vp->m_stop.cno) + if (ISMOTION(vp)) { + --vp->m_stop.cno; + vp->m_final = vp->m_start; + } else + vp->m_final = vp->m_stop; + else { + if (ISMOTION(vp)) + --vp->m_start.cno; + vp->m_final = vp->m_stop; + } + return (0); +} + +/* + * v_ncol -- [count]| + * Move to column count or the first column on this line. If the + * requested column is past EOL, move to EOL. The nasty part is + * that we have to know character column widths to make this work. + * + * PUBLIC: int v_ncol(SCR *, VICMD *); + */ +int +v_ncol(SCR *sp, VICMD *vp) +{ + if (F_ISSET(vp, VC_C1SET) && vp->count > 1) { + --vp->count; + vp->m_stop.cno = + vs_colpos(sp, vp->m_start.lno, (size_t)vp->count); + /* + * !!! + * The | command succeeded if used as a command and the cursor + * didn't move, but failed if used as a motion component in the + * same situation. + */ + if (ISMOTION(vp) && vp->m_stop.cno == vp->m_start.cno) { + v_nomove(sp); + return (1); + } + } else { + /* + * !!! + * The | command succeeded if used as a command in column 0 + * without a count, but failed if used as a motion component + * in the same situation. + */ + if (ISMOTION(vp) && vp->m_start.cno == 0) { + v_sol(sp); + return (1); + } + vp->m_stop.cno = 0; + } + + /* + * If moving right, non-motion commands move to the end of the range. + * Delete and yank stay at the start. Motion commands adjust the + * ending point to the character before the current ending charcter. + * + * If moving left, all commands move to the end of the range. Motion + * commands adjust the starting point to the character before the + * current starting character. + */ + if (vp->m_start.cno < vp->m_stop.cno) + if (ISMOTION(vp)) { + --vp->m_stop.cno; + vp->m_final = vp->m_start; + } else + vp->m_final = vp->m_stop; + else { + if (ISMOTION(vp)) + --vp->m_start.cno; + vp->m_final = vp->m_stop; + } + return (0); +} + +/* + * v_zero -- 0 + * Move to the first column on this line. + * + * PUBLIC: int v_zero(SCR *, VICMD *); + */ +int +v_zero(SCR *sp, VICMD *vp) +{ + /* + * !!! + * The 0 command succeeded if used as a command in the first column + * but failed if used as a motion component in the same situation. + */ + if (ISMOTION(vp) && vp->m_start.cno == 0) { + v_sol(sp); + return (1); + } + + /* + * All commands move to the end of the range. Motion commands + * adjust the starting point to the character before the current + * one. + */ + vp->m_stop.cno = 0; + if (ISMOTION(vp)) + --vp->m_start.cno; + vp->m_final = vp->m_stop; + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/vi/v_left.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/vi/v_mark.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/vi/v_mark.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/vi/v_mark.c (revision 366308) @@ -0,0 +1,227 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include + +#include "../common/common.h" +#include "vi.h" + +enum which {BQMARK, FQMARK}; +static int mark(SCR *, VICMD *, int, enum which); + +/* + * v_mark -- m[a-z] + * Set a mark. + * + * PUBLIC: int v_mark(SCR *, VICMD *); + */ +int +v_mark(SCR *sp, VICMD *vp) +{ + return (mark_set(sp, vp->character, &vp->m_start, 1)); +} + +/* + * v_bmark -- `['`a-z] + * Move to a mark. + * + * Moves to a mark, setting both row and column. + * + * !!! + * Although not commonly known, the "'`" and "'`" forms are historically + * valid. The behavior is determined by the first character, so "`'" is + * the same as "``". Remember this fact -- you'll be amazed at how many + * people don't know it and will be delighted that you are able to tell + * them. + * + * PUBLIC: int v_bmark(SCR *, VICMD *); + */ +int +v_bmark(SCR *sp, VICMD *vp) +{ + return (mark(sp, vp, 1, BQMARK)); +} + +/* + * v_fmark -- '['`a-z] + * Move to a mark. + * + * Move to the first nonblank character of the line containing the mark. + * + * PUBLIC: int v_fmark(SCR *, VICMD *); + */ +int +v_fmark(SCR *sp, VICMD *vp) +{ + return (mark(sp, vp, 1, FQMARK)); +} + +/* + * v_emark -- + * Mouse mark. + * + * PUBLIC: int v_emark(SCR *, VICMD *); + */ +int +v_emark(SCR *sp, VICMD *vp) +{ + SMAP *smp; + + smp = HMAP + vp->ev.e_lno; + if (smp > TMAP) { + msgq(sp, M_BERR, "320|Unknown cursor position."); + return (1); + } + vp->m_stop.lno = smp->lno; + vp->m_stop.cno = + vs_colpos(sp, smp->lno, vp->ev.e_cno + (smp->soff - 1) * sp->cols); + return (mark(sp, vp, 0, BQMARK)); +} + +/* + * mark -- + * Mark commands. + */ +static int +mark(SCR *sp, VICMD *vp, int getmark, enum which cmd) +{ + dir_t dir; + MARK m; + size_t len; + + if (getmark && mark_get(sp, vp->character, &vp->m_stop, M_BERR)) + return (1); + + /* + * !!! + * Historically, BQMARKS for character positions that no longer + * existed acted as FQMARKS. + * + * FQMARKS move to the first non-blank. + */ + switch (cmd) { + case BQMARK: + if (db_get(sp, vp->m_stop.lno, DBG_FATAL, NULL, &len)) + return (1); + if (vp->m_stop.cno < len || + (vp->m_stop.cno == len && len == 0)) + break; + + if (ISMOTION(vp)) + F_SET(vp, VM_LMODE); + cmd = FQMARK; + /* FALLTHROUGH */ + case FQMARK: + vp->m_stop.cno = 0; + if (nonblank(sp, vp->m_stop.lno, &vp->m_stop.cno)) + return (1); + break; + default: + abort(); + } + + /* Non-motion commands move to the end of the range. */ + if (!ISMOTION(vp)) { + vp->m_final = vp->m_stop; + return (0); + } + + /* + * !!! + * If a motion component to a BQMARK, the cursor has to move. + */ + if (cmd == BQMARK && + vp->m_stop.lno == vp->m_start.lno && + vp->m_stop.cno == vp->m_start.cno) { + v_nomove(sp); + return (1); + } + + /* + * If the motion is in the reverse direction, switch the start and + * stop MARK's so that it's in a forward direction. (There's no + * reason for this other than to make the tests below easier. The + * code in vi.c:vi() would have done the switch.) Both forward + * and backward motions can happen for any kind of search command. + */ + if (vp->m_start.lno > vp->m_stop.lno || + (vp->m_start.lno == vp->m_stop.lno && + vp->m_start.cno > vp->m_stop.cno)) { + m = vp->m_start; + vp->m_start = vp->m_stop; + vp->m_stop = m; + dir = BACKWARD; + } else + dir = FORWARD; + + /* + * Yank cursor motion, when associated with marks as motion commands, + * historically behaved as follows: + * + * ` motion ' motion + * Line change? Line change? + * Y N Y N + * -------------- --------------- + * FORWARD: | NM NM | NM NM + * | | + * BACKWARD: | M M | M NM(1) + * + * where NM means the cursor didn't move, and M means the cursor + * moved to the mark. + * + * As the cursor was usually moved for yank commands associated + * with backward motions, this implementation regularizes it by + * changing the NM at position (1) to be an M. This makes mark + * motions match search motions, which is probably A Good Thing. + * + * Delete cursor motion was always to the start of the text region, + * regardless. Ignore other motion commands. + */ + vp->m_final = vp->m_start; + + /* + * Forward marks are always line oriented, and it's set in the + * vcmd.c table. + */ + if (cmd == FQMARK) + return (0); + + /* + * BQMARK'S moving backward and starting at column 0, and ones moving + * forward and ending at column 0 are corrected to the last column of + * the previous line. Otherwise, adjust the starting/ending point to + * the character before the current one (this is safe because we know + * the search had to move to succeed). + * + * Mark motions become line mode opertions if they start at the first + * nonblank and end at column 0 of another line. + */ + if (vp->m_start.lno < vp->m_stop.lno && vp->m_stop.cno == 0) { + if (db_get(sp, --vp->m_stop.lno, DBG_FATAL, NULL, &len)) + return (1); + vp->m_stop.cno = len ? len - 1 : 0; + len = 0; + if (nonblank(sp, vp->m_start.lno, &len)) + return (1); + if (vp->m_start.cno <= len) + F_SET(vp, VM_LMODE); + } else + --vp->m_stop.cno; + + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/vi/v_mark.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/vi/v_match.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/vi/v_match.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/vi/v_match.c (revision 366308) @@ -0,0 +1,172 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "../common/common.h" +#include "vi.h" + +/* + * v_match -- % + * Search to matching character. + * + * PUBLIC: int v_match(SCR *, VICMD *); + */ +int +v_match(SCR *sp, VICMD *vp) +{ + VCS cs; + MARK *mp; + size_t cno, len, off; + int cnt, isempty, matchc, startc, (*gc)(SCR *, VCS *); + CHAR_T *p; + CHAR_T *cp; + const CHAR_T *match_chars; + + /* + * Historically vi would match (), {} and [] however + * an update included <>. This is ok for editing HTML + * but a pain in the butt for C source. + * Making it an option lets the user decide what is 'right'. + */ + match_chars = VIP(sp)->mcs; + + /* + * !!! + * Historic practice; ignore the count. + * + * !!! + * Historical practice was to search for the initial character in the + * forward direction only. + */ + if (db_eget(sp, vp->m_start.lno, &p, &len, &isempty)) { + if (isempty) + goto nomatch; + return (1); + } + for (off = vp->m_start.cno;; ++off) { + if (off >= len) { +nomatch: msgq(sp, M_BERR, "184|No match character on this line"); + return (1); + } + startc = p[off]; + cp = STRCHR(match_chars, startc); + if (cp != NULL) { + cnt = cp - match_chars; + matchc = match_chars[cnt ^ 1]; + gc = cnt & 1 ? cs_prev : cs_next; + break; + } + } + + cs.cs_lno = vp->m_start.lno; + cs.cs_cno = off; + if (cs_init(sp, &cs)) + return (1); + for (cnt = 1;;) { + if (gc(sp, &cs)) + return (1); + if (cs.cs_flags != 0) { + if (cs.cs_flags == CS_EOF || cs.cs_flags == CS_SOF) + break; + continue; + } + if (cs.cs_ch == startc) + ++cnt; + else if (cs.cs_ch == matchc && --cnt == 0) + break; + } + if (cnt) { + msgq(sp, M_BERR, "185|Matching character not found"); + return (1); + } + + vp->m_stop.lno = cs.cs_lno; + vp->m_stop.cno = cs.cs_cno; + + /* + * If moving right, non-motion commands move to the end of the range. + * Delete and yank stay at the start. + * + * If moving left, all commands move to the end of the range. + * + * !!! + * Don't correct for leftward movement -- historic vi deleted the + * starting cursor position when deleting to a match. + */ + if (vp->m_start.lno < vp->m_stop.lno || + (vp->m_start.lno == vp->m_stop.lno && + vp->m_start.cno < vp->m_stop.cno)) + vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop; + else + vp->m_final = vp->m_stop; + + /* + * !!! + * If the motion is across lines, and the earliest cursor position + * is at or before any non-blank characters in the line, i.e. the + * movement is cutting all of the line's text, and the later cursor + * position has nothing other than whitespace characters between it + * and the end of its line, the buffer is in line mode. + */ + if (!ISMOTION(vp) || vp->m_start.lno == vp->m_stop.lno) + return (0); + mp = vp->m_start.lno < vp->m_stop.lno ? &vp->m_start : &vp->m_stop; + if (mp->cno != 0) { + cno = 0; + if (nonblank(sp, mp->lno, &cno)) + return (1); + if (cno < mp->cno) + return (0); + } + mp = vp->m_start.lno < vp->m_stop.lno ? &vp->m_stop : &vp->m_start; + if (db_get(sp, mp->lno, DBG_FATAL, &p, &len)) + return (1); + for (p += mp->cno + 1, len -= mp->cno; --len; ++p) + if (!isblank(*p)) + return (0); + F_SET(vp, VM_LMODE); + return (0); +} + +/* + * v_buildmcs -- + * Build the match character list. + * + * PUBLIC: int v_buildmcs(SCR *, char *); + */ +int +v_buildmcs(SCR *sp, char *str) +{ + CHAR_T **mp = &VIP(sp)->mcs; + size_t len = strlen(str) + 1; + + free(*mp); + MALLOC(sp, *mp, len * sizeof(CHAR_T)); + if (*mp == NULL) + return (1); +#ifdef USE_WIDECHAR + if (mbstowcs(*mp, str, len) == (size_t)-1) + return (1); +#else + memcpy(*mp, str, len); +#endif + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/vi/v_match.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/vi/v_put.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/vi/v_put.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/vi/v_put.c (revision 366308) @@ -0,0 +1,136 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include + +#include "../common/common.h" +#include "vi.h" + +static void inc_buf(SCR *, VICMD *); + +/* + * v_Put -- [buffer]P + * Insert the contents of the buffer before the cursor. + * + * PUBLIC: int v_Put(SCR *, VICMD *); + */ +int +v_Put(SCR *sp, VICMD *vp) +{ + u_long cnt; + + if (F_ISSET(vp, VC_ISDOT)) + inc_buf(sp, vp); + + /* + * !!! + * Historic vi did not support a count with the 'p' and 'P' + * commands. It's useful, so we do. + */ + for (cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) { + if (put(sp, NULL, + F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL, + &vp->m_start, &vp->m_final, 0)) + return (1); + vp->m_start = vp->m_final; + if (INTERRUPTED(sp)) + return (1); + } + return (0); +} + +/* + * v_put -- [buffer]p + * Insert the contents of the buffer after the cursor. + * + * PUBLIC: int v_put(SCR *, VICMD *); + */ +int +v_put(SCR *sp, VICMD *vp) +{ + u_long cnt; + + if (F_ISSET(vp, VC_ISDOT)) + inc_buf(sp, vp); + + /* + * !!! + * Historic vi did not support a count with the 'p' and 'P' + * commands. It's useful, so we do. + */ + for (cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) { + if (put(sp, NULL, + F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL, + &vp->m_start, &vp->m_final, 1)) + return (1); + vp->m_start = vp->m_final; + if (INTERRUPTED(sp)) + return (1); + } + return (0); +} + +/* + * !!! + * Historical whackadoo. The dot command `puts' the numbered buffer + * after the last one put. For example, `"4p.' would put buffer #4 + * and buffer #5. If the user continued to enter '.', the #9 buffer + * would be repeatedly output. This was not documented, and is a bit + * tricky to reconstruct. Historical versions of vi also dropped the + * contents of the default buffer after each put, so after `"4p' the + * default buffer would be empty. This makes no sense to me, so we + * don't bother. Don't assume sequential order of numeric characters. + * + * And, if that weren't exciting enough, failed commands don't normally + * set the dot command. Well, boys and girls, an exception is that + * the buffer increment gets done regardless of the success of the put. + */ +static void +inc_buf(SCR *sp, VICMD *vp) +{ + CHAR_T v; + + switch (vp->buffer) { + case '1': + v = '2'; + break; + case '2': + v = '3'; + break; + case '3': + v = '4'; + break; + case '4': + v = '5'; + break; + case '5': + v = '6'; + break; + case '6': + v = '7'; + break; + case '7': + v = '8'; + break; + case '8': + v = '9'; + break; + default: + return; + } + VIP(sp)->sdot.buffer = vp->buffer = v; +} Property changes on: vendor/nvi/2.2.0-05ed8b9/vi/v_put.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/vi/v_redraw.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/vi/v_redraw.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/vi/v_redraw.c (revision 366308) @@ -0,0 +1,33 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include + +#include "../common/common.h" +#include "vi.h" + +/* + * v_redraw -- ^L, ^R + * Redraw the screen. + * + * PUBLIC: int v_redraw(SCR *, VICMD *); + */ +int +v_redraw(SCR *sp, VICMD *vp) +{ + return (sp->gp->scr_refresh(sp, 1)); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/vi/v_redraw.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/vi/v_replace.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/vi/v_replace.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/vi/v_replace.c (revision 366308) @@ -0,0 +1,198 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "../common/common.h" +#include "vi.h" + +/* + * v_replace -- [count]r + * + * !!! + * The r command in historic vi was almost beautiful in its badness. For + * example, "r" and "r" beeped the terminal and deleted + * a single character. "Nr", where N was greater than 1, + * inserted a single carriage return. "r" did cancel the command, + * but "r" erased a single character. To enter a literal + * character, it required three characters after the + * command. This may not be right, but at least it's not insane. + * + * PUBLIC: int v_replace(SCR *, VICMD *); + */ +int +v_replace(SCR *sp, VICMD *vp) +{ + EVENT ev; + VI_PRIVATE *vip; + TEXT *tp; + size_t blen, len; + u_long cnt; + int quote, rval; + CHAR_T *bp; + CHAR_T *p; + + vip = VIP(sp); + + /* + * If the line doesn't exist, or it's empty, replacement isn't + * allowed. It's not hard to implement, but: + * + * 1: It's historic practice (vi beeped before the replacement + * character was even entered). + * 2: For consistency, this change would require that the more + * general case, "Nr", when the user is < N characters from + * the end of the line, also work, which would be a bit odd. + * 3: Replacing with a has somewhat odd semantics. + */ + if (db_get(sp, vp->m_start.lno, DBG_FATAL, &p, &len)) + return (1); + if (len == 0) { + msgq(sp, M_BERR, "186|No characters to replace"); + return (1); + } + + /* + * Figure out how many characters to be replace. For no particular + * reason (other than that the semantics of replacing the newline + * are confusing) only permit the replacement of the characters in + * the current line. I suppose we could append replacement characters + * to the line, but I see no compelling reason to do so. Check this + * before we get the character to match historic practice, where Nr + * failed immediately if there were less than N characters from the + * cursor to the end of the line. + */ + cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; + vp->m_stop.lno = vp->m_start.lno; + vp->m_stop.cno = vp->m_start.cno + cnt - 1; + if (vp->m_stop.cno > len - 1) { + v_eol(sp, &vp->m_start); + return (1); + } + + /* + * If it's not a repeat, reset the current mode and get a replacement + * character. + */ + quote = 0; + if (!F_ISSET(vp, VC_ISDOT)) { + sp->showmode = SM_REPLACE; + if (vs_refresh(sp, 0)) + return (1); +next: if (v_event_get(sp, &ev, 0, 0)) + return (1); + + switch (ev.e_event) { + case E_CHARACTER: + /* + * means escape the next character. + * means they changed their minds. + */ + if (!quote) { + if (ev.e_value == K_VLNEXT) { + quote = 1; + goto next; + } + if (ev.e_value == K_ESCAPE) + return (0); + } + vip->rlast = ev.e_c; + vip->rvalue = ev.e_value; + break; + case E_ERR: + case E_EOF: + F_SET(sp, SC_EXIT_FORCE); + return (1); + case E_INTERRUPT: + /* means they changed their minds. */ + return (0); + case E_WRESIZE: + /* interrupts the input mode. */ + v_emsg(sp, NULL, VIM_WRESIZE); + return (0); + case E_REPAINT: + if (vs_repaint(sp, &ev)) + return (1); + goto next; + default: + v_event_err(sp, &ev); + return (0); + } + } + + /* Copy the line. */ + GET_SPACE_RETW(sp, bp, blen, len); + MEMMOVE(bp, p, len); + p = bp; + + /* + * Versions of nvi before 1.57 created N new lines when they replaced + * N characters with or characters. This + * is different from the historic vi, which replaced N characters with + * a single new line. Users complained, so we match historic practice. + */ + if ((!quote && vip->rvalue == K_CR) || vip->rvalue == K_NL) { + /* Set return line. */ + vp->m_stop.lno = vp->m_start.lno + 1; + vp->m_stop.cno = 0; + + /* The first part of the current line. */ + if (db_set(sp, vp->m_start.lno, p, vp->m_start.cno)) + goto err_ret; + + /* + * The rest of the current line. And, of course, now it gets + * tricky. If there are characters left in the line and if + * the autoindent edit option is set, white space after the + * replaced character is discarded, autoindent is applied, and + * the cursor moves to the last indent character. + */ + p += vp->m_start.cno + cnt; + len -= vp->m_start.cno + cnt; + if (len != 0 && O_ISSET(sp, O_AUTOINDENT)) + for (; len && isblank(*p); --len, ++p); + + if ((tp = text_init(sp, p, len, len)) == NULL) + goto err_ret; + + if (len != 0 && O_ISSET(sp, O_AUTOINDENT)) { + if (v_txt_auto(sp, vp->m_start.lno, NULL, 0, tp)) + goto err_ret; + vp->m_stop.cno = tp->ai ? tp->ai - 1 : 0; + } else + vp->m_stop.cno = 0; + + vp->m_stop.cno = tp->ai ? tp->ai - 1 : 0; + if (db_append(sp, 1, vp->m_start.lno, tp->lb, tp->len)) +err_ret: rval = 1; + else { + text_free(tp); + rval = 0; + } + } else { + STRSET(bp + vp->m_start.cno, vip->rlast, cnt); + rval = db_set(sp, vp->m_start.lno, bp, len); + } + FREE_SPACEW(sp, bp, blen); + + vp->m_final = vp->m_stop; + return (rval); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/vi/v_replace.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/vi/v_right.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/vi/v_right.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/vi/v_right.c (revision 366308) @@ -0,0 +1,137 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include + +#include "../common/common.h" +#include "vi.h" + +/* + * v_right -- [count]' ', [count]l + * Move right by columns. + * + * PUBLIC: int v_right(SCR *, VICMD *); + */ +int +v_right(SCR *sp, VICMD *vp) +{ + size_t len; + int isempty; + + if (db_eget(sp, vp->m_start.lno, NULL, &len, &isempty)) { + if (isempty) + goto eol; + return (1); + } + + /* It's always illegal to move right on empty lines. */ + if (len == 0) { +eol: v_eol(sp, NULL); + return (1); + } + + /* + * Non-motion commands move to the end of the range. Delete and + * yank stay at the start. Ignore others. Adjust the end of the + * range for motion commands. + * + * !!! + * Historically, "[cdsy]l" worked at the end of a line. Also, + * EOL is a count sink. + */ + vp->m_stop.cno = vp->m_start.cno + + (F_ISSET(vp, VC_C1SET) ? vp->count : 1); + if (vp->m_start.cno == len - 1 && !ISMOTION(vp)) { + v_eol(sp, NULL); + return (1); + } + if (vp->m_stop.cno >= len) { + vp->m_stop.cno = len - 1; + vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop; + } else if (ISMOTION(vp)) { + --vp->m_stop.cno; + vp->m_final = vp->m_start; + } else + vp->m_final = vp->m_stop; + return (0); +} + +/* + * v_dollar -- [count]$ + * Move to the last column. + * + * PUBLIC: int v_dollar(SCR *, VICMD *); + */ +int +v_dollar(SCR *sp, VICMD *vp) +{ + size_t len; + int isempty; + + /* + * !!! + * A count moves down count - 1 rows, so, "3$" is the same as "2j$". + */ + if ((F_ISSET(vp, VC_C1SET) ? vp->count : 1) != 1) { + /* + * !!! + * Historically, if the $ is a motion, and deleting from + * at or before the first non-blank of the line, it's a + * line motion, and the line motion flag is set. + */ + vp->m_stop.cno = 0; + if (nonblank(sp, vp->m_start.lno, &vp->m_stop.cno)) + return (1); + if (ISMOTION(vp) && vp->m_start.cno <= vp->m_stop.cno) + F_SET(vp, VM_LMODE); + + --vp->count; + if (v_down(sp, vp)) + return (1); + } + + /* + * !!! + * Historically, it was illegal to use $ as a motion command on + * an empty line. Unfortunately, even though C was historically + * aliased to c$, it (and not c$) was special cased to work on + * empty lines. Since we alias C to c$ too, we have a problem. + * To fix it, we let c$ go through, on the assumption that it's + * not a problem for it to work. + */ + if (db_eget(sp, vp->m_stop.lno, NULL, &len, &isempty)) { + if (!isempty) + return (1); + len = 0; + } + + if (len == 0) { + if (ISMOTION(vp) && !ISCMD(vp->rkp, 'c')) { + v_eol(sp, NULL); + return (1); + } + return (0); + } + + /* + * Non-motion commands move to the end of the range. Delete + * and yank stay at the start. Ignore others. + */ + vp->m_stop.cno = len ? len - 1 : 0; + vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop; + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/vi/v_right.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/vi/v_screen.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/vi/v_screen.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/vi/v_screen.c (revision 366308) @@ -0,0 +1,59 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include + +#include "../common/common.h" +#include "vi.h" + +/* + * v_screen -- ^W + * Switch screens. + * + * PUBLIC: int v_screen(SCR *, VICMD *); + */ +int +v_screen(SCR *sp, VICMD *vp) +{ + /* + * You can't leave a colon command-line edit window -- it's not that + * it won't work, but it gets real weird, real fast when you execute + * a colon command out of a window that was forked from a window that's + * now backgrounded... You get the idea. + */ + if (F_ISSET(sp, SC_COMEDIT)) { + msgq(sp, M_ERR, + "308|Enter to execute a command, :q to exit"); + return (1); + } + + /* + * Try for the next lower screen, or, go back to the first + * screen on the stack. + */ + if (TAILQ_NEXT(sp, q) != NULL) + sp->nextdisp = TAILQ_NEXT(sp, q); + else if (TAILQ_FIRST(sp->gp->dq) == sp) { + msgq(sp, M_ERR, "187|No other screen to switch to"); + return (1); + } else + sp->nextdisp = TAILQ_FIRST(sp->gp->dq); + + F_SET(sp->nextdisp, SC_STATUS); + F_SET(sp, SC_SSWITCH | SC_STATUS); + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/vi/v_screen.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/vi/v_scroll.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/vi/v_scroll.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/vi/v_scroll.c (revision 366308) @@ -0,0 +1,443 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include + +#include "../common/common.h" +#include "vi.h" + +static void goto_adjust(VICMD *); + +/* + * The historic vi had a problem in that all movements were by physical + * lines, not by logical, or screen lines. Arguments can be made that this + * is the right thing to do. For example, single line movements, such as + * 'j' or 'k', should probably work on physical lines. Commands like "dj", + * or "j.", where '.' is a change command, make more sense for physical lines + * than they do for logical lines. + * + * These arguments, however, don't apply to scrolling commands like ^D and + * ^F -- if the window is fairly small, using physical lines can result in + * a half-page scroll repainting the entire screen, which is not what the + * user wanted. Second, if the line is larger than the screen, using physical + * lines can make it impossible to display parts of the line -- there aren't + * any commands that don't display the beginning of the line in historic vi, + * and if both the beginning and end of the line can't be on the screen at + * the same time, you lose. This is even worse in the case of the H, L, and + * M commands -- for large lines, they may all refer to the same line and + * will result in no movement at all. + * + * Another issue is that page and half-page scrolling commands historically + * moved to the first non-blank character in the new line. If the line is + * approximately the same size as the screen, this loses because the cursor + * before and after a ^D, may refer to the same location on the screen. In + * this implementation, scrolling commands set the cursor to the first non- + * blank character if the line changes because of the scroll. Otherwise, + * the cursor is left alone. + * + * This implementation does the scrolling (^B, ^D, ^F, ^U, ^Y, ^E), and the + * cursor positioning commands (H, L, M) commands using logical lines, not + * physical. + */ + +/* + * v_lgoto -- [count]G + * Go to first non-blank character of the line count, the last line + * of the file by default. + * + * PUBLIC: int v_lgoto(SCR *, VICMD *); + */ +int +v_lgoto(SCR *sp, VICMD *vp) +{ + recno_t nlines; + + if (F_ISSET(vp, VC_C1SET)) { + if (!db_exist(sp, vp->count)) { + /* + * !!! + * Historically, 1G was legal in an empty file. + */ + if (vp->count == 1) { + if (db_last(sp, &nlines)) + return (1); + if (nlines == 0) + return (0); + } + v_eof(sp, &vp->m_start); + return (1); + } + vp->m_stop.lno = vp->count; + } else { + if (db_last(sp, &nlines)) + return (1); + vp->m_stop.lno = nlines ? nlines : 1; + } + goto_adjust(vp); + return (0); +} + +/* + * v_home -- [count]H + * Move to the first non-blank character of the logical line + * count - 1 from the top of the screen, 0 by default. + * + * PUBLIC: int v_home(SCR *, VICMD *); + */ +int +v_home(SCR *sp, VICMD *vp) +{ + if (vs_sm_position(sp, &vp->m_stop, + F_ISSET(vp, VC_C1SET) ? vp->count - 1 : 0, P_TOP)) + return (1); + goto_adjust(vp); + return (0); +} + +/* + * v_middle -- M + * Move to the first non-blank character of the logical line + * in the middle of the screen. + * + * PUBLIC: int v_middle(SCR *, VICMD *); + */ +int +v_middle(SCR *sp, VICMD *vp) +{ + /* + * Yielding to none in our quest for compatibility with every + * historical blemish of vi, no matter how strange it might be, + * we permit the user to enter a count and then ignore it. + */ + if (vs_sm_position(sp, &vp->m_stop, 0, P_MIDDLE)) + return (1); + goto_adjust(vp); + return (0); +} + +/* + * v_bottom -- [count]L + * Move to the first non-blank character of the logical line + * count - 1 from the bottom of the screen, 0 by default. + * + * PUBLIC: int v_bottom(SCR *, VICMD *); + */ +int +v_bottom(SCR *sp, VICMD *vp) +{ + if (vs_sm_position(sp, &vp->m_stop, + F_ISSET(vp, VC_C1SET) ? vp->count - 1 : 0, P_BOTTOM)) + return (1); + goto_adjust(vp); + return (0); +} + +static void +goto_adjust(VICMD *vp) +{ + /* Guess that it's the end of the range. */ + vp->m_final = vp->m_stop; + + /* + * Non-motion commands move the cursor to the end of the range, and + * then to the NEXT nonblank of the line. Historic vi always moved + * to the first nonblank in the line; since the H, M, and L commands + * are logical motions in this implementation, we do the next nonblank + * so that it looks approximately the same to the user. To make this + * happen, the VM_RCM_SETNNB flag is set in the vcmd.c command table. + * + * If it's a motion, it's more complicated. The best possible solution + * is probably to display the first nonblank of the line the cursor + * will eventually rest on. This is tricky, particularly given that if + * the associated command is a delete, we don't yet know what line that + * will be. So, we clear the VM_RCM_SETNNB flag, and set the first + * nonblank flag (VM_RCM_SETFNB). Note, if the lines are sufficiently + * long, this can cause the cursor to warp out of the screen. It's too + * hard to fix. + * + * XXX + * The G command is always first nonblank, so it's okay to reset it. + */ + if (ISMOTION(vp)) { + F_CLR(vp, VM_RCM_MASK); + F_SET(vp, VM_RCM_SETFNB); + } else + return; + + /* + * If moving backward in the file, delete and yank move to the end + * of the range, unless the line didn't change, in which case yank + * doesn't move. If moving forward in the file, delete and yank + * stay at the start of the range. Ignore others. + */ + if (vp->m_stop.lno < vp->m_start.lno || + (vp->m_stop.lno == vp->m_start.lno && + vp->m_stop.cno < vp->m_start.cno)) { + if (ISCMD(vp->rkp, 'y') && vp->m_stop.lno == vp->m_start.lno) + vp->m_final = vp->m_start; + } else + vp->m_final = vp->m_start; +} + +/* + * v_up -- [count]^P, [count]k, [count]- + * Move up by lines. + * + * PUBLIC: int v_up(SCR *, VICMD *); + */ +int +v_up(SCR *sp, VICMD *vp) +{ + recno_t lno; + + lno = F_ISSET(vp, VC_C1SET) ? vp->count : 1; + if (vp->m_start.lno <= lno) { + v_sof(sp, &vp->m_start); + return (1); + } + vp->m_stop.lno = vp->m_start.lno - lno; + vp->m_final = vp->m_stop; + return (0); +} + +/* + * v_cr -- [count]^M + * In a script window, send the line to the shell. + * In a regular window, move down by lines. + * + * PUBLIC: int v_cr(SCR *, VICMD *); + */ +int +v_cr(SCR *sp, VICMD *vp) +{ + /* If it's a colon command-line edit window, it's an ex command. */ + if (F_ISSET(sp, SC_COMEDIT)) + return (v_ecl_exec(sp)); + + /* If it's a script window, exec the line. */ + if (F_ISSET(sp, SC_SCRIPT)) + return (sscr_exec(sp, vp->m_start.lno)); + + /* Otherwise, it's the same as v_down(). */ + return (v_down(sp, vp)); +} + +/* + * v_down -- [count]^J, [count]^N, [count]j, [count]^M, [count]+ + * Move down by lines. + * + * PUBLIC: int v_down(SCR *, VICMD *); + */ +int +v_down(SCR *sp, VICMD *vp) +{ + recno_t lno; + + lno = vp->m_start.lno + (F_ISSET(vp, VC_C1SET) ? vp->count : 1); + if (!db_exist(sp, lno)) { + v_eof(sp, &vp->m_start); + return (1); + } + vp->m_stop.lno = lno; + vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop; + return (0); +} + +/* + * v_hpageup -- [count]^U + * Page up half screens. + * + * PUBLIC: int v_hpageup(SCR *, VICMD *); + */ +int +v_hpageup(SCR *sp, VICMD *vp) +{ + /* + * Half screens always succeed unless already at SOF. + * + * !!! + * Half screens set the scroll value, even if the command + * ultimately failed, in historic vi. Probably a don't care. + */ + if (F_ISSET(vp, VC_C1SET)) + sp->defscroll = vp->count; + if (vs_sm_scroll(sp, &vp->m_stop, sp->defscroll, CNTRL_U)) + return (1); + vp->m_final = vp->m_stop; + return (0); +} + +/* + * v_hpagedown -- [count]^D + * Page down half screens. + * + * PUBLIC: int v_hpagedown(SCR *, VICMD *); + */ +int +v_hpagedown(SCR *sp, VICMD *vp) +{ + /* + * Half screens always succeed unless already at EOF. + * + * !!! + * Half screens set the scroll value, even if the command + * ultimately failed, in historic vi. Probably a don't care. + */ + if (F_ISSET(vp, VC_C1SET)) + sp->defscroll = vp->count; + if (vs_sm_scroll(sp, &vp->m_stop, sp->defscroll, CNTRL_D)) + return (1); + vp->m_final = vp->m_stop; + return (0); +} + +/* + * v_pagedown -- [count]^F + * Page down full screens. + * !!! + * Historic vi did not move to the EOF if the screen couldn't move, i.e. + * if EOF was already displayed on the screen. This implementation does + * move to EOF in that case, making ^F more like the historic ^D. + * + * PUBLIC: int v_pagedown(SCR *, VICMD *); + */ +int +v_pagedown(SCR *sp, VICMD *vp) +{ + recno_t offset; + + /* + * !!! + * The calculation in IEEE Std 1003.2-1992 (POSIX) is: + * + * top_line = top_line + count * (window - 2); + * + * which was historically wrong. The correct one is: + * + * top_line = top_line + count * window - 2; + * + * i.e. the two line "overlap" was only subtracted once. Which + * makes no sense, but then again, an overlap makes no sense for + * any screen but the "next" one anyway. We do it the historical + * way as there's no good reason to change it. + * + * If the screen has been split horizontally, use the smaller of + * the current window size and the window option value. + * + * It possible for this calculation to be less than 1; move at + * least one line. + */ + offset = (F_ISSET(vp, VC_C1SET) ? vp->count : 1) * (IS_SPLIT(sp) ? + MIN(sp->t_maxrows, O_VAL(sp, O_WINDOW)) : O_VAL(sp, O_WINDOW)); + offset = offset <= 2 ? 1 : offset - 2; + if (vs_sm_scroll(sp, &vp->m_stop, offset, CNTRL_F)) + return (1); + vp->m_final = vp->m_stop; + return (0); +} + +/* + * v_pageup -- [count]^B + * Page up full screens. + * + * !!! + * Historic vi did not move to the SOF if the screen couldn't move, i.e. + * if SOF was already displayed on the screen. This implementation does + * move to SOF in that case, making ^B more like the historic ^U. + * + * PUBLIC: int v_pageup(SCR *, VICMD *); + */ +int +v_pageup(SCR *sp, VICMD *vp) +{ + recno_t offset; + + /* + * !!! + * The calculation in IEEE Std 1003.2-1992 (POSIX) is: + * + * top_line = top_line - count * (window - 2); + * + * which was historically wrong. The correct one is: + * + * top_line = (top_line - count * window) + 2; + * + * A simpler expression is that, as with ^F, we scroll exactly: + * + * count * window - 2 + * + * lines. + * + * Bizarre. As with ^F, an overlap makes no sense for anything + * but the first screen. We do it the historical way as there's + * no good reason to change it. + * + * If the screen has been split horizontally, use the smaller of + * the current window size and the window option value. + * + * It possible for this calculation to be less than 1; move at + * least one line. + */ + offset = (F_ISSET(vp, VC_C1SET) ? vp->count : 1) * (IS_SPLIT(sp) ? + MIN(sp->t_maxrows, O_VAL(sp, O_WINDOW)) : O_VAL(sp, O_WINDOW)); + offset = offset <= 2 ? 1 : offset - 2; + if (vs_sm_scroll(sp, &vp->m_stop, offset, CNTRL_B)) + return (1); + vp->m_final = vp->m_stop; + return (0); +} + +/* + * v_lineup -- [count]^Y + * Page up by lines. + * + * PUBLIC: int v_lineup(SCR *, VICMD *); + */ +int +v_lineup(SCR *sp, VICMD *vp) +{ + /* + * The cursor moves down, staying with its original line, unless it + * reaches the bottom of the screen. + */ + if (vs_sm_scroll(sp, + &vp->m_stop, F_ISSET(vp, VC_C1SET) ? vp->count : 1, CNTRL_Y)) + return (1); + vp->m_final = vp->m_stop; + return (0); +} + +/* + * v_linedown -- [count]^E + * Page down by lines. + * + * PUBLIC: int v_linedown(SCR *, VICMD *); + */ +int +v_linedown(SCR *sp, VICMD *vp) +{ + /* + * The cursor moves up, staying with its original line, unless it + * reaches the top of the screen. + */ + if (vs_sm_scroll(sp, + &vp->m_stop, F_ISSET(vp, VC_C1SET) ? vp->count : 1, CNTRL_E)) + return (1); + vp->m_final = vp->m_stop; + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/vi/v_scroll.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/vi/v_search.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/vi/v_search.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/vi/v_search.c (revision 366308) @@ -0,0 +1,544 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "../common/common.h" +#include "vi.h" + +static int v_exaddr(SCR *, VICMD *, dir_t); +static int v_search(SCR *, VICMD *, CHAR_T *, size_t, u_int, dir_t); + +/* + * v_srch -- [count]?RE[? offset] + * Ex address search backward. + * + * PUBLIC: int v_searchb(SCR *, VICMD *); + */ +int +v_searchb(SCR *sp, VICMD *vp) +{ + return (v_exaddr(sp, vp, BACKWARD)); +} + +/* + * v_searchf -- [count]/RE[/ offset] + * Ex address search forward. + * + * PUBLIC: int v_searchf(SCR *, VICMD *); + */ +int +v_searchf(SCR *sp, VICMD *vp) +{ + return (v_exaddr(sp, vp, FORWARD)); +} + +/* + * v_exaddr -- + * Do a vi search (which is really an ex address). + */ +static int +v_exaddr(SCR *sp, VICMD *vp, dir_t dir) +{ + static EXCMDLIST fake = { L("search") }; + EXCMD *cmdp; + GS *gp; + TEXT *tp; + recno_t s_lno; + size_t len, s_cno, tlen; + int err, nb, type; + char buf[20]; + CHAR_T *cmd, *t; + CHAR_T *w; + size_t wlen; + + /* + * !!! + * If using the search command as a motion, any addressing components + * are lost, i.e. y/ptrn/+2, when repeated, is the same as y/ptrn/. + */ + if (F_ISSET(vp, VC_ISDOT)) + return (v_search(sp, vp, + NULL, 0, SEARCH_PARSE | SEARCH_MSG | SEARCH_SET, dir)); + + /* Get the search pattern. */ + if (v_tcmd(sp, vp, dir == BACKWARD ? CH_BSEARCH : CH_FSEARCH, + TXT_BS | TXT_CR | TXT_ESCAPE | TXT_PROMPT | + (O_ISSET(sp, O_SEARCHINCR) ? TXT_SEARCHINCR : 0))) + return (1); + + tp = TAILQ_FIRST(sp->tiq); + + /* If the user backspaced over the prompt, do nothing. */ + if (tp->term == TERM_BS) + return (1); + + /* + * If the user was doing an incremental search, then we've already + * updated the cursor and moved to the right location. Return the + * correct values, we're done. + */ + if (tp->term == TERM_SEARCH) { + vp->m_stop.lno = sp->lno; + vp->m_stop.cno = sp->cno; + if (ISMOTION(vp)) + return (v_correct(sp, vp, 0)); + vp->m_final = vp->m_stop; + return (0); + } + + /* + * If the user entered or , the length is + * 1 and the right thing will happen, i.e. the prompt will be used + * as a command character. + * + * Build a fake ex command structure. + */ + gp = sp->gp; + gp->excmd.cp = tp->lb; + gp->excmd.clen = tp->len; + F_INIT(&gp->excmd, E_VISEARCH); + + /* + * XXX + * Warn if the search wraps. This is a pretty special case, but it's + * nice feature that wasn't in the original implementations of ex/vi. + * (It was added at some point to System V's version.) This message + * is only displayed if there are no keys in the queue. The problem is + * the command is going to succeed, and the message is informational, + * not an error. If a macro displays it repeatedly, e.g., the pattern + * only occurs once in the file and wrapscan is set, you lose big. For + * example, if the macro does something like: + * + * :map K /pattern/^MjK + * + * Each search will display the message, but the following "/pattern/" + * will immediately overwrite it, with strange results. The System V + * vi displays the "wrapped" message multiple times, but because it's + * overwritten each time, it's not as noticeable. As we don't discard + * messages, it's a real problem for us. + */ + if (!KEYS_WAITING(sp)) + F_SET(&gp->excmd, E_SEARCH_WMSG); + + /* Save the current line/column. */ + s_lno = sp->lno; + s_cno = sp->cno; + + /* + * !!! + * Historically, vi / and ? commands were full-blown ex addresses, + * including ';' delimiters, trailing 's, multiple search + * strings (separated by semi-colons) and, finally, full-blown z + * commands after the / and ? search strings. (If the search was + * being used as a motion, the trailing z command was ignored. + * Also, we do some argument checking on the z command, to be sure + * that it's not some other random command.) For multiple search + * strings, leading 's at the second and subsequent strings + * were eaten as well. This has some (unintended?) side-effects: + * the command /ptrn/;3 is legal and results in moving to line 3. + * I suppose you could use it to optionally move to line 3... + * + * !!! + * Historically, if any part of the search command failed, the cursor + * remained unmodified (even if ; was used). We have to play games + * because the underlying ex parser thinks we're modifying the cursor + * as we go, but I think we're compatible with historic practice. + * + * !!! + * Historically, the command "/STRING/; " failed, apparently it + * confused the parser. We're not that compatible. + */ + cmdp = &gp->excmd; + if (ex_range(sp, cmdp, &err)) + return (1); + + /* + * Remember where any remaining command information is, and clean + * up the fake ex command. + */ + cmd = cmdp->cp; + len = cmdp->clen; + gp->excmd.clen = 0; + + if (err) + goto err2; + + /* Copy out the new cursor position and make sure it's okay. */ + switch (cmdp->addrcnt) { + case 1: + vp->m_stop = cmdp->addr1; + break; + case 2: + vp->m_stop = cmdp->addr2; + break; + } + if (!db_exist(sp, vp->m_stop.lno)) { + ex_badaddr(sp, &fake, + vp->m_stop.lno == 0 ? A_ZERO : A_EOF, NUM_OK); + goto err2; + } + + /* + * !!! + * Historic practice is that a trailing 'z' was ignored if it was a + * motion command. Should probably be an error, but not worth the + * effort. + */ + if (ISMOTION(vp)) + return (v_correct(sp, vp, F_ISSET(cmdp, E_DELTA))); + + /* + * !!! + * Historically, if it wasn't a motion command, a delta in the search + * pattern turns it into a first nonblank movement. + */ + nb = F_ISSET(cmdp, E_DELTA); + + /* Check for the 'z' command. */ + if (len != 0) { + if (*cmd != 'z') + goto err1; + + /* No blanks, just like the z command. */ + for (t = cmd + 1, tlen = len - 1; tlen > 0; ++t, --tlen) + if (!isdigit(*t)) + break; + if (tlen && + (*t == '-' || *t == '.' || *t == '+' || *t == '^')) { + ++t; + --tlen; + type = 1; + } else + type = 0; + if (tlen) + goto err1; + + /* The z command will do the nonblank for us. */ + nb = 0; + + /* Default to z+. */ + if (!type && + v_event_push(sp, NULL, L("+"), 1, CH_NOMAP | CH_QUOTED)) + return (1); + + /* Push the user's command. */ + if (v_event_push(sp, NULL, cmd, len, CH_NOMAP | CH_QUOTED)) + return (1); + + /* Push line number so get correct z display. */ + tlen = snprintf(buf, + sizeof(buf), "%lu", (u_long)vp->m_stop.lno); + CHAR2INT(sp, buf, tlen, w, wlen); + if (v_event_push(sp, NULL, w, wlen, CH_NOMAP | CH_QUOTED)) + return (1); + + /* Don't refresh until after 'z' happens. */ + F_SET(VIP(sp), VIP_S_REFRESH); + } + + /* Non-motion commands move to the end of the range. */ + vp->m_final = vp->m_stop; + if (nb) { + F_CLR(vp, VM_RCM_MASK); + F_SET(vp, VM_RCM_SETFNB); + } + return (0); + +err1: msgq(sp, M_ERR, + "188|Characters after search string, line offset and/or z command"); +err2: vp->m_final.lno = s_lno; + vp->m_final.cno = s_cno; + return (1); +} + +/* + * v_searchN -- N + * Reverse last search. + * + * PUBLIC: int v_searchN(SCR *, VICMD *); + */ +int +v_searchN(SCR *sp, VICMD *vp) +{ + dir_t dir; + + switch (sp->searchdir) { + case BACKWARD: + dir = FORWARD; + break; + case FORWARD: + dir = BACKWARD; + break; + default: + dir = sp->searchdir; + break; + } + return (v_search(sp, vp, NULL, 0, SEARCH_PARSE, dir)); +} + +/* + * v_searchn -- n + * Repeat last search. + * + * PUBLIC: int v_searchn(SCR *, VICMD *); + */ +int +v_searchn(SCR *sp, VICMD *vp) +{ + return (v_search(sp, vp, NULL, 0, SEARCH_PARSE, sp->searchdir)); +} + +/* + * is_special -- + * Test if the character is special in a basic RE. + */ +static int +is_special(CHAR_T c) +{ + /* + * !!! + * `*' and `$' are ordinary when appear at the beginning of a RE, + * but it's safe to distinguish them from the ordinary characters. + * The tilde is vi-specific, of course. + */ + return (STRCHR(L(".[*\\^$~"), c) && c); +} + +/* + * Rear delimiter for word search when the keyword ends in + * (i.e., consists of) a non-word character. See v_searchw below. + */ +#define RE_NWSTOP L("([^[:alnum:]_]|$)") +#define RE_NWSTOP_LEN (SIZE(RE_NWSTOP) - 1) + +/* + * v_searchw -- [count]^A + * Search for the word under the cursor. + * + * PUBLIC: int v_searchw(SCR *, VICMD *); + */ +int +v_searchw(SCR *sp, VICMD *vp) +{ + size_t blen, len; + int rval; + CHAR_T *bp, *p; + + /* An upper bound for the SIZE of the RE under construction. */ + len = VIP(sp)->klen + MAX(RE_WSTART_LEN, 1) + + MAX(RE_WSTOP_LEN, RE_NWSTOP_LEN); + GET_SPACE_RETW(sp, bp, blen, len); + p = bp; + + /* Only the first character can be non-word, see v_curword. */ + if (inword(VIP(sp)->keyw[0])) { + MEMCPY(p, RE_WSTART, RE_WSTART_LEN); + p += RE_WSTART_LEN; + } else if (is_special(VIP(sp)->keyw[0])) { + MEMCPY(p, L("\\"), 1); + p += 1; + } + + MEMCPY(p, VIP(sp)->keyw, VIP(sp)->klen); + p += VIP(sp)->klen; + + if (inword(p[-1])) { + MEMCPY(p, RE_WSTOP, RE_WSTOP_LEN); + p += RE_WSTOP_LEN; + } else { + /* + * The keyword is a single non-word character. + * We want it to stay the same when typing ^A several times + * in a row, just the way the other cases behave. + */ + MEMCPY(p, RE_NWSTOP, RE_NWSTOP_LEN); + p += RE_NWSTOP_LEN; + } + + len = p - bp; + rval = v_search(sp, vp, bp, len, SEARCH_SET, FORWARD); + + FREE_SPACEW(sp, bp, blen); + return (rval); +} + +/* + * v_search -- + * The search commands. + */ +static int +v_search(SCR *sp, VICMD *vp, CHAR_T *ptrn, size_t plen, u_int flags, dir_t dir) +{ + /* Display messages. */ + LF_SET(SEARCH_MSG); + + /* If it's a motion search, offset past end-of-line is okay. */ + if (ISMOTION(vp)) + LF_SET(SEARCH_EOL); + + /* + * XXX + * Warn if the search wraps. See the comment above, in v_exaddr(). + */ + if (!KEYS_WAITING(sp)) + LF_SET(SEARCH_WMSG); + + switch (dir) { + case BACKWARD: + if (b_search(sp, + &vp->m_start, &vp->m_stop, ptrn, plen, NULL, flags)) + return (1); + break; + case FORWARD: + if (f_search(sp, + &vp->m_start, &vp->m_stop, ptrn, plen, NULL, flags)) + return (1); + break; + case NOTSET: + msgq(sp, M_ERR, "189|No previous search pattern"); + return (1); + default: + abort(); + } + + /* Correct motion commands, otherwise, simply move to the location. */ + if (ISMOTION(vp)) { + if (v_correct(sp, vp, 0)) + return(1); + } else + vp->m_final = vp->m_stop; + return (0); +} + +/* + * v_correct -- + * Handle command with a search as the motion. + * + * !!! + * Historically, commands didn't affect the line searched to/from if the + * motion command was a search and the final position was the start/end + * of the line. There were some special cases and vi was not consistent; + * it was fairly easy to confuse it. For example, given the two lines: + * + * abcdefghi + * ABCDEFGHI + * + * placing the cursor on the 'A' and doing y?$ would so confuse it that 'h' + * 'k' and put would no longer work correctly. In any case, we try to do + * the right thing, but it's not going to exactly match historic practice. + * + * PUBLIC: int v_correct(SCR *, VICMD *, int); + */ +int +v_correct(SCR *sp, VICMD *vp, int isdelta) +{ + dir_t dir; + MARK m; + size_t len; + + /* + * !!! + * We may have wrapped if wrapscan was set, and we may have returned + * to the position where the cursor started. Historic vi didn't cope + * with this well. Yank wouldn't beep, but the first put after the + * yank would move the cursor right one column (without adding any + * text) and the second would put a copy of the current line. The + * change and delete commands would beep, but would leave the cursor + * on the colon command line. I believe that there are macros that + * depend on delete, at least, failing. For now, commands that use + * search as a motion component fail when the search returns to the + * original cursor position. + */ + if (vp->m_start.lno == vp->m_stop.lno && + vp->m_start.cno == vp->m_stop.cno) { + msgq(sp, M_BERR, "190|Search wrapped to original position"); + return (1); + } + + /* + * !!! + * Searches become line mode operations if there was a delta specified + * to the search pattern. + */ + if (isdelta) + F_SET(vp, VM_LMODE); + + /* + * If the motion is in the reverse direction, switch the start and + * stop MARK's so that it's in a forward direction. (There's no + * reason for this other than to make the tests below easier. The + * code in vi.c:vi() would have done the switch.) Both forward + * and backward motions can happen for any kind of search command + * because of the wrapscan option. + */ + if (vp->m_start.lno > vp->m_stop.lno || + (vp->m_start.lno == vp->m_stop.lno && + vp->m_start.cno > vp->m_stop.cno)) { + m = vp->m_start; + vp->m_start = vp->m_stop; + vp->m_stop = m; + dir = BACKWARD; + } else + dir = FORWARD; + + /* + * BACKWARD: + * Delete and yank commands move to the end of the range. + * Ignore others. + * + * FORWARD: + * Delete and yank commands don't move. Ignore others. + */ + vp->m_final = vp->m_start; + + /* + * !!! + * Delta'd searches don't correct based on column positions. + */ + if (isdelta) + return (0); + + /* + * !!! + * Backward searches starting at column 0, and forward searches ending + * at column 0 are corrected to the last column of the previous line. + * Otherwise, adjust the starting/ending point to the character before + * the current one (this is safe because we know the search had to move + * to succeed). + * + * Searches become line mode operations if they start at the first + * nonblank and end at column 0 of another line. + */ + if (vp->m_start.lno < vp->m_stop.lno && vp->m_stop.cno == 0) { + if (db_get(sp, --vp->m_stop.lno, DBG_FATAL, NULL, &len)) + return (1); + vp->m_stop.cno = len ? len - 1 : 0; + len = 0; + if (nonblank(sp, vp->m_start.lno, &len)) + return (1); + if (vp->m_start.cno <= len) + F_SET(vp, VM_LMODE); + } else + --vp->m_stop.cno; + + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/vi/v_search.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/vi/v_status.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/vi/v_status.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/vi/v_status.c (revision 366308) @@ -0,0 +1,34 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include + +#include "../common/common.h" +#include "vi.h" + +/* + * v_status -- ^G + * Show the file status. + * + * PUBLIC: int v_status(SCR *, VICMD *); + */ +int +v_status(SCR *sp, VICMD *vp) +{ + (void)msgq_status(sp, vp->m_start.lno, MSTAT_SHOWLAST); + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/vi/v_status.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/vi/v_ulcase.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/vi/v_ulcase.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/vi/v_ulcase.c (revision 366308) @@ -0,0 +1,167 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "../common/common.h" +#include "vi.h" + +static int ulcase(SCR *, recno_t, CHAR_T *, size_t, size_t, size_t); + +/* + * v_ulcase -- [count]~ + * Toggle upper & lower case letters. + * + * !!! + * Historic vi didn't permit ~ to cross newline boundaries. I can + * think of no reason why it shouldn't, which at least lets the user + * auto-repeat through a paragraph. + * + * !!! + * In historic vi, the count was ignored. It would have been better + * if there had been an associated motion, but it's too late to make + * that the default now. + * + * PUBLIC: int v_ulcase(SCR *, VICMD *); + */ +int +v_ulcase(SCR *sp, VICMD *vp) +{ + recno_t lno; + size_t cno, lcnt, len; + u_long cnt; + CHAR_T *p; + + lno = vp->m_start.lno; + cno = vp->m_start.cno; + + for (cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt > 0; cno = 0) { + /* SOF is an error, EOF is an infinite count sink. */ + if (db_get(sp, lno, 0, &p, &len)) { + if (lno == 1) { + v_emsg(sp, NULL, VIM_EMPTY); + return (1); + } + --lno; + break; + } + + /* Empty lines decrement the count by one. */ + if (len == 0) { + --cnt; + vp->m_final.cno = 0; + continue; + } + + if (cno + cnt >= len) { + lcnt = len - 1; + cnt -= len - cno; + + vp->m_final.cno = len - 1; + } else { + lcnt = cno + cnt - 1; + cnt = 0; + + vp->m_final.cno = lcnt + 1; + } + + if (ulcase(sp, lno, p, len, cno, lcnt)) + return (1); + + if (cnt > 0) + ++lno; + } + + vp->m_final.lno = lno; + return (0); +} + +/* + * v_mulcase -- [count]~[count]motion + * Toggle upper & lower case letters over a range. + * + * PUBLIC: int v_mulcase(SCR *, VICMD *); + */ +int +v_mulcase(SCR *sp, VICMD *vp) +{ + CHAR_T *p; + size_t len; + recno_t lno; + + for (lno = vp->m_start.lno;;) { + if (db_get(sp, lno, DBG_FATAL, &p, &len)) + return (1); + if (len != 0 && ulcase(sp, lno, p, len, + lno == vp->m_start.lno ? vp->m_start.cno : 0, + !F_ISSET(vp, VM_LMODE) && + lno == vp->m_stop.lno ? vp->m_stop.cno : len)) + return (1); + + if (++lno > vp->m_stop.lno) + break; + } + + /* + * XXX + * I didn't create a new motion command when I added motion semantics + * for ~. While that's the correct way to do it, that choice would + * have required changes all over the vi directory for little gain. + * Instead, we pretend it's a yank command. Note, this means that we + * follow the cursor motion rules for yank commands, but that seems + * reasonable to me. + */ + return (0); +} + +/* + * ulcase -- + * Change part of a line's case. + */ +static int +ulcase(SCR *sp, recno_t lno, CHAR_T *lp, size_t len, size_t scno, size_t ecno) +{ + size_t blen; + int change, rval; + ARG_CHAR_T ch; + CHAR_T *p, *t, *bp; + + GET_SPACE_RETW(sp, bp, blen, len); + MEMMOVE(bp, lp, len); + + change = rval = 0; + for (p = bp + scno, t = bp + ecno + 1; p < t; ++p) { + ch = (UCHAR_T)*p; + if (ISLOWER(ch)) { + *p = TOUPPER(ch); + change = 1; + } else if (ISUPPER(ch)) { + *p = TOLOWER(ch); + change = 1; + } + } + + if (change && db_set(sp, lno, bp, len)) + rval = 1; + + FREE_SPACEW(sp, bp, blen); + return (rval); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/vi/v_ulcase.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/vi/v_undo.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/vi/v_undo.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/vi/v_undo.c (revision 366308) @@ -0,0 +1,131 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "../common/common.h" +#include "vi.h" + +/* + * v_Undo -- U + * Undo changes to this line. + * + * PUBLIC: int v_Undo(SCR *, VICMD *); + */ +int +v_Undo(SCR *sp, VICMD *vp) +{ + /* + * Historically, U reset the cursor to the first column in the line + * (not the first non-blank). This seems a bit non-intuitive, but, + * considering that we may have undone multiple changes, anything + * else (including the cursor position stored in the logging records) + * is going to appear random. + */ + vp->m_final.cno = 0; + + /* + * !!! + * Set up the flags so that an immediately subsequent 'u' will roll + * forward, instead of backward. In historic vi, a 'u' following a + * 'U' redid all of the changes to the line. Given that the user has + * explicitly discarded those changes by entering 'U', it seems likely + * that the user wants something between the original and end forms of + * the line, so starting to replay the changes seems the best way to + * get to there. + */ + F_SET(sp->ep, F_UNDO); + sp->ep->lundo = BACKWARD; + + return (log_setline(sp)); +} + +/* + * v_undo -- u + * Undo the last change. + * + * PUBLIC: int v_undo(SCR *, VICMD *); + */ +int +v_undo(SCR *sp, VICMD *vp) +{ + EXF *ep; + + /* Set the command count. */ + VIP(sp)->u_ccnt = sp->ccnt; + + /* + * !!! + * In historic vi, 'u' toggled between "undo" and "redo", i.e. 'u' + * undid the last undo. However, if there has been a change since + * the last undo/redo, we always do an undo. To make this work when + * the user can undo multiple operations, we leave the old semantic + * unchanged, but make '.' after a 'u' do another undo/redo operation. + * This has two problems. + * + * The first is that 'u' didn't set '.' in historic vi. So, if a + * user made a change, realized it was in the wrong place, does a + * 'u' to undo it, moves to the right place and then does '.', the + * change was reapplied. To make this work, we only apply the '.' + * to the undo command if it's the command immediately following an + * undo command. See vi/vi.c:getcmd() for the details. + * + * The second is that the traditional way to view the numbered cut + * buffers in vi was to enter the commands "1pu.u.u.u. which will + * no longer work because the '.' immediately follows the 'u' command. + * Since we provide a much better method of viewing buffers, and + * nobody can think of a better way of adding in multiple undo, this + * remains broken. + * + * !!! + * There is change to historic practice for the final cursor position + * in this implementation. In historic vi, if an undo was isolated to + * a single line, the cursor moved to the start of the change, and + * then, subsequent 'u' commands would not move it again. (It has been + * pointed out that users used multiple undo commands to get the cursor + * to the start of the changed text.) Nvi toggles between the cursor + * position before and after the change was made. One final issue is + * that historic vi only did this if the user had not moved off of the + * line before entering the undo command; otherwise, vi would move the + * cursor to the most attractive position on the changed line. + * + * It would be difficult to match historic practice in this area. You + * not only have to know that the changes were isolated to one line, + * but whether it was the first or second undo command as well. And, + * to completely match historic practice, we'd have to track users line + * changes, too. This isn't worth the effort. + */ + ep = sp->ep; + if (!F_ISSET(ep, F_UNDO)) { + F_SET(ep, F_UNDO); + ep->lundo = BACKWARD; + } else if (!F_ISSET(vp, VC_ISDOT)) + ep->lundo = ep->lundo == BACKWARD ? FORWARD : BACKWARD; + + switch (ep->lundo) { + case BACKWARD: + return (log_backward(sp, &vp->m_final)); + case FORWARD: + return (log_forward(sp, &vp->m_final)); + default: + abort(); + } + /* NOTREACHED */ +} Property changes on: vendor/nvi/2.2.0-05ed8b9/vi/v_undo.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/vi/v_util.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/vi/v_util.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/vi/v_util.c (revision 366308) @@ -0,0 +1,163 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "../common/common.h" +#include "vi.h" + +/* + * v_eof -- + * Vi end-of-file error. + * + * PUBLIC: void v_eof(SCR *, MARK *); + */ +void +v_eof(SCR *sp, MARK *mp) +{ + recno_t lno; + + if (mp == NULL) + v_emsg(sp, NULL, VIM_EOF); + else { + if (db_last(sp, &lno)) + return; + if (mp->lno >= lno) + v_emsg(sp, NULL, VIM_EOF); + else + msgq(sp, M_BERR, "195|Movement past the end-of-file"); + } +} + +/* + * v_eol -- + * Vi end-of-line error. + * + * PUBLIC: void v_eol(SCR *, MARK *); + */ +void +v_eol(SCR *sp, MARK *mp) +{ + size_t len; + + if (mp == NULL) + v_emsg(sp, NULL, VIM_EOL); + else { + if (db_get(sp, mp->lno, DBG_FATAL, NULL, &len)) + return; + if (mp->cno == len - 1) + v_emsg(sp, NULL, VIM_EOL); + else + msgq(sp, M_BERR, "196|Movement past the end-of-line"); + } +} + +/* + * v_nomove -- + * Vi no cursor movement error. + * + * PUBLIC: void v_nomove(SCR *); + */ +void +v_nomove(SCR *sp) +{ + msgq(sp, M_BERR, "197|No cursor movement made"); +} + +/* + * v_sof -- + * Vi start-of-file error. + * + * PUBLIC: void v_sof(SCR *, MARK *); + */ +void +v_sof(SCR *sp, MARK *mp) +{ + if (mp == NULL || mp->lno == 1) + msgq(sp, M_BERR, "198|Already at the beginning of the file"); + else + msgq(sp, M_BERR, "199|Movement past the beginning of the file"); +} + +/* + * v_sol -- + * Vi start-of-line error. + * + * PUBLIC: void v_sol(SCR *); + */ +void +v_sol(SCR *sp) +{ + msgq(sp, M_BERR, "200|Already in the first column"); +} + +/* + * v_isempty -- + * Return if the line contains nothing but white-space characters. + * + * PUBLIC: int v_isempty(CHAR_T *, size_t); + */ +int +v_isempty(CHAR_T *p, size_t len) +{ + for (; len--; ++p) + if (!isblank(*p)) + return (0); + return (1); +} + +/* + * v_emsg -- + * Display a few common vi messages. + * + * PUBLIC: void v_emsg(SCR *, char *, vim_t); + */ +void +v_emsg(SCR *sp, char *p, vim_t which) +{ + switch (which) { + case VIM_COMBUF: + msgq(sp, M_ERR, + "201|Buffers should be specified before the command"); + break; + case VIM_EMPTY: + msgq(sp, M_BERR, "209|The file is empty"); + break; + case VIM_EOF: + msgq(sp, M_BERR, "202|Already at end-of-file"); + break; + case VIM_EOL: + msgq(sp, M_BERR, "203|Already at end-of-line"); + break; + case VIM_NOCOM: + case VIM_NOCOM_B: + msgq(sp, + which == VIM_NOCOM_B ? M_BERR : M_ERR, + "204|%s isn't a vi command", p); + break; + case VIM_WRESIZE: + msgq(sp, M_ERR, "Window resize interrupted text input mode"); + break; + case VIM_USAGE: + msgq(sp, M_ERR, "205|Usage: %s", p); + break; + } +} Property changes on: vendor/nvi/2.2.0-05ed8b9/vi/v_util.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/vi/v_word.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/vi/v_word.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/vi/v_word.c (revision 366308) @@ -0,0 +1,522 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include + +#include "../common/common.h" +#include "vi.h" + +/* + * There are two types of "words". Bigwords are easy -- groups of anything + * delimited by whitespace. Normal words are trickier. They are either a + * group of characters, numbers and underscores, or a group of anything but, + * delimited by whitespace. When for a word, if you're in whitespace, it's + * easy, just remove the whitespace and go to the beginning or end of the + * word. Otherwise, figure out if the next character is in a different group. + * If it is, go to the beginning or end of that group, otherwise, go to the + * beginning or end of the current group. The historic version of vi didn't + * get this right, so, for example, there were cases where "4e" was not the + * same as "eeee" -- in particular, single character words, and commands that + * began in whitespace were almost always handled incorrectly. To get it right + * you have to resolve the cursor after each search so that the look-ahead to + * figure out what type of "word" the cursor is in will be correct. + * + * Empty lines, and lines that consist of only white-space characters count + * as a single word, and the beginning and end of the file counts as an + * infinite number of words. + * + * Movements associated with commands are different than movement commands. + * For example, in "abc def", with the cursor on the 'a', "cw" is from + * 'a' to 'c', while "w" is from 'a' to 'd'. In general, trailing white + * space is discarded from the change movement. Another example is that, + * in the same string, a "cw" on any white space character replaces that + * single character, and nothing else. Ain't nothin' in here that's easy. + * + * One historic note -- in the original vi, the 'w', 'W' and 'B' commands + * would treat groups of empty lines as individual words, i.e. the command + * would move the cursor to each new empty line. The 'e' and 'E' commands + * would treat groups of empty lines as a single word, i.e. the first use + * would move past the group of lines. The 'b' command would just beep at + * you, or, if you did it from the start of the line as part of a motion + * command, go absolutely nuts. If the lines contained only white-space + * characters, the 'w' and 'W' commands would just beep at you, and the 'B', + * 'b', 'E' and 'e' commands would treat the group as a single word, and + * the 'B' and 'b' commands will treat the lines as individual words. This + * implementation treats all of these cases as a single white-space word. + */ + +enum which {BIGWORD, LITTLEWORD}; + +static int bword(SCR *, VICMD *, enum which); +static int eword(SCR *, VICMD *, enum which); +static int fword(SCR *, VICMD *, enum which); + +/* + * v_wordW -- [count]W + * Move forward a bigword at a time. + * + * PUBLIC: int v_wordW(SCR *, VICMD *); + */ +int +v_wordW(SCR *sp, VICMD *vp) +{ + return (fword(sp, vp, BIGWORD)); +} + +/* + * v_wordw -- [count]w + * Move forward a word at a time. + * + * PUBLIC: int v_wordw(SCR *, VICMD *); + */ +int +v_wordw(SCR *sp, VICMD *vp) +{ + return (fword(sp, vp, LITTLEWORD)); +} + +/* + * fword -- + * Move forward by words. + */ +static int +fword(SCR *sp, VICMD *vp, enum which type) +{ + enum { INWORD, NOTWORD } state; + VCS cs; + u_long cnt; + + cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; + cs.cs_lno = vp->m_start.lno; + cs.cs_cno = vp->m_start.cno; + if (cs_init(sp, &cs)) + return (1); + + /* + * If in white-space: + * If the count is 1, and it's a change command, we're done. + * Else, move to the first non-white-space character, which + * counts as a single word move. If it's a motion command, + * don't move off the end of the line. + */ + if (cs.cs_flags == CS_EMP || (cs.cs_flags == 0 && ISBLANK(cs.cs_ch))) { + if (ISMOTION(vp) && cs.cs_flags != CS_EMP && cnt == 1) { + if (ISCMD(vp->rkp, 'c')) + return (0); + if (ISCMD(vp->rkp, 'd') || ISCMD(vp->rkp, 'y')) { + if (cs_fspace(sp, &cs)) + return (1); + goto ret; + } + } + if (cs_fblank(sp, &cs)) + return (1); + --cnt; + } + + /* + * Cyclically move to the next word -- this involves skipping + * over word characters and then any trailing non-word characters. + * Note, for the 'w' command, the definition of a word keeps + * switching. + */ + if (type == BIGWORD) + while (cnt--) { + for (;;) { + if (cs_next(sp, &cs)) + return (1); + if (cs.cs_flags == CS_EOF) + goto ret; + if (cs.cs_flags != 0 || ISBLANK(cs.cs_ch)) + break; + } + /* + * If a motion command and we're at the end of the + * last word, we're done. Delete and yank eat any + * trailing blanks, but we don't move off the end + * of the line regardless. + */ + if (cnt == 0 && ISMOTION(vp)) { + if ((ISCMD(vp->rkp, 'd') || + ISCMD(vp->rkp, 'y')) && + cs_fspace(sp, &cs)) + return (1); + break; + } + + /* Eat whitespace characters. */ + if (cs_fblank(sp, &cs)) + return (1); + if (cs.cs_flags == CS_EOF) + goto ret; + } + else + while (cnt--) { + state = cs.cs_flags == 0 && + inword(cs.cs_ch) ? INWORD : NOTWORD; + for (;;) { + if (cs_next(sp, &cs)) + return (1); + if (cs.cs_flags == CS_EOF) + goto ret; + if (cs.cs_flags != 0 || ISBLANK(cs.cs_ch)) + break; + if (state == INWORD) { + if (!inword(cs.cs_ch)) + break; + } else + if (inword(cs.cs_ch)) + break; + } + /* See comment above. */ + if (cnt == 0 && ISMOTION(vp)) { + if ((ISCMD(vp->rkp, 'd') || + ISCMD(vp->rkp, 'y')) && + cs_fspace(sp, &cs)) + return (1); + break; + } + + /* Eat whitespace characters. */ + if (cs.cs_flags != 0 || ISBLANK(cs.cs_ch)) + if (cs_fblank(sp, &cs)) + return (1); + if (cs.cs_flags == CS_EOF) + goto ret; + } + + /* + * If we didn't move, we must be at EOF. + * + * !!! + * That's okay for motion commands, however. + */ +ret: if (!ISMOTION(vp) && + cs.cs_lno == vp->m_start.lno && cs.cs_cno == vp->m_start.cno) { + v_eof(sp, &vp->m_start); + return (1); + } + + /* Adjust the end of the range for motion commands. */ + vp->m_stop.lno = cs.cs_lno; + vp->m_stop.cno = cs.cs_cno; + if (ISMOTION(vp) && cs.cs_flags == 0) + --vp->m_stop.cno; + + /* + * Non-motion commands move to the end of the range. Delete + * and yank stay at the start, ignore others. + */ + vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop; + return (0); +} + +/* + * v_wordE -- [count]E + * Move forward to the end of the bigword. + * + * PUBLIC: int v_wordE(SCR *, VICMD *); + */ +int +v_wordE(SCR *sp, VICMD *vp) +{ + return (eword(sp, vp, BIGWORD)); +} + +/* + * v_worde -- [count]e + * Move forward to the end of the word. + * + * PUBLIC: int v_worde(SCR *, VICMD *); + */ +int +v_worde(SCR *sp, VICMD *vp) +{ + return (eword(sp, vp, LITTLEWORD)); +} + +/* + * eword -- + * Move forward to the end of the word. + */ +static int +eword(SCR *sp, VICMD *vp, enum which type) +{ + enum { INWORD, NOTWORD } state; + VCS cs; + u_long cnt; + + cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; + cs.cs_lno = vp->m_start.lno; + cs.cs_cno = vp->m_start.cno; + if (cs_init(sp, &cs)) + return (1); + + /* + * !!! + * If in whitespace, or the next character is whitespace, move past + * it. (This doesn't count as a word move.) Stay at the character + * past the current one, it sets word "state" for the 'e' command. + */ + if (cs.cs_flags == 0 && !ISBLANK(cs.cs_ch)) { + if (cs_next(sp, &cs)) + return (1); + if (cs.cs_flags == 0 && !ISBLANK(cs.cs_ch)) + goto start; + } + if (cs_fblank(sp, &cs)) + return (1); + + /* + * Cyclically move to the next word -- this involves skipping + * over word characters and then any trailing non-word characters. + * Note, for the 'e' command, the definition of a word keeps + * switching. + */ +start: if (type == BIGWORD) + while (cnt--) { + for (;;) { + if (cs_next(sp, &cs)) + return (1); + if (cs.cs_flags == CS_EOF) + goto ret; + if (cs.cs_flags != 0 || ISBLANK(cs.cs_ch)) + break; + } + /* + * When we reach the start of the word after the last + * word, we're done. If we changed state, back up one + * to the end of the previous word. + */ + if (cnt == 0) { + if (cs.cs_flags == 0 && cs_prev(sp, &cs)) + return (1); + break; + } + + /* Eat whitespace characters. */ + if (cs_fblank(sp, &cs)) + return (1); + if (cs.cs_flags == CS_EOF) + goto ret; + } + else + while (cnt--) { + state = cs.cs_flags == 0 && + inword(cs.cs_ch) ? INWORD : NOTWORD; + for (;;) { + if (cs_next(sp, &cs)) + return (1); + if (cs.cs_flags == CS_EOF) + goto ret; + if (cs.cs_flags != 0 || ISBLANK(cs.cs_ch)) + break; + if (state == INWORD) { + if (!inword(cs.cs_ch)) + break; + } else + if (inword(cs.cs_ch)) + break; + } + /* See comment above. */ + if (cnt == 0) { + if (cs.cs_flags == 0 && cs_prev(sp, &cs)) + return (1); + break; + } + + /* Eat whitespace characters. */ + if (cs.cs_flags != 0 || ISBLANK(cs.cs_ch)) + if (cs_fblank(sp, &cs)) + return (1); + if (cs.cs_flags == CS_EOF) + goto ret; + } + + /* + * If we didn't move, we must be at EOF. + * + * !!! + * That's okay for motion commands, however. + */ +ret: if (!ISMOTION(vp) && + cs.cs_lno == vp->m_start.lno && cs.cs_cno == vp->m_start.cno) { + v_eof(sp, &vp->m_start); + return (1); + } + + /* Set the end of the range for motion commands. */ + vp->m_stop.lno = cs.cs_lno; + vp->m_stop.cno = cs.cs_cno; + + /* + * Non-motion commands move to the end of the range. + * Delete and yank stay at the start, ignore others. + */ + vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop; + return (0); +} + +/* + * v_WordB -- [count]B + * Move backward a bigword at a time. + * + * PUBLIC: int v_wordB(SCR *, VICMD *); + */ +int +v_wordB(SCR *sp, VICMD *vp) +{ + return (bword(sp, vp, BIGWORD)); +} + +/* + * v_wordb -- [count]b + * Move backward a word at a time. + * + * PUBLIC: int v_wordb(SCR *, VICMD *); + */ +int +v_wordb(SCR *sp, VICMD *vp) +{ + return (bword(sp, vp, LITTLEWORD)); +} + +/* + * bword -- + * Move backward by words. + */ +static int +bword(SCR *sp, VICMD *vp, enum which type) +{ + enum { INWORD, NOTWORD } state; + VCS cs; + u_long cnt; + + cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; + cs.cs_lno = vp->m_start.lno; + cs.cs_cno = vp->m_start.cno; + if (cs_init(sp, &cs)) + return (1); + + /* + * !!! + * If in whitespace, or the previous character is whitespace, move + * past it. (This doesn't count as a word move.) Stay at the + * character before the current one, it sets word "state" for the + * 'b' command. + */ + if (cs.cs_flags == 0 && !ISBLANK(cs.cs_ch)) { + if (cs_prev(sp, &cs)) + return (1); + if (cs.cs_flags == 0 && !ISBLANK(cs.cs_ch)) + goto start; + } + if (cs_bblank(sp, &cs)) + return (1); + + /* + * Cyclically move to the beginning of the previous word -- this + * involves skipping over word characters and then any trailing + * non-word characters. Note, for the 'b' command, the definition + * of a word keeps switching. + */ +start: if (type == BIGWORD) + while (cnt--) { + for (;;) { + if (cs_prev(sp, &cs)) + return (1); + if (cs.cs_flags == CS_SOF) + goto ret; + if (cs.cs_flags != 0 || ISBLANK(cs.cs_ch)) + break; + } + /* + * When we reach the end of the word before the last + * word, we're done. If we changed state, move forward + * one to the end of the next word. + */ + if (cnt == 0) { + if (cs.cs_flags == 0 && cs_next(sp, &cs)) + return (1); + break; + } + + /* Eat whitespace characters. */ + if (cs_bblank(sp, &cs)) + return (1); + if (cs.cs_flags == CS_SOF) + goto ret; + } + else + while (cnt--) { + state = cs.cs_flags == 0 && + inword(cs.cs_ch) ? INWORD : NOTWORD; + for (;;) { + if (cs_prev(sp, &cs)) + return (1); + if (cs.cs_flags == CS_SOF) + goto ret; + if (cs.cs_flags != 0 || ISBLANK(cs.cs_ch)) + break; + if (state == INWORD) { + if (!inword(cs.cs_ch)) + break; + } else + if (inword(cs.cs_ch)) + break; + } + /* See comment above. */ + if (cnt == 0) { + if (cs.cs_flags == 0 && cs_next(sp, &cs)) + return (1); + break; + } + + /* Eat whitespace characters. */ + if (cs.cs_flags != 0 || ISBLANK(cs.cs_ch)) + if (cs_bblank(sp, &cs)) + return (1); + if (cs.cs_flags == CS_SOF) + goto ret; + } + + /* If we didn't move, we must be at SOF. */ +ret: if (cs.cs_lno == vp->m_start.lno && cs.cs_cno == vp->m_start.cno) { + v_sof(sp, &vp->m_start); + return (1); + } + + /* Set the end of the range for motion commands. */ + vp->m_stop.lno = cs.cs_lno; + vp->m_stop.cno = cs.cs_cno; + + /* + * All commands move to the end of the range. Motion commands + * adjust the starting point to the character before the current + * one. + * + * !!! + * The historic vi didn't get this right -- the `yb' command yanked + * the right stuff and even updated the cursor value, but the cursor + * was not actually updated on the screen. + */ + vp->m_final = vp->m_stop; + if (ISMOTION(vp)) + --vp->m_start.cno; + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/vi/v_word.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/vi/v_xchar.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/vi/v_xchar.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/vi/v_xchar.c (revision 366308) @@ -0,0 +1,99 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include + +#include "../common/common.h" +#include "vi.h" + +/* + * v_xchar -- [buffer] [count]x + * Deletes the character(s) on which the cursor sits. + * + * PUBLIC: int v_xchar(SCR *, VICMD *); + */ +int +v_xchar(SCR *sp, VICMD *vp) +{ + size_t len; + int isempty; + + if (db_eget(sp, vp->m_start.lno, NULL, &len, &isempty)) { + if (isempty) + goto nodel; + return (1); + } + if (len == 0) { +nodel: msgq(sp, M_BERR, "206|No characters to delete"); + return (1); + } + + /* + * Delete from the cursor toward the end of line, w/o moving the + * cursor. + * + * !!! + * Note, "2x" at EOL isn't the same as "xx" because the left movement + * of the cursor as part of the 'x' command isn't taken into account. + * Historically correct. + */ + if (F_ISSET(vp, VC_C1SET)) + vp->m_stop.cno += vp->count - 1; + if (vp->m_stop.cno >= len - 1) { + vp->m_stop.cno = len - 1; + vp->m_final.cno = vp->m_start.cno ? vp->m_start.cno - 1 : 0; + } else + vp->m_final.cno = vp->m_start.cno; + + if (cut(sp, + F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL, + &vp->m_start, &vp->m_stop, 0)) + return (1); + return (del(sp, &vp->m_start, &vp->m_stop, 0)); +} + +/* + * v_Xchar -- [buffer] [count]X + * Deletes the character(s) immediately before the current cursor + * position. + * + * PUBLIC: int v_Xchar(SCR *, VICMD *); + */ +int +v_Xchar(SCR *sp, VICMD *vp) +{ + u_long cnt; + + if (vp->m_start.cno == 0) { + v_sol(sp); + return (1); + } + + cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; + if (cnt >= vp->m_start.cno) + vp->m_start.cno = 0; + else + vp->m_start.cno -= cnt; + --vp->m_stop.cno; + vp->m_final.cno = vp->m_start.cno; + + if (cut(sp, + F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL, + &vp->m_start, &vp->m_stop, 0)) + return (1); + return (del(sp, &vp->m_start, &vp->m_stop, 0)); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/vi/v_xchar.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/vi/v_yank.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/vi/v_yank.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/vi/v_yank.c (revision 366308) @@ -0,0 +1,76 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include + +#include "../common/common.h" +#include "vi.h" + +/* + * v_yank -- [buffer][count]y[count][motion] + * [buffer][count]Y + * Yank text (or lines of text) into a cut buffer. + * + * !!! + * Historic vi moved the cursor to the from MARK if it was before the current + * cursor and on a different line, e.g., "yk" moves the cursor but "yj" and + * "yl" do not. Unfortunately, it's too late to change this now. Matching + * the historic semantics isn't easy. The line number was always changed and + * column movement was usually relative. However, "y'a" moved the cursor to + * the first non-blank of the line marked by a, while "y`a" moved the cursor + * to the line and column marked by a. Hopefully, the motion component code + * got it right... Unlike delete, we make no adjustments here. + * + * PUBLIC: int v_yank(SCR *, VICMD *); + */ +int +v_yank(SCR *sp, VICMD *vp) +{ + size_t len; + + if (cut(sp, + F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL, &vp->m_start, + &vp->m_stop, F_ISSET(vp, VM_LMODE) ? CUT_LINEMODE : 0)) + return (1); + sp->rptlines[L_YANKED] += (vp->m_stop.lno - vp->m_start.lno) + 1; + + /* + * One special correction, in case we've deleted the current line or + * character. We check it here instead of checking in every command + * that can be a motion component. + */ + if (db_get(sp, vp->m_final.lno, DBG_FATAL, NULL, &len)) + return (1); + + /* + * !!! + * Cursor movements, other than those caused by a line mode command + * moving to another line, historically reset the relative position. + * + * This currently matches the check made in v_delete(), I'm hoping + * that they should be consistent... + */ + if (!F_ISSET(vp, VM_LMODE)) { + F_CLR(vp, VM_RCM_MASK); + F_SET(vp, VM_RCM_SET); + + /* Make sure the set cursor position exists. */ + if (vp->m_final.cno >= len) + vp->m_final.cno = len ? len - 1 : 0; + } + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/vi/v_yank.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/vi/v_z.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/vi/v_z.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/vi/v_z.c (revision 366308) @@ -0,0 +1,141 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include + +#include "../common/common.h" +#include "vi.h" + +/* + * v_z -- [count]z[count][-.+^] + * Move the screen. + * + * PUBLIC: int v_z(SCR *, VICMD *); + */ +int +v_z(SCR *sp, VICMD *vp) +{ + recno_t lno; + e_key_t value; + + /* + * The first count is the line to use. If the value doesn't + * exist, use the last line. + */ + if (F_ISSET(vp, VC_C1SET)) { + lno = vp->count; + if (!db_exist(sp, lno) && db_last(sp, &lno)) + return (1); + } else + lno = vp->m_start.lno; + + /* Set default return cursor line. */ + vp->m_final.lno = lno; + vp->m_final.cno = vp->m_start.cno; + + /* + * The second count is the displayed window size, i.e. the 'z' command + * is another way to get artificially small windows. Note, you can't + * grow beyond the size of the window. + * + * !!! + * A window size of 0 was historically allowed, and simply ignored. + * This could be much more simply done by modifying the value of the + * O_WINDOW option, but that's not how it worked historically. + */ + if (F_ISSET(vp, VC_C2SET) && vp->count2 != 0) { + if (vp->count2 > O_VAL(sp, O_WINDOW)) + vp->count2 = O_VAL(sp, O_WINDOW); + if (vs_crel(sp, vp->count2)) + return (1); + } + + switch (vp->character) { + case '-': /* Put the line at the bottom. */ + if (vs_sm_fill(sp, lno, P_BOTTOM)) + return (1); + break; + case '.': /* Put the line in the middle. */ + if (vs_sm_fill(sp, lno, P_MIDDLE)) + return (1); + break; + case '+': + /* + * If the user specified a line number, put that line at the + * top and move the cursor to it. Otherwise, scroll forward + * a screen from the current screen. + */ + if (F_ISSET(vp, VC_C1SET)) { + if (vs_sm_fill(sp, lno, P_TOP)) + return (1); + if (vs_sm_position(sp, &vp->m_final, 0, P_TOP)) + return (1); + } else + if (vs_sm_scroll(sp, &vp->m_final, sp->t_rows, Z_PLUS)) + return (1); + break; + case '^': + /* + * If the user specified a line number, put that line at the + * bottom, move the cursor to it, and then display the screen + * before that one. Otherwise, scroll backward a screen from + * the current screen. + * + * !!! + * Note, we match the off-by-one characteristics of historic + * vi, here. + */ + if (F_ISSET(vp, VC_C1SET)) { + if (vs_sm_fill(sp, lno, P_BOTTOM)) + return (1); + if (vs_sm_position(sp, &vp->m_final, 0, P_TOP)) + return (1); + if (vs_sm_fill(sp, vp->m_final.lno, P_BOTTOM)) + return (1); + } else + if (vs_sm_scroll(sp, &vp->m_final, sp->t_rows, Z_CARAT)) + return (1); + break; + default: /* Put the line at the top for . */ + value = KEY_VAL(sp, vp->character); + if (value != K_CR && value != K_NL) { + v_emsg(sp, vp->kp->usage, VIM_USAGE); + return (1); + } + if (vs_sm_fill(sp, lno, P_TOP)) + return (1); + break; + } + return (0); +} + +/* + * vs_crel -- + * Change the relative size of the current screen. + * + * PUBLIC: int vs_crel(SCR *, long); + */ +int +vs_crel(SCR *sp, long int count) +{ + sp->t_minrows = sp->t_rows = count; + if (sp->t_rows > sp->rows - 1) + sp->t_minrows = sp->t_rows = sp->rows - 1; + TMAP = HMAP + (sp->t_rows - 1); + F_SET(sp, SC_SCR_REDRAW); + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/vi/v_z.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/vi/v_zexit.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/vi/v_zexit.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/vi/v_zexit.c (revision 366308) @@ -0,0 +1,48 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include + +#include "../common/common.h" +#include "vi.h" + +/* + * v_zexit -- ZZ + * Save the file and exit. + * + * PUBLIC: int v_zexit(SCR *, VICMD *); + */ +int +v_zexit(SCR *sp, VICMD *vp) +{ + /* Write back any modifications. */ + if (F_ISSET(sp->ep, F_MODIFIED) && + file_write(sp, NULL, NULL, NULL, FS_ALL)) + return (1); + + /* Check to make sure it's not a temporary file. */ + if (file_m3(sp, 0)) + return (1); + + /* Check for more files to edit. */ + if (ex_ncheck(sp, 0)) + return (1); + + F_SET(sp, SC_EXIT); + return (0); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/vi/v_zexit.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/vi/vi.h =================================================================== --- vendor/nvi/2.2.0-05ed8b9/vi/vi.h (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/vi/vi.h (revision 366308) @@ -0,0 +1,384 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +/* Definition of a vi "word". */ +#define inword(ch) ((ch) == '_' || (ISGRAPH(ch) && !ISPUNCT(ch))) + +typedef struct _vikeys VIKEYS; + +/* Structure passed around to functions implementing vi commands. */ +typedef struct _vicmd { + CHAR_T key; /* Command key. */ + CHAR_T buffer; /* Buffer. */ + CHAR_T character; /* Character. */ + u_long count; /* Count. */ + u_long count2; /* Second count (only used by z). */ + EVENT ev; /* Associated event. */ + +#define ISCMD(p, key) ((p) == &vikeys[key]) + VIKEYS const *kp; /* Command/Motion VIKEYS entry. */ +#define ISMOTION(vp) (vp->rkp != NULL && F_ISSET(vp->rkp, V_MOTION)) + VIKEYS const *rkp; /* Related C/M VIKEYS entry. */ + + /* + * Historic vi allowed "dl" when the cursor was on the last column, + * deleting the last character, and similarly allowed "dw" when + * the cursor was on the last column of the file. It didn't allow + * "dh" when the cursor was on column 1, although these cases are + * not strictly analogous. The point is that some movements would + * succeed if they were associated with a motion command, and fail + * otherwise. This is part of the off-by-1 schizophrenia that + * plagued vi. Other examples are that "dfb" deleted everything + * up to and including the next 'b' character, while "d/b" deleted + * everything up to the next 'b' character. While this implementation + * regularizes the interface to the extent possible, there are many + * special cases that can't be fixed. The special cases are handled + * by setting flags per command so that the underlying command and + * motion routines know what's really going on. + * + * The VM_* flags are set in the vikeys array and by the underlying + * functions (motion component or command) as well. For this reason, + * the flags in the VICMD and VIKEYS structures live in the same name + * space. + */ +#define VM_CMDFAILED 0x00000001 /* Command failed. */ +#define VM_CUTREQ 0x00000002 /* Always cut into numeric buffers. */ +#define VM_LDOUBLE 0x00000004 /* Doubled command for line mode. */ +#define VM_LMODE 0x00000008 /* Motion is line oriented. */ +#define VM_COMMASK 0x0000000f /* Mask for VM flags. */ + + /* + * The VM_RCM_* flags are single usage, i.e. if you set one, you have + * to clear the others. + */ +#define VM_RCM 0x00000010 /* Use relative cursor movment (RCM). */ +#define VM_RCM_SET 0x00000020 /* RCM: set to current position. */ +#define VM_RCM_SETFNB 0x00000040 /* RCM: set to first non-blank (FNB). */ +#define VM_RCM_SETLAST 0x00000080 /* RCM: set to last character. */ +#define VM_RCM_SETNNB 0x00000100 /* RCM: set to next non-blank. */ +#define VM_RCM_MASK 0x000001f0 /* Mask for RCM flags. */ + + /* Flags for the underlying function. */ +#define VC_BUFFER 0x00000200 /* The buffer was set. */ +#define VC_C1RESET 0x00000400 /* Reset C1SET flag for dot commands. */ +#define VC_C1SET 0x00000800 /* Count 1 was set. */ +#define VC_C2SET 0x00001000 /* Count 2 was set. */ +#define VC_ISDOT 0x00002000 /* Command was the dot command. */ + u_int32_t flags; + + /* + * There are four cursor locations that we worry about: the initial + * cursor position, the start of the range, the end of the range, + * and the final cursor position. The initial cursor position and + * the start of the range are both m_start, and are always the same. + * All locations are initialized to the starting cursor position by + * the main vi routines, and the underlying functions depend on this. + * + * Commands that can be motion components set the end of the range + * cursor position, m_stop. All commands must set the ending cursor + * position, m_final. The reason that m_stop isn't the same as m_final + * is that there are situations where the final position of the cursor + * is outside of the cut/delete range (e.g. 'd[[' from the first column + * of a line). The final cursor position often varies based on the + * direction of the movement, as well as the command. The only special + * case that the delete code handles is that it will make adjustments + * if the final cursor position is deleted. + * + * The reason for all of this is that the historic vi semantics were + * defined command-by-command. Every function has to roll its own + * starting and stopping positions, and adjust them if it's being used + * as a motion component. The general rules are as follows: + * + * 1: If not a motion component, the final cursor is at the end + * of the range. + * 2: If moving backward in the file, delete and yank move the + * final cursor to the end of the range. + * 3: If moving forward in the file, delete and yank leave the + * final cursor at the start of the range. + * + * Usually, if moving backward in the file and it's a motion component, + * the starting cursor is decremented by a single character (or, in a + * few cases, to the end of the previous line) so that the starting + * cursor character isn't cut or deleted. No cursor adjustment is + * needed for moving forward, because the cut/delete routines handle + * m_stop inclusively, i.e. the last character in the range is cut or + * deleted. This makes cutting to the EOF/EOL reasonable. + * + * The 'c', '<', '>', and '!' commands are special cases. We ignore + * the final cursor position for all of them: for 'c', the text input + * routines set the cursor to the last character inserted; for '<', + * '>' and '!', the underlying ex commands that do the operation will + * set the cursor for us, usually to something related to the first + * . + */ + MARK m_start; /* mark: initial cursor, range start. */ + MARK m_stop; /* mark: range end. */ + MARK m_final; /* mark: final cursor position. */ +} VICMD; + +/* Vi command table structure. */ +struct _vikeys { /* Underlying function. */ + int (*func)(SCR *, VICMD *); +#define V_ABS 0x00004000 /* Absolute movement, set '' mark. */ +#define V_ABS_C 0x00008000 /* V_ABS: if the line/column changed. */ +#define V_ABS_L 0x00010000 /* V_ABS: if the line changed. */ +#define V_CHAR 0x00020000 /* Character (required, trailing). */ +#define V_CNT 0x00040000 /* Count (optional, leading). */ +#define V_DOT 0x00080000 /* On success, sets dot command. */ +#define V_KEYW 0x00100000 /* Cursor referenced word. */ +#define V_MOTION 0x00200000 /* Motion (required, trailing). */ +#define V_MOVE 0x00400000 /* Command defines movement. */ +#define V_OBUF 0x00800000 /* Buffer (optional, leading). */ +#define V_RBUF 0x01000000 /* Buffer (required, trailing). */ +#define V_SECURE 0x02000000 /* Permission denied if O_SECURE set. */ + u_int32_t flags; + char *usage; /* Usage line. */ + char *help; /* Help line. */ +}; +#define MAXVIKEY 126 /* List of vi commands. */ +extern VIKEYS const vikeys[MAXVIKEY + 1]; +extern VIKEYS const tmotion; /* XXX Hacked ~ command. */ + +/* Character stream structure, prototypes. */ +typedef struct _vcs { + recno_t cs_lno; /* Line. */ + size_t cs_cno; /* Column. */ + CHAR_T *cs_bp; /* Buffer. */ + size_t cs_len; /* Length. */ + CHAR_T cs_ch; /* Character. */ +#define CS_EMP 1 /* Empty line. */ +#define CS_EOF 2 /* End-of-file. */ +#define CS_EOL 3 /* End-of-line. */ +#define CS_SOF 4 /* Start-of-file. */ + int cs_flags; /* Return flags. */ +} VCS; + +int cs_bblank(SCR *, VCS *); +int cs_fblank(SCR *, VCS *); +int cs_fspace(SCR *, VCS *); +int cs_init(SCR *, VCS *); +int cs_next(SCR *, VCS *); +int cs_prev(SCR *, VCS *); + +/* + * We use a single "window" for each set of vi screens. The model would be + * simpler with two windows (one for the text, and one for the modeline) + * because scrolling the text window down would work correctly then, not + * affecting the mode line. As it is we have to play games to make it look + * right. The reason for this choice is that it would be difficult for + * curses to optimize the movement, i.e. detect that the downward scroll + * isn't going to change the modeline, set the scrolling region on the + * terminal and only scroll the first part of the text window. + * + * Structure for mapping lines to the screen. An SMAP is an array, with one + * structure element per screen line, which holds information describing the + * physical line which is displayed in the screen line. The first two fields + * (lno and off) are all that are necessary to describe a line. The rest of + * the information is useful to keep information from being re-calculated. + * + * The SMAP always has an entry for each line of the physical screen, plus a + * slot for the colon command line, so there is room to add any screen into + * another one at screen exit. + * + * Lno is the line number. If doing the historic vi long line folding, soff + * is the screen offset into the line. For example, the pair 2:1 would be + * the first screen of line 2, and 2:2 would be the second. In the case of + * long lines, the screen map will tend to be staggered, e.g., 1:1, 1:2, 1:3, + * 2:1, 3:1, etc. If doing left-right scrolling, the coff field is the screen + * column offset into the lines, and can take on any value, as it's adjusted + * by the user set value O_SIDESCROLL. + */ +typedef struct _smap { + recno_t lno; /* 1-N: Physical file line number. */ + size_t coff; /* 0-N: Column offset in the line. */ + size_t soff; /* 1-N: Screen offset in the line. */ + + /* vs_line() cache information. */ + size_t c_sboff; /* 0-N: offset of first character on screen. */ + size_t c_eboff; /* 0-N: offset of last character on screen. */ + u_int8_t c_scoff; /* 0-N: offset into the first character. */ + /* 255: no character of line visible. */ + u_int8_t c_eclen; /* 1-N: columns from the last character. */ + u_int8_t c_ecsize; /* 1-N: size of the last character. */ +} SMAP; + /* Macros to flush/test cached information. */ +#define SMAP_CACHE(smp) ((smp)->c_ecsize != 0) +#define SMAP_FLUSH(smp) ((smp)->c_ecsize = 0) + + /* Character search information. */ +typedef enum { CNOTSET, FSEARCH, fSEARCH, TSEARCH, tSEARCH } cdir_t; + +typedef enum { AB_NOTSET, AB_NOTWORD, AB_INWORD } abb_t; +typedef enum { Q_NOTSET, Q_VNEXT, Q_VTHIS } quote_t; + +/* Vi private, per-screen memory. */ +typedef struct _vi_private { + VICMD cmd; /* Current command, motion. */ + VICMD motion; + + /* + * !!! + * The saved command structure can be modified by the underlying + * vi functions, see v_Put() and v_put(). + */ + VICMD sdot; /* Saved dot, motion command. */ + VICMD sdotmotion; + + CHAR_T *keyw; /* Keyword buffer. */ + size_t klen; /* Keyword length. */ + size_t keywlen; /* Keyword buffer length. */ + + CHAR_T rlast; /* Last 'r' replacement character. */ + e_key_t rvalue; /* Value of last replacement character. */ + + EVENT *rep; /* Input replay buffer. */ + size_t rep_len; /* Input replay buffer length. */ + size_t rep_cnt; /* Input replay buffer characters. */ + + mtype_t mtype; /* Last displayed message type. */ + size_t linecount; /* 1-N: Output overwrite count. */ + size_t lcontinue; /* 1-N: Output line continue value. */ + size_t totalcount; /* 1-N: Output overwrite count. */ + + /* Busy state. */ + int busy_ref; /* Busy reference count. */ + int busy_ch; /* Busy character. */ + size_t busy_fx; /* Busy character x coordinate. */ + size_t busy_oldy; /* Saved y coordinate. */ + size_t busy_oldx; /* Saved x coordinate. */ + struct timespec busy_ts;/* Busy timer. */ + + MARK sel; /* Select start position. */ + + CHAR_T *mcs; /* Match character list. */ + char *ps; /* Paragraph plus section list. */ + + u_long u_ccnt; /* Undo command count. */ + + CHAR_T lastckey; /* Last search character. */ + cdir_t csearchdir; /* Character search direction. */ + + SMAP *h_smap; /* First slot of the line map. */ + SMAP *t_smap; /* Last slot of the line map. */ + + /* + * One extra slot is always allocated for the map so that we can use + * it to do vi :colon command input; see v_tcmd(). + */ + recno_t sv_tm_lno; /* tcmd: saved TMAP lno field. */ + size_t sv_tm_coff; /* tcmd: saved TMAP coff field. */ + size_t sv_tm_soff; /* tcmd: saved TMAP soff field. */ + size_t sv_t_maxrows; /* tcmd: saved t_maxrows. */ + size_t sv_t_minrows; /* tcmd: saved t_minrows. */ + size_t sv_t_rows; /* tcmd: saved t_rows. */ +#define SIZE_HMAP(sp) (VIP(sp)->srows + 1) + + /* + * Macros to get to the head/tail of the smap. If the screen only has + * one line, HMAP can be equal to TMAP, so the code has to understand + * the off-by-one errors that can result. If stepping through an SMAP + * and operating on each entry, use sp->t_rows as the count of slots, + * don't use a loop that compares <= TMAP. + */ +#define _HMAP(sp) (VIP(sp)->h_smap) +#define HMAP _HMAP(sp) +#define _TMAP(sp) (VIP(sp)->t_smap) +#define TMAP _TMAP(sp) + + recno_t ss_lno; /* 1-N: vi_opt_screens cached line number. */ + size_t ss_screens; /* vi_opt_screens cached return value. */ +#define VI_SCR_CFLUSH(vip) vip->ss_lno = OOBLNO + + size_t srows; /* 1-N: rows in the terminal/window. */ + recno_t olno; /* 1-N: old cursor file line. */ + size_t ocno; /* 0-N: old file cursor column. */ + size_t sc_col; /* 0-N: LOGICAL screen column. */ + SMAP *sc_smap; /* SMAP entry where sc_col occurs. */ + +#define VIP_CUR_INVALID 0x0001 /* Cursor position is unknown. */ +#define VIP_DIVIDER 0x0002 /* Divider line was displayed. */ +#define VIP_N_EX_PAINT 0x0004 /* Clear and repaint when ex finishes. */ +#define VIP_N_EX_REDRAW 0x0008 /* Schedule SC_SCR_REDRAW when ex finishes. */ +#define VIP_N_REFRESH 0x0010 /* Repaint (from SMAP) on the next refresh. */ +#define VIP_N_RENUMBER 0x0020 /* Renumber screen on the next refresh. */ +#define VIP_RCM_LAST 0x0040 /* Cursor drawn to the last column. */ +#define VIP_S_MODELINE 0x0080 /* Skip next modeline refresh. */ +#define VIP_S_REFRESH 0x0100 /* Skip next refresh. */ + u_int16_t flags; +} VI_PRIVATE; + +/* Vi private area. */ +#define VIP(sp) ((VI_PRIVATE *)((sp)->vi_private)) + +#define O_NUMBER_FMT "%7lu " /* O_NUMBER format, length. */ +#define O_NUMBER_LENGTH 8 +#define SCREEN_COLS(sp) /* Screen columns. */ \ + ((O_ISSET(sp, O_NUMBER) ? (sp)->cols - O_NUMBER_LENGTH : (sp)->cols)) + +/* + * LASTLINE is the zero-based, last line in the screen. Note that it is correct + * regardless of the changes in the screen to permit text input on the last line + * of the screen, or the existence of small screens. + */ +#define LASTLINE(sp) \ + ((sp)->t_maxrows < (sp)->rows ? (sp)->t_maxrows : (sp)->rows - 1) + +/* + * Small screen (see vs_refresh.c, section 6a) and one-line screen test. + * Note, both cannot be true for the same screen. + */ +#define IS_SMALL(sp) ((sp)->t_minrows != (sp)->t_maxrows) +#define IS_ONELINE(sp) ((sp)->rows == 1) + +#define HALFTEXT(sp) /* Half text. */ \ + ((sp)->t_rows == 1 ? 1 : (sp)->t_rows / 2) +#define HALFSCREEN(sp) /* Half text screen. */ \ + ((sp)->t_maxrows == 1 ? 1 : (sp)->t_maxrows / 2) + +/* + * Next tab offset. + * + * !!! + * There are problems with how the historical vi handled tabs. For example, + * by doing "set ts=3" and building lines that fold, you can get it to step + * through tabs as if they were spaces and move inserted characters to new + * positions when is entered. I believe that nvi does tabs correctly, + * but there are some historical incompatibilities. + */ +#define TAB_OFF(c) COL_OFF((c), O_VAL(sp, O_TABSTOP)) + +/* If more than one horizontal screen being shown. */ +#define IS_HSPLIT(sp) \ + ((sp)->rows != O_VAL(sp, O_LINES)) +/* If more than one vertical screen being shown. */ +#define IS_VSPLIT(sp) \ + ((sp)->cols != O_VAL(sp, O_COLUMNS)) +/* If more than one screen being shown. */ +#define IS_SPLIT(sp) \ + (IS_HSPLIT(sp) || IS_VSPLIT(sp)) + +/* Screen adjustment operations. */ +typedef enum { A_DECREASE, A_INCREASE, A_SET } adj_t; + +/* Screen position operations. */ +typedef enum { P_BOTTOM, P_FILL, P_MIDDLE, P_TOP } pos_t; + +/* Scrolling operations. */ +typedef enum { + CNTRL_B, CNTRL_D, CNTRL_E, CNTRL_F, + CNTRL_U, CNTRL_Y, Z_CARAT, Z_PLUS +} scroll_t; + +/* Vi common error messages. */ +typedef enum { + VIM_COMBUF, VIM_EMPTY, VIM_EOF, VIM_EOL, + VIM_NOCOM, VIM_NOCOM_B, VIM_USAGE, VIM_WRESIZE +} vim_t; + +#include "extern.h" Property changes on: vendor/nvi/2.2.0-05ed8b9/vi/vi.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/vi/vs_split.c =================================================================== --- vendor/nvi/2.2.0-05ed8b9/vi/vs_split.c (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/vi/vs_split.c (revision 366308) @@ -0,0 +1,945 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "../common/common.h" +#include "vi.h" + +typedef enum { HORIZ_FOLLOW, HORIZ_PRECEDE, VERT_FOLLOW, VERT_PRECEDE } jdir_t; + +static SCR *vs_getbg(SCR *, char *); +static void vs_insert(SCR *sp, GS *gp); +static int vs_join(SCR *, SCR **, jdir_t *); + +/* + * vs_split -- + * Create a new screen, horizontally. + * + * PUBLIC: int vs_split(SCR *, SCR *, int); + */ +int +vs_split( + SCR *sp, + SCR *new, + int ccl) /* Colon-command line split. */ +{ + GS *gp; + SMAP *smp; + size_t half; + int issmallscreen, splitup; + + gp = sp->gp; + + /* Check to see if it's possible. */ + /* XXX: The IS_ONELINE fix will change this, too. */ + if (sp->rows < 4) { + msgq(sp, M_ERR, + "222|Screen must be larger than %d lines to split", 4 - 1); + return (1); + } + + /* Wait for any messages in the screen. */ + vs_resolve(sp, NULL, 1); + + /* Get a new screen map. */ + CALLOC(sp, _HMAP(new), SIZE_HMAP(sp), sizeof(SMAP)); + if (_HMAP(new) == NULL) + return (1); + _HMAP(new)->lno = sp->lno; + _HMAP(new)->coff = 0; + _HMAP(new)->soff = 1; + + /* Split the screen in half. */ + half = sp->rows / 2; + if (ccl && half > 6) + half = 6; + + /* + * Small screens: see vs_refresh.c section 6a. Set a flag so + * we know to fix the screen up later. + */ + issmallscreen = IS_SMALL(sp); + + /* The columns in the screen don't change. */ + new->coff = sp->coff; + new->cols = sp->cols; + + /* + * Split the screen, and link the screens together. If creating a + * screen to edit the colon command line or the cursor is in the top + * half of the current screen, the new screen goes under the current + * screen. Else, it goes above the current screen. + * + * Recalculate current cursor position based on sp->lno, we're called + * with the cursor on the colon command line. Then split the screen + * in half and update the shared information. + */ + splitup = + !ccl && (vs_sm_cursor(sp, &smp) ? 0 : (smp - HMAP) + 1) >= half; + if (splitup) { /* Old is bottom half. */ + new->rows = sp->rows - half; /* New. */ + new->roff = sp->roff; + sp->rows = half; /* Old. */ + sp->roff += new->rows; + + /* + * If the parent is the bottom half of the screen, shift + * the map down to match on-screen text. + */ + memcpy(_HMAP(sp), _HMAP(sp) + new->rows, + (sp->t_maxrows - new->rows) * sizeof(SMAP)); + } else { /* Old is top half. */ + new->rows = half; /* New. */ + sp->rows -= half; /* Old. */ + new->roff = sp->roff + sp->rows; + } + + /* Adjust maximum text count. */ + sp->t_maxrows = IS_ONELINE(sp) ? 1 : sp->rows - 1; + new->t_maxrows = IS_ONELINE(new) ? 1 : new->rows - 1; + + /* + * Small screens: see vs_refresh.c, section 6a. + * + * The child may have different screen options sizes than the parent, + * so use them. Guarantee that text counts aren't larger than the + * new screen sizes. + */ + if (issmallscreen) { + /* Fix the text line count for the parent. */ + if (splitup) + sp->t_rows -= new->rows; + + /* Fix the parent screen. */ + if (sp->t_rows > sp->t_maxrows) + sp->t_rows = sp->t_maxrows; + if (sp->t_minrows > sp->t_maxrows) + sp->t_minrows = sp->t_maxrows; + + /* Fix the child screen. */ + new->t_minrows = new->t_rows = O_VAL(sp, O_WINDOW); + if (new->t_rows > new->t_maxrows) + new->t_rows = new->t_maxrows; + if (new->t_minrows > new->t_maxrows) + new->t_minrows = new->t_maxrows; + } else { + sp->t_minrows = sp->t_rows = IS_ONELINE(sp) ? 1 : sp->rows - 1; + + /* + * The new screen may be a small screen, even if the parent + * was not. Don't complain if O_WINDOW is too large, we're + * splitting the screen so the screen is much smaller than + * normal. + */ + new->t_minrows = new->t_rows = O_VAL(sp, O_WINDOW); + if (new->t_rows > new->rows - 1) + new->t_minrows = new->t_rows = + IS_ONELINE(new) ? 1 : new->rows - 1; + } + + /* Adjust the ends of the new and old maps. */ + _TMAP(sp) = IS_ONELINE(sp) ? + _HMAP(sp) : _HMAP(sp) + (sp->t_rows - 1); + _TMAP(new) = IS_ONELINE(new) ? + _HMAP(new) : _HMAP(new) + (new->t_rows - 1); + + /* Reset the length of the default scroll. */ + if ((sp->defscroll = sp->t_maxrows / 2) == 0) + sp->defscroll = 1; + if ((new->defscroll = new->t_maxrows / 2) == 0) + new->defscroll = 1; + + /* Fit the screen into the logical chain. */ + vs_insert(new, sp->gp); + + /* Tell the display that we're splitting. */ + (void)gp->scr_split(sp, new); + + /* + * Initialize the screen flags: + * + * If we're in vi mode in one screen, we don't have to reinitialize. + * This isn't just a cosmetic fix. The path goes like this: + * + * return into vi(), SC_SSWITCH set + * call vs_refresh() with SC_STATUS set + * call vs_resolve to display the status message + * call vs_refresh() because the SC_SCR_VI bit isn't set + * + * Things go downhill at this point. + * + * Draw the new screen from scratch, and add a status line. + */ + F_SET(new, + SC_SCR_REFORMAT | SC_STATUS | + F_ISSET(sp, SC_EX | SC_VI | SC_SCR_VI | SC_SCR_EX | SC_READONLY)); + return (0); +} + +/* + * vs_vsplit -- + * Create a new screen, vertically. + * + * PUBLIC: int vs_vsplit(SCR *, SCR *); + */ +int +vs_vsplit(SCR *sp, SCR *new) +{ + GS *gp; + size_t cols; + + gp = sp->gp; + + /* Check to see if it's possible. */ + if (sp->cols / 2 <= MINIMUM_SCREEN_COLS) { + msgq(sp, M_ERR, + "288|Screen must be larger than %d columns to split", + MINIMUM_SCREEN_COLS * 2); + return (1); + } + + /* Wait for any messages in the screen. */ + vs_resolve(sp, NULL, 1); + + /* Get a new screen map. */ + CALLOC(sp, _HMAP(new), SIZE_HMAP(sp), sizeof(SMAP)); + if (_HMAP(new) == NULL) + return (1); + _HMAP(new)->lno = sp->lno; + _HMAP(new)->coff = 0; + _HMAP(new)->soff = 1; + + /* + * Split the screen in half; we have to sacrifice a column to delimit + * the screens. + * + * XXX + * We always split to the right... that makes more sense to me, and + * I don't want to play the stupid games that I play when splitting + * horizontally. + * + * XXX + * We reserve a column for the screen, "knowing" that curses needs + * one. This should be worked out with the display interface. + */ + cols = sp->cols / 2; + new->cols = sp->cols - cols - 1; + sp->cols = cols; + new->coff = sp->coff + cols + 1; + sp->cno = 0; + + /* Nothing else changes. */ + new->rows = sp->rows; + new->t_rows = sp->t_rows; + new->t_maxrows = sp->t_maxrows; + new->t_minrows = sp->t_minrows; + new->roff = sp->roff; + new->defscroll = sp->defscroll; + _TMAP(new) = _HMAP(new) + (new->t_rows - 1); + + /* Fit the screen into the logical chain. */ + vs_insert(new, sp->gp); + + /* Tell the display that we're splitting. */ + (void)gp->scr_split(sp, new); + + /* Redraw the old screen from scratch. */ + F_SET(sp, SC_SCR_REFORMAT | SC_STATUS); + + /* + * Initialize the screen flags: + * + * If we're in vi mode in one screen, we don't have to reinitialize. + * This isn't just a cosmetic fix. The path goes like this: + * + * return into vi(), SC_SSWITCH set + * call vs_refresh() with SC_STATUS set + * call vs_resolve to display the status message + * call vs_refresh() because the SC_SCR_VI bit isn't set + * + * Things go downhill at this point. + * + * Draw the new screen from scratch, and add a status line. + */ + F_SET(new, + SC_SCR_REFORMAT | SC_STATUS | + F_ISSET(sp, SC_EX | SC_VI | SC_SCR_VI | SC_SCR_EX | SC_READONLY)); + return (0); +} + +/* + * vs_insert -- + * Insert the new screen into the correct place in the logical + * chain. + */ +static void +vs_insert(SCR *sp, GS *gp) +{ + SCR *tsp; + + gp = sp->gp; + + /* Move past all screens with lower row numbers. */ + TAILQ_FOREACH(tsp, gp->dq, q) + if (tsp->roff >= sp->roff) + break; + /* + * Move past all screens with the same row number and lower + * column numbers. + */ + for (; tsp != NULL; tsp = TAILQ_NEXT(tsp, q)) + if (tsp->roff != sp->roff || tsp->coff > sp->coff) + break; + + /* + * If we reached the end, this screen goes there. Otherwise, + * put it before or after the screen where we stopped. + */ + if (tsp == NULL) { + TAILQ_INSERT_TAIL(gp->dq, sp, q); + } else if (tsp->roff < sp->roff || + (tsp->roff == sp->roff && tsp->coff < sp->coff)) { + TAILQ_INSERT_AFTER(gp->dq, tsp, sp, q); + } else + TAILQ_INSERT_BEFORE(tsp, sp, q); +} + +/* + * vs_discard -- + * Discard the screen, folding the real-estate into a related screen, + * if one exists, and return that screen. + * + * PUBLIC: int vs_discard(SCR *, SCR **); + */ +int +vs_discard(SCR *sp, SCR **spp) +{ + GS *gp; + SCR *tsp, **lp, *list[100]; + jdir_t jdir; + + gp = sp->gp; + + /* + * Save the old screen's cursor information. + * + * XXX + * If called after file_end(), and the underlying file was a tmp + * file, it may have gone away. + */ + if (sp->frp != NULL) { + sp->frp->lno = sp->lno; + sp->frp->cno = sp->cno; + F_SET(sp->frp, FR_CURSORSET); + } + + /* If no other screens to join, we're done. */ + if (!IS_SPLIT(sp)) { + (void)gp->scr_discard(sp, NULL); + + if (spp != NULL) + *spp = NULL; + return (0); + } + + /* + * Find a set of screens that cover one of the screen's borders. + * Check the vertical axis first, for no particular reason. + * + * XXX + * It's possible (I think?), to create a screen that shares no full + * border with any other set of screens, so we can't discard it. We + * just complain at the user until they clean it up. + */ + if (vs_join(sp, list, &jdir)) + return (1); + + /* + * Modify the affected screens. Redraw the modified screen(s) from + * scratch, setting a status line. If this is ever a performance + * problem we could play games with the map, but I wrote that code + * before and it was never clean or easy. + * + * Don't clean up the discarded screen's information. If the screen + * isn't exiting, we'll do the work when the user redisplays it. + */ + switch (jdir) { + case HORIZ_FOLLOW: + case HORIZ_PRECEDE: + for (lp = &list[0]; (tsp = *lp) != NULL; ++lp) { + /* + * Small screens: see vs_refresh.c section 6a. Adjust + * text line info, unless it's a small screen. + * + * Reset the length of the default scroll. + * + * Reset the map references. + */ + tsp->rows += sp->rows; + if (!IS_SMALL(tsp)) + tsp->t_rows = tsp->t_minrows = tsp->rows - 1; + tsp->t_maxrows = tsp->rows - 1; + + tsp->defscroll = tsp->t_maxrows / 2; + + *(_HMAP(tsp) + (tsp->t_rows - 1)) = *_TMAP(tsp); + _TMAP(tsp) = _HMAP(tsp) + (tsp->t_rows - 1); + + switch (jdir) { + case HORIZ_FOLLOW: + tsp->roff = sp->roff; + vs_sm_fill(tsp, OOBLNO, P_TOP); + break; + case HORIZ_PRECEDE: + vs_sm_fill(tsp, OOBLNO, P_BOTTOM); + break; + default: + abort(); + } + F_SET(tsp, SC_STATUS); + } + break; + case VERT_FOLLOW: + case VERT_PRECEDE: + for (lp = &list[0]; (tsp = *lp) != NULL; ++lp) { + if (jdir == VERT_FOLLOW) + tsp->coff = sp->coff; + tsp->cols += sp->cols + 1; /* XXX: DIVIDER */ + vs_sm_fill(tsp, OOBLNO, P_TOP); + F_SET(tsp, SC_STATUS); + } + break; + default: + abort(); + } + + /* Find the closest screen that changed and move to it. */ + tsp = list[0]; + if (spp != NULL) + *spp = tsp; + + /* Tell the display that we're discarding a screen. */ + (void)gp->scr_discard(sp, list); + + return (0); +} + +/* + * vs_join -- + * Find a set of screens that covers a screen's border. + */ +static int +vs_join(SCR *sp, SCR **listp, jdir_t *jdirp) +{ + GS *gp; + SCR **lp, *tsp; + int first; + size_t tlen; + + gp = sp->gp; + + /* Check preceding vertical. */ + for (lp = listp, tlen = sp->rows, + tsp = TAILQ_FIRST(gp->dq); + tsp != NULL; tsp = TAILQ_NEXT(tsp, q)) { + if (sp == tsp) + continue; + /* Test if precedes the screen vertically. */ + if (tsp->coff + tsp->cols + 1 != sp->coff) + continue; + /* + * Test if a subset on the vertical axis. If overlaps the + * beginning or end, we can't join on this axis at all. + */ + if (tsp->roff > sp->roff + sp->rows) + continue; + if (tsp->roff < sp->roff) { + if (tsp->roff + tsp->rows >= sp->roff) + break; + continue; + } + if (tsp->roff + tsp->rows > sp->roff + sp->rows) + break; +#ifdef DEBUG + if (tlen < tsp->rows) + abort(); +#endif + tlen -= tsp->rows; + *lp++ = tsp; + } + if (tlen == 0) { + *lp = NULL; + *jdirp = VERT_PRECEDE; + return (0); + } + + /* Check following vertical. */ + for (lp = listp, tlen = sp->rows, + tsp = TAILQ_FIRST(gp->dq); + tsp != NULL; tsp = TAILQ_NEXT(tsp, q)) { + if (sp == tsp) + continue; + /* Test if follows the screen vertically. */ + if (tsp->coff != sp->coff + sp->cols + 1) + continue; + /* + * Test if a subset on the vertical axis. If overlaps the + * beginning or end, we can't join on this axis at all. + */ + if (tsp->roff > sp->roff + sp->rows) + continue; + if (tsp->roff < sp->roff) { + if (tsp->roff + tsp->rows >= sp->roff) + break; + continue; + } + if (tsp->roff + tsp->rows > sp->roff + sp->rows) + break; +#ifdef DEBUG + if (tlen < tsp->rows) + abort(); +#endif + tlen -= tsp->rows; + *lp++ = tsp; + } + if (tlen == 0) { + *lp = NULL; + *jdirp = VERT_FOLLOW; + return (0); + } + + /* Check preceding horizontal. */ + for (first = 0, lp = listp, tlen = sp->cols, + tsp = TAILQ_FIRST(gp->dq); + tsp != NULL; tsp = TAILQ_NEXT(tsp, q)) { + if (sp == tsp) + continue; + /* Test if precedes the screen horizontally. */ + if (tsp->roff + tsp->rows != sp->roff) + continue; + /* + * Test if a subset on the horizontal axis. If overlaps the + * beginning or end, we can't join on this axis at all. + */ + if (tsp->coff > sp->coff + sp->cols) + continue; + if (tsp->coff < sp->coff) { + if (tsp->coff + tsp->cols >= sp->coff) + break; + continue; + } + if (tsp->coff + tsp->cols > sp->coff + sp->cols) + break; +#ifdef DEBUG + if (tlen < tsp->cols) + abort(); +#endif + tlen -= tsp->cols + first; + first = 1; + *lp++ = tsp; + } + if (tlen == 0) { + *lp = NULL; + *jdirp = HORIZ_PRECEDE; + return (0); + } + + /* Check following horizontal. */ + for (first = 0, lp = listp, tlen = sp->cols, + tsp = TAILQ_FIRST(gp->dq); + tsp != NULL; tsp = TAILQ_NEXT(tsp, q)) { + if (sp == tsp) + continue; + /* Test if precedes the screen horizontally. */ + if (tsp->roff != sp->roff + sp->rows) + continue; + /* + * Test if a subset on the horizontal axis. If overlaps the + * beginning or end, we can't join on this axis at all. + */ + if (tsp->coff > sp->coff + sp->cols) + continue; + if (tsp->coff < sp->coff) { + if (tsp->coff + tsp->cols >= sp->coff) + break; + continue; + } + if (tsp->coff + tsp->cols > sp->coff + sp->cols) + break; +#ifdef DEBUG + if (tlen < tsp->cols) + abort(); +#endif + tlen -= tsp->cols + first; + first = 1; + *lp++ = tsp; + } + if (tlen == 0) { + *lp = NULL; + *jdirp = HORIZ_FOLLOW; + return (0); + } + return (1); +} + +/* + * vs_fg -- + * Background the current screen, and foreground a new one. + * + * PUBLIC: int vs_fg(SCR *, SCR **, CHAR_T *, int); + */ +int +vs_fg(SCR *sp, SCR **nspp, CHAR_T *name, int newscreen) +{ + GS *gp; + SCR *nsp; + char *np; + size_t nlen; + + gp = sp->gp; + + if (name) + INT2CHAR(sp, name, STRLEN(name) + 1, np, nlen); + else + np = NULL; + if (newscreen) + /* Get the specified background screen. */ + nsp = vs_getbg(sp, np); + else + /* Swap screens. */ + if (vs_swap(sp, &nsp, np)) + return (1); + + if ((*nspp = nsp) == NULL) { + msgq_wstr(sp, M_ERR, name, + name == NULL ? + "223|There are no background screens" : + "224|There's no background screen editing a file named %s"); + return (1); + } + + if (newscreen) { + /* Remove the new screen from the background queue. */ + TAILQ_REMOVE(gp->hq, nsp, q); + + /* Split the screen; if we fail, hook the screen back in. */ + if (vs_split(sp, nsp, 0)) { + TAILQ_INSERT_TAIL(gp->hq, nsp, q); + return (1); + } + } else { + /* Move the old screen to the background queue. */ + TAILQ_REMOVE(gp->dq, sp, q); + TAILQ_INSERT_TAIL(gp->hq, sp, q); + } + return (0); +} + +/* + * vs_bg -- + * Background the screen, and switch to the next one. + * + * PUBLIC: int vs_bg(SCR *); + */ +int +vs_bg(SCR *sp) +{ + GS *gp; + SCR *nsp; + + gp = sp->gp; + + /* Try and join with another screen. */ + if (vs_discard(sp, &nsp)) + return (1); + if (nsp == NULL) { + msgq(sp, M_ERR, + "225|You may not background your only displayed screen"); + return (1); + } + + /* Move the old screen to the background queue. */ + TAILQ_REMOVE(gp->dq, sp, q); + TAILQ_INSERT_TAIL(gp->hq, sp, q); + + /* Toss the screen map. */ + free(_HMAP(sp)); + _HMAP(sp) = NULL; + + /* Switch screens. */ + sp->nextdisp = nsp; + F_SET(sp, SC_SSWITCH); + + return (0); +} + +/* + * vs_swap -- + * Swap the current screen with a backgrounded one. + * + * PUBLIC: int vs_swap(SCR *, SCR **, char *); + */ +int +vs_swap(SCR *sp, SCR **nspp, char *name) +{ + GS *gp; + SCR *nsp, *list[2]; + + gp = sp->gp; + + /* Get the specified background screen. */ + if ((*nspp = nsp = vs_getbg(sp, name)) == NULL) + return (0); + + /* + * Save the old screen's cursor information. + * + * XXX + * If called after file_end(), and the underlying file was a tmp + * file, it may have gone away. + */ + if (sp->frp != NULL) { + sp->frp->lno = sp->lno; + sp->frp->cno = sp->cno; + F_SET(sp->frp, FR_CURSORSET); + } + + /* Switch screens. */ + sp->nextdisp = nsp; + F_SET(sp, SC_SSWITCH); + + /* Initialize terminal information. */ + VIP(nsp)->srows = VIP(sp)->srows; + + /* Initialize screen information. */ + nsp->cols = sp->cols; + nsp->rows = sp->rows; /* XXX: Only place in vi that sets rows. */ + nsp->roff = sp->roff; + + /* + * Small screens: see vs_refresh.c, section 6a. + * + * The new screens may have different screen options sizes than the + * old one, so use them. Make sure that text counts aren't larger + * than the new screen sizes. + */ + if (IS_SMALL(nsp)) { + nsp->t_minrows = nsp->t_rows = O_VAL(nsp, O_WINDOW); + if (nsp->t_rows > sp->t_maxrows) + nsp->t_rows = nsp->t_maxrows; + if (nsp->t_minrows > sp->t_maxrows) + nsp->t_minrows = nsp->t_maxrows; + } else + nsp->t_rows = nsp->t_maxrows = nsp->t_minrows = nsp->rows - 1; + + /* Reset the length of the default scroll. */ + nsp->defscroll = nsp->t_maxrows / 2; + + /* Allocate a new screen map. */ + CALLOC_RET(nsp, _HMAP(nsp), SIZE_HMAP(nsp), sizeof(SMAP)); + _TMAP(nsp) = _HMAP(nsp) + (nsp->t_rows - 1); + + /* Fill the map. */ + nsp->gp = sp->gp; + if (vs_sm_fill(nsp, nsp->lno, P_FILL)) + return (1); + + /* + * The new screen replaces the old screen in the parent/child list. + * We insert the new screen after the old one. If we're exiting, + * the exit will delete the old one, if we're foregrounding, the fg + * code will move the old one to the background queue. + */ + TAILQ_REMOVE(gp->hq, nsp, q); + TAILQ_INSERT_AFTER(gp->dq, sp, nsp, q); + + /* + * Don't change the screen's cursor information other than to + * note that the cursor is wrong. + */ + F_SET(VIP(nsp), VIP_CUR_INVALID); + + /* Draw the new screen from scratch, and add a status line. */ + F_SET(nsp, SC_SCR_REDRAW | SC_STATUS); + + list[0] = nsp; list[1] = NULL; + (void)gp->scr_discard(sp, list); + + return (0); +} + +/* + * vs_resize -- + * Change the absolute size of the current screen. + * + * PUBLIC: int vs_resize(SCR *, long, adj_t); + */ +int +vs_resize(SCR *sp, long int count, adj_t adj) +{ + GS *gp; + SCR *g, *s, *prev, *next, *list[3] = {NULL, NULL, NULL}; + size_t g_off, s_off; + + gp = sp->gp; + + /* + * Figure out which screens will grow, which will shrink, and + * make sure it's possible. + */ + if (count == 0) + return (0); + if (adj == A_SET) { + if (sp->t_maxrows == count) + return (0); + if (sp->t_maxrows > count) { + adj = A_DECREASE; + count = sp->t_maxrows - count; + } else { + adj = A_INCREASE; + count = count - sp->t_maxrows; + } + } + + /* Find first overlapping screen */ + for (next = TAILQ_NEXT(sp, q); next != NULL && + (next->coff >= sp->coff + sp->cols || + next->coff + next->cols <= sp->coff); + next = TAILQ_NEXT(next, q)); + /* See if we can use it */ + if (next != NULL && + (sp->coff != next->coff || sp->cols != next->cols)) + next = NULL; + for (prev = TAILQ_PREV(sp, _dqh, q); prev != NULL && + (prev->coff >= sp->coff + sp->cols || + prev->coff + prev->cols <= sp->coff); + prev = TAILQ_PREV(prev, _dqh, q)); + if (prev != NULL && + (sp->coff != prev->coff || sp->cols != prev->cols)) + prev = NULL; + + g_off = s_off = 0; + if (adj == A_DECREASE) { + if (count < 0) + count = -count; + s = sp; + if (s->t_maxrows < MINIMUM_SCREEN_ROWS + count) + goto toosmall; + if ((g = prev) == NULL) { + if ((g = next) == NULL) + goto toobig; + g_off = -count; + } else + s_off = count; + } else { + g = sp; + if ((s = next) != NULL && + s->t_maxrows >= MINIMUM_SCREEN_ROWS + count) + s_off = count; + else + s = NULL; + if (s == NULL) { + if ((s = prev) == NULL) { +toobig: msgq(sp, M_BERR, adj == A_DECREASE ? + "227|The screen cannot shrink" : + "228|The screen cannot grow"); + return (1); + } + if (s->t_maxrows < MINIMUM_SCREEN_ROWS + count) { +toosmall: msgq(sp, M_BERR, + "226|The screen can only shrink to %d rows", + MINIMUM_SCREEN_ROWS); + return (1); + } + g_off = -count; + } + } + + /* + * Fix up the screens; we could optimize the reformatting of the + * screen, but this isn't likely to be a common enough operation + * to make it worthwhile. + */ + s->rows += -count; + s->roff += s_off; + g->rows += count; + g->roff += g_off; + + g->t_rows += count; + if (g->t_minrows == g->t_maxrows) + g->t_minrows += count; + g->t_maxrows += count; + _TMAP(g) += count; + F_SET(g, SC_SCR_REFORMAT | SC_STATUS); + + s->t_rows -= count; + s->t_maxrows -= count; + if (s->t_minrows > s->t_maxrows) + s->t_minrows = s->t_maxrows; + _TMAP(s) -= count; + F_SET(s, SC_SCR_REFORMAT | SC_STATUS); + + /* XXXX */ + list[0] = g; list[1] = s; + gp->scr_discard(0, list); + + return (0); +} + +/* + * vs_getbg -- + * Get the specified background screen, or, if name is NULL, the first + * background screen. + */ +static SCR * +vs_getbg(SCR *sp, char *name) +{ + GS *gp; + SCR *nsp; + char *p; + + gp = sp->gp; + + /* If name is NULL, return the first background screen on the list. */ + if (name == NULL) + return (TAILQ_FIRST(gp->hq)); + + /* Search for a full match. */ + TAILQ_FOREACH(nsp, gp->hq, q) + if (!strcmp(nsp->frp->name, name)) + break; + if (nsp != NULL) + return (nsp); + + /* Search for a last-component match. */ + TAILQ_FOREACH(nsp, gp->hq, q) { + if ((p = strrchr(nsp->frp->name, '/')) == NULL) + p = nsp->frp->name; + else + ++p; + if (!strcmp(p, name)) + break; + } + if (nsp != NULL) + return (nsp); + + return (NULL); +} Property changes on: vendor/nvi/2.2.0-05ed8b9/vi/vs_split.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/.gitignore =================================================================== --- vendor/nvi/2.2.0-05ed8b9/.gitignore (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/.gitignore (revision 366308) @@ -0,0 +1,9 @@ +*.swp +*~ +*.orig +*.core +extern.h +*_def.h +version.h +tags +build/ Index: vendor/nvi/2.2.0-05ed8b9/LICENSE =================================================================== --- vendor/nvi/2.2.0-05ed8b9/LICENSE (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/LICENSE (revision 366308) @@ -0,0 +1,37 @@ +The following are the copyrights and redistribution conditions that apply +to this copy of the Vi software. + +/* + * Copyright (c) 1991, 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000 + * Keith Bostic. All rights reserved. + * Copyright (c) 1999, 2000 + * Sven Verdoolaege. All rights reserved. + * Copyright (c) 2011 + * Zhihao Yuan. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ Property changes on: vendor/nvi/2.2.0-05ed8b9/LICENSE ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor/nvi/2.2.0-05ed8b9/README =================================================================== --- vendor/nvi/2.2.0-05ed8b9/README (nonexistent) +++ vendor/nvi/2.2.0-05ed8b9/README (revision 366308) @@ -0,0 +1,64 @@ +This is version 2.2.0 (2020-08-01) of nex/nvi, a reimplementation of the ex/vi +text editors originally distributed as part of the Fourth Berkeley +Software Distribution (4BSD), by the University of California, Berkeley. + +The directory layout is as follows: + + LICENSE ....... Copyright, use and redistribution information. + README ........ This file. + catalog ....... Message catalogs; see catalog/README. + cl ............ Vi interface to the curses(3) library. + common ........ Code shared by ex and vi. + ex ............ Ex source code. + files ......... Template files. + man ........... Ex/vi documentation. + regex ......... Modified regex library with wide character support. + vi ............ Vi source code. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +o Nvi was written by Keith Bostic, and the last version is 1.79. After that, + + Sven Verdoolaege added the iconv support and the DB3 locking. + + Jun-ichiro itojun Hagino developed the file encoding detection + techniques in his nvi-m17n. + +The following acknowledgments were written by Keith Bostic: + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +o This software is several years old and is the product of many folks' work. + + This software was originally derived from software contributed to + the University of California, Berkeley by Steve Kirkendall, the + author of the vi clone elvis. Without his work, this work would + have been far more difficult. + + IEEE POSIX 1003.2 style regular expression support is courtesy of + Henry Spencer, for which I am *very* grateful. + + Elan Amir did the original 4BSD curses work that made it possible + to support a full-screen editor using curses. + + George Neville-Neil added the Tcl interpreter, and the initial + interpreter design was his. + + Sven Verdoolaege added the Perl interpreter. + + Rob Mayoff provided the original Cscope support. + +o Many, many people suggested enhancements, and provided bug reports and + testing, far too many to individually thank. + +o From the original vi acknowledgements, by William Joy and Mark Horton: + + Bruce Englar encouraged the early development of this display + editor. Peter Kessler helped bring sanity to version 2's + command layout. Bill Joy wrote versions 1 and 2.0 through 2.7, + and created the framework that users see in the present editor. + Mark Horton added macros and other features and made the editor + work on a large number of terminals and Unix systems. + +o And... + The financial support of UUNET Communications Services is gratefully + acknowledged. Property changes on: vendor/nvi/2.2.0-05ed8b9/README ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property