~vcs-imports/simias/trunk

« back to all changes in this revision

Viewing changes to simias/tools/gsoap/gsoap-linux-2.7/wsdl/service.cpp

  • Committer: kalidasbala
  • Date: 2007-08-25 12:48:51 UTC
  • Revision ID: vcs-imports@canonical.com-20070825124851-vlfvzun3732ld196
Latest gsoap code update

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 
 
3
service.cpp
 
4
 
 
5
Service structures.
 
6
 
 
7
--------------------------------------------------------------------------------
 
8
gSOAP XML Web services tools
 
9
Copyright (C) 2001-2006, Robert van Engelen, Genivia Inc. All Rights Reserved.
 
10
This part of the software is released under one of the following licenses:
 
11
GPL or Genivia's license for commercial use.
 
12
--------------------------------------------------------------------------------
 
13
GPL license.
 
14
 
 
15
This program is free software; you can redistribute it and/or modify it under
 
16
the terms of the GNU General Public License as published by the Free Software
 
17
Foundation; either version 2 of the License, or (at your option) any later
 
18
version.
 
19
 
 
20
This program is distributed in the hope that it will be useful, but WITHOUT ANY
 
21
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 
22
PARTICULAR PURPOSE. See the GNU General Public License for more details.
 
23
 
 
24
You should have received a copy of the GNU General Public License along with
 
25
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 
26
Place, Suite 330, Boston, MA 02111-1307 USA
 
27
 
 
28
Author contact information:
 
29
engelen@genivia.com / engelen@acm.org
 
30
--------------------------------------------------------------------------------
 
31
A commercial use license is available from Genivia, Inc., contact@genivia.com
 
32
--------------------------------------------------------------------------------
 
33
 
 
34
TODO:   consider adding support for non-SOAP HTTP operations
 
35
        add headerfault output definitions
 
36
 
 
37
*/
 
38
 
 
39
#include "types.h"
 
40
#include "service.h"
 
41
 
 
42
static void comment(const char *start, const char *middle, const char *end, const char *text);
 
43
static void page(const char *page, const char *title, const char *text);
 
44
static void section(const char *section, const char *title, const char *text);
 
45
static void banner(const char*);
 
46
static void ident();
 
47
static void text(const char*);
 
48
 
 
49
////////////////////////////////////////////////////////////////////////////////
 
50
//
 
51
//      Definitions methods
 
52
//
 
53
////////////////////////////////////////////////////////////////////////////////
 
54
 
 
55
Definitions::Definitions()
 
56
{ }
 
57
 
 
58
void Definitions::collect(const wsdl__definitions &definitions)
 
59
{ // Collect information: analyze WSDL definitions and imported definitions
 
60
  analyze(definitions);
 
61
  for (vector<wsdl__import>::const_iterator import = definitions.import.begin(); import != definitions.import.end(); ++import)
 
62
    if ((*import).definitionsPtr())
 
63
      analyze(*(*import).definitionsPtr());
 
64
}
 
65
 
 
66
void Definitions::analyze(const wsdl__definitions &definitions)
 
