





_1.  _O_v_e_r_v_i_e_w _o_f _p_e_p_s_y _s_y_s_t_e_m

     This  section  describes  how  the  various  parts  fit
together  to  make  the  system  work.  The principle behind
pepsy is fairly simple.  The ASN.1 is summarised  as  tables
of integers.  These tables are read by driver routines which
encode or decode data to or from the  internal  format  that
ISODE  OSI implementation uses.  In ISODE specific functions
are generated for each ASN.1 type defined  in  contrast  the
pepsy  merely generates a new table of data which is far far
smaller.

     As there is a great deal  of  effort  invested  in  the
ISODE  interface  to  the  encoding/decoding  routines pepsy
automatically provides macros which map the  original  func-
tions  into the appropriate function call of a driver.  This
allows existing posy using code to switch to the pepsy  sys-
tem  with  no  changes  to  the  code  provided  no function
pointers are used to the  original  ISODE  functions.   Even
when  there  are function pointers used the changes are very
simple and take only a few hours to implement.

_1._1.  _B_r_i_e_f _d_e_s_c_r_i_p_t_i_o_n _o_f _t_h_e _u_s_e _o_f _t_h_e _p_e_p_s_y _s_y_s_t_e_m.

_1._1._1.  _O_u_t_l_i_n_e _o_f _t_h_e _f_i_l_e_s _p_r_o_d_u_c_e_d _u_n_d_e_r _t_h_e  _p_e_p_s_y  _s_y_s_-
_t_e_m.

     The pepsy system consists  of  a  program  called  _p_o_s_y
which  translates ASN.1 modules into a set of tables, called
_p_o_s_y at the moment, and library of driver  routines,  called
_l_i_b_p_e_p_s_y._a.   Running  this  _p_o_s_y  program on the ASN.1 file
will produce several files.  If the name of the ASN.1 module
is MODULE the following files are generated:

MODULE-types.h
     which contains C structure definitions.   The  user  of
     the  library  provides data as a linked list of these C
     data structures and expects to receive data back  as  a
     similar linked list.  These data structures are exactly
     the same as those produced by the original  ISODE  _p_o_s_y
     so that existing software written for the old _p_o_s_y pro-
     gram needs no change.  For details on the C data struc-
     tures types generated see the documentation of the ori-
     ginal _p_o_s_y program in volume 4 Chapter 5 of  the  ISODE
     manuals.

MODULE_tables.c
     This file contains the tables generated by the new _p_o_s_y
     program.   These  tables  consist  of  three parts, the
     first which contains the summary of ASN.1 types.   Each
     type  is  summarised  as  an array of a primitive type,
     struct pte, for encoding and decoding, and struct  ptpe
     for  printing.   As implied there is one array for each
     type for each of encoding,  decoding  and  printing  as



                      January 23, 1990





                           - 2 -


     specified  when _p_o_s_y is run.  The next part contains up
     to three tables of pointers to these arrays.   Each  of
     the three different types of arrays, encoding, decoding
     and printing, has its own table of  pointers.   Finally
     there is the module type definition which contains con-
     tains pointers to these tables and  some  other  useful
     information  about  the  module such as its name.  This
     module type structure, which is typedefed to modtyp, is
     the only piece of data which is global, all the rest of
     the data is static and is only addressable via the mod-
     typ  data  structure.  This  provides  a kind of object
     oriented approach to handling the tables.  Once you are
     passed a pointer to an ASN.1's modtyp structure you can
     encode, decode and print any of its  types  by  calling
     the   appropriate  libpepsy.a  routine  with  its  type
     number.

MODULE_pre_defs.h
     This file contains #defines symbol of each of the ASN.1
     types  to its type number, which is used when calling a
     libpepsy.a routine.  Each symbol  is  _Ztype-nameMODULE
     where _t_y_p_e-_n_a_m_e is the name of the type with dashes (-)
     turned into underscores (_) and _M_O_D_U_L_E is the  name  of
     the  module.   For  example of the ASN.1 universal type
     _G_r_a_p_h_i_c_S_t_r_i_n_g would  have  the  #define  symbol  _ZGra-
     phicStringUNIV.  The __Z is prepended to try to make the
     symbols unique.  This file  also  contains  and  extern
     declaration for the modtyp data for its module.

MODULE_defs.h
     This file contains macros for  all the encoding, decod-
     ing  and printing functions that the _p_e_p_y program would
     have for these ASN.1 types.  This allows  much  of  the
     code  that  uses  the routines generated by running the
     old _p_o_s_y program and taking its output and running _p_e_p_y
     on  augmented ASN.1 output can be recompiled unchanged.
     If the code used pointers  to  these  functions  it  is
     necessary  to change it to pass around the type numbers
     instead and to call  appropriately  call  a  libpepsy.a
     library  routine  with the type number.  As pointers to
     the printing routines in ISODE are passed as  arguments
     a  #define  is  provided  to turn the argument into the
     pair of arguments, type number and  pointer  to  modtyp
     structure,  which  are  needed  to allow the diagnostic
     printing code to work with no change  for  the  current
     ISODE stack.  This file also contains a #include of the
     _M_O_D_U_L_E__p_r_e__d_e_f_s._h file.

     As the _M_O_D_U_L_E-_t_y_p_e_s._h file #include's the _M_O_D_U_L_E__d_e_f_s._h
file  no  further  #includes  need  to be added to the files
using the encoding/decoding/printing functions.  This  means
that code written to use posy/pepy system may need no change
at all and  the  only  effort  required  is  to  change  the
Makefile  to use the pepsy system.  If there is code changes



                      January 23, 1990





                           - 3 -


required it would most likely be because  function  pointers
are  used  to reference the functions generated by posy.  If
only the _p_e_p_y system was used, not posy then pepy, with code
placed inside action statements then quite a large amount of
work may be needed to change over to the new system, depend-
ing on how large and complex the _p_e_p_y module is.

_1._1._2.  _O_u_t_l_i_n_e _o_f _t_h_e _p_e_p_s_y _l_i_b_r_a_r_y.

enc.cThis contains the routines that encode data from the  C
     data  structures into ISODE's PElement linked list data
     structure which it uses for all presentation data.  The
     most  important  function to pepsy users is enc_f which
     called to encode a particular type.  It is  passed  the
     type  number and a pointer to modtyp structure for that
     module and then the rest of  the  arguments  which  are
     passed  to  an  encode  function generated by _p_o_s_y/_p_e_p_y
     system.  See the documentation in Volume 4, "The Appli-
     cations  Cookbook",  Section  6.4 called "Pepy Environ-
     ment".  Most of these  latter  arguments  are  ignored,
     only parm and pe, are used.

     Contrary to what the  ISODE  documentation  says  these
ignored  parameters  are  hardly ever used by existing code.
We have not found a single case where used  for  encoding  a
named type, which is all that the user can reference anyway,
so we don't see  any  problems  with  ignoring  these  other
parameters.   Hopefully  one  day  they  can  be thrown away
entirely, until then they are actually passed the the encod-
ing function.

     The rest of the functions are mostly recursive routines
which  encode a particular type of table entry.  For example
SEQUENCE is encoded by en_seq which may call itself or  oth-
ers  to  encode  the  types  from which it is built up.  The
function en_type builds up a simple type and en_obj  encodes
a  new  type (object) and so on with other functions.  There
are a few utility routines in the file such  as  same  which
determines  whether  the  value  is  the same as the default
value also.

dec.cThis file contains the decoding routines that translate
     presentation data into C data structures defined in the
     MODULE-types.h is like _e_n_c._c.  It is very much like the
     file _e_n_c._c except the routines do the reverse tasks The
     routines are structured in a very similar way.  We have
     dec_f  which is called by the user to decode a type and
     like enc_f takes the same  arguments  as  the  decoding
     functions  generated  by  _p_o_s_y  with two additions, the
     type number and a pointer to the modtyp  structure  for
     that  module.   Likewise  the  other functions are very
     much like those of enc.c

prnt.cThis  file  contains  the  routines  that  print   the



                      January 23, 1990





                           - 4 -


     presentation data in a format similar to that generated
     by  _p_e_p_y's  printing  functions.   It's  main  function
     prnt_f  is  takes  the  same  arguments as the printing
     function generated by _p_e_p_y as well as the now  familiar
     type  number  and  modtyp  pointer.   The functions are
     modeled on the decoding routines as it has similar  job
     to.  The only difference is that instead of storing the
     decoded data into a  C  data  structure  it  is  nicely
     printed out.

fr.c This file contains code to  free  the  data  structures
     defined  in MODULE-types.h.  Likewise if the -f flag is
     given when generating the types file it  also  includes
     macros  in  the  types  file  which replace the freeing
     functions generated by ISODE's _p_o_s_y.  The function that
     the  user calls us fre_obj which takes a pointer to the
     data structure, its decoding table entry and a  pointer
     to  the modtyp structure for the module. The freeing is
     based on the decoding routines except instead of decod-
     ing  all  it  does is free each part of the data struc-
     ture, which might  involve  recursive  calls,  then  it
     frees the data structure at the end.

util.cThis contains the utility routines used by  more  than
     one of the above files.  This is mostly diagnostic rou-
     tines at the moment, more  general  routines  could  be
     included  in  here.  If there is an error at the moment
     which it can't recover from it just prints out  a  mes-
     sage on standard error and calls exit.  Not perfect and
     this is something that will need work.

