1
0
mirror of https://github.com/rricharz/Tek4010.git synced 2026-05-08 00:17:24 +00:00

Stable PTY terminal mode, ready for testing

This commit is contained in:
Rene Richarz
2026-05-05 09:55:51 +02:00
parent 6840e8b0f8
commit 97556f6711
16 changed files with 360 additions and 71 deletions

View File

@@ -1,56 +1,48 @@
# Tek4010 Quick Start
This is a Tektronix 4010 graphics terminal emulator.
It is not a full VT100/xterm terminal.
Basic usage:
tek4010 [options] command [command options]
The command is required, for example: cat, head,
telnet, or rsh.
tek4010 [options]
---
## Examples
To use the included examples and demos, go to the
Tek4010 directory first
To use the included examples and demos, start tek4010 with the command
tek4010
In the tek4010 window, change to the Tek4010 directory:
cd Tek4010
Display a plot file:
tek4010 -noexit cat test.plt
ARDS example:
tek4010 -noexit -ARDS cat ardsfiles/trek.pic
Text output:
tek4010 -noexit head -n 32 src/tek4010.c
cat test.plt
Animation:
tek4010 cat animation.plt
cat animation.plt
Demo script:
tek4010 demos/demo.sh
---
## Important option
-noexit
Keeps the window open after the command finishes.
sh demos/demo.sh
---
## Options
By default, the screen clears automatically when the bottom is reached.
Use -noAutoClear to disable this.
| Option | Description |
|----------|------------------------------------------|
| -noexit | Keep window open after command |
| -fast | Fast rendering without fading |
| -full | Full screen mode (Ctrl-Q to close) |
| -half | Use half of the screen width. |
| -b9600… | Emulate terminal baud rates |
---

1
dodekagon.plt vendored
View File

@@ -1 +0,0 @@
 ,f:^1u9N

View File

@@ -107,6 +107,9 @@ void check_graphics_response(long lag)
long now = tube_mSeconds();
if (brightCounter <= 0)
return;
// ignore startup phase (first 1000 ms)
if (now < STARTUP_IGNORE_MSEC)
return;
@@ -439,8 +442,11 @@ int main (int argc, char *argv[])
}
gtk_window_set_title(GTK_WINDOW(window), windowName);
gtk_widget_set_can_focus(window, TRUE);
gtk_widget_show_all(window);
gtk_window_present(GTK_WINDOW(window));
gtk_widget_grab_focus(window);
gtk_main();

View File