67
{ // Analyze WSDL and build Service information
 
68
  int binding_count = 0;
 
69
  // Determine number of relevant SOAP service bindings
 
70
  for (vector<wsdl__binding>::const_iterator i = definitions.binding.begin(); i != definitions.binding.end(); ++i)
 
71
  { for (vector<wsdl__binding_operation>::const_iterator j = (*i).operation.begin(); j != (*i).operation.end(); ++j)
 
72
    { if ((*j).operationPtr() && (*j).input && (*j).input->soap__body_)
 
73
      { binding_count++;
 
74
        break;
 
75
      }
 
76
    }
 
77
  }
 
78
  // Analyze and collect service data
 
79
  for (vector<wsdl__binding>::const_iterator binding = definitions.binding.begin(); binding != definitions.binding.end(); ++binding)
 
80
  { // /definitions/binding/documentation
 
81
    const char *binding_documentation = (*binding).documentation;
 
82
    // /definitions/binding/soap:binding
 
83
    soap__binding *soap__binding_ = (*binding).soap__binding_;
 
84
    // /definitions/binding/soap:binding/@transport
 
85
    const char *soap__binding_transport = NULL;
 
86
    if (soap__binding_)
 
87
      soap__binding_transport = soap__binding_->transport;
 
88
    // /definitions/binding/soap:binding/@style
 
89
    soap__styleChoice soap__binding_style = rpc;
 
90
    if (soap__binding_ && soap__binding_->style)
 
91
      soap__binding_style = *soap__binding_->style;
 
92
    // /definitions/binding/http:binding
 
93
    http__binding *http__binding_ = (*binding).http__binding_;
 
94
    const char *http__binding_verb = NULL;
 
95
    if (http__binding_)
 
96
       http__binding_verb = http__binding_->verb;
 
97
    // /definitions/binding/operation*
 
98
    for (vector<wsdl__binding_operation>::const_iterator operation = (*binding).operation.begin(); operation != (*binding).operation.end(); ++operation)
 
99
    { // /definitions/portType/operation/ associated with /definitions/binding/operation
 
100
      wsdl__operation *wsdl__operation_ = (*operation).operationPtr();
 
101
      // /definitions/binding/operation/soap:operation
 
102
      soap__operation *soap__operation_ = (*operation).soap__operation_;
 
103
      // /definitions/binding/operation/soap:operation/@style
 
104
      soap__styleChoice soap__operation_style = soap__binding_style;
 
105
      if (soap__operation_ && soap__operation_->style)
 
106
        soap__operation_style = *soap__operation_->style;
 
107
      // /definitions/binding/operation/http:operation
 
108
      http__operation *http__operation_ = (*operation).http__operation_;
 
109
      // /definitions/binding/operation/http:operation/@location
 
110
      const char *http__operation_location = NULL;
 
111
      if (http__operation_)
 
112
        http__operation_location = http__operation_->location;
 
113
      // /definitions/binding/operation/input
 
114
      wsdl__ext_input *ext_input = (*operation).input;
 
115
      // /definitions/binding/operation/output
 
116
      wsdl__ext_output *ext_output = (*operation).output;
 
117
      // /definitions/portType/operation
 
118
      if (wsdl__operation_)
 
119
      { wsdl__input *input = wsdl__operation_->input;
 
120
        wsdl__output *output = wsdl__operation_->output;
 
121
        if (http__operation_)
 
122
        { // TODO: HTTP operation
 
123
        }
 
124
        else if (input && ext_input)
 
125
        { soap__body *input_body = ext_input->soap__body_;
 
126
          if (ext_input->mime__multipartRelated_)
 
127
          { for (vector<mime__part>::const_iterator part = ext_input->mime__multipartRelated_->part.begin(); part != ext_input->mime__multipartRelated_->part.end(); ++part)
 
128
              if ((*part).soap__body_)
 
129
              { input_body = (*part).soap__body_;
 
130
                break;
 
131
              }
 
132
          }
 
133
          // MUST have an input, otherwise can't generate a service operation
 
134
          if (input_body)
 
135
          { char *URI;
 
136
            if (soap__operation_style == rpc)
 
137
              URI = input_body->namespace_;
 
138
            else if (binding_count == 1)
 
139
              URI = definitions.targetNamespace;
 
140
            else
 
141
            { // multiple service bidings are used, each needs a unique new URI
 
142
              URI = (char*)soap_malloc(definitions.soap, strlen(definitions.targetNamespace) + strlen((*binding).name) + 2);
 
143
              strcpy(URI, definitions.targetNamespace);
 
144
              if (*URI && URI[strlen(URI)-1] != '/')
 
145
                strcat(URI, "/");
 
146
              strcat(URI, (*binding).name);
 
147
            }
 
148
            if (URI)
 
149
            { const char *prefix = types.nsprefix(service_prefix, URI);
 
150
              const char *name = types.aname(NULL, NULL, (*binding).name); // name of service is binding name
 
151
              Service *s = services[prefix];
 
152
              if (!s)
 
153
              { s = services[prefix] = new Service();
 
154
                s->prefix = prefix;
 
155
                s->URI = URI;
 
156
                s->name = name;
 
157
                s->transport = soap__binding_transport;
 
158
                if ((*binding).portTypePtr())
 
159
                  s->type = types.aname(NULL, NULL, (*binding).portTypePtr()->name);
 
160
                else
 
161
                  s->type = NULL;
 
162
              }
 
163
              for (vector<wsdl__service>::const_iterator service = definitions.service.begin(); service != definitions.service.end(); ++service)
 
164
              { for (vector<wsdl__port>::const_iterator port = (*service).port.begin(); port != (*service).port.end(); ++port)
 
165
                { if ((*port).bindingPtr() == &(*binding))
 
166
                  { if ((*port).soap__address_)
 
167
                      s->location.insert((*port).soap__address_->location);
 
168
                    // TODO: HTTP address for HTTP operations
 
169
                    // if ((*port).http__address_)
 
170
                      // http__address_location = http__address_->location;
 
171
                    if ((*service).documentation)
 
172
                      s->service_documentation[(*service).name] = (*service).documentation;
 
173
                    if ((*port).documentation && (*port).name)
 
174
                      s->port_documentation[(*port).name] = (*port).documentation;
 
175
                    if (binding_documentation)
 
176
                      s->binding_documentation[(*binding).name] = binding_documentation;
 
177
                  }
 
178
                }
 
179
              }
 
180
              Operation *o = new Operation();
 
181
              o->name = types.aname(NULL, NULL, wsdl__operation_->name);
 
182
              o->prefix = prefix;
 
183
              o->URI = URI;
 
184
              o->style = soap__operation_style;
 
185
              o->documentation = wsdl__operation_->documentation;
 
186
              o->operation_documentation = (*operation).documentation;
 
187
              o->parameterOrder = wsdl__operation_->parameterOrder;
 
188
              if ((*operation).soap__operation_)
 
189
                o->soapAction = (*operation).soap__operation_->soapAction;
 
190
              else
 
191
              { o->soapAction = "";
 
192
                // determine if we use SOAP 1.2 in which case soapAction is absent, this is a bit of a hack due to the lack of WSDL1.1/SOAP1.2 support and better alternatives
 
193
                for (Namespace *p = definitions.soap->local_namespaces; p && p->id; p++)
 
194
                { if (p->out && !strcmp(p->id, "soap") && !strcmp(p->out, "http://schemas.xmlsoap.org/wsdl/soap12/"))
 
195
                  { o->soapAction = NULL;
 
196
                    break;
 
197
                  }
 
198
                }
 
199
              }
 
200
              o->input = new Message();
 
201
              o->input->name = (*operation).name; // RPC uses operation/@name
 
202
              if (soap__operation_style == rpc && !input_body->namespace_)
 
203
              { o->input->URI = "";
 
204
                fprintf(stderr, "Error: no soap:body namespace attribute\n");
 
205
              }
 
206
              else
 
207
                o->input->URI = input_body->namespace_;
 
208
              o->input->use = input_body->use;
 
209
              o->input->encodingStyle = input_body->encodingStyle;
 
210
              o->input->message = input->messagePtr();
 
211
              o->input->part = NULL;
 
212
              o->input->multipartRelated = ext_input->mime__multipartRelated_;
 
213
              o->input->content = NULL;
 
214
              if (ext_input->mime__multipartRelated_ && !ext_input->mime__multipartRelated_->part.empty())
 
215
                o->input->header = ext_input->mime__multipartRelated_->part.front().soap__header_;
 
216
              else
 
217
                o->input->header = ext_input->soap__header_;
 
218
              if (ext_input->mime__multipartRelated_ && !ext_input->mime__multipartRelated_->part.empty() && ext_input->mime__multipartRelated_->part.front().soap__body_)
 
219
                o->input->body_parts = ext_input->mime__multipartRelated_->part.front().soap__body_->parts;
 
220
              else
 
221
                o->input->body_parts = input_body->parts;
 
222
              if (ext_input->dime__message_)
 
223
                o->input->layout = ext_input->dime__message_->layout;
 
224
              else
 
225
                o->input->layout = NULL;
 
226
              o->input->documentation = input->documentation;
 
227
              o->input->ext_documentation = ext_input->documentation;
 
228
              if (soap__operation_style == document)
 
229
                o->input_name = types.oname("__", o->URI, o->input->name);
 
230
              else
 
231
                o->input_name = types.oname(NULL, o->input->URI, o->input->name);
 
232
              if (output && ext_output)
 
233
              { soap__body *output_body = ext_output->soap__body_;
 
234
                if (ext_output->mime__multipartRelated_)
 
235
                { for (vector<mime__part>::const_iterator part = ext_output->mime__multipartRelated_->part.begin(); part != ext_output->mime__multipartRelated_->part.end(); ++part)
 
236
                    if ((*part).soap__body_)
 
237
                    { output_body = (*part).soap__body_;
 
238
                      break;
 
239
                    }
 
240
                }
 
241
                if (ext_output->mime__content_)
 
242
                { o->output = new Message();
 
243
                  o->output->name = NULL;
 
244
                  o->output->URI = NULL;
 
245
                  o->output->encodingStyle = NULL;
 
246
                  o->output->body_parts = NULL;
 
247
                  o->output->part = NULL;
 
248
                  o->output->multipartRelated = NULL;
 
249
                  o->output->content = ext_output->mime__content_;
 
250
                  o->output->message = output->messagePtr();
 
251
                  o->output->layout = NULL;
 
252
                  o->output->documentation = output->documentation;
 
253
                  o->output->ext_documentation = ext_output->documentation;
 
254
                }
 
255
                else if (output_body)
 
256
                { o->output = new Message();
 
257
                  o->output->name = (*operation).name; // RPC uses operation/@name with suffix 'Response' as set below
 
258
                  o->output->use = output_body->use;
 
259
                  // the code below is a hack around the RPC encoded response message element tag mismatch with Axis:
 
260
                  if (!output_body->namespace_ || output_body->use == encoded)
 
261
                    o->output->URI = o->input->URI; // encoded seems (?) to require the request's namespace
 
262
                  else
 
263
                    o->output->URI = output_body->namespace_;
 
264
                  o->output->encodingStyle = output_body->encodingStyle;
 
265
                  o->output->message = output->messagePtr();
 
266
                  o->output->part = NULL;
 
267
                  o->output->multipartRelated = ext_output->mime__multipartRelated_;
 
268
                  o->output->content = NULL;
 
269
                  if (ext_output->mime__multipartRelated_ && !ext_output->mime__multipartRelated_->part.empty())
 
270
                    o->output->header = ext_output->mime__multipartRelated_->part.front().soap__header_;
 
271
                  else
 
272
                    o->output->header = ext_output->soap__header_;
 
273
                  if (ext_output->mime__multipartRelated_ && !ext_output->mime__multipartRelated_->part.empty() && ext_output->mime__multipartRelated_->part.front().soap__body_)
 
274
                    o->output->body_parts = ext_output->mime__multipartRelated_->part.front().soap__body_->parts;
 
275
                  else
 
276
                    o->output->body_parts = output_body->parts;
 
277
                  if (ext_output->dime__message_)
 
278
                    o->output->layout = ext_output->dime__message_->layout;
 
279
                  else
 
280
                    o->output->layout = NULL;
 
281
                  o->output->documentation = output->documentation;
 
282
                  o->output->ext_documentation = ext_output->documentation;
 
283
                  char *s = (char*)soap_malloc(definitions.soap, strlen(o->output->name) + 9);
 
284
                  strcpy(s, o->output->name);
 
285
                  strcat(s, "Response");
 
286
                  if (soap__operation_style == document)
 
287
                    o->output_name = types.oname("__", o->URI, s);
 
288
                  else
 
289
                    o->output_name = types.oname(NULL, o->output->URI, s);
 
290
                }
 
291
              }
 
292
              else
 
293
              { o->output_name = NULL;
 
294
                o->output = NULL;
 
295
              }
 
296
              // collect input headers and headerfaults
 
297
              if (ext_input)
 
298
              { const vector<soap__header> *soap__header_ = NULL;
 
299
                // check if soap header is in mime:multipartRelated
 
300
                if (ext_input->mime__multipartRelated_)
 
301
                { for (vector<mime__part>::const_iterator part = ext_input->mime__multipartRelated_->part.begin(); part != ext_input->mime__multipartRelated_->part.end(); ++part)
 
302
                  if (!(*part).soap__header_.empty())
 
303
                  { soap__header_ = &(*part).soap__header_;
 
304
                    break;
 
305
                  }
 
306
                }
 
307
                if (!soap__header_)
 
308
                  soap__header_ = &ext_input->soap__header_;
 
309
                for (vector<soap__header>::const_iterator header = soap__header_->begin(); header != soap__header_->end(); ++header)
 
310
                { Message *h = new Message();
 
311
                  h->message = (*header).messagePtr();
 
312
                  h->body_parts = NULL;
 
313
                  h->part = (*header).partPtr();
 
314
                  h->URI = (*header).namespace_;
 
315
                  if (h->part && h->part->element)
 
316
                    h->name = types.aname(NULL, NULL, h->part->element);
 
317
                  else if (h->URI && h->part && h->part->name && h->part->type)
 
318
                    h->name = types.aname(NULL, h->URI, h->part->name);
 
319
                  else
 
320
                  { fprintf(stderr, "Error in SOAP Header part definition: input part '%s' missing?\n", h->part && h->part->name ? h->part->name : "?");
 
321
                    h->name = "";
 
322
                  }
 
323
                  h->encodingStyle = (*header).encodingStyle;
 
324
                  h->use = (*header).use;
 
325
                  h->multipartRelated = NULL;
 
326
                  h->content = NULL;
 
327
                  h->layout = NULL;
 
328
                  h->ext_documentation = NULL;  // TODO: add document content
 
329
                  h->documentation = NULL;              // TODO: add document content
 
330
                  s->header[h->name] = h;
 
331
                  for (vector<soap__headerfault>::const_iterator headerfault = (*header).headerfault.begin(); headerfault != (*header).headerfault.end(); ++headerfault)
 
332
                  { // TODO: complete headerfault processing. This is rarely used.
 
333
                  }
 
334
                }
 
335
              }
 
336
              // collect output headers and headerfaults
 
337
              if (ext_output)
 
338
              { const vector<soap__header> *soap__header_ = NULL;
 
339
                // check if soap header is in mime:multipartRelated
 
340
                if (ext_output->mime__multipartRelated_)
 
341
                { for (vector<mime__part>::const_iterator part = ext_output->mime__multipartRelated_->part.begin(); part != ext_output->mime__multipartRelated_->part.end(); ++part)
 
342
                  if (!(*part).soap__header_.empty())
 
343
                  { soap__header_ = &(*part).soap__header_;
 
344
                    break;
 
345
                  }
 
346
                }
 
347
                if (!soap__header_)
 
348
                  soap__header_ = &ext_output->soap__header_;
 
349
                for (vector<soap__header>::const_iterator header = soap__header_->begin(); header != soap__header_->end(); ++header)
 
350
                { Message *h = new Message();
 
351
                  h->message = (*header).messagePtr();
 
352
                  h->body_parts = NULL;
 
353
                  h->part = (*header).partPtr();
 
354
                  h->URI = (*header).namespace_;
 
355
                  if (h->part && h->part->element)
 
356
                    h->name = types.aname(NULL, NULL, h->part->element);
 
357
                  else if (h->URI && h->part && h->part->name && h->part->type)
 
358
                    h->name = types.aname(NULL, h->URI, h->part->name);
 
359
                  else
 
360
                  { fprintf(stderr, "Error in SOAP Header part definition: output part '%s' missing?\n", h->part && h->part->name ? h->part->name : "?");
 
361
                    h->name = "";
 
362
                  }
 
363
                  h->encodingStyle = (*header).encodingStyle;
 
364
                  h->use = (*header).use;
 
365
                  h->multipartRelated = NULL;
 
366
                  h->content = NULL;
 
367
                  h->layout = NULL;
 
368
                  h->ext_documentation = NULL;  // TODO: add document content
 
369
                  h->documentation = NULL;      // TODO: add document content
 
370
                  s->header[h->name] = h;
 
371
                  for (vector<soap__headerfault>::const_iterator headerfault = (*header).headerfault.begin(); headerfault != (*header).headerfault.end(); ++headerfault)
 
372
                  { // TODO: complete headerfault processing. This is rarely used.
 
373
                  }
 
374
                }
 
375
              }
 
376
              // collect faults
 
377
              for (vector<wsdl__ext_fault>::const_iterator ext_fault = (*operation).fault.begin(); ext_fault != (*operation).fault.end(); ++ext_fault)
 
378
              { if ((*ext_fault).soap__fault_ && (*ext_fault).messagePtr())
 
379
                { Message *f = new Message();
 
380
                  f->message = (*ext_fault).messagePtr();
 
381
                  f->body_parts = NULL;
 
382
                  f->part = NULL;
 
383
                  f->encodingStyle = (*ext_fault).soap__fault_->encodingStyle;
 
384
                  f->URI = (*ext_fault).soap__fault_->namespace_;
 
385
                  f->use = (*ext_fault).soap__fault_->use;
 
386
                  f->multipartRelated = NULL;
 
387
                  f->content = NULL;
 
388
                  f->layout = NULL;
 
389
                  f->ext_documentation = (*ext_fault).documentation;
 
390
                  f->name = types.aname("_", f->URI, f->message->name);
 
391
                  f->documentation = f->message->documentation;
 
392
                  o->fault.push_back(f);
 
393
                  s->fault[f->name] = f;
 
394
                }
 
395
                else
 
396
                  fprintf(stderr, "Error: no wsdl:definitions/binding/operation/fault/soap:fault\n");
 
397
              }
 
398
              s->operation.push_back(o);
 
399
            }
 
400
            else
 
401
              fprintf(stderr, "Warning: no SOAP RPC operation namespace, operations will be ignored\n");
 
402
          }
 
403
          else
 
404
            fprintf(stderr, "Error: no wsdl:definitions/binding/operation/input/soap:body\n");
 
405
        }
 
406
        else
 
407
          fprintf(stderr, "Error: no wsdl:definitions/portType/operation/input\n");
 
408
      }
 
409
      else
 
410
        fprintf(stderr, "Error: no wsdl:definitions/portType/operation\n");
 
411
    }
 
412
  }
 
413
}
 
414
 
 
415
void Definitions::compile(const wsdl__definitions& definitions)
 
