mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-28 00:02:28 +00:00
Add less 643
This commit is contained in:
parent
0ed7309fdb
commit
128be2bd2e
61 changed files with 33791 additions and 2853 deletions
364
third_party/less/lsystem.c
vendored
Normal file
364
third_party/less/lsystem.c
vendored
Normal file
|
@ -0,0 +1,364 @@
|
|||
/*
|
||||
* Copyright (C) 1984-2023 Mark Nudelman
|
||||
*
|
||||
* You may distribute under the terms of either the GNU General Public
|
||||
* License or the Less License, as specified in the README file.
|
||||
*
|
||||
* For more information, see the README file.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Routines to execute other programs.
|
||||
* Necessarily very OS dependent.
|
||||
*/
|
||||
|
||||
#include "less.h"
|
||||
#include <signal.h>
|
||||
#include "position.h"
|
||||
|
||||
#if MSDOS_COMPILER
|
||||
#include <dos.h>
|
||||
#if MSDOS_COMPILER==WIN32C && defined(MINGW)
|
||||
#include <direct.h>
|
||||
#define setdisk(n) _chdrive((n)+1)
|
||||
#else
|
||||
#ifdef _MSC_VER
|
||||
#include <direct.h>
|
||||
#define setdisk(n) _chdrive((n)+1)
|
||||
#else
|
||||
#include <dir.h>
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
extern int screen_trashed;
|
||||
extern IFILE curr_ifile;
|
||||
|
||||
|
||||
#if HAVE_SYSTEM
|
||||
|
||||
/*
|
||||
* Pass the specified command to a shell to be executed.
|
||||
* Like plain "system()", but handles resetting terminal modes, etc.
|
||||
*/
|
||||
public void lsystem(char *cmd, char *donemsg)
|
||||
{
|
||||
int inp;
|
||||
#if HAVE_SHELL
|
||||
char *shell;
|
||||
char *p;
|
||||
#endif
|
||||
IFILE save_ifile;
|
||||
#if MSDOS_COMPILER && MSDOS_COMPILER!=WIN32C
|
||||
char cwd[FILENAME_MAX+1];
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Print the command which is to be executed,
|
||||
* unless the command starts with a "-".
|
||||
*/
|
||||
if (cmd[0] == '-')
|
||||
cmd++;
|
||||
else
|
||||
{
|
||||
clear_bot();
|
||||
putstr("!");
|
||||
putstr(cmd);
|
||||
putstr("\n");
|
||||
}
|
||||
|
||||
#if MSDOS_COMPILER
|
||||
#if MSDOS_COMPILER==WIN32C
|
||||
if (*cmd == '\0')
|
||||
cmd = getenv("COMSPEC");
|
||||
#else
|
||||
/*
|
||||
* Working directory is global on MSDOS.
|
||||
* The child might change the working directory, so we
|
||||
* must save and restore CWD across calls to "system",
|
||||
* or else we won't find our file when we return and
|
||||
* try to "reedit_ifile" it.
|
||||
*/
|
||||
getcwd(cwd, FILENAME_MAX);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Close the current input file.
|
||||
*/
|
||||
save_ifile = save_curr_ifile();
|
||||
(void) edit_ifile(NULL_IFILE);
|
||||
|
||||
/*
|
||||
* De-initialize the terminal and take out of raw mode.
|
||||
*/
|
||||
deinit();
|
||||
flush(); /* Make sure the deinit chars get out */
|
||||
raw_mode(0);
|
||||
#if MSDOS_COMPILER==WIN32C
|
||||
close_getchr();
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Restore signals to their defaults.
|
||||
*/
|
||||
init_signals(0);
|
||||
|
||||
#if HAVE_DUP
|
||||
/*
|
||||
* Force standard input to be the user's terminal
|
||||
* (the normal standard input), even if less's standard input
|
||||
* is coming from a pipe.
|
||||
*/
|
||||
inp = dup(0);
|
||||
close(0);
|
||||
#if !MSDOS_COMPILER
|
||||
if (open_tty() < 0)
|
||||
#endif
|
||||
dup(inp);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Pass the command to the system to be executed.
|
||||
* If we have a SHELL environment variable, use
|
||||
* <$SHELL -c "command"> instead of just <command>.
|
||||
* If the command is empty, just invoke a shell.
|
||||
*/
|
||||
#if HAVE_SHELL
|
||||
p = NULL;
|
||||
if ((shell = lgetenv("SHELL")) != NULL && *shell != '\0')
|
||||
{
|
||||
if (*cmd == '\0')
|
||||
p = save(shell);
|
||||
else
|
||||
{
|
||||
char *esccmd = shell_quote(cmd);
|
||||
if (esccmd != NULL)
|
||||
{
|
||||
int len = (int) (strlen(shell) + strlen(esccmd) + 5);
|
||||
p = (char *) ecalloc(len, sizeof(char));
|
||||
SNPRINTF3(p, len, "%s %s %s", shell, shell_coption(), esccmd);
|
||||
free(esccmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (p == NULL)
|
||||
{
|
||||
if (*cmd == '\0')
|
||||
p = save("sh");
|
||||
else
|
||||
p = save(cmd);
|
||||
}
|
||||
system(p);
|
||||
free(p);
|
||||
#else
|
||||
#if MSDOS_COMPILER==DJGPPC
|
||||
/*
|
||||
* Make stdin of the child be in cooked mode.
|
||||
*/
|
||||
setmode(0, O_TEXT);
|
||||
/*
|
||||
* We don't need to catch signals of the child (it
|
||||
* also makes trouble with some DPMI servers).
|
||||
*/
|
||||
__djgpp_exception_toggle();
|
||||
system(cmd);
|
||||
__djgpp_exception_toggle();
|
||||
#else
|
||||
system(cmd);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if HAVE_DUP
|
||||
/*
|
||||
* Restore standard input, reset signals, raw mode, etc.
|
||||
*/
|
||||
close(0);
|
||||
dup(inp);
|
||||
close(inp);
|
||||
#endif
|
||||
|
||||
#if MSDOS_COMPILER==WIN32C
|
||||
open_getchr();
|
||||
#endif
|
||||
init_signals(1);
|
||||
raw_mode(1);
|
||||
if (donemsg != NULL)
|
||||
{
|
||||
putstr(donemsg);
|
||||
putstr(" (press RETURN)");
|
||||
get_return();
|
||||
putchr('\n');
|
||||
flush();
|
||||
}
|
||||
init();
|
||||
screen_trashed = 1;
|
||||
|
||||
#if MSDOS_COMPILER && MSDOS_COMPILER!=WIN32C
|
||||
/*
|
||||
* Restore the previous directory (possibly
|
||||
* changed by the child program we just ran).
|
||||
*/
|
||||
chdir(cwd);
|
||||
#if MSDOS_COMPILER != DJGPPC
|
||||
/*
|
||||
* Some versions of chdir() don't change to the drive
|
||||
* which is part of CWD. (DJGPP does this in chdir.)
|
||||
*/
|
||||
if (cwd[1] == ':')
|
||||
{
|
||||
if (cwd[0] >= 'a' && cwd[0] <= 'z')
|
||||
setdisk(cwd[0] - 'a');
|
||||
else if (cwd[0] >= 'A' && cwd[0] <= 'Z')
|
||||
setdisk(cwd[0] - 'A');
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Reopen the current input file.
|
||||
*/
|
||||
reedit_ifile(save_ifile);
|
||||
|
||||
#if defined(SIGWINCH) || defined(SIGWIND)
|
||||
/*
|
||||
* Since we were ignoring window change signals while we executed
|
||||
* the system command, we must assume the window changed.
|
||||
* Warning: this leaves a signal pending (in "sigs"),
|
||||
* so psignals() should be called soon after lsystem().
|
||||
*/
|
||||
winch(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if PIPEC
|
||||
|
||||
/*
|
||||
* Pipe a section of the input file into the given shell command.
|
||||
* The section to be piped is the section "between" the current
|
||||
* position and the position marked by the given letter.
|
||||
*
|
||||
* If the mark is after the current screen, the section between
|
||||
* the top line displayed and the mark is piped.
|
||||
* If the mark is before the current screen, the section between
|
||||
* the mark and the bottom line displayed is piped.
|
||||
* If the mark is on the current screen, or if the mark is ".",
|
||||
* the whole current screen is piped.
|
||||
*/
|
||||
public int pipe_mark(int c, char *cmd)
|
||||
{
|
||||
POSITION mpos, tpos, bpos;
|
||||
|
||||
/*
|
||||
* mpos = the marked position.
|
||||
* tpos = top of screen.
|
||||
* bpos = bottom of screen.
|
||||
*/
|
||||
mpos = markpos(c);
|
||||
if (mpos == NULL_POSITION)
|
||||
return (-1);
|
||||
tpos = position(TOP);
|
||||
if (tpos == NULL_POSITION)
|
||||
tpos = ch_zero();
|
||||
bpos = position(BOTTOM);
|
||||
|
||||
if (c == '.')
|
||||
return (pipe_data(cmd, tpos, bpos));
|
||||
else if (mpos <= tpos)
|
||||
return (pipe_data(cmd, mpos, bpos));
|
||||
else if (bpos == NULL_POSITION)
|
||||
return (pipe_data(cmd, tpos, bpos));
|
||||
else
|
||||
return (pipe_data(cmd, tpos, mpos));
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a pipe to the given shell command.
|
||||
* Feed it the file contents between the positions spos and epos.
|
||||
*/
|
||||
public int pipe_data(char *cmd, POSITION spos, POSITION epos)
|
||||
{
|
||||
FILE *f;
|
||||
int c;
|
||||
|
||||
/*
|
||||
* This is structured much like lsystem().
|
||||
* Since we're running a shell program, we must be careful
|
||||
* to perform the necessary deinitialization before running
|
||||
* the command, and reinitialization after it.
|
||||
*/
|
||||
if (ch_seek(spos) != 0)
|
||||
{
|
||||
error("Cannot seek to start position", NULL_PARG);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if ((f = popen(cmd, "w")) == NULL)
|
||||
{
|
||||
error("Cannot create pipe", NULL_PARG);
|
||||
return (-1);
|
||||
}
|
||||
clear_bot();
|
||||
putstr("!");
|
||||
putstr(cmd);
|
||||
putstr("\n");
|
||||
|
||||
deinit();
|
||||
flush();
|
||||
raw_mode(0);
|
||||
init_signals(0);
|
||||
#if MSDOS_COMPILER==WIN32C
|
||||
close_getchr();
|
||||
#endif
|
||||
#ifdef SIGPIPE
|
||||
LSIGNAL(SIGPIPE, SIG_IGN);
|
||||
#endif
|
||||
|
||||
c = EOI;
|
||||
while (epos == NULL_POSITION || spos++ <= epos)
|
||||
{
|
||||
/*
|
||||
* Read a character from the file and give it to the pipe.
|
||||
*/
|
||||
c = ch_forw_get();
|
||||
if (c == EOI)
|
||||
break;
|
||||
if (putc(c, f) == EOF)
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Finish up the last line.
|
||||
*/
|
||||
while (c != '\n' && c != EOI )
|
||||
{
|
||||
c = ch_forw_get();
|
||||
if (c == EOI)
|
||||
break;
|
||||
if (putc(c, f) == EOF)
|
||||
break;
|
||||
}
|
||||
|
||||
pclose(f);
|
||||
|
||||
#ifdef SIGPIPE
|
||||
LSIGNAL(SIGPIPE, SIG_DFL);
|
||||
#endif
|
||||
#if MSDOS_COMPILER==WIN32C
|
||||
open_getchr();
|
||||
#endif
|
||||
init_signals(1);
|
||||
raw_mode(1);
|
||||
init();
|
||||
screen_trashed = 1;
|
||||
#if defined(SIGWINCH) || defined(SIGWIND)
|
||||
/* {{ Probably don't need this here. }} */
|
||||
winch(0);
|
||||
#endif
|
||||
return (0);
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue