diff options
Diffstat (limited to 'runtime/tools')
-rw-r--r-- | runtime/tools/README.txt | 37 | ||||
-rw-r--r-- | runtime/tools/blink.c | 24 | ||||
-rw-r--r-- | runtime/tools/ccfilter.1 | 93 | ||||
-rw-r--r-- | runtime/tools/ccfilter.c | 328 | ||||
-rw-r--r-- | runtime/tools/ccfilter_README.txt | 101 | ||||
-rw-r--r-- | runtime/tools/demoserver.py | 107 | ||||
-rwxr-xr-x | runtime/tools/efm_filter.pl | 39 | ||||
-rw-r--r-- | runtime/tools/efm_filter.txt | 31 | ||||
-rwxr-xr-x | runtime/tools/efm_perl.pl | 153 | ||||
-rw-r--r-- | runtime/tools/emoji_list.vim | 23 | ||||
-rwxr-xr-x | runtime/tools/mve.awk | 23 | ||||
-rw-r--r-- | runtime/tools/mve.txt | 20 | ||||
-rwxr-xr-x | runtime/tools/pltags.pl | 300 | ||||
-rwxr-xr-x | runtime/tools/ref | 11 | ||||
-rw-r--r-- | runtime/tools/shtags.1 | 61 | ||||
-rwxr-xr-x | runtime/tools/shtags.pl | 144 | ||||
-rw-r--r-- | runtime/tools/unicode.vim | 471 | ||||
-rwxr-xr-x | runtime/tools/vim132 | 13 | ||||
-rw-r--r-- | runtime/tools/vim_vs_net.cmd | 23 | ||||
-rwxr-xr-x | runtime/tools/vimm | 6 | ||||
-rwxr-xr-x | runtime/tools/vimspell.sh | 55 | ||||
-rw-r--r-- | runtime/tools/vimspell.txt | 22 | ||||
-rw-r--r-- | runtime/tools/xcmdsrv_client.c | 578 |
23 files changed, 2663 insertions, 0 deletions
diff --git a/runtime/tools/README.txt b/runtime/tools/README.txt new file mode 100644 index 0000000..19976b3 --- /dev/null +++ b/runtime/tools/README.txt @@ -0,0 +1,37 @@ +Some tools that can be used with Vim: + +blink.c: C program to make the cursor blink in an xterm. + +ccfilter*: C program to filter the output of a few compilers to a common + QuickFix format. + +efm_filter.*: Perl script to filter compiler messages to QuickFix format. + +efm_perl.pl: Perl script to filter error messages from the Perl interpreter + for use with Vim quickfix mode. + +mve.* Awk script to filter error messages to QuickFix format. + +pltags.pl: Perl script to create a tags file from Perl scripts. + +ref: Shell script for the K command. + +shtags.*: Perl script to create a tags file from a shell script. + +vim132: Shell script to edit in 132 column mode on vt100 compatible + terminals. + +vimm: Shell script to start Vim on a DEC terminal with mouse + enabled. + +vimspell.*: Shell script for highlighting spelling mistakes. + +vim_vs_net.cmd: MS-Windows command file to use Vim with MS Visual Studio 7 and + later. + +xcmdsrv_client.c: Example for a client program that communicates with a Vim + server through the X-Windows interface. + +unicode.vim Vim script to generate tables for src/mbyte.c. + +[xxd can be found in the src directory] diff --git a/runtime/tools/blink.c b/runtime/tools/blink.c new file mode 100644 index 0000000..a782061 --- /dev/null +++ b/runtime/tools/blink.c @@ -0,0 +1,24 @@ +/* + * An extremely simple program to make the cursor blink in an xterm. + * This is useful when the cursor is hard to spot in a highlighted file. + * Start in the background: "blink&" Stop by killing it. + * Bram Moolenaar 980109 (based on an idea from John Lange). + */ + +#include <stdio.h> +#include <unistd.h> + + int +main(void) +{ + while (1) + { + printf("\e[?25h"); + fflush(stdout); + usleep(400000); /* on time */ + printf("\e[?25l"); + fflush(stdout); + usleep(250000); /* off time */ + } + return 0; +} diff --git a/runtime/tools/ccfilter.1 b/runtime/tools/ccfilter.1 new file mode 100644 index 0000000..92fe624 --- /dev/null +++ b/runtime/tools/ccfilter.1 @@ -0,0 +1,93 @@ +.TH ccfilter 1 "01-Apr-97" +.SH NAME +ccfilter \- a compiler's output filter for vim quickfix +.SH SYNOPSIS +ccfilter [ +.B <options> +] +.SH DESCRIPTION +The ccfilter utility "filters" the output of several compilers +and makers (make/gmake) from several platforms (see NOTES below) +to a standardized format which easily fits in vim's quickfix +feature. For further details, see in vim ":help quickfix". +.PP +ccfilter reads +.B 'stdin' +and outputs to +.B 'stdout' +\. +.PP +The need for ccfilter is clear, as some compilers have irregular +and/or multiple line error messages (with the relevant information on +line 2), which makes it impossible for the errorformat to correctly +display them ! + +When working on different platforms, and with different compilers, +ccfilter eases the utilization of quickfix, due to its standardized +output, allowing to have in .vimrc a plain +.br +.B \ \ \ \ :set\ errorformat=%f:%l:%c:%t:%m + +.SH USAGE +When using ccfilter, one would include the following lines in .vimrc: +.br +.B \ \ \ \ :set shellpipe=\\\\|&ccfilter\\\\> +.br +.B \ \ \ \ :set errorformat=%f:%l:%c:%t:%m + +.SH OPTIONS +.TP 16 +-c +Decrement column by one. This may be needed, depending on +the compiler being used. +.TP +-r +Decrement row by one. This may be needed, depending on +the compiler being used. +.TP +-v +Verbose (Outputs also invalid lines). +This option makes ccfilter output also the lines that +couldn't be correctly parsed. This is used mostly for +ccfilter debugging. +.TP +-o <COMPILER> +Treat input as <COMPILER>'s output. +Even when configuring ccfilter to assume a default +COMPILER, sometimes it's helpful to be able to specify +the COMPILER used to generate ccfilter's input. +For example, when cross-compiling on a network from a +single machine. +.TP +-h +Shows a brief help, describing the configured default COMPILER +and the valid parameters for COMPILER. + +.SH NOTES +Currently, ccfilter accepts output from several compilers, as +described below: +.TP 10 +GCC +GCC compiler +.TP +AIX +AIX's C compiler +.TP +ATT +AT&T/NCR's High Performance C Compiler +.TP +IRIX +IRIX's MIPS/MIPSpro C compiler +.TP +SOLARIS +SOLARIS's SparcWorks C compiler +.TP +HPUX +HPUX's C compiler + +.SH AUTHOR +.B ccfilter +was developed by +.B Pablo Ariel Kohan +.BR +.B mailto:pablo@memco.co.il diff --git a/runtime/tools/ccfilter.c b/runtime/tools/ccfilter.c new file mode 100644 index 0000000..43489f1 --- /dev/null +++ b/runtime/tools/ccfilter.c @@ -0,0 +1,328 @@ +/* ======================================================================= */ +/* Project : VIM */ +/* Module : ccfilter Version: 02.01.01 */ +/* File : ccfilter.c */ +/* Purpose : Filter gmake/cc output into a standardized form */ +/* ======================================================================= */ +/* Created On: 12-Sep-95 20:32 */ +/* Last modification: 03-Feb-98 */ +/* -e option added by Bernd Feige */ +/* ======================================================================= */ +/* Copyright : */ +/* This source file is copyright (c) to Pablo Ariel Kohan */ +/* ======================================================================= */ +#define __CCFILTER_C__ + +#include <ctype.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#define LINELENGTH 2048 + +/* Collector(s) */ +char Line[LINELENGTH]; +char Line2[LINELENGTH]; +/* Components */ +char FileName[1024]; +char BasePath[1024]; +char CWD[1024]; +unsigned long Row; +unsigned long Col; +char Severity; +char Reason[LINELENGTH]; + +#define COMPILER_UNKNOWN 0 +#define COMPILER_GCC 1 +#define COMPILER_AIX 2 +#define COMPILER_ATT 3 +#define COMPILER_IRIX 4 +#define COMPILER_SOLARIS 5 +#define COMPILER_HPUX 6 + +char *COMPILER_Names[][2] = + { + /* Name Description */ + { "N/A", "" }, + { "GCC", "GCC compiler" }, + { "AIX", "AIX's C compiler" }, + { "ATT", "AT&T/NCR's High Performance C Compiler" }, + { "IRIX", "IRIX's MIPS/MIPSpro C compiler" }, + { "SOLARIS", "SOLARIS's SparcWorks C compiler" }, + { "HPUX", "HPUX's C compiler" } + }; +#define COMPILER_QTY (sizeof(COMPILER_Names)/sizeof(COMPILER_Names[0])) + +#if defined(_GCC) +# define COMPILER_DEFAULT COMPILER_GCC +#elif defined(_AIX) +# define COMPILER_DEFAULT COMPILER_AIX +#elif defined(_ATT) +# define COMPILER_DEFAULT COMPILER_ATT +#elif defined(_IRIX) +# define COMPILER_DEFAULT COMPILER_IRIX +#elif defined(_SOLARIS) +# define COMPILER_DEFAULT COMPILER_SOLARIS +#elif defined(_HPUX) +# define COMPILER_DEFAULT COMPILER_HPUX +#else +# define COMPILER_DEFAULT COMPILER_UNKNOWN +#endif + +const char USAGE[] = +"ccfilter v2.1 (c)1994-1997 by Pablo Ariel Kohan\n" +"Filter Out compiler's output, and converts it to fit VIM\n\n" +"Usage:\n" +" ccfilter [<options>]\n" +"Where: <options> is one or more of:\n" +" -c Decrement column by one\n" +" -r Decrement row by one\n" +" -e Echo stdin to stderr\n" +" -v Verbose (Outputs also invalid lines)\n" +" -o <COMPILER> Treat input as <COMPILER>'s output\n" +" Note: COMPILER may be preceded by an _\n" +" -h This usage.\n"; + + +int ShowUsage( char *szError ) +{ + int i; + + fprintf( stderr, USAGE ); + + fprintf( stderr, "Current default <COMPILER>: %s\n", + COMPILER_Names[COMPILER_DEFAULT][0] ); + + fprintf( stderr, "Acceptable parameters for <COMPILER> are:\n" ); + for (i=1; i < COMPILER_QTY; i++) + fprintf( stderr, " %-15.15s %s\n", + COMPILER_Names[i][0], + COMPILER_Names[i][1] ); + fprintf(stderr, szError); + return 0; +} + +char *echogets(char *s, int echo) +{ + char * const retval=fgets(s, LINELENGTH, stdin); + if (echo!=0 && retval!=NULL) { + fputs(retval, stderr); + } + return retval; +} + +int main( int argc, char *argv[] ) +{ int rv, i, j, ok; + int stay; + int prefetch; + char *p; + int dec_col = 0; /* Decrement column value by 1 */ + int dec_row = 0; /* Decrement row value by 1 */ + int echo = 0; /* Echo stdin to stderr */ + int verbose = 0; /* Include Bad Formatted Lines */ + int CWDlen; + int COMPILER = COMPILER_DEFAULT; + + getcwd( CWD, sizeof(CWD) ); + CWDlen = strlen(CWD); + + for (i=1; i<argc; i++) + { + if (argv[i][0] != '-') + return ShowUsage(""); + switch ( argv[i][1] ) + { + case 'c': + dec_col = 1; + break; + case 'r': + dec_row = 1; + break; + case 'e': + echo = 1; + break; + case 'v': + verbose = 1; + break; + case 'o': + { + if (i+1 >= argc) + return ShowUsage("Error: Missing parameter for -o\n"); + i++; + COMPILER = -1; + for (j=1; j<COMPILER_QTY; j++) + if ( (strcmp(argv[i], COMPILER_Names[j][0]) == 0) || + ( (argv[i][0] == '_') && + (strcmp(&argv[i][1], COMPILER_Names[j][0]) == 0) ) ) + COMPILER = j; + if (COMPILER == -1) + return ShowUsage("Error: Invalid COMPILER specified\n"); + } + break; + case 'h': + return ShowUsage(""); + default: + return ShowUsage("Error: Invalid option\n"); + } + } + if (COMPILER == 0) + return ShowUsage("Error: COMPILER must be specified in this system\n"); + + stay = ( echogets(Line, echo) != NULL ); + prefetch = 0; + + while( stay ) + { + *FileName = 0; + Row = 0; + Col = 0; + Severity = ' '; + *Reason = 0; + ok = 0; + switch (COMPILER) + { + case COMPILER_GCC: + Severity = 'e'; +#ifdef GOTO_FROM_WHERE_INCLUDED + rv = sscanf( Line, "In file included from %[^:]:%lu:", + FileName, &Row ); + if ( rv == 2 ) + { + ok = (echogets(Reason, echo) != NULL); + } + else +#endif + { + if ((rv = sscanf( Line, "%[^:]:%lu: warning: %[^\n]", + FileName, &Row, Reason ))==3) { + Severity = 'w'; + } else { + rv = sscanf( Line, "%[^:]:%lu: %[^\n]", + FileName, &Row, Reason ); + } + ok = ( rv == 3 ); + } + Col = (dec_col ? 1 : 0 ); + break; + case COMPILER_AIX: + rv = sscanf( Line, "\"%[^\"]\", line %lu.%lu: %*s (%c) %[^\n]", + FileName, &Row, &Col, &Severity, Reason ); + ok = ( rv == 5 ); + break; + case COMPILER_HPUX: + rv = sscanf( Line, "cc: \"%[^\"]\", line %lu: %c%*[^:]: %[^\n]", + FileName, &Row, &Severity, Reason ); + ok = ( rv == 4 ); + Col = (dec_col ? 1 : 0 ); + break; + case COMPILER_SOLARIS: + rv = sscanf( Line, "\"%[^\"]\", line %lu: warning: %[^\n]", + FileName, &Row, Reason ); + Severity = 'w'; + ok = ( rv == 3 ); + if ( rv != 3 ) + { + rv = sscanf( Line, "\"%[^\"]\", line %lu: %[^\n]", + FileName, &Row, Reason ); + Severity = 'e'; + ok = ( rv == 3 ); + } + Col = (dec_col ? 1 : 0 ); + break; + case COMPILER_ATT: + rv = sscanf( Line, "%c \"%[^\"]\",L%lu/C%lu%*[^:]:%[^\n]", + &Severity, FileName, &Row, &Col, Reason ); + ok = ( rv == 5 ); + + if (rv != 5) + { rv = sscanf( Line, "%c \"%[^\"]\",L%lu/C%lu: %[^\n]", + &Severity, FileName, &Row, &Col, Reason ); + ok = ( rv == 5 ); + } + + if (rv != 5) + { rv = sscanf( Line, "%c \"%[^\"]\",L%lu: %[^\n]", + &Severity, FileName, &Row, Reason ); + ok = ( rv == 4 ); + Col = (dec_col ? 1 : 0 ); + } + + stay = (echogets(Line2, echo) != NULL); + while ( stay && (Line2[0] == '|') ) + { for (p=&Line2[2]; (*p) && (isspace(*p)); p++); + strcat( Reason, ": " ); + strcat( Reason, p ); + Line2[0] = 0; + stay = (echogets(Line2, echo) != NULL); + } + prefetch = 1; + strcpy( Line, Line2 ); + break; + case COMPILER_IRIX: + Col = 1; + prefetch = 0; + rv = 0; + ok = 0; + if ( !strncmp(Line, "cfe: ", 5) ) + { p = &Line[5]; + Severity = tolower(*p); + p = strchr( &Line[5], ':' ); + if (p == NULL) + { ok = 0; + } + else + { + rv = sscanf( p+2, "%[^:]: %lu: %[^\n]", + FileName, &Row, Reason ); + if (rv != 3) + rv = sscanf( p+2, "%[^,], line %lu: %[^\n]", + FileName, &Row, Reason ); + ok = ( rv == 3 ); + } + + if (ok) + { prefetch = 1; + stay = (echogets(Line, echo) != NULL); + if (Line[0] == ' ') + stay = (echogets(Line2, echo) != NULL); + if ( (Line2[0] == ' ') && + ( (Line2[1] == '-') || (Line2[1] == '^') ) ) + { Col = strlen(Line2)-1; + prefetch = 0; + } + else + { strcat( Line, "\n" ); + strcat( Line, Line2 ); + } + } + } + break; + } + if (dec_col) Col--; + if (dec_row) Row--; + if (!ok) + { + if ( Line[0] == 'g' ) + p = &Line[1]; + else + p = &Line[0]; + ok = sscanf( p, "make[%*d]: Entering directory `%[^']", + BasePath ); + if (verbose) + printf( "[%u]?%s\n", (unsigned)ok, Line ); + } + else + { + for (p=Reason; (*p) && (isspace(*p)); p++); + if ( BasePath[CWDlen] == 0 ) + printf( "%s:%lu:%lu:%c:%s\n", FileName, Row, Col, Severity, p ); + else + { + printf( "%s/%s:%lu:%lu:%c:%s\n", &BasePath[CWDlen+1], FileName, Row, Col, Severity, p ); + } + } + if (!prefetch) + stay = ( echogets(Line, echo) != NULL ); + } + return 0; +} diff --git a/runtime/tools/ccfilter_README.txt b/runtime/tools/ccfilter_README.txt new file mode 100644 index 0000000..ea989f2 --- /dev/null +++ b/runtime/tools/ccfilter_README.txt @@ -0,0 +1,101 @@ +READ THIS FIRST +=============== + +ccfilter is a C program to filter the output of a few compilers to a common +QuickFix format. It is provided with Vim to make quickfix useful for more +compilers. + +ccfilter WILL FAIL with long lines (more than 2047 bytes). + + +COMPILING AND INSTALLING: +========================= + +To compile ccfilter, you can just do a plain: + cc ccfilter.c -o ccfilter +Though, it may be wise to have your default compiler defined, +so you would normally compile it with one of the following: + cc -D_GCC ccfilter.c -o ccfilter + cc -D_AIX ccfilter.c -o ccfilter + cc -D_ATT ccfilter.c -o ccfilter + cc -D_IRIX ccfilter.c -o ccfilter + cc -D_SOLARIS ccfilter.c -o ccfilter + cc -D_HPUX ccfilter.c -o ccfilter +You can then copy ccfilter to its target destination (i.e: /usr/local/bin). +The man page ccfilter.1 has to be copied to somewhere in your MANPATH, +under a man1 directory (i.e: /usr/local/man/man1). + + +SUPPORTED COMPILERS/PORTING NOTES: +================================== + +The supported formats for the different compilers are described below: +In this section, meta-names are used as place-holders in the line +formats: <FILE> <ROW> <COL> <SEVERITY> <REASON> <> +The <> denotes ignored text. +Line formats are delimited by the ^ (caret) symbol. + +0) Special case: "gmake directory change" lines: + Lines with a format like: + ^gmake[<NUM>]: Entering directory `<DIR>'^ + are used to follow the directory changes during the make process, + providing in the <FILE> part, a relative (if possible) directory + path to the erroneous file. + + +1) GCC: + Recognized lines are of the format: + - ^In file included from <FILE>:<ROW>:^ + Line following this one is used as <REASON> + <SEVERITY> is always 'e' (error) + <COL> is always '0' + + - ^<FILE>:<ROW>:<REASON>^ + <SEVERITY> is always 'e' (error) + <COL> is always '0' + + +2) AIX: + Recognized lines are of the format: + - ^"<FILE>", line <ROW>.<COL>: <> (<SEVERITY>) <REASON>", + + +3) HPUX: + Recognized lines are of the format: + - ^cc: "<FILE>", line <ROW>: <SEVERITY>: <REASON>^ + <COL> is always '0' + + +4) SOLARIS: + Recognized lines are of the format: + - ^"<FILE>", line <ROW>: warning: <REASON>^ + This assumes <SEVERITY> is "W" + <COL> is always '0' + + - ^"<FILE>", line <ROW>: <REASON>^ + This assumes <SEVERITY> is "E" + <COL> is always '0' + + +5) ATT / NCR: + Recognized lines are of the format: + - ^<SEVERITY> "<FILE>",L<ROW>/C<COL><>:<REASON>^ + or + - ^<SEVERITY> "<FILE>",L<ROW>/C<COL>:<REASON>^ + Following lines beginning with a pipe (|) are continuation + lines, and are therefore appended to the <REASON> + + - ^<SEVERITY> "<FILE>",L<ROW>:<REASON>^ + <COL> is '0' + Following lines beginning with a pipe (|) are continuation + lines, and are therefore appended to the <REASON> + + +6) SGI-IRIX: + Recognized lines are of the format: + - ^cfe: <SEVERITY>: <FILE>: <ROW>: <REASON>^ + or + ^cfe: <SEVERITY>: <FILE>, line <ROW>: <REASON>^ + Following lines beginning with a dash (-) are "column-bar" + that end with a caret in the column of the error. These lines + are analyzed to generate the <COL>. diff --git a/runtime/tools/demoserver.py b/runtime/tools/demoserver.py new file mode 100644 index 0000000..2667aed --- /dev/null +++ b/runtime/tools/demoserver.py @@ -0,0 +1,107 @@ +#!/usr/bin/python +# +# Server that will accept connections from a Vim channel. +# Run this server and then in Vim you can open the channel: +# :let handle = ch_open('localhost:8765') +# +# Then Vim can send requests to the server: +# :let response = ch_sendexpr(handle, 'hello!') +# +# And you can control Vim by typing a JSON message here, e.g.: +# ["ex","echo 'hi there'"] +# +# There is no prompt, just type a line and press Enter. +# To exit cleanly type "quit<Enter>". +# +# See ":help channel-demo" in Vim. +# +# This requires Python 2.6 or later. + +from __future__ import print_function +import json +import socket +import sys +import threading + +try: + # Python 3 + import socketserver +except ImportError: + # Python 2 + import SocketServer as socketserver + +thesocket = None + +class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler): + + def handle(self): + print("=== socket opened ===") + global thesocket + thesocket = self.request + while True: + try: + data = self.request.recv(4096).decode('utf-8') + except socket.error: + print("=== socket error ===") + break + if data == '': + print("=== socket closed ===") + break + print("received: {0}".format(data)) + try: + decoded = json.loads(data) + except ValueError: + print("json decoding failed") + decoded = [-1, ''] + + # Send a response if the sequence number is positive. + # Negative numbers are used for "eval" responses. + if decoded[0] >= 0: + if decoded[1] == 'hello!': + response = "got it" + id = decoded[0] + elif decoded[1] == 'hello channel!': + response = "got that" + # response is not to a specific message callback but to the + # channel callback, need to use ID zero + id = 0 + else: + response = "what?" + id = decoded[0] + encoded = json.dumps([id, response]) + print("sending {0}".format(encoded)) + self.request.sendall(encoded.encode('utf-8')) + thesocket = None + +class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer): + pass + +if __name__ == "__main__": + HOST, PORT = "localhost", 8765 + + server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler) + ip, port = server.server_address + + # Start a thread with the server -- that thread will then start one + # more thread for each request + server_thread = threading.Thread(target=server.serve_forever) + + # Exit the server thread when the main thread terminates + server_thread.daemon = True + server_thread.start() + print("Server loop running in thread: ", server_thread.name) + + print("Listening on port {0}".format(PORT)) + while True: + typed = sys.stdin.readline() + if "quit" in typed: + print("Goodbye!") + break + if thesocket is None: + print("No socket yet") + else: + print("sending {0}".format(typed)) + thesocket.sendall(typed.encode('utf-8')) + + server.shutdown() + server.server_close() diff --git a/runtime/tools/efm_filter.pl b/runtime/tools/efm_filter.pl new file mode 100755 index 0000000..1d1a4f3 --- /dev/null +++ b/runtime/tools/efm_filter.pl @@ -0,0 +1,39 @@ +#!/usr/bin/env perl +# +# This program works as a filter that reads from stdin, copies to +# stdout *and* creates an error file that can be read by vim. +# +# This program has only been tested on SGI, Irix5.3. +# +# Written by Ives Aerts in 1996. This little program is not guaranteed +# to do (or not do) anything at all and can be freely used for +# whatever purpose you can think of. + +$args = @ARGV; + +unless ($args == 1) { + die("Usage: vimccparse <output filename>\n"); +} + +$filename = @ARGV[0]; +open (OUT, ">$filename") || die ("Can't open file: \"$filename\""); + +while (<STDIN>) { + print; + if ( (/"(.*)", line (\d+): (e)rror\((\d+)\):/) + || (/"(.*)", line (\d+): (w)arning\((\d+)\):/) ) { + $file=$1; + $line=$2; + $errortype="\u$3"; + $errornr=$4; + chop($errormsg=<STDIN>); + $errormsg =~ s/^\s*//; + $sourceline=<STDIN>; + $column=index(<STDIN>, "^") - 1; + + print OUT "$file>$line:$column:$errortype:$errornr:$errormsg\n"; + } +} + +close(OUT); +exit(0); diff --git a/runtime/tools/efm_filter.txt b/runtime/tools/efm_filter.txt new file mode 100644 index 0000000..d3f97f4 --- /dev/null +++ b/runtime/tools/efm_filter.txt @@ -0,0 +1,31 @@ +[adopted from a message that Ives posted in the Vim mailing list] + +Some compilers produce an error message that cannot be handled with +'errorformat' in Vim. Following is an example of a Perl script that +translates one error message into something that Vim understands. + + +The compiler that generates this kind of error messages (4 lines): + +"/tmp_mnt/cm/src/apertos/MoU/MetaCore/MetaCore/common/src/MetaCoreImp_M.cc", +line 50: error(3114): + identifier "PRIMITIVE_M" is undefined + return(ExecuteCore(PRIMITIVE_M, + +You can find a small perl program at the end. +The way I use it is: + +:set errorformat=%f>%l:%c:%t:%n:%m +:set makeprg=clearmake\ -C\ gnu +:set shellpipe=2>&1\|\ vimccparse + +If somebody thinks this is useful: feel free to do whatever you can think +of with this code. + +-Ives +____________________________________________________________ +Ives Aerts (SW Developer) Sony Telecom Europe +ives@sonytel.be St.Stevens Woluwestr. 55 +`Death could create most things, B-1130 Brussels, Belgium + except for plumbing.' PHONE : +32 2 724 19 67 + (Soul Music - T.Pratchett) FAX : +32 2 726 26 86 diff --git a/runtime/tools/efm_perl.pl b/runtime/tools/efm_perl.pl new file mode 100755 index 0000000..1aab2d4 --- /dev/null +++ b/runtime/tools/efm_perl.pl @@ -0,0 +1,153 @@ +#!/usr/bin/perl -w + +# vimparse.pl - Reformats the error messages of the Perl interpreter for use +# with the quickfix mode of Vim +# +# Copyright (c) 2001 by Joerg Ziefle <joerg.ziefle@gmx.de> +# You may use and distribute this software under the same terms as Perl itself. +# +# Usage: put one of the two configurations below in your ~/.vimrc (without the +# description and '# ') and enjoy (be sure to adjust the paths to vimparse.pl +# before): +# +# Program is run interactively with 'perl -w': +# +# set makeprg=$HOME/bin/vimparse.pl\ %\ $* +# set errorformat=%f:%l:%m +# +# Program is only compiled with 'perl -wc': +# +# set makeprg=$HOME/bin/vimparse.pl\ -c\ %\ $* +# set errorformat=%f:%l:%m +# +# Usage: +# vimparse.pl [-c] [-f <errorfile>] <programfile> [programargs] +# +# -c compile only, don't run (perl -wc) +# -f write errors to <errorfile> +# +# Example usages: +# * From the command line: +# vimparse.pl program.pl +# +# vimparse.pl -c -f errorfile program.pl +# Then run vim -q errorfile to edit the errors with Vim. +# +# * From Vim: +# Edit in Vim (and save, if you don't have autowrite on), then +# type ':mak' or ':mak args' (args being the program arguments) +# to error check. +# +# Version history: +# 0.2 (04/12/2001): +# * First public version (sent to Bram) +# * -c command line option for compiling only +# * grammatical fix: 'There was 1 error.' +# * bug fix for multiple arguments +# * more error checks +# * documentation (top of file, &usage) +# * minor code clean ups +# 0.1 (02/02/2001): +# * Initial version +# * Basic functionality +# +# Todo: +# * test on more systems +# * use portable way to determine the location of perl ('use Config') +# * include option that shows perldiag messages for each error +# * allow to pass in program by STDIN +# * more intuitive behaviour if no error is found (show message) +# +# Tested under SunOS 5.7 with Perl 5.6.0. Let me know if it's not working for +# you. + +use strict; +use Getopt::Std; + +use vars qw/$opt_c $opt_f $opt_h/; # needed for Getopt in combination with use strict 'vars' + +use constant VERSION => 0.2; + +getopts('cf:h'); + +&usage if $opt_h; # not necessarily needed, but good for further extension + +if (defined $opt_f) { + + open FILE, "> $opt_f" or do { + warn "Couldn't open $opt_f: $!. Using STDOUT instead.\n"; + undef $opt_f; + }; + +}; + +my $handle = (defined $opt_f ? \*FILE : \*STDOUT); + +(my $file = shift) or &usage; # display usage if no filename is supplied +my $args = (@ARGV ? ' ' . join ' ', @ARGV : ''); + +my @lines = `perl @{[defined $opt_c ? '-c ' : '' ]} -w "$file$args" 2>&1`; + +my $errors = 0; +foreach my $line (@lines) { + + chomp($line); + my ($file, $lineno, $message, $rest); + + if ($line =~ /^(.*)\sat\s(.*)\sline\s(\d+)(\.|,\snear\s\".*\")$/) { + + ($message, $file, $lineno, $rest) = ($1, $2, $3, $4); + $errors++; + $message .= $rest if ($rest =~ s/^,//); + print $handle "$file:$lineno:$message\n"; + + } else { next }; + +} + +if (defined $opt_f) { + + my $msg; + if ($errors == 1) { + + $msg = "There was 1 error.\n"; + + } else { + + $msg = "There were $errors errors.\n"; + + }; + + print STDOUT $msg; + close FILE; + unlink $opt_f unless $errors; + +}; + +sub usage { + + (local $0 = $0) =~ s/^.*\/([^\/]+)$/$1/; # remove path from name of program + print<<EOT; +Usage: + $0 [-c] [-f <errorfile>] <programfile> [programargs] + + -c compile only, don't run (executes 'perl -wc') + -f write errors to <errorfile> + +Examples: + * At the command line: + $0 program.pl + Displays output on STDOUT. + + $0 -c -f errorfile program.pl + Then run 'vim -q errorfile' to edit the errors with Vim. + + * In Vim: + Edit in Vim (and save, if you don't have autowrite on), then + type ':mak' or ':mak args' (args being the program arguments) + to error check. +EOT + + exit 0; + +}; diff --git a/runtime/tools/emoji_list.vim b/runtime/tools/emoji_list.vim new file mode 100644 index 0000000..d361b7e --- /dev/null +++ b/runtime/tools/emoji_list.vim @@ -0,0 +1,23 @@ +" Script to fill the window with emoji characters, one per line. +" Source this script: :source % + +if &modified + new +else + enew +endif + +" Use a compiled Vim9 function for speed +def DoIt() + var lnum = 1 + for c in range(0x100, 0x1ffff) + var cs = nr2char(c) + if charclass(cs) == 3 + setline(lnum, '|' .. cs .. '| ' .. strwidth(cs)) + lnum += 1 + endif + endfor +enddef + +call DoIt() +set nomodified diff --git a/runtime/tools/mve.awk b/runtime/tools/mve.awk new file mode 100755 index 0000000..396f806 --- /dev/null +++ b/runtime/tools/mve.awk @@ -0,0 +1,23 @@ +#!/usr/bin/nawk -f +# +# Change "nawk" to "awk" or "gawk" if you get errors. +# +# Make Vim Errors +# Processes errors from cc for use by Vim's quick fix tools +# specifically it translates the ---------^ notation to a +# column number +# +BEGIN { FS="[:,]" } + +/^cfe/ { file=$3 + msg=$5 + split($4,s," ") + line=s[2] +} + +# You may have to substitute a tab character for the \t here: +/^[\t-]*\^/ { + p=match($0, ".*\\^" ) + col=RLENGTH-2 + printf("%s, line %d, col %d : %s\n", file,line,col,msg) +} diff --git a/runtime/tools/mve.txt b/runtime/tools/mve.txt new file mode 100644 index 0000000..8aa5cf6 --- /dev/null +++ b/runtime/tools/mve.txt @@ -0,0 +1,20 @@ +[ The mve awk script was posted on the vimdev mailing list ] + +From: jimmer@barney.mdhc.mdc.com (J. McGlasson) +Date: Mon, 31 Mar 1997 13:16:49 -0700 (Mar) + +My compiler (SGI MIPSpro C compiler - IRIX 6.4) works like this. +I have written a script mve (make vim errors), through which I pipe my make +output, which translates output of the following form: + +cfe: Error: syntax.c, line 4: Syntax Error + int i[12; + ------------^ + +into: + + cl.c, line 4, col 12 : Syntax Error + +(in vim notation: %f, line %l, col %c : %m) + +You might be able to tailor this for your compiler's output. diff --git a/runtime/tools/pltags.pl b/runtime/tools/pltags.pl new file mode 100755 index 0000000..7a74682 --- /dev/null +++ b/runtime/tools/pltags.pl @@ -0,0 +1,300 @@ +#!/usr/bin/env perl + +# pltags - create a tags file for Perl code, for use by vi(m) +# +# Distributed with Vim <http://www.vim.org/>, latest version always available +# at <http://www.mscha.com/mscha.html?pltags#tools> +# +# Version 2.3, 28 February 2002 +# +# Written by Michael Schaap <pltags@mscha.com>. Suggestions for improvement +# are very welcome! +# +# This script will not work with Perl 4 or below! +# +# Revision history: +# 1.0 1997? Original version, quickly hacked together +# 2.0 1999? Completely rewritten, better structured and documented, +# support for variables, packages, Exuberant Ctags extensions +# 2.1 Jun 2000 Fixed critical bug (typo in comment) ;-) +# Support multiple level packages (e.g. Archive::Zip::Member) +# 2.2 Jul 2001 'Glob' wildcards - especially useful under Windows +# (thanks to Serge Sivkov and Jason King) +# Bug fix: reset package name for each file +# 2.21 Jul 2001 Oops... bug in variable detection (/local../ -> /^local.../) +# 2.3 Feb 2002 Support variables declared with "our" +# (thanks to Lutz Mende) + +# Complain about undeclared variables +use strict; + +# Used modules +use Getopt::Long; + +# Options with their defaults +my $do_subs = 1; # --subs, --nosubs include subs in tags file? +my $do_vars = 1; # --vars, --novars include variables in tags file? +my $do_pkgs = 1; # --pkgs, --nopkgs include packages in tags file? +my $do_exts = 1; # --extensions, --noextensions + # include Exuberant Ctags extensions + +# Global variables +my $VERSION = "2.21"; # pltags version +my $status = 0; # GetOptions return value +my $file = ""; # File being processed +my @tags = (); # List of produced tags +my $is_pkg = 0; # Are we tagging a package? +my $has_subs = 0; # Has this file any subs yet? +my $package_name = ""; # Name of current package +my $var_continues = 0; # Variable declaration continues on last line +my $line = ""; # Current line in file +my $stmt = ""; # Current Perl statement +my @vars = (); # List of variables in declaration +my $var = ""; # Variable in declaration +my $tagline = ""; # Tag file line + +# Create a tag file line and push it on the list of found tags +sub MakeTag($$$$$) +{ + my ($tag, # Tag name + $type, # Type of tag + $is_static, # Is this a static tag? + $file, # File in which tag appears + $line) = @_; # Line in which tag appears + + my $tagline = ""; # Created tag line + + # Only process tag if not empty + if ($tag) + { + # Get rid of \n, and escape / and \ in line + chomp $line; + $line =~ s/\\/\\\\/g; + $line =~ s/\//\\\//g; + + # Create a tag line + $tagline = "$tag\t$file\t/^$line\$/"; + + # If we're told to do so, add extensions + if ($do_exts) + { + $tagline .= ";\"\t$type" + . ($is_static ? "\tfile:" : "") + . ($package_name ? "\tclass:$package_name" : ""); + } + + # Push it on the stack + push (@tags, $tagline); + } +} + +# Parse package name from statement +sub PackageName($) +{ + my ($stmt) = @_; # Statement + + # Look for the argument to "package". Return it if found, else return "" + if ($stmt =~ /^package\s+([\w:]+)/) + { + my $pkgname = $1; + + # Remove any parent package name(s) + $pkgname =~ s/.*://; + return $pkgname; + } + else + { + return ""; + } +} + +# Parse sub name from statement +sub SubName($) +{ + my ($stmt) = @_; # Statement + + # Look for the argument to "sub". Return it if found, else return "" + if ($stmt =~ /^sub\s+([\w:]+)/) + { + my $subname = $1; + + # Remove any parent package name(s) + $subname =~ s/.*://; + return $subname; + } + else + { + return ""; + } +} + +# Parse all variable names from statement +sub VarNames($) +{ + my ($stmt) = @_; + + # Remove my or local from statement, if present + $stmt =~ s/^(my|our|local)\s+//; + + # Remove any assignment piece + $stmt =~ s/\s*=.*//; + + # Now find all variable names, i.e. "words" preceded by $, @ or % + @vars = ($stmt =~ /[\$\@\%]([\w:]+)\b/g); + + # Remove any parent package name(s) + map(s/.*://, @vars); + + return (@vars); +} + +############### Start ############### + +print "\npltags $VERSION by Michael Schaap <mscha\@mscha.com>\n\n"; + +# Get options +$status = GetOptions("subs!" => \$do_subs, + "vars!" => \$do_vars, + "pkgs!" => \$do_pkgs, + "extensions!" => \$do_exts); + +# Usage if error in options or no arguments given +unless ($status && @ARGV) +{ + print "\n" unless ($status); + print " Usage: $0 [options] filename ...\n\n"; + print " Where options can be:\n"; + print " --subs (--nosubs) (don't) include sub declarations in tag file\n"; + print " --vars (--novars) (don't) include variable declarations in tag file\n"; + print " --pkgs (--nopkgs) (don't) include package declarations in tag file\n"; + print " --extensions (--noextensions)\n"; + print " (don't) include Exuberant Ctags / Vim style\n"; + print " extensions in tag file\n\n"; + print " Default options: "; + print ($do_subs ? "--subs " : "--nosubs "); + print ($do_vars ? "--vars " : "--novars "); + print ($do_pkgs ? "--pkgs " : "--nopkgs "); + print ($do_exts ? "--extensions\n\n" : "--noextensions\n\n"); + print " Example: $0 *.pl *.pm ../shared/*.pm\n\n"; + exit; +} + +# Loop through files on command line - 'glob' any wildcards, since Windows +# doesn't do this for us +foreach $file (map { glob } @ARGV) +{ + # Skip if this is not a file we can open. Also skip tags files and backup + # files + next unless ((-f $file) && (-r $file) && ($file !~ /tags$/) + && ($file !~ /~$/)); + + print "Tagging file $file...\n"; + + $is_pkg = 0; + $package_name = ""; + $has_subs = 0; + $var_continues = 0; + + open (IN, $file) or die "Can't open file '$file': $!"; + + # Loop through file + foreach $line (<IN>) + { + # Statement is line with comments and whitespace trimmed + ($stmt = $line) =~ s/#.*//; + $stmt =~ s/^\s*//; + $stmt =~ s/\s*$//; + + # Nothing left? Never mind. + next unless ($stmt); + + # This is a variable declaration if one was started on the previous + # line, or if this line starts with my or local + if ($var_continues or ($stmt =~/^my\b/) + or ($stmt =~/^our\b/) or ($stmt =~/^local\b/)) + { + # The declaration continues if the line does not end with ; + $var_continues = ($stmt !~ /;$/); + + # Loop through all variable names in the declaration + foreach $var (VarNames($stmt)) + { + # Make a tag for this variable unless we're told not to. We + # assume that a variable is always static, unless it appears + # in a package before any sub. (Not necessarily true, but + # it's ok for most purposes and Vim works fine even if it is + # incorrect) + if ($do_vars) + { + MakeTag($var, "v", (!$is_pkg or $has_subs), $file, $line); + } + } + } + + # This is a package declaration if the line starts with package + elsif ($stmt =~/^package\b/) + { + # Get name of the package + $package_name = PackageName($stmt); + + if ($package_name) + { + # Remember that we're doing a package + $is_pkg = 1; + + # Make a tag for this package unless we're told not to. A + # package is never static. + if ($do_pkgs) + { + MakeTag($package_name, "p", 0, $file, $line); + } + } + } + + # This is a sub declaration if the line starts with sub + elsif ($stmt =~/^sub\b/) + { + # Remember that this file has subs + $has_subs = 1; + + # Make a tag for this sub unless we're told not to. We assume + # that a sub is static, unless it appears in a package. (Not + # necessarily true, but it's ok for most purposes and Vim works + # fine even if it is incorrect) + if ($do_subs) + { + MakeTag(SubName($stmt), "s", (!$is_pkg), $file, $line); + } + } + } + close (IN); +} + +# Do we have any tags? If so, write them to the tags file +if (@tags) +{ + # Add some tag file extensions if we're told to + if ($do_exts) + { + push (@tags, "!_TAG_FILE_FORMAT\t2\t/extended format/"); + push (@tags, "!_TAG_FILE_SORTED\t1\t/0=unsorted, 1=sorted/"); + push (@tags, "!_TAG_PROGRAM_AUTHOR\tMichael Schaap\t/mscha\@mscha.com/"); + push (@tags, "!_TAG_PROGRAM_NAME\tpltags\t//"); + push (@tags, "!_TAG_PROGRAM_VERSION\t$VERSION\t/supports multiple tags and extended format/"); + } + + print "\nWriting tags file.\n"; + + open (OUT, ">tags") or die "Can't open tags file: $!"; + + foreach $tagline (sort @tags) + { + print OUT "$tagline\n"; + } + + close (OUT); +} +else +{ + print "\nNo tags found.\n"; +} diff --git a/runtime/tools/ref b/runtime/tools/ref new file mode 100755 index 0000000..77bfc80 --- /dev/null +++ b/runtime/tools/ref @@ -0,0 +1,11 @@ +#!/bin/sh +# +# ref - Check spelling of the arguments +# +# Usage: ref word .. +# +# can be used for the K command of Vim +# +spell <<EOF +$* +EOF diff --git a/runtime/tools/shtags.1 b/runtime/tools/shtags.1 new file mode 100644 index 0000000..0a13802 --- /dev/null +++ b/runtime/tools/shtags.1 @@ -0,0 +1,61 @@ +.TH shtags 1 "local Utilities" +.SH NAME +shtags \- Create tags for shell scripts +.SH SYNOPSIS +.B shtags +[\fI-mvw\fP] [\fI-t <file>\fP] [\fI-s <shell>\fP] <files> +.SH DESCRIPTION +\fBshtags\fP creates a \fBvi(1)\fP tags file for shell scripts - which +essentially turns your code into a hypertext document. \fBshtags\fP +attempts to create tags for all function and variable definitions, +although this is a little difficult, because in most shell languages, +variables don't need to be explicitly defined, and as such there is +often no distinct "variable definition". If this is the case, +\fBshtags\fP simply creates a tag for the first instance of a variable +which is being set in a simple way, ie: \fIset x = 5\fP. +.SH OPTIONS +.IP "\fB-t <file>\fP" +Name of tags file to create. (default is 'tags') +.IP "\fB-s <shell>\fP" +The name of the shell used by the script(s). By default, +\fBshtags\fP tries to work out which is the appropriate shell for each +file individually by looking at the first line of each file. This won't +work however, if the script starts as a bourne shell script and tries +to be clever about starting the shell it really wants. +.b +Currently supported shells are: +.RS +.IP \fBsh\fP +Bourne Shell +.IP \fBperl\fP +Perl (versions 4 and 5) +.IP \fBksh\fP +Korn Shell +.IP \fBtclsh\fP +The TCL shell +.IP \fBwish\fP +The TK Windowing shell (same as tclsh) +.RE + +.IP \fB-v\fP +Include variable definitions (variables mentioned at the start of a line) +.IP \fB-V\fP +Print version information. +.IP \fB-w\fP +Suppress "duplicate tag" warning messages. +.IP \fB-x\fP +Explicitly create a new tags file. Normally new tags are merged with +the old tags file. +.PP +\fBshtags\fP scans the specified files for subroutines and possibly +variable definitions, and creates a \fBvi\fP style tags file. +.SH FILES +.IP \fBtags\fP +A tags file contains a sorted list of tags, one tag per line. The +format is the same as that used by \fBvi\fP(1) +.SH AUTHOR +Stephen Riehm +.br +sr@pc-plus.de +.SH "SEE ALSO" +ctags(1), etags(1), perl(1), tclsh(1), wish(1), sh(1), ksh(1). diff --git a/runtime/tools/shtags.pl b/runtime/tools/shtags.pl new file mode 100755 index 0000000..49a469a --- /dev/null +++ b/runtime/tools/shtags.pl @@ -0,0 +1,144 @@ +#!/usr/bin/env perl +# +# shtags: create a tags file for perl scripts +# +# Author: Stephen Riehm +# Updated by: David Woodfall <dave@dawoodfall.net> +# Last Changed: 2018/04/02 +# + +use Getopt::Std; + +# obvious... :-) +sub usage + { + print <<_EOUSAGE_ ; +USAGE: $program [-kvwVx] [-t <file>] <files> + -t <file> Name of tags file to create. (default is 'tags') + -s <shell> Name of the shell language in the script + -v Include variable definitions. + (variables mentioned at the start of a line) + -V Print version information. + -w Suppress "duplicate tag" warnings. + -x Explicitly create a new tags file. Normally tags are merged. + <files> List of files to scan for tags. +_EOUSAGE_ + exit 0 + } + +sub version +{ + # + # Version information + # + @id = split( ', ', 'scripts/bin/shtags, /usr/local/, LOCAL_SCRIPTS, 1.2, 18/04/02, 07:37' ); + $id[0] =~ s,.*/,,; + print <<_EOVERS; +$id[0]: $id[3] +Last Modified: @id[4,5] +Component: $id[1] +Release: $id[2] +_EOVERS + exit( 1 ); +} + +# +# initialisations +# +($program = $0) =~ s,.*/,,; + +# +# parse command line +# +getopts( "t:s:vVwx" ) || &usage(); +$tags_file = $opt_t || 'tags'; +$explicit = $opt_x; +$variable_tags = $opt_v; +$allow_warnings = ! $opt_w; +&version if $opt_V; +&usage() unless @ARGV != 0; + +# slurp up the existing tags. Some will be replaced, the ones that aren't +# will be re-written exactly as they were read +if( ! $explicit && open( TAGS, "< $tags_file" ) ) + { + while( <TAGS> ) + { + /^\S+/; + $tags{$&} = $_; + } + close( TAGS ); + } + +# +# for each line of every file listed on the command line, look for a +# 'sub' definition, or, if variables are wanted as well, look for a +# variable definition at the start of a line +# +while( <> ) + { + &check_shell($_), ( $old_file = $ARGV ) if $ARGV ne $old_file; + next unless $shell; + if( $shell eq "sh" ) + { + next unless /^\s*(((\w+)))\s*\(\s*\)/ + || ( $variable_tags && /^(((\w+)=))/ ); + $match = $3; + } + if( $shell eq "ksh" ) + { + # ksh + next unless /^\s*function\s+(((\w+)))/ + || ( $variable_tags && /^(((\w+)=))/ ); + $match = $3; + } + if( $shell eq "perl" ) + { + # perl + next unless /^\s*sub\s+(\w+('|::))?(\w+)/ + || /^\s*(((\w+))):/ + || ( $variable_tags && /^(([(\s]*[\$\@\%]{1}(\w+).*=))/ ); + $match = $3; + } + if( $shell eq "tcl" ) + { + next unless /^\s*proc\s+(((\S+)))/ + || ( $variable_tags && /^\s*set\s+(((\w+)\s))/ ); + $match = $3; + } + chop; + warn "$match - duplicate ignored\n" + if ( $new{$match}++ + || !( $tags{$match} = sprintf( "%s\t%s\t?^%s\$?\n", $match, $ARGV, $_ ) ) ) + && $allow_warnings; + } + +# write the new tags to the tags file - note that the whole file is rewritten +open( TAGS, "> $tags_file" ); +foreach( sort( keys %tags ) ) + { + print TAGS "$tags{$_}"; + } +close( TAGS ); + +sub check_shell + { + local( $_ ) = @_; + # read the first line of a script, and work out which shell it is, + # unless a shell was specified on the command line + # + # This routine can't handle clever scripts which start sh and then + # use sh to start the shell they really wanted. + if( $opt_s ) + { + $shell = $opt_s; + } + else + { + $shell = "sh" if /^:$/ || /^#!.*\/bin\/sh/; + $shell = "ksh" if /^#!.*\/ksh/; + $shell = "perl" if /^#!.*\/perl/; + $shell = "tcl" if /^#!.*\/wish/; + printf "Using $shell for $ARGV\n"; + } + } diff --git a/runtime/tools/unicode.vim b/runtime/tools/unicode.vim new file mode 100644 index 0000000..630a581 --- /dev/null +++ b/runtime/tools/unicode.vim @@ -0,0 +1,471 @@ +" Script to extract tables from Unicode .txt files, to be used in src/mbyte.c. +" The format of the UnicodeData.txt file is explained here: +" http://www.unicode.org/Public/5.1.0/ucd/UCD.html +" For the other files see the header. +" +" Might need to update the URL to the emoji-data.txt +" Usage: Vim -S <this-file> +" +" Author: Bram Moolenaar +" Last Update: 2020 Aug 24 + +" Parse lines of UnicodeData.txt. Creates a list of lists in s:dataprops. +func! ParseDataToProps() + let s:dataprops = [] + let lnum = 1 + while lnum <= line('$') + let l = split(getline(lnum), '\s*;\s*', 1) + if len(l) != 15 + echoerr 'Found ' . len(l) . ' items in line ' . lnum . ', expected 15' + return + endif + call add(s:dataprops, l) + let lnum += 1 + endwhile +endfunc + +" Parse lines of CaseFolding.txt. Creates a list of lists in s:foldprops. +func! ParseFoldProps() + let s:foldprops = [] + let lnum = 1 + while lnum <= line('$') + let line = getline(lnum) + if line !~ '^#' && line !~ '^\s*$' + let l = split(line, '\s*;\s*', 1) + if len(l) != 4 + echoerr 'Found ' . len(l) . ' items in line ' . lnum . ', expected 4' + return + endif + call add(s:foldprops, l) + endif + let lnum += 1 + endwhile +endfunc + +" Parse lines of EastAsianWidth.txt. Creates a list of lists in s:widthprops. +func! ParseWidthProps() + let s:widthprops = [] + let lnum = 1 + while lnum <= line('$') + let line = getline(lnum) + if line !~ '^#' && line !~ '^\s*$' + let l = split(line, '\s*;\s*', 1) + if len(l) != 2 + echoerr 'Found ' . len(l) . ' items in line ' . lnum . ', expected 2' + return + endif + call add(s:widthprops, l) + endif + let lnum += 1 + endwhile +endfunc + +" Build the toLower or toUpper table in a new buffer. +" Uses s:dataprops. +func! BuildCaseTable(name, index) + let start = -1 + let end = -1 + let step = 0 + let add = -1 + let ranges = [] + for p in s:dataprops + if p[a:index] != '' + let n = ('0x' . p[0]) + 0 + let nl = ('0x' . p[a:index]) + 0 + if start >= 0 && add == nl - n && (step == 0 || n - end == step) + " continue with same range. + let step = n - end + let end = n + else + if start >= 0 + " produce previous range + call Range(ranges, start, end, step, add) + endif + let start = n + let end = n + let step = 0 + let add = nl - n + endif + endif + endfor + if start >= 0 + call Range(ranges, start, end, step, add) + endif + + " New buffer to put the result in. + new + exe "file to" . a:name + call setline(1, "static convertStruct to" . a:name . "[] =") + call setline(2, "{") + call append('$', ranges) + call setline('$', getline('$')[:-2]) " remove last comma + call setline(line('$') + 1, "};") + wincmd p +endfunc + +" Build the foldCase table in a new buffer. +" Uses s:foldprops. +func! BuildFoldTable() + let start = -1 + let end = -1 + let step = 0 + let add = -1 + let ranges = [] + for p in s:foldprops + if p[1] == 'C' || p[1] == 'S' + let n = ('0x' . p[0]) + 0 + let nl = ('0x' . p[2]) + 0 + if start >= 0 && add == nl - n && (step == 0 || n - end == step) + " continue with same range. + let step = n - end + let end = n + else + if start >= 0 + " produce previous range + call Range(ranges, start, end, step, add) + endif + let start = n + let end = n + let step = 0 + let add = nl - n + endif + endif + endfor + if start >= 0 + call Range(ranges, start, end, step, add) + endif + + " New buffer to put the result in. + new + file foldCase + call setline(1, "static convertStruct foldCase[] =") + call setline(2, "{") + call append('$', ranges) + call setline('$', getline('$')[:-2]) " remove last comma + call setline(line('$') + 1, "};") + wincmd p +endfunc + +func! Range(ranges, start, end, step, add) + let s = printf("\t{0x%x,0x%x,%d,%d},", a:start, a:end, a:step == 0 ? -1 : a:step, a:add) + call add(a:ranges, s) +endfunc + +" Build the combining table. +" Uses s:dataprops. +func! BuildCombiningTable() + let start = -1 + let end = -1 + let ranges = [] + for p in s:dataprops + " The 'Mc' property was removed, it does take up space. + if p[2] == 'Mn' || p[2] == 'Me' + let n = ('0x' . p[0]) + 0 + if start >= 0 && end + 1 == n + " continue with same range. + let end = n + else + if start >= 0 + " produce previous range + call add(ranges, printf("\t{0x%04x, 0x%04x},", start, end)) + endif + let start = n + let end = n + endif + endif + endfor + if start >= 0 + call add(ranges, printf("\t{0x%04x, 0x%04x},", start, end)) + endif + + " New buffer to put the result in. + new + file combining + call setline(1, " static struct interval combining[] =") + call setline(2, " {") + call append('$', ranges) + call setline('$', getline('$')[:-2]) " remove last comma + call setline(line('$') + 1, " };") + wincmd p +endfunc + +" Build the double width or ambiguous width table in a new buffer. +" Uses s:widthprops and s:dataprops. +func! BuildWidthTable(pattern, tableName) + let start = -1 + let end = -1 + let ranges = [] + let dataidx = 0 + " Account for indentation differences between ambiguous and doublewidth + " table in mbyte.c + if a:pattern == 'A' + let spc = ' ' + else + let spc = "\t" + endif + for p in s:widthprops + if p[1][0] =~ a:pattern + if p[0] =~ '\.\.' + " It is a range. we don't check for composing char then. + let rng = split(p[0], '\.\.') + if len(rng) != 2 + echoerr "Cannot parse range: '" . p[0] . "' in width table" + endif + let n = ('0x' . rng[0]) + 0 + let n_last = ('0x' . rng[1]) + 0 + else + let n = ('0x' . p[0]) + 0 + let n_last = n + endif + " Find this char in the data table. + while 1 + let dn = ('0x' . s:dataprops[dataidx][0]) + 0 + if dn >= n + break + endif + let dataidx += 1 + endwhile + if dn != n && n_last == n + echoerr "Cannot find character " . n . " in data table" + endif + " Only use the char when it's not a composing char. + " But use all chars from a range. + let dp = s:dataprops[dataidx] + if n_last > n || (dp[2] != 'Mn' && dp[2] != 'Mc' && dp[2] != 'Me') + if start >= 0 && end + 1 == n + " continue with same range. + else + if start >= 0 + " produce previous range + call add(ranges, printf("%s{0x%04x, 0x%04x},", spc, start, end)) + if a:pattern == 'A' + call add(s:ambitable, [start, end]) + else + call add(s:doubletable, [start, end]) + endif + endif + let start = n + endif + let end = n_last + endif + endif + endfor + if start >= 0 + call add(ranges, printf("%s{0x%04x, 0x%04x},", spc, start, end)) + if a:pattern == 'A' + call add(s:ambitable, [start, end]) + else + call add(s:doubletable, [start, end]) + endif + endif + + " New buffer to put the result in. + new + exe "file " . a:tableName + if a:pattern == 'A' + call setline(1, "static struct interval " . a:tableName . "[] =") + call setline(2, "{") + else + call setline(1, " static struct interval " . a:tableName . "[] =") + call setline(2, " {") + endif + call append('$', ranges) + call setline('$', getline('$')[:-2]) " remove last comma + if a:pattern == 'A' + call setline(line('$') + 1, "};") + else + call setline(line('$') + 1, " };") + endif + wincmd p +endfunc + + +" Get characters from a list of lines in form "12ab .." or "12ab..56cd ..." +" and put them in dictionary "chardict" +func AddLinesToCharDict(lines, chardict) + for line in a:lines + let tokens = split(line, '\.\.') + let first = str2nr(tokens[0], 16) + if len(tokens) == 1 + let last = first + else + let last = str2nr(tokens[1], 16) + endif + for nr in range(first, last) + let a:chardict[nr] = 1 + endfor + endfor +endfunc + +func Test_AddLinesToCharDict() + let dict = {} + call AddLinesToCharDict([ + \ '1234 blah blah', + \ '1235 blah blah', + \ '12a0..12a2 blah blah', + \ '12a1 blah blah', + \ ], dict) + call assert_equal({0x1234: 1, 0x1235: 1, + \ 0x12a0: 1, 0x12a1: 1, 0x12a2: 1, + \ }, dict) + if v:errors != [] + echoerr 'AddLinesToCharDict' v:errors + return 1 + endif + return 0 +endfunc + + +func CharDictToPairList(chardict) + let result = [] + let keys = keys(a:chardict)->map('str2nr(v:val)')->sort('N') + let low = keys[0] + let high = keys[0] + for key in keys + if key > high + 1 + call add(result, [low, high]) + let low = key + let high = key + else + let high = key + endif + endfor + call add(result, [low, high]) + return result +endfunc + +func Test_CharDictToPairList() + let dict = {0x1020: 1, 0x1021: 1, 0x1022: 1, + \ 0x1024: 1, + \ 0x2022: 1, + \ 0x2024: 1, 0x2025: 1} + call assert_equal([ + \ [0x1020, 0x1022], + \ [0x1024, 0x1024], + \ [0x2022, 0x2022], + \ [0x2024, 0x2025], + \ ], CharDictToPairList(dict)) + if v:errors != [] + echoerr 'CharDictToPairList' v:errors + return 1 + endif + return 0 +endfunc + + +" Build the amoji width table in a new buffer. +func BuildEmojiTable() + " First make the table for all emojis. + let pattern = '; Emoji\s\+#\s' + let lines = map(filter(filter(getline(1, '$'), 'v:val=~"^[1-9]"'), 'v:val=~pattern'), 'matchstr(v:val,"^\\S\\+")') + + " Make a dictionary with an entry for each character. + let chardict = {} + call AddLinesToCharDict(lines, chardict) + let pairlist = CharDictToPairList(chardict) + let allranges = map(pairlist, 'printf(" {0x%04x, 0x%04x},", v:val[0], v:val[1])') + + " New buffer to put the result in. + new + exe 'file emoji_all' + call setline(1, "static struct interval emoji_all[] =") + call setline(2, "{") + call append('$', allranges) + call setline('$', getline('$')[:-2]) " remove last comma + call setline(line('$') + 1, "};") + wincmd p + + " Make the table for wide emojis. + let pattern = '; Emoji_\(Presentation\|Modifier_Base\)\s\+#\s' + let lines = map(filter(filter(getline(1, '$'), 'v:val=~"^[1-9]"'), 'v:val=~pattern'), 'matchstr(v:val,"^\\S\\+")') + + " Make a dictionary with an entry for each character. + let chardict = {} + call AddLinesToCharDict(lines, chardict) + + " exclude characters that are in the "ambiguous" or "doublewidth" table + for ambi in s:ambitable + for nr in range(ambi[0], ambi[1]) + if has_key(chardict, nr) + call remove(chardict, nr) + endif + endfor + endfor + + for wide in s:doubletable + for nr in range(wide[0], wide[1]) + if has_key(chardict, nr) + call remove(chardict, nr) + endif + endfor + endfor + + let pairlist = CharDictToPairList(chardict) + let wide_ranges = map(pairlist, 'printf("\t{0x%04x, 0x%04x},", v:val[0], v:val[1])') + + " New buffer to put the result in. + new + exe 'file emoji_wide' + call setline(1, " static struct interval emoji_wide[] =") + call setline(2, " {") + call append('$', wide_ranges) + call setline('$', getline('$')[:-2]) " remove last comma + call setline(line('$') + 1, " };") + wincmd p +endfunc + +" First test a few things +let v:errors = [] +if Test_AddLinesToCharDict() || Test_CharDictToPairList() + finish +endif + + +" Try to avoid hitting E36 +set equalalways + +" Edit the Unicode text file. Requires the netrw plugin. +edit http://unicode.org/Public/UNIDATA/UnicodeData.txt + +" Parse each line, create a list of lists. +call ParseDataToProps() + +" Build the toLower table. +call BuildCaseTable("Lower", 13) + +" Build the toUpper table. +call BuildCaseTable("Upper", 12) + +" Build the ranges of composing chars. +call BuildCombiningTable() + +" Edit the case folding text file. Requires the netrw plugin. +edit http://www.unicode.org/Public/UNIDATA/CaseFolding.txt + +" Parse each line, create a list of lists. +call ParseFoldProps() + +" Build the foldCase table. +call BuildFoldTable() + +" Edit the width text file. Requires the netrw plugin. +edit http://www.unicode.org/Public/UNIDATA/EastAsianWidth.txt + +" Parse each line, create a list of lists. +call ParseWidthProps() + +" Build the double width table. +let s:doubletable = [] +call BuildWidthTable('[WF]', 'doublewidth') + +" Build the ambiguous width table. +let s:ambitable = [] +call BuildWidthTable('A', 'ambiguous') + +" Edit the emoji text file. Requires the netrw plugin. +" commented out, because it drops too many characters +"edit https://unicode.org/Public/15.0.0/ucd/emoji/emoji-data.txt +" +"" Build the emoji table. Ver. 1.0 - 6.0 +"" Must come after the "ambiguous" and "doublewidth" tables +"call BuildEmojiTable() diff --git a/runtime/tools/vim132 b/runtime/tools/vim132 new file mode 100755 index 0000000..29ea4ce --- /dev/null +++ b/runtime/tools/vim132 @@ -0,0 +1,13 @@ +#!/bin/csh +# +# Shell script for use with UNIX +# Starts up Vim with the terminal in 132 column mode +# Only works on VT-100 terminals and lookalikes +# You need to have a termcap entry "vt100-w". Same as vt100 but 132 columns. +# +set oldterm=$term +echo "[?3h" +setenv TERM vt100-w +vim $* +set term=$oldterm +echo "[?3l" diff --git a/runtime/tools/vim_vs_net.cmd b/runtime/tools/vim_vs_net.cmd new file mode 100644 index 0000000..335236c --- /dev/null +++ b/runtime/tools/vim_vs_net.cmd @@ -0,0 +1,23 @@ +@rem +@rem To use this with Visual Studio .Net +@rem Tools->External Tools... +@rem Add +@rem Title - Vim +@rem Command - d:\files\util\vim_vs_net.cmd +@rem Arguments - +$(CurLine) $(ItemPath) +@rem Init Dir - Empty +@rem +@rem Courtesy of Brian Sturk +@rem +@rem --remote-silent +%1 is a command +954, move ahead 954 lines +@rem --remote-silent %2 full path to file +@rem In Vim +@rem :h --remote-silent for more details +@rem +@rem --servername VS_NET +@rem This will create a new instance of vim called VS_NET. So if you open +@rem multiple files from VS, they will use the same instance of Vim. +@rem This allows you to have multiple copies of Vim running, but you can +@rem control which one has VS files in it. +@rem +start /b gvim.exe --servername VS_NET --remote-silent "%1" "%2" diff --git a/runtime/tools/vimm b/runtime/tools/vimm new file mode 100755 index 0000000..7b84cb2 --- /dev/null +++ b/runtime/tools/vimm @@ -0,0 +1,6 @@ +#!/bin/sh +# enable DEC locator input model on remote terminal +printf "\033[1;2'z\033[1;3'{\c" +vim "$@" +# disable DEC locator input model on remote terminal +printf "\033[2;4'{\033[0'z\c" diff --git a/runtime/tools/vimspell.sh b/runtime/tools/vimspell.sh new file mode 100755 index 0000000..d336fe6 --- /dev/null +++ b/runtime/tools/vimspell.sh @@ -0,0 +1,55 @@ +#!/bin/sh +# +# Spell a file & generate the syntax statements necessary to +# highlight in vim. Based on a program from Krishna Gadepalli +# <krishna@stdavids.picker.com>. +# +# I use the following mappings (in .vimrc): +# +# noremap <F8> :so `vimspell.sh %`<CR><CR> +# noremap <F7> :syntax clear SpellErrors<CR> +# +# Neil Schemenauer <nascheme@ucalgary.ca> +# March 1999 +# updated 2008 Jul 17 by Bram +# +# Safe method for the temp file by Javier Fernández-Sanguino_Peña + +INFILE=$1 +tmp="${TMPDIR-/tmp}" +OUTFILE=`mktemp -t vimspellXXXXXX || tempfile -p vimspell || echo none` +# If the standard commands failed then create the file +# since we cannot create a directory (we cannot remove it on exit) +# create a file in the safest way possible. +if test "$OUTFILE" = none; then + OUTFILE=$tmp/vimspell$$ + [ -e $OUTFILE ] && { echo "Cannot use temporary file $OUTFILE, it already exists!"; exit 1 ; } + (umask 077; touch $OUTFILE) +fi +# Note the copy of vimspell cannot be deleted on exit since it is +# used by vim, otherwise it should do this: +# trap "rm -f $OUTFILE" 0 1 2 3 9 11 13 15 + + +# +# local spellings +# +LOCAL_DICT=${LOCAL_DICT-$HOME/local/lib/local_dict} + +if [ -f $LOCAL_DICT ] +then + SPELL_ARGS="+$LOCAL_DICT" +fi + +spell $SPELL_ARGS $INFILE | sort -u | +awk ' + { + printf "syntax match SpellErrors \"\\<%s\\>\"\n", $0 ; + } + +END { + printf "highlight link SpellErrors ErrorMsg\n\n" ; + } +' > $OUTFILE +echo "!rm $OUTFILE" >> $OUTFILE +echo $OUTFILE diff --git a/runtime/tools/vimspell.txt b/runtime/tools/vimspell.txt new file mode 100644 index 0000000..2842af7 --- /dev/null +++ b/runtime/tools/vimspell.txt @@ -0,0 +1,22 @@ +vimspell.sh +=========== + +This is a simple script to spell check a file and generate the syntax +statements necessary to highlight the errors in vim. It is based on a +similar program by Krishna Gadepalli <krishna@stdavids.picker.com>. + +To use this script, first place it in a directory in your path. Next, +you should add some convenient key mappings. I use the following (in +.vimrc): + + noremap <F8> :so `vimspell.sh %`<CR><CR> + noremap <F7> :syntax clear SpellErrors<CR> + +This program requires the old Unix "spell" command. On my Debian +system, "spell" is a wrapper around "ispell". For better security, +you should uncomment the line in the script that uses "tempfile" to +create a temporary file. As all systems don't have "tempfile" the +insecure "pid method" is used. + + + Neil Schemenauer <nascheme@ucalgary.ca> diff --git a/runtime/tools/xcmdsrv_client.c b/runtime/tools/xcmdsrv_client.c new file mode 100644 index 0000000..e1aea10 --- /dev/null +++ b/runtime/tools/xcmdsrv_client.c @@ -0,0 +1,578 @@ +/* vi:set ts=8 sts=4 sw=4: + * + * VIM - Vi IMproved by Bram Moolenaar + * X-Windows communication by Flemming Madsen + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + * + * Client for sending commands to an '+xcmdsrv' enabled vim. + * This is mostly a de-Vimified version of if_xcmdsrv.c in vim. + * See that file for a protocol specification. + * + * You can make a test program with a Makefile like: + * xcmdsrv_client: xcmdsrv_client.c + * cc -o $@ -g -DMAIN -I/usr/X11R6/include -L/usr/X11R6/lib $< -lX11 + * + */ + +#include <stdio.h> +#include <string.h> +#ifdef HAVE_SELECT +#include <sys/time.h> +#include <sys/types.h> +#include <unistd.h> +#else +#include <sys/poll.h> +#endif +#include <X11/Intrinsic.h> +#include <X11/Xatom.h> + +/* Client API */ +char * sendToVim(Display *dpy, char *name, char *cmd, int asKeys, int *code); + +#ifdef MAIN +/* A sample program */ +main(int argc, char **argv) +{ + char *res; + int code; + + if (argc == 4) + { + if ((res = sendToVim(XOpenDisplay(NULL), argv[2], argv[3], + argv[1][0] != 'e', &code)) != NULL) + { + if (code) + printf("Error code returned: %d\n", code); + puts(res); + } + exit(0); + } + else + fprintf(stderr, "Usage: %s {k|e} <server> <command>", argv[0]); + + exit(1); +} +#endif + +/* + * Maximum size property that can be read at one time by + * this module: + */ + +#define MAX_PROP_WORDS 100000 + +/* + * Forward declarations for procedures defined later in this file: + */ + +static int x_error_check(Display *dpy, XErrorEvent *error_event); +static int AppendPropCarefully(Display *display, + Window window, Atom property, char *value, int length); +static Window LookupName(Display *dpy, char *name, + int delete, char **loose); +static int SendInit(Display *dpy); +static char *SendEventProc(Display *dpy, XEvent *eventPtr, + int expect, int *code); +static int IsSerialName(char *name); + +/* Private variables */ +static Atom registryProperty = None; +static Atom commProperty = None; +static Window commWindow = None; +static int got_x_error = FALSE; + + +/* + * sendToVim -- + * Send to an instance of Vim via the X display. + * + * Results: + * A string with the result or NULL. Caller must free if non-NULL + */ + + char * +sendToVim( + Display *dpy, /* Where to send. */ + char *name, /* Where to send. */ + char *cmd, /* What to send. */ + int asKeys, /* Interpret as keystrokes or expr ? */ + int *code) /* Return code. 0 => OK */ +{ + Window w; + Atom *plist; + XErrorHandler old_handler; +#define STATIC_SPACE 500 + char *property, staticSpace[STATIC_SPACE]; + int length; + int res; + static int serial = 0; /* Running count of sent commands. + * Used to give each command a + * different serial number. */ + XEvent event; + XPropertyEvent *e = (XPropertyEvent *)&event; + time_t start; + char *result; + char *loosename = NULL; + + if (commProperty == None && dpy != NULL) + { + if (SendInit(dpy) < 0) + return NULL; + } + + /* + * Bind the server name to a communication window. + * + * Find any survivor with a serialno attached to the name if the + * original registrant of the wanted name is no longer present. + * + * Delete any lingering names from dead editors. + */ + + old_handler = XSetErrorHandler(x_error_check); + while (TRUE) + { + got_x_error = FALSE; + w = LookupName(dpy, name, 0, &loosename); + /* Check that the window is hot */ + if (w != None) + { + plist = XListProperties(dpy, w, &res); + XSync(dpy, False); + if (plist != NULL) + XFree(plist); + if (got_x_error) + { + LookupName(dpy, loosename ? loosename : name, + /*DELETE=*/TRUE, NULL); + continue; + } + } + break; + } + if (w == None) + { + fprintf(stderr, "no registered server named %s\n", name); + return NULL; + } + else if (loosename != NULL) + name = loosename; + + /* + * Send the command to target interpreter by appending it to the + * comm window in the communication window. + */ + + length = strlen(name) + strlen(cmd) + 10; + if (length <= STATIC_SPACE) + property = staticSpace; + else + property = (char *) malloc((unsigned) length); + + serial++; + sprintf(property, "%c%c%c-n %s%c-s %s", + 0, asKeys ? 'k' : 'c', 0, name, 0, cmd); + if (name == loosename) + free(loosename); + if (!asKeys) + { + /* Add a back reference to our comm window */ + sprintf(property + length, "%c-r %x %d", 0, (uint) commWindow, serial); + length += strlen(property + length + 1) + 1; + } + + res = AppendPropCarefully(dpy, w, commProperty, property, length + 1); + if (length > STATIC_SPACE) + free(property); + if (res < 0) + { + fprintf(stderr, "Failed to send command to the destination program\n"); + return NULL; + } + + if (asKeys) /* There is no answer for this - Keys are sent async */ + return NULL; + + + /* + * Enter a loop processing X events & pooling chars until we see the result + */ + +#define SEND_MSEC_POLL 50 + + time(&start); + while ((time((time_t *) 0) - start) < 60) + { + /* Look out for the answer */ +#ifndef HAVE_SELECT + struct pollfd fds; + + fds.fd = ConnectionNumber(dpy); + fds.events = POLLIN; + if (poll(&fds, 1, SEND_MSEC_POLL) < 0) + break; +#else + fd_set fds; + struct timeval tv; + + tv.tv_sec = 0; + tv.tv_usec = SEND_MSEC_POLL * 1000; + FD_ZERO(&fds); + FD_SET(ConnectionNumber(dpy), &fds); + if (select(ConnectionNumber(dpy) + 1, &fds, NULL, NULL, &tv) < 0) + break; +#endif + while (XEventsQueued(dpy, QueuedAfterReading) > 0) + { + XNextEvent(dpy, &event); + if (event.type == PropertyNotify && e->window == commWindow) + if ((result = SendEventProc(dpy, &event, serial, code)) != NULL) + return result; + } + } + return NULL; +} + + +/* + * SendInit -- + * This procedure is called to initialize the + * communication channels for sending commands and + * receiving results. + */ + + static int +SendInit(Display *dpy) +{ + XErrorHandler old_handler; + + /* + * Create the window used for communication, and set up an + * event handler for it. + */ + old_handler = XSetErrorHandler(x_error_check); + got_x_error = FALSE; + + commProperty = XInternAtom(dpy, "Comm", False); + /* Change this back to "InterpRegistry" to talk to tk processes */ + registryProperty = XInternAtom(dpy, "VimRegistry", False); + + if (commWindow == None) + { + commWindow = + XCreateSimpleWindow(dpy, XDefaultRootWindow(dpy), + getpid(), 0, 10, 10, 0, + WhitePixel(dpy, DefaultScreen(dpy)), + WhitePixel(dpy, DefaultScreen(dpy))); + XSelectInput(dpy, commWindow, PropertyChangeMask); + } + + XSync(dpy, False); + (void) XSetErrorHandler(old_handler); + + return got_x_error ? -1 : 0; +} + +/* + * LookupName -- + * Given an interpreter name, see if the name exists in + * the interpreter registry for a particular display. + * + * Results: + * If the given name is registered, return the ID of + * the window associated with the name. If the name + * isn't registered, then return 0. + */ + + static Window +LookupName( + Display *dpy, /* Display whose registry to check. */ + char *name, /* Name of an interpreter. */ + int delete, /* If non-zero, delete info about name. */ + char **loose) /* Do another search matching -999 if not found + Return result here if a match is found */ +{ + unsigned char *regProp, *entry; + unsigned char *p; + int result, actualFormat; + unsigned long numItems, bytesAfter; + Atom actualType; + Window returnValue; + + /* + * Read the registry property. + */ + + regProp = NULL; + result = XGetWindowProperty(dpy, RootWindow(dpy, 0), registryProperty, 0, + MAX_PROP_WORDS, False, XA_STRING, &actualType, + &actualFormat, &numItems, &bytesAfter, + ®Prop); + + if (actualType == None) + return 0; + + /* + * If the property is improperly formed, then delete it. + */ + + if ((result != Success) || (actualFormat != 8) || (actualType != XA_STRING)) + { + if (regProp != NULL) + XFree(regProp); + XDeleteProperty(dpy, RootWindow(dpy, 0), registryProperty); + return 0; + } + + /* + * Scan the property for the desired name. + */ + + returnValue = None; + entry = NULL; /* Not needed, but eliminates compiler warning. */ + for (p = regProp; (p - regProp) < numItems; ) + { + entry = p; + while ((*p != 0) && (!isspace(*p))) + p++; + if ((*p != 0) && (strcasecmp(name, p + 1) == 0)) + { + sscanf(entry, "%x", (uint*) &returnValue); + break; + } + while (*p != 0) + p++; + p++; + } + + if (loose != NULL && returnValue == None && !IsSerialName(name)) + { + for (p = regProp; (p - regProp) < numItems; ) + { + entry = p; + while ((*p != 0) && (!isspace(*p))) + p++; + if ((*p != 0) && IsSerialName(p + 1) + && (strncmp(name, p + 1, strlen(name)) == 0)) + { + sscanf(entry, "%x", (uint*) &returnValue); + *loose = strdup(p + 1); + break; + } + while (*p != 0) + p++; + p++; + } + } + + /* + * Delete the property, if that is desired (copy down the + * remainder of the registry property to overlay the deleted + * info, then rewrite the property). + */ + + if ((delete) && (returnValue != None)) + { + int count; + + while (*p != 0) + p++; + p++; + count = numItems - (p-regProp); + if (count > 0) + memcpy(entry, p, count); + XChangeProperty(dpy, RootWindow(dpy, 0), registryProperty, XA_STRING, + 8, PropModeReplace, regProp, + (int) (numItems - (p-entry))); + XSync(dpy, False); + } + + XFree(regProp); + return returnValue; +} + + static char * +SendEventProc( + Display *dpy, + XEvent *eventPtr, /* Information about event. */ + int expected, /* The one were waiting for */ + int *code) /* Return code. 0 => OK */ +{ + unsigned char *propInfo; + unsigned char *p; + int result, actualFormat; + int retCode; + unsigned long numItems, bytesAfter; + Atom actualType; + + if ((eventPtr->xproperty.atom != commProperty) + || (eventPtr->xproperty.state != PropertyNewValue)) + { + return; + } + + /* + * Read the comm property and delete it. + */ + + propInfo = NULL; + result = XGetWindowProperty(dpy, commWindow, commProperty, 0, + MAX_PROP_WORDS, True, XA_STRING, &actualType, + &actualFormat, &numItems, &bytesAfter, + &propInfo); + + /* + * If the property doesn't exist or is improperly formed + * then ignore it. + */ + + if ((result != Success) || (actualType != XA_STRING) + || (actualFormat != 8)) + { + if (propInfo != NULL) + { + XFree(propInfo); + } + return; + } + + /* + * Several commands and results could arrive in the property at + * one time; each iteration through the outer loop handles a + * single command or result. + */ + + for (p = propInfo; (p - propInfo) < numItems; ) + { + /* + * Ignore leading NULs; each command or result starts with a + * NUL so that no matter how badly formed a preceding command + * is, we'll be able to tell that a new command/result is + * starting. + */ + + if (*p == 0) + { + p++; + continue; + } + + if ((*p == 'r') && (p[1] == 0)) + { + int serial, gotSerial; + char *res; + + /* + * This is a reply to some command that we sent out. Iterate + * over all of its options. Stop when we reach the end of the + * property or something that doesn't look like an option. + */ + + p += 2; + gotSerial = 0; + res = ""; + retCode = 0; + while (((p-propInfo) < numItems) && (*p == '-')) + { + switch (p[1]) + { + case 'r': + if (p[2] == ' ') + res = p + 3; + break; + case 's': + if (sscanf(p + 2, " %d", &serial) == 1) + gotSerial = 1; + break; + case 'c': + if (sscanf(p + 2, " %d", &retCode) != 1) + retCode = 0; + break; + } + while (*p != 0) + p++; + p++; + } + + if (!gotSerial) + continue; + + if (code != NULL) + *code = retCode; + return serial == expected ? strdup(res) : NULL; + } + else + { + /* + * Didn't recognize this thing. Just skip through the next + * null character and try again. + * Also, throw away commands that we can't process anyway. + */ + + while (*p != 0) + p++; + p++; + } + } + XFree(propInfo); +} + +/* + * AppendPropCarefully -- + * + * Append a given property to a given window, but set up + * an X error handler so that if the append fails this + * procedure can return an error code rather than having + * Xlib panic. + * + * Return: + * 0 on OK - -1 on error + *-------------------------------------------------------------- + */ + + static int +AppendPropCarefully( + Display *dpy, /* Display on which to operate. */ + Window window, /* Window whose property is to + * be modified. */ + Atom property, /* Name of property. */ + char *value, /* Characters to append to property. */ + int length) /* How much to append */ +{ + XErrorHandler old_handler; + + old_handler = XSetErrorHandler(x_error_check); + got_x_error = FALSE; + XChangeProperty(dpy, window, property, XA_STRING, 8, + PropModeAppend, value, length); + XSync(dpy, False); + (void) XSetErrorHandler(old_handler); + return got_x_error ? -1 : 0; +} + + +/* + * Another X Error handler, just used to check for errors. + */ +/* ARGSUSED */ + static int +x_error_check(Display *dpy, XErrorEvent *error_event) +{ + got_x_error = TRUE; + return 0; +} + +/* + * Check if "str" looks like it had a serial number appended. + * Actually just checks if the name ends in a digit. + */ + static int +IsSerialName(char *str) +{ + int len = strlen(str); + + return (len > 1 && isdigit(str[len - 1])); +} |