Category : Alternate Operating Systems - Quarterdeck DesqView, CP/M, etc
Archive   : PCCAPP.ZIP
Filename : TYPE2.CC

 
Output of file : TYPE2.CC contained in archive : PCCAPP.ZIP
// type2.cc: Typing tutor, dual-process version. You type whatever you see
// on the screen, and the program will ask you to try again if the text that
// you typed isn't the same as the text that appeared on the screen. The
// program stops when you type '#'. The text to be typed comes from the
// file "in.1". One process reads lines from the file and prints them while
// another process reads lines from the keyboard and compares them with the
// lines read from the file. This program also computes the time taken
// to run the entire session.
#include "OutputStream.h"
#include "InputStream.h"
#include "NameServer.h"
#include "FileSystemInterface.h"
#include "ReadFileStream.h"
#include "ReadFileStreamStar.h"
#include "WriteFileStream.h"
#include "WriteFileStreamStar.h"
#include "FreeRunningTimer.h"
#include "FreeRunningTimerStar.h"
#include "Process.h"
#include "ProcessStar.h"
#include "Semaphore.h"
#include "line.h"

int Line::ReadfromKeyboard (InputStream *in, int &end)
{
// Repeatedly read characters from "in" and write them into my line
// until a newline or ENDCHAR is read. Set "end" to true if a newline has
// been read. Return the number of characters read, not counting the
// newline. My old line is wiped out before reading any characters.
// Will not work if there are more than MAXLINE characters to be read.
length = 0;
int charsRead = in -> read (&linechar [length], 1);
while ((linechar [length] != ENDCHAR) && (charsRead > 0) &&
(linechar [length] != '\n'))
{
length++;
charsRead = in -> read (&linechar [length], 1);
}
if (linechar [length] != '\n')
end = 0;
else
end = 1;
return length;
}

int Line::ReadfromFile (ReadFileStream *in, int &end)
{
// Repeatedly read characters from "in" and write them into my line
// until a newline or ENDCHAR is read, or until there are no more
// characters to be read. Set "end" to true if a newline has
// been read. Return the number of characters read, not counting the
// newline. My old line is wiped out before reading any characters.
// Will not work if there are more than MAXLINE characters to be read.
length = 0;
int charsRead = in -> read (&linechar [length], 1);
while ((linechar [length] != ENDCHAR) && (charsRead > 0) &&
(linechar [length] != '\n'))
{
length++;
charsRead = in -> read (&linechar [length], 1);
}
if (linechar [length] != '\n')
end = 0;
else
end = 1;
return length;
}


int Line::WriteToScreen (OutputStream *out)
{
// Write my line and a newline to "out". Return the number of characters
// written, not counting the newline.
int charWritten;
if (length != 0)
{
charWritten = out -> write (linechar, length + 1); // Output '\n' also.
out -> flush();
return charWritten;
}
else return 0;
}

int Line::WriteToFile (WriteFileStream *out)
{
// Write my line and a newline to "out". Return the number of characters
// written, including the newline.
if (length != 0)
return out -> write (linechar, length + 1); // Output '\n' also.
else
return 0;
}

// This semaphore is used for synchronizing the two processes. The teacher
// process V()'s this semaphore to tell the student process to read a line
// from the keyboard, and then the teacher process P()'s this semaphore.
// The student process V()'s this semaphore to tell the teacher process
// that it has finished reading a line from the keyboard, and the student
// process P()'s this semaphore.
Semaphore *sem;

// Variables shared by both lightweight processes: NotEnd is false if
// the file ran out of lines or if the user typed '#'. studentline is
// the line typed by the user. The student process sets this variable when
// the user types a line, and the teacher process compares studentline
// with the line read from the file. The two global variables together with
// sem are accessible to both processes because they are lightweight
// processes which share the same global variable space.
int NotEnd;
Line *studentline = new Line;