@@ -84,7 +84,7 @@ struct keyCode {
struct keyCode keyTable[MAXKEYCODES];
int argNoexit = 0; // options
int argNoexit = 1; // options
int argRaw = 0;
int argBaud = 19200;
int argTab1 = 0;
@@ -92,7 +92,7 @@ int argFull = 0;
int argFullV = 0;
int argARDS = 0;
int argAPL = 0;
int argAutoClear = 0;
int argAutoClear = 1;
int argKeepSize = 0;
int argHideCursor = 0;
int argWait = 0;
@@ -119,6 +119,7 @@ int specialPlotMode = 0;
int defocussed = 0;
int intensity = 100;
int aplMode = 0;
pid_t childPid = -1;
int argPty = 0;
@@ -314,6 +315,8 @@ void tube_init(int argc, char* argv[])
size_t bufsize = 127;
int firstArg = 1;
int ptyMaster = -1;
argAutoClear = 1;
argNoexit = 1;
printf("tek4010 version 2.0\n");
windowName = "Tektronix 4010/4014 emulator";
if (argc > 19) {
@@ -338,6 +341,8 @@ void tube_init(int argc, char* argv[])
argRaw = 1;
else if (strcmp(argv[firstArg],"-noexit") == 0)
argNoexit = 1;
else if (strcmp(argv[firstArg],"-exit") == 0)
argNoexit = 0;
else if (strcmp(argv[firstArg],"-b100000") == 0)
argBaud = 100000;
else if (strcmp(argv[firstArg],"-b38400") == 0)
@@ -364,6 +369,8 @@ void tube_init(int argc, char* argv[])
argFullV = 1;
else if (strcmp(argv[firstArg],"-autoClear") == 0)
argAutoClear = 1;
else if (strcmp(argv[firstArg],"-noAutoClear") == 0)
argAutoClear = 0;
else if (strcmp(argv[firstArg],"-keepsize") == 0)
argKeepSize = 1;
else if (strcmp(argv[firstArg],"-hidecursor") == 0)
@@ -429,13 +436,14 @@ void tube_init(int argc, char* argv[])
printf("Cannot fork pseudo terminal\n");
exit(1);
}
else if (pid == 0) {
setenv("TERM", "vt100", 1);
setenv("PS1", "Tek4010$ ", 1);
execl("/bin/sh", "sh", "-i", (char *) NULL);
_exit(127);
}
else if (pid == 0) {
setenv("TERM", "vt100", 1);
setenv("PS1", "tek4010$ ", 1);
execl("/bin/sh", "sh", "-i", (char *) NULL);
_exit(127);
}
childPid = pid;
getDataPipe[0] = ptyMaster;
putKeysPipe[1] = dup(ptyMaster);
if (putKeysPipe[1] == -1) {
@@ -516,6 +524,9 @@ else if (pid == 0) {
}
// parent process
childPid = pid;
free(str);
close(getDataPipe[1]); // not used
@@ -566,31 +577,34 @@ int tube_on_timer_event()
// is child process still running?
int status;
if (argWait && (tube_isInput() == 0) && (waitpid(-1, &status, WNOHANG))) {
if (firstWait == 0)
firstWait = tube_mSeconds();
else {
if ((int)((tube_mSeconds() - firstWait) / 1000) > argWait) {
tube_quit();
gtk_main_quit();
printf("Process has been terminated after %d seconds\n", argWait);
exit(0);
}
}
}
else if ((!argNoexit) && (tube_isInput() == 0) && (waitpid(-1, &status, WNOHANG))) {
long t = tube_mSeconds();
// printf("Execution time: %0.3f sec\n", (double)t/1000.0);
// if (t > 0) {
// printf("Average screen refresh rate: %0.1f Hz\n",(double)(1000.0*refreshCount)/t);
// printf("Average character rate: %0.0f baud\n",(double)(8000.0*charCount)/t);
// }
tube_quit();
gtk_main_quit();
printf("Process has been terminated\n");
exit(0);
}
int status;
int childExited = 0;
if (childPid > 0) {
if (waitpid(childPid, &status, WNOHANG) == childPid)
childExited = 1;
}
if (childExited) {
if (argPty || !argNoexit) {
tube_quit();
gtk_main_quit();
printf("Process has been terminated\n");
exit(0);
}
if (argWait) {
if (firstWait == 0)
firstWait = tube_mSeconds();
else if ((int)((tube_mSeconds() - firstWait) / 1000) > argWait) {
tube_quit();
gtk_main_quit();
printf("Process has been terminated after %d seconds\n", argWait);
exit(0);
}
}
}
if (brightCounter > 0)
brightCounter--;

View File

@@ -47,6 +47,7 @@ extern int aplMode;
extern int plotPointMode;
extern int writeThroughMode;
extern pid_t childPid;
extern int argPty;
extern int tube_x0, tube_x2, tube_y0, tube_y2;

BIN
tektests/circles Executable file

Binary file not shown.

View File

@@ -48,7 +48,7 @@ void endDraw()
fflush(stdout);
}
int drawCircle(int x,int y,int r)
void drawCircle(int x,int y,int r)
{
int i;
double arg;
@@ -63,12 +63,12 @@ int drawCircle(int x,int y,int r)
int main (int argc, char *argv[])
{
drawCircle(512, 340, 200);
drawCircle(612, 340, 100);
drawCircle(412, 340, 100);
drawCircle(512, 240, 100);
drawCircle(612, 340, 100);
drawCircle(412, 340, 100);
drawCircle(512, 240, 100);
drawCircle(512, 440, 100);
startDraw(212,340); draw(812,340); endDraw();
startDraw(512,040); draw(512,640); endDraw();
startDraw(1,1); endDraw(); // move the cursor out of the way
//startDraw(1,1); endDraw(); // move the cursor out of the way
}

View File

@@ -1 +0,0 @@
*t6HHzG+`GfGmFsEyDC,eAk@q5^w\}Y-cWiTnRtOyLH.dEiAn4^sZxV|Q/aMeHjDn3_rZuUyP|K0`Ec@f2ZhUkOmIpCr1]tWuQwKxEy0_zY{RLF|@{/ZTNzGyAx.[wUuOtIrCp-]mWkQhKfFc@`,[/|UyPuKrFnAj+\eXaS.|OxJsFnBi*_d[-XyTtQnNiLcI,}GwDqBk@e)_+]y\s[mZfY`Y*zYtXnYhYbY){Zu[o\i]c_(}*@wBqDkGeI'LzNtQoTiXd[&_z+BuFpJlOgScX%~\z,AvFsKoPlUh[e-@bF`K$}Q{Wx]v.CtIsOqUp[o/AnGmNTZl0@mFLRnYo_p1EqKsQtWv]x2C{I}O%`UbZe3@hElKoPsUvZz_~4D&cHgMlQpVuZz^5A'dEiHoLtOzRT(eWkYq\w^}6@)cAiCoDuE{F*bGhGnGtH*t6HHzG+`GfFlDrCx@~5^,d[iXnTsQxL|H-aCd4^hYkTnNpHsBt3\vVwPJxDw2^XvRtLsFp@n1ZkThOdJaE,|@x0\sWnTiPdM+~JxHrElDfB`A*zAt@nAhAbB)|DvEpHjJdM(PzTuWp\l1@gEdJ`O'}TzZx2@uFtLrRqX^p3DqJPrVt\u4BxHzN}T(`Yd^g5ClHpLuQzTX)d[j^p6@vC|D*bFhGnGtH*t0@@z/_+`_f^l\r[xX~V,dSiPnLsIxD|@-a.[dVhQkLnFp@s-ZtTvNwHBx,\wVPvJtDs+^pXnRkLhGdBa*],|XxTsOnLiHdE+~Bx@r)]l\fZ`Y*zYtXnYhYbZ)|\v]p*@jBdE(HzLuOpTlXg]d+B`G'}LzRxXu^t,DrJqPVp\q-BHrNtTuZx.@zF}L(`QdVg[l/@pDuIzLP)dSjVpXv[|\*b^h_n_t0@'p3DDvC|C(bBh@n2_t\zZ)`WeTjPoMtHxD}1_*`ZdUgPjJlDo0^pXrRsLFt@s/ZTrNpHoBl.\jVgPdK`F)}Ax-\tXoSjPeL`I(zFtDnAh@b,^'|]v]p\j]d]&~^x-@rAlDfF`I%{LvPqSlXh\c.A`F$|KyPvVt\q/BpHnNmTZl0@mFLnRpXq^t1DvJyP|U%`Zc_h2DlHqMvP{T&`WfZl\r_x3@~B'dCjCpD-x3DD~C.dCjBp@v2_|\/bZhWmTrPwM|H0`De1_hZlUoPrJtDw0^xXzR{LF|@{/ZTzNxHwBt.\rVoPlKhFeA`-\/|XwSrPmLhIbF.|DvAp@j,^d]-~]x\r]l]f^`-@,zAtDnFhIcL+~PyStXp\k.AhFdKaP*~V|\y/BxHvNuTZt0@uFLvRxXy^|1D~J+aPdUhZk_p2DtHyM~P,cThWnZt\z_-`3@fBlCrCxD*t&Tt9L!`0@4@ a A

