Internet DRAFT - draft-bernardini-embedded-code

draft-bernardini-embedded-code






Internet Engineering Task Force                         R. Riccardo, Ed.
Internet-Draft                                       University of Udine
Intended status: Informational                             July 12, 2013
Expires: January 13, 2014


                   A Format for Embedding Code in RFC
                   draft-bernardini-embedded-code-00

Abstract

   Some RFC need to include some code or some kind of data like test
   vectors.  Extracting the code or the data from the RFC "by hand" is
   possible, but tiresome and prone to errors, especially if the portion
   to be extracted is long or comprises many files.  This document
   describes a format that can be used to embed code or data in an RFC,
   so that it can be extract by a software, while preserving the
   readibility of the embedded text.

Status of this Memo

   This Internet-Draft is submitted in full conformance with the
   provisions of BCP 78 and BCP 79.

   Internet-Drafts are working documents of the Internet Engineering
   Task Force (IETF).  Note that other groups may also distribute
   working documents as Internet-Drafts.  The list of current Internet-
   Drafts is at http://datatracker.ietf.org/drafts/current/.

   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."

   This Internet-Draft will expire on January 13, 2014.

Copyright Notice

   Copyright (c) 2013 IETF Trust and the persons identified as the
   document authors.  All rights reserved.

   This document is subject to BCP 78 and the IETF Trust's Legal
   Provisions Relating to IETF Documents
   (http://trustee.ietf.org/license-info) in effect on the date of
   publication of this document.  Please review these documents
   carefully, as they describe your rights and restrictions with respect
   to this document.  Code Components extracted from this document must
   include Simplified BSD License text as described in Section 4.e of



Riccardo                Expires January 13, 2014                [Page 1]

Internet-Draft               Embedding Code                    July 2013


   the Trust Legal Provisions and are provided without warranty as
   described in the Simplified BSD License.


Table of Contents

   1.  Introduction . . . . . . . . . . . . . . . . . . . . . . . . .  3
     1.1.  Requirements Language  . . . . . . . . . . . . . . . . . .  3
   2.  Informal description . . . . . . . . . . . . . . . . . . . . .  3
   3.  Requirements . . . . . . . . . . . . . . . . . . . . . . . . .  4
   4.  Format description . . . . . . . . . . . . . . . . . . . . . .  6
   5.  Extractting and embedding  . . . . . . . . . . . . . . . . . . 10
     5.1.  Extractor behaviour  . . . . . . . . . . . . . . . . . . . 10
     5.2.  Embedder behaviour . . . . . . . . . . . . . . . . . . . . 11
   6.  Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 12
   7.  IANA Considerations  . . . . . . . . . . . . . . . . . . . . . 12
   8.  Security Considerations  . . . . . . . . . . . . . . . . . . . 12
   9.  References . . . . . . . . . . . . . . . . . . . . . . . . . . 13
     9.1.  Normative References . . . . . . . . . . . . . . . . . . . 13
     9.2.  Informative References . . . . . . . . . . . . . . . . . . 13
   Appendix A.  Software  . . . . . . . . . . . . . . . . . . . . . . 13
     A.1.  Bare-bone extractor  . . . . . . . . . . . . . . . . . . . 14
     A.2.  Full implentation  . . . . . . . . . . . . . . . . . . . . 16
       A.2.1.  Usage  . . . . . . . . . . . . . . . . . . . . . . . . 16
         A.2.1.1.  Embedder . . . . . . . . . . . . . . . . . . . . . 16
         A.2.1.2.  Extractor  . . . . . . . . . . . . . . . . . . . . 16
       A.2.2.  Sources  . . . . . . . . . . . . . . . . . . . . . . . 16
   Author's Address . . . . . . . . . . . . . . . . . . . . . . . . . 51























Riccardo                Expires January 13, 2014                [Page 2]

Internet-Draft               Embedding Code                    July 2013


1.  Introduction

   Some RFC has the necessity of including code and/or data such as test
   vectors.  Depending on the specific RFC, the embedded code can be
   quite long and be spread among a fair number of files.  While it is
   possible to extract the embedded text "by hand", the procedure can be
   tiresome and prone to errors.

   Although some RFC adopted some ad hoc solution for this problem, this
   document tries to give a general solution by proposing a format that
   allows to embed in an RFC any line-oriented text file in a way that
   allows for automatic extraction, while preserving the readibility of
   the embedded text.

1.1.  Requirements Language

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
   document are to be interpreted as described in RFC 2119 [RFC2119].


2.  Informal description

   It is worth to begin with an informal example of the proposed format


   !--((BGN))--Ggroup-name F"example.txt"
   !. This is an example of embedded file
   !,1This is a very, very, very, very, very, very, very, very, very,
   !. very, very, very long line
   !.
   !. The line above is empty
   !.3This line ends with 3 spaces

   This line is not part of the content (and it is ignored)

   !, %09This line begins with a tab and contains %05%07 non-printable
   !.  characters
   !--((END))--


   It can be seen that

   o  the embedded code is delimited by the two lines beginning with
      "!--((BGN))--" (header) and "!--((END))--" (trailer).

   o  The header includes the name of the file (after the letter "F")
      and an optional group name marked by the letter "G".



Riccardo                Expires January 13, 2014                [Page 3]

Internet-Draft               Embedding Code                    July 2013


   o  Every line of the embedded content begins with a _line header_
      "!," or "!.".  If the line begins "!,", the embedded line is part
      of a line longer than 64 characters and that it has been broken
      over a "block" of more than one embedded lines.  The last line of
      the block begins with "!.".

   o  "!+" or "!=" can be followed by a single number that shows the
      number of spaces that must be added at the end of the embedded
      line (see, for example, the third line from bottom).  If the
      number is absent, no spaces are present at the end of the line.

   o  Printable ASCII characters (32..127) are inserted "as they are".
      Characters outside this interval are represented by an escape
      sequence "%xx".


3.  Requirements

   This section briefly describes and justifies the requirements that
   were used to develop the proposed format

   REQ-1:   The text to be embedded is most frequently represented by
      source code.  The text is organized as a sequence of lines and
      most of the lines only contains printable ASCII characters (i.e.,
      octets in the range 32..127).  No constraint on the line lenght
      must be imposed.

   REQ-2:   Lines are separated according to the local convention (i.e.,
      with CR-LF on Windows and with LF on Unix).  When a file is
      extracted, the line terminator used is determined by the local
      convention of the machine used for the extraction, independently
      on the convention used on the machine that produced the embedded
      text.

   Rationale:   According to the model described by REQ-1 and REQ-2, the
      embedded file is not just a stream of octets, but a sequence of
      lines, each line being a sequence of octets.  We feel that this
      "line-wise" approach is more natural when working with files that
      represent source code.

   REQ-3:   A mechanism to include generic octets must be provide, but
      it is not necessary that the mechanism is efficient.

   Rationale:   According to REQ-1, most of the text will be represented
      by printable characters; however, we cannot be sure that a non-
      printable character will never appaer in a source code (e.g., it
      could be an accented letter in a programmer's name in a comment),
      so an escaping mechanism must be provided.  However, since we do



Riccardo                Expires January 13, 2014                [Page 4]

Internet-Draft               Embedding Code                    July 2013


      not expect many non-printable characters, even an inefficient
      escaping mechanism (such as the "%xx" used in URL that triplicates
      the number of characters) can be used.

   REQ-4:   Every embedded file must stores also its filename,
      optionally complete with a relative path.  Absolute paths must not
      be allowed.

   Rationale:   Even sliglthly complex software usually includes many
      files, typically organized in a tree.  In order to re-create the
      original file organization, it is necessary to preserve the name
      of each single file and to include relative paths in the name.  In
      this context absolute paths do not make much sense; moreover,
      since they could depend on the specific operative system, in our
      opinion it is better to avoid them.
      The alternative to the requirement of storing the path was to
      allow only "simple names" and store an organized collection of
      files as an archive.  However, most of the current archive formats
      (e.g., tar, zip, rar) are binary-based and not suitable for
      embedding.  There are few formats that are ASCII-based, but they
      are not common and their use would introduce a dependence on the
      archival software.  We considered that it was simpler to allow for
      full path names in the embedded format.

   REQ-5:   The pathname will be stored in an OS-independent manner.  It
      will be the duty of the extractor to convert the stored pathname
      to local convention.  A hierarchical file system structure can be
      assumed.

   Rationale:   The necessity of getting rid of the differences in
      filename conventions between OSes is clear.  The hypothesis that
      the destination filesystem is hierarchically organized, it seems
      to be not too rescricting (do non-hierarchical filesystem exists
      for systems that can be used to extract files from an RFC?) and it
      simplifies path handling.  Moreover, if the target system was not
      hierarchically organized, how would we organize the fileset, say,
      "foo/src/bar.c", "foo/include/bar.h", "foo/man1/bar.1"?

   REQ-6:   The embedding format must not depend on the amount of spaces
      on _both_ sides of the lines

   Rationale:   This requirement was, actually, an afterthought.  At the
      beginning I supposed that every embedded line would have its '!'
      in column 1 and that every character in the line was significant,
      ending spaces included.  At the first test I discovered that
      <artwork> adds, nevertheless, three spaces at the beginning of
      every line, so that the constraint of beginning on column 1 had to
      be removed.  Since a constraint that required _exactly_ three



Riccardo                Expires January 13, 2014                [Page 5]

Internet-Draft               Embedding Code                    July 2013


      spaces looked to frail to me, I decided that any amount of space
      could precede the initial '!'.
      The requirement that also spaces at the end of the line must be
      ignored was introduced when I discovered that, even when the
      embedded code was put inside a CDATA block, the spaces at the end
      of each line were removed.  I did not investigate if this was due
      to XML specs or a characteristic of xml2rfc or something in my
      editor (jedit); I just decided that it would have been more robust
      to ignore the spaces at the end and put a "space counter" just
      after the line header.

   REQ-7:  The embedding format must allow for non-embedded lines in the
      embedding section.

   Rationale:   For example, if an embedding section spans more than one
      page, page headers and footers will be surrounded by embedded
      lines.

   REQ-8:  A file extracted from an RFC must be a line-by-line verbatim
      copy of the original file, in the sense that the two files will
      have the same number of lines and that the sequence of octets in
      the n-th line in the original file will be equal to the sequence
      of octets in the n-th line in the extracted file (for every n, of
      course).

   Rationale:   The necessity of having a lossless recovery is pretty
      obvious.  The fact that "lossless recovery" is tested line by
      line, rather then character by character, aligns itself with the
      idea of considering the source code line-organized and makes
      lossless recovery possible even cross-architecture.

   REQ-9:  The length of any embedded line (including header and spaces
      at the beginning) cannot be larger than 72.

   Rationale:   This constrain is inherithed from the RFC format.


4.  Format description

   In this section we describe formally the proposed format.

   o  Every file to be embedded is converted into an _embedded text_ to
      be included in the target RFC (e.g., via a CDATA block).  The
      embedded text is split into _embedded lines_

   o  Spaces at the beginning and at the end of an embedded line are not
      significant, so that the extractor can trim each line at both
      sides, if this makes its duty simpler.



Riccardo                Expires January 13, 2014                [Page 6]

Internet-Draft               Embedding Code                    July 2013


   o  The embedded text begins with the _header line_ "!--((BGN))--" and
      ends with the _trailer line_ "!--((END))--"

   o  Header and trailer formats are described by the following grammar

   header-line = header-marker [group] filename
   header-marker = %x21.45.45.40.40.66.71.78.41.41.45.45
   trailer-line  = %x21.45.45.40.40.69.78.68.41.41.45.45
   group         = %x48 1*VCHAR SP         ; G
   filename      = %x4F delim1 path delim2 ; F
   delim1        = NO-SLASH
   delim2        = NO-SLASH
   path          = [directory] simple-name
   directory     = 1*(name "/")
   simple-name   = name
   name          = 1*(SP / NO-SLASH)
   VCHAR         = %x21-7E
   NO-SLASH      = %x21-46 / %x48-7E       ; Visible char without '/'

      where delim1 MUST be equal to delim2 and MUST not be contained in
      path (it is not possible to specify this constraint with ABNF).
      delim1 and delim2 can be any printable character, but "/" since it
      is used as path separator.

      Rationale:  In other words, the first char after the "F" acts as a
         delimiter for the filename.  This "adaptive quotation"
         mechanism allows to quote every filename without any escaping
         mechanism.  (OK, _almost_ all filenames: a filename that uses
         every printable character is not quotable)

   o  The filename after the "F" in the header line is the path to be
      used to save the extracted files.  The format used is Unix-like
      with "/" as separator; it will be the duty of the extractor to
      convert this convention to the local convention (e.g., "foo/src/
      bar.c" will be transformed to "foo\src\bar.c" for Windows or
      "[.foo.src]bar.c" for VMS).  The last component of the filename is
      considered the basename of the file, while the remaining part is
      the path, split into its components.  This distinction between
      path and basename, although obvious, it is worth to be pointed out
      because some sistems (e.g., VMS) use a different syntax for the
      two components.

   o  The optional group name after the "G" in the header line has no
      particular meaning for the embedding format, but it can be useful
      to help users to extract only the file of interest.  Suppose, for
      example, that an RFC provides some code in C and some code in
      Python that implement the RFC.  Typically, one user will be
      interested only in one version.  In this case one can collect the



Riccardo                Expires January 13, 2014                [Page 7]

Internet-Draft               Embedding Code                    July 2013


      C sources under the group "C" and the python sources under the
      group "python" and the user will be able to ask to the extracter
      to extract only the files belonging to a group.

   o  Note that in the header line there is no space between the last
      "-" and the following letter (F or G) and that there is _exactly
      one space_ between the end of the group name and the letter F.

   o  The embedded text is between the header and the trailer lines.
      Not every line between the header and the trailer is an embedded
      line, but only the lines that begin with "!," or "!." (after
      discarding any initial spaces, as explained above).  There are
      three types of embedded lines: empty lines, full lines, partial
      lines.  The corresponding ABNF grammar is as follows

   empty-line      = full-marker
   full-line       = full-marker padding [body]
   partial-line    = partial-marker padding [body]
   full-marker     = "!."
   partial-marker  = "!,"
   padding         = SP / NON-ZERO / ALPHA / "|" / "@" / ":"
   body            = *63(%x20-7E) %x21-7E
   ALPHA           = %x41-5A / %x61-7A
   NON-ZERO        = %x31-39

   o  As shown in the grammar, the body of an embedded line can be any
      non-empty sequence of at most 64 printable characters.  Note that
      the body cannot end with a space, since trailing spaces are
      considered non-significant.  The limit of 64 grunts us that the
      total line length (64 characters + 3 spaces for margin + 3
      characters for marker and padding = 70) will not be larger than
      72.

   o  If a line is not empty, the inital marker (full or partial) is
      followed by a character that specifies how many white spaces are
      to be added at the end of body.  The meaning of padding is shown
      in Table 1.
      This is necessary in order to handle lines that ends with spaces.
      As explained in the requirements section, this apparently
      involuted procedure (trim the spaces at the end and put them back
      later, using a character to store the padding length) is necessary
      because in some occasions ending spaces were lost.

   o  If a content line is longer than 64 characters, it is split over
      several embedded lines.  Every embedded line but the last will
      begin with the partial-marker, while the last one will begin with
      full-marker.  Of course, if the line is shorter than 64
      characters, only the full-line will be generated.



Riccardo                Expires January 13, 2014                [Page 8]

Internet-Draft               Embedding Code                    July 2013


      Rationale:  Markers "!." and "!," were chosen because they do not
         clutter too much the embedded text, making it easly readable.
         Also the choice of using a space rather than a 0 in order to
         mark an empty padding is due to the same reason.

   o  Since only printable characters can be included in an RFC (and,
      therefore, in the body of an embedded line), an escaping mechanism
      must be provided for the occasional non-printing character.  There
      are three different types of escape sequences, described in the
      following grammar

   normal-escape  = "%" 2HEXDIGIT
   percent-escape = "%%"
   empty-escape   = "%."

      When a string is unescaped the following substitution are made

      *  In the case of a normal-escape sequence "%xy" the sequence is
         replaced by the octect whose value is equal to the hexadecimal
         number xy (e.g, %09 is replaced by a tab).

         Question:  Should we allow this only for non-printable
            characters or also for the printable ones?

      *  In the case of the percent-escape "%%" the sequence is replaced
         by a single %

      *  In the case of the empty-escape "%." the sequence is just
         deleted.

         Rationale:  This escape sequence could seem strange.  It has
            been introduced so that it can be used to break sequences of
            characters that could be misinterpreted in some context.
            For example, if the embedded text is imported in an XML file
            enclosed in a CDATA block and the code to be embedded
            contains the string "]]>" (for example, if the code produces
            an XML output), the string "]]>" in the source code can be
            mistaken for the end of the CDATA block.  By adding an
            empty-escape "%."after the "]]" the problem can be avoided.
            (In case you are wondering: yes, this happenend while
            developing the format).










Riccardo                Expires January 13, 2014                [Page 9]

Internet-Draft               Embedding Code                    July 2013


                          +-----------+--------+
                          | Character |  Value |
                          +-----------+--------+
                          |   space   |    0   |
                          |    1..9   |  1..9  |
                          |    A..Z   | 10..35 |
                          |    a..z   | 36..61 |
                          |     @     |   62   |
                          |     |     |   63   |
                          |     :     |   64   |
                          +-----------+--------+

                 Table 1: Meaning of the padding character


5.  Extractting and embedding

   In this section we describe the expected behaviour of an extractor/
   embedder by describing a possible way to extract/embed text.  We want
   to emphasize here that we do not want to constraint the algorithm
   used in a specific extractor/embedder: as soon as the external
   behaviour is equal to the behaviour of the algorithms described here,
   the extractor/embedder is acceptable.  When we say that "external
   behaviour is equal" it means that starting from the same correctly
   formatted input, the two algorithms will produce exactly the same
   output.

   If the input is not correctly formatted, we have an error condition.
   In the presence of an error condition the extractor can behave in any
   way: raise a warning, abort the execution or try to correct the
   error.

5.1.  Extractor behaviour

   The expected behaviour of an extractor must be equivalent to the
   following

   1.  The extractor keeps an internal flag In_Embedding that is true
       when the extractor is processing an embedding section.  The
       extractor also keep a string Buffer used to accumulate partial
       embedded lines

   2.  At the beginning the flag In_Embedding is set to false and the
       Buffer is empty.

   3.  For every line of the input





Riccardo                Expires January 13, 2014               [Page 10]

Internet-Draft               Embedding Code                    July 2013


       1.  Trim the spaces at the beginning and at the end of the line

       2.  If the line is a header-line and In_Embedding is false, set
           In_Embedding to true and start the next iteration of the
           loop.  It is an error if the line is a header-line and
           In_Embedding is true.

       3.  If we are here, the line is not an header-line.  If
           In_Embedding is false, start a new interation; otherwise
           check the line type

           1.  If the line is a full-line (including an empty-line),

               1.  Append the body of the line, suitably padded with the
                   required number of spaces, to Buffer

               2.  Unescape the content of Buffer

               3.  Output the result of the unescape procedure

               4.  Empty the buffer and start a new iteration

           2.  If the line is a partial-line, append its content ,
               suitably padded with the required number of spaces, to
               Buffer and start a new iteration.

           3.  If the line is a trailer-line, set In_Embedding to true
               and start a new iteration.  It is an error if when we are
               here, Buffer is not empty since it should not be possible
               to have the embedded section terminating with a partial
               line.

           4.  Ignore any other (non-embedded) line

   4.  It is an error if at the end of the file In_Embedding is true.

   Note that the unescaping step is done after joining all the lines in
   a block and not line-by-line.  This because it could happen that a
   partial line could end with a partial escape sequence, e.g., "%0".
   Although the embedder could be carefull and not split a line in the
   middle of an escape sequence, it is simpler to do the unescaping
   after the joining.

5.2.  Embedder behaviour

   The behaviour required to the embedder is simpler.  The embedder, for
   every line of the content




Riccardo                Expires January 13, 2014               [Page 11]

Internet-Draft               Embedding Code                    July 2013


   1.  Apply the escape procedure to the content line, replacing every
       non-printable character and every % with the corresponding escape
       sequence.  Optionally, it can insert the empty escape sequence
       "%." where necessary.

   2.  Break the result of the escaping procedure in blocks of at most
       64 characters.  (Of course, if the line is smaller than 64
       characters, a single block suffices.)  Blocks can be smaller than
       64 characters if the embedder decides to break the line in some
       special places like, for example, at whitespaces.  (Breaking
       lines at a whitespace could make it easier to extract the content
       by hand.)

   3.  For every block obtained at the previous step

       1.  Remove the trailing spaces, keeping track of their number

       2.  Prepend the block with the correct marker (full-marker if the
           block is the last one, partial-marker for the others)
           followed by the character specifying the number of removed
           trailing spaces

       3.  Output the result of the previous step

   Of course, the sequence of content lines will be preceded by the
   header line and followed by the trailer line.


6.  Acknowledgements


7.  IANA Considerations

   This memo includes no request to IANA.


8.  Security Considerations

   All drafts are required to have a security considerations section.
   See RFC 3552 [RFC3552] for a guide.

   TO BE WRITTEN


9.  References






Riccardo                Expires January 13, 2014               [Page 12]

Internet-Draft               Embedding Code                    July 2013


9.1.  Normative References

   [RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
              Requirement Levels", BCP 14, RFC 2119, March 1997.

   [min_ref]  authSurName, authInitials., "Minimal Reference", 2006.

9.2.  Informative References

   [I-D.narten-iana-considerations-rfc2434bis]
              Narten, T. and H. Alvestrand, "Guidelines for Writing an
              IANA Considerations Section in RFCs",
              draft-narten-iana-considerations-rfc2434bis-09 (work in
              progress), March 2008.

   [RFC2629]  Rose, M., "Writing I-Ds and RFCs using XML", RFC 2629,
              June 1999.

   [RFC3552]  Rescorla, E. and B. Korver, "Guidelines for Writing RFC
              Text on Security Considerations", BCP 72, RFC 3552,
              July 2003.


Appendix A.  Software

   In this appendix we include some software to extract/embed code from/
   into RFCs.  More precisely, we provide

   o  A bare-bones, not fully conformant, Ruby script for extraction.
      The script is not fully conformant because

      1.  It does not handle some corner cases such as padding lengths
          larger than 9, lines ending with a '%', and so on...

      2.  It does not save the extracted files according the path
          specified with F, but it acts as a filter, writing to standard
          output (i) the header and trailer lines "as they are" and (i)
          the content lines unescaped and joined together.  For example,
          if one run the Ruby script with the example shown in
          Section 2, one would obtain on the standard output the
          following result










Riccardo                Expires January 13, 2014               [Page 13]

Internet-Draft               Embedding Code                    July 2013


! --((BGN))--Ggroup-name F"example.txt"
This is an example of embedded file
This is a very, very, very, very, very, very, very, very, very,
 very, very, very long line

The line above is empty
This line ends with 3 spaces
^IThis line begins with a tab and contains ^E^G non-printable characters
! --((END))--


          where we used notation like ^I to make "visible" the non-
          printable characters.  Note that from this output is quite
          easy to extract and save the real content with a simple
          editor.

      The reason for providing this bare-bone script is that being very
      short is quite easy to extract by hand so that it can be used as a
      help in extracting the sources of the full implementation.  In a
      sense, the Ruby script acts as a "bootstrap" extractor.

   o  A fully conformant implementation of an embedder and an extractor.
      The set of the sources is contains 15 source files, plus some
      auxiliary files (README, project files, ...).  They can be easily
      extracted with the bare-bone script.

A.1.  Bare-bone extractor

   The following is the basic extractor in Ruby.  Note that it does not
   use the embedding format described here since it is expected to be
   extracted manually.


   #!/usr/bin/env ruby

   def pad_body(padding, body)
     if padding == ' '
       return body
     else
       return body + (" " * padding.to_i)
     end
   end

   def unescape(s)
     result = ""
     while pos = s.index('%')
       result += s[0...pos]
       raise "% Alone" if pos == s.length-1



Riccardo                Expires January 13, 2014               [Page 14]

Internet-Draft               Embedding Code                    July 2013


       if s[pos+1] == '.'
         s = s[pos+2..-1]
       elsif s[pos+1] == '%'
         result += '%'
         s = s[pos+2..-1]
       else
         result += s[pos+1..pos+2].to_i(16).chr
         s = s[pos+3..-1]
       end
     end

     return result + s
   end

   buffer = ""
   $stdin.each_line do |line|
     case line.strip
     when /^!\,([ 1-9])(.*)$/
       buffer += pad_body($1, $2)

     when /^!\.([ 1-9])(.*)$/
       buffer += pad_body($1, $2)
       puts unescape(buffer)
       buffer = ""

     when /^!\.$/
       puts ""

     when /^!--/
       puts line
       buffer = ""
     end
   end
   ##  END OF CODE ##


   The use of the script above is very simple.  Suppose you called it
   "basic_extractor.rb" and that you want to extract the code from
   "cool-rfc.txt" to "cool-sources.txt" you just do

         ruby basic_extractor.rb < cool-rfc.txt > cool-sources.txt

   Now you can extract the sources from cool-sources.txt with an editor
   and some patience...







Riccardo                Expires January 13, 2014               [Page 15]

Internet-Draft               Embedding Code                    July 2013


A.2.  Full implentation

A.2.1.  Usage

A.2.1.1.  Embedder

   The command line syntax for the embedder is as follows

              rfc_embedding-embedder [-C] [-g<group>] filename ...

   The command prints to the standard output the files listed on the
   command line embedded as described in this document.  If option -C is
   present, every file is embedded in a CDATA block.  If option -g is
   present, it specifies the group name to be used.

A.2.1.2.  Extractor

   The command line syntax for the extractor is as follows

                 rfc_embedding-extractor [-g<group>] [filename]

   The command reads the specified file (or the standard input, if
   filename is missing) and save the embedded files, as specified by
   their paths.  If option -g is present, only the files of the
   specified group are extracted.

A.2.2.  Sources



   !--((BGN))--Gada F"rfc_embedding.ads"
   !.
   !. package RFC_Embedding is
   !.    -- Root package
   !. end RFC_Embedding;
   !--((END))--


   !--((BGN))--Gada F"rfc_embedding-command_parsing.adb"
   !. with Ada.Strings.Fixed;
   !.
   !. with Ada.Command_Line;
   !. use Ada;
   !. with Ada.Text_IO; use Ada.Text_IO;
   !.
   !. package body RFC_Embedding.Command_Parsing is
   !.    Option_Char : constant Character := '-';
   !.



Riccardo                Expires January 13, 2014               [Page 16]

Internet-Draft               Embedding Code                    July 2013


   !.    ------------------------
   !.    -- Parse_Command_Line --
   !.    ------------------------
   !.
   !,    function Parse_Command_Line (Spec : String) return Parsing_Re
   !. sult is
   !.       use Ada.Strings.Fixed;
   !.
   !.       type Spec_Entry is
   !.          record
   !.             Void    : Boolean;
   !.             Has_Arg : Boolean;
   !.          end record;
   !.
   !,       Void_Spec : constant Spec_Entry := (Void => True, others =
   !. > <>);
   !.
   !.       type Parsed_Spec is array (Character) of Spec_Entry;
   !.
   !.       function Parse_Spec (Spec : String) return Parsed_Spec is
   !.          Result : Parsed_Spec := (others => Void_Spec);
   !.          Cursor : Positive;
   !.          Option : Character;
   !.       begin
   !.          Cursor := Spec'First;
   !.
   !.          while Cursor <= Spec'Last loop
   !.             Option := Spec (Cursor);
   !.             Cursor := Cursor + 1;
   !.
   !.             if not Result (Option).Void then
   !.                raise Program_Error;
   !.             end if;
   !.
   !,1            if Cursor <= Spec'Last and then Spec (Cursor) = ':'
   !. then
   !.                Cursor := Cursor + 1;
   !,                Result (Option) := (Void => False, Has_Arg => Tru
   !. e);
   !.             else
   !,                Result (Option) := (Void => False, Has_Arg => Fal
   !. se);
   !.             end if;
   !.          end loop;
   !.
   !.          return Result;
   !.       end Parse_Spec;
   !.



Riccardo                Expires January 13, 2014               [Page 17]

Internet-Draft               Embedding Code                    July 2013


   !.       Specs  : Parsed_Spec := Parse_Spec (Spec);
   !.       Result : Parsing_Result :=
   !.                  (Table      => (others => Void_Entry),
   !,                   Non_Option => Command_Line.Argument_Count + 1)
   !. ;
   !.       Cursor : Positive;
   !.    begin
   !.       Cursor := 1;
   !.
   !.       Option_Loop :
   !.       while Cursor <= Command_Line.Argument_Count loop
   !.          declare
   !.             Option : String := Command_Line.Argument (Cursor);
   !.             Name   : Character;
   !.          begin
   !. --              Put_Line ("Parsing '" & Option & "'");
   !.
   !,             if Option (Option'First) /= Option_Char or Option'Le
   !. ngth = 1 then
   !, --                 Put_Line ("Exiting... con cursor = " & Cursor
   !. 'Img);
   !.                Result.Non_Option := Cursor;
   !.                exit Option_Loop;
   !.             end if;
   !.
   !.             Name := Option (Option'First + 1);
   !.
   !.             if Name = Option_Char then
   !.                --  Option '--' mark the end of the options
   !.
   !.                Result.Non_Option := Cursor + 1;
   !.                exit Option_Loop;
   !.             end if;
   !.
   !.
   !.
   !.
   !.             if Specs (Name).Void then
   !.                raise Program_Error;
   !.             end if;
   !.
   !.             if Result.Table (Name).Given then
   !,                raise Program_Error with "Option '" & Name & "' g
   !. iven twice";
   !.             end if;
   !.
   !.             Result.Table (Name) := (Given => True,
   !,                                     Value => Null_Unbounded_Stri



Riccardo                Expires January 13, 2014               [Page 18]

Internet-Draft               Embedding Code                    July 2013


   !. ng);
   !.
   !.
   !.             Cursor := Cursor + 1;
   !.
   !.             if Specs (Name).Has_Arg then
   !.                if Option'Length > 2 then
   !.                   Result.Table (Name).Value :=
   !,                     To_Unbounded_String (Tail (Option, Option'Le
   !. ngth - 2));
   !.                else
   !.                   if Cursor > Command_Line.Argument_Count then
   !.                      raise Program_Error;
   !.                   else
   !.                      Result.Table (Name).Value :=
   !,                        To_Unbounded_String (Command_Line.Argumen
   !. t (Cursor));
   !.
   !.                      Cursor := Cursor + 1;
   !.                   end if;
   !.                end if;
   !.             else
   !.                if Option'Length > 2 then
   !.                   raise Program_Error;
   !.                end if;
   !.             end if;
   !.          end;
   !.       end loop Option_Loop;
   !.
   !, --        Put_Line ("Primo utile : " & Integer'Image (Result.Non
   !. _Option));
   !.       return Result;
   !.    end Parse_Command_Line;
   !.
   !.    ----------------
   !.    -- Get_Option --
   !.    ----------------
   !.
   !.    function Get_Option
   !.      (From    : Parsing_Result;
   !.       Name    : Character;
   !.       Default : String := "")
   !.       return String
   !.    is
   !.    begin
   !.       if From.Table (Name).Given then
   !.          return To_String (From.Table (Name).Value);
   !.       else



Riccardo                Expires January 13, 2014               [Page 19]

Internet-Draft               Embedding Code                    July 2013


   !.          return Default;
   !.       end if;
   !.    end Get_Option;
   !.
   !.
   !.    --------------
   !.    -- Is_Given --
   !.    --------------
   !.
   !.    function Is_Given (Item    : Parsing_Result;
   !.                       Name    : Character) return Boolean is
   !.    begin
   !.       return Item.Table (Name).Given;
   !.    end Is_Given;
   !.
   !.    ----------------------
   !.    -- First_Non_Option --
   !.    ----------------------
   !.
   !,    function First_Non_Option (Item  : Parsing_Result) return Nat
   !. ural is
   !.    begin
   !.       return Item.Non_Option;
   !.    end First_Non_Option;
   !.
   !. end RFC_Embedding.Command_Parsing;
   !--((END))--


   !--((BGN))--Gada F"rfc_embedding-command_parsing.ads"
   !. with Ada.Strings.Unbounded;       use Ada.Strings.Unbounded;
   !.
   !. --
   !. --  Yes, I confess, I am guilty of writing the Aleph_1-th
   !. --  package for parsing command lines.  It must be said that
   !, --  the usage of this package is more convinient (in my opinion)
   !.
   !. --  than the usual getopt-like approach.
   !. --
   !. --  The basic usage is as follows:
   !. --
   !, --     * At the beginning of the program, the function Parse_Com
   !. mand_Line
   !, --       is called and it returns an object of type Parsing_Resu
   !. lt.  Since
   !, --       Parsing_Result is declared to have unknown specifiers (
   !. <>), a variable
   !, --       of this type must be initialized at declaration time, s



Riccardo                Expires January 13, 2014               [Page 20]

Internet-Draft               Embedding Code                    July 2013


   !. o the
   !. --       usual calling sequence is
   !. --
   !, --          CL_Options : Parsing_Result := Parse_Command_Line("g
   !. :xh");
   !. --
   !, --     * The Parsing_Result object is queried to check is some o
   !. ptions were
   !. --       specified and to get the value given to the option.
   !. --
   !, --  Options begin with '-' and their name is just a single chara
   !. cter
   !, --  (multi-char names are not implmented), the option order does
   !.  not matter,
   !. --  option values can be given both as in "-f115" or "-f 115",
   !, --  an option cannot be specified more than once, special option
   !.  '--'
   !. --  can be used to mark the end of options.
   !. --
   !.
   !. package RFC_Embedding.Command_Parsing is
   !.    type Parsing_Result (<>) is tagged private;
   !.
   !,    function Parse_Command_Line (Spec : String) return Parsing_Re
   !. sult;
   !,    --  Parse the given command line and return the result in a v
   !. alue
   !,    --  of type Parsing_Result.  Spec specifies the recognized op
   !. tions.
   !,    --  As with getopt, Spec is a sequence of option where ':' fo
   !. llows
   !.    --  an option name if the option expects a parameter
   !.
   !.    function Get_Option (From    : Parsing_Result;
   !.                         Name    : Character;
   !.                         Default : String := "")
   !.                         return String;
   !,    --  Return the value associated to the specified option Name.
   !.   If the
   !,    --  option was not given on the command line, return the valu
   !. e
   !.    --  of Default.
   !.
   !.
   !.
   !.    function Is_Given (Item    : Parsing_Result;
   !.                       Name    : Character) return Boolean;
   !,    --  Return true if the specified option was given on the comm



Riccardo                Expires January 13, 2014               [Page 21]

Internet-Draft               Embedding Code                    July 2013


   !. and line
   !.
   !,    function First_Non_Option (Item  : Parsing_Result) return Nat
   !. ural;
   !.    --  Return the index of the first non-option value
   !.
   !. private
   !.    type Option_Entry is
   !.       record
   !.          Given : Boolean;
   !.          Value : Unbounded_String;
   !.       end record;
   !.
   !,    Void_Entry : constant Option_Entry := (False, Null_Unbounded_
   !. String);
   !.
   !.    type Option_Array is array (Character) of Option_Entry;
   !.
   !.    type Parsing_Result  is tagged
   !.       record
   !.          Table      : Option_Array;
   !.          Non_Option : Positive;
   !.       end record;
   !. end RFC_Embedding.Command_Parsing;
   !--((END))--


   !--((BGN))--Gada F"rfc_embedding-embedder.adb"
   !. with RFC_Embedding.Syntax;
   !. with RFC_Embedding.Syntax.Escaping;
   !.
   !. with RFC_Embedding.Command_Parsing;
   !.
   !. with Ada.Directories;
   !. with Ada.Strings.Unbounded;
   !. with Ada.Strings.Fixed;
   !. with Ada.Text_IO.Unbounded_IO;
   !. with Ada.Command_Line;
   !. use  Ada;
   !. use  Ada.Strings.Unbounded;
   !. use  Ada.Strings.Fixed;
   !. use  Ada.Text_IO;
   !.
   !. procedure RFC_Embedding.Embedder is
   !.    User_Error : exception;
   !.
   !.    procedure Print_Embedded (Filename  : String;
   !.                              Group     : String;



Riccardo                Expires January 13, 2014               [Page 22]

Internet-Draft               Embedding Code                    July 2013


   !.                              Use_Cdata : Boolean) is
   !.       use Syntax, Syntax.Escaping;
   !.       use Text_IO;
   !.       use Text_IO.Unbounded_IO;
   !.       use type Directories.File_Kind;
   !.
   !.       Input : Text_IO.File_Type;
   !.    begin
   !,       if Directories.Kind (Filename) /= Directories.Ordinary_Fil
   !. e then
   !.          return;
   !.       end if;
   !.
   !.       Text_IO.Open (File => Input,
   !.                     Mode => Text_IO.In_File,
   !.                     Name => Filename);
   !.
   !.       if Use_CData then
   !.          Put_Line ("<![CDATA[");
   !.       end if;
   !.
   !.       Put_Line (Make_Begin_Line (Full_Filename => Filename,
   !.                                  Group         => Group));
   !.
   !.       loop
   !.          declare
   !.             Lines  : constant Line_Array :=
   !,                        Make_Embedded_Lines (Escape (Get_Line (In
   !. put), "]]%."));
   !.          begin
   !.             for I in Lines'Range loop
   !.                Put_Line (Lines (I));
   !.             end loop;
   !.          end;
   !.
   !.          exit when End_Of_File (Input);
   !.       end loop;
   !.
   !.       Put_Line (Syntax.End_Line);
   !.
   !.       if Use_CData then
   !.          Put_Line ("]]%.>");
   !.       end if;
   !.
   !.    end Print_Embedded;
   !.
   !.    procedure Die_With_Help is
   !.    begin



Riccardo                Expires January 13, 2014               [Page 23]

Internet-Draft               Embedding Code                    July 2013


   !.       New_Line (Standard_Error);
   !,       Put_Line (Standard_Error, "Usage: embedder [options...] [f
   !. ilename...]");
   !.       New_Line (Standard_Error);
   !,       Put_Line (Standard_Error, "  If no filename is given on th
   !. e command");
   !,       Put_Line (Standard_Error, "  line, the names are read from
   !.  the ");
   !.       Put_Line (Standard_Error, "  standard input.");
   !.       New_Line (Standard_Error);
   !.       Put_Line (Standard_Error, "  Options:");
   !,       Put_Line (Standard_Error, "  -g<group>     Use group name"
   !. );
   !,       Put_Line (Standard_Error, "  -C            Put a CData she
   !. ll around the text");
   !.       New_Line (Standard_Error);
   !.
   !.       raise User_Error;
   !.    end Die_With_Help;
   !.
   !,    procedure Get_Group_Name (Group_Name   : out Unbounded_String
   !. ;
   !.                              First_Unused : out Positive) is
   !.    begin
   !.       if Command_Line.Argument_Count = 0 then
   !.          Group_Name  := Null_Unbounded_String;
   !.          First_Unused := 1;
   !.          return;
   !.       end if;
   !.
   !.       declare
   !.          First_Arg : String := Command_Line.Argument (1);
   !.       begin
   !.          First_Unused := 1;
   !.
   !,          if First_Arg'Length >= 2 and then Head (First_Arg, 2) =
   !.  "-g" then
   !.             if First_Arg'Length > 2 then
   !.                Group_Name :=
   !,                  To_Unbounded_String  (Tail (First_Arg, First_Ar
   !. g'Length - 2));
   !.
   !.                First_Unused := 2;
   !.             else
   !.                if Command_Line.Argument_Count = 1 then
   !.                   Die_With_Help;
   !.                end if;
   !.



Riccardo                Expires January 13, 2014               [Page 24]

Internet-Draft               Embedding Code                    July 2013


   !,                Group_Name := To_Unbounded_String (Command_Line.A
   !. rgument (2));
   !.                First_Unused := 3;
   !.             end if;
   !.          end if;
   !.       end;
   !.    end Get_Group_Name;
   !.
   !.    First_Unused    : Positive;
   !.    Group_Name      : Unbounded_String;
   !.    Use_CData_Shell : Boolean;
   !.    Options         : Command_Parsing.Parsing_Result :=
   !,                        Command_Parsing.Parse_Command_Line ("g:C"
   !. );
   !. begin
   !,    Group_Name := To_Unbounded_String (Options.Get_Option ('g', "
   !. "));
   !.    Use_CData_Shell := Options.Is_Given ('C');
   !.
   !.    First_Unused := Options.First_Non_Option;
   !.
   !.    if Command_Line.Argument_Count >= First_Unused then
   !.       for I in First_Unused .. Command_Line.Argument_Count loop
   !.          Print_Embedded (Filename => Command_Line.Argument (I),
   !.                          Group    => To_String (Group_Name),
   !.                          Use_CData => Use_CData_Shell);
   !.       end loop;
   !.    else
   !.       loop
   !.          declare
   !.             Filename : String := Get_Line;
   !.          begin
   !.             Print_Embedded (Filename => Filename,
   !.                             Group    => To_String (Group_Name),
   !.                             Use_CData => Use_CData_Shell);
   !.          end;
   !.
   !.          exit when End_Of_File;
   !.       end loop;
   !.    end if;
   !.
   !. exception
   !.    when User_Error =>
   !.       Command_Line.Set_Exit_Status (Command_Line.Failure);
   !. end RFC_Embedding.Embedder;
   !--((END))--





Riccardo                Expires January 13, 2014               [Page 25]

Internet-Draft               Embedding Code                    July 2013


   !--((BGN))--Gada F"rfc_embedding-errors.adb"
   !. with Ada.Text_IO;           use  Ada.Text_IO;
   !.
   !. package body RFC_Embedding.Errors is
   !.    Warnings_Are_Fatal : Boolean := False;
   !.
   !.    procedure Raise_Error (Source : Error_Source)
   !.    is
   !.    begin
   !.       case Source is
   !.          when User =>
   !.             raise User_Error;
   !.          when Format =>
   !.             raise Format_Error;
   !.       end case;
   !.    end Raise_Error;
   !.
   !.    procedure Warning (Msg    : String;
   !.                       Source : Error_Source := User) is
   !.    begin
   !.       Put_Line (Standard_Error, "Warning : " & Msg);
   !.
   !.       if Warnings_Are_Fatal then
   !.          Raise_Error (Source);
   !.       end if;
   !.    end Warning;
   !.
   !.    procedure Die (Msg    : String;
   !.                   Source : Error_Source := User) is
   !.    begin
   !.       Put_Line (Standard_Error, "Error : " & Msg);
   !.
   !.       Raise_Error (Source);
   !.    end Die;
   !.
   !.    -------------------------
   !.    -- Make_Warnings_Fatal --
   !.    -------------------------
   !.
   !.    procedure Make_Warnings_Fatal (Status : Boolean) is
   !.    begin
   !.       Warnings_Are_Fatal := Status;
   !.    end Make_Warnings_Fatal;
   !.
   !. end RFC_Embedding.Errors;
   !--((END))--





Riccardo                Expires January 13, 2014               [Page 26]

Internet-Draft               Embedding Code                    July 2013


   !--((BGN))--Gada F"rfc_embedding-errors.ads"
   !.
   !. package RFC_Embedding.Errors is
   !.    type Error_Source is (User, Format);
   !.
   !.    procedure Die (Msg    : String;
   !.                   Source : Error_Source := User);
   !.
   !.    procedure Warning (Msg    : String;
   !.                       Source : Error_Source := User);
   !.
   !.    procedure Make_Warnings_Fatal (Status : Boolean);
   !.
   !.    User_Error : exception;
   !.    Format_Error : exception;
   !. end RFC_Embedding.Errors;
   !--((END))--


   !--((BGN))--Gada F"rfc_embedding-extractor.adb"
   !. with Ada.Strings.Fixed;
   !. with Ada.Strings.Maps.Constants;
   !. with Ada.Strings.Unbounded;
   !. use  Ada.Strings.Unbounded;
   !. use  Ada.Strings;
   !. use  Ada;
   !.
   !. with Ada.Directories;
   !.
   !. with Ada.Characters.Handling;
   !. with Ada.Characters.Latin_1;
   !. use  Ada.Characters.Latin_1;
   !.
   !. with Ada.Command_Line;
   !. use  Ada.Command_Line;
   !.
   !. with Ada.Text_IO.Unbounded_IO;
   !. use Ada.Text_IO;
   !.
   !. with RFC_Embedding.Syntax.Escaping;
   !. with RFC_Embedding.Errors;
   !.
   !. use RFC_Embedding.Syntax.Escaping;
   !. use RFC_Embedding.Errors;
   !.
   !. with RFC_Embedding.Command_Parsing;
   !. use  RFC_Embedding.Command_Parsing;
   !.



Riccardo                Expires January 13, 2014               [Page 27]

Internet-Draft               Embedding Code                    July 2013


   !. procedure RFC_Embedding.Extractor is
   !.    type Group_Pattern is new Unbounded_String;
   !.
   !.    Any_Group : constant Group_Pattern :=
   !.                  Group_Pattern (Null_Unbounded_String);
   !.
   !.    type Status_Type is (In_Body, In_Content);
   !.
   !.    type Content_Action is (Extract, Skip);
   !.
   !,1   function Read_Line (Input : Text_Io.File_Type) return String
   !. is
   !.       Line : String := Text_Io.Get_Line (Input);
   !.       From : Natural := Line'First;
   !.       To   : Natural := Line'Last;
   !.    begin
   !.       --  Ada is smart enough to handle the local end-of-line
   !,       --  convention.  Although according to RFC ????, the RFC t
   !. ext
   !,       --  should use the local convention for end-of-line, it co
   !. uld happen
   !.       --  that
   !.       if Line (Line'First) = CR or Line (Line'First) = LF then
   !.          From := From + 1;
   !.       end if;
   !.
   !.       if Line (Line'Last) = CR or Line (Line'Last) = LF then
   !.          To := To - 1;
   !.       end if;
   !.
   !.       return Line (From .. To);
   !.    end Read_Line;
   !.
   !.    procedure Empty_Buffer (Output  : Text_Io.File_Type;
   !.                            Buffer  : in out Unbounded_String)
   !.    is
   !.    begin
   !.       Put_Line (File => Output,
   !.                 Item => Unescape (To_String (Buffer)));
   !.
   !.       Buffer := Null_Unbounded_String;
   !.    end Empty_Buffer;
   !.
   !.    function Is_Desired (Desired : Group_Pattern;
   !.                         Group   : Syntax.Group_Name)
   !.                         return Boolean
   !.    is
   !.       use Syntax;



Riccardo                Expires January 13, 2014               [Page 28]

Internet-Draft               Embedding Code                    July 2013


   !.    begin
   !.       Put_Line ("Desidered : '" & To_String (Desired)  & "'"
   !.                 & "Got : '" & To_String (Group) & "'");
   !.       return
   !.         Desired = Any_Group  or
   !.         Unbounded_String (Desired) = Unbounded_String (Group);
   !.    end Is_Desired;
   !.
   !.
   !.    Output        : Text_Io.File_Type;
   !.    Input         : Text_Io.File_Type;
   !.    Buffer        : Unbounded_String := Null_Unbounded_String;
   !.    Status        : Status_Type := In_Body;
   !.    Action        : Content_Action;
   !.    Class         : Syntax.Line_Class;
   !.    Content       : Unbounded_String;
   !.    Desired       : Group_Pattern := Any_Group;
   !.    Options       : Parsing_Result := Parse_Command_Line ("g:");
   !. begin
   !.    if Options.Is_Given('g') then
   !,       Desired := To_Unbounded_String (Options.Get_Option ('g'));
   !.
   !.    end if;
   !.
   !,    case Command_Line.Argument_Count - Options.First_Non_Option i
   !. s
   !.       when -1 =>
   !.          null;
   !.
   !.       when 0 =>
   !.          Text_Io.Open (File => Input,
   !.                        Mode => Text_Io.In_File,
   !,                        Name => Command_Line.Argument (Options.Fi
   !. rst_Non_Option));
   !.
   !.          Text_Io.Set_Input (Input);
   !.
   !.       when others =>
   !.          raise Program_Error;
   !.    end case;
   !.
   !.    loop
   !.       declare
   !.          Line : String := Text_Io.Get_Line;
   !.       begin
   !.          case Status is
   !.             when In_Body =>
   !.                if Syntax.Is_Begin_Line (Line) then



Riccardo                Expires January 13, 2014               [Page 29]

Internet-Draft               Embedding Code                    July 2013


   !.                   Status := In_Content;
   !.
   !.                   declare
   !.                      use Ada.Directories;
   !.
   !.                      Group    : Syntax.Group_Name;
   !.                      Path     : Unbounded_String;
   !.                      Filename : Unbounded_String;
   !.                   begin
   !.                      Syntax.Parse_Begin_Line (Item     => Line,
   !,                                               Group    => Group,
   !.
   !.                                               Dir      => Path,
   !,                                               Filename => Filena
   !. me);
   !.
   !.                      if Path /= Null_Unbounded_String then
   !.                         Create_Path (To_String (Path));
   !.                      end if;
   !.
   !.                      if Is_Desired (Desired, Group) then
   !.                         Action := Extract;
   !.
   !.                         Text_Io.Create
   !.                           (File => Output,
   !.                            Mode => Text_Io.Out_File,
   !.                            Name => Compose
   !,1                             (Containing_Directory => To_String
   !. (Path),
   !,1                              Name                 => To_String
   !. (Filename)));
   !.                      else
   !.                         Action := Skip;
   !.                      end if;
   !.                   end;
   !.                end if;
   !.
   !.             when In_Content =>
   !.                Syntax.Parse_Content_Line (Item    => Line,
   !.                                           Class   => Class,
   !.                                           Content => Content);
   !.
   !.                case Class is
   !.                   when Syntax.Full_Content =>
   !.                      if Action = Extract then
   !.                         Append (Buffer, Content);
   !.
   !.                         Empty_Buffer (Output, Buffer);



Riccardo                Expires January 13, 2014               [Page 30]

Internet-Draft               Embedding Code                    July 2013


   !.                      end if;
   !.
   !.
   !.                   when Syntax.Partial_Content =>
   !.                      if Action = Extract then
   !.                         Append (Buffer, Content);
   !.                      end if;
   !.
   !.                   when Syntax.End_Content =>
   !.                      if Buffer /= Null_Unbounded_String then
   !,                         Warning ("End line after partial content
   !.  line");
   !.
   !.                         if Action = Extract then
   !.                            Empty_Buffer (Output, Buffer);
   !.                         end if;
   !.                      end if;
   !.
   !.                      if Action = Extract then
   !.                         Text_Io.Close (Output);
   !.                      end if;
   !.
   !.                      Status := In_Body;
   !.
   !.                   when Syntax.No_Content =>
   !.                      null;
   !.                end case;
   !.          end case;
   !.       end;
   !.
   !.       if Text_Io.End_Of_File then
   !.          if Status = In_Content then
   !.             Warning ("End of file while in content");
   !.
   !.             if Action = Extract then
   !.                if Buffer /= Null_Unbounded_String then
   !.                   Empty_Buffer (Output, Buffer);
   !.                end if;
   !.
   !.                Text_Io.Close (Output);
   !.             end if;
   !.          end if;
   !.
   !.          exit;
   !.       end if;
   !.    end loop;
   !.
   !. exception



Riccardo                Expires January 13, 2014               [Page 31]

Internet-Draft               Embedding Code                    July 2013


   !.    when User_Error =>
   !.       Set_Exit_Status (Failure);
   !. end RFC_Embedding.Extractor;
   !--((END))--


   !--((BGN))--Gada F"rfc_embedding-syntax.adb"
   !, with Ada.Strings.Fixed;                    use Ada, Ada.Strings;
   !.
   !.
   !. with RFC_Embedding.Syntax.Path_Syntax;
   !. with RFC_Embedding.Syntax.Escaping;
   !.
   !.
   !. package body RFC_Embedding.Syntax is
   !.    Max_Block_Size    : constant Integer := 64;
   !.    Begin_Mark        : constant String := "!--((BGN))--";
   !.    End_Mark          : constant String := "!--((END))--";
   !.    Full_Line_Head    : constant String := "!.";
   !.    Partial_Line_Head : constant String := "!,";
   !.
   !.    Group_Marker      : constant Character := 'G';
   !.    Filename_Marker   : constant Character := 'F';
   !.
   !,    subtype Extended_Space_Length is Integer range -1 .. Max_Bloc
   !. k_Size;
   !,    subtype Space_Length is Extended_Space_Length range 0 .. Max_
   !. Block_Size;
   !.
   !.    Space_Length_Encoding : array (Space_Length) of Character;
   !,    Space_Length_Decoding : array (Character) of Extended_Space_L
   !. ength :=
   !.                              (others => -1);
   !.
   !,    pragma Assert (Full_Line_Head'Length = Partial_Line_Head'Leng
   !. th);
   !,    pragma Assert (Full_Line_Head'Length + Max_Block_Size + 3 < 7
   !. 2);
   !.
   !.    -------------------
   !.    -- Is_Begin_Line --
   !.    -------------------
   !.
   !.    function Is_Begin_Line (Line : String) return Boolean is
   !.       L : String := Fixed.Trim(Line, Strings.Left);
   !.    begin
   !.       return L'Length > Begin_Mark'Length and then
   !,          L (L'First .. L'First + Begin_Mark'Length - 1) = Begin_



Riccardo                Expires January 13, 2014               [Page 32]

Internet-Draft               Embedding Code                    July 2013


   !. Mark;
   !.    end Is_Begin_Line;
   !.
   !.    ----------------------
   !.    -- Parse_Begin_Line --
   !.    ----------------------
   !.
   !.    procedure Parse_Begin_Line
   !.       (Item     : String;
   !.        Group    : out Group_Name;
   !.        Dir      : out Unbounded_String;
   !.        Filename : out Unbounded_String)
   !.    is
   !.       use Ada.Strings.Fixed;
   !.
   !.       procedure Extract_Group_Name (Line   : String;
   !.                                     Cursor : in out Natural;
   !.                                     Group  :    out Group_Name)
   !.       is
   !.          Idx : Natural;
   !.       begin
   !.          Idx := Index (Source  => Line,
   !.                        Pattern => " ",
   !.                        From    => Cursor);
   !.
   !.          if Idx = 0 or Idx = Cursor or Idx = Line'Last then
   !.             raise Program_Error;
   !.          end if;
   !.
   !,          Group := To_Unbounded_String (Line (Cursor + 1 .. Idx -
   !.  1));
   !.
   !.          Cursor := Index_Non_Blank (Source => Line,
   !.                                     From   => Idx + 1);
   !.
   !.          if Cursor = 0 then
   !.             raise Program_Error;
   !.          end if;
   !.       end Extract_Group_Name;
   !.
   !.       Line : String := Fixed.Trim (Item, Strings.Left);
   !.       Cursor : Natural;
   !.    begin
   !.       if not Is_Begin_Line (Line) then
   !.          raise Program_Error;
   !.       end if;
   !.
   !.       Cursor := Index_Non_Blank (Source => Line,



Riccardo                Expires January 13, 2014               [Page 33]

Internet-Draft               Embedding Code                    July 2013


   !,                                  From   => Line'First + Begin_Ma
   !. rk'Length);
   !.
   !.       if Cursor = 0 then
   !.          raise Program_Error;
   !.       end if;
   !.
   !.       if Line (Cursor) = Group_Marker then
   !.          Extract_Group_Name (Line, Cursor, Group);
   !.       else
   !.          Group := Group_Name (Null_Unbounded_String);
   !.       end if;
   !.
   !,       if Cursor + 2 > Line'Last or else Line (Cursor) /= Filenam
   !. e_Marker then
   !.          raise Program_Error;
   !.       end if;
   !.
   !.       Cursor := Cursor + 1;
   !.
   !.       declare
   !.          use Path_Syntax;
   !.
   !.          End_Char : constant String := Line (Cursor .. Cursor);
   !.          Last     : constant Natural := Index (Source  => Line,
   !,                                                Pattern => End_Ch
   !. ar,
   !,                                                From    => Cursor
   !.  + 1);
   !.       begin
   !.          if Last = 0 or Last = Cursor + 1 then
   !.             raise Program_Error;
   !.          end if;
   !.
   !,          To_Local_Syntax (Source   => Line (Cursor + 1 .. Last -
   !.  1),
   !.                           Path      => Dir,
   !.                           Filename => Filename);
   !.       end;
   !.
   !.    end Parse_Begin_Line;
   !.
   !.    ---------------------
   !.    -- Make_Begin_Line --
   !.    ---------------------
   !.
   !.    function Make_Begin_Line
   !.       (Full_Filename : String;



Riccardo                Expires January 13, 2014               [Page 34]

Internet-Draft               Embedding Code                    July 2013


   !.        Group         : String := "")
   !.       return String
   !.    is
   !.       use Ada.Strings.Fixed;
   !.       use Path_Syntax;
   !.
   !.       function Find_Unused (X : String) return Character is
   !.          Candidates : constant String := """'%%$|,;:*^#";
   !.       begin
   !.          for I in Candidates'Range loop
   !,1            if Index (Source  => X, Pattern => Candidates (I ..
   !. I)) = 0 then
   !.                return Candidates (I);
   !.             end if;
   !.          end loop;
   !.
   !.          raise Program_Error;
   !.       end Find_Unused;
   !.
   !,       Result : Unbounded_String := To_Unbounded_String (Begin_Ma
   !. rk);
   !,       Embedding_Name : String := To_Embedded_Syntax (Full_Filena
   !. me);
   !.       Delim  : Character := Find_Unused (Embedding_Name);
   !.    begin
   !.       if Group /= "" then
   !.          if Index (Source => Group, Pattern => " ") /= 0 then
   !.             raise Program_Error;
   !.          end if;
   !.
   !.          Result := Result & Group_Marker & Group & " ";
   !.       end if;
   !.
   !.       Result := Result
   !.          & Filename_Marker
   !.          & Delim
   !.          & Embedding_Name
   !.          & Delim;
   !.
   !.       return To_String (Result);
   !.    end Make_Begin_Line;
   !.
   !.    --------------
   !.    -- End_Line --
   !.    --------------
   !.
   !.    function End_Line return String is
   !.    begin



Riccardo                Expires January 13, 2014               [Page 35]

Internet-Draft               Embedding Code                    July 2013


   !.       return End_Mark;
   !.    end End_Line;
   !.
   !.    ------------------------
   !.    -- Parse_Content_Line --
   !.    ------------------------
   !.
   !.    procedure Parse_Content_Line
   !.       (Item    : String;
   !.        Class   : out Line_Class;
   !.        Content : out Unbounded_String)
   !.    is
   !.       use Escaping;
   !.
   !.       function Get_Line_Type (Line : String) return Line_Class
   !.       is
   !,          function Head_Is (Line : String; Other : String) return
   !.  Boolean
   !.          is
   !.          begin
   !.             if Line'Length < Other'Length then
   !.                return False;
   !.             else
   !,                return Line (Line'First .. Line'First + Other'Len
   !. gth - 1) = Other;
   !.             end if;
   !.          end Head_Is;
   !.       begin
   !.          if Head_Is (Line, End_Mark) then
   !.             return End_Content;
   !.
   !.          elsif Head_Is (Line, Full_Line_Head) then
   !.             return Full_Content;
   !.
   !.          elsif Head_Is (Line, Partial_Line_Head) then
   !.             return Partial_Content;
   !.
   !.          else
   !.             return No_Content;
   !.          end if;
   !.       end Get_Line_Type;
   !.
   !.       Line : String := Fixed.Trim (Item, Strings.Left);
   !.       Padding : Integer;
   !.    begin
   !.       Class := Get_Line_Type (Line);
   !.
   !.       if Class = Partial_Content or Class = Full_Content then



Riccardo                Expires January 13, 2014               [Page 36]

Internet-Draft               Embedding Code                    July 2013


   !.          if Line'Length = Full_Line_Head'Length then
   !.             if Class = Full_Content then
   !.                Content := Null_Unbounded_String;
   !.                return;
   !.             else
   !.                raise Program_Error;
   !.             end if;
   !.          end if;
   !.
   !,          Padding := Space_Length_Decoding (Line (Line'First + Fu
   !. ll_Line_Head'Length));
   !.
   !.          if not (Padding in Space_Length) then
   !.             raise Program_Error;
   !.          end if;
   !.
   !.          Content := To_Unbounded_String
   !,            (Line (Line'First + Full_Line_Head'Length + 1 .. Line
   !. 'Last));
   !.
   !.          Content := Content & (Padding * " ");
   !.       end if;
   !.    end Parse_Content_Line;
   !.
   !.    -------------------------
   !.    -- Make_Embedded_Lines --
   !.    -------------------------
   !.
   !,    function Make_Embedded_Lines (Line : String) return Line_Arra
   !. y is
   !.       use Escaping;
   !.
   !,       N_Blocks   : constant Integer := 1 + Line'Length / Max_Blo
   !. ck_Size;
   !.
   !,       function Make_Block (Item : String) return Unbounded_Strin
   !. g is
   !,          Trimmed : constant String := Fixed.Trim (Item, Strings.
   !. Right);
   !,          Padding : constant Space_Length := Item'Length - Trimme
   !. d'Length;
   !.       begin
   !.          if Item = "" then
   !.             return Null_Unbounded_String;
   !.          else
   !.             return To_Unbounded_String
   !.               (Space_Length_Encoding (Padding) & Trimmed);
   !.          end if;



Riccardo                Expires January 13, 2014               [Page 37]

Internet-Draft               Embedding Code                    July 2013


   !.       end Make_Block;
   !.
   !.       Result : Line_Array (1 .. N_Blocks);
   !.    begin
   !.       for Block in 1 .. N_Blocks - 1 loop
   !.          Result (Block) := Partial_Line_Head &
   !,          Make_Block (Line ((Block - 1) * Max_Block_Size + 1 .. B
   !. lock * Max_Block_Size));
   !.       end loop;
   !.
   !.       Result (N_Blocks) := Full_Line_Head &
   !,       Make_Block (Line ((N_Blocks - 1) * Max_Block_Size + 1 .. L
   !. ine'Last));
   !.
   !.       return Result;
   !.    end Make_Embedded_Lines;
   !. begin
   !.    Space_Length_Encoding (0) := ' ';
   !.
   !.    for I in 1 .. 9 loop
   !,1      Space_Length_Encoding (I) := Character'Val (Character'Pos
   !. ('0')+I);
   !.    end loop;
   !.
   !.    for I in 0 .. 25 loop
   !,       Space_Length_Encoding (I + 10) := Character'Val (Character
   !. 'Pos ('A')+I);
   !,       Space_Length_Encoding (I + 36) := Character'Val (Character
   !. 'Pos ('a')+I);
   !.    end loop;
   !.
   !.    Space_Length_Encoding (62) := '@';
   !.    Space_Length_Encoding (63) := '|';
   !.    Space_Length_Encoding (64) := ':';
   !.
   !.    for I in Space_Length_Encoding'Range loop
   !.       Space_Length_Decoding (Space_Length_Encoding (I)) := I;
   !.    end loop;
   !. end RFC_Embedding.Syntax;
   !--((END))--


   !--((BGN))--Gada F"rfc_embedding-syntax.ads"
   !. with Ada.Strings.Unbounded;      use Ada.Strings.Unbounded;
   !.
   !. --
   !. --  This package takes care of most of the syntactical aspects
   !. --  of the embedded format: embedded line headers, begin/end



Riccardo                Expires January 13, 2014               [Page 38]

Internet-Draft               Embedding Code                    July 2013


   !. --  markers, groups and filenames and so on
   !. --
   !.
   !. package RFC_Embedding.Syntax is
   !.    type Group_Name is new Unbounded_String;
   !.
   !.    type Line_Class is
   !.      (Full_Content, Partial_Content, No_Content, End_Content);
   !.
   !.    function Is_Begin_Line (Line : String)return Boolean;
   !.    --  Return true if the line begins an embedded content
   !.
   !.
   !.    procedure Parse_Begin_Line
   !.      (Item     : String;
   !.       Group    : out Group_Name;
   !.       Dir      : out Unbounded_String;
   !.       Filename : out Unbounded_String);
   !.
   !.    pragma Precondition (Is_Begin_Line (Item));
   !,    --  Parse a "begin line" and return the filename of the conte
   !. nt, an
   !,    --  optional path and the optional group the content belong t
   !. o.  The path
   !,    --  and the filename follows the "local" convention; for exam
   !. ple, the path
   !.    --  will be separated by '/' in *nix and by '\' in Windows.
   !.
   !.    function Make_Begin_Line
   !.      (Full_Filename : String;
   !.       Group         : String := "")
   !.        return String;
   !,    --  Create a "begin line" using the given filename (in the "l
   !. ocal" syntax)
   !.    --  and optional group
   !.
   !,    pragma Postcondition (Is_Begin_Line (Make_Begin_Line'Result))
   !. ;
   !.
   !.    function End_Line return String;
   !.    --  Return the line used to mark the end of an embedded file
   !.
   !.    procedure Parse_Content_Line
   !.      (Item    : String;
   !.       Class   : out Line_Class;
   !.       Content : out Unbounded_String);
   !,    --  Determine the class of the given line and return it in Cl
   !. ass.  If



Riccardo                Expires January 13, 2014               [Page 39]

Internet-Draft               Embedding Code                    July 2013


   !,1   --  the line is a content line (full or partial), return the
   !. "body" of
   !,    --  the line in Content.  The value of Content is unspecified
   !.  if
   !.    --  Class = No_content or End_Content
   !.
   !,    type Line_Array is array (Positive range <>) of Unbounded_Str
   !. ing;
   !.
   !,    function Make_Embedded_Lines (Line : String) return Line_Arra
   !. y;
   !,    --  Take the content line and create one (or more, if necessa
   !. ry) lines
   !.    --  with the correct marker at the begin
   !.
   !. end RFC_Embedding.Syntax;
   !--((END))--


   !--((BGN))--Gada F"rfc_embedding-syntax-escaping.adb"
   !. with Ada.Characters.Handling;
   !.
   !. with Ada.Strings.Fixed;
   !. use  Ada.Strings.Fixed;
   !.
   !. with RFC_Embedding.Errors;
   !. use RFC_Embedding.Errors;
   !.
   !. package body RFC_Embedding.Syntax.Escaping is
   !.
   !.    ------------
   !.    -- Escape --
   !.    ------------
   !.
   !.    function Escape (X        : String;
   !.                     Breakers : Breaker_Array) return String is
   !.       use Ada.Strings.Unbounded;
   !.
   !.       function To_Hex (C : Character) return String is
   !.          Hex : constant String := "0123456789abcdef";
   !.          N   : constant Integer := Character'Pos (C);
   !.       begin
   !.          return Hex ((N / 16)+1) & Hex ((N mod 16)+1);
   !.       end To_Hex;
   !.
   !.       procedure Break_After (Pattern : String;
   !.                              Item    : in out Unbounded_String)
   !.       is



Riccardo                Expires January 13, 2014               [Page 40]

Internet-Draft               Embedding Code                    July 2013


   !.          Tmp    : String := To_String (Item);
   !.          Cursor : Natural;
   !.          Next   : Natural;
   !.       begin
   !.          Item := Null_Unbounded_String;
   !.
   !.          Cursor := 1;
   !.
   !.          loop
   !.             Next := Index (Source  => Tmp,
   !.                            Pattern => Pattern,
   !.                            From    => Cursor);
   !.
   !,             exit when Next = 0 or Next = Tmp'Last - Pattern'Leng
   !. th - 1;
   !.
   !.             Item := Item & Tmp (Cursor .. Next + 1) & "%%.";
   !.             Cursor := Next + Pattern'Length;
   !.          end loop;
   !.
   !.          Item := Item & Tmp (Cursor .. Tmp'Last);
   !.       end Break_After;
   !.
   !.       Result : Unbounded_String;
   !.    begin
   !.       for I in X'Range loop
   !.          case X (I) is
   !.             when ' ' .. '$' | '&' .. '~' =>
   !.                Result := Result & X (I);
   !.
   !.             when '%%' =>
   !.                Result := Result & "%%%%";
   !.
   !.                --              when '>' =>
   !.                --                 Result := Result & "%%>";
   !.
   !.
   !.             when others =>
   !.                Result := Result & '%%' & To_Hex (X (I));
   !.          end case;
   !.       end loop;
   !.
   !.       for I in Breakers'Range loop
   !.          Break_After (To_String (Breakers (I)), Result);
   !.       end loop;
   !.
   !.       return To_String (Result);
   !.    end Escape;



Riccardo                Expires January 13, 2014               [Page 41]

Internet-Draft               Embedding Code                    July 2013


   !.
   !.    function Escape (X        : String;
   !.                     Breaker  : String) return String is
   !.       B : constant Breaker_Array (1 .. 1) :=
   !.             (1 => To_Unbounded_String (Breaker));
   !.    begin
   !.       return Escape (X, B);
   !.    end Escape;
   !.
   !.    function Escape (X : String) return String is
   !.       B : Breaker_Array (1 .. 0);
   !.    begin
   !.       return Escape (X, B);
   !.    end Escape;
   !.
   !.    --------------
   !.    -- Unescape --
   !.    --------------
   !.
   !.    function Unescape (X : String) return String
   !.    is
   !.       function To_Char (X : String) return Character;
   !.       pragma Precondition (X'Length = 2);
   !.
   !.       function To_Char (X : String) return Character is
   !.          use Ada.Characters.Handling;
   !.       begin
   !.          if (not Is_Hexadecimal_Digit (X (X'First)))
   !,             or (not Is_Hexadecimal_Digit (X (X'First + 1))) then
   !.
   !.             raise Program_Error;
   !.          end if;
   !.
   !,          return Character'Val (Integer'Value ("16#" & X & "#"));
   !.
   !.       end To_Char;
   !.
   !.       Result : Unbounded_String;
   !.       Cursor : Natural := X'First;
   !.    begin
   !.
   !.       loop
   !.          exit when Cursor > X'Last;
   !.
   !.          if X (Cursor) /= '%%' then
   !.             Result := Result & X (Cursor);
   !.             Cursor := Cursor + 1;
   !.



Riccardo                Expires January 13, 2014               [Page 42]

Internet-Draft               Embedding Code                    July 2013


   !.          else
   !.             Cursor := Cursor + 1;
   !.
   !.             if Cursor > X'Last then
   !.                Die ("Lone '%%' at end of line");
   !.             end if;
   !.
   !.             if X (Cursor) = '%%' then
   !.                Result := Result & X (Cursor);
   !.                Cursor := Cursor + 1;
   !.
   !.             elsif X (Cursor) = '.' then
   !.                Cursor := Cursor + 1;
   !.
   !.             else
   !.                if Cursor > X'Last - 1 then
   !.                   Die ("Wrong '%%' escape sequence");
   !.                end if;
   !.
   !,                Result := Result & To_Char (X (Cursor .. Cursor +
   !.  1));
   !.
   !.                Cursor := Cursor + 2;
   !.             end if;
   !.          end if;
   !.       end loop;
   !.
   !.       return To_String (Result);
   !.    end Unescape;
   !.
   !.
   !. end RFC_Embedding.Syntax.Escaping;
   !--((END))--


   !--((BGN))--Gada F"rfc_embedding-syntax-escaping.ads"
   !. with Ada.Strings.Unbounded;
   !. use Ada.Strings.Unbounded;
   !.
   !. package RFC_Embedding.Syntax.Escaping is
   !.    type Breaker_Array is
   !.       array (Positive range <>) of Unbounded_String;
   !.
   !.    function Escape (X        : String;
   !.                     Breakers : Breaker_Array) return String;
   !,    --  Replace non-printable characters and '%%' with the corres
   !. ponding
   !,    --  escape sequence.  After the replacement, if some entry of



Riccardo                Expires January 13, 2014               [Page 43]

Internet-Draft               Embedding Code                    July 2013


   !.  Breakers
   !,1   --  is present but not at the end of the escaped string, add
   !. after
   !,    --  them the "null escape" sequence "%%.".  This is useful to
   !.  break
   !,    --  specific character sequences that could me taken for "con
   !. trol"
   !,1   --  sequences in some context.  For example, when escaping a
   !. string
   !,    --  for XML embedding, one could want to have "]]%." in Break
   !. ers, so that
   !,    --  by chance, the sequence "]]%.>" (that marks the end of CD
   !. ATA in XML)
   !,    --  is in the input string, then it is converted to "]]%.%%.>
   !. ".
   !.
   !.    function Escape (X        : String;
   !.                     Breaker  : String) return String;
   !,    --  Equivalent to calling the function above with a one-eleme
   !. nt array
   !,1   --  Example: use Escape(X, "]]%.") to apply the XML escaping
   !. explained
   !.    --  above.
   !.
   !.    function Escape (X : String) return String;
   !.    --  Equivalent to calling Escape with an empty array
   !.
   !.    function Unescape (X : String) return String;
   !.    --  Remove the escaping in X
   !. end RFC_Embedding.Syntax.Escaping;
   !--((END))--


   !--((BGN))--Gada F"rfc_embedding-syntax-escaping-test.adb"
   !. with Ada.Text_IO; use Ada.Text_IO;
   !.
   !. procedure RFC_Embedding.Syntax.Escaping.Test is
   !.    Source    : String :=
   !.                  "prova%%15"
   !.                  & Character'Val (5)
   !.                  & Character'Val (7)
   !.                  & "%%%%%%afgigi";
   !.    Escaped   : String := Escape (Source);
   !.    Unescaped : String := Unescape (Escaped);
   !. begin
   !.    Put_Line (Escaped);
   !.
   !.    if Unescaped = Source then



Riccardo                Expires January 13, 2014               [Page 44]

Internet-Draft               Embedding Code                    July 2013


   !.       Put_Line ("OK");
   !.    else
   !.       Put_Line ("BAD");
   !.    end if;
   !. end RFC_Embedding.Syntax.Escaping.Test;
   !--((END))--


   !--((BGN))--Gada F"rfc_embedding-syntax-path_syntax.adb"
   !. with Ada.Strings.Maps;        use Ada.Strings.Maps;
   !. with Ada.Strings.Fixed;       use Ada, Ada.Strings;
   !. with Ada.Directories;
   !. with Ada.Text_IO;             use Ada.Text_IO;
   !.
   !. with RFC_Embedding.Errors;    use RFC_Embedding.Errors;
   !.
   !.
   !.
   !. package body RFC_Embedding.Syntax.Path_Syntax is
   !.
   !.    Embedder_Separator : constant Character := '/';
   !.
   !.    ---------------------
   !.    -- To_Local_Syntax --
   !.    ---------------------
   !.
   !.    procedure To_Local_Syntax
   !.       (Source    : String;
   !.        Path      : out Unbounded_String;
   !.        Filename  : out Unbounded_String)
   !.    is
   !,       function Find_Last_Separator (X : String) return Natural i
   !. s
   !.       begin
   !.          return Fixed.Index (Source  => X,
   !,                              Pattern => Embedder_Separator & "",
   !.
   !.                              From    => X'Last,
   !.                              Going   => Backward);
   !.       end Find_Last_Separator;
   !.
   !.       function To_Local_Path (Path : String) return String;
   !.       pragma Precondition
   !.          (Path (Path'First) /= Embedder_Separator and
   !.              Path (Path'Last) /= Embedder_Separator);
   !.
   !.       function To_Local_Path (Path : String) return String is
   !,          --  Converte a "pure path" (i.e., without filename to t



Riccardo                Expires January 13, 2014               [Page 45]

Internet-Draft               Embedding Code                    July 2013


   !. he end
   !.          --  to the local syntax.
   !.
   !.          Split_Point : Natural := Find_Last_Separator (Path);
   !.       begin
   !.          if Split_Point = 0 then
   !.             return Path;
   !.          else
   !,             pragma Assert (Split_Point > Path'First and Split_Po
   !. int < Path'Last);
   !.
   !.             --  Yes, we are recursive.
   !.             return Directories.Compose
   !,                (Containing_Directory => To_Local_Path (Path (Pat
   !. h'First .. Split_Point - 1)),
   !,                 Name                 => Path (Split_Point + 1 ..
   !.  Path'Last));
   !.          end if;
   !.       end To_Local_Path;
   !.
   !.       Split_Point : Natural;
   !.    begin
   !.       if Source (Source'First) = Embedder_Separator then
   !.          declare
   !.             Idx : Natural := Fixed.Index (Source => Source,
   !,1                                          Set    => Maps.To_Set
   !. (Embedder_Separator),
   !,                                           Test   => Strings.Outs
   !. ide);
   !.          begin
   !.             if Idx = 0 then
   !.                Die ("Root dir not allowed");
   !.             else
   !,                Warning ("Absolute path (" & Source & ") found. I
   !. nitial '/' ignored");
   !.
   !,                To_Local_Syntax (Source (Idx .. Source'Last), Pat
   !. h, Filename);
   !.                return;
   !.             end if;
   !.          end;
   !.       end if;
   !.
   !,       pragma Assert (Source (Source'First) /= Embedder_Separator
   !. );
   !.
   !.       Split_Point := Find_Last_Separator (Source);
   !.



Riccardo                Expires January 13, 2014               [Page 46]

Internet-Draft               Embedding Code                    July 2013


   !.       pragma Assert (Split_Point /= Source'First);
   !.
   !.       if Split_Point = 0 then
   !.          --  No path separator found: we have a pure filename
   !.          Filename := To_Unbounded_String (Source);
   !.          Path := Null_Unbounded_String;
   !.          return;
   !.       end if;
   !.
   !.
   !.       if Split_Point = Source'Last then
   !.          Die ("Pure directories not allowed");
   !.       end if;
   !.
   !,1      pragma Assert (Split_Point > Source'First and Split_Point
   !. < Source'Last);
   !.
   !,       Path := To_Unbounded_String (To_Local_Path (Source (Source
   !. 'First .. Split_Point - 1)));
   !.
   !,       Filename := To_Unbounded_String (Source (Split_Point + 1 .
   !. . Source'Last));
   !.    end To_Local_Syntax;
   !.
   !.
   !.    ------------------------
   !.    -- To_Embedded_Syntax --
   !.    ------------------------
   !.
   !.    function To_Embedded_Syntax
   !.       (Filename : String)
   !.        return String
   !.    is
   !.       use Ada.Directories;
   !.
   !.       function Is_Full_Name (X : String) return Boolean is
   !.       begin
   !.          return X = Full_Name (X);
   !.       end Is_Full_Name;
   !.
   !.       function Is_Simple_Name (X : String) return Boolean is
   !.       begin
   !.          return X = Simple_Name (X);
   !.       end Is_Simple_Name;
   !.
   !.       procedure Check_Part (X : String) is
   !.          use Ada.Strings.Fixed;
   !.       begin



Riccardo                Expires January 13, 2014               [Page 47]

Internet-Draft               Embedding Code                    July 2013


   !,          if Index (Source  => X, Pattern => Embedder_Separator &
   !.  "") /= 0 then
   !,             Die ("Filenames cannot contain '" & Embedder_Separat
   !. or & "'");
   !.          end if;
   !.       end Check_Part;
   !.    begin
   !.       if Is_Full_Name (Filename) then
   !.          Die ("Filename '" & Filename & "' is absolute");
   !.       end if;
   !.
   !.       if Is_Simple_Name (Filename) then
   !.          Check_Part (Filename);
   !.          return Filename;
   !.       else
   !.          declare
   !,             Dir    : constant String := Containing_Directory (Fi
   !. lename);
   !.             Simple : constant String := Simple_Name (Filename);
   !.          begin
   !.             Check_Part (Simple);
   !.
   !.             return To_Embedded_Syntax (Dir)
   !.                & Embedder_Separator
   !.                & Simple;
   !.          end;
   !.       end if;
   !.    end To_Embedded_Syntax;
   !.
   !. end RFC_Embedding.Syntax.Path_Syntax;
   !--((END))--


   !--((BGN))--Gada F"rfc_embedding-syntax-path_syntax.ads"
   !.
   !. --
   !, --  In the embedded format the file path is stored in a format i
   !. ndependent
   !, --  on the source/target system.  The embedded syntax is just Un
   !. ix-like:
   !, --  directories in the path are separated by '/' and absolute pa
   !. th names
   !,1--  are not allowed.  This package provides two procedures that
   !. map
   !, --  back and forth from the local syntax to the embedding syntax
   !. .
   !. --
   !.



Riccardo                Expires January 13, 2014               [Page 48]

Internet-Draft               Embedding Code                    July 2013


   !. package RFC_Embedding.Syntax.Path_Syntax is
   !.    procedure To_Local_Syntax
   !.      (Source    : String;
   !.       Path      : out Unbounded_String;
   !.       Filename  : out Unbounded_String);
   !,    --  Parse Source as an embedded filename and return the "path
   !. " part
   !,    --  and the "filename" part.  If the embedded filename is "si
   !. mple" (i.e.,
   !.    --  it has no '/'), Path is the empty string.
   !.
   !.    function To_Embedded_Syntax
   !.       (Filename : String)
   !.        return String;
   !,    --  Parse the full path in the local syntax and return the co
   !. rresponding
   !.    --  path in the embedding syntax.
   !. end RFC_Embedding.Syntax.Path_Syntax;
   !--((END))--


   !--((BGN))--Gada F"rfc_embedding-syntax-path_syntax-test.adb"
   !. with Ada.Strings.Unbounded;
   !. use  Ada.Strings.Unbounded;
   !.
   !. with Ada.Directories;
   !. use Ada.Directories;
   !.
   !. with Ada.Text_IO;
   !. use Ada.Text_IO;
   !.
   !. procedure RFC_Embedding.Syntax.Path_Syntax.Test is
   !.    Name : constant String := "pippo.c";
   !.    Source : String := Current_Directory;
   !.    Embedded : String := To_Embedded_Syntax
   !,       (Compose (Containing_Directory => Source (2 .. Source'Last
   !. ),
   !.                 Name                 => Name));
   !.
   !.    Path     : Unbounded_String;
   !.    Filename : Unbounded_String;
   !. begin
   !.    To_Local_Syntax (Source   => Embedded,
   !.                     Path     => Path,
   !.                     Filename => Filename);
   !.
   !.    Put_Line ("Source    = '" & Source & "'");
   !.    Put_Line ("Embedded  = '" & Embedded & "'");



Riccardo                Expires January 13, 2014               [Page 49]

Internet-Draft               Embedding Code                    July 2013


   !.    Put_Line ("Path      = '" & To_String (Path) & "'");
   !.    Put_Line ("File      = '" & To_String (Filename) & "'");
   !.
   !,    if Source (2 .. Source'Last) = To_String (Path) and Name = To
   !. _String (Filename) then
   !.       Put_Line ("OK");
   !.    else
   !.       Put_Line ("BAD");
   !.    end if;
   !. end RFC_Embedding.Syntax.Path_Syntax.Test;
   !--((END))--


   !--((BGN))--Gada F"README"
   !. ===================
   !. == What is this? ==
   !. ===================
   !.
   !. This is the source code of the embedder/extractor.
   !.
   !. ======================
   !. == How do I use it? ==
   !. ======================
   !.
   !.2You need an Ada compiler, for example, the GNAT compiler.
   !.
   !. The main files are
   !.
   !.   * rfc_embedding-embedder.adb
   !.   * rfc_embedding-extractor.adb
   !.
   !,1If you have the GNAT compiler, you can compile everything using
   !. the
   !. provided project file.
   !--((END))--


   !--((BGN))--Gada F"extractor.gpr"
   !. project Extractor is
   !.
   !,    for Main use ("rfc_embedding-embedder.adb", "rfc_embedding-ex
   !, tractor.adb", "rfc_embedding-syntax-escaping-test.adb", "rfc_emb
   !. edding-syntax-path_syntax-test.adb");
   !.    for Object_Dir use "bin/";
   !.
   !.    package Compiler is
   !,       for Default_Switches ("ada") use ("-gnato", "-fstack-check
   !. ", "-gnata", "-gnat05");



Riccardo                Expires January 13, 2014               [Page 50]

Internet-Draft               Embedding Code                    July 2013


   !.    end Compiler;
   !.
   !. end Extractor;
   !--((END))--



Author's Address

   Riccardo Bernardini (editor)
   University of Udine
   Via delle Scienze, 208
   Udine  33100
   Italy

   Phone: +39 0432 55 8271
   Email: riccardo.bernardini@uniud.it


































Riccardo                Expires January 13, 2014               [Page 51]