1 //
2 // Copyright (c) ZeroC, Inc. All rights reserved.
3 //
4
5 #include <IceUtil/CtrlCHandler.h>
6 #include <IceUtil/IceUtil.h>
7 #include <IceUtil/InputUtil.h>
8 #include <IceUtil/Options.h>
9 #include <IceUtil/OutputUtil.h>
10 #include <IceUtil/StringUtil.h>
11 #include <IceUtil/Mutex.h>
12 #include <IceUtil/MutexPtrLock.h>
13 #include <IceUtil/ConsoleUtil.h>
14 #include <Slice/Checksum.h>
15 #include <Slice/Preprocessor.h>
16 #include <Slice/FileTracker.h>
17 #include <Slice/PHPUtil.h>
18 #include <Slice/Parser.h>
19 #include <Slice/Util.h>
20 #include <cstring>
21 #include <climits>
22
23 #include <sys/types.h>
24 #include <sys/stat.h>
25
26 #ifdef _WIN32
27 # include <direct.h>
28 #else
29 # include <unistd.h>
30 #endif
31
32 // TODO: fix this warning!
33 #if defined(_MSC_VER)
34 # pragma warning(disable:4456) // shadow
35 # pragma warning(disable:4457) // shadow
36 # pragma warning(disable:4459) // shadow
37 #elif defined(__clang__)
38 # pragma clang diagnostic ignored "-Wshadow"
39 #elif defined(__GNUC__)
40 # pragma GCC diagnostic ignored "-Wshadow"
41 #endif
42
43 using namespace std;
44 using namespace Slice;
45 using namespace Slice::PHP;
46 using namespace IceUtilInternal;
47
48 namespace
49 {
50
51 //
52 // Get the fully-qualified name of the given definition. If a suffix is provided,
53 // it is prepended to the definition's unqualified name. If the nameSuffix
54 // is provided, it is appended to the container's name.
55 //
56 string
getAbsolute(const ContainedPtr & cont,bool ns,const string & pfx=std::string (),const string & suffix=std::string ())57 getAbsolute(const ContainedPtr& cont, bool ns, const string& pfx = std::string(), const string& suffix = std::string())
58 {
59 return scopedToName(cont->scope() + pfx + cont->name() + suffix, ns);
60 }
61
62 }
63
64 //
65 // CodeVisitor generates the PHP mapping for a translation unit.
66 //
67 class CodeVisitor : public ParserVisitor
68 {
69 public:
70
71 CodeVisitor(IceUtilInternal::Output&, bool);
72
73 virtual void visitClassDecl(const ClassDeclPtr&);
74 virtual bool visitClassDefStart(const ClassDefPtr&);
75 virtual bool visitExceptionStart(const ExceptionPtr&);
76 virtual bool visitStructStart(const StructPtr&);
77 virtual void visitSequence(const SequencePtr&);
78 virtual void visitDictionary(const DictionaryPtr&);
79 virtual void visitEnum(const EnumPtr&);
80 virtual void visitConst(const ConstPtr&);
81
82 private:
83
84 void startNamespace(const ContainedPtr&);
85 void endNamespace();
86
87 //
88 // Return the PHP name for the given Slice type. When using namespaces,
89 // this name is a relative (unqualified) name, otherwise this name is the
90 // flattened absolute name.
91 //
92 string getName(const ContainedPtr&, const string& = string());
93
94 //
95 // Return the PHP variable for the given object's type.
96 //
97 string getTypeVar(const ContainedPtr&, const string& = string());
98
99 //
100 // Emit the array for a Slice type.
101 //
102 void writeType(const TypePtr&);
103 string getType(const TypePtr&);
104
105 //
106 // Write a default value for a given type.
107 //
108 void writeDefaultValue(const DataMemberPtr&);
109
110 struct MemberInfo
111 {
112 string fixedName;
113 bool inherited;
114 DataMemberPtr dataMember;
115 };
116 typedef list<MemberInfo> MemberInfoList;
117
118 //
119 // Write a member assignment statement for a constructor.
120 //
121 void writeAssign(const MemberInfo&);
122
123 //
124 // Write constant value.
125 //
126 void writeConstantValue(const TypePtr&, const SyntaxTreeBasePtr&, const string&);
127
128 //
129 // Write constructor parameters with default values.
130 //
131 void writeConstructorParams(const MemberInfoList&);
132
133 //
134 // Convert an operation mode into a string.
135 //
136 string getOperationMode(Slice::Operation::Mode, bool);
137
138 void collectClassMembers(const ClassDefPtr&, MemberInfoList&, bool);
139 void collectExceptionMembers(const ExceptionPtr&, MemberInfoList&, bool);
140
141 Output& _out;
142 bool _ns; // Using namespaces?
143 list<string> _moduleStack; // TODO: Necessary?
144 set<string> _classHistory; // TODO: Necessary?
145 };
146
147 //
148 // CodeVisitor implementation.
149 //
CodeVisitor(Output & out,bool ns)150 CodeVisitor::CodeVisitor(Output& out, bool ns) :
151 _out(out),
152 _ns(ns)
153 {
154 }
155
156 void
visitClassDecl(const ClassDeclPtr & p)157 CodeVisitor::visitClassDecl(const ClassDeclPtr& p)
158 {
159 //
160 // Handle forward declarations.
161 //
162 string scoped = p->scoped();
163 if(_classHistory.count(scoped) == 0)
164 {
165 startNamespace(p);
166
167 string type = getTypeVar(p);
168 _out << sp << nl << "global " << type << ';';
169
170 bool isInterface = p->isInterface();
171 ClassDefPtr def = p->definition();
172 if(!p->isLocal() && (isInterface || (def && def->allOperations().size() > 0)))
173 {
174 _out << nl << "global " << type << "Prx;";
175 }
176 _out << nl << "if(!isset(" << type << "))";
177 _out << sb;
178 _out << nl << type << " = IcePHP_declareClass('" << scoped << "');";
179 if(!p->isLocal() && (isInterface || (def && def->allOperations().size() > 0)))
180 {
181 _out << nl << type << "Prx = IcePHP_declareProxy('" << scoped << "');";
182 }
183 _out << eb;
184
185 endNamespace();
186
187 _classHistory.insert(scoped); // Avoid redundant declarations.
188 }
189 }
190
191 bool
visitClassDefStart(const ClassDefPtr & p)192 CodeVisitor::visitClassDefStart(const ClassDefPtr& p)
193 {
194 string scoped = p->scoped();
195 string name = getName(p);
196 string type = getTypeVar(p);
197 string abs = getAbsolute(p, _ns);
198 string prxName = getName(p, "Prx");
199 string prxType = getTypeVar(p, "Prx");
200 string prxAbs = getAbsolute(p, _ns, "", "Prx");
201 ClassList bases = p->bases();
202 ClassDefPtr base;
203 OperationList ops = p->operations();
204 DataMemberList members = p->dataMembers();
205 bool isInterface = p->isInterface();
206 bool isAbstract = isInterface || p->allOperations().size() > 0; // Don't use isAbstract() - see bug 3739
207
208 startNamespace(p);
209
210 _out << sp << nl << "global " << type << ';';
211 if(!p->isLocal() && isAbstract)
212 {
213 _out << nl << "global " << prxType << ';';
214 }
215
216 //
217 // Define the class.
218 //
219 if(isInterface)
220 {
221 if(p->isLocal())
222 {
223 _out << nl << "interface " << name;
224 if(bases.empty())
225 {
226 if(!p->isLocal())
227 {
228 _out << " extends " << scopedToName("::Ice::Object", _ns);
229 }
230 }
231 else
232 {
233 _out << " extends ";
234 for(ClassList::const_iterator q = bases.begin(); q != bases.end(); ++q)
235 {
236 if(q != bases.begin())
237 {
238 _out << ", ";
239 }
240 _out << getAbsolute(*q, _ns);
241 }
242 }
243 _out << sb;
244 for(OperationList::iterator oli = ops.begin(); oli != ops.end(); ++oli)
245 {
246 _out << nl << "public function " << fixIdent((*oli)->name()) << '(';
247 ParamDeclList params = (*oli)->parameters();
248 for(ParamDeclList::iterator q = params.begin(); q != params.end(); ++q)
249 {
250 if(q != params.begin())
251 {
252 _out << ", ";
253 }
254 _out << '$' << fixIdent((*q)->name());
255 }
256 _out << ");";
257 }
258
259 _out << eb;
260 }
261 }
262 else
263 {
264 _out << nl;
265 _out << "class " << name;
266 if(!bases.empty() && !bases.front()->isInterface())
267 {
268 base = bases.front();
269 bases.pop_front();
270 }
271 if(base)
272 {
273 _out << " extends " << getAbsolute(base, _ns);
274 }
275 else
276 {
277 if(!p->isLocal())
278 {
279 _out << " extends " << scopedToName("::Ice::Value", _ns);
280 }
281 }
282
283 //
284 // Value objects don't implement any interfaces.
285 //
286 if(p->isLocal() && !bases.empty())
287 {
288 _out << " implements ";
289 for(ClassList::const_iterator q = bases.begin(); q != bases.end(); ++q)
290 {
291 if(q != bases.begin())
292 {
293 _out << ", ";
294 }
295 _out << getAbsolute(*q, _ns);
296 }
297 }
298
299 _out << sb;
300
301 //
302 // __construct
303 //
304 _out << nl << "public function __construct(";
305 MemberInfoList allMembers;
306 collectClassMembers(p, allMembers, false);
307 writeConstructorParams(allMembers);
308 _out << ")";
309 _out << sb;
310 if(base)
311 {
312 _out << nl << "parent::__construct(";
313 int count = 0;
314 for(MemberInfoList::iterator q = allMembers.begin(); q != allMembers.end(); ++q)
315 {
316 if(q->inherited)
317 {
318 if(count)
319 {
320 _out << ", ";
321 }
322 _out << '$' << q->fixedName;
323 ++count;
324 }
325 }
326 _out << ");";
327 }
328 {
329 for(MemberInfoList::iterator q = allMembers.begin(); q != allMembers.end(); ++q)
330 {
331 if(!q->inherited)
332 {
333 writeAssign(*q);
334 }
335 }
336 }
337 _out << eb;
338
339 if(!p->isLocal())
340 {
341 //
342 // ice_ice
343 //
344 _out << sp << nl << "public function ice_id()";
345 _out << sb;
346 _out << nl << "return '" << scoped << "';";
347 _out << eb;
348
349 //
350 // ice_staticId
351 //
352 _out << sp << nl << "public static function ice_staticId()";
353 _out << sb;
354 _out << nl << "return '" << scoped << "';";
355 _out << eb;
356 }
357
358 //
359 // __toString
360 //
361 _out << sp << nl << "public function __toString()";
362 _out << sb;
363 _out << nl << "global " << type << ';';
364 _out << nl << "return IcePHP_stringify($this, " << type << ");";
365 _out << eb;
366
367 if(!members.empty())
368 {
369 _out << sp;
370 bool isProtected = p->hasMetaData("protected");
371 for(DataMemberList::iterator q = members.begin(); q != members.end(); ++q)
372 {
373 _out << nl;
374 if(isProtected || (*q)->hasMetaData("protected"))
375 {
376 _out << "protected ";
377 }
378 else
379 {
380 _out << "public ";
381 }
382 _out << "$" << fixIdent((*q)->name()) << ";";
383 }
384 }
385
386 _out << eb; // End of class.
387 }
388
389 //
390 // Define the proxy class.
391 //
392 if(!p->isLocal() && isAbstract)
393 {
394 _out << sp << nl << "class " << prxName << "Helper";
395 _out << sb;
396
397 _out << sp << nl << "public static function checkedCast($proxy, $facetOrContext=null, $context=null)";
398 _out << sb;
399 _out << nl << "return $proxy->ice_checkedCast('" << scoped << "', $facetOrContext, $context);";
400 _out << eb;
401
402 _out << sp << nl << "public static function uncheckedCast($proxy, $facet=null)";
403 _out << sb;
404 _out << nl << "return $proxy->ice_uncheckedCast('" << scoped << "', $facet);";
405 _out << eb;
406
407 _out << sp << nl << "public static function ice_staticId()";
408 _out << sb;
409 _out << nl << "return '" << scoped << "';";
410 _out << eb;
411
412 _out << eb;
413 }
414
415 if(_classHistory.count(scoped) == 0 && p->canBeCyclic())
416 {
417 //
418 // Emit a forward declaration for the class in case a data member refers to this type.
419 //
420 _out << sp << nl << type << " = IcePHP_declareClass('" << scoped << "');";
421 if(!p->isLocal() && isAbstract)
422 {
423 _out << nl << prxType << " = IcePHP_declareProxy('" << scoped << "');";
424 }
425 }
426
427 {
428 string type;
429 vector<string> seenType;
430 if(base || (!p->isLocal() && !isInterface))
431 {
432 _out << sp << nl << "global ";
433 if(!base)
434 {
435 type = "$Ice__t_Value";
436 }
437 else
438 {
439 type = getTypeVar(base);
440 }
441 _out << type << ";";
442 }
443 seenType.push_back(type);
444
445 for(DataMemberList::iterator q = members.begin(); q != members.end(); ++q)
446 {
447 string type = getType((*q)->type());
448 if(find(seenType.begin(), seenType.end(), type) == seenType.end())
449 {
450 seenType.push_back(type);
451 _out << nl << "global " << type << ";";
452 }
453 }
454 }
455
456 //
457 // Emit the type information.
458 //
459 const bool preserved = p->hasMetaData("preserve-slice") || p->inheritsMetaData("preserve-slice");
460 _out << nl << type << " = IcePHP_defineClass('" << scoped << "', '" << escapeName(abs) << "', "
461 << p->compactId() << ", " << (preserved ? "true" : "false") << ", "
462 << (isInterface ? "true" : "false") << ", ";
463 if(!base)
464 {
465 if(p->isLocal() || isInterface)
466 {
467 _out << "null";
468 }
469 else
470 {
471 _out << "$Ice__t_Value";
472 }
473 }
474 else
475 {
476 _out << getTypeVar(base);
477 }
478 _out << ", ";
479 //
480 // Members
481 //
482 // Data members are represented as an array:
483 //
484 // ('MemberName', MemberType, Optional, Tag)
485 //
486 // where MemberType is either a primitive type constant (T_INT, etc.) or the id of a constructed type.
487 //
488 if(!members.empty())
489 {
490 _out << "array(";
491 for(DataMemberList::iterator q = members.begin(); q != members.end(); ++q)
492 {
493 if(q != members.begin())
494 {
495 _out << ',';
496 }
497 _out.inc();
498 _out << nl << "array('" << fixIdent((*q)->name()) << "', ";
499 writeType((*q)->type());
500 _out << ", " << ((*q)->optional() ? "true" : "false") << ", "
501 << ((*q)->optional() ? (*q)->tag() : 0) << ')';
502 _out.dec();
503 }
504 _out << ')';
505 }
506 else
507 {
508 _out << "null";
509 }
510 _out << ");";
511
512 if(!p->isLocal() && isAbstract)
513 {
514 _out << sp << nl << "global ";
515 if(!base || base->allOperations().empty())
516 {
517 _out << "$Ice__t_ObjectPrx";
518 }
519 else
520 {
521 _out << getTypeVar(base, "Prx");
522 }
523 _out << ";";
524 _out << nl << prxType << " = IcePHP_defineProxy('" << scoped << "', ";
525 if(!base || base->allOperations().empty())
526 {
527 _out << "$Ice__t_ObjectPrx";
528 }
529 else
530 {
531 _out << getTypeVar(base, "Prx");
532 }
533 _out << ", ";
534 //
535 // Interfaces
536 //
537 if(!bases.empty())
538 {
539 _out << "array(";
540 for(ClassList::const_iterator q = bases.begin(); q != bases.end(); ++q)
541 {
542 if(q != bases.begin())
543 {
544 _out << ", ";
545 }
546 _out << getTypeVar(*q, "Prx");
547 }
548 _out << ')';
549 }
550 else
551 {
552 _out << "null";
553 }
554 _out << ");";
555
556 //
557 // Define each operation. The arguments to IcePHP_defineOperation are:
558 //
559 // $ClassType, 'opName', Mode, SendMode, FormatType, (InParams), (OutParams), ReturnParam, (Exceptions)
560 //
561 // where InParams and OutParams are arrays of type descriptions, and Exceptions
562 // is an array of exception type ids.
563 //
564 if(!ops.empty())
565 {
566 _out << sp;
567 vector<string> seenTypes;
568 for(OperationList::const_iterator p = ops.begin(); p != ops.end(); ++p)
569 {
570 ParamDeclList params = (*p)->parameters();
571 for(ParamDeclList::const_iterator q = params.begin(); q != params.end(); ++q)
572 {
573 string type = getType((*q)->type());
574 if(find(seenTypes.begin(), seenTypes.end(), type) == seenTypes.end())
575 {
576 seenTypes.push_back(type);
577 _out << nl << "global " << type << ";";
578 }
579 }
580
581 if((*p)->returnType())
582 {
583 string type = getType((*p)->returnType());
584 if(find(seenTypes.begin(), seenTypes.end(), type) == seenTypes.end())
585 {
586 seenTypes.push_back(type);
587 _out << nl << "global " << type << ";";
588 }
589 }
590 }
591
592 for(OperationList::iterator oli = ops.begin(); oli != ops.end(); ++oli)
593 {
594 ParamDeclList params = (*oli)->parameters();
595 ParamDeclList::iterator t;
596 int count;
597
598 _out << nl << "IcePHP_defineOperation(" << prxType << ", '" << (*oli)->name() << "', "
599 << getOperationMode((*oli)->mode(), _ns) << ", " << getOperationMode((*oli)->sendMode(), _ns)
600 << ", " << static_cast<int>((*oli)->format()) << ", ";
601 for(t = params.begin(), count = 0; t != params.end(); ++t)
602 {
603 if(!(*t)->isOutParam())
604 {
605 if(count == 0)
606 {
607 _out << "array(";
608 }
609 else if(count > 0)
610 {
611 _out << ", ";
612 }
613 _out << "array(";
614 writeType((*t)->type());
615 if((*t)->optional())
616 {
617 _out << ", " << (*t)->tag();
618 }
619 _out << ')';
620 ++count;
621 }
622 }
623 if(count > 0)
624 {
625 _out << ')';
626 }
627 else
628 {
629 _out << "null";
630 }
631 _out << ", ";
632 for(t = params.begin(), count = 0; t != params.end(); ++t)
633 {
634 if((*t)->isOutParam())
635 {
636 if(count == 0)
637 {
638 _out << "array(";
639 }
640 else if(count > 0)
641 {
642 _out << ", ";
643 }
644 _out << "array(";
645 writeType((*t)->type());
646 if((*t)->optional())
647 {
648 _out << ", " << (*t)->tag();
649 }
650 _out << ')';
651 ++count;
652 }
653 }
654 if(count > 0)
655 {
656 _out << ')';
657 }
658 else
659 {
660 _out << "null";
661 }
662 _out << ", ";
663 TypePtr returnType = (*oli)->returnType();
664 if(returnType)
665 {
666 //
667 // The return type has the same format as an in/out parameter:
668 //
669 // Type, Optional?, OptionalTag
670 //
671 _out << "array(";
672 writeType(returnType);
673 if((*oli)->returnIsOptional())
674 {
675 _out << ", " << (*oli)->returnTag();
676 }
677 _out << ')';
678 }
679 else
680 {
681 _out << "null";
682 }
683 _out << ", ";
684 ExceptionList exceptions = (*oli)->throws();
685 if(!exceptions.empty())
686 {
687 _out << "array(";
688 for(ExceptionList::iterator u = exceptions.begin(); u != exceptions.end(); ++u)
689 {
690 if(u != exceptions.begin())
691 {
692 _out << ", ";
693 }
694 _out << getTypeVar(*u);
695 }
696 _out << ')';
697 }
698 else
699 {
700 _out << "null";
701 }
702 _out << ");";
703 }
704 }
705 }
706
707 endNamespace();
708
709 if(_classHistory.count(scoped) == 0)
710 {
711 _classHistory.insert(scoped); // Avoid redundant declarations.
712 }
713
714 return false;
715 }
716
717 bool
visitExceptionStart(const ExceptionPtr & p)718 CodeVisitor::visitExceptionStart(const ExceptionPtr& p)
719 {
720 string scoped = p->scoped();
721 string name = getName(p);
722 string type = getTypeVar(p);
723 string abs = getAbsolute(p, _ns);
724
725 startNamespace(p);
726
727 _out << sp << nl << "global " << type << ';';
728 _out << nl << "class " << name << " extends ";
729 ExceptionPtr base = p->base();
730 string baseName;
731 if(base)
732 {
733 baseName = getAbsolute(base, _ns);
734 _out << baseName;
735 }
736 else if(p->isLocal())
737 {
738 _out << scopedToName("::Ice::LocalException", _ns);
739 }
740 else
741 {
742 _out << scopedToName("::Ice::UserException", _ns);
743 }
744 _out << sb;
745
746 DataMemberList members = p->dataMembers();
747
748 //
749 // __construct
750 //
751 _out << nl << "public function __construct(";
752 MemberInfoList allMembers;
753 collectExceptionMembers(p, allMembers, false);
754 writeConstructorParams(allMembers);
755 _out << ")";
756 _out << sb;
757 if(base)
758 {
759 _out << nl << "parent::__construct(";
760 int count = 0;
761 for(MemberInfoList::iterator q = allMembers.begin(); q != allMembers.end(); ++q)
762 {
763 if(q->inherited)
764 {
765 if(count)
766 {
767 _out << ", ";
768 }
769 _out << '$' << q->fixedName;
770 ++count;
771 }
772 }
773 _out << ");";
774 }
775 for(MemberInfoList::iterator q = allMembers.begin(); q != allMembers.end(); ++q)
776 {
777 if(!q->inherited)
778 {
779 writeAssign(*q);
780 }
781 }
782 _out << eb;
783
784 //
785 // ice_id
786 //
787 _out << sp << nl << "public function ice_id()";
788 _out << sb;
789 _out << nl << "return '" << scoped << "';";
790 _out << eb;
791
792 //
793 // __toString
794 //
795 _out << sp << nl << "public function __toString()";
796 _out << sb;
797 _out << nl << "global " << type << ';';
798 _out << nl << "return IcePHP_stringifyException($this, " << type << ");";
799 _out << eb;
800
801 if(!members.empty())
802 {
803 _out << sp;
804 for(DataMemberList::iterator dmli = members.begin(); dmli != members.end(); ++dmli)
805 {
806 _out << nl << "public $" << fixIdent((*dmli)->name()) << ";";
807 }
808 }
809
810 _out << eb;
811
812 vector<string> seenType;
813 for(DataMemberList::iterator dmli = members.begin(); dmli != members.end(); ++dmli)
814 {
815 string type = getType((*dmli)->type());
816 if(find(seenType.begin(), seenType.end(), type) == seenType.end())
817 {
818 seenType.push_back(type);
819 _out << nl << "global " << type << ";";
820 }
821 }
822
823 //
824 // Emit the type information.
825 //
826 const bool preserved = p->hasMetaData("preserve-slice") || p->inheritsMetaData("preserve-slice");
827 _out << sp << nl << type << " = IcePHP_defineException('" << scoped << "', '" << escapeName(abs) << "', "
828 << (preserved ? "true" : "false") << ", ";
829 if(!base)
830 {
831 _out << "null";
832 }
833 else
834 {
835 _out << getTypeVar(base);
836 }
837 _out << ", ";
838 //
839 // Data members are represented as an array:
840 //
841 // ('MemberName', MemberType, Optional, Tag)
842 //
843 // where MemberType is either a primitive type constant (T_INT, etc.) or the id of a constructed type.
844 //
845 if(!members.empty())
846 {
847 _out << "array(";
848 for(DataMemberList::iterator dmli = members.begin(); dmli != members.end(); ++dmli)
849 {
850 if(dmli != members.begin())
851 {
852 _out << ',';
853 }
854 _out.inc();
855 _out << nl << "array('" << fixIdent((*dmli)->name()) << "', ";
856 writeType((*dmli)->type());
857 _out << ", " << ((*dmli)->optional() ? "true" : "false") << ", "
858 << ((*dmli)->optional() ? (*dmli)->tag() : 0) << ')';
859 _out.dec();
860 }
861 _out << ')';
862 }
863 else
864 {
865 _out << "null";
866 }
867 _out << ");";
868
869 endNamespace();
870
871 return false;
872 }
873
874 bool
visitStructStart(const StructPtr & p)875 CodeVisitor::visitStructStart(const StructPtr& p)
876 {
877 string scoped = p->scoped();
878 string name = getName(p);
879 string type = getTypeVar(p);
880 string abs = getAbsolute(p, _ns);
881 MemberInfoList memberList;
882
883 {
884 DataMemberList members = p->dataMembers();
885 for(DataMemberList::iterator q = members.begin(); q != members.end(); ++q)
886 {
887 memberList.push_back(MemberInfo());
888 memberList.back().fixedName = fixIdent((*q)->name());
889 memberList.back().inherited = false;
890 memberList.back().dataMember = *q;
891 }
892 }
893
894 startNamespace(p);
895
896 _out << sp << nl << "global " << type << ';';
897
898 _out << nl << "class " << name;
899 _out << sb;
900 _out << nl << "public function __construct(";
901 writeConstructorParams(memberList);
902 _out << ")";
903 _out << sb;
904 for(MemberInfoList::iterator r = memberList.begin(); r != memberList.end(); ++r)
905 {
906 writeAssign(*r);
907 }
908 _out << eb;
909
910 //
911 // __toString
912 //
913 _out << sp << nl << "public function __toString()";
914 _out << sb;
915 _out << nl << "global " << type << ';';
916 _out << nl << "return IcePHP_stringify($this, " << type << ");";
917 _out << eb;
918
919 if(!memberList.empty())
920 {
921 _out << sp;
922 for(MemberInfoList::iterator r = memberList.begin(); r != memberList.end(); ++r)
923 {
924 _out << nl << "public $" << r->fixedName << ';';
925 }
926 }
927
928 _out << eb;
929
930 _out << sp;
931 vector<string> seenType;
932 for(MemberInfoList::iterator r = memberList.begin(); r != memberList.end(); ++r)
933 {
934 string type = getType(r->dataMember->type());
935 if(find(seenType.begin(), seenType.end(), type) == seenType.end())
936 {
937 seenType.push_back(type);
938 _out << nl << "global " << type << ";";
939 }
940 }
941 //
942 // Emit the type information.
943 //
944 _out << nl << type << " = IcePHP_defineStruct('" << scoped << "', '" << escapeName(abs) << "', array(";
945 //
946 // Data members are represented as an array:
947 //
948 // ('MemberName', MemberType)
949 //
950 // where MemberType is either a primitive type constant (T_INT, etc.) or the id of a constructed type.
951 //
952 for(MemberInfoList::iterator r = memberList.begin(); r != memberList.end(); ++r)
953 {
954 if(r != memberList.begin())
955 {
956 _out << ",";
957 }
958 _out.inc();
959 _out << nl << "array('" << r->fixedName << "', ";
960 writeType(r->dataMember->type());
961 _out << ')';
962 _out.dec();
963 }
964 _out << "));";
965 endNamespace();
966
967 return false;
968 }
969
970 void
visitSequence(const SequencePtr & p)971 CodeVisitor::visitSequence(const SequencePtr& p)
972 {
973 string type = getTypeVar(p);
974 TypePtr content = p->type();
975
976 startNamespace(p);
977
978 //
979 // Emit the type information.
980 //
981 string scoped = p->scoped();
982 _out << sp << nl << "global " << type << ';';
983 _out << sp << nl << "if(!isset(" << type << "))";
984 _out << sb;
985 _out << nl << "global " << getType(content) << ";";
986 _out << nl << type << " = IcePHP_defineSequence('" << scoped << "', ";
987 writeType(content);
988 _out << ");";
989 _out << eb;
990
991 endNamespace();
992 }
993
994 void
visitDictionary(const DictionaryPtr & p)995 CodeVisitor::visitDictionary(const DictionaryPtr& p)
996 {
997 TypePtr keyType = p->keyType();
998 BuiltinPtr b = BuiltinPtr::dynamicCast(keyType);
999
1000 const UnitPtr unit = p->unit();
1001 const DefinitionContextPtr dc = unit->findDefinitionContext(p->file());
1002 assert(dc);
1003 if(b)
1004 {
1005 switch(b->kind())
1006 {
1007 case Slice::Builtin::KindBool:
1008 case Slice::Builtin::KindByte:
1009 case Slice::Builtin::KindShort:
1010 case Slice::Builtin::KindInt:
1011 case Slice::Builtin::KindLong:
1012 case Slice::Builtin::KindString:
1013 //
1014 // These types are acceptable as dictionary keys.
1015 //
1016 break;
1017
1018 case Slice::Builtin::KindFloat:
1019 case Slice::Builtin::KindDouble:
1020 {
1021 dc->warning(InvalidMetaData, p->file(), p->line(), "dictionary key type not supported in PHP");
1022 break;
1023 }
1024
1025 case Slice::Builtin::KindObject:
1026 case Slice::Builtin::KindObjectProxy:
1027 case Slice::Builtin::KindLocalObject:
1028 case Slice::Builtin::KindValue:
1029 assert(false);
1030 }
1031 }
1032 else if(!EnumPtr::dynamicCast(keyType))
1033 {
1034 dc->warning(InvalidMetaData, p->file(), p->line(), "dictionary key type not supported in PHP");
1035 }
1036
1037 string type = getTypeVar(p);
1038
1039 startNamespace(p);
1040
1041 //
1042 // Emit the type information.
1043 //
1044 string scoped = p->scoped();
1045 _out << sp << nl << "global " << type << ';';
1046 _out << sp << nl << "if(!isset(" << type << "))";
1047 _out << sb;
1048 _out << nl << "global " << getType(p->keyType()) << ";";
1049 _out << nl << "global " << getType(p->valueType()) << ";";
1050 _out << nl << type << " = IcePHP_defineDictionary('" << scoped << "', ";
1051 writeType(p->keyType());
1052 _out << ", ";
1053 writeType(p->valueType());
1054 _out << ");";
1055 _out << eb;
1056
1057 endNamespace();
1058 }
1059
1060 void
visitEnum(const EnumPtr & p)1061 CodeVisitor::visitEnum(const EnumPtr& p)
1062 {
1063 string scoped = p->scoped();
1064 string name = getName(p);
1065 string type = getTypeVar(p);
1066 string abs = getAbsolute(p, _ns);
1067 EnumeratorList enums = p->enumerators();
1068
1069 startNamespace(p);
1070
1071 _out << sp << nl << "global " << type << ';';
1072 _out << nl << "class " << name;
1073 _out << sb;
1074
1075 {
1076 long i = 0;
1077 for(EnumeratorList::iterator q = enums.begin(); q != enums.end(); ++q, ++i)
1078 {
1079 _out << nl << "const " << fixIdent((*q)->name()) << " = " << (*q)->value() << ';';
1080 }
1081 }
1082
1083 _out << eb;
1084
1085 //
1086 // Emit the type information.
1087 //
1088 _out << sp << nl << type << " = IcePHP_defineEnum('" << scoped << "', array(";
1089 for(EnumeratorList::iterator q = enums.begin(); q != enums.end(); ++q)
1090 {
1091 if(q != enums.begin())
1092 {
1093 _out << ", ";
1094 }
1095 _out << "'" << (*q)->name() << "', " << (*q)->value();
1096 }
1097 _out << "));";
1098
1099 endNamespace();
1100 }
1101
1102 void
visitConst(const ConstPtr & p)1103 CodeVisitor::visitConst(const ConstPtr& p)
1104 {
1105 string name = getName(p);
1106 string type = getTypeVar(p);
1107 string abs = getAbsolute(p, _ns);
1108
1109 startNamespace(p);
1110
1111 _out << sp << nl << "if(!defined('" << escapeName(abs) << "'))";
1112 _out << sb;
1113 if(_ns)
1114 {
1115 _out << sp << nl << "define(__NAMESPACE__ . '\\\\" << name << "', ";
1116 }
1117 else
1118 {
1119 _out << sp << nl << "define('" << name << "', ";
1120 }
1121
1122 writeConstantValue(p->type(), p->valueType(), p->value());
1123
1124 _out << ");";
1125 _out << eb;
1126
1127 endNamespace();
1128 }
1129
1130 void
startNamespace(const ContainedPtr & cont)1131 CodeVisitor::startNamespace(const ContainedPtr& cont)
1132 {
1133 if(_ns)
1134 {
1135 string scope = cont->scope();
1136 scope = scope.substr(2); // Removing leading '::'
1137 scope = scope.substr(0, scope.length() - 2); // Removing trailing '::'
1138 _out << sp << nl << "namespace " << scopedToName(scope, true);
1139 _out << sb;
1140 }
1141 }
1142
1143 void
endNamespace()1144 CodeVisitor::endNamespace()
1145 {
1146 if(_ns)
1147 {
1148 _out << eb;
1149 }
1150 }
1151
1152 string
getTypeVar(const ContainedPtr & p,const string & suffix)1153 CodeVisitor::getTypeVar(const ContainedPtr& p, const string& suffix)
1154 {
1155 return "$" + getAbsolute(p, false, "_t_", suffix);
1156 }
1157
1158 string
getName(const ContainedPtr & p,const string & suffix)1159 CodeVisitor::getName(const ContainedPtr& p, const string& suffix)
1160 {
1161 if(_ns)
1162 {
1163 return fixIdent(p->name() + suffix);
1164 }
1165 else
1166 {
1167 return getAbsolute(p, false, "", suffix);
1168 }
1169 }
1170
1171 void
writeType(const TypePtr & p)1172 CodeVisitor::writeType(const TypePtr& p)
1173 {
1174 _out << getType(p);
1175 }
1176
1177 string
getType(const TypePtr & p)1178 CodeVisitor::getType(const TypePtr& p)
1179 {
1180 BuiltinPtr builtin = BuiltinPtr::dynamicCast(p);
1181 if(builtin)
1182 {
1183 switch(builtin->kind())
1184 {
1185 case Builtin::KindBool:
1186 {
1187 return "$IcePHP__t_bool";
1188 }
1189 case Builtin::KindByte:
1190 {
1191 return "$IcePHP__t_byte";
1192 }
1193 case Builtin::KindShort:
1194 {
1195 return "$IcePHP__t_short";
1196 }
1197 case Builtin::KindInt:
1198 {
1199 return "$IcePHP__t_int";
1200 }
1201 case Builtin::KindLong:
1202 {
1203 return "$IcePHP__t_long";
1204 }
1205 case Builtin::KindFloat:
1206 {
1207 return "$IcePHP__t_float";
1208 }
1209 case Builtin::KindDouble:
1210 {
1211 return "$IcePHP__t_double";
1212 }
1213 case Builtin::KindString:
1214 {
1215 return "$IcePHP__t_string";
1216 }
1217 case Builtin::KindObject:
1218 case Builtin::KindValue:
1219 {
1220 return "$Ice__t_Value";
1221 }
1222 case Builtin::KindObjectProxy:
1223 {
1224 return "$Ice__t_ObjectPrx";
1225 }
1226 case Builtin::KindLocalObject:
1227 {
1228 return "$Ice__t_LocalObject";
1229 }
1230 }
1231 }
1232
1233 ProxyPtr prx = ProxyPtr::dynamicCast(p);
1234 if(prx)
1235 {
1236 ClassDefPtr def = prx->_class()->definition();
1237 if(def && (def->isInterface() || def->allOperations().size() > 0))
1238 {
1239 return getTypeVar(prx->_class(), "Prx");
1240 }
1241 else
1242 {
1243 return "$Ice__t_ObjectPrx";
1244 }
1245 }
1246
1247 ContainedPtr cont = ContainedPtr::dynamicCast(p);
1248 assert(cont);
1249 return getTypeVar(cont);
1250 }
1251
1252 void
writeDefaultValue(const DataMemberPtr & m)1253 CodeVisitor::writeDefaultValue(const DataMemberPtr& m)
1254 {
1255 TypePtr p = m->type();
1256 BuiltinPtr builtin = BuiltinPtr::dynamicCast(p);
1257 if(builtin)
1258 {
1259 switch(builtin->kind())
1260 {
1261 case Builtin::KindBool:
1262 {
1263 _out << "false";
1264 break;
1265 }
1266 case Builtin::KindByte:
1267 case Builtin::KindShort:
1268 case Builtin::KindInt:
1269 case Builtin::KindLong:
1270 {
1271 _out << "0";
1272 break;
1273 }
1274 case Builtin::KindFloat:
1275 case Builtin::KindDouble:
1276 {
1277 _out << "0.0";
1278 break;
1279 }
1280 case Builtin::KindString:
1281 {
1282 _out << "''";
1283 break;
1284 }
1285 case Builtin::KindObject:
1286 case Builtin::KindObjectProxy:
1287 case Builtin::KindLocalObject:
1288 case Builtin::KindValue:
1289 {
1290 _out << "null";
1291 break;
1292 }
1293 }
1294 return;
1295 }
1296
1297 EnumPtr en = EnumPtr::dynamicCast(p);
1298 if(en)
1299 {
1300 EnumeratorList enums = en->enumerators();
1301 _out << getAbsolute(en, _ns) << "::" << fixIdent(enums.front()->name());
1302 return;
1303 }
1304
1305 //
1306 // PHP does not allow the following construct:
1307 //
1308 // function foo($theStruct=new MyStructType)
1309 //
1310 // Instead we use null as the default value and allocate an instance in
1311 // the constructor.
1312 //
1313 if(StructPtr::dynamicCast(p))
1314 {
1315 _out << "null";
1316 return;
1317 }
1318
1319 _out << "null";
1320 }
1321
1322 void
writeAssign(const MemberInfo & info)1323 CodeVisitor::writeAssign(const MemberInfo& info)
1324 {
1325 StructPtr st = StructPtr::dynamicCast(info.dataMember->type());
1326 if(st)
1327 {
1328 _out << nl << "$this->" << info.fixedName << " = is_null($" << info.fixedName << ") ? new "
1329 << getAbsolute(st, _ns) << " : $" << info.fixedName << ';';
1330 }
1331 else
1332 {
1333 _out << nl << "$this->" << info.fixedName << " = $" << info.fixedName << ';';
1334 }
1335 }
1336
1337 void
writeConstantValue(const TypePtr & type,const SyntaxTreeBasePtr & valueType,const string & value)1338 CodeVisitor::writeConstantValue(const TypePtr& type, const SyntaxTreeBasePtr& valueType, const string& value)
1339 {
1340 ConstPtr constant = ConstPtr::dynamicCast(valueType);
1341 if(constant)
1342 {
1343 _out << getAbsolute(constant, _ns);
1344 }
1345 else
1346 {
1347 Slice::BuiltinPtr b = Slice::BuiltinPtr::dynamicCast(type);
1348 Slice::EnumPtr en = Slice::EnumPtr::dynamicCast(type);
1349 if(b)
1350 {
1351 switch(b->kind())
1352 {
1353 case Slice::Builtin::KindBool:
1354 case Slice::Builtin::KindByte:
1355 case Slice::Builtin::KindShort:
1356 case Slice::Builtin::KindInt:
1357 case Slice::Builtin::KindFloat:
1358 case Slice::Builtin::KindDouble:
1359 {
1360 _out << value;
1361 break;
1362 }
1363 case Slice::Builtin::KindLong:
1364 {
1365 IceUtil::Int64 l;
1366 IceUtilInternal::stringToInt64(value, l);
1367 //
1368 // The platform's 'long' type may not be 64 bits, so we store 64-bit
1369 // values as a string.
1370 //
1371 if(sizeof(IceUtil::Int64) > sizeof(long) && (l < LONG_MIN || l > LONG_MAX))
1372 {
1373 _out << "'" << value << "'";
1374 }
1375 else
1376 {
1377 _out << value;
1378 }
1379 break;
1380 }
1381 case Slice::Builtin::KindString:
1382 {
1383 // PHP 7.x also supports an EC6UCN-like notation, see:
1384 // https://wiki.php.net/rfc/unicode_escape
1385 //
1386 _out << "\"" << toStringLiteral(value, "\f\n\r\t\v\x1b", "$", Octal, 0) << "\"";
1387 break;
1388 }
1389 case Slice::Builtin::KindObject:
1390 case Slice::Builtin::KindObjectProxy:
1391 case Slice::Builtin::KindLocalObject:
1392 case Slice::Builtin::KindValue:
1393 assert(false);
1394 }
1395 }
1396 else if(en)
1397 {
1398 EnumeratorPtr lte = EnumeratorPtr::dynamicCast(valueType);
1399 assert(lte);
1400 _out << getAbsolute(en, _ns) << "::" << fixIdent(lte->name());
1401 }
1402 else
1403 {
1404 assert(false); // Unknown const type.
1405 }
1406 }
1407 }
1408
1409 void
writeConstructorParams(const MemberInfoList & members)1410 CodeVisitor::writeConstructorParams(const MemberInfoList& members)
1411 {
1412 for(MemberInfoList::const_iterator p = members.begin(); p != members.end(); ++p)
1413 {
1414 if(p != members.begin())
1415 {
1416 _out << ", ";
1417 }
1418 _out << '$' << p->fixedName << "=";
1419
1420 const DataMemberPtr member = p->dataMember;
1421 if(member->defaultValueType())
1422 {
1423 writeConstantValue(member->type(), member->defaultValueType(), member->defaultValue());
1424 }
1425 else if(member->optional())
1426 {
1427 _out << (_ns ? scopedToName("::Ice::None", _ns) : "Ice_Unset");
1428 }
1429 else
1430 {
1431 writeDefaultValue(member);
1432 }
1433 }
1434 }
1435
1436 string
getOperationMode(Slice::Operation::Mode mode,bool)1437 CodeVisitor::getOperationMode(Slice::Operation::Mode mode, bool /*ns*/)
1438 {
1439 ostringstream ostr;
1440 ostr << static_cast<int>(mode);
1441 return ostr.str();
1442 }
1443
1444 void
collectClassMembers(const ClassDefPtr & p,MemberInfoList & allMembers,bool inherited)1445 CodeVisitor::collectClassMembers(const ClassDefPtr& p, MemberInfoList& allMembers, bool inherited)
1446 {
1447 ClassList bases = p->bases();
1448 if(!bases.empty() && !bases.front()->isInterface())
1449 {
1450 collectClassMembers(bases.front(), allMembers, true);
1451 }
1452
1453 DataMemberList members = p->dataMembers();
1454
1455 for(DataMemberList::iterator q = members.begin(); q != members.end(); ++q)
1456 {
1457 MemberInfo m;
1458 m.fixedName = fixIdent((*q)->name());
1459 m.inherited = inherited;
1460 m.dataMember = *q;
1461 allMembers.push_back(m);
1462 }
1463 }
1464
1465 void
collectExceptionMembers(const ExceptionPtr & p,MemberInfoList & allMembers,bool inherited)1466 CodeVisitor::collectExceptionMembers(const ExceptionPtr& p, MemberInfoList& allMembers, bool inherited)
1467 {
1468 ExceptionPtr base = p->base();
1469 if(base)
1470 {
1471 collectExceptionMembers(base, allMembers, true);
1472 }
1473
1474 DataMemberList members = p->dataMembers();
1475
1476 for(DataMemberList::iterator q = members.begin(); q != members.end(); ++q)
1477 {
1478 MemberInfo m;
1479 m.fixedName = fixIdent((*q)->name());
1480 m.inherited = inherited;
1481 m.dataMember = *q;
1482 allMembers.push_back(m);
1483 }
1484 }
1485
1486 static void
generate(const UnitPtr & un,bool all,bool checksum,bool ns,const vector<string> & includePaths,Output & out)1487 generate(const UnitPtr& un, bool all, bool checksum, bool ns, const vector<string>& includePaths, Output& out)
1488 {
1489 if(!all)
1490 {
1491 vector<string> paths = includePaths;
1492 for(vector<string>::iterator p = paths.begin(); p != paths.end(); ++p)
1493 {
1494 *p = fullPath(*p);
1495 }
1496
1497 StringList includes = un->includeFiles();
1498 if(!includes.empty())
1499 {
1500 if(ns)
1501 {
1502 out << sp;
1503 out << nl << "namespace";
1504 out << sb;
1505 }
1506 for(StringList::const_iterator q = includes.begin(); q != includes.end(); ++q)
1507 {
1508 string file = changeInclude(*q, paths);
1509 out << nl << "require_once '" << file << ".php';";
1510 }
1511 if(ns)
1512 {
1513 out << eb;
1514 }
1515 }
1516 }
1517
1518 CodeVisitor codeVisitor(out, ns);
1519 un->visit(&codeVisitor, false);
1520
1521 if(checksum)
1522 {
1523 ChecksumMap checksums = createChecksums(un);
1524 if(!checksums.empty())
1525 {
1526 out << sp;
1527 if(ns)
1528 {
1529 out << "namespace"; // Global namespace.
1530 out << sb;
1531 out << "new Ice\\SliceChecksumInit(array(";
1532 for(ChecksumMap::const_iterator p = checksums.begin(); p != checksums.end();)
1533 {
1534 out << nl << "\"" << p->first << "\" => \"";
1535 ostringstream str;
1536 str.flags(ios_base::hex);
1537 str.fill('0');
1538 for(vector<unsigned char>::const_iterator q = p->second.begin(); q != p->second.end(); ++q)
1539 {
1540 str << static_cast<int>(*q);
1541 }
1542 out << str.str() << "\"";
1543 if(++p != checksums.end())
1544 {
1545 out << ",";
1546 }
1547 }
1548 out << "));";
1549 out << eb;
1550 }
1551 else
1552 {
1553 out << nl << "global $Ice_sliceChecksums;";
1554 for(ChecksumMap::const_iterator p = checksums.begin(); p != checksums.end(); ++p)
1555 {
1556 out << nl << "$Ice_sliceChecksums[\"" << p->first << "\"] = \"";
1557 ostringstream str;
1558 str.flags(ios_base::hex);
1559 str.fill('0');
1560 for(vector<unsigned char>::const_iterator q = p->second.begin(); q != p->second.end(); ++q)
1561 {
1562 str << static_cast<int>(*q);
1563 }
1564 out << str.str() << "\";";
1565 }
1566 }
1567 }
1568 }
1569
1570 out << nl; // Trailing newline.
1571 }
1572
1573 static void
printHeader(IceUtilInternal::Output & out)1574 printHeader(IceUtilInternal::Output& out)
1575 {
1576 static const char* header =
1577 "//\n"
1578 "// Copyright (c) ZeroC, Inc. All rights reserved.\n"
1579 "//\n"
1580 ;
1581
1582 out << header;
1583 out << "//\n";
1584 out << "// Ice version " << ICE_STRING_VERSION << "\n";
1585 out << "//\n";
1586 }
1587
1588 namespace
1589 {
1590
1591 IceUtil::Mutex* globalMutex = 0;
1592 bool interrupted = false;
1593
1594 class Init
1595 {
1596 public:
1597
Init()1598 Init()
1599 {
1600 globalMutex = new IceUtil::Mutex;
1601 }
1602
~Init()1603 ~Init()
1604 {
1605 delete globalMutex;
1606 globalMutex = 0;
1607 }
1608 };
1609
1610 Init init;
1611
1612 }
1613
1614 static void
interruptedCallback(int)1615 interruptedCallback(int /*signal*/)
1616 {
1617 IceUtilInternal::MutexPtrLock<IceUtil::Mutex> sync(globalMutex);
1618
1619 interrupted = true;
1620 }
1621
1622 static void
usage(const string & n)1623 usage(const string& n)
1624 {
1625 consoleErr << "Usage: " << n << " [options] slice-files...\n";
1626 consoleErr <<
1627 "Options:\n"
1628 "-h, --help Show this message.\n"
1629 "-v, --version Display the Ice version.\n"
1630 "-DNAME Define NAME as 1.\n"
1631 "-DNAME=DEF Define NAME as DEF.\n"
1632 "-UNAME Remove any definition for NAME.\n"
1633 "-IDIR Put DIR in the include file search path.\n"
1634 "-E Print preprocessor output on stdout.\n"
1635 "--output-dir DIR Create files in the directory DIR.\n"
1636 "-d, --debug Print debug messages.\n"
1637 "--depend Generate Makefile dependencies.\n"
1638 "--depend-xml Generate dependencies in XML format.\n"
1639 "--depend-file FILE Write dependencies to FILE instead of standard output.\n"
1640 "--validate Validate command line options.\n"
1641 "--all Generate code for Slice definitions in included files.\n"
1642 "--no-namespace Do not use PHP namespaces (deprecated).\n"
1643 "--checksum Generate checksums for Slice definitions.\n"
1644 "--ice Allow reserved Ice prefix in Slice identifiers\n"
1645 " deprecated: use instead [[\"ice-prefix\"]] metadata.\n"
1646 "--underscore Allow underscores in Slice identifiers\n"
1647 " deprecated: use instead [[\"underscore\"]] metadata.\n"
1648 ;
1649 }
1650
1651 int
compile(const vector<string> & argv)1652 compile(const vector<string>& argv)
1653 {
1654 IceUtilInternal::Options opts;
1655 opts.addOpt("h", "help");
1656 opts.addOpt("v", "version");
1657 opts.addOpt("", "validate");
1658 opts.addOpt("D", "", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat);
1659 opts.addOpt("U", "", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat);
1660 opts.addOpt("I", "", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat);
1661 opts.addOpt("E");
1662 opts.addOpt("", "output-dir", IceUtilInternal::Options::NeedArg);
1663 opts.addOpt("", "depend");
1664 opts.addOpt("", "depend-xml");
1665 opts.addOpt("", "depend-file", IceUtilInternal::Options::NeedArg, "");
1666 opts.addOpt("d", "debug");
1667 opts.addOpt("", "ice");
1668 opts.addOpt("", "underscore");
1669 opts.addOpt("", "all");
1670 opts.addOpt("", "checksum");
1671 opts.addOpt("n", "no-namespace");
1672
1673 bool validate = find(argv.begin(), argv.end(), "--validate") != argv.end();
1674
1675 vector<string> args;
1676 try
1677 {
1678 args = opts.parse(argv);
1679 }
1680 catch(const IceUtilInternal::BadOptException& e)
1681 {
1682 consoleErr << argv[0] << ": error: " << e.reason << endl;
1683 if(!validate)
1684 {
1685 usage(argv[0]);
1686 }
1687 return EXIT_FAILURE;
1688 }
1689
1690 if(opts.isSet("help"))
1691 {
1692 usage(argv[0]);
1693 return EXIT_SUCCESS;
1694 }
1695
1696 if(opts.isSet("version"))
1697 {
1698 consoleErr << ICE_STRING_VERSION << endl;
1699 return EXIT_SUCCESS;
1700 }
1701
1702 vector<string> cppArgs;
1703 vector<string> optargs = opts.argVec("D");
1704 for(vector<string>::const_iterator i = optargs.begin(); i != optargs.end(); ++i)
1705 {
1706 cppArgs.push_back("-D" + *i);
1707 }
1708
1709 optargs = opts.argVec("U");
1710 for(vector<string>::const_iterator i = optargs.begin(); i != optargs.end(); ++i)
1711 {
1712 cppArgs.push_back("-U" + *i);
1713 }
1714
1715 vector<string> includePaths = opts.argVec("I");
1716 for(vector<string>::const_iterator i = includePaths.begin(); i != includePaths.end(); ++i)
1717 {
1718 cppArgs.push_back("-I" + Preprocessor::normalizeIncludePath(*i));
1719 }
1720
1721 bool preprocess = opts.isSet("E");
1722
1723 string output = opts.optArg("output-dir");
1724
1725 bool depend = opts.isSet("depend");
1726
1727 bool dependxml = opts.isSet("depend-xml");
1728
1729 string dependFile = opts.optArg("depend-file");
1730
1731 bool debug = opts.isSet("debug");
1732
1733 bool ice = opts.isSet("ice");
1734
1735 bool underscore = opts.isSet("underscore");
1736
1737 bool all = opts.isSet("all");
1738
1739 bool checksum = opts.isSet("checksum");
1740
1741 bool ns = !opts.isSet("no-namespace");
1742
1743 if(args.empty())
1744 {
1745 consoleErr << argv[0] << ": error: no input file" << endl;
1746 if(!validate)
1747 {
1748 usage(argv[0]);
1749 }
1750 return EXIT_FAILURE;
1751 }
1752
1753 if(depend && dependxml)
1754 {
1755 consoleErr << argv[0] << ": error: cannot specify both --depend and --depend-xml" << endl;
1756 if(!validate)
1757 {
1758 usage(argv[0]);
1759 }
1760 return EXIT_FAILURE;
1761 }
1762
1763 if(validate)
1764 {
1765 return EXIT_SUCCESS;
1766 }
1767
1768 int status = EXIT_SUCCESS;
1769
1770 IceUtil::CtrlCHandler ctrlCHandler;
1771 ctrlCHandler.setCallback(interruptedCallback);
1772
1773 ostringstream os;
1774 if(dependxml)
1775 {
1776 os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<dependencies>" << endl;
1777 }
1778
1779 for(vector<string>::const_iterator i = args.begin(); i != args.end(); ++i)
1780 {
1781 //
1782 // Ignore duplicates.
1783 //
1784 vector<string>::iterator p = find(args.begin(), args.end(), *i);
1785 if(p != i)
1786 {
1787 continue;
1788 }
1789
1790 if(depend || dependxml)
1791 {
1792 PreprocessorPtr icecpp = Preprocessor::create(argv[0], *i, cppArgs);
1793 FILE* cppHandle = icecpp->preprocess(false, "-D__SLICE2PHP__");
1794
1795 if(cppHandle == 0)
1796 {
1797 return EXIT_FAILURE;
1798 }
1799
1800 UnitPtr u = Unit::createUnit(false, false, ice, underscore);
1801 int parseStatus = u->parse(*i, cppHandle, debug);
1802 u->destroy();
1803
1804 if(parseStatus == EXIT_FAILURE)
1805 {
1806 return EXIT_FAILURE;
1807 }
1808
1809 if(!icecpp->printMakefileDependencies(os, depend ? Preprocessor::PHP : Preprocessor::SliceXML,
1810 includePaths, "-D__SLICE2PHP__"))
1811 {
1812 return EXIT_FAILURE;
1813 }
1814
1815 if(!icecpp->close())
1816 {
1817 return EXIT_FAILURE;
1818 }
1819 }
1820 else
1821 {
1822 PreprocessorPtr icecpp = Preprocessor::create(argv[0], *i, cppArgs);
1823 FILE* cppHandle = icecpp->preprocess(false, "-D__SLICE2PHP__");
1824
1825 if(cppHandle == 0)
1826 {
1827 return EXIT_FAILURE;
1828 }
1829
1830 if(preprocess)
1831 {
1832 char buf[4096];
1833 while(fgets(buf, static_cast<int>(sizeof(buf)), cppHandle) != ICE_NULLPTR)
1834 {
1835 if(fputs(buf, stdout) == EOF)
1836 {
1837 return EXIT_FAILURE;
1838 }
1839 }
1840 if(!icecpp->close())
1841 {
1842 return EXIT_FAILURE;
1843 }
1844 }
1845 else
1846 {
1847 UnitPtr u = Unit::createUnit(false, all, ice, underscore);
1848 int parseStatus = u->parse(*i, cppHandle, debug);
1849
1850 if(!icecpp->close())
1851 {
1852 u->destroy();
1853 return EXIT_FAILURE;
1854 }
1855
1856 if(parseStatus == EXIT_FAILURE)
1857 {
1858 status = EXIT_FAILURE;
1859 }
1860 else
1861 {
1862 string base = icecpp->getBaseName();
1863 string::size_type pos = base.find_last_of("/\\");
1864 if(pos != string::npos)
1865 {
1866 base.erase(0, pos + 1);
1867 }
1868
1869 string file = base + ".php";
1870 if(!output.empty())
1871 {
1872 file = output + '/' + file;
1873 }
1874
1875 try
1876 {
1877 IceUtilInternal::Output out;
1878 out.open(file.c_str());
1879 if(!out)
1880 {
1881 ostringstream os;
1882 os << "cannot open`" << file << "': " << IceUtilInternal::errorToString(errno);
1883 throw FileException(__FILE__, __LINE__, os.str());
1884 }
1885 FileTracker::instance()->addFile(file);
1886
1887 out << "<?php\n";
1888 printHeader(out);
1889 printGeneratedHeader(out, base + ".ice");
1890
1891 //
1892 // Generate the PHP mapping.
1893 //
1894 generate(u, all, checksum, ns, includePaths, out);
1895
1896 out << "?>\n";
1897 out.close();
1898 }
1899 catch(const Slice::FileException& ex)
1900 {
1901 // If a file could not be created, then cleanup any
1902 // created files.
1903 FileTracker::instance()->cleanup();
1904 u->destroy();
1905 consoleErr << argv[0] << ": error: " << ex.reason() << endl;
1906 return EXIT_FAILURE;
1907 }
1908 catch(const string& err)
1909 {
1910 FileTracker::instance()->cleanup();
1911 consoleErr << argv[0] << ": error: " << err << endl;
1912 status = EXIT_FAILURE;
1913 }
1914 }
1915
1916 u->destroy();
1917 }
1918 }
1919
1920 {
1921 IceUtilInternal::MutexPtrLock<IceUtil::Mutex> sync(globalMutex);
1922
1923 if(interrupted)
1924 {
1925 FileTracker::instance()->cleanup();
1926 return EXIT_FAILURE;
1927 }
1928 }
1929 }
1930
1931 if(dependxml)
1932 {
1933 os << "</dependencies>\n";
1934 }
1935
1936 if(depend || dependxml)
1937 {
1938 writeDependencies(os.str(), dependFile);
1939 }
1940
1941 return status;
1942 }
1943
1944 #ifdef _WIN32
wmain(int argc,wchar_t * argv[])1945 int wmain(int argc, wchar_t* argv[])
1946 #else
1947 int main(int argc, char* argv[])
1948 #endif
1949 {
1950 vector<string> args = Slice::argvToArgs(argc, argv);
1951 try
1952 {
1953 return compile(args);
1954 }
1955 catch(const std::exception& ex)
1956 {
1957 consoleErr << args[0] << ": error:" << ex.what() << endl;
1958 return EXIT_FAILURE;
1959 }
1960 catch(...)
1961 {
1962 consoleErr << args[0] << ": error:" << "unknown exception" << endl;
1963 return EXIT_FAILURE;
1964 }
1965 }
1966