BIN
tektests/dodecagon Executable file

Binary file not shown.

29
tektests/dodecagon.c Executable file
View File

@@ -0,0 +1,29 @@
/* dodecagon.c */
/* rricharz 2019 */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "tekio.h"
int main (int argc, char *argv[])
{
int angle, angle1;
double rad = 3.14159265 / 180;
int xcenter = MAXX / 2;
int ycenter = MAXY / 2;
int radius = 9 * MAXY / 20;
clearScreen();
for (angle = 0; angle < 360; angle += 30) {
for (angle1 = angle + 30; angle1 < 360; angle1 += 30) {
drawVector((int)(xcenter + radius * cos(rad * angle)),
(int)(ycenter + radius * sin (rad * angle)),
(int)(xcenter + radius * cos (rad * angle1)),
(int)(ycenter + radius * sin (rad * angle1)));
}
}
moveAlpha(34,0);
exit(0);
}

BIN
tektests/incremental Executable file

Binary file not shown.

View File

@@ -1 +0,0 @@
$l0@PEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII

View File

@@ -1,8 +1,11 @@
CC = gcc
LDFLAGS = -lm
all: incremental circles
all: incremental circles dodecagon
incremental: incremental.c
circles: circles.c
dodecagon: tekio.h tekio.c dodecagon.c
cc -o dodecagon dodecagon.c tekio.c -lm

