home *** CD-ROM | disk | FTP | other *** search
/ PC World 1998 October / PCWorld_1998-10_cd.bin / software / prehled / komix / DATA.Z / cpp_funcs.tcl < prev    next >
Text File  |  1997-10-21  |  61KB  |  2,062 lines

  1. #---------------------------------------------------------------------------
  2. #
  3. # Copyright (c) 1993-1995 by Cadre Technologies Inc.
  4. #
  5. # This software is furnished under a license and may be used only in
  6. # accordance with the terms of such license and with the inclusion of
  7. # the above copyright notice. This software or any other copies thereof
  8. # may not be provided or otherwise made available to any other person.
  9. # No title to and ownership of the software is hereby transferred.
  10. #
  11. # The information in this software is subject to change without notice
  12. # and should not be construed as a commitment by Cadre Technologies Inc.
  13. #
  14. #---------------------------------------------------------------------------
  15. #
  16. #    File        : @(#)cpp_funcs.tcl    /main/titanic/8
  17. #    Original date    : 4-2-1993
  18. #    Description    : C++ generator functions
  19. #
  20. #---------------------------------------------------------------------------
  21. #
  22. global classesOfInterest
  23. set classesOfInterest ""
  24.  
  25. proc oopl_model::generate {model} {
  26.     global classesOfInterest
  27.     set classesOfInterest  [getSelectedOoplClasses $model]
  28.     check_unique_file_names $model
  29.  
  30.     foreach class $classesOfInterest {
  31.         if [$class isExternal] {
  32.             continue
  33.         }
  34.         if {[$class getName] == ""} {
  35.             puts stderr "Class without name skipped"
  36.             continue
  37.         }
  38.         class2tgtfiles $class nts nth
  39.         global skip_file
  40.         global gen_file
  41.         global import_new
  42.         if [info exists gen_file($nth)] {
  43.             set gen_file($nts) 1
  44.         }
  45.         if {[$class getPropertyValue class_source] != ""} {
  46.             process_external_class_source $class
  47.             continue
  48.         }
  49.         if {( $import_new &&
  50.               ([is_special_class $class] ||
  51.                [info exists skip_file($nts)]) &&
  52.               [info exists skip_file($nth)]) ||
  53.             ( !$import_new &&
  54.               ![info exists gen_file($nts)] &&
  55.               ![info exists gen_file($nth)])} {
  56.             continue
  57.         }
  58.  
  59.         global cpp_error_state
  60.         set cpp_error_state 0
  61.  
  62.         generate $class
  63.     }
  64. }
  65.  
  66. # Check uniqueness of filenames
  67. #
  68. proc check_unique_file_names {model } {
  69.     global classesOfInterest
  70.  
  71.     foreach class $classesOfInterest {
  72.         set cl_name [$class getName]
  73.         set file_name [class2file $cl_name]
  74.         if [$class isExternal] {
  75.             continue
  76.         }
  77.         if [info exists names($file_name)] {
  78.             error "Classes '$cl_name' and '$names($file_name)' map to the same file name" "" ERR_UNIQUE_FILENAME
  79.         }
  80.         set names($file_name) $cl_name
  81.     }
  82. }
  83.  
  84. proc class::generate {class} {
  85.     if [catch {prepare_regeneration $class} result] {
  86.         # something went wrong, find out what
  87.         switch $errorCode {
  88.             ERR_REGEN {puts stderr $result}
  89.             default {error $result $errorInfo $errorCode}
  90.         }
  91.         class2tgtfiles $class src_file h_file
  92.         global gen_file
  93.         catch {unset gen_file($src_file)}
  94.         if {! [info exists gen_file($h_file)]} {
  95.             return
  96.         }
  97.     }
  98.     create_cpp_sections [concat $cpp_hdr_sections $cpp_src_sections]
  99.     init_cpp_sections $class
  100.     puts stdout "Generating for class '[$class getName]'"
  101.     class::gen_description $class $cpp_sections(h_class_nm_sect)
  102.     set is_db [is_db_class $class]
  103.     if {$is_db} {
  104.         db_class_before $class
  105.     }
  106.     gen_user_added_include
  107.     add_src_inc $class
  108.     gen_start_protector $class
  109.     gen_class_decl $class
  110.     set sect $cpp_sections(h_pub_func_sect)
  111.     foreach feat [$class featureSet] {
  112.         generate $feat $class
  113.     }
  114.     if {$is_db} {
  115.         db_class_after $class
  116.     }
  117.     gen_delayed_code $class
  118.     gen_user_added_ctor
  119.     gen_user_added_dtor
  120.     gen_end_protector $class
  121.     append_obsolete_code $class
  122.     exit_cpp_sections $class
  123.     write_cpp_sections $class $cpp_hdr_sections $cpp_src_sections
  124. }
  125.  
  126. proc class::gen_description {class sect} {
  127.     set ftext [$class getFreeText]
  128.     if {$ftext != ""} {
  129.         $sect append "\n"
  130.         string_to_oopl_comment $sect $ftext "//"
  131.         $sect append "\n"
  132.     }
  133. }
  134.  
  135. proc class_enum::generate {class} {
  136.     puts stdout "Generating for enum class '[$class getName]'"
  137.     create_cpp_sections $limited_cpp_hdr_sections
  138.     gen_start_protector $class
  139.     set sect $cpp_sections(h_inl_sect)
  140.     class::gen_description $class $sect
  141.     $sect append "enum [$class getName] \{\n"
  142.     $sect indent +
  143.     set first 1
  144.     foreach feat [$class featureSet] {
  145.         if {$first} {
  146.             set first 0
  147.         } else {
  148.             $sect append ",\n"
  149.         }
  150.         $sect append [$feat getName]
  151.         set iv [$feat getPropertyValue initial_value]
  152.         if {$iv != ""} {
  153.             $sect append " = $iv"
  154.         }
  155.     }
  156.     $sect append "\n"
  157.     $sect indent -
  158.     $sect append "\};\n"
  159.     gen_end_protector $class
  160.     write_cpp_sections $class $limited_cpp_hdr_sections ""
  161.  
  162.         if {[$class specNodeSet] != ""} {
  163.         if {![is_derivable_class $class]} {
  164.                 puts "ERROR: Enum Class '[$class getName]'\
  165.                     cannot have subclasses since it is a standard type"
  166.         }
  167.         }
  168. }
  169.  
  170. proc class_typedef::generate {class} {
  171.     puts stdout "Generating for typedef class '[$class getName]'"
  172.     create_cpp_sections $limited_cpp_hdr_sections
  173.     gen_start_protector $class
  174.     set sect $cpp_sections(h_inl_sect)
  175.     class::gen_description $class $sect
  176.     set feat [$class dataAttrSet]
  177.     $sect append \
  178.         "typedef [gen_var_decl [$feat ooplType] [$class getName]];\n"
  179.  
  180.     gen_delayed_code $class
  181.     gen_end_protector $class
  182.     write_cpp_sections $class $limited_cpp_hdr_sections ""
  183.  
  184.         if {[$class specNodeSet] != ""} {
  185.         if {![is_derivable_class $class]} {
  186.                 puts "ERROR: Typedef Class '[$class getName]'\
  187.                     cannot have subclasses since it is a standard type"
  188.         }
  189.         }
  190. }
  191.  
  192. proc class_generic_typedef::generate {class} {
  193.     puts stdout "Generating for generic typedef class '[$class getName]'"
  194.     create_cpp_sections $limited_cpp_hdr_sections
  195.     gen_start_protector $class
  196.     set sect $cpp_sections(h_inl_sect)
  197.     class::gen_description $class $sect
  198.     set feat [$class genAssocAttrSet]
  199.     gen_typedef $feat $class
  200.     gen_delayed_code $class
  201.  
  202.     gen_end_protector $class
  203.     write_cpp_sections $class $limited_cpp_hdr_sections ""
  204.  
  205.         if {[$class specNodeSet] != ""} {
  206.         if {![is_derivable_class $class]} {
  207.                 puts "ERROR: Generic Typedef Class '[$class getName]'\
  208.                     cannot have subclasses since it is a standard type"
  209.         }
  210.         }
  211. }
  212.  
  213. # look in global 're_user_includes' for previous user includes
  214.  
  215. proc gen_user_added_include {} {
  216.     set sect $cpp_sections(c_hdr_sect)
  217.  
  218.     global re_user_includes
  219.     $sect append "$START_INCLUDE_MESSAGE\n"
  220.     $sect append $re_user_includes
  221.     $sect append "$END_INCLUDE_MESSAGE\n\n"
  222. }
  223.  
  224. # look in global 're_ctor' for previous user additions to constructor
  225.  
  226. proc gen_user_added_ctor {} {
  227.     set sect $cpp_sections(c_ctor_body_iv_sect)
  228.     global re_ctor
  229.     set old_ind [$sect indent]
  230.     $sect append "$START_CTOR_MESSAGE\n"
  231.     $sect indent 0
  232.     $sect append $re_ctor
  233.     $sect indent $old_ind
  234.     $sect append "$END_CTOR_MESSAGE\n"
  235. }
  236.  
  237. # look in global 're_dtor' for previous user additions to destructor
  238.  
  239. proc gen_user_added_dtor {} {
  240.     set sect $cpp_sections(c_dtor_sect)
  241.     global re_dtor
  242.     set old_ind [$sect indent]
  243.     $sect append "$START_DTOR_MESSAGE\n"
  244.     $sect indent 0
  245.     $sect append $re_dtor
  246.     $sect indent $old_ind
  247.     $sect append "$END_DTOR_MESSAGE\n"
  248. }
  249.  
  250. proc gen_start_protector {class} {
  251.     set protector [protector_name [$class getName]]
  252.     expand_text $cpp_sections(h_hdr_sect) {
  253.         #ifndef ~$protector
  254.         #define ~$protector
  255.  
  256.     }
  257. }
  258.  
  259. proc gen_end_protector {class} {
  260.     set protector [protector_name [$class getName]]
  261.     $cpp_sections(h_trailer_sect) append "\n#endif /* $protector */\n"
  262. }
  263.  
  264. proc class::gen_class_decl {class} {
  265.     set sect $cpp_sections(h_class_nm_sect)
  266.     $sect append "class [$class getName] "
  267.     set first 1
  268.     foreach super [$class genNodeSet] {
  269.         generate $super first
  270.     }
  271.     $sect append "\{\n"
  272. }
  273.  
  274. proc link_class::generate {class} {
  275.     puts stdout "Generating for link class '[$class getName]'"
  276.     if {[$class getName] == ""} {
  277.         puts stderr "Link class without name skipped"
  278.         return
  279.     }
  280.     class::generate $class
  281. }
  282.  
  283. proc link_class::gen_class_decl {class} {
  284.     class::gen_class_decl $class
  285. }
  286.  
  287. proc inher_group::generate {group f} {
  288.     upvar $f first
  289.     set sect $cpp_sections(h_class_nm_sect)
  290.     if {$first} {
  291.         $sect append ": "
  292.         set first 0
  293.     } else {
  294.         $sect append ", "
  295.     }
  296.     set access [$group getPropertyValue inher_access]
  297.     if {$access != ""} {
  298.         set access [string tolower $access]
  299.     } else {
  300.         set access public
  301.     }
  302.     $sect append "$access "
  303.     if {[$group isOverlapping] == "1"} {
  304.         $sect append "virtual "
  305.     }
  306.     add_hdr_inc [$group superClass]
  307.     $sect append "[$group getSuperClassName] "
  308. }
  309.  
  310. proc feature::gen_description {feature sect} {
  311.     set ftext [$feature getFreeText]
  312.     if {$ftext != ""} {
  313.         string_to_oopl_comment $sect $ftext "//"
  314.     }
  315. }
  316.  
  317. proc data_attrib::generate {attrib class} {
  318.     if [info exists cpp_sections(h_priv_data_user-defined_sect)] {
  319.         set sect $cpp_sections(h_priv_data_user-defined_sect)
  320.     } else {
  321.         set sect $cpp_sections(h_priv_data_sect)
  322.     }
  323.     feature::gen_description $attrib $sect
  324.     if {[$attrib isClassFeature] == "1"} {
  325.         set static_string "static "
  326.         # static funcs: not const
  327.         set const_string ""
  328.     } else {
  329.         set static_string ""
  330.         set const_string " const"
  331.     }
  332.     set name [cap [$attrib getName]]
  333.     # set type as value and as parameter
  334.     # next line says:
  335.     # generate type with header include,
  336.     # look at modifier, use Value if modifier not set
  337.         set type [$attrib ooplType]
  338.     set t_val [generate $type inc "" Value]
  339.         set obj_type [$type get_obj_type]
  340.     if {$obj_type == "base_type" || $obj_type == "enum_type" ||
  341.             ($obj_type == "typedef_type" && [$type getType3GL] != "")} {
  342.         set t_par [generate $type fwd Value]
  343.     } else {
  344.         set t_par [generate $type fwd "Reference to Const"]
  345.     }
  346.     set iv [$attrib getPropertyValue initial_value]
  347.     if { $iv != "" } {
  348.         set dflt " /* = $iv */"
  349.     } else {
  350.         set dflt ""
  351.     }
  352.     # special treatment for char array
  353.     if [type_is_char_array $type] {
  354.         set tp_nm [gen_var_decl $type [$attrib getName]]
  355.         $sect append "$static_string$tp_nm$dflt;\n"
  356.     } else {
  357.         $sect append "$static_string$t_val[$attrib getName]$dflt;\n"
  358.     }
  359.     data_attrib_initial_value $attrib $class
  360.     set mdf [$attrib getPropertyValue modifier]
  361.     if {$mdf != "" && $mdf != "Default"} {
  362.         # when a modifier is specified
  363.         # do not generate access funcs
  364.         return
  365.     }
  366.     set sect [get_attrib_hdr_sect $attrib r]
  367.     expand_text $sect {
  368.         ~${static_string}~${t_par}get~${name}()~${const_string};
  369.     }
  370.     set sect [get_attrib_hdr_sect $attrib w]
  371.     expand_text $sect {
  372.         ~${static_string}void set~${name}(~${t_par}new~${name});
  373.     }
  374.     set sect [get_attrib_src_sect $attrib 1 r]
  375.     expand_text $sect {
  376.         inline ~${t_par}~[$class getName]::get~${name}()~${const_string}
  377.         {
  378.             return ~[$attrib getName];
  379.         }
  380.     
  381.     }
  382.     set sect [get_attrib_src_sect $attrib 1 w]
  383.     expand_text $sect {
  384.         inline void ~[$class getName]::set~${name}(~${t_par}new~${name})
  385.         {
  386.             ~[assign_var [$attrib getName] new${name} \
  387.                      [$attrib ooplType] $sect]
  388.         }
  389.  
  390.     }
  391. }
  392.  
  393. # generate an initial value line
  394.  
  395. proc data_attrib_initial_value {attrib class} {
  396.     set is_static 0
  397.     if {[$attrib isClassFeature] == "1"} {
  398.         set is_static 1
  399.     } else {
  400.         set is_static 0
  401.     }
  402.     set iv [$attrib getPropertyValue initial_value]
  403.     set a_name [$attrib getName]
  404.     set c_name [$class getName]
  405.     if $is_static {
  406.         set sect $cpp_sections(c_static_sect)
  407.         set t_val [generate [$attrib ooplType] inc Value]
  408.         $sect append "${t_val}$c_name::$a_name"
  409.         if {$iv != ""} {
  410.             $sect append " = $iv"
  411.         } else {
  412.             gen_def_init_val $attrib $sect
  413.         }
  414.         $sect append ";\n"
  415.         return
  416.     }
  417.     if {$iv == ""} {
  418.         return
  419.     }
  420.  
  421.     set type [$attrib ooplType]
  422.     if {[type_is_char_array $type] || [is_db_class $class]} {
  423.         if [is_db_class $class] {
  424.             set a_name "data.$a_name"
  425.         }
  426.         set sect $cpp_sections(c_ctor_body_iv_sect)
  427.         $sect append "[assign_var $a_name $iv $type $sect]\n"
  428.         return
  429.     }
  430.     append_ctor_iv_init $a_name $iv
  431. }
  432.  
  433. # Returns the default initial value for $attrib
  434. #
  435. proc gen_def_init_val {attrib sect} {
  436.     set type [$attrib ooplType]
  437.  
  438.     if {[$type get_obj_type] == "typedef_type"} {
  439.         # search type def
  440.         set type_class [$type ooplClass]
  441.  
  442.         if {[$type_class get_obj_type] != "class_generic_typedef"} {
  443.             return
  444.         }
  445.  
  446.         set attrib [$type_class genAssocAttrSet]
  447.     }
  448.  
  449.     if {[$attrib get_obj_type] != "qual_assoc_attrib"} {
  450.         return
  451.     }
  452.     set key [[$attrib qualifier] ooplType]
  453.     set value [$attrib ooplType]
  454.     if {[$attrib getMultiplicity] == "one"} {
  455.         set result [dict::initializer "" $key $value]
  456.     } else {
  457.         set setpfx [set_prefix $attrib]
  458.         set result [${setpfx}psdict::initializer "" $key $value]
  459.     }
  460.     $sect append $result
  461. }
  462.  
  463.  
  464. # produces 'mem(value)' in ctor initializers section
  465.  
  466. proc append_ctor_init {mem value} {
  467.     ### to do: should also do char array test
  468.     set sect $cpp_sections(c_ctor_init_sect)
  469.     gen_ctor_sep $sect
  470.     $sect append "${mem}($value)"
  471. }
  472.  
  473. proc append_ctor_iv_init {mem value} {
  474.     ### to do: should also do char array test
  475.     set sect $cpp_sections(c_ctor_init_iv_sect)
  476.     gen_ctor_iv_sep $sect
  477.     $sect append "${mem}($value)"
  478. }
  479.  
  480. # produce correct separator for constructor initializer part
  481.  
  482. proc gen_ctor_sep {sect} {
  483.     global ctor_init_sep
  484.     if $ctor_init_sep {
  485.         set ctor_init_sep 0
  486.         $sect append " :\n"
  487.     } else {
  488.         $sect append ",\n"
  489.     }
  490. }
  491.  
  492. proc gen_ctor_iv_sep {sect} {
  493.     global ctor_init_iv_sep
  494.     if $ctor_init_iv_sep {
  495.         set ctor_init_iv_sep 0
  496.         $sect indent +
  497.     } else {
  498.         $sect append ",\n"
  499.     }
  500. }
  501.  
  502. # Common generate dispatch function for associations
  503. #
  504. proc gen_for_assoc {attrib class} {
  505.     set prefix "[$attrib get_obj_type]::[$attrib getMultiplicity]"
  506.     ${prefix}_data $attrib
  507.     ${prefix}_get $attrib $class
  508.     ${prefix}_set_self $attrib $class
  509.     ${prefix}_rm_self $attrib $class
  510.     ${prefix}_dtor $attrib $class
  511.     set type [$attrib ooplType]
  512.     if {[$attrib opposite] != ""} {
  513.         add_friend $type
  514.         add_src_inc $type
  515.     } else {
  516.         add_forward $type
  517.     }
  518. }
  519.  
  520. # Common generate dispatch function for database associations
  521. #
  522. proc gen_for_db_assoc {attrib class} {
  523.     set prefix "[$attrib get_obj_type]::[$attrib getMultiplicity]"
  524.     ${prefix}_get $attrib $class
  525.     ${prefix}_set $attrib $class
  526.     ${prefix}_remove $attrib $class
  527.     set type [$attrib ooplType]
  528.     add_src_inc $type
  529.     add_forward $type
  530. }
  531.  
  532. # Common generate dispatch function for links
  533. #
  534. proc gen_for_link {attrib class} {
  535.     set prefix "[$attrib get_obj_type]::[$attrib getMultiplicity]"
  536.     ${prefix}_data $attrib
  537.     ${prefix}_get $attrib $class
  538.     set type [$attrib ooplType]
  539.     if {[$attrib opposite] != ""} {
  540.         add_friend $type
  541.         add_src_inc $type
  542.     } else {
  543.         add_forward $type
  544.     }
  545. }
  546.  
  547. # Common generate dispatch function for reverse links
  548. #
  549. proc gen_for_rv_link {attrib class} {
  550.     set prefix "[$attrib get_obj_type]::[$attrib getMultiplicity]"
  551.     ${prefix}_data $attrib
  552.     ${prefix}_get $attrib $class
  553.     ${prefix}_dtor $attrib $class
  554.     set type [$attrib ooplType]
  555.     add_forward $type
  556. }
  557.  
  558. # Dispatch functions for rm/set other
  559. #
  560. proc rm_other {attrib sect ptr} {
  561.     set prefix "[$attrib get_obj_type]::[$attrib getMultiplicity]"
  562.     ${prefix}_rm_other $attrib $sect $ptr
  563. }
  564.  
  565. proc set_other {attrib sect ptr} {
  566.     set prefix "[$attrib get_obj_type]::[$attrib getMultiplicity]"
  567.     ${prefix}_set_other $attrib $sect $ptr
  568. }
  569.  
  570. proc assoc_attrib::generate {attrib class} {
  571.     gen_for_assoc $attrib $class
  572. }
  573.  
  574. proc assign_var {to from type_obj {sect "src"}} {
  575.     if [type_is_char_array $type_obj] {
  576.                 add_[determine_sect_type $sect]_inc_name "string" "h"
  577.         return "strcpy($to, $from);"
  578.     }
  579.     return "$to = $from;"
  580. }
  581.  
  582. proc assoc_attrib::one_typedef {attrib class} {
  583.     set sect $cpp_sections(h_inl_sect)
  584.     set name [$class getName]
  585.     set type [$attrib ooplType]
  586.     set type_nm [$type getName]
  587.     ###add_forward $type
  588.     # gen_var_decl does not deliver it the format we want, alas
  589.     set dum [gen_var_decl $type $name]
  590.     $sect append "typedef $type_nm *$name;\n"
  591. }
  592.  
  593. proc assoc_attrib::one_data {attrib} {
  594.     if [info exists cpp_sections(h_priv_data_assoc-storage_sect)] {
  595.         set sect $cpp_sections(h_priv_data_assoc-storage_sect)
  596.     } else {
  597.         set sect $cpp_sections(h_priv_data_sect)
  598.     }
  599.     set type [[$attrib ooplType] getName]
  600.     set name [uncap [pointer_name [$attrib getName]]]
  601.     $sect append "$type *$name;\n"
  602.     if [$attrib isMandatory] {
  603.         return
  604.     }
  605.     set sect $cpp_sections(c_ctor_body_iv_sect)
  606.     $sect append "$name = 0;\n"
  607. }
  608.  
  609. proc assoc_attrib::one_set_self {attrib class} {
  610.     set type [[$attrib ooplType] getName]
  611.     set name [cap [$attrib getName]]
  612.     set cl_name [$class getName]
  613.     set sect [get_assoc_hdr_sect $attrib w]
  614.     $sect append "void set${name}($type *new${name});\n"
  615.     set sect [get_assoc_src_sect $attrib 0 w]
  616.     $sect append "void $cl_name::set${name}($type *new${name})\n\{\n"
  617.     $sect indent +
  618.     set opposite [$attrib opposite]
  619.     set ptr_name [uncap [pointer_name $name]]
  620.     if {$opposite != ""} {
  621.         $sect append "if ($ptr_name) \{\n"
  622.         $sect indent +
  623.         rm_other $opposite $sect $ptr_name
  624.         $sect indent -
  625.         $sect append "\}\n"
  626.         set_other $opposite $sect new${name}
  627.     }
  628.     $sect append "$ptr_name = new${name};\n"
  629.     $sect indent -
  630.     $sect append "\}\n\n"
  631. }
  632.  
  633. proc assoc_attrib::one_rm_self {attrib class} {
  634.     if [$attrib isMandatory] {
  635.         return
  636.     }
  637.     set type [[$attrib ooplType] getName]
  638.     set name [cap [$attrib getName]]
  639.     set cl_name [$class getName]
  640.     set sect [get_assoc_hdr_sect $attrib w]
  641.     $sect append "void remove${name}();\n"
  642.     set sect [get_assoc_src_sect $attrib 0 w]
  643.     $sect append "void $cl_name::remove${name}()\n\{\n"
  644.     $sect indent +
  645.     set opposite [$attrib opposite]
  646.     set ptr_name [uncap [pointer_name $name]]
  647.     if {$opposite != ""} {
  648.         $sect append "if ($ptr_name) \{\n"
  649.         $sect indent +
  650.         rm_other $opposite $sect $ptr_name
  651.         $sect indent -
  652.         $sect append "\}\n"
  653.     }
  654.     $sect append "$ptr_name = 0;\n"
  655.     $sect indent -
  656.     $sect append "\}\n\n"
  657. }
  658.  
  659. proc assoc_attrib::one_set_other {attrib sect ptr} {
  660.     set name [$attrib getName]
  661.     set ptrname [uncap [pointer_name $name]]
  662.     $sect append "$ptr->$ptrname = this;\n"
  663. }
  664.  
  665. proc assoc_attrib::one_rm_other {attrib sect ptr} {
  666.     set name [$attrib getName]
  667.     set ptr_name [uncap [pointer_name $name]]
  668.     $sect append "$ptr->$ptr_name = 0;\n"
  669. }
  670.  
  671. proc assoc_attrib::one_dtor {attrib class} {
  672.     set opposite [$attrib opposite]
  673.     if {$opposite != ""} {
  674.         set ptr [uncap [pointer_name [$attrib getName]]]
  675.         set sect $cpp_sections(c_dtor_sect)
  676.         $sect append "if ($ptr) \{\n"
  677.         $sect indent +
  678.         rm_other $opposite $sect $ptr
  679.         $sect indent -
  680.         $sect append "\}\n"
  681.     }
  682. }
  683.  
  684. proc assoc_attrib::one_get {attrib class} {
  685.     set type [[$attrib ooplType] getName]
  686.     set name [cap [$attrib getName]]
  687.     set cl_name [$class getName]
  688.     set sect [get_assoc_hdr_sect $attrib r]
  689.     $sect append "$type *get${name}() const;\n"
  690.     set sect [get_assoc_src_sect $attrib 1 r]
  691.     $sect append "inline $type *$cl_name::get${name}"
  692.     set ptr_name [uncap [pointer_name $name]]
  693.     $sect append "() const\n\{\n\treturn $ptr_name;\n\}\n\n";
  694. }
  695.  
  696. proc assoc_attrib::many_typedef {attrib class} {
  697.     set sect $cpp_sections(h_inl_sect)
  698.     set name [$class getName]
  699.     set setpfx [set_prefix $attrib]
  700.     set type [${setpfx}set_type_name [$attrib ooplType]]
  701.     $sect append "typedef $type $name;\n"
  702. }
  703.  
  704. proc assoc_attrib::many_data {attrib} {
  705.     if [info exists cpp_sections(h_priv_data_assoc-storage_sect)] {
  706.         set sect $cpp_sections(h_priv_data_assoc-storage_sect)
  707.     } else {
  708.         set sect $cpp_sections(h_priv_data_sect)
  709.     }
  710.     set setpfx [set_prefix $attrib]
  711.     set type [${setpfx}set_type_name [$attrib ooplType]]
  712.     set name [uncap [${setpfx}set_name [$attrib getName]]]
  713.     $sect append "$type $name;\n"
  714. }
  715.  
  716. proc assoc_attrib::many_set_self {attrib class} {
  717.     set type [[$attrib ooplType] getName]
  718.     set name [cap [$attrib getName]]
  719.     set cl_name [$class getName]
  720.     set sect [get_assoc_hdr_sect $attrib w]
  721.     $sect append "void add${name}($type *new${name});\n"
  722.     set sect [get_assoc_src_sect $attrib 0 w]
  723.     $sect append "void $cl_name::add${name}($type *new${name})\n\{\n"
  724.     $sect indent +
  725.     set opposite [$attrib opposite]
  726.     set setpfx [set_prefix $attrib]
  727.     set set_name [uncap [${setpfx}set_name $name]]
  728.     set add_func [set ${setpfx}set::add]
  729.     $sect append "$set_name.${add_func}(new${name});\n"
  730.     if {$opposite != ""} {
  731.         set_other $opposite $sect new${name}
  732.     }
  733.     $sect indent -
  734.     $sect append "\}\n\n"
  735. }
  736.  
  737. proc assoc_attrib::many_rm_self {attrib class} {
  738.     set type [[$attrib ooplType] getName]
  739.     set name [cap [$attrib getName]]
  740.     set cl_name [$class getName]
  741.     set sect [get_assoc_hdr_sect $attrib w]
  742.     $sect append "void remove${name}($type *old${name});\n"
  743.     set sect [get_assoc_src_sect $attrib 0 w]
  744.     $sect append "void $cl_name::remove${name}($type *old${name})\n\{\n"
  745.     $sect indent +
  746.     set opposite [$attrib opposite]
  747.     set setpfx [set_prefix $attrib]
  748.     set set_name [uncap [${setpfx}set_name $name]]
  749.     set remove_func [set ${setpfx}set::remove]
  750.     $sect append "$set_name.${remove_func}(old${name});\n"
  751.     if {$opposite != ""} {
  752.         rm_other $opposite $sect old${name}
  753.     }
  754.     $sect indent -
  755.     $sect append "\}\n\n"
  756. }
  757.  
  758. proc assoc_attrib::many_set_other {attrib sect ptr} {
  759.     set setpfx [set_prefix $attrib]
  760.     set name [uncap [${setpfx}set_name [$attrib getName]]]
  761.     set add_func [set ${setpfx}set::add]
  762.     $sect append "$ptr->$name.${add_func}(this);\n"
  763. }
  764.  
  765. proc assoc_attrib::many_rm_other {attrib sect ptr} {
  766.     set setpfx [set_prefix $attrib]
  767.     set name [uncap [${setpfx}set_name [$attrib getName]]]
  768.     set remove_func [set ${setpfx}set::remove]
  769.     $sect append "$ptr->$name.${remove_func}(this);\n"
  770. }
  771.  
  772. proc assoc_attrib::many_dtor {attrib class} {
  773.     set opposite [$attrib opposite]
  774.     if {$opposite != ""} {
  775.         set sect $cpp_sections(c_dtor_sect)
  776.         set type [[$attrib ooplType] getName]
  777.         set name [$attrib getName]
  778.         set action "rm_other $opposite $sect"
  779.         set setpfx [set_prefix $attrib]
  780.         ${setpfx}set::iter $sect $name $type $action
  781.     }
  782. }
  783.  
  784. proc assoc_attrib::many_get {attrib class} {
  785.     set setpfx [set_prefix $attrib]
  786.     set type [${setpfx}set_type_name [$attrib ooplType]]
  787.     set name [cap [${setpfx}set_name [$attrib getName]]]
  788.     set cl_name [$class getName]
  789.     set sect [get_assoc_hdr_sect $attrib r]
  790.     $sect append "const $type& get${name}() const;\n"
  791.     set sect [get_assoc_src_sect $attrib 1 r]
  792.     $sect append "inline const $type& $cl_name::"
  793.     $sect append "get${name}() const\n\{\n\treturn [uncap $name];\n\}\n\n"
  794. }
  795.  
  796. proc get_qualifier_type {assoc modifier} {
  797.     return [generate [[$assoc qualifier] ooplType] fwd $modifier]
  798. }
  799.  
  800. proc get_qualifier_name {assoc} {
  801.     return [[$assoc qualifier] getName]
  802. }
  803.  
  804. proc qual_assoc_attrib::generate {attrib class} {
  805.     gen_for_assoc $attrib $class
  806. }
  807.  
  808. proc qual_assoc_attrib::one_typedef {attrib class} {
  809.     set sect $cpp_sections(h_inl_sect)
  810.     set name [$class getName]
  811.     set type [dict_type_name [[$attrib qualifier] ooplType] \
  812.         [$attrib ooplType]]
  813.     $sect append "typedef $type $name;\n"
  814. }
  815.  
  816. proc qual_assoc_attrib::one_data {attrib} {
  817.     if [info exists cpp_sections(h_priv_data_assoc-storage_sect)] {
  818.         set sect $cpp_sections(h_priv_data_assoc-storage_sect)
  819.     } else {
  820.         set sect $cpp_sections(h_priv_data_sect)
  821.     }
  822.     set type [dict_type_name [[$attrib qualifier] ooplType] \
  823.                  [$attrib ooplType]]
  824.     set name [uncap [dict_name [$attrib getName]]]
  825.     $sect append "$type $name;\n"
  826.  
  827.     set sect $cpp_sections(c_ctor_init_sect)
  828.     set key [[$attrib qualifier] ooplType]
  829.     set value [$attrib ooplType]
  830.     set result [dict::initializer $name $key $value]
  831.     if {$result == ""} {
  832.         return
  833.     }
  834.     gen_ctor_sep $sect
  835.     $sect append $result
  836.  
  837. }
  838.  
  839. proc qual_assoc_attrib::one_set_self {attrib class} {
  840.     set type [[$attrib ooplType] getName]
  841.     set name [cap [$attrib getName]]
  842.     set cl_name [$class getName]
  843.     set key [get_qualifier_name $attrib]
  844.     set q_type [get_qualifier_type $attrib "Reference to Const"]
  845.     set sect [get_assoc_hdr_sect $attrib w]
  846.     $sect append \
  847.         "void set${name}($q_type$key, $type *new${name});\n"
  848.     set sect [get_assoc_src_sect $attrib 0 w]
  849.     $sect append "void $cl_name::set${name}($q_type$key, "
  850.     $sect append "$type *new${name})\n\{\n"
  851.     $sect indent +
  852.     set opposite [$attrib opposite]
  853.     set dct_name [uncap [dict_name $name]]
  854.     if {$opposite != ""} {
  855.         set action "rm_other $opposite $sect"
  856.         dict::get_test_and_act $sect $name $key $type $action
  857.         set_other $opposite $sect new${name}
  858.     }
  859.     $sect append "$dct_name.${dict::set}($key, new${name});\n"
  860.     $sect indent -
  861.     $sect append "\}\n\n"
  862. }
  863.  
  864. proc qual_assoc_attrib::one_rm_self {attrib class} {
  865.     set type [[$attrib ooplType] getName]
  866.     set name [cap [$attrib getName]]
  867.     set cl_name [$class getName]
  868.     set key [get_qualifier_name $attrib]
  869.     set q_type [get_qualifier_type $attrib "Reference to Const"]
  870.     set sect [get_assoc_hdr_sect $attrib w]
  871.     $sect append "void remove${name}($q_type$key);\n"
  872.     set sect [get_assoc_src_sect $attrib 0 w]
  873.     $sect append "void $cl_name::remove${name}($q_type$key"
  874.     $sect append ")\n\{\n"
  875.     $sect indent +
  876.     set opposite [$attrib opposite]
  877.     set dct_name [uncap [dict_name $name]]
  878.     set ptr_name [uncap [pointer_name $name]]
  879.     if {$opposite != ""} {
  880.         set action "rm_other $opposite $sect"
  881.         dict::get_test_and_act $sect $name $key $type $action
  882.     }
  883.     $sect append "$dct_name.${dict::remove}($key);\n"
  884.     $sect indent -
  885.     $sect append "\}\n\n"
  886. }
  887.  
  888. proc qual_assoc_attrib::one_set_other {attrib sect ptr} {
  889.     set name [uncap [dict_name [$attrib getName]]]
  890.     $sect append \
  891.         "$ptr->$name.${dict::set}(/* supply key here */, this);\n"
  892. }
  893.  
  894. proc qual_assoc_attrib::one_rm_other {attrib sect ptr} {
  895.     set name [uncap [dict_name [$attrib getName]]]
  896.     $sect append \
  897.         "$ptr->$name.${dict::remove}(/* supply key here */);\n"
  898. }
  899.  
  900. proc qual_assoc_attrib::one_dtor {attrib class} {
  901.     set opposite [$attrib opposite]
  902.     if {$opposite != ""} {
  903.         set sect $cpp_sections(c_dtor_sect)
  904.         set type [[$attrib ooplType] getName]
  905.         set qual_type [[[$attrib qualifier] ooplType] getName]
  906.         set name [$attrib getName]
  907.         set action "rm_other $opposite $sect"
  908.         dict::iter $sect $name $type $qual_type $action
  909.     }
  910. }
  911.  
  912. proc qual_assoc_attrib::one_get {attrib class} {
  913.     set type [[$attrib ooplType] getName]
  914.     set name [cap [$attrib getName]]
  915.     set key [get_qualifier_name $attrib]
  916.     set q_type [get_qualifier_type $attrib "Reference to Const"]
  917.     set cl_name [$class getName]
  918.     set sect [get_assoc_hdr_sect $attrib r]
  919.     $sect append "$type *get${name}($q_type$key) const;\n"
  920.     set sect [get_assoc_src_sect $attrib 1 r]
  921.     $sect append "inline $type *$cl_name::get${name}"
  922.     $sect append "($q_type$key) const\n\{\n"
  923.     set dct_name [uncap [dict_name $name]]
  924.     $sect indent +
  925.     dict::get_and_return $sect $dct_name $key $type
  926.     $sect indent -
  927.     $sect append "\}\n\n"
  928. }
  929.  
  930. proc qual_assoc_attrib::many_typedef {attrib class} {
  931.     set sect $cpp_sections(h_inl_sect)
  932.     set name [$class getName]
  933.     set setpfx [set_prefix $attrib]
  934.     set type [${setpfx}set_dict_type_name \
  935.          [[$attrib qualifier] ooplType] [$attrib ooplType]]
  936.     $sect append "typedef $type $name;\n"
  937. }
  938.  
  939. proc qual_assoc_attrib::many_data {attrib} {
  940.     if [info exists cpp_sections(h_priv_data_assoc-storage_sect)] {
  941.         set sect $cpp_sections(h_priv_data_assoc-storage_sect)
  942.     } else {
  943.         set sect $cpp_sections(h_priv_data_sect)
  944.     }
  945.     set setpfx [set_prefix $attrib]
  946.     set type [${setpfx}set_dict_type_name \
  947.         [[$attrib qualifier] ooplType] [$attrib ooplType]]
  948.     set name [uncap [${setpfx}set_dict_name [$attrib getName]]]
  949.     $sect append "$type $name;\n"
  950.  
  951.     set sect $cpp_sections(c_ctor_init_sect)
  952.     set key [[$attrib qualifier] ooplType]
  953.     set value [$attrib ooplType]
  954.     set result [${setpfx}psdict::initializer $name $key $value]
  955.     if {$result == ""} {
  956.         return
  957.     }
  958.     gen_ctor_sep $sect
  959.     $sect append $result
  960. }
  961.  
  962. proc qual_assoc_attrib::many_set_self {attrib class} {
  963.     set type [[$attrib ooplType] getName]
  964.     set name [cap [$attrib getName]]
  965.     set cl_name [$class getName]
  966.     set key [get_qualifier_name $attrib]
  967.     set q_type [get_qualifier_type $attrib "Reference to Const"]
  968.     set sect [get_assoc_hdr_sect $attrib w]
  969.     $sect append "void add${name}($q_type$key, $type *new${name});\n"
  970.     set sect [get_assoc_src_sect $attrib 0 w]
  971.     $sect append "void $cl_name::add${name}($q_type$key, "
  972.     $sect append "$type *new${name})\n\{\n"
  973.     $sect indent +
  974.     set setpfx [set_prefix $attrib]
  975.     set sdct_name [uncap [${setpfx}set_dict_name [$attrib getName]]]
  976.     set add_func [set ${setpfx}psdict::add]
  977.     $sect append "$sdct_name.${add_func}($key, new${name});\n"
  978.  
  979.     set opposite [$attrib opposite]
  980.     if {$opposite != ""} {
  981.         set_other $opposite $sect new${name}
  982.     }
  983.     $sect indent -
  984.     $sect append "\}\n\n"
  985. }
  986.  
  987. proc qual_assoc_attrib::many_rm_self {attrib class} {
  988.     set type [[$attrib ooplType] getName]
  989.     set name [cap [$attrib getName]]
  990.     set cl_name [$class getName]
  991.     set key [get_qualifier_name $attrib]
  992.     set q_type [get_qualifier_type $attrib "Reference to Const"]
  993.     set sect [get_assoc_hdr_sect $attrib w]
  994.     $sect append "void remove${name}($q_type$key, $type *old${name});\n"
  995.     set sect [get_assoc_src_sect $attrib 0 w]
  996.     $sect append "void $cl_name::remove${name}($q_type$key"
  997.     $sect append ", $type *old${name})\n\{\n"
  998.     $sect indent +
  999.     set opposite [$attrib opposite]
  1000.     if {$opposite != ""} {
  1001.         rm_other $opposite $sect old${name}
  1002.     }
  1003.     set setpfx [set_prefix $attrib]
  1004.     set sdct_name [uncap [${setpfx}set_dict_name [$attrib getName]]]
  1005.     set remove_func [set ${setpfx}psdict::remove]
  1006.     $sect append "$sdct_name.${remove_func}($key, old${name});\n"
  1007.     $sect indent -
  1008.     $sect append "\}\n\n"
  1009. }
  1010.  
  1011. proc qual_assoc_attrib::many_set_other {attrib sect ptr} {
  1012.     set type [[$attrib ooplType] getName]
  1013.     set name [cap [$attrib getName]]
  1014.     set setpfx [set_prefix $attrib]
  1015.     set sdct_name [uncap [${setpfx}set_dict_name $name]]
  1016.     set add_func [set ${setpfx}psdict::add]
  1017.     $sect append \
  1018.            "$ptr->$sdct_name.${add_func}(/* supply key here */, this);\n"
  1019. }
  1020.  
  1021. proc qual_assoc_attrib::many_rm_other {attrib sect ptr} {
  1022.     set type [[$attrib ooplType] getName]
  1023.     set name [cap [$attrib getName]]
  1024.     set setpfx [set_prefix $attrib]
  1025.     set sdct_name [uncap [${setpfx}set_dict_name $name]]
  1026.     set remove_func [set ${setpfx}psdict::remove]
  1027.     $sect append \
  1028.         "$ptr->$sdct_name.${remove_func}(/* supply key here */, this);\n"
  1029. }
  1030.  
  1031. proc qual_assoc_attrib::many_dtor {attrib class} {
  1032.     set opposite [$attrib opposite]
  1033.     if {$opposite != ""} {
  1034.         set sect $cpp_sections(c_dtor_sect)
  1035.         set type [$attrib ooplType]
  1036.         set q_type [string trimright [generate [ [$attrib qualifier]\
  1037.                         ooplType] inc Value]]
  1038.         set name [cap [$attrib getName]]
  1039.         set action "rm_other $opposite $sect"
  1040.         set setpfx [set_prefix $attrib]
  1041.         ${setpfx}psdict::iter $sect $name $type $q_type $action
  1042.     }
  1043. }
  1044.  
  1045. proc qual_assoc_attrib::many_get {attrib class} {
  1046.     set setpfx [set_prefix $attrib]
  1047.     set type [${setpfx}set_type_name [$attrib ooplType]]
  1048.     set name [cap [$attrib getName]]
  1049.     set key [get_qualifier_name $attrib]
  1050.     set q_type [get_qualifier_type $attrib "Reference to Const"]
  1051.     set cl_name [$class getName]
  1052.     set sect [get_assoc_hdr_sect $attrib r]
  1053.     $sect append "$type *get${name}($q_type$key) const;\n"
  1054.     set sect [get_assoc_src_sect $attrib 1 r]
  1055.     $sect append "inline $type *$cl_name::get${name}"
  1056.     $sect append "($q_type$key) const\n\{\n"
  1057.     set sdct_name [uncap [${setpfx}set_dict_name $name]]
  1058.     $sect indent +
  1059.     ${setpfx}psdict::get_and_return $sect $name $key $type
  1060.     $sect indent -
  1061.     $sect append "\}\n\n"
  1062. }
  1063.  
  1064. proc operation::generate {oper class} {
  1065.     global cpp_error_state
  1066.     if [is_eq_db_ctor $oper $class] {
  1067.         # skip, will be generated with runtime system
  1068.         return
  1069.     }
  1070.     set h_sect [get_hdr_sect [$oper getPropertyValue method_access] user-defined]
  1071.     feature::gen_description $oper $h_sect
  1072.     set c_sect $cpp_sections(c_impl_sect)
  1073.     set tmp_c_sect [TextSection new]
  1074.     set name [map_oper [$oper getName]]
  1075.     set is_ctor [expr {$name == "create" && [$oper isClassFeature]== "1"}]
  1076.     set is_abstract [expr {[$oper isAbstract] == "1"}]
  1077.     set is_type_conv [expr {$name == "type_conv"}]
  1078.     if $is_ctor {
  1079.         set type ""
  1080.         set name [$class getName]
  1081.     } else {
  1082.         set type [generate [$oper ooplType] fwd "" Value]
  1083.     }
  1084.     set is_static [expr {[$oper isClassFeature] == "1"} && !$is_ctor]
  1085.     if $is_static {
  1086.         $h_sect append "static "
  1087.     }
  1088.     if {[$oper isDynBound] == "1" || $is_abstract} {
  1089.                 if $is_static {
  1090.             puts "ERROR: static member function '[$class getName]::${name}()' cannot be virtual or abstract"
  1091.             set cpp_error_state 1
  1092.                 }
  1093.         $h_sect append "virtual "
  1094.     }
  1095.     if $is_type_conv {
  1096.         if {$is_static} {
  1097.             puts "ERROR: '[$class getName]::operator ${type}()' cannot be static"
  1098.             set cpp_error_state 1
  1099.         }
  1100.         $h_sect append "operator ${type}("
  1101.         if {!$is_abstract} {
  1102.             $c_sect append "[$class getName]::operator ${type}("
  1103.         }
  1104.     } else {
  1105.         $h_sect append "${type}${name}("
  1106.         if {!$is_abstract} {
  1107.             $c_sect append "${type}[$class getName]::${name}"
  1108.             $tmp_c_sect append "("
  1109.         }
  1110.     }
  1111.     set params [get_parameters $oper]
  1112.     if {$is_type_conv && $params != ""} {
  1113.             puts "ERROR: '[$class getName]::operator ${type}()' cannot have parameters"
  1114.             set cpp_error_state 1
  1115.     }
  1116.     set first 1
  1117.     foreach param [get_parameters $oper] {
  1118.         generate $param $h_sect first
  1119.         set default [$param getPropertyValue default_value]
  1120.         if {$default != ""} {
  1121.                     if [default_value_allowed [get_parameters $oper] $param] {
  1122.             $h_sect append " = $default"
  1123.                     } else {
  1124.                         puts "WARNING: default value for parameter\
  1125.                             '[$param getName]' of\
  1126.                             '[$class getName]::[$oper getName]()' is not\n   \
  1127.                 generated since this parameter is followed by parameters\
  1128.                             without\n    default values"
  1129.                     }
  1130.         }
  1131.     }
  1132.     if {!$is_abstract} {
  1133.         set first 1
  1134.         foreach param [get_parameters $oper] {
  1135.             generate $param $tmp_c_sect first
  1136.         }
  1137.         $tmp_c_sect append ")"
  1138.     }
  1139.     $h_sect append ")"
  1140.     set constStr ""
  1141.     if {[$oper isConstFunc] == "1"} {
  1142.         global cpp_error_state
  1143.         if $is_static {
  1144.             puts "ERROR: static member function '[$class getName]::${name}()' cannot be const"
  1145.             set cpp_error_state 1
  1146.         }
  1147.         if $is_ctor {
  1148.             puts "ERROR: constructor of class '[$class getName]' cannot be const"
  1149.             set cpp_error_state 1
  1150.         }
  1151.         set constStr " const"
  1152.         $h_sect append " const"
  1153.         if {!$is_abstract} {
  1154.             $tmp_c_sect append " const"
  1155.         }
  1156.     }
  1157.     if {$is_abstract} {
  1158.         $h_sect append " = 0"
  1159.     }
  1160.     $h_sect append ";\n"
  1161.  
  1162.     $c_sect appendSect $tmp_c_sect
  1163.     set method_type [$tmp_c_sect contents]
  1164.  
  1165.     if $is_abstract {
  1166.         return
  1167.     }
  1168.  
  1169.     # $c_sect append "\n"
  1170.     set impl_proc [string trim [$oper getPropertyValue method_impl]]
  1171.     if {$impl_proc == ""} {
  1172.         # get previously prepared body
  1173.         if $is_type_conv {
  1174.             get_method_body "operator $type" "()$constStr" $c_sect \
  1175.                                         "operator_[[$oper ooplType] getName]"
  1176.         } else {
  1177.             get_method_body $name $method_type $c_sect \
  1178.                                         [$oper getName]
  1179.         }
  1180.     } else {
  1181.         set impl_proc operation::$impl_proc
  1182.         if {[info procs $impl_proc] != ""} {
  1183.             $c_sect append "\n\{\n"
  1184.             $c_sect indent +
  1185.             $c_sect append [$impl_proc $oper $class $c_sect]
  1186.             $c_sect indent -
  1187.             $c_sect append "\}\n\n"
  1188.             regen_unset $name $method_type
  1189.         } else {
  1190.             puts stderr "WARNING: Tcl procedure " nonewline
  1191.             puts stderr "'$impl_proc' not found"
  1192.             # fall back to regeneration
  1193.             if $is_type_conv {
  1194.                 get_method_body "operator $type" "()$constStr" $c_sect \
  1195.                                                 "operator_[[$oper ooplType] getName]"
  1196.             } else {
  1197.                 get_method_body $name $method_type $c_sect \
  1198.                                                 [$oper getName]
  1199.             }
  1200.         }
  1201.     }
  1202. }
  1203.  
  1204. proc parameter::generate {param sect f} {
  1205.     upvar $f first
  1206.  
  1207.     if $first {
  1208.         set first 0
  1209.     } else {
  1210.         $sect append ", "
  1211.     }
  1212.     # if modifier is 'Value' then include else forward
  1213.     # (is there a better way to do this?)
  1214.     set type [$param ooplType]
  1215.     set mf [$type getPropertyValue modifier]
  1216.     if {$mf == "Value"} {
  1217.         set dc inc
  1218.     } else {
  1219.         set dc fwd
  1220.     }
  1221.     $sect append "[generate [$param ooplType] $dc][$param getName]"
  1222. }
  1223.  
  1224. proc base_type::generate {type decl {modifier ""} {default_modifier ""}} {
  1225.     set result [$type getType3GL]
  1226.     if [regexp {(var)?char\[[0-9][0-9]*]} $result] {
  1227.         return [gen_modifier "char" $type $modifier "Pointer to Const"]
  1228.     }
  1229.     if {$default_modifier == ""} {
  1230.         set default_modifier Value
  1231.     }
  1232.     return [gen_modifier $result $type $modifier $default_modifier]
  1233. }
  1234.  
  1235. proc base_type::gen_var_decl {type name {col ""}} {
  1236.     set type [$type getType3GL]
  1237.     if [regsub {(var)?char\[} $type "char $name\[" type] {
  1238.         regexp {\[(.*)\]$} $type dummy index
  1239.         set index [expr {$index + 1}]
  1240.         regsub {\[(.*)\]$} $type "\[$index]" type
  1241.         return $type
  1242.     }
  1243.     return "$type $name"
  1244. }
  1245.  
  1246. proc class_type::generate {type decl {modifier ""} {default_modifier ""}} {
  1247.     set name [$type getName]
  1248.     if {$name == ""} {
  1249.         return "void "
  1250.     }
  1251.     if {$decl == "fwd"} {
  1252.         add_forward $type
  1253.         add_src_inc $type
  1254.     } else {
  1255.         add_hdr_inc $type
  1256.     }
  1257.     if {$default_modifier == ""} {
  1258.         global default_type_modifier
  1259.         set default_modifier $default_type_modifier
  1260.     }
  1261.     return [gen_modifier $name $type $modifier $default_modifier]
  1262. }
  1263.  
  1264. proc class_type::gen_var_decl {type name {col ""}} {
  1265.     add_forward $type
  1266.     return "[$type getName] $name"
  1267. }
  1268.  
  1269. proc typedef_type::generate {type decl {modifier ""} {default_modifier ""}} {
  1270.     if [type_is_char_array $type] {
  1271.         return [base_type::generate $type $decl $modifier $default_modifier]
  1272.     }
  1273.     set name [$type getName]
  1274.     if {$name == ""} {
  1275.         return "void "
  1276.     }
  1277.     add_hdr_inc $type
  1278.     if {$default_modifier == ""} {
  1279.             if {[$type getType3GL] == ""} {
  1280.         global default_type_modifier
  1281.         set default_modifier $default_type_modifier
  1282.             } else {
  1283.                 set default_modifier Value
  1284.             }
  1285.     }
  1286.     return [gen_modifier $name $type $modifier $default_modifier]
  1287. }
  1288.  
  1289. proc typedef_type::gen_var_decl {type name {col ""}} {
  1290.     add_hdr_inc $type
  1291.     return "[$type getName] $name"
  1292. }
  1293.  
  1294. proc enum_type::generate {type decl {modifier ""} {default_modifier ""}} {
  1295.     set name [$type getName]
  1296.     if {$name == ""} {
  1297.         return "void "
  1298.     }
  1299.     add_hdr_inc $type
  1300.     if {$default_modifier == ""} {
  1301.         set default_modifier Value
  1302.     }
  1303.     return [gen_modifier $name $type $modifier $default_modifier]
  1304. }
  1305.  
  1306. proc enum_type::gen_var_decl {type name {col ""}} {
  1307.     add_hdr_inc $type
  1308.         if {$col != ""} {
  1309.             return "[$col getType3GL] $name"
  1310.         }
  1311.     return "[$type getName] $name"
  1312. }
  1313.  
  1314. proc generic_typedef_type::generate {type decl {modifier ""} {default_modifier ""}} {
  1315.     set name [$type getName]
  1316.     if {$name == ""} {
  1317.         return "void "
  1318.     }
  1319.     add_hdr_inc $type
  1320.     if {$default_modifier == ""} {
  1321.         global default_type_modifier
  1322.         set default_modifier $default_type_modifier
  1323.     }
  1324.     return [gen_modifier $name $type $modifier $default_modifier]
  1325. }
  1326.  
  1327. proc generic_typedef_type::gen_var_decl {type name {col ""}} {
  1328.     add_hdr_inc $type
  1329.     return "[$type getName] $name"
  1330. }
  1331.  
  1332. proc gen_modifier {name type modifier default_modifier} {
  1333.     if {$modifier != "Other" && $modifier != "" && \
  1334.                     [$type getPropertyValue other_modifier] != ""} {
  1335.         puts -nonewline "WARNING: type '$name' has Type Modifier "
  1336.         puts -nonewline "'$modifier'; ignoring Other Type Modifier "
  1337.         puts "'[$type getPropertyValue other_modifier]'"
  1338.     }
  1339.     case $modifier in {
  1340.         {Default ""}
  1341.         {
  1342.             set mf [$type getPropertyValue modifier]
  1343.             if {$mf != "" && $mf != "Default"} {
  1344.                 return [gen_modifier $name $type \
  1345.                             $mf $default_modifier]
  1346.             }
  1347.             if {[$type getPropertyValue other_modifier] != ""} {
  1348.                 puts stdout "WARNING: type '$name' has both 'Default' and 'Other Type Modifier' specified, using 'Other Type Modifier'"
  1349.                 return [gen_modifier $name $type \
  1350.                             Other $default_modifier]
  1351.             }
  1352.         }
  1353.         {Reference} {return "$name &"}
  1354.         {"Reference to Const"} {return "const $name &"}
  1355.         {Pointer} {return "$name *"}
  1356.         {"Pointer to Const"} {return "const $name *"}
  1357.         {Value} {return "$name "}
  1358.         {Other}
  1359.         {
  1360.             set omf [$type getPropertyValue other_modifier]
  1361.             if {$omf != ""} {
  1362.                 if [string match {*~$name*} $omf] {
  1363.                     set sect [TextSection new]
  1364.                     expand_text $sect $omf name $name
  1365.                     set result [$sect contents]
  1366.                     return $result
  1367.                 }
  1368.                 return "$name [$type getPropertyValue other_modifier] "
  1369.             }
  1370.         }
  1371.     }
  1372.     return [gen_modifier $name $type $default_modifier ""]
  1373. }
  1374.  
  1375.  
  1376. # Determine if all initializers for a class refer to a part of the key
  1377. # This is done by comparing the signature of all keys with that of all
  1378. # creation parameters
  1379. #
  1380. proc all_inits_are_keys {class} {
  1381.     set ctor_list ""
  1382.     foreach ct_param [$class fullCreationParamSet] {
  1383.         lappend ctor_list [[$ct_param ooplType] getType3GL]
  1384.     }
  1385.     set key_list ""
  1386.     foreach key [get_col_list [$class table] KEYS] {
  1387.         if {[$key getUniqueName] != $TYPE_ID_NM} {
  1388.             lappend key_list [$key getType3GL]
  1389.         }
  1390.     }
  1391.     return [expr {$ctor_list == $key_list}]
  1392. }
  1393.  
  1394. # test if a operation signature equals the
  1395. # database-runtime-constructor
  1396. #
  1397. proc is_eq_db_ctor {oper class} {
  1398.     set is_db [is_db_class $class]
  1399.     # easy tests first
  1400.     if {! $is_db || [$oper getName] != "create"}  {
  1401.         return 0
  1402.     }
  1403.     if {[$oper get_obj_type] == "constructor"} {
  1404.         set params [$class fullCreationParamSet]
  1405.     } else {
  1406.         set params [get_parameters $oper]
  1407.     }
  1408.     set keys [get_col_list [$class table] KEYS]
  1409.     # number of parameters must be equal
  1410.     # correct for extra key
  1411.     set lp [llength $params]
  1412.     incr lp
  1413.     if {$lp != [llength $keys]} {
  1414.         return 0
  1415.     }
  1416.     foreach param $params {
  1417.         set key [lvarpop keys]
  1418.         if {[$key getUniqueName] == $TYPE_ID_NM} {
  1419.             set key [lvarpop keys]
  1420.         }
  1421.         set key_t [string trim [$key getType3GL]]
  1422.         if [regexp {(var)?char\[[0-9][0-9]*]} $key_t] {
  1423.             set key_t "const char *"
  1424.         }
  1425.         set par_t [string trim [generate [$param ooplType] fwd]]
  1426.         if {$key_t != $par_t} {
  1427.             set type_obj [$param ooplType]
  1428.             if {[$type_obj get_obj_type] == "typedef_type" ||
  1429.                 [$type_obj get_obj_type] == "enum_type"} {
  1430.                 # param is typedef_type or enum_type
  1431.                 if {[$type_obj getType3GL] != $key_t} {
  1432.                                     return 0
  1433.                                 }
  1434.  
  1435.                 global default_type_modifier
  1436.                 set mod [$type_obj getPropertyValue modifier]
  1437.  
  1438.                                 # the default type modifier is used for the
  1439.                                 # database-runtime-constructor, so consider
  1440.                                 # param/key equal if no modifier specified
  1441.                                 if {$mod != "" && $mod != $default_type_modifier} {
  1442.                                     return 0
  1443.                 }
  1444.  
  1445.                 # OK
  1446.                 continue
  1447.             }
  1448.             return 0
  1449.         }
  1450.         # OK, continue
  1451.     }
  1452.     return 1
  1453. }
  1454.  
  1455. proc constructor::generate {ctor class} {
  1456.     global exists_ctor
  1457.     set exists_ctor 1
  1458.     set is_db [is_db_class $class]
  1459.     if {$is_db} {
  1460.         if [is_eq_db_ctor $ctor $class] {
  1461.             # it wil be generated later
  1462.             global db_ctor_is_unique
  1463.             set db_ctor_is_unique 1
  1464.             return
  1465.         }
  1466.         # we have a double ctor !
  1467.     }
  1468.     set sect $cpp_sections(h_ctor_sect)
  1469.     gen_ctor_decl $class $sect 1
  1470.     $sect append ";\n"
  1471.     set sect $cpp_sections(c_ctor_init_sect)
  1472.     $sect append [$class getName]::
  1473.     gen_ctor_decl $class $sect 0
  1474.     $sect indent +
  1475.     if $is_db {
  1476.         gen_ctor_sep $sect
  1477.         $sect append "DBObject([$class getName]Str)"
  1478.     }
  1479.     set body $cpp_sections(c_ctor_body_sect)
  1480.     if $is_db {
  1481.         set table [$class table]
  1482.         gen_col_list $body $table NULL_AND_NO_INIT nullInd. " = -1;\n" ""
  1483.         gen_col_list $body $table NOT_NULL_OR_INIT nullInd. " = 0;\n" ""
  1484.         $body append "strcpy(data.$TYPE_ID_NM, getClassName());\n"
  1485.     }
  1486.     foreach init [$ctor fullInitializerSet] {
  1487.         generate $init $sect $body
  1488.     }
  1489. }
  1490.  
  1491. #
  1492. # Check if the given parameter is allowed to have a default value.
  1493. #
  1494. # This is the case if all parameters following this one have default values.
  1495. #
  1496. proc default_value_allowed {paramlist param} {
  1497.     set i [lsearch $paramlist $param]
  1498.     if {$i != -1} {
  1499.     foreach p [lrange $paramlist $i end] {
  1500.             if {[$p getPropertyValue default_value] == ""} {
  1501.                 return 0
  1502.             }
  1503.     }
  1504.     }
  1505.     return 1
  1506. }
  1507.  
  1508. proc gen_ctor_decl {class sect with_default} {
  1509.     set class_nm [$class getName]
  1510.     $sect append "${class_nm}"
  1511.     set tmp_sect [TextSection new]
  1512.     $tmp_sect append "("
  1513.     set first 1
  1514.     foreach param [$class fullCreationParamSet] {
  1515.         ctor_param::generate $param $tmp_sect first
  1516.         set default [$param getPropertyValue default_value]
  1517.         if {$with_default && $default != "" &&
  1518.                     [default_value_allowed [$class fullCreationParamSet] $param]} {
  1519.             $tmp_sect append " = $default"
  1520.         }
  1521.     }
  1522.     $tmp_sect append ")"
  1523.     $sect appendSect $tmp_sect
  1524.     set method_type [$tmp_sect contents]
  1525.     ### quick hack
  1526.     global re_found_ctor
  1527.     if {$with_default && $re_found_ctor} {
  1528.         regen_unset $class_nm $method_type
  1529.     }
  1530. }
  1531.  
  1532. proc ctor_param::generate {param sect f} {
  1533.     upvar $f first
  1534.     if $first {
  1535.         set first 0
  1536.     } else {
  1537.         $sect append ", "
  1538.     }
  1539.     set type [$param ooplType]
  1540.     set mf [$type getPropertyValue modifier]
  1541.     if {$mf == "Value"} {
  1542.         set dc inc
  1543.     } else {
  1544.         set dc fwd
  1545.     }
  1546.  
  1547.         #
  1548.         # Check if this ctor param was generated because of a non-nullable
  1549.         # data attribute; if so, it must be added as a "const &" argument
  1550.         # to the constructor.  But only if it doesn't have a 3gl type,
  1551.         # because in this case the actual C++ type is a basic type.
  1552.         #
  1553.         if {[$param attrib] != "" && [$type getType3GL] == ""} {
  1554.         $sect append [generate $type $dc "" "Reference to Const"]
  1555.         } else {
  1556.         $sect append [generate $type $dc]
  1557.         }
  1558.  
  1559.     $sect append [$param getName]
  1560. }
  1561.  
  1562. proc attrib_init::generate {init init_sect body_sect} {
  1563.     ### hack !?
  1564.     set data_struct 0
  1565.     set attrib [$init attrib]
  1566.     if {[$attrib get_obj_type] == "db_data_attrib"} {
  1567.         set tgt "data.[[$attrib column] getUniqueName]"
  1568.         set data_struct 1
  1569.     } else {
  1570.         set tgt [$attrib getName]
  1571.     }
  1572.     if [type_is_char_array [$attrib ooplType]] {
  1573.                 add_[determine_sect_type $body_sect]_inc_name "string" "h"
  1574.         $body_sect append "strcpy($tgt, [$init getName]);\n"
  1575.     } else {
  1576.         if $data_struct {
  1577.             $body_sect append "$tgt = [$init getName];\n"
  1578.             return
  1579.         }
  1580.         append_ctor_init $tgt [$init getName]
  1581.     }
  1582. }
  1583.  
  1584. proc assoc_init::generate {init init_sect body_sect} {
  1585.     gen_initializer [$init assoc] $init_sect \
  1586.         $body_sect [$init getName]
  1587. }
  1588.  
  1589. proc qual_init::generate {init init_sect body_sect} {
  1590.     set qual [$init qualifier]
  1591.     set from [$init getName]
  1592.     if {[$qual get_obj_type] == "db_qualifier"} {
  1593.         set to data.[[$qual column] getUniqueName]
  1594.         $body_sect append \
  1595.             "[assign_var $to $from [$qual ooplType] $body_sect]\n"
  1596.     }
  1597.     # non-db qualifier does not need initialization
  1598. }
  1599.  
  1600. proc sc_init::generate {init sect unused_sect} {
  1601.     gen_ctor_sep $sect
  1602.     $sect append "[[$init ooplClass] getName]("
  1603.     set nm_list ""
  1604.     foreach param [$init fullParameterSet] {
  1605.         lappend nm_list [$param getName]
  1606.     }
  1607.     $sect append "[join $nm_list ", "])"
  1608. }
  1609.  
  1610. proc inher_key_init::generate {init init_sect body_sect} {
  1611.     set col [$init key]
  1612.     set name [$col getUniqueName]
  1613.     if {$name == $TYPE_ID_NM} {
  1614.         return
  1615.     }
  1616.     set class_nm [[$init ooplClass] getName]
  1617.     set base_name [$col getForeignName]
  1618.  
  1619.     $body_sect append \
  1620.         "[assign_var data.$name $class_nm::data.$base_name $col $body_sect]\n"
  1621. }
  1622.  
  1623.  
  1624. # Generate code to call func for all bases
  1625. #
  1626. proc call_for_all_bases {class sect func} {
  1627.     set supers [$class genNodeSet]
  1628.     if [lempty $supers] {
  1629.         return
  1630.     }
  1631.     $sect append "\n"
  1632.     $sect indent +
  1633.     foreach super $supers {
  1634.         set name [$super getSuperClassName]
  1635.         expand_text $sect {
  1636.             if (~$name::~${func}() < 0)
  1637.                 return -1;
  1638.         }
  1639.     }
  1640.     $sect indent -
  1641. }
  1642.  
  1643. proc get_root_class {class} {
  1644.     set supers [$class genNodeSet]
  1645.     if [lempty $supers] {
  1646.         return $class
  1647.     }
  1648.     return [get_root_class [[lindex $supers 0] superClass]]
  1649. }
  1650.  
  1651. proc rv_link_attrib::generate {attrib class} {
  1652.     # multiplicity should always be 'one' here
  1653.     gen_for_rv_link $attrib $class
  1654. }
  1655.  
  1656. proc rv_link_attrib::one_data {attrib} {
  1657.     if [info exists cpp_sections(h_priv_data_assoc-storage_sect)] {
  1658.         set sect $cpp_sections(h_priv_data_assoc-storage_sect)
  1659.     } else {
  1660.         set sect $cpp_sections(h_priv_data_sect)
  1661.     }
  1662.     set type [[$attrib ooplType] getName]
  1663.     set name [reference_name [$attrib getName]]
  1664.     $sect append "$type& $name;\n"
  1665. }
  1666.  
  1667. proc rv_link_attrib::one_get {attrib class} {
  1668.     set type [[$attrib ooplType] getName]
  1669.     set name [$attrib getName]
  1670.     set cl_name [$class getName]
  1671.     if [info exists cpp_sections(h_pub_func_assoc-access_sect)] {
  1672.         set sect $cpp_sections(h_pub_func_assoc-access_sect)
  1673.     } else {
  1674.         set sect $cpp_sections(h_pub_func_sect)
  1675.     }
  1676.     $sect append "$type& get[cap $name]() const;\n"
  1677.     set sect $cpp_sections(h_inl_sect)
  1678.     $sect append "inline $type& $cl_name::get[cap $name]"
  1679.     set ref_name [reference_name $name]
  1680.     $sect append "() const\n\{\n\treturn $ref_name;\n\}\n\n";
  1681. }
  1682.  
  1683. proc rv_link_attrib::one_dtor {attrib class} {
  1684.     set opposite [$attrib opposite]
  1685.     if {$opposite != ""} {
  1686.         set ref [reference_name [$attrib getName]]
  1687.         set sect $cpp_sections(c_dtor_sect)
  1688.         rm_other $opposite $sect $ref
  1689.     }
  1690. }
  1691.  
  1692. proc qual_link_attrib::generate {attrib class} {
  1693.     gen_for_link $attrib $class
  1694. }
  1695.  
  1696. proc qual_link_attrib::one_data {attrib} {
  1697.     if [info exists cpp_sections(h_priv_data_assoc-storage_sect)] {
  1698.         set sect $cpp_sections(h_priv_data_assoc-storage_sect)
  1699.     } else {
  1700.         set sect $cpp_sections(h_priv_data_sect)
  1701.     }
  1702.     set type [dict_type_name [[$attrib qualifier] ooplType] \
  1703.                  [$attrib ooplType]]
  1704.     set name [uncap [dict_name \
  1705.         "[[$attrib ooplType] getName]Of[cap [$attrib getName]]"]]
  1706.     $sect append "$type $name;\n"
  1707.     set sect $cpp_sections(c_ctor_init_sect)
  1708.     set key [[$attrib qualifier] ooplType]
  1709.     set value [$attrib ooplType]
  1710.     set result [dict::initializer $name $key $value]
  1711.     if {$result == ""} {
  1712.         return
  1713.     }
  1714.     gen_ctor_sep $sect
  1715.     $sect append $result
  1716. }
  1717.  
  1718. proc qual_link_attrib::one_rm_other {attrib sect ref} {
  1719.     set name [uncap [dict_name \
  1720.         [[$attrib ooplType] getName]Of[cap [$attrib getName]]]]
  1721.     $sect append "$ref.$name.${dict::remove}(/* supply key here */);\n"
  1722. }
  1723.  
  1724. proc qual_link_attrib::one_set_other {attrib sect ref} {
  1725.     set name [uncap [dict_name \
  1726.         [[$attrib ooplType] getName]Of[cap [$attrib getName]]]]
  1727.     set qual [[$attrib qualifier] getName]
  1728.     $sect append "$ref.$name.${dict::set}($qual, this);\n"
  1729. }
  1730.  
  1731. proc qual_link_attrib::one_get {attrib class} {
  1732.     set type [[$attrib ooplType] getName]
  1733.     set name [cap [[$attrib ooplType] getName]Of[cap [$attrib getName]]]
  1734.     set key [get_qualifier_name $attrib]
  1735.     set q_type [get_qualifier_type $attrib "Reference to Const"]
  1736.     set cl_name [$class getName]
  1737.     set sect [get_assoc_hdr_sect $attrib r]
  1738.     $sect append "$type *get${name}($q_type$key) const;\n"
  1739.     set sect [get_assoc_src_sect $attrib 1 r]
  1740.     $sect append "inline $type *$cl_name::get${name}"
  1741.     $sect append "($q_type$key) const\n\{\n"
  1742.     set dct_name [uncap [dict_name $name]]
  1743.     $sect indent +
  1744.     dict::get_and_return $sect $dct_name $key $type
  1745.     $sect indent -
  1746.     $sect append "\}\n\n"
  1747. }
  1748.  
  1749. proc qual_link_attrib::many_data {attrib} {
  1750.     if [info exists cpp_sections(h_priv_data_assoc-storage_sect)] {
  1751.         set sect $cpp_sections(h_priv_data_assoc-storage_sect)
  1752.     } else {
  1753.         set sect $cpp_sections(h_priv_data_sect)
  1754.     }
  1755.     set setpfx [set_prefix $attrib]
  1756.     set type [${setpfx}set_dict_type_name \
  1757.         [[$attrib qualifier] ooplType] [$attrib ooplType]]
  1758.     set name [uncap [${setpfx}set_dict_name \
  1759.         [[$attrib ooplType] getName]Of[cap [$attrib getName]]]]
  1760.     $sect append "$type $name;\n"
  1761.     set sect $cpp_sections(c_ctor_init_sect)
  1762.     set key [[$attrib qualifier] ooplType]
  1763.     set value [$attrib ooplType]
  1764.     set result [${setpfx}psdict::initializer $name $key $value]
  1765.     if {$result == ""} {
  1766.         return
  1767.     }
  1768.     gen_ctor_sep $sect
  1769.     $sect append $result
  1770. }
  1771.  
  1772. proc qual_link_attrib::many_get {attrib class} {
  1773.     set setpfx [set_prefix $attrib]
  1774.     set type [${setpfx}set_type_name [$attrib ooplType]]
  1775.     set name [cap [[$attrib ooplType] getName]Of[cap [$attrib getName]]]
  1776.     set key [get_qualifier_name $attrib]
  1777.     set q_type [get_qualifier_type $attrib "Reference to Const"]
  1778.     set cl_name [$class getName]
  1779.     set sect [get_assoc_hdr_sect $attrib r]
  1780.     $sect append "$type *get${name}($q_type$key) const;\n"
  1781.     set sect [get_assoc_src_sect $attrib 1 r]
  1782.     $sect append "inline $type *$cl_name::get${name}"
  1783.     $sect append "($q_type$key) const\n\{\n"
  1784.     $sect indent +
  1785.     ${setpfx}psdict::get_and_return $sect $name $key $type
  1786.     $sect indent -
  1787.     $sect append "\}\n\n"
  1788. }
  1789.  
  1790. proc qual_link_attrib::many_set_other {attrib sect ref} {
  1791.     set type [[$attrib ooplType] getName]
  1792.     set name [cap "${type}Of[cap [$attrib getName]]"]
  1793.     set qual [[$attrib qualifier] getName]
  1794.     set setpfx [set_prefix $attrib]
  1795.     set s_name [uncap [${setpfx}set_dict_name $name]]
  1796.     set add_func [set ${setpfx}psdict::add]
  1797.     $sect append "$ref.$s_name.${add_func}($qual, this);\n"
  1798. }
  1799.  
  1800. proc qual_link_attrib::many_rm_other {attrib sect ref} {
  1801.     set type [[$attrib ooplType] getName]
  1802.     set name [cap "${type}Of[cap [$attrib getName]]"]
  1803.     set setpfx [set_prefix $attrib]
  1804.     set s_name [uncap [${setpfx}set_dict_name $name]]
  1805.     set remove_func [set ${setpfx}psdict::remove]
  1806.     $sect append \
  1807.         "$ref.$s_name.${remove_func}(/* supply key here */, this);\n"
  1808. }
  1809.  
  1810. proc link_attrib::generate {attrib class} {
  1811.     gen_for_link $attrib $class
  1812. }
  1813.  
  1814. proc link_attrib::one_data {attrib} {
  1815.     if [info exists cpp_sections(h_priv_data_assoc-storage_sect)] {
  1816.         set sect $cpp_sections(h_priv_data_assoc-storage_sect)
  1817.     } else {
  1818.         set sect $cpp_sections(h_priv_data_sect)
  1819.     }
  1820.  
  1821.     set type [[$attrib ooplType] getName]
  1822.     set name [uncap [pointer_name "${type}Of[cap [$attrib getName]]"]]
  1823.     $sect append "$type *$name;\n"
  1824. }
  1825.  
  1826. proc link_attrib::one_get {attrib class} {
  1827.     set type [[$attrib ooplType] getName]
  1828.     set name [cap "${type}Of[cap [$attrib getName]]"]
  1829.     set cl_name [$class getName]
  1830.     set sect [get_assoc_hdr_sect $attrib r]
  1831.     $sect append "$type *get${name}() const;\n"
  1832.     set sect [get_assoc_src_sect $attrib 1 r]
  1833.     $sect append "inline $type *$cl_name::get${name}"
  1834.     set ptr_name [uncap [pointer_name $name]]
  1835.     $sect append "() const\n\{\n\treturn $ptr_name;\n\}\n\n";
  1836. }
  1837.  
  1838. proc link_attrib::one_rm_other {attrib sect ref} {
  1839.     set type [[$attrib ooplType] getName]
  1840.     set name [cap "${type}Of[cap [$attrib getName]]"]
  1841.     set ptr_name [uncap [pointer_name $name]]
  1842.     $sect append "$ref.$ptr_name = 0;\n"
  1843. }
  1844.  
  1845. proc link_attrib::one_set_other {attrib sect ref} {
  1846.     set type [[$attrib ooplType] getName]
  1847.     set name [cap "${type}Of[cap [$attrib getName]]"]
  1848.     set ptr_name [uncap [pointer_name $name]]
  1849.     $sect append "$ref.$ptr_name = this;\n"
  1850. }
  1851.  
  1852. proc link_attrib::many_data {attrib} {
  1853.     if [info exists cpp_sections(h_priv_data_assoc-storage_sect)] {
  1854.         set sect $cpp_sections(h_priv_data_assoc-storage_sect)
  1855.     } else {
  1856.         set sect $cpp_sections(h_priv_data_sect)
  1857.     }
  1858.     set setpfx [set_prefix $attrib]
  1859.     set type [${setpfx}set_type_name [$attrib ooplType]]
  1860.     set name [uncap [${setpfx}set_name "[[$attrib ooplType] getName]Of[cap [$attrib getName]]"]]
  1861.     $sect append "$type $name;\n"
  1862. }
  1863.  
  1864. proc link_attrib::many_get {attrib class} {
  1865.     set setpfx [set_prefix $attrib]
  1866.     set type [${setpfx}set_type_name [$attrib ooplType]]
  1867.     set name [cap [${setpfx}set_name "[[$attrib ooplType] getName]Of[cap [$attrib getName]]"]]
  1868.     set cl_name [$class getName]
  1869.     set sect [get_assoc_hdr_sect $attrib r]
  1870.     $sect append "const $type& get${name}() const;\n"
  1871.     set sect [get_assoc_src_sect $attrib 1 r]
  1872.     $sect append "inline const $type& $cl_name::"
  1873.     $sect append "get${name}() const\n\{\n\treturn [uncap $name];\n\}\n\n"
  1874. }
  1875.  
  1876. proc link_attrib::many_set_other {attrib sect ref} {
  1877.     set type [[$attrib ooplType] getName]
  1878.     set name [cap "${type}Of[cap [$attrib getName]]"]
  1879.     set setpfx [set_prefix $attrib]
  1880.     set s_name [uncap [${setpfx}set_name $name]]
  1881.     set add_func [set ${setpfx}set::add]
  1882.     $sect append "$ref.$s_name.${add_func}(this);\n"
  1883. }
  1884.  
  1885. proc link_attrib::many_rm_other {attrib sect ref} {
  1886.     set type [[$attrib ooplType] getName]
  1887.     set name [cap "${type}Of[cap [$attrib getName]]"]
  1888.     set setpfx [set_prefix $attrib]
  1889.     set s_name [uncap [${setpfx}set_name $name]]
  1890.     set remove_func [set ${setpfx}set::remove]
  1891.     $sect append "$ref.$s_name.${remove_func}(this);\n"
  1892. }
  1893.  
  1894. proc assoc_attrib::gen_initializer {attrib init_s body_s name} {
  1895.     gen_ctor_sep $init_s
  1896.     set ptrname [uncap [pointer_name [$attrib getName]]]
  1897.     $init_s append ${ptrname}(&[$attrib getName])
  1898.     set opposite [$attrib opposite]
  1899.     if {$opposite != ""} {
  1900.         set_other $opposite $body_s $ptrname
  1901.     }
  1902. }
  1903.  
  1904. proc rv_link_attrib::gen_initializer {attrib init_s body_s name} {
  1905.     gen_ctor_sep $init_s
  1906.     set refname [uncap [reference_name [$attrib getName]]]
  1907.     $init_s append ${refname}([$attrib getName])
  1908.     set opposite [$attrib opposite]
  1909.     if {$opposite != ""} {
  1910.         set_other $opposite $body_s $refname
  1911.         add_src_inc [$attrib ooplType]
  1912.     }
  1913. }
  1914.  
  1915. # Generate a C++ parameter declaration
  1916. #
  1917. proc gen_param_decl_cxx {section object selector {separator ", "}
  1918.                {newline ""}} {
  1919.  
  1920.     gen_param_decl_cxx_c $section [get_col_list $object $selector] \
  1921.                 $separator $newline
  1922. }
  1923.  
  1924. proc gen_param_decl_cxx_c {section columns {separator ", "} {newline ""}} {
  1925.  
  1926.     if [lempty $columns] {
  1927.         return
  1928.     }
  1929.     set col [lvarpop columns]
  1930.     $section pushIndent
  1931.     $section append "[base_type::generate $col Value][$col getUniqueName]"
  1932.     set newpf $separator$newline
  1933.     foreach col $columns {
  1934.         $section append \
  1935.               "$newpf[base_type::generate $col Value][$col getUniqueName]"
  1936.     }
  1937.     $section popIndent
  1938.     $section append $newline
  1939. }
  1940.  
  1941. # Generate a check for the nullability of the columns of a link.  These columns
  1942. # are either ALL null or ALL not null, so it suffices to check only the
  1943. # first column.
  1944. #
  1945. proc gen_null_check {sect link ind_var {ret_val 0}} {
  1946.     set col [lindex [$link columnSet] 0]
  1947.     if {$ret_val == ""} {
  1948.         set space ""
  1949.     } else {
  1950.         set space " "
  1951.     }
  1952.     expand_text $sect {
  1953.         if (~$ind_var~[$col getUniqueName] == -1)
  1954.             return~${space}~$ret_val;
  1955.     }
  1956. }
  1957.  
  1958. proc is_db_class {class} {
  1959.     return [string match {db_*} [$class get_obj_type]]
  1960. }
  1961.  
  1962. proc class2tgtfiles {class src inc} {
  1963.     upvar $src src_f
  1964.     upvar $inc inc_f
  1965.     set is_db [is_db_class $class]
  1966.     if {$is_db} {
  1967.         set src_type $esqlcplus_type
  1968.     } else {
  1969.         set src_type $cplus_type
  1970.     }
  1971.     set class_name [class2file [$class getName]]
  1972.     set src_f $class_name.$src_type
  1973.     set inc_f $class_name.$hplus_type
  1974. }
  1975.  
  1976. # we want    'class_typedef'
  1977. #      or    'class_enum'
  1978. #      or    'class_generic_typedef'
  1979. proc is_special_class {class} {
  1980.     return [string match {*class_*} [$class get_obj_type]]
  1981. }
  1982.  
  1983. #
  1984. # Function to determine if a class can have subclasses.
  1985. #
  1986. # - for an class_enum this is never the case since it's not possible in
  1987. #   C++;
  1988. #
  1989. # - for a class_typedef this is so if the "source" type is a real class and
  1990. #   not a standard type;
  1991. #
  1992. # - for a class_generic_typedef this is so if the "source" type is a container
  1993. #   class, i.e. if its assoc attrib has multiplicity many or is qualified.
  1994. #
  1995. proc is_derivable_class {class} {
  1996.     switch [$class get_obj_type] {
  1997.         "class_enum" {
  1998.             return 0
  1999.         }
  2000.         "class_typedef" {
  2001.         set attrib [lindex [$class dataAttrSet] 0]
  2002.         if {[[$attrib ooplType] getType3GL] == ""} {
  2003.         return 1
  2004.         } else {
  2005.         return 0
  2006.             }
  2007.         }
  2008.         "class_generic_typedef" {
  2009.         set assoc [lindex [$class genAssocAttrSet] 0]
  2010.         if {[$assoc getMultiplicity] == "many" ||
  2011.         [string match {qual_*} [$assoc get_obj_type]]} {
  2012.         return 1
  2013.         } else {
  2014.         return 0
  2015.             }
  2016.     }
  2017.         default {
  2018.             return 1
  2019.         }
  2020.     }
  2021. }
  2022.  
  2023.  
  2024. global opermap
  2025. set opermap(operatorDIV)        operator/
  2026. set opermap(operatorASSIGN)        operator=
  2027. set opermap(operatorASS_PLUS)        operator+=
  2028. set opermap(operatorASS_MIN)        operator-=
  2029. set opermap(operatorASS_STAR)        operator*=
  2030. set opermap(operatorASS_DIV)        operator/=
  2031. set opermap(operatorASS_MOD)        operator%=
  2032. set opermap(operatorASS_CIRCUM)        operator^=
  2033. set opermap(operatorASS_AMPER)        operator&=
  2034. set opermap(operatorASS_PIPE)        operator|=
  2035. set opermap(operatorASS_LSHIFT)        operator<<=
  2036. set opermap(operatorASS_RSHIFT)        operator>>=
  2037. set opermap(operatorEQ)            operator==
  2038. set opermap(operatorNEQ)        operator!=
  2039. set opermap(operatorLE)            operator<=
  2040. set opermap(operatorGE)            operator>=
  2041. set opermap(operatorCOMMA)        operator,
  2042. set opermap(operatornew)        "operator new"
  2043. set opermap(operatordelete)        "operator delete"
  2044. set opermap(operatorFUNC)        operator()
  2045.  
  2046. proc map_oper {name} {
  2047.     if [info exists opermap($name)] {
  2048.         return $opermap($name)
  2049.     }
  2050.     return $name
  2051. }
  2052.  
  2053. # return set prefix "o" in case ordered set are needed
  2054. #
  2055. proc set_prefix {attrib} {
  2056.     if {[$attrib isOrdered] == "1"} {
  2057.         return o
  2058.     } else {
  2059.         return
  2060.     }
  2061. }
  2062.