1
0
mirror of https://github.com/livingcomputermuseum/UniBone.git synced 2026-04-03 04:19:01 +00:00

DL11 / KW11 ZDLD and RSX11 OK

This commit is contained in:
Joerg Hoppe
2019-09-19 10:56:43 +02:00
parent e102425ebe
commit e46b26b497
8 changed files with 261 additions and 226 deletions

View File

@@ -346,13 +346,12 @@ void slu_c::on_init_changed(void) {
// background worker.
void slu_c::worker_rcv(void) {
timeout_c timeout;
int n;
unsigned char buffer[BUFLEN + 1];
rs232byte_t rcv_byte;
// poll with frequency > baudrate, to see single bits
//unsigned poll_periods_us = 1000000 / baudrate.value;
/* Receiver not time critical? UARTS are buffering
/* Receiver not time critical? UARTs are buffering
So if thread is swapped out and back a burst of characters appear.
-> Wait after each character for transfer time before polling
RS232 again.
@@ -361,7 +360,7 @@ void slu_c::worker_rcv(void) {
// poll a bit faster to be ahead of char stream.
// don't oversample: PDP-11 must process char in that time
// worker_init_realtime_priority(rt_device);
worker_init_realtime_priority(rt_device);
while (!workers_terminate) {
timeout.wait_us(poll_periods_us);
@@ -371,33 +370,14 @@ void slu_c::worker_rcv(void) {
// rcv_active: can only be set by polling the UART input GPIO pin?
// at the moments, it is only sent on maintenance loopback xmt
/* read serial data, if any */
if (rs232adapter.byte_rcv_poll(buffer)) {
if (rs232adapter.rs232byte_rcv_poll(&rcv_byte)) {
pthread_mutex_lock(&on_after_rcv_register_access_mutex); // signal changes atomic against UNIBUS accesses
rcv_or_err = rcv_fr_err = rcv_p_err = 0;
if (rcv_done) // not yet cleared? overrun!
rcv_or_err = 1;
if (buffer[0] == 0xff) {
/* How to receive framing and parity errors: see termios(3)
If IGNPAR=0, PARMRK=1: error on <char> received as \377 \0 <char>
\377 received as \377 \377
*/
n = rs232adapter.byte_rcv_poll(buffer);
assert(n); // next char after 0xff escape immediately available
if (buffer[0] == 0) { // error flags
rcv_fr_err = rcv_p_err = 1;
n = rs232adapter.byte_rcv_poll(buffer);
assert(n); // next char after 0xff 0 seq is data"
rcv_buffer = buffer[0];
} else if (buffer[0] == 0xff) { // enocoded 0xff
rcv_buffer = 0xff;
} else {
WARNING("Received 0xff <stray> seqeuence");
rcv_buffer = buffer[0];
}
} else
// received non escaped data byte
rcv_buffer = buffer[0];
rcv_buffer = rcv_byte.c;
if (rcv_byte.format_error)
rcv_fr_err = rcv_p_err = 1;
rcv_done = 1;
rcv_active = 0;
set_rbuf_dati_value();
@@ -413,7 +393,7 @@ void slu_c::worker_xmt(void) {
assert(!pthread_mutex_lock(&on_after_register_access_mutex));
// Transmitter not time critical
// worker_init_realtime_priority(rt_device);
worker_init_realtime_priority(rt_device);
while (!workers_terminate) {
// 1. wait for xmt signal
@@ -426,7 +406,10 @@ void slu_c::worker_xmt(void) {
}
// 2. transmit
rs232adapter.byte_xmt_send(xmt_buffer);
rs232byte_t xmt_byte;
xmt_byte.c = xmt_buffer;
xmt_byte.format_error = false;
rs232adapter.rs232byte_xmt_send(xmt_byte);
xmt_ready = 0;
set_xcsr_dati_value_and_INTR();
if (xmt_maint) { // loop back: simulate data byte coming in
@@ -442,7 +425,7 @@ void slu_c::worker_xmt(void) {
pthread_mutex_lock(&on_after_xmt_register_access_mutex);
if (xmt_maint)
// put sent byte into rcv buffer, receiver will poll it
rs232adapter.byte_loopback(xmt_buffer);
rs232adapter.rs232byte_loopback(xmt_byte);
xmt_ready = 1;
set_xcsr_dati_value_and_INTR();
@@ -478,9 +461,10 @@ ltc_c::ltc_c() :
reg_lks = &(this->registers[0]); // @ base addr
strcpy(reg_lks->name, "LKS"); // Line Clock Status Register
reg_lks->active_on_dati = false; // status polled by CPU, not active
// reg_lks->active_on_dati = true; // debugging
reg_lks->active_on_dato = true;
reg_lks->reset_value = 0;
reg_lks->writable_bits = LKS_INT_ENB; // interrupt enable
reg_lks->reset_value = LKS_INT_MON;
reg_lks->writable_bits = LKS_INT_ENB | LKS_INT_MON; // interrupt enable
// init parameters
frequency.value = 50;
@@ -488,7 +472,7 @@ ltc_c::ltc_c() :
// init controller state
intr_enable = 0;
intr_monitor = 0;
line_clock_monitor = 0;
}
ltc_c::~ltc_c() {
@@ -510,37 +494,23 @@ bool ltc_c::on_param_changed(parameter_c *param) {
return unibusdevice_c::on_param_changed(param); // more actions (for enable)
}
// calc static INTR condition level.
// Change of that condition calculated by intr_request_c.is_condition_raised()
// on raising edge.
bool ltc_c::get_intr_signal_level() {
return intr_monitor && intr_enable;
}
// set status register, and optionally generate INTR
// intr_raise: if inactive->active transition of interrupt condition detected.
void ltc_c::set_lks_dati_value_and_INTR(void) {
uint16_t val = (intr_monitor ? LKS_INT_MON : 0) | (intr_enable ? LKS_INT_ENB : 0);
switch (intr_request.edge_detect(get_intr_signal_level())) {
case intr_request_c::INTERRUPT_EDGE_RAISING:
void ltc_c::set_lks_dati_value_and_INTR(bool do_intr) {
uint16_t val = (line_clock_monitor ? LKS_INT_MON : 0) | (intr_enable ? LKS_INT_ENB : 0);
if (do_intr)
// set register atomically with INTR, if INTR not blocked
unibusadapter->INTR(intr_request, reg_lks, val);
break;
case intr_request_c::INTERRUPT_EDGE_FALLING:
// BR6 is tied to monitor and enable, so raised INTRs may get canceled
unibusadapter->cancel_INTR(intr_request);
else
// set unrelated to INTR condition
set_register_dati_value(reg_lks, val, __func__);
break;
default:
set_register_dati_value(reg_lks, val, __func__);
}
}
// process DATI/DATO access to one of my "active" registers
void ltc_c::on_after_register_access(unibusdevice_register_t *device_reg,
uint8_t unibus_control) {
pthread_mutex_lock(&on_after_register_access_mutex);
// not necessary, not harmful?
if (unibus_control == UNIBUS_CONTROL_DATO) // bus write
set_register_dati_value(device_reg, device_reg->active_dato_flipflops, __func__);
@@ -548,13 +518,19 @@ void ltc_c::on_after_register_access(unibusdevice_register_t *device_reg,
case 0: // LKS
if (unibus_control == UNIBUS_CONTROL_DATO) { // bus write
//DEBUG("LKS wrDATO, val = 0%6o", reg_lks->active_dato_flipflops) ;
intr_enable = !!(reg_lks->active_dato_flipflops & LKS_INT_ENB);
// schematic: INTERRUPT MONITOR can only be cleared
// schematic: LINE CLOCK MONITOR can only be cleared
if ((reg_lks->active_dato_flipflops & LKS_INT_MON) == 0)
intr_monitor = 0 ;
set_lks_dati_value_and_INTR();
}
break;
line_clock_monitor = 0;
if (!intr_enable || !line_clock_monitor) {
// BR6 is tied to monitor and enable, so raised INTRs may get canceled
unibusadapter->cancel_INTR(intr_request);
}
set_lks_dati_value_and_INTR(false); // INTR only by clock, not by LKs access
} else
//DEBUG("LKS DATI, control=%d, val = 0%6o = 0%6o", (int)unibus_control, reg_lks->active_dati_flipflops, device_reg->shared_register->value ) ;
break;
default:
break;
@@ -574,11 +550,12 @@ void ltc_c::on_init_changed(void) {
if (init_asserted) {
reset_unibus_registers();
intr_enable = 0;
intr_monitor = 1;
line_clock_monitor = 1;
intr_request.edge_detect_reset();
// INFO("ltc_c::on_init()");
}
/7 but edge_detect not used
// initial condition is "not signaled"
// INFO("ltc_c::on_init()");
}
}
/* background worker.
@@ -587,59 +564,60 @@ void ltc_c::on_init_changed(void) {
lost edges are compensated
*/
void ltc_c::worker(unsigned instance) {
UNUSED(instance); // only one
timeout_c global_time;
timeout_c timeout;
int64_t global_next_edge_ns;
UNUSED(instance); // only one
timeout_c global_time;
timeout_c timeout;
int64_t global_next_edge_ns;
INFO("KW11 time resolution is < %u us",
(unsigned )(global_time.get_resolution_ns() / 1000));
global_time.start_ns(0);
global_next_edge_ns = global_time.elapsed_ns();
uint64_t global_edge_count = 0;
while (!workers_terminate) {
// set prio to RT, but less than unibus_adapter
worker_init_realtime_priority(rt_device);
// signal egde period may change if 50/60 Hz is changed
uint64_t edge_period_ns = BILLION / (2 * frequency.value);
uint64_t wait_ns;
// overdue_ns: time which signal edge is too late
int64_t overdue_ns = (int64_t) global_time.elapsed_ns() - global_next_edge_ns;
// INFO does not work on 64 ints
// printf("elapsed [ms] =%u, overdue [us] =%u\n", (unsigned) global_time.elapsed_ms(), (unsigned) overdue_ns/1000) ;
// if overdue_ns positive, next signal edge should have occured
if (overdue_ns < 0) {
wait_ns = -overdue_ns; // wait until next edge time reached
} else {
// time for next signal edge reached
if (ltc_enable.value) {
global_edge_count++;
clock_signal = !clock_signal; // square wave
if (clock_signal) {
intr_monitor = 1;
pthread_mutex_lock(&on_after_register_access_mutex);
set_lks_dati_value_and_INTR();
pthread_mutex_unlock(&on_after_register_access_mutex);
}
} else
// clock disconnected
clock_signal = 0;
INFO("KW11 time resolution is < %u us", (unsigned )(global_time.get_resolution_ns() / 1000));
global_time.start_ns(0);
global_next_edge_ns = global_time.elapsed_ns();
uint64_t global_edge_count = 0;
while (!workers_terminate) {
// signal egde period may change if 50/60 Hz is changed
uint64_t edge_period_ns = BILLION / (2 * frequency.value);
uint64_t wait_ns;
// overdue_ns: time which signal edge is too late
int64_t overdue_ns = (int64_t) global_time.elapsed_ns() - global_next_edge_ns;
// INFO does not work on 64 ints
// printf("elapsed [ms] =%u, overdue [us] =%u\n", (unsigned) global_time.elapsed_ms(), (unsigned) overdue_ns/1000) ;
// if overdue_ns positive, next signal edge should have occured
if (overdue_ns < 0) {
wait_ns = -overdue_ns; // wait until next edge time reached
} else {
// time for next signal edge reached
if (ltc_enable.value) {
global_edge_count++;
clock_signal = !clock_signal; // square wave
if (clock_signal) {
line_clock_monitor = 1;
pthread_mutex_lock(&on_after_register_access_mutex);
set_lks_dati_value_and_INTR(intr_enable);
pthread_mutex_unlock(&on_after_register_access_mutex);
}
} else
// clock disconnected
clock_signal = 0;
// time of next signal edge
global_next_edge_ns += edge_period_ns;
// overdue_ns now time which next signal edge is too late
overdue_ns -= edge_period_ns;
// time of next signal edge
global_next_edge_ns += edge_period_ns;
// overdue_ns now time which next signal edge is too late
overdue_ns -= edge_period_ns;
if (overdue_ns < 0)
// next edge now in future: wait exact
wait_ns = -overdue_ns;
else
// next edge still in past:
// wait shorter than signal edge period to keep up slowly
wait_ns = edge_period_ns / 2;
//if ((global_edge_count % 100) == 0)
// INFO("LTC: %u secs by edges", (unsigned)(global_edge_count/100) ) ;
}
timeout.wait_ns(wait_ns);
if (overdue_ns < 0)
// next edge now in future: wait exact
wait_ns = -overdue_ns;
else
// next edge still in past:
// wait shorter than signal edge period to keep up slowly
wait_ns = edge_period_ns / 2;
//if ((global_edge_count % 100) == 0)
// INFO("LTC: %u secs by edges", (unsigned)(global_edge_count/100) ) ;
}
timeout.wait_ns(wait_ns);
}
}

View File

@@ -37,7 +37,6 @@ using namespace std;
#include "rs232.hpp"
#include "rs232adapter.hpp"
// socket console settings
//#define IP_PORT 5001
//#define IP_HOST "localhost"
@@ -103,7 +102,7 @@ private:
public:
rs232adapter_c rs232adapter; /// stream router
private:
private:
unibusdevice_register_t *reg_rcsr;
unibusdevice_register_t *reg_rbuf;
unibusdevice_register_t *reg_xcsr;
@@ -192,12 +191,13 @@ private:
// KW11 has one interrupt
intr_request_c intr_request = intr_request_c(this);
bool clock_signal; // value of 50Hz square wave signal
bool intr_enable; // interrupt enable, LKS bit 6
bool intr_monitor ; // LKS bit 7
bool line_clock_monitor; // LKS bit 7
bool clock_signal ; // square wave from pwower supply
bool get_intr_signal_level(void);
void set_lks_dati_value_and_INTR(void);
void set_lks_dati_value_and_INTR(bool do_intr);
public:

View File

@@ -37,8 +37,7 @@
. | +---> ringbuffer "PATTERN" .
. | | .
. | loopback | .
. rcv <----------|---< byte_loopback() .
. decoder | .
. rcv <-----------|---< char_loopback() .
. buffer | .
. | | .
. +-----<--------|---< rs232.Poll()---< RxD "RS232" .
@@ -66,7 +65,7 @@ rs232adapter_c::rs232adapter_c() {
stream_rcv = NULL;
stream_xmt = NULL;
rcv_termios_error_encoding = false;
rcv_decoder.clear();
rcvbuffer.clear();
pattern_stream_data[0] = 0;
pattern[0] = 0;
pattern_found = false;
@@ -79,56 +78,92 @@ rs232adapter_c::rs232adapter_c() {
// and 0xff 0xff for \ff
// If IGNPAR=0, PARMRK=1: error on <char> received as \377 \0 <char>
// \377 received as \377 \377
bool rs232adapter_c::byte_rcv_poll(unsigned char *rcvchar) {
// result: true if data received
bool rs232adapter_c::rs232byte_rcv_poll(rs232byte_t *rcvbyte) {
pthread_mutex_lock(&mutex);
bool result = false;
// mixing input streams, with RS232 priority
// if (baudrate != 0 && !rcv_baudrate_delay.reached())
// return result; // limit character rate
pthread_mutex_lock(&mutex);
// loopback or part of previous 0xff,0xff sequence ?
int c = rcv_decoder.get();
if (c != EOF) {
*rcvchar = c;
result = true;
result = !rcvbuffer.empty();
if (result) {
*rcvbyte = rcvbuffer.front();
rcvbuffer.pop_front();
}
if (!result && rs232) {
// rs2323 must be programmed to generate 0xff 0xff sequences
result = rs232->PollComport(rcvchar, 1);
// rs232 must be programmed to generate 0xff 0xff sequences
/* How to receive framing and parity errors: see termios(3)
If IGNPAR=0, PARMRK=1: error on <char> received as \377 \0 <char>
\377 received as \377 \377
*/
uint8_t c_raw;
rcvbyte->format_error = false; // default: no error info
int n = rs232->PollComport(&c_raw, 1);
if (rcv_termios_error_encoding && c_raw == 0xff) {
n = rs232->PollComport(&c_raw, 1);
assert(n); // next char after 0xff escape immediately available
if (c_raw == 0) { // error flags
rcvbyte->format_error = true;
n = rs232->PollComport(&c_raw, 1);
assert(n); // next char after 0xff 0 seq is data"
rcvbyte->c = c_raw;
} else if (c_raw == 0xff) { // enocoded 0xff
rcvbyte->c = 0xff;
} else {
WARNING("Received 0xff <stray> sequence");
rcvbyte->c = c_raw;
}
} else
// received non-escaped data byte
rcvbyte->c = c_raw;
result = (n > 0);
}
if (stream_rcv && !result) {
if (!result && stream_rcv) {
// deliver next char from stream delayed, with simulated baudrate
if (baudrate == 0 || rcv_baudrate_delay.reached()) {
int c = stream_rcv->get();
if (c != EOF) {
*rcvchar = c;
if (rcv_termios_error_encoding && c == 0xff) {
// mark 2nd 0xff for output on next call
rcv_decoder.clear();
rcv_decoder.put(0xff);
}
result = true;
if (baudrate != 0)
rcv_baudrate_delay.start_us(10 * MILLION / baudrate); // assume 10 bits per char
}
// if (baudrate == 0 || rcv_baudrate_delay.reached()) {
int c = stream_rcv->get();
if (c != EOF) {
rcvbyte->c = c;
rcvbyte->format_error = false;
result = true;
if (baudrate != 0)
rcv_baudrate_delay.start_us(10 * MILLION / baudrate); // assume 10 bits per char
}
// }
}
// if (result && baudrate != 0)
// rcv_baudrate_delay.start_us(10 * MILLION / baudrate); // assume 10 bits per char
// rcv_baudrate_delay.start_us(MILLION); // 1 sec delay
pthread_mutex_unlock(&mutex);
// if (result)
// printf("< %c\n", *rcvbyte) ;
return result;
}
void rs232adapter_c::byte_xmt_send(unsigned char xmtchar) {
void rs232adapter_c::rs232byte_xmt_send(rs232byte_t xmtbyte) {
// pthread_mutex_lock(&mutex);
// printf("%c >\n", xmtbyte) ;
if (rs232)
rs232->SendByte(xmtchar);
rs232->SendByte(xmtbyte.c);
if (stream_xmt)
stream_xmt->put(xmtchar);
stream_xmt->put(xmtbyte.c);
// pattern ring buffer
unsigned n = strlen(pattern);
if (n) {
// put new chars at end of string
unsigned m = strlen(pattern_stream_data);
assert(m < pattern_max_len);
pattern_stream_data[m] = xmtchar;
pattern_stream_data[m] = xmtbyte.c;
pattern_stream_data[m + 1] = 0;
// only keep the last chars in buffer.
while ((m = strlen(pattern_stream_data)) > n)
@@ -137,21 +172,22 @@ void rs232adapter_c::byte_xmt_send(unsigned char xmtchar) {
if (strstr(pattern_stream_data, pattern))
pattern_found = true; // user must clear
}
// pattern_buffer.
pthread_mutex_unlock(&mutex);
}
void rs232adapter_c::byte_loopback(unsigned char xmtchar) {
void rs232adapter_c::rs232byte_loopback(rs232byte_t xmtbyte) {
pthread_mutex_lock(&mutex);
// not a queue, only single char (DL11 loopback)
rcv_decoder.clear();
rcv_decoder.put(xmtchar);
if (rcv_termios_error_encoding && xmtchar == 0xff)
rcv_decoder.put(0xff);
// fill intermediate buffer with seqeunce to receive
// fill intermediate buffer with sequwnce to receive
rcvbuffer.push_back(xmtbyte);
pthread_mutex_unlock(&mutex);
}
void rs232adapter_c::set_pattern(char *pattern) {
pthread_mutex_lock(&mutex);
strncpy(this->pattern, pattern, pattern_max_len);
pattern_found = false;
pattern_stream_data[0] = 0;
pthread_mutex_unlock(&mutex);
}

View File

@@ -29,30 +29,39 @@
#include <ostream>
#include <istream>
#include <sstream>
#include <deque>
#include "utils.hpp"
#include "logsource.hpp"
#include "rs232.hpp"
// a character with additional transmission status
typedef struct {
uint8_t c; // 5/6/7/8 bit character
// framing and parity errors combined
bool format_error;
} rs232byte_t;
class rs232adapter_c: public logsource_c {
private:
// for loopback and to decode 0xff to 0xff,0xff
std::stringstream rcv_decoder;
std::deque<rs232byte_t> rcvbuffer;
// std::stringstream rcv_decoder;
// last sequence of xmt data for pattern matching
static const int pattern_max_len = 256 ;
char pattern[pattern_max_len+1]; // if != "", this is search for
char pattern_stream_data[pattern_max_len+1];
// last sequence of xmt data for pattern matching
static const int pattern_max_len = 256;
char pattern[pattern_max_len + 1]; // if != "", this is search for
char pattern_stream_data[pattern_max_len + 1];
// deliver rcv chars delayed by this "baudrate"
timeout_c rcv_baudrate_delay ;
timeout_c rcv_baudrate_delay;
public:
rs232adapter_c();
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
unsigned baudrate ; // deliver rcv chars throttled by this "baudrate"
unsigned baudrate; // deliver rcv chars throttled by this "baudrate"
// if true, an inject 0xff is delivered as 0xff,0xff.
// this is compatible with termios(3) encoding of error flags
@@ -64,9 +73,9 @@ public:
rs232_c *rs232; // if assigned, routing to initialized RS232 port
/*** BYTE interface ***/
bool byte_rcv_poll(unsigned char *rcvchar);
void byte_xmt_send(unsigned char xmtchar);
void byte_loopback(unsigned char xmtchar);
bool rs232byte_rcv_poll(rs232byte_t *rcvbyte);
void rs232byte_xmt_send(rs232byte_t xmtbyte);
void rs232byte_loopback(rs232byte_t xmtbyte);
/*** STREAM interface ***/
std::istream *stream_rcv; // users sets this to a stream which producess chars
@@ -78,7 +87,7 @@ public:
/*** PATTERN detection ***/
void set_pattern(char *pattern);
bool pattern_found; // switches ture on match, user must clear
bool pattern_found; // switches true on match, user must clear
};

View File

@@ -20,6 +20,7 @@
#include <string.h>
#include <assert.h>
#include "gpios.hpp" // debug pin
#include "unibus.h"
#include "unibusadapter.hpp"
#include "unibusdevice.hpp"

View File

@@ -1,6 +1,6 @@
/* inputline.c: Advanced routines for user text input
/* inputline.cpp: Advanced routines for user text input
Copyright (c) 2012-2016, Joerg Hoppe
Copyright (c) 2012-2019, Joerg Hoppe
j_hoppe@t-online.de, www.retrocmp.com
Permission is hereby granted, free of charge, to any person obtaining a
@@ -20,7 +20,7 @@
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
05-Sep-2019 JH C++, scripting
23-Feb-2012 JH created
@@ -36,7 +36,7 @@
#include <time.h>
#include "kbhit.h"
#include "inputline.h"
#include "inputline.hpp"
/*
* get input from user
@@ -66,14 +66,17 @@
*/
static FILE *inputline_file = NULL;
// reset input source and internal states
void inputline_init() {
void inputline_c::init() {
// close file, if open
if (inputline_file)
fclose(inputline_file);
inputline_file = NULL;
if (file)
fclose(file);
file = NULL;
}
bool inputline_c::openfile(char *filename) {
file = fopen(filename, "r");
return (file != NULL);
}
// check, if line contains an internal "inputlien" command
@@ -82,7 +85,7 @@ void inputline_init() {
// .print <text>
// result: true = internal command processed
// false = unkwown
static int inputline_internal(char *line) {
int inputline_c::internal(char *line) {
if (!strncasecmp(line, ".wait", 5)) {
struct timespec ts;
unsigned millis;
@@ -108,23 +111,23 @@ static int inputline_internal(char *line) {
return 1;
} else if (!strncasecmp(line, ".end", 3)) {
// close input file
fclose(inputline_file);
inputline_file = NULL;
fclose(file);
file = NULL;
return 1;
}
return 0;
}
char *inputline(char *buffer, int buffer_size, const char *prompt) {
char *inputline_c::readline(char *buffer, int buffer_size, const char *prompt) {
char *s;
if (inputline_file != NULL) {
if (file != NULL) {
// read from file
int ready = 0;
while (!ready && inputline_file != NULL) {
while (!ready && file != NULL) {
/*** read line from text file ***/
if (fgets(buffer, buffer_size, inputline_file) == NULL) {
fclose(inputline_file);
inputline_file = NULL; // file empty, or unreadable
if (fgets(buffer, buffer_size, file) == NULL) {
fclose(file);
file = NULL; // file empty, or unreadable
ready = 1;
} else {
// remove terminating "\n"
@@ -149,14 +152,14 @@ char *inputline(char *buffer, int buffer_size, const char *prompt) {
// if empty line: repeat
if (*buffer == 0)
continue;
if (!inputline_internal(buffer)) {
if (!internal(buffer)) {
printf("%s\n", buffer);
ready = 1;
}
}
}
}
if (inputline_file == NULL) {
if (file == NULL) {
/*** read interactive ***/
if (prompt && *prompt)
printf("%s", prompt);
@@ -169,8 +172,3 @@ char *inputline(char *buffer, int buffer_size, const char *prompt) {
return buffer;
}
bool inputline_fopen(char *filename) {
inputline_file = fopen(filename, "r");
return (inputline_file != NULL);
}

View File

@@ -1,36 +0,0 @@
/* inputline.h: Advanced routines for user text input
Copyright (c) 2012-2016, Joerg Hoppe
j_hoppe@t-online.de, www.retrocmp.com
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
JOERG HOPPE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23-Feb-2012 JH created
*/
#ifndef INPUTLINE_H_
#define INPUTLINE_H_
#include <stdbool.h>
void inputline_init(void) ;
bool inputline_fopen(char *filename) ;
char *inputline(char *buffer, int buffer_size, const char *prompt) ;
#endif /* INPUTLINE_H_ */

View File

@@ -0,0 +1,49 @@
/* inputline.hpp: Advanced routines for user text input
Copyright (c) 2012-2019, Joerg Hoppe
j_hoppe@t-online.de, www.retrocmp.com
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
JOERG HOPPE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
05-Sep-2019 JH C++, scripting
23-Feb-2012 JH created
*/
#ifndef INPUTLINE_HPP_
#define INPUTLINE_HPP_
#include <stdio.h>
#include <stdbool.h>
class inputline_c {
private:
FILE *file = NULL;
int internal(char *line);
public:
inputline_c() {
init();
}
void init(void);
bool openfile(char *filename);
char *readline(char *buffer, int buffer_size, const char *prompt);
};
#endif /* INPUTLINE_HPP_ */