170
tektests/tekio.c Executable file
View File

@@ -0,0 +1,170 @@
/* tecio.c 2.11 BSD Tektronix graphics */
/* io functions for Tektronix 4010 */
/* cc 2019 rricharz */
/* If you want to use this, you need to */
/* be in tek4010 terminal. */
/* See https://github.com/rricharz/Tek4010 */
#include <stdio.h>
#include <math.h>
#include <string.h>
#include "tekio.h"
static int xs,ys;
void startDraw(int x1, int y1)
{
if (x1 < 0) x1 = 0;
if (x1 >= MAXX) x1 = MAXX -1;
if (y1 < 0) y1 = 0;
if (y1 >= MAXY) y1 = MAXY - 1;
putchar(29);
putchar((y1 >> 5) + 32);
putchar((y1 & 31) + 96);
putchar((x1 >> 5) + 32);
putchar((x1 & 31) + 64);
xs = x1;
ys = y1;
}
void draw(int x2, int y2)
{
int hxchange, lychange;
if (x2 < 0) x2 = 0;
if (x2 >= MAXX) x2 = MAXX -1;
if (y2 < 0) y2 = 0;
if (y2 >= MAXY) y2 = MAXY - 1;
if ((y2 >> 5) != (ys >> 5)) /* if high y has changed */
putchar((y2 >> 5) + 32);
hxchange = (x2 >> 5) != (xs >> 5);
lychange = (y2 & 31) != (ys & 31);
if (hxchange || lychange) putchar((y2 & 31) + 96);
if (hxchange) /* if high order x has changed */
putchar((x2 >> 5) + 32);
putchar((x2 & 31) + 64);
xs = x2;
ys = y2;
}
void endDraw()
{
putchar(31);
fflush(stdout);
}
void moveTo(int x1, int y1)
{
startDraw(x1,y1);
endDraw();
}
void moveAlpha(int line, int column)
{
int vDotsPerChar;
double hDotsPerChar;
if (line < 1) line = 1;
if (line > MAXLINES) line = MAXLINES;
if (column < 1) column = 1;
if (column > MAXCOLUMNS) column = MAXCOLUMNS;
vDotsPerChar = MAXY / MAXLINES;
hDotsPerChar = (double)(MAXX)/(double)(MAXCOLUMNS);
moveTo((int)((double)(column - 1) * hDotsPerChar), MAXY - line * vDotsPerChar);
}
void drawVector(int x1, int y1, int x2, int y2)
{
startDraw(x1,y1);
if (x2 < 0) x2 = 0;
if (x2 >= MAXX) x2 = MAXX -1;
if (y2 < 0) y2 = 0;
if (y2 >= MAXY) y2 = MAXY - 1;
draw(x2,y2);
endDraw();
}
void clearScreen()
{
putchar(27);
putchar(12);
}
void startWriteThrough()
{
putchar(27);
putchar('p');
fflush(stdout);
}
void endWriteThrough()
{
putchar(27);
putchar('`');
fflush(stdout);
}
void drawRectangle(int x1, int y1, int x2, int y2)
{
startDraw(x1,y1);
draw(x2,y1);
draw(x2,y2);
draw(x1,y2);
draw(x1,y1);
endDraw();
}
void drawCircle(int x, int y, int r)
{
int i;
double arg;
startDraw(x + r, y);
for (i = 0; i <= r; i++) {
arg = (double)(i) * PI2 / (double) r;
draw(x + (int)((double)r * cos(arg)), y + (int)((double)r * sin(arg)));
}
endDraw();
}
void drawJustifiedText(char *s, int line, int justify)
/* justify 0=left, 1=center; 2=right */
{
int length;
length = strlen(s);
switch (justify) {
case 1: moveAlpha(line, 1); break;
case 2: moveAlpha(line, (MAXCOLUMNS - length) / 2); break;
case 3: moveAlpha(line, MAXCOLUMNS - length + 1); break;
}
printf("%s",s);
}
int fix(double r)
/* round double and convert to int */
{
if (r >= 0) return (int)(r + 0.5);
else return (int)(r - 0.5);
}
void setCharacterSize(int size)
{
if ((size >= 1) && (size <= 4)) {
putchar(27);
putchar('7' + size);
}
else
printf("setCharacterSize: Illegal size %d\n", size);
}
void setLineMode(int type)
{
if ((type >= SOLID) && (type <= LONGDASH)) {
putchar(27);
putchar(95 + type);
}
else
printf("SetLineMode: illegal type %d\n", type);
}