main.cThis contains code to perform a series of tests on the
     _p_e_p_s_y  library  which  is a useful check to see whether
     any of the routines has  been  broken  by  any  changes
     made.   It  basically  loops  through a whole series of
     test cases.  Each test case is encoded from some  built
     in test data and then decoded and checked to see if the
     data has changed in the transfer.  If  it  is  compiled
     with  -_D_P_R_N_T=_1  the encoded data is also printed out to
     check the printing  routines  which  generates  a  vast
     amount  of  output.  Finally the free routines are used
     to  free  the  allocated  data,  although  it  can  not
     directly  check  the free routines to see if they work,
     it can be used with a malloc tracing package  to  check
     that the routines work.

test_table.h
     This contains the test cases that _m_a_i_n._c program  runs.
     Each  entry in the table corresponds to a type.  One of
     the fields is count of how many times that type  is  to
     be tested to try out the different possibly data values
     it might have.

pep.h and pepdefs.h



                      January 23, 1990





                           - 5 -


     These files contain the definition of  types  used  for
     the  tables  that  drive the encoding/decoding/printing
     routines.  All the constants used  in  that  table  are
     defined  here  via  #defines.   The modtyp structure is
     defined in _p_e_p_d_e_f_s._h.

t1.py and t2.py
     These are test ASN.1 modules that are  used  by  _m_a_i_n._c
     routines  to  check  the _p_e_p_s_y library.  The file _t_1._p_y
     contains the majority of different types with a few  of
     a  different module provided in _t_2._p_y.  This allows the
     testing of the code for handling ASN.1 external  refer-
     ences,  i.e.  references  to  types  defined  in other,
     external, modules.

_1._1._3.  _N_e_w _f_i_l_e_s _i_n _t_h_e _p_e_p_y _d_i_r_e_c_t_o_r_y

etabs.c, dtabs.c and ptabs.c
     These  files  contain  the   code   to   generate   the
     encoding/decoding/printing tables.  The main routine in
     _e_t_a_b_s._c is tenc_typ which is called on each ASN.1  type
     to  generate  an array of entries which describe how to
     encode that type.  See the  details  section  for  more
     information  about  how  the  table  entries  function.
     Similarly _d_t_a_b_s._c contains the routine  tdec_typ  which
     is  called  on each type to generate its decoding table
     entries.   Likewise  tprnt_typ  routine  generates  the
     arrays  of table entries for the printing tables.  This
     function is in _p_t_a_b_s._c.

dfns.cThis file contains miscellaneous string handling  rou-
     tines  and hash table routines that don't really belong
     anywhere else.  Some of the routines could  be  cleaned
     up in that they tend not to free memory they use.

mine.hThis  file  contains  the  definitions  for  the  hash
     table(s)  that  are  used  to  keep  track of the ASN.1
     types.  This could probably be done  with  out  a  hash
     table,  should  anyone want to clean this up, feel wel-
     come.  The lookup function is in _d_f_n_s._c.

pass2.h
     This file has most of the #defines for the  table  gen-
     erating  program.  Most of the prefixes and suffixes of
     function names and files names  are  defined  here  so,
     hopefully,  the names can be changed by merely changing
     the definition.  This contains most  of  the  important
     definitions  needed  by the changes to the _p_o_s_y program
     needed to generate tables.

posy.hThis contains the definition of a symbol which is  now
     needed  outside  of  the  the main routine and the yacc
     file.  By putting it here we can include  it  any  file
     that  needs  to  know  it  with out putting in any that



                      January 23, 1990





                           - 6 -


     doesn't need it and with out including  all  the  other
     definitions  that  occur  in _p_e_p_y._h.  The structure and
     meaning of the tables generated from the ASN.1 grammar

     Each collection of ASN.1 grammar is  called  a  module.
(See  ASN.1  )  Each ASN.1 module is completely specified in
the program by a single C structure of type modtyp  and  the
data  which  it  references.   See the _p_e_p_d_e_f_s._h file in the
_p_e_p_s_y directory.  For each  ASN.1  module  there  are  three
tables that are generated fromASN.1 grammar.  These initial-
ised arrays which we call tables are  called  the  encoding,
decoding  and  printing  tables.   Each  of  these tables is
referenced through a different pointer of the modtyp  struc-
ture.

     Each of these pointers references an array of pointers,
one  pointer for each ASN.1 type defined in the module.  The
position of one of these pointers is the unique type  number
we  give  to its corresponding type.  The pointer references
an array of type tpe or ptpe, depending  whether  it  is  an
entry  in  the  decoding/encoding  tables or printing tables
respectively.  See _p_e_p._h in the _p_e_p_s_y directory.  This array
actually    contains    the    necessary    information   to
encode/decode/print that ASN.1 type.  So  given  the  modtyp
structure  of  an  ASN.1  module and its type number you can
call a routine to encode, decode or print that type.

     The rest of this document assumes a good  knowledge  of
