1 // Copyright (c) 1994 James Clark
2 // See the file COPYING for copying permission.
3 
4 #ifdef __GNUG__
5 #pragma implementation
6 #endif
7 #include "splib.h"
8 #include "LinkProcess.h"
9 // ParserState is used for access to parser messages
10 #include "ParserState.h"
11 #include "MessageArg.h"
12 #include "ParserMessages.h"
13 
14 #ifdef SP_NAMESPACE
15 namespace SP_NAMESPACE {
16 #endif
17 
LinkProcess()18 LinkProcess::LinkProcess()
19 {
20 }
21 
init(const ConstPtr<ComplexLpd> & lpd)22 void LinkProcess::init(const ConstPtr<ComplexLpd> &lpd)
23 {
24   lpd_ = lpd;
25   open_.clear();
26   open_.insert(new LinkProcessOpenElement(lpd_->initialLinkSet()));
27 }
28 
startElement(const ElementType * element,const AttributeList & attributes,const Location & location,Messenger & mgr,const AttributeList * & linkAttributes,const ResultElementSpec * & resultElementSpec)29 Boolean LinkProcess::startElement(const ElementType *element,
30 				  const AttributeList &attributes,
31 				  const Location &location,
32 				  Messenger &mgr,
33 				  const AttributeList *&linkAttributes,
34 				  const ResultElementSpec *&resultElementSpec)
35 {
36   if (lpd_.isNull()) {
37     linkAttributes = 0;
38     resultElementSpec = 0;
39     return 1;
40   }
41   const StringC *id = attributes.getId();
42   if (id) {
43     const IdLinkRuleGroup *p = lpd_->lookupIdLink(*id);
44     if (p) {
45       size_t selected;
46       if (p->nLinkRules() > 1) {
47 	linkAttributes_.resize(p->nLinkRules());
48 	for (size_t i = 0; i < linkAttributes_.size(); i++)
49 	  linkAttributes_[i] = &p->linkRule(i).attributes();
50 	if (!selectLinkRule(linkAttributes_,
51 			    location,
52 			    selected))
53 	  return 0;
54       }
55       else
56 	selected = 0;
57       const IdLinkRule &rule = p->linkRule(selected);
58       open_.insert(new LinkProcessOpenElement(open_.head()->current,
59 					      rule));
60       linkAttributes = &rule.attributes();
61       resultElementSpec = &rule.resultElementSpec();
62       if (!rule.isAssociatedWith(element)) {
63 	mgr.setNextLocation(location);
64 	mgr.message(ParserMessages::idlinkElementType,
65 		    StringMessageArg(element->name()),
66 		    StringMessageArg(*id));
67       }
68       return 1;
69     }
70   }
71   const LinkSet *currentLinkSet = open_.head()->current;
72   size_t nRules = currentLinkSet->nLinkRules(element);
73   if (nRules > 0) {
74     size_t selected;
75     if (nRules > 1) {
76       linkAttributes_.resize(nRules);
77       for (size_t i = 0; i < nRules; i++)
78 	linkAttributes_[i]
79 	  = &currentLinkSet->linkRule(element, i).attributes();
80       if (!selectLinkRule(linkAttributes_,
81 			  location,
82 			  selected))
83 	return 0;
84     }
85     else
86       selected = 0;
87     const SourceLinkRule &rule = currentLinkSet->linkRule(element, selected);
88     open_.insert(new LinkProcessOpenElement(open_.head()->current,
89 					    rule));
90     linkAttributes = &rule.attributes();
91     resultElementSpec = &rule.resultElementSpec();
92     return 1;
93   }
94   // FIXME construct attributes from attribute definition list
95   linkAttributes = 0;
96   resultElementSpec = 0;
97   open_.insert(new LinkProcessOpenElement(open_.head()->current));
98   return 1;
99 }
100 
101 
endElement()102 void LinkProcess::endElement()
103 {
104   if (lpd_.isNull())
105     return;
106   LinkProcessOpenElement *top = open_.get();
107   if (top->post)
108     open_.head()->current = top->post;
109   else if (top->postRestore)
110     open_.head()->current = open_.head()->restore;
111   delete top;
112 }
113 
uselink(const LinkSet * linkSet,Boolean restore,const Lpd * lpd)114 void LinkProcess::uselink(const LinkSet *linkSet,
115 			  Boolean restore,
116 			  const Lpd *lpd)
117 {
118   if (lpd_.isNull())
119     return;
120   if (lpd != lpd_.pointer())
121     return;
122   if (restore)
123     open_.head()->current = open_.head()->restore;
124   else if (linkSet)
125     open_.head()->current = linkSet;
126 }
127 
nImpliedLinkRules() const128 size_t LinkProcess::nImpliedLinkRules() const
129 {
130   if (!open_.head())
131     return 0;
132   return open_.head()->current->nImpliedLinkRules();
133 }
134 
impliedLinkRule(size_t i) const135 const ResultElementSpec &LinkProcess::impliedLinkRule(size_t i) const
136 {
137   return open_.head()->current->impliedLinkRule(i);
138 }
139 
140 // Usually redefined by application.
141 
selectLinkRule(const Vector<const AttributeList * > &,const Location &,size_t & selected)142 Boolean LinkProcess::selectLinkRule(const Vector<const AttributeList *> &,
143 				    const Location &,
144 				    size_t &selected)
145 {
146   selected = 0;
147   return 1;
148 }
149 
clear()150 void LinkProcess::clear()
151 {
152   open_.clear();
153   lpd_.clear();
154   linkAttributes_.clear();
155 }
156 
swap(LinkProcess & to)157 void LinkProcess::swap(LinkProcess &to)
158 {
159   open_.swap(to.open_);
160   lpd_.swap(to.lpd_);
161   linkAttributes_.swap(to.linkAttributes_);
162 }
163 
LinkProcessOpenElement(const LinkSet * cur,const SourceLinkRule & rule)164 LinkProcessOpenElement::LinkProcessOpenElement(const LinkSet *cur,
165 					       const SourceLinkRule &rule)
166 {
167   current = rule.uselink();
168   if (!current)
169     current = cur;
170   restore = cur;
171   post = rule.postlink();
172   postRestore = rule.postlinkRestore();
173 }
174 
LinkProcessOpenElement(const LinkSet * cur)175 LinkProcessOpenElement::LinkProcessOpenElement(const LinkSet *cur)
176 {
177   restore = current = cur;
178   post = 0;
179   postRestore = 0;
180 }
181 
182 
183 #ifdef SP_NAMESPACE
184 }
185 #endif
186