77
tektests/tekio.h Executable file
View File

@@ -0,0 +1,77 @@
/* tecio.h 2.11 BSD Tektronix graphics */
/* io functions for Tektronix 4010 */
/* cc 2019 rricharz */
/* If you want to use this, you need to */
/* be in tek4010 */
/* See https://github.com/rricharz/Tek4010 */
#define MAXX 1023 /* Tektronix graphics screen size */
#define MAXY 780
#define MAXCOLUMNS 74 /* Tektronix alpha screen size */
#define MAXLINES 35
/* */
/* clear screen with */
/* clearScreen() */
/* */
/* draw individual vectors with */
/* drawVector(x1,y1,x2,y2) */
/* */
/* draw a string using graphics coordinates */
/* moveTo(x1,y1) */
/* printf(.....) */
/* */
/* draw a string using alpha coordinates */
/* moveAlpha(line,column) */
/* printf(.....) */
/* */
/* fast draw multiple joint vectors */
/* startDraw(x1,y1) */
/* draw(x2,y2) */
/* draw(x3,y3) */
/* ............. */
/* endDraw() */
/* */
/* drawRectange(x1,y1.x2.y2) */
/* */
/* drawCircle(x,y,r) */
/* */
/* drawJustifiedText(s, line, justify) */
/* justify 0=left, 1=center; 2=right */
/* */
/* writethrough mode for short animations */
/* startWriteThrough() */
/* endWriteThrough() */
/* */
/* setCharacterSize(size) */
/* select character size 1..4 */
/* */
/* void setLineMode(type) */
/* set line type */
/* SOLID,DOTTED,DOTDASH,SHORTDASH,LONGDASH */
#define PI 3.14159265
#define PI2 6.28318531
#define SOLID 1
#define DOTTED 2
#define DOTDASH 3
#define SHORTDASH 4
#define LONGDASH 5
extern void drawVector(int x1, int y1, int x2, int y2);
extern void moveTo(int lx, int ly);
extern void moveAlpha(int line, int column);
extern void clearScreen(void);
extern void startDraw(int lx, int ly);
extern void draw(int x2, int y2);
extern void endDraw(void);
extern void startWriteThrough();
extern void endWriteThrough();
extern void drawRectangle(int x1, int y1, int x2, int y2);
extern void drawCircle(int x, int y, int r);
extern void drawJustifiedText(char *s, int line, int justify);
extern int fix(double r);
extern void setCharacterSize(int size);
extern void setLineMode(int type);