ASN.1  notation  so  go  read a copy if you haven't already.
From here on I shall mention only tpe and this means tpe  in
the  case  of  encoding  or decoding and ptpe in the case of
printing, unless otherwise stated.  Each type is represented
by  an  array of tpe (or ptpe for printing).  The basic ele-
ment consists of four integer fields, the printing table  is
the  same with an addition char pointer field which contains
the name corresponding to that entry in the  ASN.1  grammar.
The first specifies the type of the entry and determines how
the rest are interpreted.  The possible types are listed  in
_p_e_p_s_y/_p_e_p._h.   Each  type  is  an array which starts with an
entry of type PE_START and ends with  one  of  type  PE_END.
Each  primitive type requires one entry to specify it, apart
from possible PE_START and PE_END used to specify the  start
and end of the type.  Constructed types are represented by a
list of entries terminated by an entry of type  PE_END.   As
ASN.1  types can be nested inside so will the representation
in tpe entries be nested.  For example the ASN.1 type defin-
ition:
           Example1 ::=
                   SEQUENCE {
                       seq1 SEQUENCE {
                                an-i INTEGER,
                                an-ostring OCTET STRING
                            },
                       a-bool IMPLICIT [0] BOOLEAN



                      January 23, 1990





                           - 7 -


                   }
              Will generate an encoding array:
static tpe et_Example1Test[] = {
        { PE_START, 0, 0, 0 },
        { SEQ_START, 0, 16, FL_UNIVERSAL },
        { SEQ_START, OFFSET(struct type_Test_Example1, seq1), 16, FL_UNIVERSAL },
        { INTEGER, OFFSET(struct element_Test_0, an__i), 2, FL_UNIVERSAL },
        { OCTETSTRING, OFFSET(struct element_Test_0, an__ostring), 4, FL_UNIVERSAL },
        { PE_END, 0, 0, 0 },
        { BOOLEAN, OFFSET(struct type_Test_Example1, a__bool), 0, FL_CONTEXT },
        { PE_END, 0, 0, 0 },
        { PE_END, 0, 0, 0 }
        };


     Here the second last PE_END matches and closes off  the
first  SEQ_START.  The entries which correspond to the other
primative types are pretty obvious, with the  INTEGER  entry
corresponding  to  the  primative  INTEGER.  For fields that
generate data the general interpretation of the other  three
fields is offset, tag and flags/class fields respectively.

offsetThe second field gives the offset in a C  data  struc-
     ture  needed  to reference the data that corresponds to
     this table entry.  Each  ASN.1  type  has  C  structure
     types  generated  as  described  in  the ISODE manuals,
     volume 4 "The applications Cookbook" Section 5.2, "POSY
     Environment".  As this offset may have to be determined
     in a compiler dependent manner a C  preprocessor  macro
     is used hide the actual details.

tag  This is the tag associated with the ASN.1 type for that
     entry.   Notice  that  in  the example the [0] IMPLICIT
     which changes the tag associated with the BOOLEAN entry
     actually  has the correct tag of 0 in the table.  Like-
     wise  SEQUENCE  has  the  correct  tag  of  16  in  its
     SEQ_START entry and so on for the others.

flags/class
     This contains  the  ASN.1  class  associated  with  the
     entry's  type.   That  is  UNIVERSAL for all except the
     BOOLEAN type which is CONTEXT class.  This  fourth  can
     also contain flags that specify if the type is OPTIONAL
     or DEFAULT.  There is plenty of room here as  there  is
     only four possibly classes.

     Now that you have some idea of  how  these  arrays  are
arranged  for a type definition I will proceed to go through
the possible type of entries and describe what they  do  and
how  they  work.   These  values are defined in _p_e_p_s_y/_p_e_p._h.
Those entries with a value below TYPE_DATA are entries  that
don't  correspond  to data to be encoded/decoded and are for
other book keeping type purposes.




                      January 23, 1990





                           - 8 -


PE_START and PE_END
     As explained above PE_START starts the beginning  of  a
     ASN.1  type's  array.   It probably isn't necessary but
     the size of the tables is so small it isn't much of  an
     over  head  to  keep  around for cosmetic reasons.  The
     entry type PE_END is necessary to mark the end of  some
     compound type as well as the end of ASN.1 data type.

XOBJECT and UCODE
     These  are  obsolete  types  and  probably  should   be
     removed.  They were to allow C code written directly by
     the user to be incorporated into the  encoding/decoding
     but  it was found unnecessary.  Prehaps some brave soul
     would like to use them in an  attempt  to  implement  a
     similar  system  based  on  _p_e_p_y which is what we first
     attempted to do until we found this to be much easier.