416
{ // compile the definitions and generate gSOAP header file
 
417
  const char *defs;
 
418
  if (definitions.name)
 
419
    defs = types.aname(NULL, NULL, definitions.name);
 
420
  else
 
421
    defs = "Service";
 
422
  ident();
 
423
  fprintf(stream, "/* NOTE:\n\n - Compile this file with soapcpp2 to complete the code generation process.\n - Use soapcpp2 option -I to specify paths for #import\n   To build with STL, 'stlvector.h' is imported from 'import' dir in package.\n - Use wsdl2h options -c and -s to generate pure C code or C++ code without STL.\n - Use 'typemap.dat' to control schema namespace bindings and type mappings.\n   It is strongly recommended to customize the names of the namespace prefixes\n   generated by wsdl2h. To do so, modify the prefix bindings in the Namespaces\n   section below and add the modified lines to 'typemap.dat' to rerun wsdl2h.\n - Use Doxygen (www.doxygen.org) to browse this file.\n - Use wsdl2h option -l to view the software license terms.\n\n   DO NOT include this file directly into your project.\n   Include only the soapcpp2-generated headers and source code files.\n*/\n");
 
424
  // gsoap compiler options: 'w' disables WSDL/schema output to avoid file collisions
 
425
  if (cflag)
 
426
    fprintf(stream, "\n//gsoapopt cw\n");
 
427
  else
 
428
    fprintf(stream, "\n//gsoapopt w\n");
 
429
  banner(definitions.targetNamespace?definitions.targetNamespace:"targetNamespace");
 
430
  // copy documentation from WSDL definitions
 
431
  if (definitions.documentation)
 
432
  { fprintf(stream, "/* WSDL Documentation:\n\n");
 
433
    text(definitions.documentation);
 
434
    fprintf(stream, "*/\n\n");
 
435
  }
 
436
  if (lflag)
 
437
  { banner("License");
 
438
    fprintf(stream, "/*\n%s*/\n\n", licensenotice);
 
439
  }
 
440
  if (definitions.version)
 
441
  { banner("Version");
 
442
    fprintf(stream, "#define SOAP_WSDL_VERSION \"%s\"\n", definitions.version);
 
443
  }
 
444
  banner("Import");
 
445
  if (dflag)
 
446
  { fprintf(stream, "\n// dom.h declares the DOM xsd__anyType object (compiler and link with dom.cpp)\n");
 
447
    if (import_path)
 
448
      fprintf(stream, "#import \"%s/dom.h\"\n", import_path);
 
449
    else
 
450
      fprintf(stream, "#import \"dom.h\"\n");
 
451
  }
 
452
  if (!cflag && !sflag)
 
453
  { fprintf(stream, "\n// STL vector containers (use option -s to disable)\n");
 
454
    if (import_path)
 
455
      fprintf(stream, "#import \"%s/stlvector.h\"\n", import_path);
 
456
    else
 
457
      fprintf(stream, "#import \"stlvector.h\"\n");
 
458
  }
 
459
  if (mflag)
 
460
  { if (import_path)
 
461
      fprintf(stream, "#import \"%s/", import_path);
 
462
    else
 
463
      fprintf(stream, "#import \"");
 
464
    fprintf(stream, "xsd.h\"\t// import primitive XSD types.\n");
 
465
  }
 
466
  for (SetOfString::const_iterator u = exturis.begin(); u != exturis.end(); ++u)
 
467
  { bool found = false;
 
468
    size_t n = strlen(*u);
 
469
    for (SetOfString::const_iterator i = definitions.builtinTypes().begin(); i != definitions.builtinTypes().end(); ++i)
 
470
    { if (**i == '"' && !strncmp(*u, *i + 1, n))
 
471
      { found = true;
 
472
        break;
 
473
      }
 
474
    }
 
475
    if (!found)
 
476
    { for (SetOfString::const_iterator j = definitions.builtinElements().begin(); j != definitions.builtinElements().end(); ++j)
 
477
      { if (**j == '"' && !strncmp(*u, *j + 1, n))
 
478
        { found = true;
 
479
          break;
 
480
        }
 
481
      }
 
482
    }
 
483
    if (!found)
 
484
    { for (SetOfString::const_iterator k = definitions.builtinAttributes().begin(); k != definitions.builtinAttributes().end(); ++k)
 
485
      { if (**k == '"' && !strncmp(*u, *k + 1, n))
 
486
        { found = true;
 
487
          break;
 
488
        }
 
489
      }
 
490
    }
 
491
    if (found)
 
492
    { if (vflag)
 
493
        fprintf(stderr, "import %s\n", *u);
 
494
      if (import_path)
 
495
        fprintf(stream, "#import \"%s/%s.h\"\t// %s = <%s>\n", import_path, types.nsprefix(NULL, *u), types.nsprefix(NULL, *u), *u);
 
496
      else
 
497
        fprintf(stream, "#import \"%s.h\"\t// %s = <%s>\n", types.nsprefix(NULL, *u), types.nsprefix(NULL, *u), *u);
 
498
    }
 
499
  }
 
500
  banner("Schema Namespaces");
 
501
  // determine if we must use SOAP 1.2, this is a bit of a hack due to the lack of WSDL1.1/SOAP1.2 support and better alternatives
 
502
  for (Namespace *p = definitions.soap->local_namespaces; p && p->id; p++)
 
503
  { // p->out is set to the actual namespace name that matches the p->in pattern
 
504
    if (p->out && !strcmp(p->id, "soap") && !strcmp(p->out, "http://schemas.xmlsoap.org/wsdl/soap12/"))
 
505
    { fprintf(stream, "// This service uses SOAP 1.2 namespaces:\n");
 
506
      fprintf(stream, schemaformat, "SOAP-ENV", "namespace", "http://www.w3.org/2003/05/soap-envelope");
 
507
      fprintf(stream, schemaformat, "SOAP-ENC", "namespace", "http://www.w3.org/2003/05/soap-encoding");
 
508
      break;
 
509
    }
 
510
  }
 
511
  if (definitions.types)
 
512
  { fprintf(stream, "\n/* NOTE:\n\nIt is strongly recommended to customize the names of the namespace prefixes\ngenerated by wsdl2h. To do so, modify the prefix bindings below and add the\nmodified lines to typemap.dat to rerun wsdl2h:\n\n");
 
513
    if (definitions.targetNamespace && *definitions.targetNamespace)
 
514
      fprintf(stream, "%s = \"%s\"\n", types.nsprefix(service_prefix, definitions.targetNamespace), definitions.targetNamespace);
 
515
    for (vector<xs__schema*>::const_iterator schema1 = definitions.types->xs__schema_.begin(); schema1 != definitions.types->xs__schema_.end(); ++schema1)
 
516
      if (!definitions.targetNamespace || strcmp((*schema1)->targetNamespace, definitions.targetNamespace))
 
517
        fprintf(stream, "%s = \"%s\"\n", types.nsprefix(NULL, (*schema1)->targetNamespace), (*schema1)->targetNamespace);
 
518
    fprintf(stream, "\n*/\n\n");
 
519
    for (vector<xs__schema*>::const_iterator schema2 = definitions.types->xs__schema_.begin(); schema2 != definitions.types->xs__schema_.end(); ++schema2)
 
520
      fprintf(stream, schemaformat, types.nsprefix(NULL, (*schema2)->targetNamespace), "namespace", (*schema2)->targetNamespace);
 
521
    for (vector<xs__schema*>::const_iterator schema3 = definitions.types->xs__schema_.begin(); schema3 != definitions.types->xs__schema_.end(); ++schema3)
 
522
    { if ((*schema3)->elementFormDefault == (*schema3)->attributeFormDefault)
 
523
        fprintf(stream, schemaformat, types.nsprefix(NULL, (*schema3)->targetNamespace), "form", (*schema3)->elementFormDefault == qualified ? "qualified" : "unqualified");
 
524
      else
 
525
      { fprintf(stream, schemaformat, types.nsprefix(NULL, (*schema3)->targetNamespace), "elementForm", (*schema3)->elementFormDefault == qualified ? "qualified" : "unqualified");
 
526
        fprintf(stream, schemaformat, types.nsprefix(NULL, (*schema3)->targetNamespace), "attributeForm", (*schema3)->attributeFormDefault == qualified ? "qualified" : "unqualified");
 
527
      }
 
528
    }
 
529
  }
 
530
  banner("Schema Types");
 
531
  // generate the prototypes first: these should allow use before def, e.g. class names then generate the defs
 
532
  // check if xsd:anyType is used
 
533
  if (!cflag && !pflag)
 
534
  { for (SetOfString::const_iterator i = definitions.builtinTypes().begin(); i != definitions.builtinTypes().end(); ++i)
 
535
    { if (!cflag && !strcmp(*i, "xs:anyType"))
 
536
      { pflag = 1;
 
537
        break;
 
538
      }
 
539
    }
 
540
  }
 
541
  if (dflag && pflag)
 
542
  { fprintf(stderr, "\nWarning -d option: -p option disabled and xsd__anyType base class removed.\nUse run-time SOAP_DOM_NODE flag to deserialize class instances into DOM nodes.\n");
 
543
    fprintf(stream, "\n/*\nWarning -d option used: -p option disabled and xsd:anyType base class removed.\nUse run-time SOAP_DOM_NODE flag to deserialize class instances into DOM nodes.\nA DOM node is represented by the xsd__anyType object implemented in dom.cpp.\n*/\n\n");
 
544
    pflag = 0;
 
545
  }
 
546
  // define xsd:anyType first, if used
 
547
  if (!cflag && pflag)
 
548
  { const char *s, *t;
 
549
    t = types.cname(NULL, NULL, "xs:anyType");
 
550
    s = types.deftypemap[t];
 
551
    if (s)
 
552
    { if (*s)
 
553
      { if (!mflag)
 
554
          fprintf(stream, "%s\n", s);
 
555
      }
 
556
      s = types.usetypemap[t];
 
557
      if (s)
 
558
      { if (mflag)
 
559
          fprintf(stream, "//  xsd.h: should define type %s\n", s);
 
560
        types.knames.insert(s);
 
561
      }
 
562
    }
 
563
    else
 
564
    { fprintf(stderr, "Error: no xsd__anyType defined in type map\n");
 
565
      pflag = 0;
 
566
    }
 
567
  }
 
568
  // produce built-in primitive types, limited to the ones that are used only
 
569
  if (vflag)
 
570
    fprintf(stderr, "\nGenerating built-in types\n");
 
571
  for (SetOfString::const_iterator i = definitions.builtinTypes().begin(); i != definitions.builtinTypes().end(); ++i)
 
572
  { const char *s, *t;
 
573
    if (!cflag && !strcmp(*i, "xs:anyType"))
 
574
      continue;
 
575
    t = types.cname(NULL, NULL, *i);
 
576
    s = types.deftypemap[t];
 
577
    if (s)
 
578
    { if (*s)
 
579
      { if (**i == '"')
 
580
          fprintf(stream, "\n/// Imported type %s from typemap %s.\n", *i, mapfile?mapfile:"");
 
581
        else
 
582
          fprintf(stream, "\n/// Built-in type \"%s\".\n", *i);
 
583
        if (mflag)
 
584
          fprintf(stream, "//  (declaration of %s removed by option -m)\n", t);
 
585
        else
 
586
          types.format(s);
 
587
      }
 
588
      s = types.usetypemap[t];
 
589
      if (s && *s)
 
590
      { if (mflag && **i != '"')
 
591
          fprintf(stream, "\n//  xsd.h: typemap override of type %s with %s\n", t, s);
 
592
        if (types.knames.find(s) == types.knames.end())
 
593
          types.knames.insert(s);
 
594
      }
 
595
    }
 
596
    else
 
597
    { if (!mflag)
 
598
      { if (**i == '"')
 
599
          fprintf(stream, "\n// Imported type %s defined by %s\n", *i, t);
 
600
        else
 
601
        { s = types.tname(NULL, NULL, "xsd:string");
 
602
          fprintf(stream, "\n/// Primitive built-in type \"%s\"\n", *i);
 
603
          fprintf(stream, "typedef %s %s;\n", s, t);
 
604
          types.deftname(TYPEDEF, NULL, strchr(s, '*') != NULL, NULL, NULL, *i);
 
605
        }
 
606
      }
 
607
      else if (**i == '"')
 
608
        fprintf(stream, "\n//  Imported type %s defined by %s\n", *i, t);
 
609
      else
 
610
        fprintf(stream, "\n//  xsd.h: should define type %s\n", t);
 
611
      types.deftname(TYPEDEF, NULL, false, NULL, NULL, *i);
 
612
    }
 
613
    if (pflag && !strncmp(*i, "xs:", 3))                // only xsi types are polymorph
 
614
    { s = types.aname(NULL, NULL, *i);
 
615
      if (!mflag)
 
616
      { fprintf(stream, "\n/// Class wrapper for built-in type \"%s\" derived from xsd__anyType\n", *i);
 
617
        fprintf(stream, "class %s : public xsd__anyType\n{ public:\n", s);
 
618
        fprintf(stream, elementformat, types.tname(NULL, NULL, *i), "__item;");
 
619
        fprintf(stream, "\n};\n");
 
620
      }
 
621
      types.knames.insert(s);
 
622
    }
 
623
  }
 
624
  // produce built-in primitive elements, limited to the ones that are used only
 
625
  if (vflag)
 
626
    fprintf(stderr, "\nGenerating built-in elements\n");
 
627
  for (SetOfString::const_iterator j = definitions.builtinElements().begin(); j != definitions.builtinElements().end(); ++j)
 
628
  { const char *s, *t;
 
629
    t = types.cname("_", NULL, *j);
 
630
    s = types.deftypemap[t];
 
631
    if (s)
 
632
    { if (*s)
 
633
      { if (**j == '"')
 
634
          fprintf(stream, "\n/// Imported element %s from typemap %s.\n", *j, mapfile?mapfile:"");
 
635
        else
 
636
          fprintf(stream, "\n/// Built-in element \"%s\".\n", *j);
 
637
        if (mflag)
 
638
          fprintf(stream, "//  (declaration of %s removed by option -m)\n", t);
 
639
        else
 
640
          types.format(s);
 
641
      }
 
642
      s = types.usetypemap[t];
 
643
      if (s && *s)
 
644
      { if (mflag && **j != '"')
 
645
          fprintf(stream, "\n//  xsd.h: typemap override of element %s with %s\n", t, s);
 
646
        if (types.knames.find(s) == types.knames.end())
 
647
          types.knames.insert(s);
 
648
      }
 
649
    }
 
650
    else
 
651
    { if (!mflag)
 
652
      { if (**j == '"')
 
653
          fprintf(stream, "\n// Imported element %s declared as %s\n", *j, t);
 
654
        else
 
655
        { fprintf(stream, "\n/// Built-in element \"%s\".\n", *j);
 
656
          fprintf(stream, "typedef _XML %s;\n", t);
 
657
          types.deftname(TYPEDEF, NULL, true, "_", NULL, *j);   // already pointer
 
658
        }
 
659
      }
 
660
      else if (**j == '"')
 
661
        fprintf(stream, "\n//  Imported element %s declared as %s\n", *j, t);
 
662
      else
 
663
        fprintf(stream, "\n//  xsd.h: should define element %s\n", t);
 
664
      types.deftname(TYPEDEF, NULL, false, "_", NULL, *j);
 
665
    }
 
666
  }
 
667
  // produce built-in primitive attributes, limited to the ones that are used only
 
668
  if (vflag)
 
669
    fprintf(stderr, "\nGenerating built-in attributes\n");
 
670
  for (SetOfString::const_iterator k = definitions.builtinAttributes().begin(); k != definitions.builtinAttributes().end(); ++k)
 
671
  { const char *s, *t;
 
672
    t = types.cname("_", NULL, *k);
 
673
    s = types.deftypemap[t];
 
674
    if (s)
 
675
    { if (*s)
 
676
      { if (**k == '"')
 
677
          fprintf(stream, "\n/// Imported attribute %s from typemap %s.\n", *k, mapfile?mapfile:"");
 
678
        else
 
679
          fprintf(stream, "\n/// Built-in attribute \"%s\".\n", *k);
 
680
        if (mflag)
 
681
          fprintf(stream, "//  (declaration of %s removed by option -m)\n", t);
 
682
        else
 
683
          types.format(s);
 
684
      }
 
685
      s = types.usetypemap[t];
 
686
      if (s && *s)
 
687
      { if (mflag && **k != '"')
 
688
          fprintf(stream, "\n//  xsd.h: typemap override of attribute %s with %s\n", t, s);
 
689
        if (types.knames.find(s) == types.knames.end())
 
690
          types.knames.insert(s);
 
691
      }
 
692
    }
 
693
    else
 
694
    { s = types.tname(NULL, NULL, "xsd:string");
 
695
      if (!mflag)
 
696
      { if (**k == '"')
 
697
          fprintf(stream, "\n// Imported attribute %s declared as %s\n", *k, t);
 
698
        else
 
699
        { fprintf(stream, "\n/// Built-in attribute \"%s\".\n", *k);
 
700
          fprintf(stream, "typedef %s %s;\n", s, t);
 
701
        }
 
702
      }
 
703
      else if (**k == '"')
 
704
        fprintf(stream, "//  Imported attribute %s declared as %s\n", *k, t);
 
705
      else
 
706
        fprintf(stream, "//  xsd.h: should define attribute %s\n", t);
 
707
      types.deftname(TYPEDEF, NULL, strchr(s, '*') != NULL, "_", NULL, *k);
 
708
    }
 
709
  }
 
710
  // produce types
 
711
  // define class/struct types first
 
712
  if (definitions.types)
 
713
  { comment("Definitions", defs, "types", definitions.types->documentation);
 
714
    fprintf(stream, "\n");
 
715
    for (vector<xs__schema*>::const_iterator schema4 = definitions.types->xs__schema_.begin(); schema4 != definitions.types->xs__schema_.end(); ++schema4)
 
716
    { if (vflag)
 
717
        fprintf(stderr, "\nDefining types in %s\n", (*schema4)->targetNamespace);
 
718
      for (vector<xs__complexType>::const_iterator complexType = (*schema4)->complexType.begin(); complexType != (*schema4)->complexType.end(); ++complexType)
 
719
        types.define((*schema4)->targetNamespace, NULL, *complexType);
 
720
      if (vflag)
 
721
        fprintf(stderr, "\nDefining elements in %s\n", (*schema4)->targetNamespace);
 
722
      for (vector<xs__element>::const_iterator element = (*schema4)->element.begin(); element != (*schema4)->element.end(); ++element)
 
723
      { if (!(*element).type && !(*element).abstract)
 
724
        { if ((*element).complexTypePtr())
 
725
            types.define((*schema4)->targetNamespace, (*element).name, *(*element).complexTypePtr());
 
726
          else if (!(*element).simpleTypePtr())
 
727
          { fprintf(stream, "\n/// Element \"%s\":%s.\n", (*schema4)->targetNamespace, (*element).name);
 
728
            if (gflag)
 
729
            { const char *t = types.deftname(TYPEDEF, NULL, false, "_", (*schema4)->targetNamespace, (*element).name);
 
730
              if (t)
 
731
                fprintf(stream, "typedef _XML %s;\n", t);
 
732
              else
 
733
                fprintf(stream, "// Element definition intentionally left blank.\n");
 
734
            }
 
735
            else
 
736
            { const char *s = types.cname("_", (*schema4)->targetNamespace, (*element).name);
 
737
              types.ptrtypemap[s] = types.usetypemap[s] = "_XML";
 
738
              fprintf(stream, "/// Note: use wsdl2h option -g to generate this global element declaration.\n");
 
739
            }
 
740
          }
 
741
        }
 
742
      }
 
743
    }  
 
744
    // visit types with lowest base level first
 
745
    int baseLevel = 1;
 
746
    bool found;
 
747
    do
 
748
    { found = (baseLevel == 1);
 
749
      for (vector<xs__schema*>::iterator schema = definitions.types->xs__schema_.begin(); schema != definitions.types->xs__schema_.end(); ++schema)
 
750
      { for (vector<xs__simpleType>::iterator simpleType = (*schema)->simpleType.begin(); simpleType != (*schema)->simpleType.end(); ++simpleType)
 
751
        { if ((*simpleType).baseLevel() == baseLevel)
 
752
          { found = true;
 
753
            types.gen((*schema)->targetNamespace, NULL, *simpleType, false);
 
754
          }
 
755
        }
 
756
        for (vector<xs__element>::iterator element = (*schema)->element.begin(); element != (*schema)->element.end(); ++element)
 
757
        { if (!(*element).type && (*element).simpleTypePtr() && (*element).simpleTypePtr()->baseLevel() == baseLevel)
 
758
          { found = true;
 
759
            if ((*element).type)
 
760
              fprintf(stream, "/// Element \"%s\":%s of simpleType %s.\n", (*schema)->targetNamespace, (*element).name, (*element).type);
 
761
            types.document((*element).annotation);
 
762
            types.gen((*schema)->targetNamespace, (*element).name, *(*element).simpleTypePtr(), false);
 
763
          }
 
764
          if (!(*element).type && (*element).complexTypePtr() && (*element).complexTypePtr()->baseLevel() == baseLevel)
 
765
            found = true;
 
766
        }
 
767
        for (vector<xs__attribute>::const_iterator attribute = (*schema)->attribute.begin(); attribute != (*schema)->attribute.end(); ++attribute)
 
768
        { if (!(*attribute).type && (*attribute).simpleTypePtr() && (*attribute).simpleTypePtr()->baseLevel() == baseLevel)
 
769
          { found = true;
 
770
            if ((*attribute).type)
 
771
              fprintf(stream, "/// Attribute \"%s\":%s of simpleType %s.\n", (*schema)->targetNamespace, (*attribute).name, (*attribute).type);
 
772
            types.document((*attribute).annotation);
 
773
            types.gen((*schema)->targetNamespace, (*attribute).name, *(*attribute).simpleTypePtr(), false); // URI = NULL won't generate type in schema (type without namespace qualifier)
 
774
          }
 
775
        }
 
776
        for (vector<xs__complexType>::iterator complexType = (*schema)->complexType.begin(); complexType != (*schema)->complexType.end(); ++complexType)
 
777
        { if ((*complexType).baseLevel() == baseLevel)
 
778
            found = true;
 
779
        }
 
780
      }
 
781
      ++baseLevel;
 
782
    } while (found);
 
783
    // generate complex type defs. Problem: what if a simpleType restriction/extension depends on a complexType simpleContent restriction/extension?
 
784
    int maxLevel = baseLevel;
 
785
    for (baseLevel = 1; baseLevel < maxLevel; ++baseLevel)
 
786
    { for (vector<xs__schema*>::iterator schema = definitions.types->xs__schema_.begin(); schema != definitions.types->xs__schema_.end(); ++schema)
 
787
      { for (vector<xs__complexType>::iterator complexType = (*schema)->complexType.begin(); complexType != (*schema)->complexType.end(); ++complexType)
 
788
        { if ((*complexType).baseLevel() == baseLevel)
 
789
            types.gen((*schema)->targetNamespace, NULL, *complexType, false);
 
790
        }
 
791
        for (vector<xs__element>::iterator element = (*schema)->element.begin(); element != (*schema)->element.end(); ++element)
 
792
        { if (!(*element).type && (*element).complexTypePtr() && (*element).complexTypePtr()->baseLevel() == baseLevel)
 
793
          { fprintf(stream, "\n\n/// Element \"%s\":%s of complexType.\n", (*schema)->targetNamespace, (*element).name);
 
794
            types.document((*element).annotation);
 
795
            types.gen((*schema)->targetNamespace, (*element).name, *(*element).complexTypePtr(), false);
 
796
          }
 
797
        }
 
798
      }
 
799
    }
 
800
    // option to consider: generate local complexTypes iteratively
 
801
    /*
 
802
    for (MapOfStringToType::const_iterator local = types.locals.begin(); local != types.locals.end(); ++local)
 
803
    { types.gen(NULL, (*local).first, *(*local).second);
 
804
    }
 
805
    */
 
806
    for (vector<xs__schema*>::iterator schema = definitions.types->xs__schema_.begin(); schema != definitions.types->xs__schema_.end(); ++schema)
 
807
    { if (vflag)
 
808
        fprintf(stderr, "\nGenerating elements in %s\n", (*schema)->targetNamespace);
 
809
      for (vector<xs__element>::iterator element = (*schema)->element.begin(); element != (*schema)->element.end(); ++element)
 
810
      { if ((*element).name && (*element).type && !(*element).abstract)
 
811
        { fprintf(stream, "\n/// Element \"%s\":%s of type %s.\n", (*schema)->targetNamespace, (*element).name, (*element).type);
 
812
          types.document((*element).annotation);
 
813
          if (!types.is_defined("_", (*schema)->targetNamespace, (*element).name))
 
814
          { const char *s = types.tname(NULL, (*schema)->targetNamespace, (*element).type);
 
815
            const char *t = types.deftname(TYPEDEF, NULL, false, "_", (*schema)->targetNamespace, (*element).name);
 
816
            if (gflag)
 
817
            { if (strncmp(s, "char", 4) && strchr(s, '*')) // don't want pointer typedef, unless char*
 
818
              { size_t n = strlen(s);
 
819
                char *r = (char*)malloc(n);
 
820
                strncpy(r, s, n - 1);
 
821
                r[n - 1] = '\0';
 
822
                fprintf(stream, "typedef %s %s;\n", r, t);
 
823
                free(r);
 
824
              }
 
825
              else
 
826
                fprintf(stream, "typedef %s %s;\n", s, t);
 
827
            }
 
828
            else
 
829
              fprintf(stream, "/// Note: use wsdl2h option -g to generate this global element declaration.\n");
 
830
          }
 
831
          else
 
832
          { const char *s = types.cname("_", (*schema)->targetNamespace, (*element).name);
 
833
            const char *t = types.deftypemap[s];
 
834
            if (t && *t)
 
835
            { fprintf(stream, "/// Imported element %s from typemap %s.\n", s, mapfile?mapfile:"");
 
836
              types.format(t);
 
837
            }
 
838
            else
 
839
              fprintf(stream, "// '%s' element definition intentionally left blank.\n", types.cname("_", (*schema)->targetNamespace, (*element).name));
 
840
          }
 
841
        }
 
842
      }
 
843
      if (vflag)
 
844
        fprintf(stderr, "\nGenerating attributes in %s\n", (*schema)->targetNamespace);
 
845
      for (vector<xs__attribute>::iterator attribute = (*schema)->attribute.begin(); attribute != (*schema)->attribute.end(); ++attribute)
 
846
      { if ((*attribute).name && (*attribute).type)
 
847
        { fprintf(stream, "\n/// Attribute \"%s\":%s of simpleType %s.\n", (*schema)->targetNamespace, (*attribute).name, (*attribute).type);
 
848
          types.document((*attribute).annotation);
 
849
          if (!types.is_defined("_", (*schema)->targetNamespace, (*attribute).name))
 
850
          { const char *s = types.tname(NULL, (*schema)->targetNamespace, (*attribute).type);
 
851
            const char *t = types.deftname(TYPEDEF, NULL, false, "_", (*schema)->targetNamespace, (*attribute).name);
 
852
            if (gflag)
 
853
            { if (strncmp(s, "char", 4) && strchr(s, '*')) // don't want pointer typedef, unless char*
 
854
              { size_t n = strlen(s);
 
855
                char *r = (char*)malloc(n);
 
856
                strncpy(r, s, n - 1);
 
857
                r[n - 1] = '\0';
 
858
                fprintf(stream, "typedef %s %s;\n", r, t);
 
859
                free(r);
 
860
              }
 
861
              else
 
862
                fprintf(stream, "typedef %s %s;\n", s, t);
 
863
            }
 
864
            else
 
865
              fprintf(stream, "/// Note: use wsdl2h option -g to generate this global attribute declaration.\n");
 
866
          }
 
867
          else
 
868
          { const char *s = types.cname("_", (*schema)->targetNamespace, (*attribute).name);
 
869
            const char *t = types.deftypemap[s];
 
870
            if (t && *t)
 
871
            { fprintf(stream, "/// Imported attribute %s from typemap %s.\n", s, mapfile?mapfile:"");
 
872
              types.format(t);
 
873
            }
 
874
            else
 
875
              fprintf(stream, "// '%s' attribute definition intentionally left blank.\n", types.cname("_", (*schema)->targetNamespace, (*attribute).name));
 
876
          }
 
877
        }
 
878
      }
 
879
    }
 
880
  }
 
881
  if (vflag)
 
882
    fprintf(stderr, "\nCollecting service bindings");
 
883
  collect(definitions);
 
884
  if (!services.empty())
 
885
  { banner("Services");
 
886
    for (MapOfStringToService::const_iterator service1 = services.begin(); service1 != services.end(); ++service1)
 
887
    { Service *sv = (*service1).second;
 
888
      if (sv && sv->prefix)
 
889
      { fprintf(stream, "\n");
 
890
        if (sv->name)
 
891
          fprintf(stream, serviceformat, sv->prefix, "name", sv->name, "");
 
892
        if (sv->type)
 
893
          fprintf(stream, serviceformat, sv->prefix, "type", sv->type, "");
 
894
        for (SetOfString::const_iterator port = sv->location.begin(); port != sv->location.end(); ++port)
 
895
          fprintf(stream, serviceformat, sv->prefix, "port", (*port), "");
 
896
        if (sv->URI)
 
897
          fprintf(stream, serviceformat, sv->prefix, "namespace", sv->URI, "");
 
898
        if (sv->transport)
 
899
          fprintf(stream, serviceformat, sv->prefix, "transport", sv->transport, "");
 
900
      }
 
901
    }
 
902
    fprintf(stream, "\n/** @mainpage %s Definitions\n", definitions.name?definitions.name:"Service");
 
903
    if (definitions.version)
 
904
    { section(defs, "_version Version", NULL);
 
905
      text(definitions.version);
 
906
    }
 
907
    if (definitions.documentation)
 
908
    { section(defs, "_documentation Documentation", NULL);
 
909
      text(definitions.documentation);
 
910
    }
 
911
    if (definitions.types && definitions.types->documentation)
 
912
    { section(defs, "_types Types", NULL);
 
913
      text(definitions.types->documentation);
 
914
    }
 
915
    section(defs, "_bindings Bindings", NULL);
 
916
    for (MapOfStringToService::const_iterator service2 = services.begin(); service2 != services.end(); ++service2)
 
917
    { Service *sv = (*service2).second;
 
918
      if (sv && sv->name)
 
919
        fprintf(stream, "  - @ref %s\n", sv->name);
 
920
    }
 
921
    fprintf(stream, "\n*/\n");
 
922
    for (MapOfStringToService::const_iterator service3 = services.begin(); service3 != services.end(); ++service3)
 
923
    { Service *sv = (*service3).second;
 
924
      if (sv && sv->name)
 
925
      { fprintf(stream, "\n/**\n");
 
926
        page(sv->name, " Binding", sv->name);
 
927
        for (MapOfStringToString::const_iterator service_doc = sv->service_documentation.begin(); service_doc != sv->service_documentation.end(); ++service_doc)
 
928
        { const char *name = types.aname(NULL, NULL, (*service_doc).first);
 
929
          section(name, "_service Service Documentation", (*service_doc).first);
 
930
          text((*service_doc).second);
 
931
        }
 
932
        for (MapOfStringToString::const_iterator port_doc = sv->port_documentation.begin(); port_doc != sv->port_documentation.end(); ++port_doc)
 
933
        { const char *name = types.aname(NULL, NULL, (*port_doc).first);
 
934
          section(name, "_port Port Documentation", (*port_doc).first);
 
935
          text((*port_doc).second);
 
936
        }
 
937
        for (MapOfStringToString::const_iterator binding_doc = sv->binding_documentation.begin(); binding_doc != sv->binding_documentation.end(); ++binding_doc)
 
938
        { const char *name = types.aname(NULL, NULL, (*binding_doc).first);
 
939
          section(name, "_binding Binding Documentation", (*binding_doc).first);
 
940
          text((*binding_doc).second);
 
941
        }
 
942
        section(sv->name, "_operations Operations of Binding ", sv->name);
 
943
        for (vector<Operation*>::const_iterator op = sv->operation.begin(); op != sv->operation.end(); ++op)
 
944
        { if (*op && (*op)->input_name)
 
945
            fprintf(stream, "  - @ref %s\n", (*op)->input_name);
 
946
        }
 
947
        section((*sv).name, "_ports Endpoints of Binding ", sv->name);
 
948
        for (SetOfString::const_iterator port = sv->location.begin(); port != sv->location.end(); ++port)
 
949
          fprintf(stream, "  - %s\n", *port);
 
950
        fprintf(stream, "\nNote: use wsdl2h option -N to change the service binding prefix name\n\n*/\n");
 
951
      }
 
952
    }
 
953
  }
 
954
  generate();
 
955
  if (cppnamespace)
 
956
    fprintf(stream, "\n} // namespace %s\n", cppnamespace);
 
957
  fprintf(stream, "\n/* End of %s */\n", outfile?outfile:"file");
 
958
}
 