2
test.plt vendored
View File

@@ -1 +1 @@
6d:Ld M3o*P{:U5w+Z!u O }(Z#s7Y6d9B` ]3p+J~9]4w+H!t \a)Q$q7[6d\5|!N3p,A9Fx*W!s!Jg*H%m7[6c6X5x!_3q,V8O2{*H!r!Xm*^&h7Y6c5V5t"P3r-I}7X1)[!r"Gu+S'a7V6b4X5q#A3r-Zz7B1e)N!r"V~,F'y7Q6a3[5n#S3s.Iv6L0l)D!s#E"g,X(p7K6`3A5k$D3s.Vp5W/u(Z!t#U"q-I)f7D52Jh$U3s/Aj5B.~(R!u$D"|-Y)z6]5~1Tf%E3r/Jc4N.i(K!w$T#g.H*n6T5}1@c%U3r/S2{3[-u(E!z%C#r.U+`6K5{0Na&E3q/Y2s3H-b(@!|%R#~/A+q6B5z/]4~&U3o/_2j2V,p'\"`&A$j/L,b5X5y/N4|'D3m0C2a2E+'Y"c&P$w/W,q5N5w/A4y'R3k0G1w1T+o'W"h&_%c0@-`5D5v.U4w(@3h0I1m1D+a'V"lM%p0H-n4Y5t.J4u(M3e0J1cU*s'U"q\%}0O-{4O5s.A4r(Z3b0K0yG*f'V"w(I&i0V.g4E5q-Y4p)F2~0K0n/Y)z'W"|(W&v0[.s3Z5o-Q4n)Q2z0J0c/L)o'X#b)D'c1@.~3P5n-K4k)\2v0H/y/@)e'Z#i)P'o1D/h3G5l-E4h*F2q0F/n.U({']#p)]'|1G/r2]5j-A4f*P2l0D/d.J(s(@#w*H(h1J/{2S5h,]4c*Y2g0A.y.@(k(D#~*T(t1L0d2J5f,Y4`+A2b/^.o-V(d(H$e*^)`1N0l2A
 ,f:^1u9N,f:^5u5N,f:^7e/_,f:^5u*O,f:^1u&O,f:^f%@,f:^&v&O,f:^"v*O,f:^!g/^,f:^"v5N,f:^&v9N1u9N5u5N1u9N7e/_1u9N5u*O1u9Nu&O1u9N,f%@1u9N&v&O1u9N"v*O1u9N!g/^1u9N"v5N1u9N&vN5u5N7e/_5u5Nu*O5u5N1u&O5u5N,f%@5u5N&v&O5u5N"v*O5u5N!g/^5u5N"vN5u5N&v9N7e/_5u*O7e/_1u&O7e/_,f%@7e/_&v&O7e/_"v*O7e/_!g^7e/_"v5N7e/_&v9N5u*O1u&O5u*O,f%@5u*O&v&O5u*O"vO5u*O!g/^5u*O"v5N5u*O&v9N1u&O,f%@1u&O&vO1u&O"v*O1u&O!g/^1u&O"v5N1u&O&v9N,f%@&v&O,f%@"v*O,f%@!g/^,f%@"v5N,f%@&v9N&v&O"v*O&v&O!g/^&v&O"v5N&v&Ov9N"v*O!g/^"v*Ov5N"v*O&v9N!g/^"v5N!g/^&v9N"v5N&v9N!` @