mirror of
https://github.com/RTimothyEdwards/magic.git
synced 2026-09-01 10:39:43 +02:00
Added a ARG_UNUSED macro in utils/magic.h, which produces a simple cast to void to silence the warnings. The reasons this is used as opposed to an attribute is that most compilers should support this. Besides this, the macro can be easily searched for in the future to potentially remove (where possible) the unused parameters.
1469 lines
38 KiB
C
1469 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;
|
|
|
|
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);
|
|
}
|