959
 
 
960
void Definitions::generate()
 
961
{ MapOfStringToMessage headers;
 
962
  MapOfStringToMessage faults;
 
963
  const char *t;
 
964
  for (MapOfStringToService::const_iterator service1 = services.begin(); service1 != services.end(); ++service1)
 
965
  { if ((*service1).second)
 
966
    { for (MapOfStringToMessage::const_iterator header = (*service1).second->header.begin(); header != (*service1).second->header.end(); ++header)
 
967
        headers[(*header).first] = (*header).second;
 
968
      for (MapOfStringToMessage::const_iterator fault = (*service1).second->fault.begin(); fault != (*service1).second->fault.end(); ++fault)
 
969
        faults[(*fault).first] = (*fault).second;
 
970
    }
 
971
  }
 
972
  // Generate SOAP Header definition
 
973
  t = types.deftypemap["SOAP_ENV__Header"];
 
974
  if (t && *t)
 
975
  { banner("Custom SOAP Header");
 
976
    types.format(t);
 
977
  }
 
978
  else if (!jflag && !headers.empty())
 
979
  { banner("SOAP Header");
 
980
    fprintf(stream, "/**\n\nThe SOAP Header is part of the gSOAP context and its content is accessed\nthrough the soap.header variable. You may have to set the soap.actor variable\nto serialize SOAP Headers with SOAP-ENV:actor or SOAP-ENV:role attributes.\nUse option -j to omit.\n\n*/\n");
 
981
    fprintf(stream, "struct SOAP_ENV__Header\n{\n");
 
982
    for (MapOfStringToMessage::const_iterator header = headers.begin(); header != headers.end(); ++header)
 
983
    { if ((*header).second->URI && !types.uris[(*header).second->URI])
 
984
        fprintf(stream, schemaformat, types.nsprefix(NULL, (*header).second->URI), "namespace", (*header).second->URI);
 
985
      comment("Header", (*header).first, "WSDL", (*header).second->ext_documentation);
 
986
      comment("Header", (*header).first, "SOAP", (*header).second->documentation);
 
987
      fprintf(stream, elementformat, "mustUnderstand", "// must be understood by receiver");
 
988
      fprintf(stream, "\n");
 
989
      if ((*header).second->part && (*header).second->part->elementPtr())
 
990
      { fprintf(stream, "/// \"%s\" SOAP Header part element\n", (*header).second->part->name);
 
991
        types.gen(NULL, *(*header).second->part->elementPtr());
 
992
      }
 
993
      else if ((*header).second->part && (*header).second->part->type)
 
994
      { fprintf(stream, elementformat, types.pname(true, NULL, NULL, (*header).second->part->type), types.aname(NULL, (*header).second->URI, (*header).second->part->name));
 
995
        fprintf(stream, ";\n");
 
996
      }
 
997
      else
 
998
      { if ((*header).second->part && (*header).second->part->element)
 
999
          fprintf(stream, elementformat, types.pname(true, "_", NULL, (*header).second->part->element), (*header).first);
 
1000
        else
 
1001
          fprintf(stream, pointerformat, (*header).first, (*header).first);
 
1002
        fprintf(stream, ";\t///< TODO: Please check element name and type (imported type)\n");
 
1003
      }
 
1004
    }
 
1005
    types.modify("SOAP_ENV__Header");
 
1006
    fprintf(stream, "\n};\n");
 
1007
  }
 
1008
  // Generate Fault detail element definitions
 
1009
  for (MapOfStringToMessage::const_iterator fault = faults.begin(); fault != faults.end(); ++fault)
 
1010
  { if ((*fault).second->use == encoded)
 
1011
    { banner("SOAP Fault Detail Message");
 
1012
      fprintf(stream, "/// SOAP Fault detail message \"%s:%s\"\n", (*fault).second->URI, (*fault).second->message->name);
 
1013
      comment("Fault", (*fault).first, "WSDL", (*fault).second->ext_documentation);
 
1014
      comment("Fault", (*fault).first, "SOAP", (*fault).second->documentation);
 
1015
      if (cflag)
 
1016
        fprintf(stream, "struct %s\n{", (*fault).first);
 
1017
      else
 
1018
        fprintf(stream, "class %s\n{ public:", (*fault).first);
 
1019
      (*fault).second->generate(types, ";", false, true, false);
 
1020
      if (!cflag)
 
1021
      { fprintf(stream, "\n");
 
1022
        fprintf(stream, pointerformat, "struct soap", "soap");
 
1023
        fprintf(stream, ";");
 
1024
      }
 
1025
      fprintf(stream, "\n};\n");
 
1026
      if (cflag)
 
1027
        fprintf(stream, "typedef struct %s %s;\n", (*fault).first, (*fault).first);
 
1028
      if ((*fault).second->URI && !types.uris[(*fault).second->URI])
 
1029
        fprintf(stream, schemaformat, types.nsprefix(NULL, (*fault).second->URI), "namespace", (*fault).second->URI);
 
1030
    }
 
1031
  }
 
1032
  t = types.deftypemap["SOAP_ENV__Detail"];
 
1033
  if (t && *t)
 
1034
  { banner("Custom SOAP Detail");
 
1035
    types.format(t);
 
1036
  }
 
1037
  else if (!jflag && !faults.empty())
 
1038
  { SetOfString fault_elements;
 
1039
    banner("SOAP Fault Detail");
 
1040
    fprintf(stream, "/**\n\nThe SOAP Fault is part of the gSOAP context and its content is accessed\nthrough the soap.fault->detail variable (SOAP 1.1) or the\nsoap.fault->SOAP_ENV__Detail variable (SOAP 1.2).\nUse option -j to omit.\n\n*/\n");
 
1041
    fprintf(stream, "struct SOAP_ENV__Detail\n{\n");
 
1042
    for (MapOfStringToMessage::const_iterator fault = faults.begin(); fault != faults.end(); ++fault)
 
1043
    { if ((*fault).second->URI && !types.uris[(*fault).second->URI])
 
1044
        fprintf(stream, schemaformat, types.nsprefix(NULL, (*fault).second->URI), "namespace", (*fault).second->URI);
 
1045
      comment("Fault", (*fault).first, "WSDL", (*fault).second->ext_documentation);
 
1046
      comment("Fault", (*fault).first, "SOAP", (*fault).second->documentation);
 
1047
      if ((*fault).second->use == literal)
 
1048
      { for (vector<wsdl__part>::const_iterator part = (*fault).second->message->part.begin(); part != (*fault).second->message->part.end(); ++part)
 
1049
        { if ((*part).elementPtr())
 
1050
          { if (fault_elements.find((*part).element) == fault_elements.end())
 
1051
            { if ((*part).elementPtr()->type)
 
1052
                fprintf(stream, elementformat, types.pname(true, NULL, NULL, (*part).elementPtr()->type), types.aname(NULL, (*fault).second->URI, (*part).element));
 
1053
              else
 
1054
                fprintf(stream, elementformat, types.pname(true, "_", NULL, (*part).element), types.aname(NULL, (*fault).second->URI, (*part).element));
 
1055
              fprintf(stream, ";\n");
 
1056
              fault_elements.insert((*part).element);
 
1057
            }
 
1058
            fprintf(stream, "///< SOAP Fault element \"%s\" part \"%s\"\n", (*part).element?(*part).element:"", (*part).name?(*part).name:"");
 
1059
          }
 
1060
          else if ((*part).name && (*part).type)
 
1061
          { if (fault_elements.find((*part).name) == fault_elements.end())
 
1062
            { fprintf(stream, elementformat, types.pname(true, NULL, NULL, (*part).type), types.aname("_", (*fault).second->URI, (*part).name));
 
1063
              fprintf(stream, ";\n");
 
1064
              fault_elements.insert((*part).name);
 
1065
            }
 
1066
            fprintf(stream, "///< SOAP Fault type \"%s\" part \"%s\"\n", (*part).type, (*part).name);
 
1067
          }
 
1068
          else
 
1069
            fprintf(stream, "// Unknown SOAP Fault element \"%s\" part \"%s\"\n", (*fault).second->message->name, (*part).name?(*part).name:"");
 
1070
        }
 
1071
      }
 
1072
      else
 
1073
      { fprintf(stream, pointerformat, (*fault).first, types.aname(NULL, (*fault).second->URI, (*fault).second->message->name));
 
1074
        fprintf(stream, ";\t///< SOAP Fault detail message \"%s\":%s\n", (*fault).second->URI, (*fault).second->message->name);
 
1075
      }
 
1076
    }
 
1077
    types.modify("SOAP_ENV__Detail");
 
1078
    fprintf(stream, elementformat, "int", "__type");
 
1079
    fprintf(stream, ";\t///< set to SOAP_TYPE_X for a serializable type X\n");
 
1080
    fprintf(stream, pointerformat, "void", "fault");
 
1081
    fprintf(stream, ";\t///< points to serializable object X or NULL\n");
 
1082
    if (dflag)
 
1083
    { fprintf(stream, pointerformat, "xsd__anyType", "__any");
 
1084
      fprintf(stream, ";\t///< Catch any element content in DOM.\n");
 
1085
    }
 
1086
    else
 
1087
    { fprintf(stream, elementformat, "_XML", "__any");
 
1088
      fprintf(stream, ";\t///< Catch any element content in XML string.\n");
 
1089
    }
 
1090
    fprintf(stream, "};\n");
 
1091
  }
 
1092
  /* The SOAP Fault struct below is autogenerated by soapcpp2 (kept here for future mods)
 
1093
  if (!mflag && !faults.empty())
 
1094
  { fprintf(stream, "struct SOAP_ENV__Code\n{\n"); 
 
1095
    fprintf(stream, elementformat, "_QName", "SOAP_ENV__Value");
 
1096
    fprintf(stream, ";\n");
 
1097
    fprintf(stream, pointerformat, "char", "SOAP_ENV__Node");
 
1098
    fprintf(stream, ";\n");
 
1099
    fprintf(stream, pointerformat, "char", "SOAP_ENV__Role");
 
1100
    fprintf(stream, ";\n};\n");
 
1101
    fprintf(stream, "struct SOAP_ENV__Detail\n{\n"); 
 
1102
    fprintf(stream, elementformat, "int", "__type");
 
1103
    fprintf(stream, ";\n");
 
1104
    fprintf(stream, pointerformat, "void", "fault");
 
1105
    fprintf(stream, ";\n");
 
1106
    fprintf(stream, elementformat, "_XML", "__any");
 
1107
    fprintf(stream, ";\n};\n");
 
1108
    fprintf(stream, "struct SOAP_ENV__Fault\n{\n"); 
 
1109
    fprintf(stream, elementformat, "_QName", "faultcode");
 
1110
    fprintf(stream, ";\n");
 
1111
    fprintf(stream, pointerformat, "char", "faultstring");
 
1112
    fprintf(stream, ";\n");
 
1113
    fprintf(stream, pointerformat, "char", "faultactor");
 
1114
    fprintf(stream, ";\n");
 
1115
    fprintf(stream, pointerformat, "struct SOAP_ENV__Detail", "detail");
 
1116
    fprintf(stream, ";\n");
 
1117
    fprintf(stream, pointerformat, "struct SOAP_ENV__Code", "SOAP_ENV__Code");
 
1118
    fprintf(stream, ";\n");
 
1119
    fprintf(stream, pointerformat, "char", "SOAP_ENV__Reason");
 
1120
    fprintf(stream, ";\n");
 
1121
    fprintf(stream, pointerformat, "struct SOAP_ENV__Detail", "SOAP_ENV__Detail");
 
1122
    fprintf(stream, ";\n};\n");
 
1123
  }
 
1124
  */
 
1125
  for (MapOfStringToService::const_iterator service2 = services.begin(); service2 != services.end(); ++service2)
 
1126
    if ((*service2).second)
 
1127
      (*service2).second->generate(types);
 
1128
}
 