MALLOCThis field only occurs in  the  decoding  tables.   It
     specifies  how much space to malloc out for the current
     C structure it is just inside of.  For instance in  the
     example  above  the  decoding  table  has the following
     entry:

      { MALLOC, 0, sizeof (struct type_Test_Example1), 0 },

     just after the first SEQ_START entry.  It tells  it  to
     malloc  out  a  struct  type_Test_Example1 structure to
     hold the data from the sequence when it is decoded.

SCTRLThis entry is used in handling the ASN.1  CHOICE  type.
     The  C type generated for ASN.1 CHOICE type is a struc-
     ture with an offset field in it and a union of all  the
     C  types present in the CHOICE.  Each ASN.1 type in the
     CHOICE of types has a C type definition  generated  for
     it.   The union is of all these types, which is quite a
     logical way to implement a  CHOICE  type.   The  offset
     field  specifies  which possibility of interpreting the
     union should be used (which  _m_e_m_b_e_r  should  selected).
     As  such  it  needs to be read by the encoding routines
     when encoding the data from the C data  structures  and
     to  be set by the decoding routines when it is decoding
     the data into the C data structures.  There is one such
     entry  for each CHOICE type to specify where the offset
     field is.

CH_ACTAnother redundant entry type.  I think this  was  also
     used  in  code to handle C statements or actions speci-
     fied by the user.  It probably should be removed.

OPTL This is used to handle the optionals field that is gen-
     erated  by posy when optional types that are _n_o_t imple-
     mented by pointers are present in the ASN.1 type.   For
     example  if an ASN.1 type has an optional integer field
     how does the encoding routine determine if the  integer



                      January 23, 1990





                           - 9 -


     is  to  be  present or not?  If it was implemented as a
     pointer it could use a NULL (zero) pointer to mean that
     the  type was not present because NULL is guaranteed to
     never occur as a legal pointer to a real  object.   But
     all  the  possible  values for integer could be legally
     passed  so  instead  for  these  types  which  are  not
     pointers and are optional a bit map is allocated in the
     structure.  Each non pointer optional type a  bit  from
     the bit map is allocated.

     If that bit is set the corresponding  type  is  present
and it is not present if the bit is not set.  Each bit has a
#define generated for it.  The bit map is merely an  integer
field  called  "optionals"  limiting  maximum number of such
optionals to 32 on Sun machines, 16  on  some  others.   (An
array  of char as BSD fd_sets would have avoid all such lim-
its, not that this limit is expected  to  be  exceeded  very
often  !)  Like  the SCTRL entry this entry merely serves to
specify where this field is so it can be test and set by the
encoding and decoding routines respectively.

ANY and CONS_ANY
     The C type corresponding to the entry is a PE  pointer.
     To  conform  with  _p_e_p_y the tag and class of this entry
     are ignored, which may or may not be the most  sensible
     thing.   The CONS_ANY is a redundant symbol which means
     the same thing but is not used.  This should  be  clean
     up and removed.

INTEGER, BOOLEAN, BITSTRING, OCTETSTRING and OBJID
     These are just as described in the first article.   See
     the ISODE manual to find out what they are allocated as
     a C data type to implement  them.   The  offset  fields
     says  where  to find this data type with in the current
     structure.

SET_START, SETOF_START, SEQ_START and SEQOF_START
     These compound entries differ from the  above  in  that
     they group all the following entries together up to the
     matching  PE_END.   The  entries  with   OF   in   them
     correspond  to  the  ASN.1  types which have OF in them
     e.g. SET OF.  Allowing the OF items to  have  an  arbi-
     trary  number of entries is excessive flexibility, they
     can only have one type by the ASN.1 grammar rules.  The
     C data type corresponding to them is either a structure
     if it is the first such type in the array or a  pointer
     to a structure is isn't.  This complicates the process-
     ing of these structures a little but not greatly.   The
     OF types differ one other important way, they may occur
     zero, one or more times, with no upper bound.  To  cope
     with  this  the C data type is a linked list structure.
     The pointer to the data structure determines whether or
     not  there  is another occurrence of the type, if it is
     NULL there isn't.  Thus each data  structure  has  this



                      January 23, 1990





                           - 10 -


     pointer  to  the  next  occurrence,  the offset of this
     pointer is placed in the PE_END field where it can con-
     veniently  be  used to determine whether or not to make
     another pass through the table entry.

OBJECTWhen one  type  references  another  it  generates  an
     OBJECT  entry.   This  specifies the type number of the
     type which is present in  the  3rd  field  of  the  tpe
     structure,  pe_tag.   The  2nd  field  still  gives the
     offset in the C data structure  which  specifies  where
     the  user's data for that type is to be found.  Usually
     this a pointer to the C data structure for that type.

T_NULLThis entry means the ASN.1 primative  type  NULL.   It
     doesn't have any body and consequently has no offset as
     it cannot carry data directly.   Only  its  absence  or
     presence can mean anything so if it is optional it sets
     or clears a bit in the bit map as described earlier for
     OPTL entry.

