mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-21 20:33:55 +00:00
232 lines
6.5 KiB
C
232 lines
6.5 KiB
C
// vim: ts=4 sw=4 expandtab ft=c
|
|
|
|
// Copyright (C) 1998-2002, 2005-2007 The University of Melbourne.
|
|
// Copyright (C) 2014-2016, 2018 The Mercury team.
|
|
// This file is distributed under the terms specified in COPYING.LIB.
|
|
|
|
// A simple interface to read a line, normally done using GNU readline.
|
|
//
|
|
// Main authors: fjh, zs.
|
|
|
|
#include "mercury_imp.h"
|
|
#include "mercury_array_macros.h"
|
|
#include "mercury_memory.h"
|
|
#include "mercury_std.h"
|
|
#include "mercury_wrapper.h"
|
|
|
|
#include "mercury_trace_readline.h"
|
|
#include "mercury_trace_completion.h"
|
|
|
|
#if defined(MR_USE_READLINE) || defined(MR_USE_EDITLINE)
|
|
#if defined(MR_HAVE_READLINE_READLINE_H)
|
|
#include <readline/readline.h>
|
|
#elif defined(MR_HAVE_EDITLINE_READLINE_H)
|
|
#include <editline/readline.h>
|
|
#else
|
|
extern FILE *rl_instream;
|
|
extern FILE *rl_outstream;
|
|
extern char (*rl_completion_entry_function)(const char *, int);
|
|
extern const char *rl_readline_name;
|
|
extern void (*rl_prep_term_function)(int);
|
|
extern void (*rl_deprep_term_function)(void);
|
|
#endif
|
|
#ifdef MR_HAVE_READLINE_HISTORY_H
|
|
#include <readline/history.h>
|
|
#endif
|
|
#ifdef MR_HAVE_UNISTD_H
|
|
#include <unistd.h> // for isatty()
|
|
#endif
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
// The initial size of the array of characters used to hold the line.
|
|
#define MR_INIT_BUF_LEN 80
|
|
|
|
static void MR_dummy_prep_term_function(int ignored);
|
|
static void MR_dummy_deprep_term_function(void);
|
|
|
|
char *
|
|
MR_trace_readline(const char *prompt, FILE *in, FILE *out)
|
|
{
|
|
#if (defined(isatty) || defined(MR_HAVE_ISATTY)) \
|
|
&& (defined(fileno) || defined(MR_HAVE_FILENO)) \
|
|
&& (defined(MR_USE_READLINE) || defined(MR_USE_EDITLINE))
|
|
char *line;
|
|
MR_bool in_isatty;
|
|
char *last_nl;
|
|
|
|
in_isatty = isatty(fileno(in));
|
|
if (in_isatty || MR_force_readline) {
|
|
rl_instream = in;
|
|
rl_outstream = out;
|
|
|
|
// The cast to (void *) silences a spurious "assignment from
|
|
// incompatible pointer type" warning (old versions of readline
|
|
// are very sloppy about declaring the types of function pointers).
|
|
|
|
rl_completion_entry_function = (void *) &MR_trace_line_completer;
|
|
rl_readline_name = (char *) "mdb";
|
|
|
|
if (!in_isatty) {
|
|
// This is necessary for tests/debugger/completion, otherwise
|
|
// we get lots of messages about readline not being able to get
|
|
// the terminal settings. This is possibly a bit flaky, but it is
|
|
// only used by our tests.
|
|
|
|
rl_prep_term_function = (void *) MR_dummy_prep_term_function;
|
|
rl_deprep_term_function = (void *) MR_dummy_deprep_term_function;
|
|
}
|
|
|
|
// If the prompt contains newlines then readline doesn't
|
|
// display it properly.
|
|
|
|
last_nl = strrchr(prompt, '\n');
|
|
if (last_nl != NULL) {
|
|
char *real_prompt;
|
|
char *pre_prompt;
|
|
|
|
real_prompt = (char *) MR_malloc(strlen(last_nl));
|
|
strcpy(real_prompt, last_nl + 1);
|
|
pre_prompt = (char *) MR_malloc(last_nl - prompt + 2);
|
|
strncpy(pre_prompt, prompt, last_nl - prompt + 1);
|
|
pre_prompt[last_nl - prompt + 1] = '\0';
|
|
fputs(pre_prompt, out);
|
|
line = readline((char *) real_prompt);
|
|
MR_free(real_prompt);
|
|
MR_free(pre_prompt);
|
|
} else {
|
|
line = readline((char *) prompt);
|
|
}
|
|
|
|
// readline() allocates with malloc(), and we want to return something
|
|
// allocated with MR_malloc(), but that's OK, because MR_malloc() and
|
|
// malloc() are interchangeable.
|
|
|
|
#if 0
|
|
{
|
|
char *tmp = line;
|
|
|
|
line = MR_copy_string(line);
|
|
free(tmp);
|
|
}
|
|
#endif
|
|
|
|
if (line != NULL && line[0] != '\0') {
|
|
add_history(line);
|
|
}
|
|
|
|
return line;
|
|
}
|
|
#endif // have isatty && have fileno && (have readline || have editline)
|
|
|
|
// Otherwise, don't use readline.
|
|
fprintf(out, "%s", prompt);
|
|
fflush(out);
|
|
return MR_trace_readline_raw(in);
|
|
}
|
|
|
|
char *
|
|
MR_trace_readline_raw(FILE *fp)
|
|
{
|
|
char *contents;
|
|
int content_max;
|
|
int c;
|
|
int i;
|
|
|
|
contents = NULL;
|
|
content_max = 0;
|
|
|
|
i = 0;
|
|
while ((c = getc(fp)) != EOF && c != '\n') {
|
|
MR_ensure_big_enough(i, content, char, MR_INIT_BUF_LEN);
|
|
contents[i++] = c;
|
|
}
|
|
|
|
if (c == '\n' || i > 0) {
|
|
MR_ensure_big_enough(i, content, char, MR_INIT_BUF_LEN);
|
|
contents[i] = '\0';
|
|
return contents;
|
|
} else {
|
|
MR_free(contents);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
char *
|
|
MR_trace_readline_from_script(FILE *fp, char **args, int num_args)
|
|
{
|
|
char *line = NULL;
|
|
size_t line_length;
|
|
int line_index;
|
|
size_t expanded_line_length;
|
|
char *expanded_line;
|
|
int expanded_line_index;
|
|
int arg_num;
|
|
size_t arg_length;
|
|
char *arg;
|
|
|
|
do {
|
|
if (line != NULL) {
|
|
MR_free(line);
|
|
}
|
|
line = MR_trace_readline_raw(fp);
|
|
if (line == NULL) {
|
|
return NULL;
|
|
}
|
|
// Ignore lines starting with '#'.
|
|
|
|
} while (*line == '#');
|
|
|
|
line_length = strlen(line);
|
|
|
|
expanded_line_length = line_length;
|
|
expanded_line = (char*) MR_malloc(line_length + 1);
|
|
expanded_line[0] = '\0';
|
|
expanded_line_index = 0;
|
|
|
|
for (line_index = 0; line_index < line_length; line_index++) {
|
|
if ((line[line_index] == '$') &&
|
|
(line_index < (line_length - 1)) &&
|
|
(line[line_index + 1] >= '1') &&
|
|
(line[line_index + 1] <= '9'))
|
|
{
|
|
arg_num = (int)(line[line_index + 1] - '1');
|
|
if (arg_num < num_args) {
|
|
arg = args[arg_num];
|
|
arg_length = strlen(arg);
|
|
// Subtract 2 for the "$n" which will not occur
|
|
// in the expanded string.
|
|
|
|
expanded_line_length += arg_length - 2;
|
|
expanded_line = MR_realloc(expanded_line,
|
|
expanded_line_length + 1);
|
|
expanded_line[expanded_line_index] = '\0';
|
|
strcat(expanded_line, arg);
|
|
expanded_line_index += arg_length;
|
|
}
|
|
// Skip the digit after the '$'.
|
|
line_index++;
|
|
} else {
|
|
expanded_line[expanded_line_index] = line[line_index];
|
|
expanded_line_index++;
|
|
}
|
|
}
|
|
|
|
MR_free(line);
|
|
expanded_line[expanded_line_index] = '\0';
|
|
|
|
return expanded_line;
|
|
}
|
|
|
|
static void
|
|
MR_dummy_prep_term_function(int ignored)
|
|
{
|
|
}
|
|
|
|
static void
|
|
MR_dummy_deprep_term_function(void)
|
|
{
|
|
}
|