1129
 
 
1130
////////////////////////////////////////////////////////////////////////////////
 
1131
//
 
1132
//      Service methods
 
1133
//
 
1134
////////////////////////////////////////////////////////////////////////////////
 
1135
 
 
1136
Service::Service()
 
1137
{ prefix = NULL;
 
1138
  URI = NULL;
 
1139
  name = NULL;
 
1140
  type = NULL;
 
1141
  transport = NULL;
 
1142
}
 
1143
 
 
1144
void Service::generate(Types& types)
 
1145
{ if (name)
 
1146
    banner(name);
 
1147
  for (vector<Operation*>::const_iterator op2 = operation.begin(); op2 != operation.end(); ++op2)
 
1148
  { if (*op2 && (*op2)->input)
 
1149
    { bool flag = false, anonymous = ((*op2)->style != document && (*op2)->parameterOrder != NULL);
 
1150
      banner((*op2)->input_name);
 
1151
      if ((*op2)->output && (*op2)->output_name)
 
1152
      { if ((*op2)->style == document)
 
1153
          flag = (*op2)->output->message && (*op2)->output->message->part.size() == 1;
 
1154
        else if (!wflag)
 
1155
          flag = (*op2)->output->message && (*op2)->output->use == encoded && (*op2)->output->message->part.size() == 1 && !(*(*op2)->output->message->part.begin()).simpleTypePtr() && !(*(*op2)->output->message->part.begin()).complexTypePtr();
 
1156
        if (flag && (*op2)->input->message && (*(*op2)->output->message->part.begin()).element)
 
1157
          for (vector<wsdl__part>::const_iterator part = (*op2)->input->message->part.begin(); part != (*op2)->input->message->part.end(); ++part)
 
1158
            if ((*part).element && !strcmp((*part).element, (*(*op2)->output->message->part.begin()).element))
 
1159
              flag = false;
 
1160
        if (!flag)
 
1161
        { fprintf(stream, "/// Operation response struct \"%s\" of service binding \"%s\" operation \"%s\"\n", (*op2)->output_name, name, (*op2)->input_name);
 
1162
          fprintf(stream, "struct %s\n{", (*op2)->output_name);
 
1163
          (*op2)->output->generate(types, ";", anonymous, true, false);
 
1164
          fprintf(stream, "\n};\n");
 
1165
        }
 
1166
      }
 
1167
      fprintf(stream, "\n/// Operation \"%s\" of service binding \"%s\"\n\n/**\n\nOperation details:\n\n", (*op2)->input_name, name);
 
1168
      if ((*op2)->documentation)
 
1169
        text((*op2)->documentation);
 
1170
      if ((*op2)->operation_documentation)
 
1171
        text((*op2)->operation_documentation);
 
1172
      if ((*op2)->input->documentation)
 
1173
      { fprintf(stream, "Input request:\n");
 
1174
        text((*op2)->input->documentation);
 
1175
      }
 
1176
      if ((*op2)->input->ext_documentation)
 
1177
      { fprintf(stream, "Input request:\n");
 
1178
        text((*op2)->input->ext_documentation);
 
1179
      }
 
1180
      if ((*op2)->output)
 
1181
      { if ((*op2)->output->documentation)
 
1182
        { fprintf(stream, "Output response:\n");
 
1183
          text((*op2)->output->documentation);
 
1184
        }
 
1185
        if ((*op2)->output->ext_documentation)
 
1186
        { fprintf(stream, "Output response:\n");
 
1187
          text((*op2)->output->ext_documentation);
 
1188
        }
 
1189
      }
 
1190
      if ((*op2)->output)
 
1191
      { if ((*op2)->output->content)
 
1192
        { fprintf(stream, "  - Response has MIME content");
 
1193
          if ((*op2)->output->content->type)
 
1194
          { fprintf(stream, " type=\"");
 
1195
            text((*op2)->output->content->type);
 
1196
            fprintf(stream, "\"");
 
1197
          }
 
1198
          fprintf(stream, "\n    TODO: this form of MIME content response is not automatically handled.\n    Use one-way request and implement code to parse response.\n");
 
1199
        }
 
1200
      }
 
1201
      else
 
1202
        fprintf(stream, "  - One-way message\n");
 
1203
      if ((*op2)->style == document)
 
1204
        fprintf(stream, "  - SOAP document/literal style\n");
 
1205
      else
 
1206
      { if ((*op2)->input->use == literal)
 
1207
          fprintf(stream, "  - SOAP RPC literal style\n");
 
1208
        else if ((*op2)->input->encodingStyle)
 
1209
          fprintf(stream, "  - SOAP RPC encodingStyle=\"%s\"\n", (*op2)->input->encodingStyle);
 
1210
        else
 
1211
          fprintf(stream, "  - SOAP RPC encoded\n");
 
1212
      }
 
1213
      if ((*op2)->output)
 
1214
      { if ((*op2)->input->use != (*op2)->output->use)
 
1215
        { if ((*op2)->output->use == literal)
 
1216
            fprintf(stream, "  - SOAP RPC literal response\n");
 
1217
          else if ((*op2)->output->encodingStyle)
 
1218
            fprintf(stream, "  - SOAP RPC response encodingStyle=\"%s\"\n", (*op2)->output->encodingStyle);
 
1219
          else
 
1220
            fprintf(stream, "  - SOAP RPC encoded response\n");
 
1221
        }
 
1222
      }
 
1223
      if ((*op2)->soapAction)
 
1224
      { if (*(*op2)->soapAction)
 
1225
          fprintf(stream, "  - SOAP action=\"%s\"\n", (*op2)->soapAction);
 
1226
      }
 
1227
      for (vector<Message*>::const_iterator message = (*op2)->fault.begin(); message != (*op2)->fault.end(); ++message)
 
1228
      { if ((*message)->use == literal)
 
1229
        { for (vector<wsdl__part>::const_iterator part = (*message)->message->part.begin(); part != (*message)->message->part.end(); ++part)
 
1230
          { if ((*part).element)
 
1231
              fprintf(stream, "  - SOAP Fault: %s (literal)\n", (*part).element);
 
1232
            else if ((*part).name && (*part).type)
 
1233
              fprintf(stream, "  - SOAP Fault: %s (literal)\n", (*part).name);
 
1234
          }
 
1235
        }
 
1236
        else if ((*message)->message && (*message)->message->name)
 
1237
          fprintf(stream, "  - SOAP Fault: %s\n", (*message)->name);
 
1238
      }
 
1239
      if (!(*op2)->input->header.empty())
 
1240
        fprintf(stream, "  - Request message has mandatory header part(s):\n");
 
1241
      for (vector<soap__header>::const_iterator inputheader = (*op2)->input->header.begin(); inputheader != (*op2)->input->header.end(); ++inputheader)
 
1242
      { if ((*inputheader).part)
 
1243
        { if ((*inputheader).use == encoded && (*inputheader).namespace_)
 
1244
            fprintf(stream, "    - %s\n", types.aname(NULL, (*inputheader).namespace_, (*inputheader).part));
 
1245
          else if ((*inputheader).partPtr() && (*inputheader).partPtr()->element)
 
1246
            fprintf(stream, "    - %s\n", types.aname(NULL, NULL, (*inputheader).partPtr()->element));
 
1247
        }
 
1248
      }
 
1249
      if ((*op2)->input->multipartRelated)
 
1250
      { int k = 2;
 
1251
        fprintf(stream, "  - Request message has MIME multipart/related attachments:\n");
 
1252
        for (vector<mime__part>::const_iterator part = (*op2)->input->multipartRelated->part.begin(); part != (*op2)->input->multipartRelated->part.end(); ++part)
 
1253
        { if ((*part).soap__body_)
 
1254
          { fprintf(stream, "    -# MIME attachment with SOAP Body and mandatory header part(s):\n");
 
1255
            for (vector<soap__header>::const_iterator header = (*part).soap__header_.begin(); header != (*part).soap__header_.end(); ++header)
 
1256
            { if ((*header).part)
 
1257
              { if ((*header).use == encoded && (*header).namespace_)
 
1258
                  fprintf(stream, "       - %s\n", types.aname(NULL, (*header).namespace_, (*header).part));
 
1259
                else if ((*header).partPtr() && (*header).partPtr()->element)
 
1260
                  fprintf(stream, "       - %s\n", types.aname(NULL, NULL, (*header).partPtr()->element));
 
1261
              }
 
1262
            }
 
1263
          }
 
1264
          else
 
1265
          { fprintf(stream, "    -# MIME attachment %d:\n", k++);
 
1266
            for (vector<mime__content>::const_iterator content = (*part).content.begin(); content != (*part).content.end(); ++content)
 
1267
            { fprintf(stream, "       -");
 
1268
              if ((*content).part)
 
1269
              { fprintf(stream, " part=\"");
 
1270
                text((*content).part);
 
1271
                fprintf(stream, "\"");
 
1272
              }
 
1273
              if ((*content).type)
 
1274
              { fprintf(stream, " type=\"");
 
1275
                text((*content).type);
 
1276
                fprintf(stream, "\"");
 
1277
              }
 
1278
              fprintf(stream, "\n");
 
1279
            }
 
1280
          }
 
1281
        }
 
1282
      }
 
1283
      if ((*op2)->input->layout)
 
1284
        fprintf(stream, "  - Request message has DIME attachments in compliance with %s\n", (*op2)->input->layout);
 
1285
      if ((*op2)->output)
 
1286
      { if (!(*op2)->output->header.empty())
 
1287
          fprintf(stream, "  - Response message has mandatory header part(s):\n");
 
1288
        for (vector<soap__header>::const_iterator outputheader = (*op2)->output->header.begin(); outputheader != (*op2)->output->header.end(); ++outputheader)
 
1289
        { if ((*outputheader).part)
 
1290
          { if ((*outputheader).use == encoded && (*outputheader).namespace_)
 
1291
              fprintf(stream, "    - %s\n", types.aname(NULL, (*outputheader).namespace_, (*outputheader).part));
 
1292
            else if ((*outputheader).partPtr() && (*outputheader).partPtr()->element)
 
1293
              fprintf(stream, "    - %s\n", types.aname(NULL, NULL, (*outputheader).partPtr()->element));
 
1294
          }
 
1295
        }
 
1296
      }
 
1297
      if ((*op2)->output && (*op2)->output_name && (*op2)->output->multipartRelated)
 
1298
      { int k = 2;
 
1299
        fprintf(stream, "  - Response message has MIME multipart/related attachments\n");
 
1300
        for (vector<mime__part>::const_iterator part = (*op2)->output->multipartRelated->part.begin(); part != (*op2)->output->multipartRelated->part.end(); ++part)
 
1301
        { if ((*part).soap__body_)
 
1302
          { fprintf(stream, "    -# MIME attachment with SOAP Body and mandatory header part(s):\n");
 
1303
            for (vector<soap__header>::const_iterator header = (*part).soap__header_.begin(); header != (*part).soap__header_.end(); ++header)
 
1304
            { if ((*header).part)
 
1305
              { if ((*header).use == encoded && (*header).namespace_)
 
1306
                  fprintf(stream, "       - %s\n", types.aname(NULL, (*header).namespace_, (*header).part));
 
1307
                else if ((*header).partPtr() && (*header).partPtr()->element)
 
1308
                  fprintf(stream, "       - %s\n", types.aname(NULL, NULL, (*header).partPtr()->element));
 
1309
              }
 
1310
            }
 
1311
          }
 
1312
          else
 
1313
          { fprintf(stream, "    -# MIME attachment %d:\n", k++);
 
1314
            for (vector<mime__content>::const_iterator content = (*part).content.begin(); content != (*part).content.end(); ++content)
 
1315
            { fprintf(stream, "       -");
 
1316
              if ((*content).part)
 
1317
              { fprintf(stream, " part=\"");
 
1318
                text((*content).part);
 
1319
                fprintf(stream, "\"");
 
1320
              }
 
1321
              if ((*content).type)
 
1322
              { fprintf(stream, " type=\"");
 
1323
                text((*content).type);
 
1324
                fprintf(stream, "\"");
 
1325
              }
 
1326
              fprintf(stream, "\n");
 
1327
            }
 
1328
          }
 
1329
        }
 
1330
      }
 
1331
      if ((*op2)->output && (*op2)->output_name && (*op2)->output->layout)
 
1332
        fprintf(stream, "  - Response message has DIME attachments in compliance with %s\n", (*op2)->output->layout);
 
1333
      fprintf(stream, "\nC stub function (defined in soapClient.c[pp] generated by soapcpp2):\n@code\n  int soap_call_%s(\n    struct soap *soap,\n    NULL, // char *endpoint = NULL selects default endpoint for this operation\n    NULL, // char *action = NULL selects default action for this operation\n    // request parameters:", (*op2)->input_name);
 
1334
      (*op2)->input->generate(types, ",", false, false, false);
 
1335
      fprintf(stream, "\n    // response parameters:");
 
1336
      if ((*op2)->output && (*op2)->output_name)
 
1337
      { if (flag)
 
1338
        { if ((*op2)->style == document)
 
1339
          { // Shortcut: do not generate wrapper struct
 
1340
            (*op2)->output->generate(types, "", false, false, true);
 
1341
          }
 
1342
          else if ((*(*op2)->output->message->part.begin()).name)
 
1343
          { fprintf(stream, "\n");
 
1344
            fprintf(stream, anonymous ? anonformat : paraformat, types.tname(NULL, NULL, (*(*op2)->output->message->part.begin()).type), cflag ? "*" : "&", types.aname(NULL, NULL, (*(*op2)->output->message->part.begin()).name), "");
 
1345
          }
 
1346
        }
 
1347
        else
 
1348
          fprintf(stream, "\n    struct %s%s", (*op2)->output_name, cflag ? "*" : "&");
 
1349
      }
 
1350
      fprintf(stream, "\n  );\n@endcode\n\nC server function (called from the service dispatcher defined in soapServer.c[pp]):\n@code\n  int %s(\n    struct soap *soap,\n    // request parameters:", (*op2)->input_name);
 
1351
      (*op2)->input->generate(types, ",", false, false, false);
 
1352
      fprintf(stream, "\n    // response parameters:");
 
1353
      if ((*op2)->output && (*op2)->output_name)
 
1354
      { if (flag)
 
1355
        { if ((*op2)->style == document)
 
1356
          { // Shortcut: do not generate wrapper struct
 
1357
            (*op2)->output->generate(types, "", false, false, true);
 
1358
          }
 
1359
          else if ((*(*op2)->output->message->part.begin()).name)
 
1360
          { fprintf(stream, "\n");
 
1361
            fprintf(stream, anonymous ? anonformat : paraformat, types.tname(NULL, NULL, (*(*op2)->output->message->part.begin()).type), cflag ? "*" : "&", types.aname(NULL, NULL, (*(*op2)->output->message->part.begin()).name), "");
 
1362
          }
 
1363
        }
 
1364
        else
 
1365
          fprintf(stream, "\n    struct %s%s", (*op2)->output_name, cflag ? "*" : "&");
 
1366
      }
 
1367
      fprintf(stream, "\n  );\n@endcode\n\n");
 
1368
      if (!cflag)
 
1369
      { fprintf(stream, "C++ proxy class (defined in soap%sProxy.h):\n", name);
 
1370
        fprintf(stream, "  class %s;\n\n", name);
 
1371
        fprintf(stream, "Note: use soapcpp2 option '-i' to generate improved proxy and service classes;\n\n");
 
1372
      }
 
1373
      fprintf(stream, "*/\n\n");
 
1374
      (*op2)->generate(types);
 
1375
    }
 
1376
  }
 
1377
}
 