int main2 (int, char **)
{
// This function runs as the teacher process, and the process dies when
// this function returns. The teacher process is created in main().
// This process opens the file "in.1" for reading by calling open() on
// the StandardFileSystemInterface, which returns a ReadFileStream object.
// We then repeated read a line from the file (by calling ReadfromFile()),
// print it (by calling WriteToScreen()), signal the student process to
// read a line from the keyboard, wait for the line to be read and compare
// the line read from the keyboard with the line from from the file.
// We continue to read lines from the keyboard and compare them with
// the line read from the file until they match.
//
// We quit when the file runs out of lines or when the user presses '#'
// (the student process signals this by storing false in NotEnd). Just
// before we quit, we wake up the student process.
//
// The StandardFileSystemInterface is a special global variable that
// is used for accessing file services.

// Lightweight process created in main() starts here.
int error;
// Open the file "in.1" for reading.
ReadFileStreamStar inf = StandardFileSystemInterface -> open
("in.1", ReadFileStreamClass, error);
if (error)
{
*StandardOutput << "*** error opening file \n" << eor;
return 0;
}

*StandardOutput << "Type a sequence of keys ending with #\n" << eor;
Line *teacherline = new Line;
// Read the first line from the file and print it.
teacherline -> ReadfromFile (inf, NotEnd);
teacherline -> WriteToScreen (StandardOutput);
sem -> V(); // Wake up the student process to read a line from keyboard.
sem -> P(); // Wait for the student process to finish reading the line.
while (NotEnd)
{
// NotEnd is true if user didn't type '#'. Check whether the line that
// the user has typed is equal to the line we have just read.
if (equal (studentline, teacherline))
{
// If so, read the next line from the file and print it. NotEnd is
// set to false if there are no more lines to be read from the file.
teacherline -> ReadfromFile (inf, NotEnd);
teacherline -> WriteToScreen (StandardOutput);
}
else
// The lines don't match; tell the user to type again.
*StandardOutput << "Try again\n" << eor;
if (NotEnd)
{
sem -> V(); // Wake up student process to read a line from keyboard.
sem -> P(); // Wait for student process to finish reading the line.
}
}
sem -> V(); // Wake up student process in case it's still waiting.
delete teacherline;
// This process dies here.
return 0;
}

int main (int, char **)
{
// This process runs as the student process, reading lines from the
// keyboard and waking up the teacher process when the lines are ready.
// In this process, we first create a semaphore for synchronizing the
// two processes. We then fetch the SystemTimer from the StandardName
// Server by calling lookup(). We create the teacher process and
// make it runnable by calling ready() on the process. By calling
// time() on the SystemTimer, we obtain the current system time in
// microseconds; this value is stored in "start".
//
// After that, we repeatedly read lines from the keyboard, print them,
// signal the teacher process to process the line and wait for the teacher
// process to finish processing the line. We stop when the user presses
// '#' or when the file runs out of lines (parent process indicates this
// by storing false in NotEnd). Next, we signal the teacher process
// to wake up. Finally we print out the duration of the session by
// subtracting the starting time ("start") from the current time
// (obtained by calling time() on the SystemTimer).
//
// Lines read from the keyboard are stored in the global variable
// studentline. studentline is read from the keyboard by calling
// ReadfromKeyboard(); studentline is printed by calling WriteToScreen().
//
// StandardNameServer is a special global variable used for fetching
// system objects.

// Create a semaphore and set its counter to 0.
sem = new Semaphore (0);
unsigned int start, duration;
// Fetch the system timer from the StandardNameServer.
FreeRunningTimerStar SystemTimer = (FreeRunningTimerStar)
StandardNameServer -> lookup ("SystemTimer", "FreeRunningTimer" );

// Create the teacher process which will start execution at main2().
ProcessStar proc = new ApplicationProcess (main2);
// Process will not run until we ready() it.
proc -> ready ();
// Remember the time now.
start = SystemTimer -> time ();
// Wait for teacher process to read a line from the file and print it.
sem -> P ();
while (NotEnd)
{
// NotEnd is true if the file hasn't run out of lines. Read a line
// from the keyboard and set NotEnd to false if user types '#'.
studentline -> ReadfromKeyboard (StandardInput, NotEnd);
studentline -> WriteToScreen (StandardOutput);
if (NotEnd)
{
sem -> V (); // If user didn't type '#', wake up the teacher process.
sem -> P (); // Wait for teacher process to read a line from the file.
}
}
sem -> V (); // Wake up the teacher in case it's still waiting.

delete studentline;
// Print the total duration of this session.
duration = SystemTimer -> time () - start;
*StandardOutput << "Time typing " << duration << " microseconds\n" << eor;
return 0;
}


  3 Responses to “Category : Alternate Operating Systems - Quarterdeck DesqView, CP/M, etc
Archive   : PCCAPP.ZIP
Filename : TYPE2.CC

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/