aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Haberkorn <robin.haberkorn@googlemail.com>2025-03-29 06:19:21 +0300
committerRobin Haberkorn <robin.haberkorn@googlemail.com>2025-04-23 06:51:22 +0300
commit92f964701d55ae3a7c2060da3a78fe6d3b665bcb (patch)
tree4deb210d56a018259411b2fd5f79743698b6b69b
parent93f61120ddba2093d85dbd09dff2deb42f0393e2 (diff)
downloadvideoteco-fork-92f964701d55ae3a7c2060da3a78fe6d3b665bcb.tar.gz
MS-DOS real-mode (8086) port
It can be cross-compiled or compiled natively on 32-bit DOS with OpenWatcom C v1.9. Compiling on an 8086 might be possible later on - but we would have to add support for some ancient ANSI C compiler.
-rw-r--r--Makefile.wcc41
-rw-r--r--tecbuf.c8
-rw-r--r--teccmd.c32
-rw-r--r--tecmem.c2
-rw-r--r--teco.c90
-rw-r--r--teco.h52
-rw-r--r--tecparse.c17
-rw-r--r--tecterm.c45
8 files changed, 254 insertions, 33 deletions
diff --git a/Makefile.wcc b/Makefile.wcc
new file mode 100644
index 0000000..21d1b8e
--- /dev/null
+++ b/Makefile.wcc
@@ -0,0 +1,41 @@
+CC = $(%WATCOM)/binl64/wcc
+LD = $(%WATCOM)/binl64/wlink
+
+# For the fastest code (C Guide, p.70):
+# -onatx -oh -oi+ -ei -zp8 -0 -fpi87
+# Large data model: far code and data pointers
+!ifdef DEBUG
+# You can also -dDEBUG or even -dDEBUG1.
+CFLAGS = -d2
+#-dDEBUG1
+LDFLAGS = debug all
+!endif
+
+CFLAGS += -q -ze -j -os -0 -ml -bt=DOS @WCC_DEFS
+LDFLAGS += format dos option map option stack=16k &
+ libpath $(%WATCOM)/lib286:$(%WATCOM)/lib286/dos
+
+.BEFORE
+!ifndef %WATCOM
+ set WATCOM=/usr/bin/watcom
+!endif
+ set include=$(%WATCOM)/h
+ set lib=$(%WATCOM)/lib286;$(%WATCOM)/lib286/dos
+ set WCC_DEFS=-dSTDC_HEADERS=1 -dHAVE_STDIO_H -dHAVE_CTYPE_H -dHAVE_ERRNO_H &
+ -dHAVE_STRING_H -dHAVE_STRINGS_H -dHAVE_FCNTL_H -dHAVE_IO_H &
+ -dHAVE_SYS_STAT_H -dHAVE_SIGNAL_H -dHAVE_STDLIB_H -dHAVE_UNISTD_H &
+ -dHAVE_STDINT_H -dHAVE_DIRECT_H -dHAVE_SBRK -dHAVE_STRCHR -dTERMCAP
+
+all : teco.exe .SYMBOLIC
+
+teco.exe : tecbuf.obj teccmd.obj tecdebug.obj tecdisp.obj tecexec.obj &
+ tecmem.obj teco.obj tecparse.obj tecstate.obj tecterm.obj tecundo.obj
+ set WLINK_OBJ=$(LDFLAGS) name $@ file { $< }
+ $(LD) @WLINK_OBJ
+
+.c.obj:
+ $(CC) $(CFLAGS) -fo=$@ $<
+
+clean: .SYMBOLIC
+ rm -f teco.exe
+ rm *.obj
diff --git a/tecbuf.c b/tecbuf.c
index 9af3957..46f0f53 100644
--- a/tecbuf.c
+++ b/tecbuf.c
@@ -92,10 +92,10 @@ unsigned int hash = stringHash( name );
// printf("hash match! %s %s\n",name,bp->name);
/*
* This loop implements the equivalent of strcmp, except that in the
- * case of VMS, it is case insensitive.
+ * case of VMS and MS-DOS, it is case insensitive.
*/
for(cp1 = name, cp2 = bp->name;;cp1++,cp2++){
-#ifdef VMS
+#if defined(VMS) || defined(MSDOS)
if(UPCASE(*cp1) != UPCASE(*cp2)) break;
#else
if(*cp1 != *cp2) break;
@@ -1488,9 +1488,11 @@ char outbuf[1024];
bytes_required_for_line + INCREMENTAL_LINE_BUFFER_SIZE - 1;
bytes_to_allocate -=
bytes_to_allocate % INCREMENTAL_LINE_BUFFER_SIZE;
+#if LARGEST_LOOKASIDE_BLOCK > 0
if(dlbp->buffer_size > LARGEST_LOOKASIDE_BLOCK){
bytes_to_allocate = dlbp->buffer_size * 2;
}/* End IF */
+#endif
if(bytes_to_allocate < bytes_required_for_line){
char tmp_message[1024];
@@ -1610,9 +1612,11 @@ char outbuf[1024];
bytes_required_for_line + INCREMENTAL_LINE_BUFFER_SIZE - 1;
bytes_to_allocate -=
bytes_to_allocate % INCREMENTAL_LINE_BUFFER_SIZE;
+#if LARGEST_LOOKASIDE_BLOCK > 0
if(dlbp->buffer_size > LARGEST_LOOKASIDE_BLOCK){
bytes_to_allocate = dlbp->buffer_size * 2;
}/* End IF */
+#endif
if(bytes_to_allocate < bytes_required_for_line){
char tmp_message[1024];
diff --git a/teccmd.c b/teccmd.c
index bd0ea6c..ae3fe72 100644
--- a/teccmd.c
+++ b/teccmd.c
@@ -1047,6 +1047,11 @@ int status;
PREAMBLE();
+ /*
+ * FIXME: This could be supported on MS-DOS if we
+ * respected DOS directory separators and
+ * used short filename extensions.
+ */
#ifdef UNIX
/*
* First step is to separate the path elements from the filename itself.
@@ -1198,7 +1203,12 @@ register int status;
PREAMBLE();
#ifndef HAVE_LONG_FILE_NAMES
- if(mkdir(pathname,0777)){
+#ifdef MSDOS
+ i = mkdir(pathname);
+#else
+ i = mkdir(pathname,0777);
+#endif
+ if(i){
if(errno != EEXIST){
sprintf(tmp_message,"?Error creating subdirectory <%s>: %s",
pathname,error_text(errno));
@@ -1492,8 +1502,12 @@ cmd_interrupt()
if(waiting_for_input_flag == NO){
restore_tty();
fprintf(stderr,"TECO aborted...\n");
+#ifdef MSDOS
+ abort();
+#else
signal(SIGINT,(void (*)(int))SIG_DFL);
kill(getpid(),SIGINT);
+#endif
}/* End IF */
}/* End IF */
@@ -1937,11 +1951,7 @@ failreap:
/* END OF UNIX CONDITIONAL CODE */
-#endif
-
-
-
-#ifdef VMS
+#else /* UNIX */
/**
* \brief Issue a command to the operating system
@@ -1949,12 +1959,16 @@ failreap:
* This routine is called in response to the EC command which allows the
* user to execute operating system commands from within the editor.
*/
-cmd_oscmd(ct)
-register struct cmd_token *ct;
+int
+cmd_oscmd(struct cmd_token *uct, int arg_count, int arg1, int arg2, char *cp)
{
PREAMBLE();
- error_message("?VMS Does not currently support EC");
+ /*
+ * FIXME: We could at least implement a subset with system(),
+ * that would work on DOS as well.
+ */
+ error_message("?OS Does not currently support EC");
return(FAIL);
}/* End Routine */
diff --git a/tecmem.c b/tecmem.c
index f5abd95..88431a9 100644
--- a/tecmem.c
+++ b/tecmem.c
@@ -39,7 +39,7 @@ char *tecmem_c_version = "tecmem.c: $Revision: 1.3 $";
char *starting_break;
-#ifndef HAVE_UNISTD_H
+#if !defined(HAVE_UNISTD_H) && !defined(HAVE_STDLIB_H)
char *malloc();
void free();
void exit();
diff --git a/teco.c b/teco.c
index bf5d58b..9e92e4b 100644
--- a/teco.c
+++ b/teco.c
@@ -188,7 +188,7 @@ register int i;
remove_checkpoint_file();
#endif /* CHECKPOINT */
-#ifdef UNIX
+#if defined(UNIX) || defined(MSDOS)
return(0);
#endif
@@ -210,7 +210,7 @@ register int i;
* package a chance to initialize itself.
*/
void
-initialize_tty()
+initialize_tty( void )
{
#if HAVE_TERMIOS_H
struct termios tmp_tty_modes;
@@ -427,8 +427,57 @@ initialize_tty()
/* END OF UNIX CONDITIONAL CODE */
+#ifdef MSDOS
+
+void
+initialize_tty( void )
+{
+ tty_input_chan = 0;
+ tty_output_chan = 1;
+
+ /*
+ * The terminal speed is checked in various situations,
+ * so it's important to be initialized even though we're
+ * not on a real serial connection.
+ */
+ term_speed = 32000;
+ main_delete_character = 8;
+
+ // Block cursor
+ //_settextcursor(0x0007);
+
+/*
+ * Check out the termcap description for this tty now. It makes
+ * no sense to go changing the terminal modes all around until
+ * we decide whether we can run on this terminal or not.
+ */
+ init_term_description();
+
+ if(forced_height > 0) term_lines = forced_height;
+ if(forced_width > 0) term_columns = forced_width;
+ if(term_lines == 0) term_lines = 24;
+ if(term_columns == 0) term_columns = 80;
+
+ if(term_lines >= SCREEN_MAX_LINES){
+ char tmp_message[LINE_BUFFER_SIZE];
+ sprintf(
+ tmp_message,
+ "terminal line count of %d exceeds maximum of %d",
+ term_lines,
+ SCREEN_MAX_LINES
+ );
+ tec_error(E2BIG,tmp_message);
+ }/* End IF */
+
+ screen_init();
+}/* End Routine */
+
+#endif /* MSDOS */
+
+#ifndef MSDOS
+
#if !HAVE_TCGETATTR
/**
@@ -504,6 +553,8 @@ int status;
#endif /* !HAVE_TCSETATTR */
+#endif /* !MSDOS */
+
#ifdef VMS
@@ -741,6 +792,10 @@ int err;
#endif
+#ifdef MSDOS
+ if(kbhit()) return(YES);
+#endif
+
return(NO);
}/* End Routine */
@@ -819,6 +874,16 @@ char comment_flag = NO;
#endif
+#ifdef MSDOS
+
+ /*
+ * FIXME: We should use the location
+ * of teco.exe.
+ */
+ (void) strcat(filename,".teco_ini");
+
+#endif
+
#ifdef VMS
strcpy(filename,"SYS$LOGIN:TECO.INI");
@@ -956,7 +1021,11 @@ char *cp, c;
* This code handles the command line arguments to VTECO. This requires
* different processing for different operating systems.
*/
-#ifdef UNIX
+#if defined(UNIX) || defined(MSDOS)
+/*
+ * FIXME: Perhaps DOS should have its own version with `/` arguments.
+ * The Watcom C runtime probably also doesn't expand wildcards.
+ */
int
handle_command_line( int which_time, int argc, char **argv )
{
@@ -1323,7 +1392,7 @@ char *cp,*sp;
*
* This routine returns a linked list of expanded filenames.
*/
-#ifdef UNIX
+#if defined(UNIX) || defined(MSDOS)
struct wildcard_expansion *name_list;
struct wildcard_expansion *name_list_end;
@@ -1339,12 +1408,16 @@ struct passwd *pw;
name_list = NULL;
name_list_end = NULL;
+ /*
+ * FIXME: DOS should use \ directory separators.
+ */
/*
* Else, start branching down into the directory list he specified
*/
if(wildcard_string[0] == '/'){
process_directory(&wildcard_string[0],"/",2);
}
+#ifdef UNIX
else if (wildcard_string[0] == '~'){
cp = temp_name;
sp = &wildcard_string[1];
@@ -1360,6 +1433,7 @@ struct passwd *pw;
strcat(temp_name,sp);
process_directory(temp_name,"/",2);
}
+#endif
else {
strcpy(temp_name,"./");
strcat(temp_name,wildcard_string);
@@ -1616,7 +1690,7 @@ int pattern_char;
}/* End While */
}/* End Routine */
-#endif
+#endif /* UNIX || MSDOS */
@@ -1699,6 +1773,8 @@ open_debug_log_file()
+#ifndef MSDOS
+
/**
* \brief Map system dependent baud fields to a standard integer
*
@@ -1774,6 +1850,8 @@ static int equivalent_baudrates[] = {
}/* End Routine */
+#endif /* !MSDOS */
+
/**
@@ -1842,7 +1920,7 @@ static char *tec_errlist[] = {
}/* End IF */
#endif
-#ifdef UNIX
+#if defined(UNIX) || defined(MSDOS)
#if 0
return((char *)sys_errlist[err_num]);
#endif
diff --git a/teco.h b/teco.h
index 39921fc..c72fb03 100644
--- a/teco.h
+++ b/teco.h
@@ -41,8 +41,8 @@
#define BLOCKED 2
#define INVALIDATE 3
-#define VMAJOR 6
-#define VMINOR 7
+#define VMAJOR 7
+#define VMINOR 0
#define AUTO_DATE "$Date: 2007/12/10 22:13:07 $"
#define TECO_FILENAME_TOTAL_LENGTH 1024
@@ -60,7 +60,12 @@
#define LINE_BUFFER_SIZE 1024
#define DEFAULT_CHECKPOINT (5*60)
#define TAG_HASH_ENTRIES 1024
+#if defined(MSDOS) && !defined(__HUGE__)
+/* make sure that all variables fit into 64kb */
+#define PARSER_STRING_MAX 512
+#else
#define PARSER_STRING_MAX 1024
+#endif
#define SEARCH_STRING_MAX PARSER_STRING_MAX
#define NORMAL_TAB_WIDTH 8
#define MAX_TAB_WIDTH 16
@@ -69,8 +74,18 @@
#define INITIAL_LINE_BUFFER_SIZE 32
#define INCREMENTAL_LINE_BUFFER_SIZE 32
#define MINIMUM_ALLOCATION_BLOCK 32
+#if defined(MSDOS) && !defined(__HUGE__)
+/*
+ * FIXME: The lookaside mechanism needs to be revised.
+ * It has been disabled, so that all tec_alloc() are
+ * more or less directly passed to malloc().
+ */
+#define LOOKASIDE_COUNT 1
+#define LARGEST_LOOKASIDE_BLOCK 0
+#else
#define LOOKASIDE_COUNT 32
#define LARGEST_LOOKASIDE_BLOCK (LOOKASIDE_COUNT * MINIMUM_ALLOCATION_BLOCK)
+#endif
#define BIG_MALLOC_HUNK_SIZE (LARGEST_LOOKASIDE_BLOCK * 64)
#define NORMAL_TAB_WIDTH 8
@@ -129,12 +144,12 @@
#define TYPE_C_TAGSTR 49
#define TYPE_C_MAXTYPE 49
-#define MAGIC_SCREEN 0x01010101
-#define MAGIC_BUFFER 0x02020202
-#define MAGIC_LINE 0x03030303
-#define MAGIC_LINE_LOOKASIDE 0x04040404
-#define MAGIC_FORMAT 0x05050505
-#define MAGIC_FORMAT_LOOKASIDE 0x06060606
+#define MAGIC_SCREEN ((int)0x01010101)
+#define MAGIC_BUFFER ((int)0x02020202)
+#define MAGIC_LINE ((int)0x03030303)
+#define MAGIC_LINE_LOOKASIDE ((int)0x04040404)
+#define MAGIC_FORMAT ((int)0x05050505)
+#define MAGIC_FORMAT_LOOKASIDE ((int)0x06060606)
#ifdef DEBUG1
void do_preamble_checks(void);
@@ -352,15 +367,22 @@ typedef unsigned long teco_ptrint_t;
* vms. It lets us write our own version of functions which simply do not
* exist outside of unix.
*/
-#ifndef VMS
+#if !defined(VMS) && !defined(MSDOS)
#define UNIX
#define JOB_CONTROL
#endif
/*
* Include Files From GNU Autoconf/Autoheader
+ *
+ * FIXME: The Autoconf build system does not pass down -DHAVE_CONFIG_H.
+ * This should be fixed by rewriting it as the original sources
+ * are missing.
*/
+//#ifdef HAVE_CONFIG_H
+#ifndef __WATCOMC__
#include "config.h"
+#endif
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
@@ -451,6 +473,10 @@ typedef unsigned long teco_ptrint_t;
#endif
#endif
+#if HAVE_DIRECT_H
+#include <direct.h>
+#endif
+
#if HAVE_SYS_WAIT_H
# include <sys/wait.h>
#endif
@@ -475,6 +501,10 @@ typedef unsigned long teco_ptrint_t;
# include <termio.h>
#endif
+#if HAVE_IO_H
+#include <io.h>
+#endif
+
#if HAVE_FCNTL_H
#include <fcntl.h>
#endif
@@ -565,6 +595,10 @@ typedef unsigned long teco_ptrint_t;
}
#endif
+#ifdef MSDOS
+#include <conio.h>
+#endif
+
/* method declarations */
void error_message(char * string);
void tec_release(unsigned char type, char *addr);
diff --git a/tecparse.c b/tecparse.c
index e726ea6..a1426fa 100644
--- a/tecparse.c
+++ b/tecparse.c
@@ -1004,6 +1004,19 @@ char inbuf[4];
if(errno == EINTR) continue;
#endif
+#ifdef MSDOS
+ waiting_for_input_flag = YES;
+ /* does not echo */
+ i = getch();
+ waiting_for_input_flag = NO;
+
+ intr_flag = 0;
+
+ if(i != EOF){
+ inbuf[0] = i;
+ break;
+ }
+#endif
#ifdef VMS
waiting_for_input_flag = YES;
i = sys$qiow(0,tty_input_chan,IO$_READVBLK|IO$M_NOECHO|IO$M_NOFILTR,
@@ -1091,7 +1104,7 @@ register struct buff_header *qbp;
* The return code determines whether this was done okay or not.
*/
int
-unpreserve_rubout_char( struct cmd_token *ct __attribute__((unused)))
+unpreserve_rubout_char( struct cmd_token *ct )
{
register struct buff_header *qbp;
int c;
@@ -1133,7 +1146,7 @@ int c;
* special Q-register so that it doesn't grow without bounds.
*/
void
-parser_clean_preserve_list()
+parser_clean_preserve_list( void )
{
register struct buff_header *qbp;
diff --git a/tecterm.c b/tecterm.c
index 8f196ce..5b5d116 100644
--- a/tecterm.c
+++ b/tecterm.c
@@ -37,6 +37,13 @@ char *tecterm_c_version = "tecterm.c: $Revision: 1.3 $";
#include <term.h>
#endif
+#if defined(VMS) || defined(MSDOS)
+int tgetent(char *,char *);
+int scan_termcap(FILE *,char *,char *);
+int tgetnum(char *);
+char *tgetstr(char *, char **);
+#endif
+
/*
* Global Storage is defined here for lack of a better place.
*/
@@ -1045,7 +1052,7 @@ term_flush()
i = SCREEN_OUTPUT_BUFFER_SIZE - scr_outbuf_left;
-#ifdef UNIX
+#if defined(UNIX) || defined(MSDOS)
if(i) write(tty_output_chan,scr_outbuf,(unsigned)i);
#endif
@@ -1072,7 +1079,7 @@ term_flush()
* has certain basic capabilities that we require.
*/
int
-init_term_description()
+init_term_description( void )
{
char termcap_description_buffer[TERMCAP_BUFFER_SIZE];
char *terminal_name;
@@ -1086,7 +1093,11 @@ init_term_description()
if((terminal_name = getenv("TECO_TERM")) == NULL){
if((terminal_name = getenv("TERM")) == NULL){
+#ifdef MSDOS
+ terminal_name = "ansi.sys";
+#else
tec_error(ENOENT,"Environment variable TERM not found");
+#endif
}/* End IF */
}/* End IF */
@@ -1319,7 +1330,6 @@ init_term_description()
#ifdef VMS
-char *current_termcap_description;
char *termcap =
"d1|vt100-80|vt-100|dec vt100:\
:co#80:li#24:cl=50\\E[;H\\E[2J:bs:am:cm=5\\E[%i%2;%2H:nd=2\\E[C:up=2\\E[A:\
@@ -1328,7 +1338,33 @@ char *termcap =
:ku=\\E[A:kd=\\E[B:kr=\\E[C:kl=\\E[D:\
:cs=\\E[%i%d;%dr:sf=5\\ED:\
:kh=\\E[H:k1=\\EOP:k2=\\EOQ:k3=\\EOR:k4=\\EOS:pt:sr=5\\EM:xn:xv:";
+#endif
+
+#ifdef MSDOS
+/*
+ * Generated via `infocmp -C ansi.sys`.
+ */
+char *termcap =
+"ansi.sys|ANSI.SYS 3.1 and later versions:\
+:am:bs:mi:ms:xo:\
+:co#80:li#25:\
+:K1=\\0G:K2=\\0L:K3=\\0I:K4=\\0O:K5=\\0Q:ce=\\E[K:cl=\\E[2J:\
+:cm=\\E[%i%d;%dH:do=\\E[B:ho=\\E[H:is=\\E[m\\E[?7h:k1=\\0;:\
+:k2=\\0<:k3=\\0=:k4=\\0>:k5=\\0?:k6=\\0@:k7=\\0A:k8=\\0B:k9=\\0C:\
+:kD=\\0S:kI=\\0R:kN=\\0Q:kP=\\0I:kb=^H:kd=\\0P:kh=\\0G:kl=\\0K:\
+:kr=\\0M:ku=\\0H:le=^H:mb=\\E[5m:md=\\E[1m:me=\\E[0m:mr=\\E[7m:\
+:nd=\\E[C:rc=\\E[u:\
+:..sa=\\E[0;10%?%p1%t;7%;%?%p2%t;4%;%?%p3%t;7%;%?%p4%t;5%;%?%p6%t;1%;%?%p7%t;8%;%?%p9%t;11%;m:\
+:sc=\\E[s:se=\\E[m:so=\\E[7m:ue=\\E[m:up=\\E[A:us=\\E[4m:"
+/*
+ * Some extensions.
+ * At least Dosbox seems to have these escapes.
+ */
+":cd=50\\E[J:al=\\E[1L:dl=\\E[1M:ic=\\E[1@:dc=\\E[1P:";
+#endif
+#if defined(VMS) || defined(MSDOS)
+char *current_termcap_description;
/**
* \brief Version of TGETENT for Non-UNIX systems
@@ -1398,6 +1434,7 @@ FILE *fd;
* This routine scans the termcap file for an entry which matches our
* terminal, and returns non-zero if it finds it.
*/
+int
scan_termcap(fd,temp_buffer,term_name)
FILE *fd;
char *temp_buffer;
@@ -1553,4 +1590,4 @@ char *buffer;
/* END OF VMS CONDITIONAL CODE */
-#endif
+#endif /* VMS || MSDOS */