1378
 
 
1379
////////////////////////////////////////////////////////////////////////////////
 
1380
//
 
1381
//      Operation methods
 
1382
//
 
1383
////////////////////////////////////////////////////////////////////////////////
 
1384
 
 
1385
void Operation::generate(Types &types)
 
1386
{ bool flag = false, anonymous = ((style != document) && parameterOrder != NULL);
 
1387
  const char *method_name = strstr(input_name + 1, "__") + 2;
 
1388
  if (!method_name)
 
1389
    method_name = input_name;
 
1390
  if (style == document)
 
1391
    fprintf(stream, serviceformat, prefix, "method-style", method_name, "document");
 
1392
  else
 
1393
    fprintf(stream, serviceformat, prefix, "method-style", method_name, "rpc");
 
1394
  if (input->use == literal)
 
1395
    fprintf(stream, serviceformat, prefix, "method-encoding", method_name, "literal");
 
1396
  else if (input->encodingStyle)
 
1397
    fprintf(stream, serviceformat, prefix, "method-encoding", method_name, input->encodingStyle);
 
1398
  else
 
1399
    fprintf(stream, serviceformat, prefix, "method-encoding", method_name, "encoded");
 
1400
  if (output)
 
1401
  { if (input->use != output->use)
 
1402
    { if (output->use == literal)
 
1403
        fprintf(stream, serviceformat, prefix, "method-response-encoding", method_name, "literal");
 
1404
      else if (output->encodingStyle)
 
1405
        fprintf(stream, serviceformat, prefix, "method-response-encoding", method_name, output->encodingStyle);
 
1406
      else
 
1407
        fprintf(stream, serviceformat, prefix, "method-response-encoding", method_name, "encoded");
 
1408
    }
 
1409
    if (style == rpc && input->URI && output->URI && strcmp(input->URI, output->URI))
 
1410
      fprintf(stream, schemaformat, types.nsprefix(NULL, output->URI), "namespace", output->URI);
 
1411
  }
 
1412
  if (soapAction)
 
1413
  { if (*soapAction)
 
1414
      fprintf(stream, serviceformat, prefix, "method-action", method_name, soapAction);
 
1415
    else
 
1416
      fprintf(stream, serviceformat, prefix, "method-action", method_name, "\"\"");
 
1417
  }
 
1418
  for (vector<Message*>::const_iterator message = fault.begin(); message != fault.end(); ++message)
 
1419
  { if ((*message)->use == literal)
 
1420
    { for (vector<wsdl__part>::const_iterator part = (*message)->message->part.begin(); part != (*message)->message->part.end(); ++part)
 
1421
      { if ((*part).element)
 
1422
          fprintf(stream, serviceformat, prefix, "method-fault", method_name, types.aname(NULL, NULL, (*part).element));
 
1423
        else if ((*part).type)
 
1424
          fprintf(stream, serviceformat, prefix, "method-fault", method_name, types.aname(NULL, (*message)->URI, (*part).name));
 
1425
      }
 
1426
    }
 
1427
    else
 
1428
    { if ((*message)->message && (*message)->message->name)
 
1429
        fprintf(stream, serviceformat, prefix, "method-fault", method_name, (*message)->name);
 
1430
    }
 
1431
  }
 
1432
  if (input->multipartRelated)
 
1433
  { for (vector<mime__part>::const_iterator inputmime = input->multipartRelated->part.begin(); inputmime != input->multipartRelated->part.end(); ++inputmime)
 
1434
    { for (vector<soap__header>::const_iterator inputheader = (*inputmime).soap__header_.begin(); inputheader != (*inputmime).soap__header_.end(); ++inputheader)
 
1435
      { if ((*inputheader).part)
 
1436
        { if ((*inputheader).use == encoded && (*inputheader).namespace_)
 
1437
            fprintf(stream, serviceformat, prefix, "method-input-header-part", method_name, types.aname(NULL, (*inputheader).namespace_, (*inputheader).part));
 
1438
          else if ((*inputheader).partPtr() && (*inputheader).partPtr()->element)
 
1439
            fprintf(stream, serviceformat, prefix, "method-input-header-part", method_name, types.aname(NULL, NULL, (*inputheader).partPtr()->element));
 
1440
        }
 
1441
      }
 
1442
      for (vector<mime__content>::const_iterator content = (*inputmime).content.begin(); content != (*inputmime).content.end(); ++content)
 
1443
        if ((*content).type)
 
1444
          fprintf(stream, serviceformat, prefix, "method-input-mime-type", method_name, (*content).type);
 
1445
    }
 
1446
  }
 
1447
  // TODO: add headerfault directives
 
1448
  for (vector<soap__header>::const_iterator inputheader = input->header.begin(); inputheader != input->header.end(); ++inputheader)
 
1449
  { if ((*inputheader).part)
 
1450
    { if ((*inputheader).use == encoded && (*inputheader).namespace_)
 
1451
        fprintf(stream, serviceformat, prefix, "method-input-header-part", method_name, types.aname(NULL, (*inputheader).namespace_, (*inputheader).part));
 
1452
      else if ((*inputheader).partPtr() && (*inputheader).partPtr()->element)
 
1453
        fprintf(stream, serviceformat, prefix, "method-input-header-part", method_name, types.aname(NULL, NULL, (*inputheader).partPtr()->element));
 
1454
    }
 
1455
  }
 
1456
  if (output)
 
1457
  { if (output->multipartRelated)
 
1458
    { for (vector<mime__part>::const_iterator outputmime = output->multipartRelated->part.begin(); outputmime != output->multipartRelated->part.end(); ++outputmime)
 
1459
      { for (vector<soap__header>::const_iterator outputheader = (*outputmime).soap__header_.begin(); outputheader != (*outputmime).soap__header_.end(); ++outputheader)
 
1460
        { if ((*outputheader).part)
 
1461
          { if ((*outputheader).use == encoded && (*outputheader).namespace_)
 
1462
              fprintf(stream, serviceformat, prefix, "method-output-header-part", method_name, types.aname(NULL, (*outputheader).namespace_, (*outputheader).part));
 
1463
            else if ((*outputheader).partPtr() && (*outputheader).partPtr()->element)
 
1464
              fprintf(stream, serviceformat, prefix, "method-output-header-part", method_name, types.aname(NULL, NULL, (*outputheader).partPtr()->element));
 
1465
          }
 
1466
        }
 
1467
        for (vector<mime__content>::const_iterator content = (*outputmime).content.begin(); content != (*outputmime).content.end(); ++content)
 
1468
          if ((*content).type)
 
1469
            fprintf(stream, serviceformat, prefix, "method-output-mime-type", method_name, (*content).type);
 
1470
      }
 
1471
    }
 
1472
    for (vector<soap__header>::const_iterator outputheader = output->header.begin(); outputheader != output->header.end(); ++outputheader)
 
1473
    { if ((*outputheader).part)
 
1474
      { if ((*outputheader).use == encoded && (*outputheader).namespace_)
 
1475
          fprintf(stream, serviceformat, prefix, "method-output-header-part", method_name, types.aname(NULL, (*outputheader).namespace_, (*outputheader).part));
 
1476
        else if ((*outputheader).partPtr() && (*outputheader).partPtr()->element)
 
1477
          fprintf(stream, serviceformat, prefix, "method-output-header-part", method_name, types.aname(NULL, NULL, (*outputheader).partPtr()->element));
 
1478
      }
 
1479
    }
 
1480
  }
 
1481
  if (output_name)
 
1482
  { if (style == document)
 
1483
      flag = output->message && output->message->part.size() == 1;
 
1484
    else if (!wflag)
 
1485
      flag = output->message && output->use == encoded && output->message->part.size() == 1 && !(*output->message->part.begin()).simpleTypePtr() && !(*output->message->part.begin()).complexTypePtr();
 
1486
    if (flag && input->message && (*output->message->part.begin()).element)
 
1487
      for (vector<wsdl__part>::const_iterator part = input->message->part.begin(); part != input->message->part.end(); ++part)
 
1488
        if ((*part).element && !strcmp((*part).element, (*output->message->part.begin()).element))
 
1489
          flag = false;
 
1490
  }
 
1491
  fprintf(stream, "int %s(", input_name);
 
1492
  input->generate(types, ",", anonymous, true, false);
 
1493
  if (output_name)
 
1494
  { if (flag)
 
1495
    { if (style == document)
 
1496
      { // Shortcut: do not generate wrapper struct
 
1497
        output->generate(types, "", false, true, true);
 
1498
      }
 
1499
      else if ((*output->message->part.begin()).name)
 
1500
      { fprintf(stream, "\n");
 
1501
        fprintf(stream, anonymous ? anonformat : paraformat, types.tname(NULL, NULL, (*output->message->part.begin()).type), cflag ? "*" : "&", types.aname(NULL, NULL, (*output->message->part.begin()).name), "");
 
1502
        fprintf(stream, "\t///< Response parameter");
 
1503
      }
 
1504
    }
 
1505
    else
 
1506
    { fprintf(stream, "\n    struct %-28s%s", output_name, cflag ? "*" : "&");
 
1507
      fprintf(stream, "\t///< Response struct parameter");
 
1508
    }
 
1509
    fprintf(stream, "\n);\n");
 
1510
  }
 
1511
  else
 
1512
    fprintf(stream, "\n    void\t///< One-way message: no response parameter\n);\n");
 
1513
}
 