T_OIDThis use to be used for Object Identifiers and  now  is
     unused, it should be got rid.

OBJIDThis corresponds to the Object  Identifier  ASN.1  type
     primitive.   It is implemented the same as other prima-
     tive types like INTEGER and OCTET STRING.

ETAG This entry gives the  explicit  tag  of  the  following
     entry.  The usual fields which define class and tag are
     the only ones which have meaning  in  this  entry.   By
     concatenating successive ETAG entries it is possibly to
     build up an limited number explicit tags, although this
     hasn't been tested yet.

IMP_OBJ
     If a type has an implicit tag usually all we have to do
     is  set  its  tag and class appropriately in its entry.
     This works for all but one important case,  the  refer-
     ence  of  another type.  This is messy because we can't
     alter the definition of the type with out  wrecking  it
     for  the  other  uses.   So  what we do for encoding is
     build the type normally and then afterward it is  built
     change  its  tag  and  class  to be the values we want.
     Similarly for decoding we match the tag  and  class  up
     and  then  decode the body of the type.  We can't use a
     OBJECT entry for this because among other reasons there
     3rd  field  is  already to store the type number.  (The
     forth needs to be free to contain flags such as DEFAULT
     and  OPTIONAL) So a new entry type is used, IMP_OBJ, to
     hold the tag and class.  It  must  be  followed  by  an
     OBJECT  entry  which is used to handle the type as nor-
     mal, the IMP_OBJ entry gives the tag and  class  to  be
     used.   Like  the  ETAG  entry  the IMP_OBJ affects the
     entry that follows it.



                      January 23, 1990





                           - 11 -


EXTOBJ and EXTMOD
     These handle external type references.   This  is  just
     like a normal (internal?) type reference except we must
     now specify which module as well as  the  type.   Simi-
     larly  because  there  are  no  more free fields in the
     OBJECT type we need two entries to hold all the  infor-
     mation  we need.  The EXTMOD occurs first and holds the
     type number and the offset into the  C  data  structure
     and  the  flags,  exactly  as for an OBJECT entry.  The
     next entry, which must be an EXTMOD, contains a pointer
     to  the modtyp structure for its module.  Like a normal
     OBJECT entry to handle the case of an implicit  tag  an
     IMP_OBJ  entry  would  occur  before  these two entries
     which gives the class and tag.  Likewise it could  have
     an  explicit tag in which the two entries would be pro-
     ceeded by an ETAG entry.

DFLT_F and DFLT_B
     When a type has a default value, to handle decoding and
     encoding properly you need to know its value.  As there
     is no space to store the value in most entries we allo-
     cate a whole entry to specify the value.  When encoding
     it is convenient to have the default occur  before  the
     entry it refers to.  This allows a single check to han-
     dle all the default encoding.  All  it  has  to  do  is
     check  whether  it is the same as the default value and
     if so not bother encoding the next type.  On the  other
     hand  when  decoding  it is more convenient to have the
     entry after the one it refers to.  In this case we need
     to  determine  that  it  is  missing  before we use the
     default value to determine the value  to  pass  to  the
     user.   To  handle  this we have entries of both types.
     _D_F_L_T__F contains the default  value  for  the  following
     entry  (F  =  Front)  and  DFLT_B contains that for the
     entry before it (B = Back).   Consequently  DFLT_F  are
     only used in the decoding tables and DFLT_B entries are
     only used in the decoding (and printing tables).

