D.14. splitter.g

[Note]

This has been moved to doc/i/tutorial/.

#!/usr/cogent/bin/gamma

/*
 * This program reads a Gamma program that has been marked up with
 * processing instructions, and splits it into chunk files suitable
 * for inserting into documentation text.  It then writes a copy of the
 * program without the processing instructions.  The source program name
 * should have an extra character (I usually use "d") before the ".g",
 * like this: <programname>d.g
 * The final program name will not have the final character, like this:
 * <programname>.g
 * The chunk files should be of this format:
 * <programname>_<#>.g
 * where <#> is an integer representing the cardinal order of the chunks.
 *
 * Most of the functions in this program are processing instructions that are
 * called from a source program, as special comment lines, with this format:
 *
 * //PI (setq write_file (doc_begin <filename>))   - opens the file.
 * //PI (setq enabled 1)                           - starts writing.
 * //PI (setq enabled 0)                           - finishes writing.
 * //PI (setq write_file (doc_end write_file))     - closes the file.
 * //PI (doc_newfile <filename>)         - finishes and closes a file,
 *                                         then opens and starts a new
 *                                         file, for convenience.
 * 
 * If a file has been opened, you can call this function:
 * //PI (doc_embed_string write_file <string>)   - writes the string.
 */

PI_PATH = "../../i/tutorial/";

if (root_path(cadr(argv)) == "../../i/tutorial")
     BASENAME = basename(cadr(argv), "d.g");
else
     BASENAME = string("lib/", basename(cadr(argv), "d.g"));

     

function doc_begin(!filename)
{
  local fp;
  if (!undefined_p(eval(filename)))         // This is necessary for calls
    filename = eval(filename);              // from doc_newfile().
  if (fp = open (string(PI_PATH, "chunks/", filename), "w"))
    fp;
  else
    error (string("Failed to open file: ", filename));
}


function doc_end(fp)
{
  flush(fp);
  close(fp);
  nil;
}


function doc_embed_string(fp, string)
{
  writec(fp, string);
}


/* This is a convenience function that compresses these four
   lines of code in the program to one line.*/

function doc_newfile(!fl)
{
  enabled = 0;
  doc_end(write_file);
  write_file = doc_begin(fl);
  enabled = 1;
}
     

function main()
{
  local fr, preproc_file = nil, evs, line = nil, dv,
        write_file = nil, enabled = 0, pilist = list();

  /* Preprocess the file to change any \n to PI_NEWLINE
     to hide it from the parser */
  
  system(string("sed ", PI_PATH, BASENAME, "d.g -e 's/\\\\n/PI_NEWLINE/g' > temp"));
  system(string("mv temp ", PI_PATH, "preproc_file"));

  if (fr = open(string(PI_PATH, "preproc_file"), "r"))
    {

      /* Make the chunk files. */
  
      line = read_line(fr);
      while (line != _eof_)
	{
	  if (strstr(line, "//PI") == 0)
	    {
	      evs = eval_string(substr(line, 4, -1));
	    }
	  if ((write_file != nil) &&
	      (enabled == 1) &&
	      (strstr(line, "//PI") != 0))
	    {
	      writec(write_file, string("   ", line, "\n"));
	    }
	  line = read_line(fr);
	}
      close(fr);


      /* Create a distribution version of the code with
	 all processing instructions removed. (This makes a
	 call to the Perl program replacer.pl.)  */
      
      dn = string(PI_PATH, BASENAME, ".g");
      system(string("grep -v \'\/\/PI\' ",
		    PI_PATH, 
		    BASENAME,
		    "d.g > ",
		    dn));
      system(string(PI_PATH, "replacer.pl ", dn));

      /* Make a list of all chunk files */
      
      system(string("ls ", PI_PATH, "chunks/", basename(BASENAME), "_*.g > temp"));
      fp = open("temp", "r");
      line = nil;

      while (line != _eof_)
	{
	  if (line != nil)
	    pilist = cons(line, pilist);
	  line = read_line(fp);
	}
      close(fp);


      /* Call the replacer.pl script to replace all tabs and newlines
	 for every chunk file in the list.  */
      
      with x in pilist do
	{
	  system(string(PI_PATH, "replacer.pl ", x));
	}
    }
  else
    error (string("Failed to open file: ", file));  
}