1514
 
 
1515
////////////////////////////////////////////////////////////////////////////////
 
1516
//
 
1517
//      Message methods
 
1518
//
 
1519
////////////////////////////////////////////////////////////////////////////////
 
1520
 
 
1521
void Message::generate(Types &types, const char *sep, bool anonymous, bool remark, bool response)
 
1522
{ if (message)
 
1523
  { for (vector<wsdl__part>::const_iterator part = message->part.begin(); part != message->part.end(); ++part)
 
1524
    { if (!(*part).name)
 
1525
        fprintf(stderr, "Error: no part name in message '%s'\n", message->name?message->name:"");
 
1526
      else if (!body_parts || soap_strsearch(body_parts, (*part).name))
 
1527
      { if (remark && (*part).documentation)
 
1528
          comment("", (*part).name, "parameter", (*part).documentation);
 
1529
        else
 
1530
          fprintf(stream, "\n");
 
1531
        if ((*part).element)
 
1532
        { if ((*part).elementPtr())
 
1533
          { const char *name, *type, *URI, *prefix = NULL;
 
1534
            name = (*part).elementPtr()->name;
 
1535
            /* comment out to use a type that refers to an element defined with typedef */
 
1536
            if ((*part).elementPtr()->type)
 
1537
              type = (*part).elementPtr()->type;
 
1538
            else
 
1539
            { type = name;
 
1540
              prefix = "_";
 
1541
            }
 
1542
            if ((*part).elementPtr()->schemaPtr())
 
1543
              URI = (*part).elementPtr()->schemaPtr()->targetNamespace;
 
1544
            else
 
1545
              URI = NULL;
 
1546
            if (response)
 
1547
            { const char *t = types.tname(prefix, URI, type);
 
1548
              bool flag = (strchr(t, '*') && strcmp(t, "char*") && strcmp(t, "char *"));
 
1549
              fprintf(stream, anonymous ? anonformat : paraformat, t, flag ? " " : cflag ? "*" : "&", types.aname(NULL, URI, name), sep);
 
1550
              if (remark)
 
1551
                fprintf(stream, "\t///< Response parameter");
 
1552
            }
 
1553
            else
 
1554
            { fprintf(stream, anonymous ? anonformat : paraformat, types.pname(false, prefix, URI, type), " ", types.aname(NULL, URI, name), sep);
 
1555
              if (remark && *sep == ',')
 
1556
                fprintf(stream, "\t///< Request parameter");
 
1557
            }
 
1558
          }
 
1559
          else
 
1560
          { fprintf(stream, anonymous ? anonformat : paraformat, types.pname(false, NULL, NULL, (*part).element), " ", types.aname(NULL, NULL, (*part).element), sep);
 
1561
            if (remark)
 
1562
              fprintf(stream, "\t///< TODO: Check element type (imported type)");
 
1563
          }
 
1564
        }
 
1565
        else if ((*part).type)
 
1566
        { if (use == literal)
 
1567
            fprintf(stderr, "Warning: part '%s' uses literal style and should refer to an element rather than a type\n", (*part).name);
 
1568
          if (response)
 
1569
          { const char *t = types.tname(NULL, NULL, (*part).type);
 
1570
            bool flag = (strchr(t, '*') && strcmp(t, "char*") && strcmp(t, "char *"));
 
1571
            fprintf(stream, anonymous ? anonformat : paraformat, t, flag ? " " : cflag ? "*" : "&", types.aname(NULL, NULL, (*part).name), sep);
 
1572
            if (remark)
 
1573
              fprintf(stream, "\t///< Response parameter");
 
1574
          }
 
1575
          else
 
1576
          { fprintf(stream, anonymous ? anonformat : paraformat, types.pname(false, NULL, NULL, (*part).type), " ", types.aname(NULL, NULL, (*part).name), sep);
 
1577
            if (remark && *sep == ',')
 
1578
              fprintf(stream, "\t///< Request parameter");
 
1579
          }
 
1580
        }
 
1581
        else
 
1582
          fprintf(stderr, "Error: no wsdl:definitions/message/part/@type in part '%s'\n", (*part).name);
 
1583
      }
 
1584
    }
 
1585
  }
 
1586
  else
 
1587
    fprintf(stderr, "Error: no wsdl:definitions/message\n");
 
1588
}
 
