Next: , Previous: , Up: Top   [Index]


File input and output

Input and Output

This chapter describes how Ctalk performs basic file operations - opening, closing, reading, and writing files.

There are three classes that provide file input and output: ReadFileStream, which implements objects and methods for reading from files, WriteFileStream, which provides methods and objects for writing to files, and their superclass, FileStream, which provides methods and class definitions that are common to both reading and writing files. There is also a DirectoryStream class, which this chapter describes below.

Ctalk provides many of the same facilities that C’s stdio.h library functions provide, although the language implements them as objects.

Here is an example that shows how to use the openOn method (class ReadFileStream).

ReadFileStream new myInput;

myInput openOn "myFileName";

If the program was able to to open the file, you can then read input from the myInput stream.

We should note here that Ctalk also provides classes and methods that handle file I/O errors. We will deal with them later on. If you need to see how to catch file I/O errors right now, look at some of the example programs in the Ctalk package, especially ctwc.c.

Opening a file for output is similar to opening a file for input, except that the stream is an instance of class WriteFileStream.

WriteFileStream new myOutput;

myOutput openOn "outputFileName";

After a program has opened the file streams successfully, you can read and write from them with the following methods.

Operation                           Reading    Writing
---------                           -------    -------
Read or write one character.        readChar   writeChar
Read or write one line.             readLine   -
Read or write all the data.         readAll    writeStream
Read or write formatted data.       readFormat printOn
Read fixed length data.             readRec

Here is a simple example that shows opening a file, and reading each character.

ReadFileStream new inputChars;
Character new c;

inputChars openOn "inputFileName";

while ((c = inputChars readChar) != EOF) 
  printf ("%c", c);

When readChar reaches the end of a file, it returns an EOF character, which is ‘-1’ on most systems.

Using the method streamEof (class FileStream) to check for the end of the input is slightly more reliable than looking for an EOF character, because it distinguishes the end of the input caused by an error from the end of the input caused by reaching the end of a file.

ReadFileStream new inputChars;
Character new c;

inputChars openOn "inputFileName";

while (TRUE) {             /* Loop until the end of the input. */
  c = inputChars readChar;
  if (inputChars streamEof)
    break;
}

If you don’t need to examine each character as it is read, however, then you can simply use readAll (class ReadFileStream), which provides the complete input as a String object.

ReadFileStream new inputStream;
String new inputString;

inputStream openOn "myInput";
inputString = inputStream readAll;
printf ("%s", inputString);

Simple applications can use the methods readLine (class ReadFileStream) and writeStream (class WriteFileStream) together to process input.

Here is a portion of the program ctrep.c. You find the program in the Ctalk package. It checks the input for occurrences of a character string, and replaces the string before writing the output.

/*
 *  Loop until the end of input.
 */
while (TRUE) {
  line = stdinStream readLine;
  if (stdinStream streamEof)
    break;
  inputLineLength = line length;

  word = "";

  for (i = 0; i < inputLineLength; i = i + 1) {
    inputChar = line at i;
    if (inputChar isSpace) {
    if (word == pattern) {
      stdoutStream writeStream replacement;
    } else {
      stdoutStream writeStream word;
    }
      stdoutStream writeStream inputChar;
      word = "";
    } else {
      word = word + inputChar asString;
    }
  }
}

Standard Input and Standard Output

Notice that the previous example used stdinStream and stdoutStream as its input and output streams.

These two objects are class variables of ReadFileStream and WriteFileStream, respectively. They represent the program’s standard input (stdin) and standard output (stdout) file streams.

Because ctrep.c is a filter program, it uses these two streams instead of streams that work with normal files.

Class WriteFileStream also implements the stderrStream class variable, which represents the application’s standard error (stderr) stream.

You should notice, also, that most of the examples so far have used printf to print output. You can accomplish the same task with the following Ctalk statement.

stdoutStream writeStream "Hello, world!\n";

This is equivalent to:

printf ("Hello, world!\n");

Ctalk initializes stdinStream automatically when the program creates the first ReadFileStream object, and it initializes stdoutStream and stderrStream when the program creates the first WriteFileStream object.

If the program simply needs to use stdinStream, stdoutStream, or stderrStream without opening files, then it can call the class method classInit with either the class ReadFileStream or WriteFileStream as the receiver.

ReadFileStream classInit;    /* Initialize stdinStream. */
WriteFileStream classInit;   /* Initialize stdoutStream and stderrStream. */

Here is the example from the previous chapter that printed elements of arrays. This version uses stdoutStream to output the array elements.

Array instanceMethod printArrayElement (void) {

  WriteFileStream classInit;

  stdoutStream writeStream self;

  return NULL;
}

int main () {

  Array new myArray;

  myArray atPut 0, "My";
  myArray atPut 1, "name";
  myArray atPut 2, "is";
  myArray atPut 3, "Bill";

  myArray map printArrayElement;

  printf ("\n");

  myArray atPut 3, "Joe";

  myArray map printArrayElement;

  printf ("\n");
}

The printArrayElement method initializes class WriteFileStream. You need to perform the class initialization before the class is first used in the program. There is no problem with calling classInit multiple times, however, because the method checks to determine if the class is already initialized.

Directories

The class DirectoryStream provides the methods mkDir and rmDir which create and delete directories. The methods function exactly as their C library counterparts, except that they raise a SystemErrnoException on error and return an Integer with the value -1.

Ctalk uses 0755 (‘drwxr-xr-x’) as the default mode for new directories. Programs can change that value by redefining the macro CTALK_DIRECTORY_MODE.

Here is a program that creates a new directory.

/* 
 * Define more restrictive permissions for 
 * new directories. Undefine the macro first
 * to avoid a warning message.
 */
#undef CTALK_DIRECTORY_MODE
#define CTALK_DIRECTORY_MODE 0700

int main () {

  DirectoryStream new thisDir;

  thisDir mkDir "testDir";

}

The rmDir method works similarly to the mkDir method.

int main () {

  DirectoryStream new thisDir;

  thisDir rmDir "testDir";

}

Standard Input and Standard Output Implementations

The C99 standard requires that stdin, stdout, and stderr should be implemented as macros, which on some systems (notably Solaris) causes problems with C-to-object translation.

If Ctalk cannot register the macros as C variables, then you must call C functions like sscanf(3) and fscanf(3) with only C variables, or use a method with stdoutStream or stderrStream (WriteFileStream class), or stdinStream (ReadFileStream class).

Console Input

The method consoleReadLine (in class String) prints a prompt string, and then waits for you to enter a line of text. What makes this method special is that it uses the GNU readline library’s standard command editing and history features, if you built Ctalk with readline support (see the options to the configure script for details). In that case, Ctalk also defines the HAVE_GNU_READLINE macro to ‘1’. Here is an simple example of how to use consoleReadLine.

int main (int argc, char **argv)    String new s;
  String new promptStr;

  if (argc > 1)
    promptStr = argv[1];
  else
    promptStr = "Prompt ";

  printf ("Readline test.  Type ^C or, \"quit,\" to exit.\n");
#if HAVE_GNU_READLINE
  printf ("Ctalk built with GNU Readline Support.\n");
#else
  printf ("Ctalk built without GNU Readline Support.\n");
#endif
  while (1)      s consoleReadLine promptStr;
    printf ("You typed (or recalled), \"%s.\"\n", s);
    /*
     *  Matches both, "quit," and, "quit\n."
     */
    if (s match "quit")
      break;
  }
}

Next: , Previous: , Up: Top   [Index]