• ?Hello World? Under ITS On PDP-10

    From Lawrence D?Oliveiro@3:633/10 to All on Mon Jan 19 04:14:23 2026
    Out of the handful of groundbreaking operating system developments on
    various hardware platforms in the 1960s and 1970s, DEC?s PDP-10
    computer has to be unique in being the host for, not one, but two of
    them.

    Among pre-RISC hardware architectures, the ?10 is fondly remembered as
    being an elegant design, in that writing assembly language for it was
    not the complete pain in the bum that it was on too many other
    machines.

    One of those OSes was ITS, which stood for ?Incompatible Timesharing
    System?, created at MIT. In the same sort of way that the ?Unix? name
    was a play on ?MULTICS?, so ITS was a play on the name of one of the
    earliest timesharing developments, ?CTSS? (the ?Compatible
    Time-Sharing System?).

    CTSS was ?compatible? in that it had to coexist with the
    vendor-provided batch-oriented OS on the IBM machines where it was
    developed; the submission of regular production batch jobs could not
    be disrupted by the running of this new, experimental OS. Whereas ITS
    could be considered ?incompatible? in that it didn?t need to coexist
    with anything else, I guess.

    ITS was a system created by hackers, for hackers. As an example, when
    you logged in, instead of launching a command shell, you were running
    a debugger as your primary user interface, instead. Using the system
    involves issuing an interesting mix of debugging-specific commands and
    commands that look more like regular command-shell ones.

    Here <https://www.youtube.com/watch?v=kVmFqmiiM-0> is a presentation
    by Lars Brinkhoff, showing what it?s like to write a simple ?Hello
    World? program in assembly language, build it and run it.

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From jayjwa@3:633/10 to All on Mon Jan 19 12:12:38 2026
    Lawrence D?Oliveiro <ldo@nz.invalid> writes:

    a debugger as your primary user interface, instead. Using the system
    involves issuing an interesting mix of debugging-specific commands
    You're a glass is half full person, eh?

    ITS has C, too, although it's far different than the C we know today or
    even the C in TOPS-20.

    /* guess.c
    * Simple number-guessing game. Enter your guess and try to
    * match the winning number between BEGIN and END. Your
    * performance will be graded if you win.
    * This version was ported from the TOPS-20 KCC version and is
    * for Synder CC. It is very hacky & does no error checking. It
    * will likely break if given wrong input. TODO: Fix this.
    *
    * Build:
    * copy clib; c10std c to your work area (change includes if needed)
    * cc c10std.c
    * cc guess.c
    * stinkr
    * =x c/clib
    * =l c10std.stk
    * =l guess.stk
    * =o ts.guess
    */
    #include "c/stdio.h"
    #include "c/cc.h"

    /* Define the number span the user should guess in. */
    #define BEGIN 1
    #define END 50

    int random( min, max ); /* Return rand int between min-max */
    int get2int( void ); /* Get (up to) 2 digit integer from user */


    int main( void ) {
    int guess; /* The user's guess */
    int answer; /* The winning number */
    int tries; /* Running total of attempts by user */

    /* Init stdio and friends as directed by clib; c10std c */
    stdio();

    /* Initialize tries, get the user's guess, and explain
    * what is being done in terms of the game.
    */
    tries = 1;
    cprint( "\t *** Number guessing game! *** \n" );
    cprint( "Try to guess the number between %d and %d.\n", BEGIN, END );

    /* Get a randomish number from BEGIN to END */
    answer = random( BEGIN, END);

    /* Loop until success or the user exits with ctrl-z */
    do {
    cprint( "Your guess (ctrl-z to quit): " );
    /* There is no scanf() in Synder C nor strtol! */
    guess = get2int();

    /* cprint( "[DEBUG]: guess is %d.\n", guess );
    cprint( "[DEBUG]: answer is %d.\n", answer ); */

    /* Eval the guess */
    if ( guess < answer ) {
    cprint( "\nGuess higher! -->\n" );
    } else if ( guess > answer ) {
    cprint( "\n\t\t<-- Guess lower!\n" );
    } else {
    cprint( "\n\tBINGO!\n" );

    /* Grade player performance */
    switch ( tries ) {
    case 1:
    cprint( "\nRating: Guessing god. (%d try)\n", tries );
    break;
    case 2:
    case 3:
    cprint( "\nRating: Guessing pro. (%d tries)\n", tries );
    break;
    case 4:
    case 5:
    case 6:
    cprint( "\nRating: Average guesser. (%d tries)\n", tries );
    break;
    default:
    cprint( "\nRating: You're not very good at this game, are you?\n" );
    }
    /* Exit loop because the player won. */
    break;
    }
    /* Increment the number of tries the player will have
    * needed to win.
    */
    tries++;
    } while ( guess != answer );

    return 0;
    }

    /* Return a randomish integer between min and max integer */
    int random( min, max ) int min, max; {
    int num;

    /* Until I know of a better way to do this, this will
    * work for a game.
    */
    srand( etime() );
    num = rand() % END + BEGIN;
    /* rand() gives a negative occasionally, and goes one
    * below the minimum, BEGIN. Fix this here.
    */
    if ( num < 0 ) num = num * -1;
    if ( num == 0 ) num++;
    return num;
    }

    /* Get (up to) a double digit ASCII Dec integer from stdin and return its
    * proper integer value to the caller, converting from the decimal
    * equal that ITS saves for the char the user enters.
    */
    int get2int( void ) {
    int num1, num2;

    /* We must call cgeti twice if we want a two-digit integer. */
    num1 = cgeti( stdin );
    num2 = cgeti( stdin );

    /* Handle case where the user enters one digit then presses
    * Enter. Eat the user's newline if they enter two digits.
    */
    if ( num2 != '\n' ) getchar();
    /* cprint( "[DEBUG]: num1 is %c num2 is %c\n", num1, num2 ); */

    /* Now the decimal equal of the character must be converted
    * to an actual single integer. Eg, if the user enters "6"
    * the variable will store the number 54 (as in ASCII table).
    */
    if ( (num1 >= 48) && (num1 <= 57) ) {
    /* Adjust to the integer else zero out */
    num1 = num1 - 48;
    } else num1 = 0;
    if ( (num2 >= 48) && (num2 <= 57) ) {
    /* Adust as above. There is a valid integer in
    * slot 2. Return using both slots. That is,
    * tens place and ones place.
    */
    num2 = num2 - 48;
    return (num1 * 10) + (num2 * 1);
    } else {
    /* Slot 2 (one's place) is not valid (eg, users enters "3")
    * because it is outside 0-9 range. Return just num1
    */
    return num1;
    }
    }

    /* EOF */


    *guess?K!
    *** Number guessing game! ***
    Try to guess the number between 1 and 50.
    Your guess (ctrl-z to quit): 35

    <-- Guess lower!
    Your guess (ctrl-z to quit): 25

    <-- Guess lower!
    Your guess (ctrl-z to quit): 15

    <-- Guess lower!
    Your guess (ctrl-z to quit): 10

    Guess higher! -->
    Your guess (ctrl-z to quit): 12

    Guess higher! -->
    Your guess (ctrl-z to quit): 13

    BINGO!

    Rating: Average guesser. (6 tries)

    :KILL
    *

    --
    PGP Key ID: 781C A3E2 C6ED 70A6 B356 7AF5 B510 542E D460 5CAE
    "The Internet should always be the Wild West!"

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)