From dennis@peanuts.nosc.mil Fri Feb 19 16:43:39 1988 Return-Path: Received: from anl-mcs.ARPA by antares.mcs.anl (3.2/SMI-3.2) id AA04172; Fri, 19 Feb 88 16:43:35 CST Received: from cod.nosc.mil (cod.nosc.mil.ARPA) by anl-mcs.ARPA (4.12/4.9) id AA05162; Fri, 19 Feb 88 16:44:01 cst Received: from woodstock.nosc.mil by cod.nosc.mil (5.58/1.27) id AA23841; Fri, 19 Feb 88 14:46:13 PST Message-Id: <8802192246.AA23841@cod.nosc.mil> Received: by peanuts.nosc.mil; Fri, 19 Feb 88 14:43:36 pst Date: Fri, 19 Feb 88 14:43:36 pst From: dennis@peanuts.nosc.mil (Dennis Cottel) To: dongarra%antares@anl-mcs.arpa Subject: Re: netlib submission: DM_FORMAT Status: RO Rats, Jack, I'm sorry. DM_FORMAT is Apollo software. I didn't even think to make it explicit since that's about all I'm working with here. To make matters worse, a user pointed out away to generalize a recent change, so the package below should supersede what I sent you previously. I regret the confusion... --Dennis #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # dm_format.hlp # dm_format.c # This archive created: Fri Feb 19 14:37:26 1988 export PATH; PATH=/bin:$PATH echo shar: extracting "'dm_format.hlp'" '(8190 characters)' if test -f 'dm_format.hlp' then echo shar: will not over-write existing file "'dm_format.hlp'" else sed 's/^X//' << \SHAR_EOF > 'dm_format.hlp' X1.0;DM_FORMAT,2/16/87. XDM_FORMAT -- On-screen DM text formatter. XUsage: (see below) X XDESCRIPTION: X------------ X DM_FORMAT implements an on-screen text formatter for the Display Manager. X To use it, start a DM_FORMAT process and define a key to interact with it X (as described below). Now select the region to be formatted and hit the X format key --- the region will be replaced by its formatted version. X XSTARTING THE DM_FORMAT PROCESS: X------------------------------- X Execute the following DM command: X X (0,0)dr; (400,80)cp /user/local/com/dm_format -n dm_format; wi dm_format X X Place this line in your ~/user_data/startup_dm file if you want the process X started automatically when you log in. X X Note a problem with Apollo's DM (at SR9.7): if this window is not wide enough X to hold the text for a command, it will be truncated. X XSETTING UP A KEY DEFINITION: X---------------------------- X The most general way to set up the command is to define a key (e.g., F1) X as follows: X X kd f1 xd -f /tmp/dm_format.in;rm;wi -w dm_format;es'@&'Format: '';en ke X X If you wish to format the selected region and have the formatted output X inserted in your file WITHOUT replacing the original text, you can define X F1 to COPY the region rather than CUT it: X X kd f1 xc -f /tmp/dm_format.in;rm;wi -w dm_format;es'@&'Format: '';en ke X X See the EXAMPLES section below for variations on this theme. X XUSING DM_FORMAT TO FORMAT TEXT: X------------------------------- X To format a paragraph, select the lines of the paragraph just as if you X were going to delete it. But instead of typing CUT, type F1 (the format X key). Now type one of the following DM_FORMAT commands in response to the X "Format: " prompt in the command window (replace the "nn" with the column X number desired): X X F nn -- fill up to column nn (ragged right) X J nn -- justify to column nn (both margins aligned) X C nn -- center line by line between columns 1 and nn X U -- continuously underline text X | pgm -- filter region through PGM, replacing it with output of PGM X (e.g., to sort some text, format it using "| srf"). X X The paragraph will be replaced by a new, formatted version. (You can use X UNDO to get back the original.) You can format more than one paragraph at X a time -- just select all the paragraphs you want together. X XERRORS and WARNINGS: X-------------------- X Please make sure the DM_FORMAT window is invisible at the time you hit F1 X (the format key). If an error occurs during DM_FORMAT processing, the X original text in your file is restored and the DM_FORMAT window is left X visible so that you can see the error message (after which you should make X the DM_FORMAT window invisible by hand (via WI) before using it again). X X You MUST mark the beginning of the text to be formatted. The default X action that works for most commands ("from here to the end of line") does X not put a mark on the DM stack properly, and so the algorithm used here X will fail. X XHINTS and EXAMPLES: X------------------- X1. If you use a particular formatting command often, you may set up a key to X execute that command without prompting you at all. For example, if you X often fill text to column 76, you could define a key (e.g., F1) as follows: X X kd f1 xd -f /tmp/dm_format.in;rm;wi -w dm_format;es'f 76';en ke X ------ X X2. Similarly, if you underline stuff often, you could define F1 as follows: X X kd f1 xd -f /tmp/dm_format.in;rm;wi -w dm_format;es'u';en ke X --- X X3. To fill the current paragraph (the block of text surrounding the cursor) X to column 78 with one keystroke, define F1 as follows: X X kd f1 \%[ ]*@@n\;ad;cms;dr;echo;/%[ ]*@@n/;ad;xd -f /tmp/dm_format.in;rm;wi -w dm_format;es 'f 78';en ke X X4. If you want to justify text to different columns, you can get F1 to prompt X you for just the column number using: X X kd f1 xd -f /tmp/dm_format.in;rm;wi -w dm_format;es'j @&'Justify to column: '';en ke X ---------------------------- X X5. If you always use, say, 80 columns, you can get F1 to prompt you for the X particular command you want (fill, justify, center) using: X X kd f1 xd -f /tmp/dm_format.in;rm;wi -w dm_format;es'@&'Format command: ' 80';en ke X -------------------------- X X The basic idea is to tweak the arguments to the ES command to insert or X prompt you for the appropriate stuff. X X6. If you wish to filter the selected region through some program and have the X output of the program inserted in your file WITHOUT replacing the original X text, you can define F1 to COPY the region rather than CUT it: X X kd f1 xc -f /tmp/dm_format.in;rm;wi -w dm_format;es'@&'Format: '';en ke X -- X For example, you could count the number of words in a file and insert the X word count into the file by marking the entire file and typing '| wc' X or '| flen' in response to the 'Format: ' prompt, using the above key def. X X7. To do fancier text formatting, you can easily filter your text through X your favorite word processor (e.g., FMT or SCRIBE). Simply type in your X text (including FMT commands), and format it using '| fmt', etc. X XNOTES ON DM_FORMAT: X------------------- X DM_FORMAT sets the left margin of each paragraph to be the number of spaces X preceeding the first word when filling or justifying. For example, filling X this text: X ------------------------------------------------------------------ X This is the X first sentence of the first paragraph. This is the second X sentence of the X first paragraph. X ------------------------------------------------------------------ X X yields: X ------------------------------------------------------------------ X This is the first sentence of the first paragraph. This is the second X sentence of the first paragraph. X ------------------------------------------------------------------ X X This lets you fill many paragraphs with indented displays interspersed. X Fill and justify work paragraph by paragraph; Center works line by line. X X A failing of many text processors is that they don't handle spacing after X punctuation properly. DM_FORMAT borrows a trick from EMACS -- it tries to X preserve the original spacing between words. So if you type two spaces X after a period, there will be two spaces in the filled output. If you X type one space, there will be one space in the output. If you type two X spaces between words, those two spaces will be preserved (even if there is X no punctuation). The advantage is that you can produce correct spacing; X the disadvantage is that you have to be slightly more careful as a typist. X X DM_FORMAT also knows about single letters followed by period (e.g. "John X C. Doe") and a few common abbreviations (e.g. "e.g.", "i.e.", "Mr.", X etc.), for the infrequent times when these abbreviations occur at the end X of a line. This stuff is borrowed from DM_FILL. X X The filter region command `|' invokes the given program, which must take X its input from standard input and produce its output on standard output, X and replaces the marked region with the output of the program (VI or EMACS X provide similar commands). For example, to sort some text, mark the X region and format it using "| srf". DM_FORMAT looks for the program in X your CSR. To check the CSR you're getting, just filter some dummy thing X using "| csr". The invoked program may be either a shell script or a X binary file. You may always specify the full pathname, of course. X XAUTHOR: X------- X Author: Ashwin Ram X Written: 7/25/86 X Release: 2/16/87 X Credits: Inspired by the original DM_FILL command at Yale. X Bug reports, comments and suggestions welcome. X XIDENTIFICATION: X--------------- X $Revision: 1.5 $ $Date: 88/02/19 14:18:14 $ SHAR_EOF if test 8190 -ne "`wc -c < 'dm_format.hlp'`" then echo shar: error transmitting "'dm_format.hlp'" '(should have been 8190 characters)' fi chmod +x 'dm_format.hlp' fi # end of overwriting check echo shar: extracting "'dm_format.c'" '(18393 characters)' if test -f 'dm_format.c' then echo shar: will not over-write existing file "'dm_format.c'" else sed 's/^X//' << \SHAR_EOF > 'dm_format.c' X/***************************************************************************\ X DM_FORMAT.C -- A program to format text in a DM edit window. X Author: Ashwin Ram X Written: 7/25/86 (my very first C program.) X Credits: Inspired by the original DM_FILL command at Yale. X Put temporary files in /tmp -- 7/87 dennis@nosc.mil X Fixed so piping through a filter program gets user's correct X CSR path, and handles arguments to the program. -- 2/88 dennis@nosc.mil X\***************************************************************************/ X Xstatic char rcsid[] = X "$Header: //pumpkin_patch/local/source/dm_format/dm_format.c,v 1.6 88/02/19 14:06:16 dennis Exp $Purdue CS"; X X#include X X#define max_word_length 100 /* Max length of a single word */ X#define max_line_length 500 /* Max width of output line */ X X#define end_of_file 1 /* Token types returned by GET_WORD */ X#define end_of_para 2 X#define normal_word 3 X X/* #define INPUT_FILE "/tmp/dm_format.in" */ X/* #define OUTPUT_FILE "/tmp/dm_format.out" */ X X/***************************************************************************\ X Global variables. X\***************************************************************************/ X XFILE *in_stream; XFILE *out_stream; X Xchar word [max_word_length + 1]; /* Next word read from input */ Xint word_length; /* Incl. leading blanks */ Xint leading_blanks; /* In WORD buffer */ X Xint right_margin; /* Last output text column */ Xchar command; /* FORMAT command to be exec'd */ Xchar *pgm; /* PGM for | (filter) */ Xchar *dummy; /* Used to flush input lines */ X Xchar buffer [max_line_length + 1]; /* Output line being assembled */ X X/***************************************************************************\ X Loops forever, doing a FORMAT cycle each time it sees input. X Input formats: X J n -- justify to N X F n -- fill upto N X C n -- center line-by-line with right margin N X U -- underline X | pgm -- filter region through PGM, replacing it with the output of PGM X\***************************************************************************/ X Xmain () X{ X int f; X X while (1) { X if (get_command ()) { X if (open_streams ()) { X f = format (right_margin, command); X close_streams (); X if (f) { X if (! pop_formatted_file ()) X pop_original_file (); X } X else pop_original_file (); X } X } X } X} X X/***************************************************************************\ X Gets input command. X COMMAND = FORMAT command to be executed (one character). X RIGHT_MARGIN = column to which to fill or justify. X\***************************************************************************/ X Xint get_command () X{ X int items; X X items = scanf ("%1s", &command); X/* X if ...error... { X printf ("?(dm_format) Error in input\n"); X gets (&dummy); X return (0); X } X*/ X X return (1); X} X X/***************************************************************************\ X Opens input and output streams. X\***************************************************************************/ X Xint open_streams () X{ X in_stream = fopen ("/tmp/dm_format.in", "r"); X if (in_stream == 0) { X printf("?(dm_format) Can't open '/tmp/dm_format.in'\n" ); X gets (&dummy); X return (0); X } X X out_stream = fopen ("/tmp/dm_format.out", "w"); X if (out_stream == 0) { X printf ("?(dm_format) Can't open '/tmp/dm_format.out'\n"); X gets (&dummy); X fclose (in_stream); X return (0); X } X X return (1); X} X X/***************************************************************************\ X Closes input and output streams. X\***************************************************************************/ X Xclose_streams () X{ X fclose (in_stream); X fclose (out_stream); X} X X/***************************************************************************\ X Executes one FORMAT command. X\***************************************************************************/ X Xint format () X{ X if (command == 'j' || command == 'J') { X scanf ("%d", &right_margin); X fill (1); X return (1); X } X X if (command == 'f' || command == 'F') { X scanf ("%d", &right_margin); X fill (0); X return (1); X } X X if (command == 'c' || command == 'C') { X scanf ("%d", &right_margin); X center (); X return (1); X } X X if (command == 'u' || command == 'U') { X underline (); X return (1); X } X X if (command == '|') { X/* scanf ("%s", &pgm); */ X gets (&pgm); X return (filter_region ()); X } X X printf ("?(dm_format) Unrecognized command -- %1s\n", &command); X gets (&dummy); X return (0); X} X X/***************************************************************************\ X Gets an input token into WORD buffer. Also sets LEADING_BLANKS and X WORD_LENGTH (where WORD_LENGTH - LEADING_BLANKS is the actual word length). X\***************************************************************************/ X Xint get_word () X{ X static int c = -1; X static int previous_token = end_of_file; X int newline_count; X X word_length = 0; X leading_blanks = 0; X X if (c == -1) X c = getc (in_stream); X X newline_count = 0; X while (1) { X if (c == EOF) { X word_length = 0; X word [0] = 0; X return (previous_token = end_of_file); X } X else if (c == '\n') { X word_length = 0; X word [0] = 0; X if (++newline_count >= 2) X return (previous_token = end_of_para); X } X else if (c != ' ' && c != '\t') X break; X else { X if (word_length >= max_word_length) X word_length = 0; X word [word_length++] = c; X } X c = getc (in_stream); X } X X /* Delete leading blanks at beginning of line, unless it's the first *\ X line in the para. But don't delete blanks between words since we X \* want to retain the spacing. */ X X leading_blanks = word_length; X if (newline_count == 1 && previous_token != end_of_para) { X word_length = 0; X leading_blanks = 0; X } X X while (1) { X if (c == EOF || c == ' ' || c == '\t' || c == '\n' || X word_length > max_word_length) { X word [word_length] = 0; X return (previous_token = normal_word); X } X word [word_length++] = c; X c = getc (in_stream); X } X} X X/***************************************************************************\ X Checks for common abbreviations in WORD buffer. X\***************************************************************************/ X Xchar *abbreviations[] = { X "Mr.", X "Mrs.", X "Ms.", X "i.e.", X "I.e.", X "e.g.", X "E.g.", X "etc.", X "Prof.", X "Dr.", X 0, X }; X Xint common_abbreviation () X{ X int i; X int j; X char c; X X j = leading_blanks; X if (j < word_length - 1) { X c = word[j]; X if (c=='(' || c=='[' || c=='{' || c=='`' || c=='\'' || c=='"') X j++; X } X for (i = 0; abbreviations[i] != 0; i++) X if (strcmp (abbreviations[i], &buffer[j]) == 0) X return (1); X return (0); X} X X/***************************************************************************\ X Fills or justifies from IN_STREAM into OUT_STREAM. X\***************************************************************************/ X Xfill (justify) X int justify; /* Justify, or merely fill? */ X{ X int paragraph_count; /* Paras in input file */ X int word_count; /* Words in each para */ X int words_in_line; /* Words in current line */ X int beginning_of_sentence; /* Currently at beginning of sentence? */ X int left_margin; /* Left margin, set by first word in para */ X int last_column; /* Current position in output BUFFER */ X int space_needed; /* Blanks needed between words */ X int next_token; /* Type of next thing read from input */ X int previous_token = end_of_para; X int i; X int c; X X for (paragraph_count = 1; ; paragraph_count++) { X X beginning_of_sentence = 0; X words_in_line = 0; X buffer[1] = 0; X X for (word_count = 1; ; word_count++) { X X next_token = get_word (); X words_in_line++; X X if (next_token == end_of_file) { X if (previous_token != end_of_para) X fputs (&buffer[1], out_stream); X fputs ("\n", out_stream); X return; X } X else X previous_token = next_token; X X if (next_token == end_of_para) { X fputs (&buffer[1], out_stream); X fputs ("\n", out_stream); X break; X } X X if (leading_blanks <= 0) X if (beginning_of_sentence) X space_needed = 2; X else X space_needed = 1; X else X space_needed = 0; X X if (word_count == 1) { X if (paragraph_count > 1) X fputs ("\n", out_stream); X strcpy (&buffer[1], &word[0]); X left_margin = leading_blanks; X last_column = word_length; X } X else if (last_column + word_length + space_needed > right_margin) { X if (justify == 1) X spread (last_column, left_margin, right_margin, words_in_line-1); X fputs (&buffer[1], out_stream); X fputs ("\n", out_stream); X for (i = 1; i <= left_margin; i++) X buffer[i] = ' '; X strcpy (&buffer [left_margin + 1], &word [leading_blanks]); X last_column = left_margin + word_length - leading_blanks; X words_in_line = 0; X } X else { X for (i = 1; i <= space_needed; i++) X buffer [last_column + i] = ' '; X strcpy (&buffer [last_column + i], &word [0]); X last_column = last_column + space_needed + word_length; X } X X /* Don't start a sentence if the period follows an abbrev *\ X \* or if the previous word only had one char (ie, an initial). */ X X c = buffer [last_column]; X beginning_of_sentence = (c == '.' || c == '!' || c == '?') X && (word_length - leading_blanks > 2) X && (! common_abbreviation ()); X } X } X} X X/***************************************************************************\ X Spreads the line in BUFFER to justify it to column RIGHT_MARGIN. X\***************************************************************************/ X Xspread (last_column, left_margin, right_margin, num_words) X int last_column; X int left_margin; X int right_margin; X int num_words; X{ X static int dir = 1; /* 0 = l-to-r, 1 = r-to-l (to avoid "rivers") */ X int blanks; /* Number of blanks needed to justify this line */ X int each; /* Number of blanks needed per hole */ X int extra; /* Number of holes with one extra blank each */ X int holes; /* Number of holes between words */ X int count; /* Counter for current hole being processed */ X int nblanks; /* Counter for blanks being inserted in a hole */ X int i; /* Current position in original buffer */ X int j; /* Current position being transferred to */ X X buffer[right_margin+1] = 0; X X if ((holes = num_words - 1) <= 0 || X (blanks = right_margin - last_column) <= 0) X return; X X dir = 1 - dir; X each = blanks / holes; X extra = blanks - (each * holes); X i = last_column; X j = right_margin; X X for (count = 1; count <= holes; count++) { X while ((buffer[j--] = buffer[i--]) != ' '); X for (nblanks = 1; nblanks <= each; nblanks++) X buffer[j--] = ' '; X if ((dir == 1 && count <= extra) || (dir == 0 && count >= (holes-extra+1))) X buffer[j--] = ' '; X if (j == i) X return; X while (buffer[i] == ' ') X buffer[j--] = buffer[i--]; X } X} X X/***************************************************************************\ X Centers line-by-line from IN_STREAM into OUT_STREAM. X\***************************************************************************/ X Xcenter () X{ X int blanks_needed; /* Number of blanks needed on each side */ X int in_line; /* Are we within a line? */ X int i; X int c; X X while (1) { X i = 1; X in_line = 0; X while ((i < max_line_length) && ((c = getc (in_stream)) != EOF) && (c != '\n')) X if (in_line || ((c != ' ') && (c != '\t'))) { X buffer[i++] = c; X in_line = 1; X } X buffer[i] = '\0'; X if (i > 1) { X blanks_needed = (right_margin - i) / 2; X for (i = 0; i < blanks_needed; i++) X fputs (" ", out_stream); X } X fputs (&buffer[1], out_stream); X if (c == '\n') X fputs ("\n", out_stream); X else if (c == EOF) X return; X else { /* Separate this since seldom called */ X while ((c = getc (in_stream) != EOF) && (c != '\n')); X if (c == '\n') X fputs ("\n", out_stream); X else if (c == EOF) X return; X } X } X} X X/***************************************************************************\ X Underlines non-blank characters from IN_STREAM into OUT_STREAM. X\***************************************************************************/ X Xunderline () X{ X int c; X X while (1) { X c = getc (in_stream); X if (c == ' ' || c == '\t' || c == '\n') X putc (c, out_stream); X else if (c == EOF) X return; X else { X putc (c, out_stream); X putc ('\010', out_stream); X putc ('_', out_stream); X } X } X} X X/* This doesn't work perfectly because the DM can't cut and paste control *\ X characters very well. XP -F will paste the underlined characters but X\* the DM is only mediocre at editing lines with these characters in it. */ X X/***************************************************************************\ X Apollo/Aegis/DM-dependent routines: X\***************************************************************************/ X X#include X#include X#include X#include X#include X X/***************************************************************************\ X Filters input through specified PGM by invoking PGM appropriately. X\***************************************************************************/ X Xint filter_region () X{ X status_$t status; X pgm_$connv connv; X pgm_$arg a0, a1, a2, a3, a4, a5, *argv[128]; X pgm_$proc handle; X X /* Don't know how to bind standard input and standard output for the *\ X invoked program, so close the streams and use SH for redirection. X This also gives us CSR lookup for free; further, we can filter X \* stuff through shell scripts as well as binary files. */ X X close_streams (); X X/* This works but terminates the program. X execl ("/com/sh", "sh", , &pgm, "/tmp/dm_format.out", 0); X*/ X X strcpy (a0.chars, "sh"); a0.len = 2; argv[0] = &a0; X strcpy (a1.chars, "-start"); a1.len = 6; argv[1] = &a1; X strcpy (a2.chars, "-c"); a2.len = 2; argv[2] = &a2; X strcpy (a3.chars, &pgm); a3.len = strlen (&pgm); argv[3] = &a3; X strcpy (a4.chars, "/tmp/dm_format.out"); a5.len = 19; argv[5] = &a5; X X pgm_$invoke ("/com/sh", 7, 6, argv, 0, connv, pgm_$wait, handle, status); X X if (status.all != status_$ok) { X printf ("?(dm_format) Error invoking %s -- status %d\n", &pgm, status.all); X/* error_$print (status); */ X return (0); X } X X return (1); X X} X X/***************************************************************************\ X Goes to edit window and pops formatted text back into the window, then X makes the DM_FORMAT process window invisible. X\***************************************************************************/ X X#define cmd1 "gm; xp -f /tmp/dm_format.out; wi -i dm_format" X#define cmd1len 45 X Xint pop_formatted_file () X{ X status_$t status; X X pad_$dm_cmd (stream_$stdin, cmd1, cmd1len, status); X if (status.all != status_$ok) { X printf ("?(dm_format) Couldn't return formatted text to edit window -- status %d\n", &status.all); X return (0); X } X X return (1); X} X X/***************************************************************************\ X Goes to edit window and pops original text back into the window. Leaves X DM_FORMAT window visible so user can see the error. X\***************************************************************************/ X X#define cmd2 "gm; xp -f /tmp/dm_format.in" X#define cmd2len 27 X Xpop_original_file () X{ X status_$t status; X X pad_$dm_cmd (stream_$stdin, cmd2, cmd2len, status); X if (status.all != status_$ok) X printf ("?(dm_format) Couldn't return original text to edit window -- status %d\n", &status.all); X} X X/***************************************************************************\ X End. X\***************************************************************************/ X SHAR_EOF if test 18393 -ne "`wc -c < 'dm_format.c'`" then echo shar: error transmitting "'dm_format.c'" '(should have been 18393 characters)' fi chmod +x 'dm_format.c' fi # end of overwriting check # End of shell archive exit 0 .