1589
 
 
1590
////////////////////////////////////////////////////////////////////////////////
 
1591
//
 
1592
//      Miscellaneous
 
1593
//
 
1594
////////////////////////////////////////////////////////////////////////////////
 
1595
 
 
1596
static void comment(const char *start, const char *middle, const char *end, const char *text)
 
1597
{ if (text)
 
1598
  { if (strchr(text, '\r') || strchr(text, '\n'))
 
1599
      fprintf(stream, "\n/** %s %s %s documentation:\n%s\n*/\n\n", start, middle, end, text);
 
1600
    else
 
1601
      fprintf(stream, "\n/// %s %s %s: %s\n", start, middle, end, text);
 
1602
  }
 
1603
}
 
1604
 
 
1605
static void page(const char *page, const char *title, const char *text)
 
1606
{ if (text)
 
1607
    fprintf(stream, "\n@page %s%s \"%s\"\n", page, title, text);
 
1608
  else
 
1609
    fprintf(stream, "\n@page %s%s\n", page, title);
 
1610
}
 
1611
 
 
1612
static void section(const char *section, const char *title, const char *text)
 
1613
{ if (text)
 
1614
    fprintf(stream, "\n@section %s%s \"%s\"\n", section, title, text);
 
1615
  else
 
1616
    fprintf(stream, "\n@section %s%s\n", section, title);
 
1617
}
 
1618
 
 
1619
static void banner(const char *text)
 
1620
{ int i;
 
1621
  fprintf(stream, "\n/");
 
1622
  for (i = 0; i < 78; i++)
 
1623
    fputc('*', stream);
 
1624
  fprintf(stream, "\\\n *%76s*\n * %-75s*\n *%76s*\n\\", "", text, "");
 
1625
  for (i = 0; i < 78; i++)
 
1626
    fputc('*', stream);
 
1627
  fprintf(stream, "/\n\n");
 
1628
  if (vflag)
 
1629
    fprintf(stderr, "\n---- %s ----\n\n", text);
 
1630
}
 
1631
 
 
1632
static void ident()
 
1633
{ time_t t = time(NULL), *p = &t;
 
1634
  char tmp[256];
 
1635
  int i;
 
1636
  strftime(tmp, 256, "%Y-%m-%d %H:%M:%S GMT", gmtime(p));
 
1637
  fprintf(stream, "/* %s\n   Generated by wsdl2h "VERSION" from ", outfile?outfile:"");
 
1638
  if (infiles)
 
1639
  { for (i = 0; i < infiles; i++)
 
1640
      fprintf(stream, "%s ", infile[i]);
 
1641
  }
 
1642
  else
 
1643
    fprintf(stream, "(stdin) ");
 
1644
  fprintf(stream, "and %s\n   %s\n   Copyright (C) 2001-2006 Robert van Engelen, Genivia Inc. All Rights Reserved.\n   This part of the software is released under one of the following licenses:\n   GPL or Genivia's license for commercial use.\n*/\n\n", mapfile, tmp);
 
1645
}
 
1646
 
 
1647
static void text(const char *text)
 
1648
{ const char *s = text;
 
1649
  if (!s)
 
1650
    return;
 
1651
  while (*s)
 
1652
  { switch (*s)
 
1653
    { case '\n':
 
1654
      case '\t':
 
1655
      case ' ':
 
1656
        fputc(*s, stream);
 
1657
        break;
 
1658
      case '/':
 
1659
        fputc(*s, stream);
 
1660
        if (s[1] == '*')
 
1661
          fputc(' ', stream);
 
1662
        break;
 
1663
      case '*':
 
1664
        fputc(*s, stream);
 
1665
        if (s[1] == '/')
 
1666
          fputc(' ', stream);
 
1667
        break;
 
1668
      default:
 
1669
        if (*s > 32)
 
1670
          fputc(*s, stream);
 
1671
    }
 
1672
    s++;
 
1673
  }
 
1674
  fputc('\n', stream);
 
1675
}