S-Types
     These types are entries for the same ASN.1 type as  the
     entry  type  formed  by removing the starting `S'.  The
     above forms would do to handle ASN.1 but we  also  have
     to  be  compatible with the C data structures generated
     by _p_o_s_y.  The implementors decided to  optimise  the  C
     data  structures  generated  a  little means we have to
     have all these S type entries.  If a type was a  single
     field in most cases they produced a #define which elim-
     inates the need to have a whole structure just for that
     type.   In  all  the places where this type is used the
     field of the C structure is changed from a  pointer  to
     field  which holds the value directly in the structure.
     See the ISODE reference given above for more details.

     We handle this by generating the same tables that would



                      January 23, 1990





                           - 12 -


be generated with out the optimisation, except the optimised
types the S-type of entries instead of the normal ones.  For
example  an optimised OCTET STRING would have the type field
of its entry as SOCTETSTRING instead  of  OCTETSTRING.   The
only  difference  in how S type and its corresponding normal
are handle is how they find the C data  structure  for  that
entry.   That  difference  is  that  there is no indirection
through pointers.

Flags field
     Besides the encoding the class the pe_flags field  also
     contains  a  few  possible  flags.   Mainly FL_OPTIONAL
     which means the ASN.1 type corresponding to  this  flag
     is  OPTIONAL.   Consequently  when  encoding  it has to
     determine if the type is present in the user data  pos-
     sibly  using  the  bit  map as described under the OPTL
     entry.  Likewise when decoding it may have to set a bit
     in  the  bit  map appropriately.  The other flag at the
     moment is FL_DEFAULT which means the entry  corresponds
     to  an ASN.1 DEFAULT type.  This bit is still needed as
     not all types have DFLT_* entries implmented  for  them
     at  the  moment.   In  particular compound value things
     like SEQUENCE and SET can't have  thier  default  value
     specified.   This  is  consistent  with  ISODE, if fact
     implementing that may even break existing  ISODE  code.
     This last flag FL_IMPLICIT is obsolete and not not used
     any where.


_1._2.  _W_a_l_k _t_h_r_o_u_g_h _o_f _p_e_p_s_y _l_i_b_r_a_r_y _r_o_u_t_i_n_e_s.

     Here we walk through all the pepsy library routines  at
least  briefly.   If any new routines are added or a routine
changed this documentation is the most likely part that will
need changing.  First we give some theory as to how the task
have have been brocken  into  routines  then  describe  each
function in detail.  We assume you are familiar with ISODE's
PE data structure manipulation routines.  if  not  they  are
documented  in  the  ISODE  manuals,  Volume one, chapter 5,
"Encoding of Data-Structures" (It actually  covers  decoding
as well).

_1._2._1.  _O_v_e_r_v_i_e_w _o_f _p_e_p_s_y _l_i_b_r_a_r_y

     Each seperate task is put into a  different  file.   So
all  the  encoding stuff is in _e_n_c._c, all the decoding stuff
is in _d_e_c._c, printing stuff in _p_r_n_t._c and freeing  stuff  in
_f_r_e._c.   Actually  it breaks down a little in practice, some
of the routines for moving around the  tables  are  used  in
both  _e_n_c._c  and  _d_e_c._c  for  example.  Probably they should
defined in _u_t_i_l._c so that linking one of the files from  the
library doesn't force linking any other except _u_t_i_l._o.

     There is a common structure to each of the major  files



                      January 23, 1990





                           - 13 -


as  well.   There  is a main routine which the user calls to
obtain the services provided by that  file's  routines.   As
all  the  files  revolve  about processing the table entries
their structure  is  based  on  running  through  the  table
entries.

     We shall call each array  of  entries  a  table  or  an
object.   There  is a routine, usually with a name ending in
_obj, which is designed to process an object.   For  example
en_obj is the routine called to generated an encoded object.
Then there are routines to call on each compound  type  such
as en_seq for encode a SEQUENCE.  Finally all the primitives
are handled by a one function that ends in _type.  This lets
each routine concentrate on handling the features particular
to its type and call the appropriate routine to handle  each
type it finds with in its compound type.

     Most of these table processing routines have just three
arguements: which are called parm, p, mod.  The parm is char
* or char ** in the encoding and decoding  routines  respec-
tively.   This points to the user's C structure that data to
be encoded is taken from when encoding.  When decoding it is
the address of a pointer which is made to point the C struc-
ture filled with the decode data.   The  freeing,  which  is
based  on  the  decoding  routines,  has a char ** while the
printing routines don't look at the user's data and so don't
have  such  a  pointer.   The  p points to the current table
entry we are up to processing and the mod  arguement  points
to  the  modtyp structure for the current module we are pro-
cessing.

     All these processing routines return a PE  type,  which
is  defined  in ISODE's file _h/_p_s_a_p._h, and to return zero if
they have an error, but not always.  In fact the error  han-
dling  is needs some work and has not been tested very well.
Generally it tries to print out the table entry where  some-
thing went wrong and the name of the function it was in.  It
then sometimes does an exit which may not be  very  pleasent
for the user.

_1._2._2.  _T_h_e _e_n_c_o_d_i_n_g _r_o_u_t_i_n_e_s - _e_n_c._c

enc_fThis is the the routine made available to the user  for
     the  encoding  routines.   It  is  fairly  simple as it
     leaves all the hard things up to other  routines.   All
     it  does  is  use the type number and modtyp pointer to
     get a pointer to the  table  for  encoding  that  type.
     Then  it  calls  the  table or object encoding routine,
     en_obj, on that object.  It first  does  a  consistency
     check  of making sure the first entry in the table is a
     PE_start.  Note that  it  returns  an  integer  (OK  or
     NOTOK)  instead  of a PE pointer.  This is to be consi-
     tent with ISODE functions.




                      January 23, 1990





                           - 14 -


en_objWe loop through the entries until we come to  the  end
     of the table and then we return the PE we have built up
     from the user's data which is pointed to by  parm.   In
     looping through each entry we call the appropriate rou-
     tine to encode its data.  The default case  is  handled
     by  calling  en_type which takes care of all the primi-
     tive types.

     The macro NEXT_TPE sets its arguement to point  to  the
next type in the table, counting compound types as one type.
Thus if NEXT_TPE is called on a SET_START it will  skip  all
the  entries  up  to  and including the matching PE_END.  As
many objects consist of one compound type and its components
the  main loop will only be run through once.  Even when the
object is not based on a compound type it will then  consist
of  one  simple  type  which  is processed by en_type, again
probably going through the loop only once.  In fact the only
way  it can go through the loop more than once is to process
entries that subsidary to the main type, e.g.  ETAG  entries
and  things  like  that.   To  double check this is the case
there is some code that looks for  the  processing  of  more
than one data generating entry.

     Much of that testing could probably be eliminated  with
no  loss.   Similarly  prehaps the IMP_OBJ and ETAG could be
handled by the default action of calling en_type.  As  these
routines  have  evolved  after many changes there are things
like that which really need to be looked at  closely  before
trying.   The comment /*SUPRESS 288*/ means suppress warning
288 to saber C debugging tool that we use.

en_type
     This is one of the longest functions as it has so  many
     cases  to handle.  It again is structure as a loop over
     the types until PE_END but it actually returns as  soon
     as  it  has  encoded the next type.  We can now look at
     the encoding of the primative ASN.1 types in detail.

DFLT_FBecause we have arranged  that  for  encoding  tables,
     that  we  precede  the entry with a DFLT_F entry we can
     neatly handle all the default  cases.   All  we  do  is
     check  if  the  parameter  passed  in the user data, in
     parm, is the same as the default value specified in the
     DFLT_F  entry.   The function same performs this check.
     If it is the same don't encode  anything  just  return,
     otherwise continue on and encode it.

ETAG To handle explicit tags we merely allocate  a  PE  with
     the right tag and call en_etype to encode its contents,
     which are in the following entries.  The switch on  the
     pe_ucode  field  use to make a difference but now it is
     meaningless and should be cleaned up.

SEQ_START, SEQOF_START, SET_START, SETOF_START



                      January 23, 1990





                           - 15 -


     We merely call the appropriate  function  handle  them.
     Note  one  _i_m_p_o_r_t_a_n_t  difference  in  the  way they are
     called here from that in enc_obj, the parm arguement is
     used  as a base to index off and fetch a new pointer to
     pass the next function.  This seemly bizarre action  is
     quite  straight forward when seen written as it is nor-
     mally in C, "parm->offset".  Where the field offset  is
     a  pointer  which  has  an offset from the start of the
     structure of p->pe_ucode bytes.

     This is the magic of how we access  all  the  different
fields  of the C data structures with the one piece of code.
It is also prehaps the most critical dependency of the whole
system on the implementation of the C language.  As the BGNU
C compiler supports this feature then it is compilerable  on
most machines.  But any porters should pay attention to this
to ensure that thier  compiler  is  happy  generating  these
offsets and compiling these casts properly.

     The reason why this is  different  from  the  calls  in
en_obj  is  that  this is not the first compound type in the
table.  The first and only the first does not have an offset
and  does  not  need  to be indirected through any pointers.
All the compound types inside this type will have  as  their
field  a  pointer which points to a structure.  From here on
we shall say _i_n_d_i_r_e_c_t_i_o_n  to mean this adding  the  pe_ucode
field to the pointer to the structure and using it to refer-
ence a pointer.  Whether to use _i_n_d_i_r_e_c_t_i_o_n or not  is  very
important  matter  that  really  needs  to  be understood to
understand how the routines are structured.

IMP_OBJ
     Here we have to handle the case where we can encode the
     object  then  have  to  change  its tag and class after
     encoding.  At the end of this entry this is  done  very
     simply by assigning the right values to the appropriate
     fields after the object has  been  built.   This  means
     that if the intermeadiate form is altered this piece of
     code may have to be altered as well.  There seems to be
     no better way of handling this.

     The complication in handling this field is the handling
of  all  the possible types of object.  If it is an external
object we have to perform a call to enc_f with all the right
arguements  where  a  normal  OBJECT,  the last else branch,
requires a normal call to en_obj.  Note the case of  SOBJECT
is the same as OBJECT _e_x_c_e_p_t _t_h_e_r_e _i_s _n_o _i_n_d_i_r_e_c_t_i_o_n.

SOBJECT and OBJECT
     Here is the code that handles the two cases  sperately.
     It  is  exactly as in the IMP_OBJ case except seperated
     out.  Note the only difference between the two cases is
     lack of indirection in the SOBJECT case.




                      January 23, 1990





                           - 16 -


CHOICE_START
     This is exactly  as  all  other  compound  types,  like
     SEQ_START  and  OBJECT, we call the appropriate routine
     with indirection.  From reading the ISODE manuals  that
     the  ASN.1 CHOICE type is handled by a structure of its
     own like the other compund types.

EXTOBJ and SEXTOBJ

















































                      January 23, 1990


