Network Working Group M. Wildgrube Internet Draft Document: draft-wildgrube-preprfc-00.txt June 2000 Category: Experimental Expiration Date: December 2000 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. 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 Wildgrube Experimental [Page 1] Preparation of text in RFC style June 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 procedere 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! 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. It may be useful to introduce some more functionality, for example to define ordered and numbered lists. Wildgrube Experimental [Page 2] Preparation of text in RFC style June 2000 2. Description of the program Usage of program: prep infile outfile 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. .hd=left/center/right running header .ft=left/center/right running footer .it=filename inserts a file 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 preformated (document header block). The first .in command switches to "word floating modus". ".in=3" is usual. In this modus 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. Wildgrube Experimental [Page 3] Preparation of text in RFC style June 2000 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 right (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. 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. . ------------ begin of template text . --+----1----+----2----+-- (helper for right margin) +----6----+----7-- Network Working Group . Internet Draft Document: Wildgrube Experimental [Page 4] Preparation of text in RFC style June 2000 Category: Informational Expiration Date: .ce= .in=3 .hd=// .ft=/Informational/[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 .ti=Table of Contents 1. Introduction x. Security Considerations x. Author's Address .ff .ti=1. Introduction Wildgrube Experimental [Page 5] Preparation of text in RFC style June 2000 .ti=x. Security Considerations .ti=x. Author's Address email: . ----------------- end of template 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. */ #define VERSION "prep 01 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 DEF_PAGEWIDTH 72 #define DEF_PAGEHIGHT 58 #define DEF_INDENT /* 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 paragraph (17 lines) */ #define SEPARATORS " .,-:;!?" #define BORDERDEL "/" /* delimiter for header and footer parts */ #define FF 12 /* form feed */ Wildgrube Experimental [Page 6] Preparation of text in RFC style June 2000 #define CR 13 /* carriage return */ #define LF 10 /* line feed */ #define EL "" /* empty line */ #include #include #include static struct GLOBALS { FILE *infile, *outfile; unsigned int pw, ph, in; /* page width, page height, indent */ char ce [HFLENGTH]; /* center line */ char hd [HFLENGTH]; /* header */ char ft [HFLENGTH]; /* footer */ int header_set, footer_set, format; /* boolean */ int in_line_counter, pg_line_counter, page_counter; char parabuff [PBUFFLENGTH]; } g; /* prototypes */ 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 *); /*---------------------------------------------------------------*/ int main (int argc, char **argv) { char inpline [LINELEN]; if (argc != 3) printf ("%s at %s\nusage: %s infile outfile\n", VERSION, __DATE__, argv [0]); return 1; if (!(g.infile = fopen (argv [1], "rt"))) printf ("could not open input file %s\n", argv [1]); return 1; if (!(g.outfile = fopen (argv [2], "wb"))) printf ("could not open output file %s\n", argv [2]); return 1; Wildgrube Experimental [Page 7] Preparation of text in RFC style June 2000 /* defaults: */ g.pw = DEF_PAGEWIDTH; g.ph = DEF_PAGEHIGHT; g.in = DEF_INDENT; g.page_counter = 1; #if EXTRALINE putout (EL); #endif /* 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 ' ': 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) */ fclose (g.infile); fclose (g.outfile); } /*end- main */ /*---------------------------------------------------------------*/ void handle_command (char *p_inline) { short cmd; int datalen, oldind; unsigned int wnum; char wrkline [LINELEN]; FILE *ifile; Wildgrube Experimental [Page 8] Preparation of text in RFC style June 2000 if (p_inline [1] <= ' ') 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; case 'ti': /* title line */ flush_para_buffer (); oldind = g.in; g.in = 0; putout (p_inline + 4); g.in = oldind; break; case 'ce': /* center line */ flush_para_buffer (); memset (wrkline, ' ', 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) */ wnum = 999; sscanf (p_inline+4, "%d", &wnum); flush_para_buffer (); if (g.pg_line_counter + wnum > g.ph - 3*g.footer_set) do_form_feed (0); /* 0 = not the end of file */ else putout (EL); break; case 'hd': /* header */ strcpy (g.hd, p_inline+4); Wildgrube Experimental [Page 9] Preparation of text in RFC style June 2000 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 '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 for cmd '.ww=on|off' at line %d: %s\n", g.in_line_counter, p_inline); 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; Wildgrube Experimental [Page 10] Preparation of text in RFC style June 2000 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) != ' ') *(cursor++) = ' '; strcpy (cursor, p_inline); cursor += datalen; actual_size += datalen; }/*end- fill_para_buffer */ /*---------------------------------------------------------------*/ void flush_para_buffer (void) { char outline [LINELEN] = EL; unsigned int wordlen; char *cursor = g.parabuff; if (*cursor == 0) return; if (g.in > 0) memset (outline, ' ', g.in); outline [g.in] = 0; while (*cursor) wordlen = strcspn (cursor, SEPARATORS); if (*(cursor + wordlen)) wordlen += 1; Wildgrube Experimental [Page 11] Preparation of text in RFC style June 2000 if (strlen (outline) + wordlen > g.pw) putout (outline); if (g.in > 0) memset (outline, ' ', g.in); outline [g.in] = 0; 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) { while (g.pg_line_counter++ < (int)g.ph - 1) fputc (CR, g.outfile); fputc (LF, g.outfile); if (g.footer_set) fputs (make_border (g.ft), g.outfile); fputc (CR, g.outfile); fputc (LF, g.outfile); if (! p_last) fputc (FF, g.outfile); #if EXTRALINE fputc (CR, g.outfile); fputc (LF, g.outfile); g.pg_line_counter = 1; #else g.pg_line_counter = 0; #endif g.page_counter += 1; }/*end- do_form_feed */ /*---------------------------------------------------------------*/ void putout (char *p_str) /* put output string to file */ { 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 */ if (g.footer_set) fputc (CR, g.outfile); fputc (LF, g.outfile); fputc (CR, g.outfile); fputc (LF, g.outfile); Wildgrube Experimental [Page 12] Preparation of text in RFC style June 2000 fputs (make_border(g.ft), g.outfile); fputc (CR, g.outfile); fputc (LF, g.outfile); fputc (FF, g.outfile); #if EXTRALINE fputc (CR, g.outfile); fputc (LF, g.outfile); g.pg_line_counter = 1; #else g.pg_line_counter = 0; #endif g.page_counter += 1; #if EXTRALINE if (g.pg_line_counter == 1 && g.header_set) #else if (g.pg_line_counter == 0 && g.header_set) #endif fputs (make_border (g.hd), g.outfile); fputc (CR, g.outfile); fputc (LF, g.outfile); fputc (CR, g.outfile); fputc (LF, g.outfile); fputc (CR, g.outfile); fputc (LF, g.outfile); g.pg_line_counter += 3; fputs (p_str, g.outfile); fputc (CR, g.outfile); fputc (LF, g.outfile); g.pg_line_counter += 1; } /*end- putout */ /*---------------------------------------------------------------*/ char *make_border (char *p_str) { static char line [LINELEN]; char *token, work [LINELEN]; unsigned int len; if (strlen (p_str) > g.pw) printf ("line: %d: header / footer too long\n", g.in_line_counter); exit (1); memset (line, ' ', g.pw); sprintf (work, p_str, g.page_counter); Wildgrube Experimental [Page 13] Preparation of text in RFC style June 2000 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); 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] == ' ') p_str [ixLastChar] = 0; }/*end- strip */ /*--- end of source ---------------------------------------------*/ Wildgrube Experimental [Page 14] Preparation of text in RFC style June 2000 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 15]