Network Working Group M. Wildgrube Internet Draft Document: draft-wildgrube-preprfc-03.txt November 2000 Category: Experimental Expiration Date: April 2001 Preparation of text in RFC style STATUS OF THIS MEMO: This document is an Internet-Draft and is in full conformance with all provisions of Section 10 of RFC2026 [1]. Internet-Drafts are working documents of the Internet Engineering Task Force (IETF), its areas, and its working groups. Note that other groups may also distribute working documents as Internet-Drafts. Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress." The list of current Internet-Drafts can be accessed at http://www.ietf.org/ietf/1id-abstracts.txt The list of Internet-Draft Shadow Directories can be accessed at http://www.ietf.org/shadow.html. ABSTRACT This document contains a C program to convert a raw text (containing format commands similar to nroff) into a text which is in accordance with the demands of the RFC editors. You can download the newest program source, template and docu from following web site: www.pinpi.com/prep DIFFERENCE TO THE PREVIOUS DRAFT: # new command .bk (block) introduced: A better alternative to .ff=number. # correction of .ff=number: (number+1) lines was taken in account (instead of number+0). Wildgrube Experimental [Page 1] Preparation of text in RFC style October 2000 Table of Contents 1. Introduction 2. Description of the program 3. The rules for formatting a page 4. A Template for the raw text 5. Program Source 6. Security Considerations 7. Author's Address A. Appendix: additional functionality Wildgrube Experimental [Page 2] Preparation of text in RFC style October 2000 1. Introduction This document contains a C program (prep.c) to convert a raw text (containing format commands similar to nroff) into a text which is in accordance with the demands of the RFC editors (I hope). To format someone's draft in a correct manner is not an easy task. Especially Windows / Word user has some problems to use the way which is described in RFC 1543 by J. Postel. In the document http://www.ietf.org/ID-nits.html there is a link to a MS Word Template: A nice idea, but on my environment it does not work (even I used Word 97): The running footers disappeared. May be that the problem is my text-only printer driver. There is also a proposal in draft-shirey-ugli-01.txt (35 pages). I think the procedure described here is too complex (changing between UNIX with nroff and vi and Windows with Word). The proposed 'prep' program creates a file in RFC style from a raw text - ready! By starting with the template text described in chapter 4 no further format commands are necessary. But: there are various format commands which makes live easier: With the help of these commands you can define ordered, unordered and definition lists (the latter are useful for references). Word wrapping is done automatically, but for defining tables or pseudo graphics you can switch this feature off (and on again) The program is tested under Windows 98 and Linux. It is to decide if the two alternatives, presented by the macros EXTRALINE (to put 3 blank lines instead of 2 after a new page) and LASTPAGE (for suppressing the form feed after the last page) has to be removed. Of course this document was created with prep.c. Wildgrube Experimental [Page 3] Preparation of text in RFC style October 2000 2. Description of the program Usage of program: prep infile outfile or: prep filestem (In this case filenames are stem.doc for input and stem.txt for output) The infile contains text merged with some line commands (similar as for nroff): Commands starts with a dot (.) on column 1. These are the commands: . text comment .ce=text centered text .pw=number page width (default: 72) .ph=number page hight (default: 58) .in=number indentation (default: 0) .ti=text title line (no indentation) .ff form feed .ff=number conditional form feed: If at least 'number' textlines remains on the actual page, only an empty line will be produced (but see also for the .bk command) .hd=left/center/right running header .ft=left/center/right running footer .it=filename inserts a file .bk=begin | end lines between '.bk=begin' and '.bk=end' defines a 'block': A block will not devided by a page break. If there is not enough remaining place for these lines on the actual page, the complete block begins on the next page. .ww=on | off switching word wrapping on or off. .ol start of ordered list .ul=listchar start of unordered list (default listchar is '-') .dl=indent start of definition list. The definition text is indented by 'indent' columns. .el end of actual list. Lists can be nested up to 4 levels. .li list entry. Text of this entry starts at next line. (only for .ol and .ul) .li=text 'text' has different meanings: # for .ol and .ul: list entry with text, text may be continued on following lines. # for .dl: text is the item to define, it Wildgrube Experimental [Page 4] Preparation of text in RFC style October 2000 should be not longer than the 'ident' given at the .dl command. There are also some additional rules for the text processing: At the begin of the input file text will be put out as is. It is assumed that this text is preformatted (document header block). The first .in command switches to "word floating mode". ".in=3" is usual. In this mode following rules applies: o Lines in succession (not separated by blank lines) defines a paragraph; words in a paragraph are shifted to match the page width optimally. o Besides blank lines a paragraph is terminated by the following line if this line begins with a space. The first word of this line starts always on the beginning of a new line (This first leading space will be removed). o With a series of lines prefixed with a space you can realize a chunk of formatted text. A bigger chunk of preformatted text can be enclosed in a pair of '.ww=on' / '.ww=off' commands. A sequence of lines is called a block if it is enclosed in a pair of '.bk=begin' and '.bk=end' commands. If a block does not fit in the remaining part of a page, a page break will be done in front of this block: Therefore a block will not be divided by a page break - the block itself should fit into a page. 3. The rules for formatting a page Following rules are realized by the program (together with the settings as in the template): o A page consists of exactly 58 lines. o Lines 56 and 57 are always empty o Line 58 contains the running footer, with: - authors last name on the left, - the status in the middle (centered) and - the page number in the form '[Page #]' on the right. o With the exception of the first page: Line 1 contains the running header, with: - 'RFC ####' on the left (not for drafts) - the title in the middle (centered) - the day of publishing on the right. o Line 2 and 3 of all pages are blank. o Line 1 of the first page is blank. o The length of all lines are limited to 72 printable characters, followed by a carriage return (x'0D') and a line feet (x'0A') character. Wildgrube Experimental [Page 5] Preparation of text in RFC style October 2000 o The footer line (including the trailing x'0D0A') is followed by the form feed character (x'0C') 4. A Template for the raw text With following template the correct layout for a draft will be initiated. The template contains some elements enclosed in angle brackets <...> which has to be substituted by user specifications, in detail: : abbreviation of user's first name : user's last name : of the document, like draft-username-project-vv.txt : of publishing : expiration date : of document : user's text
: user's post address. : user's email address. Wildgrube Experimental [Page 6] Preparation of text in RFC style October 2000 . begin of text . --+----1----+----2----+-- (helper for right margin) +----6----+----7-- Network Working Group . Internet Draft Document: Category: Expiration Date: .ce= .in=3 .hd=// .ft=//[Page %d] .ti=STATUS OF THIS MEMO: This document is an Internet-Draft and is in full conformance with all provisions of Section 10 of RFC2026 [1]. . or: . This document is an Internet-Draft and is in full conformance . with all provisions of Section 10 of RFC2026 except that the . right to produce derivative works is not granted. . or: . This document is an Internet-Draft and is NOT offered in . accordance with Section 10 of RFC2026, and the author does not . provide the IETF with any rights other than to publish as an . Internet-Draft Internet-Drafts are working documents of the Internet Engineering Task Force (IETF), its areas, and its working groups. Note that other groups may also distribute working documents as Internet-Drafts. Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress." The list of current Internet-Drafts can be accessed at http://www.ietf.org/ietf/1id-abstracts.txt The list of Internet-Draft Shadow Directories can be accessed at http://www.ietf.org/shadow.html. .ti=Abstract Wildgrube Experimental [Page 7] Preparation of text in RFC style October 2000 .ti=Table of Contents .ol .li=Introduction .li=Security Considerations .li=Author's Address .el .ff .ti=1. Introduction .ti=x. Security Considerations .ti=x. Author's Address email: 5. Program Source This source is to be compiled with 'cc prep.c -o prep' under unix. With the GNU compiler (LINUX) warning messages about the 2-character constants in function handle_command are issued. Let me know if this caused any problems in some environments. /*--- start of source -------------------------------------------*/ /* program: prep.c title: preparation of text to RFC style author: max wildgrube copyright: free for use and further development, no warranties. created: 2000-06-22 changes: 06 2000-11-03 new command .bk : block correction of ff=lines : counting 1 line too few 05 2000-10-03 new design for lists, new list type 'definitions' 04 2000-09-01 new parameter options, option -n : no page breaks option -h : generate html page 03 2000-08-19 1. words are separated by space or end-of-line 2. no space at end of line. 3. One command line param accepted as name stem 02 2000-07-29 1. Correction: If there was a sequence of blank - nonblank at the end of line, the non-blank Wildgrube Experimental [Page 8] Preparation of text in RFC style October 2000 character was stripped. 2. Introducing ordered and unordered lists. */ #define VERSION "prep 06 by max" /* alternatives: */ #define EXTRALINE 0 /* or 1 if extra line after new page */ #define LASTPAGE 0 /* or 1 if no FF after last page */ /* defaults: */ #define INFILE_EXT ".doc" #define OUTFILE_EXT ".txt" #define OUTFILE_HTM ".html" #define HTML_HEADER "h3" #define DEF_PAGEWIDTH 72 #define DEF_PAGEHIGHT 58 #define DEF_INDENT 0 #define DEF_DL_INDENT 10 #define LISTIND_UL 3 #define LISTIND_OL 4 #define DEF_ULCHAR '-' /* constants: */ #define LINELEN 1200 /* max. linesize */ #define HFLENGTH 100 /* max. length of any of the 3 parts */ /* of header and footer */ #define PBUFFLENGTH 1200 /* max. no. of chars in a parag. (17 lines */ #define BLOCK_LINES 100 /* max. no. of block lines */ #define BLOCK_WIDTH 100 /* max. length of block line */ #define MAXLEVEL 4 /* max. levels for lists */ #define OL_FMT "%2d.%d.%d.%d." #define SEPARATORS " " #define BORDERDEL "/" /* delimiter for header and footer parts */ #define VALASS '=' #define FF 12 /* form feed */ #define CR 13 /* carriage return */ #define CRLF "\x0D\x0A" /* carriage return + line feed */ #define EL "" /* empty line */ #define SP ' ' /* space */ #include #include #include static struct GLOBALS { FILE *infile, *outfile; short pw, ph, in; /* page width, page height, indent */ char ce [HFLENGTH]; /* center line */ Wildgrube Experimental [Page 9] Preparation of text in RFC style October 2000 char hd [HFLENGTH]; /* header */ char ft [HFLENGTH]; /* footer */ short header_set, footer_set, block, format, listflag, korr; /* boolean */ short in_line_counter, pg_line_counter, page_counter, bk_line_counter; short level, ol_level; char parabuff [PBUFFLENGTH]; char blockbuff [BLOCK_LINES] [BLOCK_WIDTH]; char option; short opt_no_ff, opt_repl; } g; enum {TYPE_NONE, TYPE_OL, TYPE_UL, TYPE_DL}; static struct LIST { short type; short indent; char ul_char; /* actual char for unordered list */ short ol_number; /* ol_number [0] will be ignored */ } list [MAXLEVEL]; /* prototypes */ int open_files (int, char **); void handle_command (char *); void flush_para_buffer (void); void fill_para_buffer (char *); void putout (char *); /* put output string to file */ void do_form_feed (int); char *make_border (char *); void strip (char *); /* strips blanks and CR at end of line */ char *replace (char *p_str, char p_srch, char *p_repl); /*---------------------------------------------------------------*/ int main (int argc, char **argv) { char inpline [LINELEN]; printf ("%s at %s\n", VERSION, __DATE__); if (open_files (argc, argv) > 0) return 1; /* defaults: */ g.pw = DEF_PAGEWIDTH; g.ph = DEF_PAGEHIGHT; g.in = DEF_INDENT; g.page_counter = 1; g.level = 0; g.ol_level = 0; Wildgrube Experimental [Page 10] Preparation of text in RFC style October 2000 #if EXTRALINE putout (EL); #endif /* start of output */ if (g.option == 'h') { putout ("
");
    g.opt_repl = 1;
  }

  /* loop over input lines: */
  while (fgets (inpline, LINELEN-2, g.infile))
  {
    ++g.in_line_counter;
    strip (inpline);

    switch (inpline [0])
    {
     case '.':
      handle_command (inpline);
      break;
     case SP:
      flush_para_buffer ();
      fill_para_buffer (inpline + 1);
      break;
     case 0  :
      flush_para_buffer ();
      putout (EL);
      break;
     default:
      fill_para_buffer (inpline);
    } /*end-switch*/

  } /*end-while*/

  flush_para_buffer ();
  do_form_feed (LASTPAGE);  /* 1 = end of file (no FF) */

  /* end of output */
  if (g.option == 'h')
  {
    g.opt_repl = 0;
    putout ("
"); } fclose (g.infile); fclose (g.outfile); if (g.level > 0) printf ("some list not properly closed, level=%d.\n", g.level); Wildgrube Experimental [Page 11] Preparation of text in RFC style October 2000 else printf ("ok, inlines=%d, pages=%d.\n", g.in_line_counter, g.page_counter); return 0; } /*end- main */ /*---------------------------------------------------------------*/ int open_files (int argc, char **argv) { char infile [100], outfile [100]; int par1 = 1; if (argc > 1 && argv [1][0] == '-') { g.option = argv [1][1]; printf ("option %c specified\n", g.option); par1 = 2; argc--; switch (g.option) {case 'n': case 'h': g.opt_no_ff = 1; } } switch (argc) { case 2: strcpy (infile, argv [par1]); strcat (infile, INFILE_EXT); strcpy (outfile, argv [par1]); if (g.option == 'h') strcat (outfile, OUTFILE_HTM); else strcat (outfile, OUTFILE_EXT); break; case 3: strcpy (infile, argv [par1]); strcpy (outfile, argv [par1+1]); break; default: printf ( "usage:\n\n" " prep [-option] infile outfile\n" "or:\n" " prep [-option] stem" " (with infile = stem.doc, outfile = stem.txt)\n\n" "options are:\n" " -n no page breaks (including no headers and footers)\n" " -h generates a HTML page (includes -n)\n" , VERSION, __DATE__, argv [0], argv [0]); Wildgrube Experimental [Page 12] Preparation of text in RFC style October 2000 return 1; } if (!(g.infile = fopen (infile, "rt"))) { printf ("could not open input file %s\n", infile); return 1; } printf ("input file %s opened\n", infile); if (!(g.outfile = fopen (outfile, "wb"))) { printf ("could not open output file %s\n", outfile); return 1; } printf ("output file %s opened\n", outfile); return 0; } /*end- open_files */ /*---------------------------------------------------------------*/ void handle_command (char *p_inline) { short cmd; int datalen, oldind; int wnum; char wrkline [LINELEN], wrkline1 [LINELEN]; FILE *ifile; if (p_inline [1] <= SP) return; /* comment */ /* indifference to big or little endian: */ cmd = (((short)*(p_inline+1) & 0xFF) << 8) | ((short)*(p_inline+2) & 0xFF); switch (cmd) { case 'pw': /* page width **********************************/ sscanf (p_inline+4, "%d", &g.pw); break; case 'ph': /* page height ********************************/ sscanf (p_inline+4, "%d", &g.ph); break; case 'in': /* indentation ********************************/ sscanf (p_inline+4, "%d", &g.in); flush_para_buffer (); g.format = 1; break; Wildgrube Experimental [Page 13] Preparation of text in RFC style October 2000 case 'ti': /* title line *********************************/ if (g.level > 0) { printf ( "list structure not closed inside a chapter! (line %d)\n", g.in_line_counter); exit (1); } flush_para_buffer (); if ((! g.opt_no_ff) && g.pg_line_counter > g.ph - 3*g.footer_set - 4) do_form_feed (0); /* 0 = not the end of file */ oldind = g.in; g.in = 0; if (g.option == 'h') fputs ("<" HTML_HEADER ">", g.outfile); putout (p_inline + 4); if (g.option == 'h') fputs ("", g.outfile); g.in = oldind; break; case 'ce': /* center line ********************************/ flush_para_buffer (); memset (wrkline, SP, g.pw); datalen = strlen (p_inline) - 4; if (datalen <= 0) return; strcpy (wrkline + (g.pw - datalen)/2, p_inline + 4); putout (wrkline); break; case 'ff': /* form feed (new page) *************************/ if (g.opt_no_ff) { flush_para_buffer (); putout (EL); break; } wnum = 999; sscanf (p_inline+4, "%d", &wnum); flush_para_buffer (); if (g.pg_line_counter + 1 + wnum > g.ph - 3*g.footer_set) /*#06*/ do_form_feed (0); /* 0 = not the end of file */ else putout (EL); break; case 'hd': /* header **************************************/ Wildgrube Experimental [Page 14] Preparation of text in RFC style October 2000 strcpy (g.hd, p_inline+4); g.header_set = 1; break; case 'ft': /* footer **************************************/ strcpy (g.ft, p_inline+4); g.footer_set = 1; break; case 'it': /* insert file *********************************/ if (!(ifile = fopen (p_inline+4, "rt"))) { printf ("could not open insert file '%s' at line %d\n", p_inline+4, g.in_line_counter); exit (1); } while (fgets (wrkline, LINELEN-2, ifile)) { strip (wrkline); putout (wrkline); } fclose (ifile); break; case 'bk': /* block modus *****************************/ flush_para_buffer (); if (0 == strcmp (p_inline+4, "begin")) { g.block = 1; g.bk_line_counter = 0; break; } if (0 == strcmp (p_inline+4, "end")) { short line; g.block = 0; if (g.pg_line_counter + g.bk_line_counter > g.ph - 3*g.footer_set) do_form_feed (0); /* 0 = not the end of file */ for (line = 0; line < g.bk_line_counter; line++) putout (g.blockbuff [line]); g.bk_line_counter = 0; break; } printf ("parameter error on cmd '.bk=begin|end' at line %d: %s\n", g.in_line_counter, p_inline); break; Wildgrube Experimental [Page 15] Preparation of text in RFC style October 2000 case 'ww': /* word-wrap modus *****************************/ if (0 == strcmp (p_inline+4, "on")) { g.format = 1; break; } if (0 == strcmp (p_inline+4, "off")) { g.format = 0; break; } printf ("parameter error on cmd '.ww=on|off' at line %d: %s\n", g.in_line_counter, p_inline); break; case 'ul': /* unordered list *******************************/ flush_para_buffer (); ++ g.level; list [g.level].type = TYPE_UL; list [g.level].indent = LISTIND_UL; g.in += LISTIND_UL; list [g.level].ul_char = p_inline [3] == VALASS ? p_inline [4] : DEF_ULCHAR; break; case 'ol': /* ordered list *********************************/ flush_para_buffer (); ++ g.level; ++ g.ol_level; list [g.level].type = TYPE_OL; list [g.level].indent = LISTIND_OL; g.in += LISTIND_OL; break; case 'dl': /* definition list ******************************/ flush_para_buffer (); ++ g.level; list [g.level].type = TYPE_DL; wnum = DEF_DL_INDENT; sscanf (p_inline+4, "%d", &wnum); list [g.level].indent = wnum; g.in += wnum; break; case 'el': /* end of list **********************************/ flush_para_buffer (); list [g.level].ol_number = 0; if (list [g.level].type == TYPE_OL) -- g.ol_level; g.in -= list [g.level].indent; -- g.level; Wildgrube Experimental [Page 16] Preparation of text in RFC style October 2000 break; case 'li': /* list item ************************************/ flush_para_buffer (); g.listflag = 1; g.in -= list [g.level].indent; switch (list [g.level].type) { short ix; case TYPE_OL : if (g.ol_level > 1) { g.in -= 2 * g.ol_level - 2; g.korr = 1; } list [g.level].ol_number += 1; memset (wrkline1, 0, LINELEN); sprintf (wrkline, strncpy (wrkline1, OL_FMT, 3 * g.ol_level + 1) , list [1].ol_number , list [2].ol_number , list [3].ol_number , list [4].ol_number ); fill_para_buffer (wrkline); if (p_inline [3] == VALASS) fill_para_buffer (p_inline+4); break; case TYPE_UL : wrkline [0] = list [g.level].ul_char; ix = list [g.level].indent; memset (wrkline+1, SP, ix - 1); wrkline [ix] = 0; fill_para_buffer (wrkline); if (p_inline [3] == VALASS) fill_para_buffer (p_inline+4); break; case TYPE_DL : memset (wrkline, SP, LINELEN); ix = list [g.level].indent; if (p_inline [3] == VALASS) { wnum = strlen (p_inline+4); memcpy (wrkline, p_inline+4, wnum); wnum = ix - wnum > 0 ? ix : wnum + 1; wrkline [wnum] = 0; } else { wrkline [ix] = 0; Wildgrube Experimental [Page 17] Preparation of text in RFC style October 2000 } fill_para_buffer (wrkline); break; } break; default: printf ("unkonwn command at line %d: %s\n", g.in_line_counter, p_inline); }/*end-switch cmd */ }/*end- handle_command */ /*---------------------------------------------------------------*/ void fill_para_buffer (char *p_inline) { static char *cursor; static int actual_size; int datalen; if (p_inline == NULL) /* reset buffer after flush */ { g.parabuff [0] = 0; cursor = NULL; actual_size = 0; return; } if (! g.format) { putout (p_inline); return; } datalen = strlen (p_inline); if (actual_size + datalen + 1 > PBUFFLENGTH) { printf ("Paragraph buffer overflow!\n" "Please insert some breaks.\n"); exit (1); } if (cursor == NULL) cursor = g.parabuff; else if (*(cursor-1) != SP && *(cursor-1) != '-') *(cursor++) = SP; strcpy (cursor, p_inline); Wildgrube Experimental [Page 18] Preparation of text in RFC style October 2000 cursor += datalen; actual_size += datalen; }/*end- fill_para_buffer */ /*---------------------------------------------------------------*/ void flush_para_buffer (void) { char outline [LINELEN] = EL; int wordlen; char *cursor = g.parabuff; if (*cursor == 0) return; if (g.in > 0) memset (outline, SP, g.in); outline [g.in] = 0; while (*cursor) { wordlen = strcspn (cursor, SEPARATORS); if (*(cursor + wordlen)) wordlen += 1; if ((int)strlen (outline) + wordlen > g.pw) { int len = strlen (outline); if (outline [len-1] == SP) outline [len-1] = 0; putout (outline); if (g.in > 0) memset (outline, SP, g.in); outline [g.in] = 0; if (*cursor == SP) cursor++; } strncat (outline, cursor, wordlen); cursor += wordlen; } putout (outline); fill_para_buffer (NULL); /* reset buffer */ }/*end- flush_para_buffer */ /*---------------------------------------------------------------*/ void do_form_feed (int p_last) { if (g.opt_no_ff) return; while (g.pg_line_counter++ < (int)g.ph - 1) fputs (CRLF, g.outfile); if (g.footer_set) { Wildgrube Experimental [Page 19] Preparation of text in RFC style October 2000 fputs (make_border (g.ft), g.outfile); fputs (CRLF, g.outfile); } if (! p_last) { fputc (FF, g.outfile); #if EXTRALINE fputs (CRLF, g.outfile); #endif g.pg_line_counter = EXTRALINE; } g.page_counter += 1; }/*end- do_form_feed */ /*---------------------------------------------------------------*/ void putout (char *p_str) /* put output string to file */ { if (g.block) { if (g.bk_line_counter >= BLOCK_LINES) { printf ( "block buffer overflow: no .bk=end after %d lines. line: %d\n", BLOCK_LINES, g.in_line_counter); exit (1); } strcpy (g.blockbuff [g.bk_line_counter], p_str); g.bk_line_counter ++; } else /* no block */ { if (g.pg_line_counter == (int)g.ph - 3 * g.footer_set) { // if (p_str [0] == 0) return; /* no empty lines at end of page */ do_form_feed (0); } if (g.pg_line_counter == EXTRALINE && g.header_set) { fputs (make_border (g.hd), g.outfile); fputs (CRLF, g.outfile); fputs (CRLF, g.outfile); fputs (CRLF, g.outfile); g.pg_line_counter += 3; } if (g.opt_repl) { char outline [LINELEN]; Wildgrube Experimental [Page 20] Preparation of text in RFC style October 2000 strcpy (outline, replace (p_str, '<', "<")); fputs (replace (outline, '>', ">"), g.outfile); } else { fputs (p_str, g.outfile); } fputs (CRLF, g.outfile); g.pg_line_counter += 1; } /*end-if block */ if (g.listflag) { g.listflag = 0; g.in += list [g.level].indent; if (g.korr) { g.korr = 0; g.in += 2 * g.ol_level - 2; } } /*end-if list flag */ } /*end- putout */ /*---------------------------------------------------------------*/ char *make_border (char *p_str) { static char line [LINELEN]; char *token, work [LINELEN]; int len; if ((int)strlen (p_str) > g.pw) { printf ("line: %d: header / footer too long\n", g.in_line_counter); exit (1); } memset (line, SP, g.pw); sprintf (work, p_str, g.page_counter); token = strtok (work, BORDERDEL); if (work [0] == BORDERDEL [0]) goto center; if (token == NULL) goto error; len =strlen (token); memcpy (line, token, len); token = strtok (NULL, BORDERDEL); Wildgrube Experimental [Page 21] Preparation of text in RFC style October 2000 center: if (token == NULL) goto error; len =strlen (token); memcpy (line + (g.pw - len)/2, token, len); token = strtok (NULL, BORDERDEL); if (token == NULL) goto error; len =strlen (token); memcpy (line + g.pw - len, token, len); line [g.pw] = 0; return line; error: printf ("line %d: '%s'\nwrong param for header/footer: " "format 'left/center/right'\n", g.in_line_counter, p_str); exit (1); }/*end- make_border */ /*---------------------------------------------------------------*/ void strip (char *p_str) { int ixLastChar; if (p_str == NULL) return; ixLastChar = strlen (p_str) - 1; if (p_str [ixLastChar] == '\n') p_str [ixLastChar--] = 0; if (ixLastChar >= 0 && p_str [ixLastChar] == CR) p_str [ixLastChar--] = 0; while (ixLastChar >= 0 && p_str [ixLastChar] == SP) p_str [ixLastChar--] = 0; }/*end- strip */ /*---------------------------------------------------------------*/ char *replace (char *p_str, char p_srch, char *p_repl) { static char work1 [200]; char work2 [200] = ""; char *found; if (p_str == NULL || p_repl == NULL) return p_str; Wildgrube Experimental [Page 22] Preparation of text in RFC style October 2000 strcpy (work1, p_str); while (found = strchr (work1, p_srch)) { *found = 0; strcpy (work2, found + 1); strcat (work1, p_repl); strcat (work1, work2); } return work1; }/*end- replace */ /*--- end of source ---------------------------------------------*/ 6. Security Considerations There are no Security Considerations. 7. Author's Address Max Wildgrube Schlossstr. 120 60486 Frankfurt Germany email: max@wildgrube.com You can download the newest program source, template and docu from this web site: www.pinpi.com/prep Wildgrube Experimental [Page 23] Preparation of text in RFC style October 2000 A. Appendix: additional functionality With an additional option on the command line the program offers some special functions. The option must specify as a first parameter. Options are: -n : no form feeds are generated and therefore also no page headers and trailers. -h : a simple HTML page is generated (includes option -n). If only a stem as 2nd parameter is given, the output file name has ".html" as extension. The '<' and '>' are replaced to '&xx;' (with xx= lt, gt). Title lines (created by .ti) are marked with

tags. The files which are generated with these options are _not_ in accordance with the demands of the RFC editors. Wildgrube Experimental [Page 24]