1470 lines
38 KiB
C
1470 lines
38 KiB
C
/*
|
|
* txInput.c --
|
|
*
|
|
* Handles 'stdin' and terminal driver settings.
|
|
*
|
|
* *********************************************************************
|
|
* * Copyright (C) 1985, 1990 Regents of the University of California. *
|
|
* * Permission to use, copy, modify, and distribute this *
|
|
* * software and its documentation for any purpose and without *
|
|
* * fee is hereby granted, provided that the above copyright *
|
|
* * notice appear in all copies. The University of California *
|
|
* * makes no representations about the suitability of this *
|
|
* * software for any purpose. It is provided "as is" without *
|
|
* * express or implied warranty. Export of this software outside *
|
|
* * of the United States of America may require an export license. *
|
|
* *********************************************************************
|
|
*/
|
|
|
|
#ifndef lint
|
|
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/textio/txInput.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
|
|
#endif /* not lint */
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#ifdef HAVE_SYS_TIME_H
|
|
#include <sys/time.h>
|
|
#endif
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
#include <ctype.h>
|
|
#include <dirent.h>
|
|
|
|
|
|
#include "utils/magsgtty.h"
|
|
#include "utils/magic.h"
|
|
#include "utils/magsgtty.h"
|
|
#include "utils/main.h"
|
|
#include "textio/textio.h"
|
|
#include "utils/geometry.h"
|
|
#include "textio/txcommands.h"
|
|
#include "textio/textioInt.h"
|
|
#include "utils/dqueue.h"
|
|
#include "utils/macros.h"
|
|
#include "utils/hash.h"
|
|
#include "tiles/tile.h"
|
|
#include "database/database.h"
|
|
#include "windows/windows.h"
|
|
#include "graphics/graphics.h"
|
|
#include "database/databaseInt.h"
|
|
#include "cif/CIFint.h"
|
|
#include "cif/CIFread.h"
|
|
|
|
/* C99 compat */
|
|
#include "utils/malloc.h"
|
|
|
|
#ifdef USE_READLINE
|
|
#ifdef HAVE_READLINE
|
|
#include <readline/readline.h>
|
|
#include <readline/history.h>
|
|
#else
|
|
#include "readline/readline/readline.h"
|
|
#include "readline/readline/history.h"
|
|
#endif
|
|
|
|
int TxPrefix(void);
|
|
|
|
/* Globally keep track of the imacro string, if any; */
|
|
/* the readline callback takes no parameters. */
|
|
const char *_rl_prefix;
|
|
|
|
/* Custom completer function */
|
|
char **magic_completion_function(const char *, int, int);
|
|
|
|
/* match generators */
|
|
char *list_completion_function(const char *, int);
|
|
char *macro_completion_function(const char *, int);
|
|
char *cellname_completion_function(const char *, int);
|
|
char *istyle_completion_function(const char *, int);
|
|
char *ostyle_completion_function(const char *, int);
|
|
|
|
/* match list generators */
|
|
void make_techtype_list(void);
|
|
void update_cellname_hash(void);
|
|
|
|
const char * const *completion_list;
|
|
const char * const *magic_command_list = (const char **)NULL;
|
|
const char * const *magic_techtype_list = (const char **)NULL;
|
|
HashTable cellname_hash;
|
|
|
|
static int interactive_flag;
|
|
|
|
const char *magic_direction_list[] = {
|
|
"bottom", "down", "e", "east", "left", "n", "north", "right",
|
|
"s", "south", "top", "up", "w", "west", (char *)NULL };
|
|
|
|
#define COMMAND_COMPL 0
|
|
#define MACRO_COMPL 1
|
|
#define IMACRO_COMPL 2
|
|
#define LAYER_COMPL 3
|
|
#define PLANE_COMPL 4
|
|
#define FILE_COMPL 5
|
|
#define CELL_COMPL 6
|
|
#define ARGS_COMPL 7
|
|
#define ISTYLE_COMPL 8
|
|
#define OSTYLE_COMPL 9
|
|
#define DIRECT_COMPL 10
|
|
|
|
/* Can only accommodate 32 arg options, increase as necessary */
|
|
static const struct cmd_spec {
|
|
const char *cmd;
|
|
int type;
|
|
const char *args[32];
|
|
} magic_cmd_spec[] = {
|
|
{ "", COMMAND_COMPL, {NULL} },
|
|
{ "help", COMMAND_COMPL, {NULL} },
|
|
|
|
{ "shell", FILE_COMPL, {NULL} },
|
|
{ "addpath", FILE_COMPL, {NULL} },
|
|
{ "path", FILE_COMPL, {NULL} },
|
|
{ "logcommands", FILE_COMPL, {NULL} },
|
|
{ "startrsim", FILE_COMPL, {NULL} },
|
|
{ "rsim", FILE_COMPL, {NULL} },
|
|
{ "source", FILE_COMPL, {NULL} },
|
|
{ "save", FILE_COMPL, {NULL} },
|
|
|
|
{ "getcell", CELL_COMPL, {NULL} },
|
|
{ "child", CELL_COMPL, {NULL} },
|
|
{ "parent", CELL_COMPL, {NULL} },
|
|
{ "dump", CELL_COMPL, {NULL} },
|
|
{ "list", CELL_COMPL, {NULL} },
|
|
{ "load", CELL_COMPL, {NULL} },
|
|
{ "xload", CELL_COMPL, {NULL} },
|
|
|
|
{ "macro", MACRO_COMPL, {NULL} },
|
|
{ "imacro", IMACRO_COMPL, {NULL} },
|
|
{ "see*", LAYER_COMPL, {NULL} },
|
|
{ "paint", LAYER_COMPL, {NULL} },
|
|
|
|
{ "*extract", ARGS_COMPL, {"clrdebug", "clrlength", "driver", "interactions",
|
|
"intercount", "parents", "receiver", "setdebug",
|
|
"showdebug", "showparents", "showtech", "stats",
|
|
"step", "times", NULL} },
|
|
|
|
{ "*garoute", ARGS_COMPL, {"clrdebug", "setdebug", "showdebug", NULL} },
|
|
{ "*groute", ARGS_COMPL, {"clrdebug", "onlynet", "setdebug", "showdebug",
|
|
"sides", NULL} },
|
|
{ "*iroute", ARGS_COMPL, {"debug", "help", "parms", NULL} },
|
|
{ "*malloc", ARGS_COMPL, {"all", "off", "on", "only", "watch", "unwatch", NULL} },
|
|
{ "*mzroute", ARGS_COMPL, {"debug", "dumpEstimates", "dumpTags", "help",
|
|
"numberLine", "parms", "plane", "version", NULL} },
|
|
|
|
{ "*plow", ARGS_COMPL, {"help", "clrdebug", "jogreduce", "lwidth", "lshadow",
|
|
"mergedown", "mergeup", "move", "outline", "plow",
|
|
"print", "random", "setdebug", "shadow", "showdebug",
|
|
"split", "techshow", "trail", "whenbot", "whentop",
|
|
"width", NULL} },
|
|
{ "*plow lwidth", LAYER_COMPL, { NULL } },
|
|
{ "*plow width", LAYER_COMPL, { NULL } },
|
|
{ "*plow lshadow", LAYER_COMPL, { NULL } },
|
|
{ "*plow shadow", LAYER_COMPL, { NULL } },
|
|
{ "*plow techshow", FILE_COMPL, { NULL } },
|
|
{ "*plow outline", DIRECT_COMPL, { NULL } },
|
|
{ "*plow plow", DIRECT_COMPL, { NULL } },
|
|
|
|
{ "*profile", ARGS_COMPL, {"on", "off", NULL} },
|
|
{ "*watch", PLANE_COMPL, {NULL} },
|
|
{ "*watch*", ARGS_COMPL, {"demo", "types", NULL} },
|
|
|
|
{ "calma", ARGS_COMPL, {"help", "flatten", "labels", "lower", "noflatten",
|
|
"nolabels", "nolower", "read", "write", NULL} },
|
|
{ "calma read", FILE_COMPL, { NULL } },
|
|
{ "calma write", FILE_COMPL, { NULL } },
|
|
|
|
{ "cif", ARGS_COMPL, {"help", "arealabels", "idcell", "istyle", "prefix",
|
|
"ostyle", "read", "see", "statistics", "write", "flat", NULL} },
|
|
{ "cif read", FILE_COMPL, { NULL } },
|
|
{ "cif flat", FILE_COMPL, { NULL } },
|
|
{ "cif write", FILE_COMPL, { NULL } },
|
|
{ "cif idcell", ARGS_COMPL, { "yes", "no", NULL } },
|
|
{ "cif arealabels", ARGS_COMPL, { "yes", "no", NULL } },
|
|
{ "cif prefix", FILE_COMPL, { NULL } },
|
|
{ "cif see", LAYER_COMPL, { NULL } },
|
|
{ "cif istyle", ISTYLE_COMPL, { NULL } },
|
|
{ "cif ostyle", OSTYLE_COMPL, { NULL } },
|
|
|
|
{ "copy", DIRECT_COMPL, { NULL } },
|
|
{ "move", DIRECT_COMPL, { NULL } },
|
|
{ "stretch", DIRECT_COMPL, { NULL } },
|
|
|
|
{ "drc", ARGS_COMPL, {"help", "catchup", "check", "count", "find", "off",
|
|
"on", "printrules", "rulestats", "statistics", "why", NULL} },
|
|
{ "drc printrules", FILE_COMPL, { NULL } },
|
|
|
|
{ "ext", ARGS_COMPL, {"help", "all", "cell", "do", "length", "no", "parents",
|
|
"showparents", "style", "unique", "warn", NULL} },
|
|
{ "ext style", OSTYLE_COMPL, { NULL } },
|
|
|
|
{ "feedback", ARGS_COMPL, {"help", "add", "clear", "count", "find", "save",
|
|
"why", "fill", NULL} },
|
|
{ "feedback save", FILE_COMPL, { NULL } },
|
|
|
|
{ "garoute", ARGS_COMPL, {"help", "channel", "generate", "nowarn", "route",
|
|
"reset", "warn", NULL} },
|
|
{ "getnode", ARGS_COMPL, {"alias", "fast", "abort", NULL} },
|
|
|
|
{ "iroute", ARGS_COMPL, {"help", "contacts", "layers", "route",
|
|
"saveParameters", "search", "spacings", "verbosity",
|
|
"version", "wizard", NULL} },
|
|
{ "iroute help", ARGS_COMPL, {"contacts", "layers", "route",
|
|
"saveParameters", "search", "spacings", "verbosity",
|
|
"version", "wizard", NULL} },
|
|
|
|
{ "plot", ARGS_COMPL, {"help", "postscript", "gremlin", "versatec", "pnm",
|
|
"parameters", NULL} },
|
|
{ "plot postscript", FILE_COMPL, { NULL } },
|
|
{ "plot gremlin", FILE_COMPL, { NULL } },
|
|
{ "plot versatec", FILE_COMPL, { NULL } },
|
|
{ "plot pnm", FILE_COMPL, { NULL } },
|
|
|
|
{ "plow", ARGS_COMPL, {"help", "boundary", "horizon", "jogs", "selection",
|
|
"straighten", "noboundary", "nojogs", "nostraighten", NULL} },
|
|
{ "plow selection", DIRECT_COMPL, { NULL } },
|
|
|
|
{ "route", ARGS_COMPL, {"help", "end", "jog", "metal", "netlist", "obstacle",
|
|
"origin", "stats", "settings", "steady", "tech",
|
|
"vias", "viamin", NULL} },
|
|
{ "route netlist", FILE_COMPL, { NULL } },
|
|
|
|
{ "select", ARGS_COMPL, {"help", "more", "less", "area", "visible", "cell",
|
|
"clear", "save", "box", NULL} },
|
|
{ "select save", FILE_COMPL, { NULL } },
|
|
{ "select more", ARGS_COMPL, { "area", "visible", "cell", "box", NULL } },
|
|
{ "select less", ARGS_COMPL, { "area", "visible", "cell", "box", NULL } },
|
|
{ "select more area", LAYER_COMPL, { NULL } },
|
|
{ "select less area", LAYER_COMPL, { NULL } },
|
|
{ "select more visible", LAYER_COMPL, { NULL } },
|
|
{ "select less visible", LAYER_COMPL, { NULL } },
|
|
{ "select more cell", CELL_COMPL, { NULL } },
|
|
{ "select less cell", CELL_COMPL, { NULL } },
|
|
{ "select more box", LAYER_COMPL, { NULL } },
|
|
{ "select less box", LAYER_COMPL, { NULL } },
|
|
|
|
{ "send", ARGS_COMPL, {"netlist", "color", "layout",
|
|
#ifdef THREE_D
|
|
"wind3d",
|
|
#endif
|
|
NULL} },
|
|
{ "snap", ARGS_COMPL, {"on", "off", NULL} },
|
|
{ "tool", ARGS_COMPL, {"box", "wiring", "netlist", "rsim", NULL} },
|
|
{ "wire", ARGS_COMPL, {"help", "horizontal", "leg", "switch", "type",
|
|
"vertical", NULL} },
|
|
{ "wire type", LAYER_COMPL, { NULL } },
|
|
{ "wire switch", LAYER_COMPL, { NULL } },
|
|
|
|
#ifdef USE_READLINE
|
|
{ "history", ARGS_COMPL, {"n", "r", "help", NULL} },
|
|
#endif
|
|
{ NULL , 0, {NULL} }
|
|
};
|
|
#endif /* USE_READLINE */
|
|
|
|
|
|
/* Characters for input processing. Set to -1 if not defined */
|
|
|
|
char *TxGetLinePfix(char *dest, int maxChars, const char *prefix);
|
|
|
|
char txEraseChar = -1; /* Erase line (e.g. ^H) */
|
|
char txKillChar = -1; /* Kill line (e.g. ^U or ^X) */
|
|
char txWordChar = -1; /* Erase a word (e.g. ^W) */
|
|
char txReprintChar = -1; /* Reprint the line (e.g. ^R */
|
|
char txLitChar = -1; /* Literal next character (e.g. ^V */
|
|
char txBreakChar = -1; /* Break to a new line (normally -1) */
|
|
char TxEOFChar = -1; /* The current EOF character (e.g. ^D) */
|
|
char TxInterruptChar = -1; /* The current interrupt character (e.g. ^C) */
|
|
|
|
static char txPromptChar; /* the current prompt */
|
|
bool txHavePrompt = FALSE; /* is a prompt on the screen? */
|
|
|
|
static const char *txReprint1 = NULL;
|
|
static const char *txReprint2 = NULL;
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* TxReprint --
|
|
*
|
|
* Reprint the current input line. Used for ^R and after ^Z.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side Effects:
|
|
* None.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
TxReprint(void)
|
|
{
|
|
(void) txFprintfBasic(stdout, "\n");
|
|
if (txReprint1 != NULL) (void) txFprintfBasic(stdout, "%s", txReprint1);
|
|
if (txReprint2 != NULL) (void) txFprintfBasic(stdout, "%s", txReprint2);
|
|
(void) fflush(stdout);
|
|
}
|
|
|
|
#ifndef MAGIC_WRAPPER
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
* TxDialog --
|
|
*
|
|
* Interactive input with a prompt and a fixed set of responses
|
|
*
|
|
* Results:
|
|
* Returns the index of the response chosen. If no response is given,
|
|
* returns the default value.
|
|
*
|
|
* Side effects:
|
|
* Terminal input and output (stdout, stdin).
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
TxDialog(
|
|
const char *prompt,
|
|
const char * const *responses,
|
|
int deflt)
|
|
{
|
|
int code;
|
|
int maxresp;
|
|
char ans[100];
|
|
|
|
/* Find size of valid response set */
|
|
for (maxresp = 0; responses[maxresp] != NULL; maxresp++);
|
|
|
|
/* Get input until something matches one of the responses */
|
|
do
|
|
{
|
|
TxPrintf("%s ", prompt);
|
|
if ((deflt >= 0) && (deflt < maxresp))
|
|
TxPrintf("[%s] ", responses[deflt]);
|
|
TxFlushOut();
|
|
|
|
if (TxGetLine(ans, sizeof ans) == NULL || (ans[0] == '\0'))
|
|
{
|
|
code = deflt;
|
|
break;
|
|
}
|
|
} while ((code = Lookup(ans, responses)) < 0);
|
|
|
|
return code;
|
|
}
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
* TxSetPrompt --
|
|
*
|
|
* Set the current prompt.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* You can guess.
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
TxSetPrompt(
|
|
char ch)
|
|
{
|
|
txPromptChar = ch;
|
|
}
|
|
|
|
#endif /* !MAGIC_WRAPPER */
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
* TxPrompt --
|
|
*
|
|
* Put up the prompt which was set by TxSetPrompt.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* You can guess.
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
TxPrompt(void)
|
|
{
|
|
static char lastPromptChar;
|
|
static char prompts[2];
|
|
|
|
if (txHavePrompt && (lastPromptChar == txPromptChar)) return;
|
|
|
|
(void) fflush(stderr);
|
|
if (txHavePrompt) TxUnPrompt();
|
|
|
|
prompts[0] = txPromptChar;
|
|
prompts[1] = '\0';
|
|
|
|
txReprint1 = prompts;
|
|
if (TxInteractive) txFprintfBasic(stdout, "%s", txReprint1);
|
|
(void) fflush(stdout);
|
|
txHavePrompt = TRUE;
|
|
lastPromptChar = txPromptChar;
|
|
}
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
* TxRestorePrompt --
|
|
*
|
|
* The prompt was erased for some reason. Restore it.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* You can guess.
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
TxRestorePrompt(void)
|
|
{
|
|
if (txHavePrompt)
|
|
{
|
|
txHavePrompt = FALSE;
|
|
TxPrompt();
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
* TxUnPrompt --
|
|
*
|
|
* Erase the prompt.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* You can guess.
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
|
|
void
|
|
TxUnPrompt(void)
|
|
{
|
|
int i, tlen;
|
|
|
|
if (txHavePrompt)
|
|
{
|
|
(void) fflush(stderr);
|
|
if (TxInteractive)
|
|
{
|
|
tlen = strlen(txReprint1);
|
|
for (i = 0; i < tlen; i++)
|
|
fputc('\b', stdout);
|
|
for (i = 0; i < tlen; i++)
|
|
fputc(' ', stdout);
|
|
for (i = 0; i < tlen; i++)
|
|
fputc('\b', stdout);
|
|
}
|
|
(void) fflush(stdout);
|
|
txReprint1 = NULL;
|
|
txHavePrompt = FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* TxGetChar --
|
|
*
|
|
* Get a single character from the input stream (terminal or whatever).
|
|
*
|
|
* Results:
|
|
* One character, or EOF.
|
|
*
|
|
* Side Effects:
|
|
* None.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
TxGetChar(void)
|
|
{
|
|
int ch;
|
|
extern DQueue txInputEvents, txFreeEvents;
|
|
extern TxInputEvent txLastEvent;
|
|
TxInputEvent *event;
|
|
while (TRUE) {
|
|
/* Get an input character. Don't let TxGetInputEvent return
|
|
* because of a SigWinch or whatever. It would be nice to process
|
|
* SigWinches in a middle of text input, but that is difficult
|
|
* to do since SigWinches are processed in the normal
|
|
* command-interpretation process. Thus, we delay the processing
|
|
* until after the text is collected.
|
|
*/
|
|
if (DQIsEmpty(&txInputEvents)) TxGetInputEvent(TRUE, FALSE);
|
|
event = (TxInputEvent *) DQPopFront(&txInputEvents);
|
|
ASSERT(event != NULL, "TxGetChar");
|
|
txLastEvent = *event;
|
|
if (event->txe_button == TX_EOF) {
|
|
ch = EOF;
|
|
goto gotone;
|
|
}
|
|
if (event->txe_button == TX_CHARACTER) {
|
|
ch = TranslateChar(event->txe_ch);
|
|
goto gotone;
|
|
}
|
|
DQPushRear(&txFreeEvents, (ClientData) event);
|
|
}
|
|
|
|
gotone:
|
|
DQPushRear(&txFreeEvents, (ClientData) event);
|
|
return ch;
|
|
}
|
|
|
|
|
|
#ifdef USE_READLINE
|
|
#undef free
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
* TxPrefix --
|
|
* Instantiation of the readline function *rl_pre_input_hook(), executed
|
|
* between the prompt and the input (readline v4.1). Prepends the text
|
|
* of an interactive macro (if non-NULL) to the command line.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
int
|
|
TxPrefix(void)
|
|
{
|
|
if (_rl_prefix != NULL)
|
|
rl_insert_text(_rl_prefix);
|
|
rl_redisplay();
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* magic_completion_function --
|
|
*
|
|
* Command-name completion function for use with "readline" package.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
char **
|
|
magic_completion_function(
|
|
const char *text,
|
|
int start,
|
|
int end)
|
|
{
|
|
CPFunction *completion_func = (CPFunction *)NULL;
|
|
char **matches, **tokens;
|
|
char *line = strdup(rl_line_buffer);
|
|
int i;
|
|
|
|
for (i = start; i >= 0; i--)
|
|
if( isspace(line[i]) || line[i] == ';' )
|
|
break;
|
|
line[i+1] = '\0';
|
|
|
|
if ((tokens = history_tokenize(line)) != NULL )
|
|
{
|
|
int entry, start_token, num_tokens;
|
|
|
|
num_tokens = 0;
|
|
while (tokens[num_tokens] != (char *)NULL )
|
|
num_tokens++;
|
|
|
|
for (start_token = num_tokens - 1; start_token >= 0; start_token--)
|
|
if (tokens[start_token][0] == ';')
|
|
break;
|
|
|
|
start_token++;
|
|
|
|
line[0] = '\0';
|
|
for (i = start_token; i < num_tokens; i++)
|
|
{
|
|
strcat(line, tokens[i]);
|
|
if (i < (num_tokens - 1))
|
|
strcat(line, " ");
|
|
}
|
|
|
|
entry = LookupStructFull(line, (const char * const *)&magic_cmd_spec,
|
|
sizeof(struct cmd_spec));
|
|
|
|
if (entry == -1 && num_tokens >= 1)
|
|
{
|
|
sprintf(line, "%s*", tokens[0]);
|
|
entry = LookupStructFull(line, (const char * const *)&magic_cmd_spec,
|
|
sizeof(struct cmd_spec));
|
|
}
|
|
|
|
if (entry >= 0)
|
|
{
|
|
switch (magic_cmd_spec[entry].type)
|
|
{
|
|
case COMMAND_COMPL:
|
|
completion_func = list_completion_function;
|
|
completion_list = magic_command_list;
|
|
break;
|
|
case MACRO_COMPL:
|
|
completion_func = macro_completion_function;
|
|
interactive_flag = 0;
|
|
break;
|
|
case IMACRO_COMPL:
|
|
completion_func = macro_completion_function;
|
|
interactive_flag = 1;
|
|
break;
|
|
case LAYER_COMPL:
|
|
completion_func = list_completion_function;
|
|
if (magic_techtype_list == NULL)
|
|
make_techtype_list();
|
|
completion_list = magic_techtype_list;
|
|
break;
|
|
case PLANE_COMPL:
|
|
completion_func = list_completion_function;
|
|
completion_list = DBPlaneLongNameTbl;
|
|
break;
|
|
case FILE_COMPL:
|
|
completion_func = (text[0] == '~') ?
|
|
rl_username_completion_function :
|
|
rl_filename_completion_function;
|
|
break;
|
|
case CELL_COMPL:
|
|
update_cellname_hash();
|
|
completion_func = cellname_completion_function;
|
|
break;
|
|
case ARGS_COMPL:
|
|
completion_func = list_completion_function;
|
|
completion_list = magic_cmd_spec[entry].args;
|
|
break;
|
|
case ISTYLE_COMPL:
|
|
completion_func = istyle_completion_function;
|
|
break;
|
|
case OSTYLE_COMPL:
|
|
completion_func = ostyle_completion_function;
|
|
break;
|
|
case DIRECT_COMPL:
|
|
completion_func = list_completion_function;
|
|
completion_list = magic_direction_list;
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < num_tokens; i++)
|
|
free(tokens[i]);
|
|
|
|
free(tokens);
|
|
|
|
}
|
|
else
|
|
{
|
|
completion_func = list_completion_function;
|
|
completion_list = magic_command_list;
|
|
}
|
|
|
|
free(line);
|
|
|
|
matches = (completion_func) ? rl_completion_matches(text, completion_func)
|
|
: (char **)NULL;
|
|
|
|
/* If we match nothing, inhibit any matching, except when matching files */
|
|
|
|
rl_attempted_completion_over = (matches == (char **)NULL &&
|
|
completion_func != rl_username_completion_function &&
|
|
completion_func != rl_filename_completion_function);
|
|
return matches;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* update_cellname_hash --
|
|
*
|
|
* Update the hash table of cell names so it can be used by the
|
|
* cellname completion function.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
void
|
|
update_cellname_hash(void)
|
|
{
|
|
extern char *Path;
|
|
const char *path = Path;
|
|
char *dirname = strdup(Path);
|
|
|
|
while (nextName(&path, "", dirname, strlen(Path)))
|
|
{
|
|
DIR *dir;
|
|
|
|
if (strlen(dirname) == 0)
|
|
strcpy(dirname, ".");
|
|
|
|
dir = opendir(dirname);
|
|
|
|
if (dir != NULL)
|
|
{
|
|
struct dirent *dirent;
|
|
while ((dirent = readdir(dir)) != (struct dirent *)NULL)
|
|
{
|
|
char *base;
|
|
if ((base = (char *)strstr(dirent->d_name, DBSuffix))
|
|
!= (char *)NULL && base[strlen(DBSuffix)] == '\0')
|
|
{
|
|
*base = '\0';
|
|
if (strlen(dirent->d_name) > 0)
|
|
HashFind(&cellname_hash, dirent->d_name);
|
|
}
|
|
}
|
|
closedir(dir);
|
|
}
|
|
}
|
|
free(dirname);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* istyle_completion_function --
|
|
*
|
|
* CIF input style completion function for use with "readline" package.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
char *
|
|
istyle_completion_function(
|
|
const char *text,
|
|
int state)
|
|
{
|
|
extern CIFReadKeep *cifReadStyleList;
|
|
static CIFReadKeep *style;
|
|
static int len;
|
|
|
|
if (state == 0)
|
|
{
|
|
style = cifReadStyleList;
|
|
len = strlen(text);
|
|
}
|
|
|
|
for (; style != NULL; style = style->crs_next)
|
|
{
|
|
if (strncmp(style->crs_name, text, len) == 0)
|
|
{
|
|
char *name = style->crs_name;
|
|
style = style->crs_next;
|
|
return strdup(name);
|
|
}
|
|
}
|
|
return (char *)NULL;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* ostyle_completion_function --
|
|
*
|
|
* CIF output style completion function for use with "readline" package.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
char *
|
|
ostyle_completion_function(
|
|
const char *text,
|
|
int state)
|
|
{
|
|
extern CIFKeep *CIFStyleList;
|
|
static CIFKeep *style;
|
|
static int len;
|
|
|
|
if (state == 0)
|
|
{
|
|
style = CIFStyleList;
|
|
len = strlen(text);
|
|
}
|
|
|
|
for (; style != NULL; style = style->cs_next)
|
|
{
|
|
if (strncmp(style->cs_name, text, len) == 0)
|
|
{
|
|
char *name = style->cs_name;
|
|
style = style->cs_next;
|
|
return strdup(name);
|
|
}
|
|
}
|
|
return (char *)NULL;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* cellname_completion_function --
|
|
*
|
|
name completion function for use with "readline" package.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
char *
|
|
cellname_completion_function(
|
|
const char *text,
|
|
int state)
|
|
{
|
|
extern HashTable dbCellDefTable;
|
|
static int len;
|
|
static HashSearch hs, db_hs;
|
|
HashEntry *he;
|
|
|
|
if (state == 0)
|
|
{
|
|
len = strlen(text);
|
|
HashStartSearch(&hs);
|
|
HashStartSearch(&db_hs);
|
|
}
|
|
|
|
while ((he = HashNext(&cellname_hash, &hs)) != (HashEntry *)NULL )
|
|
{
|
|
if (strncmp(he->h_key.h_name, text, len) == 0)
|
|
return strdup(he->h_key.h_name);
|
|
}
|
|
|
|
/* Also complete cells that are in main memory only */
|
|
|
|
while ((he = HashNext(&dbCellDefTable, &db_hs)) != (HashEntry *)NULL)
|
|
{
|
|
CellDef *cd = (CellDef *)HashGetValue(he);
|
|
if (cd && !(cd->cd_flags & CDINTERNAL)
|
|
&& strcmp(cd->cd_name, UNNAMED) != 0
|
|
&& strncmp(cd->cd_name, text, len) == 0)
|
|
return strdup(cd->cd_name);
|
|
}
|
|
return (char *)NULL;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* macro_completion_function --
|
|
*
|
|
* Macro completion function for use with "readline" package.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
char *
|
|
macro_completion_function(
|
|
const char *text,
|
|
int state)
|
|
{
|
|
extern HashTable MacroClients;
|
|
static HashSearch hs, mc_hs;
|
|
static int len;
|
|
macrodef *macro;
|
|
HashEntry *he;
|
|
|
|
if (state == 0)
|
|
{
|
|
len = strlen(text);
|
|
HashStartSearch(&hs);
|
|
}
|
|
|
|
while ((he = HashNext(&MacroClients, &hs)) != (HashEntry *)NULL )
|
|
{
|
|
HashTable *ht = (HashTable *)HashGetValue(he);
|
|
HashEntry *hm;
|
|
|
|
if (state == 0)
|
|
HashStartSearch(&mc_hs);
|
|
|
|
while ((hm = HashNext(ht, &mc_hs)) != (HashEntry *)NULL )
|
|
{
|
|
macro = (macrodef *)HashGetValue(hm);
|
|
if ((macro->interactive == TRUE && interactive_flag == 1) ||
|
|
(macro->interactive == FALSE && interactive_flag == 0))
|
|
{
|
|
char *macro_name = MacroName(macro->macrotext);
|
|
if (strncmp(macro_name, text, len) == 0)
|
|
return strdup(macro_name);
|
|
}
|
|
}
|
|
}
|
|
return (char *)NULL;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* list_completion_function --
|
|
*
|
|
* List completion function for use with "readline" package.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
char *
|
|
list_completion_function(
|
|
const char *text,
|
|
int state)
|
|
{
|
|
static int list_index, len;
|
|
const char *match;
|
|
|
|
/* If this is a new word to complete, initialize now. This includes
|
|
* saving the length of TEXT for efficiency, and initializing the index
|
|
* variable to 0.
|
|
*/
|
|
|
|
if (state == 0)
|
|
{
|
|
list_index = 0;
|
|
len = strlen(text);
|
|
}
|
|
|
|
/* Return the next name which partially matches from the command list. */
|
|
|
|
while ((match = completion_list[list_index]) != (char *)NULL)
|
|
{
|
|
list_index++;
|
|
|
|
if (strncmp(match, text, len) == 0)
|
|
return strdup(match);
|
|
}
|
|
return (char *)NULL;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* make_techtype_list --
|
|
*
|
|
* Generate list of predefined types for use with completion function
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
void
|
|
make_techtype_list(void)
|
|
{
|
|
int i, techdep_layers = DBNumUserLayers - TT_TECHDEPBASE;
|
|
|
|
const char **tmp = (const char **)mallocMagic(sizeof(char *)
|
|
* (techdep_layers + 8 + 2 + 1));
|
|
|
|
for (i = 0; i < techdep_layers; i++)
|
|
tmp[i] = DBTypeLongNameTbl[i+TT_TECHDEPBASE];
|
|
|
|
tmp[i++] = "magnet";
|
|
tmp[i++] = "fence";
|
|
tmp[i++] = "rotate";
|
|
tmp[i++] = "subcircuit";
|
|
tmp[i++] = "$";
|
|
tmp[i++] = "*";
|
|
tmp[i++] = "errors";
|
|
tmp[i++] = "labels";
|
|
tmp[i++] = "subcell";
|
|
|
|
tmp[i++] = "no";
|
|
tmp[i++] = "allSame";
|
|
|
|
tmp[i] = NULL;
|
|
|
|
magic_techtype_list = tmp; /* (const char * const *) */
|
|
}
|
|
|
|
#define free You_should_use_the_Magic_procedure_freeMagic
|
|
#endif /* USE_READLINE */
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* TxGetLineWPrompt --
|
|
*
|
|
* Just like the following TxGetLine proc, but it prompts first. It
|
|
* is an advantage to have this proc put out the prompt, since that
|
|
* way if the user suspends Magic and then continues it the prompt will
|
|
* reappear in the proper fashion.
|
|
*
|
|
* Results:
|
|
* A char pointer or NULL (see TxGetLine).
|
|
*
|
|
* Side Effects:
|
|
* None.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
char *
|
|
TxGetLineWPrompt(
|
|
char *dest,
|
|
int maxChars,
|
|
const char *prompt,
|
|
const char *prefix)
|
|
{
|
|
char *res, *hist_res, *tmp;
|
|
int return_nothing = 0;
|
|
|
|
if (txHavePrompt) TxUnPrompt();
|
|
#ifndef USE_READLINE
|
|
/* without GNU readline */
|
|
|
|
if (prompt != NULL) TxPrintf("%s", prompt);
|
|
txReprint1 = prompt;
|
|
|
|
res = TxGetLinePfix(&dest[0], maxChars, prefix);
|
|
txReprint1 = NULL;
|
|
#else
|
|
_rl_prefix = prefix;
|
|
TxResetTerminal (FALSE);
|
|
|
|
if (prompt != NULL) {
|
|
res = readline (prompt);
|
|
} else {
|
|
res = readline (TX_CMD_PROMPT);
|
|
}
|
|
|
|
hist_res = (char *)NULL;
|
|
|
|
if (res && *res && !StrIsWhite(res, FALSE) ) {
|
|
/* The history_expand() function from Readline can return 4 values: */
|
|
/* -1 - There was an error in expansion. Command not added to history. */
|
|
/* This is the same behavior as tcsh. */
|
|
/* 0 - No expansion possible. Just a normal command. Add command to history, */
|
|
/* return and execute. */
|
|
/* 1 - Expansion took place. Assign $command to expansion and proceed. */
|
|
/* 2 - Expansion took place (eg. :p modifier was used). Display exspansion */
|
|
/* but don't execute. Expanded command implicitly added to history by */
|
|
/* history_expand(). */
|
|
switch( history_expand(res, &hist_res) ) {
|
|
case -1:
|
|
TxError("%s\n", hist_res);
|
|
return_nothing = 1;
|
|
break;
|
|
case 0:
|
|
add_history(res);
|
|
break;
|
|
case 1:
|
|
tmp = res;
|
|
res = hist_res;
|
|
hist_res = tmp;
|
|
add_history(res);
|
|
break;
|
|
case 2:
|
|
TxPrintf("%s\n", hist_res);
|
|
return_nothing = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (res) {
|
|
if (strlen (res) >= maxChars) {
|
|
TxPrintf ("WARNING: input string too long; truncated");
|
|
res[maxChars-1] = '\0';
|
|
}
|
|
if( return_nothing ) {
|
|
dest[0] = '\0';
|
|
} else {
|
|
strcpy (dest, res);
|
|
}
|
|
#undef free
|
|
free (res);
|
|
if( hist_res != (char *)NULL ) free(hist_res);
|
|
#define free You_should_use_the_Magic_procedure_freeMagic
|
|
res = dest;
|
|
}
|
|
TxSetTerminal ();
|
|
#endif /* USE_READLINE */
|
|
return res;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
char *
|
|
TxGetLinePrompt(
|
|
char *dest,
|
|
int maxChars,
|
|
const char *prompt)
|
|
{
|
|
return TxGetLineWPrompt(dest, maxChars, prompt, NULL);
|
|
}
|
|
|
|
#ifndef MAGIC_WRAPPER
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
* TxGetLinePfix:
|
|
*
|
|
* Reads a line from the input queue (terminal or whatever).
|
|
*
|
|
* Results:
|
|
* A char pointer to the string is returned.
|
|
* If an end-of-file is typed, returns (char *) NULL and
|
|
* stores in the string any characters recieved up to that point.
|
|
*
|
|
* Side effects:
|
|
* The input stream is read, and 'dest' is filled in with up to maxChars-1
|
|
* characters. Up to maxChars of the 'dest' may be changed during the
|
|
* input process, however, since a '\0' is added at the end. There is no
|
|
* newline at the end of 'dest'.
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
char *
|
|
TxGetLinePfix(
|
|
char *dest,
|
|
int maxChars,
|
|
const char *prefix)
|
|
{
|
|
int i;
|
|
char *ret;
|
|
int ch;
|
|
bool literal;
|
|
|
|
if (maxChars < 1) return dest;
|
|
if (txHavePrompt) TxUnPrompt();
|
|
ret = dest;
|
|
dest[0] = '\0';
|
|
txReprint2 = dest;
|
|
|
|
#define TX_ERASE() ( (i>0) ?(i--, TxPrintf("\b \b"), 0) :0)
|
|
|
|
(void) fflush(stderr);
|
|
literal = FALSE;
|
|
i = 0;
|
|
if (prefix != NULL)
|
|
{
|
|
while (prefix[i] != '\0') {
|
|
if (i >= maxChars - 1) break;
|
|
dest[i] = prefix[i];
|
|
txFprintfBasic(stdout, "%c", prefix[i]);
|
|
i++;
|
|
}
|
|
}
|
|
while (TRUE) {
|
|
dest[i] = '\0';
|
|
if (i >= maxChars - 1) break;
|
|
(void) fflush(stdout);
|
|
ch = TxGetChar();
|
|
if (ch == EOF || ch == -1 || ch == TxEOFChar) {
|
|
TxError("\nEOF encountered on input stream.\n");
|
|
ret = NULL;
|
|
break;
|
|
} else if (literal) {
|
|
literal = FALSE;
|
|
dest[i] = ch;
|
|
txFprintfBasic(stdout, "%c", ch);
|
|
i++;
|
|
} else if (ch == '\n' || ch == txBreakChar) {
|
|
break;
|
|
} else if (ch == '\t') {
|
|
while (TRUE) {
|
|
dest[i] = ' ';
|
|
txFprintfBasic(stdout, " ");
|
|
i++;
|
|
if (((i + strlen(txReprint1)) % 8) == 0) break;
|
|
}
|
|
} else if (ch == txEraseChar) {
|
|
TX_ERASE();
|
|
} else if (ch == txKillChar) {
|
|
while (i > 0) TX_ERASE();
|
|
} else if (ch == txWordChar) {
|
|
while (i > 0 && isspace(dest[i-1])) TX_ERASE();
|
|
while (i > 0 && !isspace(dest[i-1])) TX_ERASE();
|
|
} else if (ch == txReprintChar) {
|
|
TxReprint();
|
|
} else if (ch == txLitChar) {
|
|
literal = TRUE;
|
|
} else {
|
|
dest[i] = ch;
|
|
txFprintfBasic(stdout, "%c", ch);
|
|
i++;
|
|
}
|
|
}
|
|
txFprintfBasic(stdout, "\n");
|
|
txHavePrompt = FALSE;
|
|
txReprint2 = NULL;
|
|
|
|
return ret;
|
|
}
|
|
|
|
#endif /* !MAGIC_WRAPPER */
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
* TxGetLine:
|
|
*/
|
|
|
|
char *
|
|
TxGetLine(
|
|
char *dest,
|
|
int maxChars)
|
|
{
|
|
return TxGetLinePfix(dest, maxChars, NULL);
|
|
}
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
* txGetTermState:
|
|
*
|
|
* Read the state of the terminal and driver.
|
|
*
|
|
* Results:
|
|
* none.
|
|
*
|
|
* Side effects:
|
|
* The passed structure is filled in.
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
#if defined(SYSV) || defined(CYGWIN)
|
|
|
|
void
|
|
txGetTermState(
|
|
struct termio *buf)
|
|
{
|
|
ioctl( fileno( stdin ), TCGETA, buf);
|
|
}
|
|
|
|
#elif defined (__OpenBSD__) || defined(EMSCRIPTEN)
|
|
|
|
void
|
|
txGetTermState(
|
|
struct termios *buf)
|
|
{
|
|
(void) tcgetattr(fileno(stdin), buf);
|
|
}
|
|
|
|
#else
|
|
|
|
void
|
|
txGetTermState(
|
|
txTermState *buf)
|
|
{
|
|
ASSERT(TxStdinIsatty, "txGetTermState");
|
|
/* save the current terminal characteristics */
|
|
(void) ioctl(fileno(stdin), TIOCGETP, (char *) &(buf->tx_i_sgtty) );
|
|
(void) ioctl(fileno(stdin), TIOCGETC, (char *) &(buf->tx_i_tchars) );
|
|
}
|
|
#endif /* SYSV */
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
* txSetTermState:
|
|
*
|
|
* Set the state of the terminal and driver.
|
|
*
|
|
* Results:
|
|
* none.
|
|
*
|
|
* Side effects:
|
|
* The terminal driver is set up.
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
txSetTermState(
|
|
#if defined(SYSV) || defined(CYGWIN)
|
|
struct termio *buf
|
|
#elif defined (__OpenBSD__) || defined(EMSCRIPTEN)
|
|
struct termios *buf
|
|
#else
|
|
txTermState *buf
|
|
#endif /* SYSV */
|
|
)
|
|
{
|
|
#if defined(SYSV) || defined(CYGWIN)
|
|
ioctl( fileno(stdin), TCSETAF, buf );
|
|
#elif defined (__OpenBSD__) || defined(EMSCRIPTEN)
|
|
(void) tcsetattr( fileno(stdin), TCSANOW, buf );
|
|
#else
|
|
/* set the current terminal characteristics */
|
|
(void) ioctl(fileno(stdin), TIOCSETN, (char *) &(buf->tx_i_sgtty) );
|
|
(void) ioctl(fileno(stdin), TIOCSETC, (char *) &(buf->tx_i_tchars) );
|
|
#endif /* SYSV */
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
* txInitTermRec:
|
|
*
|
|
* Sets the terminal record that it has echo turned off,
|
|
* cbreak on, and no EOFs the way we like it.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* The passed terminal record is modified.
|
|
* No terminal modes are actually changed.
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
txInitTermRec(
|
|
#if defined(SYSV) || defined(CYGWIN)
|
|
struct termio *buf
|
|
#elif defined (__OpenBSD__) || defined(EMSCRIPTEN)
|
|
struct termios *buf
|
|
#else
|
|
txTermState *buf
|
|
#endif /* SYSV */
|
|
)
|
|
{
|
|
#if defined(SYSV) || defined(CYGWIN) || defined(__OpenBSD__) || defined(EMSCRIPTEN)
|
|
buf->c_lflag = ISIG; /* raw: no echo and no processing, allow signals */
|
|
buf->c_cc[ VMIN ] = 1;
|
|
buf->c_cc[ VTIME ] = 0;
|
|
#else
|
|
/* set things up for us, turn off echo, turn on cbreak, no EOF */
|
|
buf->tx_i_sgtty.sg_flags |= CBREAK;
|
|
buf->tx_i_sgtty.sg_flags &= ~ECHO;
|
|
buf->tx_i_tchars.t_eofc = -1;
|
|
|
|
#endif /* SYSV */
|
|
}
|
|
|
|
|
|
|
|
#if defined(SYSV) || defined(CYGWIN)
|
|
struct termio closeTermState;
|
|
#elif defined (__OpenBSD__) || defined(EMSCRIPTEN)
|
|
struct termios closeTermState;
|
|
#else
|
|
static txTermState closeTermState;
|
|
#endif /* SYSV */
|
|
|
|
static bool haveCloseState = FALSE;
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
* txSaveTerm:
|
|
*
|
|
* Save the terminal characteristics so they can be restored when
|
|
* magic leaves.
|
|
*
|
|
*
|
|
* Results:
|
|
* none.
|
|
*
|
|
* Side effects:
|
|
* a global variable is set.
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
txSaveTerm(void)
|
|
{
|
|
#if defined(SYSV) || defined(CYGWIN)
|
|
ioctl( fileno( stdin ), TCGETA, &closeTermState);
|
|
txEraseChar = closeTermState.c_cc[VERASE];
|
|
txKillChar = closeTermState.c_cc[VKILL];
|
|
TxEOFChar = closeTermState.c_cc[VEOF];
|
|
TxInterruptChar = closeTermState.c_cc[VINTR];
|
|
haveCloseState = TRUE;
|
|
#elif defined (__OpenBSD__) || defined(EMSCRIPTEN)
|
|
(void) tcgetattr( fileno( stdin ), &closeTermState);
|
|
txEraseChar = closeTermState.c_cc[VERASE];
|
|
txKillChar = closeTermState.c_cc[VKILL];
|
|
TxEOFChar = closeTermState.c_cc[VEOF];
|
|
TxInterruptChar = closeTermState.c_cc[VINTR];
|
|
haveCloseState = TRUE;
|
|
#else
|
|
struct ltchars lt;
|
|
txGetTermState(&closeTermState);
|
|
(void) ioctl(fileno(stdin), TIOCGLTC, (char *) <);
|
|
txEraseChar = closeTermState.tx_i_sgtty.sg_erase;
|
|
txKillChar = closeTermState.tx_i_sgtty.sg_kill;
|
|
txWordChar = lt.t_werasc;
|
|
txReprintChar = lt.t_rprntc;
|
|
txLitChar = lt.t_lnextc;
|
|
txBreakChar = closeTermState.tx_i_tchars.t_brkc;
|
|
TxEOFChar = closeTermState.tx_i_tchars.t_eofc;
|
|
TxInterruptChar = closeTermState.tx_i_tchars.t_intrc;
|
|
haveCloseState = TRUE;
|
|
#endif /* SYSV */
|
|
}
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
* TxSetTerminal:
|
|
*
|
|
* Sets the terminal up the way we like it.
|
|
*
|
|
* Results:
|
|
* none.
|
|
*
|
|
* Side effects:
|
|
* The terminal modes are changed.
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
TxSetTerminal(void)
|
|
{
|
|
#if defined(SYSV) || defined(CYGWIN)
|
|
struct termio buf;
|
|
#elif defined (__OpenBSD__) || defined(EMSCRIPTEN)
|
|
struct termios buf;
|
|
#else
|
|
txTermState buf;
|
|
#endif /* SYSV */
|
|
|
|
#ifdef MAGIC_WRAPPER
|
|
/* If using Tk console, don't mess with the terminal settings; */
|
|
/* Otherwise, this prevents running magic in the terminal background. */
|
|
if (TxTkConsole) return;
|
|
#endif
|
|
|
|
if (TxStdinIsatty)
|
|
{
|
|
if (!haveCloseState) txSaveTerm();
|
|
buf = closeTermState;
|
|
txInitTermRec(&buf);
|
|
txSetTermState(&buf);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
* TxResetTerminal:
|
|
*
|
|
* Returns the terminal to the way it was when Magic started up.
|
|
*
|
|
* 'force' maybe set for atexit() restoration, when the console
|
|
* input handler is no longer in effect. Also crash handling, SIGSTOP.
|
|
*
|
|
* Results:
|
|
* none.
|
|
*
|
|
* Side effects:
|
|
* The terminal modes are changed.
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
TxResetTerminal(
|
|
bool force)
|
|
{
|
|
#ifdef MAGIC_WRAPPER
|
|
/* If using Tk console, don't mess with the terminal settings; */
|
|
/* Otherwise, this prevents running magic in the terminal background. */
|
|
if (TxTkConsole && !force) return;
|
|
#endif
|
|
|
|
if (TxStdinIsatty && haveCloseState) txSetTermState(&closeTermState);
|
|
}
|