source: dev/trunk/abdev/BasicCompiler_Common/Compile.cpp@ 247

Last change on this file since 247 was 247, checked in by dai_9181, 17 years ago

Exit Subスケジュールをリファクタリングした

File size: 17.1 KB
Line 
1#include "stdafx.h"
2
3#include <jenga/include/smoothie/Smoothie.h>
4#include <jenga/include/smoothie/LexicalAnalysis.h>
5#include <jenga/include/smoothie/SmoothieException.h>
6
7#include <LexicalScopingImpl.h>
8#include <CodeGenerator.h>
9#include <Compiler.h>
10#include <NamespaceSupporter.h>
11
12#include "../BasicCompiler_Common/common.h"
13
14#ifdef _AMD64_
15#include "../BasicCompiler64/opcode.h"
16#else
17#include "../BasicCompiler32/opcode.h"
18#endif
19
20#include <Exception.h>
21
22//ラベルアドレス
23LABEL *pLabelNames;
24int MaxLabelNum;
25
26//Caseスケジュール
27DWORD *pCaseSchedule;
28int CaseScheduleNum;
29int NowCaseSchedule;
30
31//グローバル変数初期バッファ
32BYTE *initGlobalBuf;
33
34//With情報
35WITHINFO WithInfo;
36
37
38
39///////////////////////////////////////////////////
40// トークンを取得
41///////////////////////////////////////////////////
42void GetIdentifierToken( char *token, const char *source, int &pos ){
43 for( int i=0; ; i++, pos++ ){
44 if( ! IsVariableChar( source[pos] ) ){
45 token[i] = 0;
46 break;
47 }
48 token[i] = source[pos];
49 }
50}
51
52
53///////////////////////////////////////////////////
54// 対になっているステートメントを飛び越す
55// ※グローバル領域用
56///////////////////////////////////////////////////
57int JumpStatement(const char *source, int &pos){
58 if( source[pos] != 1 ) return 0;
59
60 if( ! IsCommandDelimitation( source[pos - 1] ) ){
61 //直前がコマンド区切りではない場合
62 return 0;
63 }
64
65 char cStatement = source[pos + 1];
66
67 char cEnd = GetEndXXXCommand( cStatement );
68 if( cEnd == 0 ) return 0;
69
70 pos += 2;
71 while( ! ( source[pos] == 1 && source[pos + 1] == cEnd ) ){
72
73 if( source[pos] == '\0' ){
74 char temporary[64];
75 GetDefaultNameFromES( cStatement, temporary );
76 SetError( 22, temporary, pos );
77 return -1;
78 }
79
80 pos++;
81 }
82 if( ! ( source[pos] == '\0' || source[pos + 2] == '\0' ) ){
83 pos += 2;
84 }
85
86 return 1;
87}
88
89
90void NextLine(void){
91 extern HANDLE hHeap;
92 extern int MaxLineInfoNum;
93 extern LINEINFO *pLineInfo;
94 if(MaxLineInfoNum){
95 if(pLineInfo[MaxLineInfoNum-1].TopObp==obp){
96 pLineInfo[MaxLineInfoNum-1].TopCp=cp;
97 return;
98 }
99 }
100 pLineInfo=(LINEINFO *)HeapReAlloc(hHeap,0,pLineInfo,(MaxLineInfoNum+1)*sizeof(LINEINFO));
101 pLineInfo[MaxLineInfoNum].TopCp=cp;
102 pLineInfo[MaxLineInfoNum].TopObp=obp;
103
104 extern BOOL bDebugSupportProc;
105 extern BOOL bSystemProc;
106 pLineInfo[MaxLineInfoNum].dwCodeType=0;
107 if(bDebugSupportProc)
108 pLineInfo[MaxLineInfoNum].dwCodeType|=CODETYPE_DEBUGPROC;
109 if(bSystemProc)
110 pLineInfo[MaxLineInfoNum].dwCodeType|=CODETYPE_SYSTEMPROC;
111
112 MaxLineInfoNum++;
113}
114
115void ChangeOpcode(char *Command){
116 extern HANDLE hHeap;
117
118 if(Command[0]=='\0')
119 {
120 return;
121 }
122
123 trace_for_sourcecodestep( FormatEscapeSequenceStringToDefaultString(Command) );
124
125 if(Command[0]=='*'&&IsVariableTopChar(Command[1])){
126 //Goto先ラベル
127 pLabelNames=(LABEL *)HeapReAlloc(hHeap,0,pLabelNames,(MaxLabelNum+1)*sizeof(LABEL));
128 pLabelNames[MaxLabelNum].pName=(char *)HeapAlloc(hHeap,0,lstrlen(Command+1)+1);
129 lstrcpy(pLabelNames[MaxLabelNum].pName,Command+1);
130 pLabelNames[MaxLabelNum].address=obp;
131 MaxLabelNum++;
132
133 //書き込みスケジュール
134 std::vector<GotoLabelSchedule>::iterator it = compiler.codeGenerator.gotoLabelSchedules.begin();
135 while( it != compiler.codeGenerator.gotoLabelSchedules.end() )
136 {
137 if( it->GetName() == Command+1 )
138 {
139 *((long *)( OpBuffer + it->GetNativeCodePos() ))=obp-(it->GetNativeCodePos()+sizeof(long));
140
141 //詰める
142 it = compiler.codeGenerator.gotoLabelSchedules.erase( it );
143 }
144 else
145 {
146 it++;
147 }
148 }
149 return;
150 }
151 if(Command[0]==1){
152 switch(Command[1]){
153 case ESC_CONST:
154 OpcodeDim(Command+2, DIMFLAG_CONST);
155 break;
156
157 case ESC_TYPEDEF:
158 if( UserProc::IsLocalAreaCompiling() ){
159 // ローカル領域をコンパイルしているとき
160 SetError(65,"TypeDef",cp );
161 }
162
163 //既に収集済み
164 break;
165
166 case ESC_STATIC:
167 OpcodeDim(Command+2,DIMFLAG_STATIC);
168 break;
169
170 case ESC_IF:
171 OpcodeIf(Command+2);
172 break;
173 case ESC_EXITWHILE:
174 {
175 CScope *pScope = GetLexicalScopes().SearchScope( SCOPE_TYPE_WHILE );
176 if( !pScope ){
177 SetError(12,"Exit While",cp);
178 return;
179 }
180 pScope->Break();
181 }
182 break;
183 case ESC_EXITFOR:
184 {
185 CScope *pScope = GetLexicalScopes().SearchScope( SCOPE_TYPE_FOR );
186 if( !pScope ){
187 SetError(12,"Exit For",cp);
188 return;
189 }
190 pScope->Break();
191 }
192 break;
193 case ESC_EXITDO:
194 {
195 CScope *pScope = GetLexicalScopes().SearchScope( SCOPE_TYPE_DO );
196 if( !pScope ){
197 SetError(12,"Exit Do",cp);
198 return;
199 }
200 pScope->Break();
201 }
202 break;
203 case ESC_CONTINUE:
204 OpcodeContinue();
205 break;
206
207 case ESC_EXITSUB:
208 case ESC_EXITFUNCTION:
209 case ESC_EXITMACRO:
210 OpcodeExitSub();
211 break;
212
213 case ESC_SELECTCASE:
214 OpcodeSelect(Command+2);
215 break;
216 case ESC_CASE:
217 case ESC_CASEELSE:
218 OpcodeCase(Command+2);
219 break;
220
221 case ESC_WITH:
222 extern WITHINFO WithInfo;
223
224 WithInfo.ppName=(char **)HeapReAlloc(hHeap,0,WithInfo.ppName,(WithInfo.num+1)*sizeof(char **));
225 WithInfo.ppName[WithInfo.num]=(char *)HeapAlloc(hHeap,0,lstrlen(Command+2)+1);
226 lstrcpy(WithInfo.ppName[WithInfo.num],Command+2);
227
228 WithInfo.pWithCp=(int *)HeapReAlloc(hHeap,0,WithInfo.pWithCp,(WithInfo.num+1)*sizeof(int));
229 WithInfo.pWithCp[WithInfo.num]=cp;
230
231 WithInfo.num++;
232 break;
233 case ESC_ENDWITH:
234 if(WithInfo.num<=0){
235 SetError(12,"End With",cp);
236 return;
237 }
238 WithInfo.num--;
239 HeapDefaultFree(WithInfo.ppName[WithInfo.num]);
240 break;
241 case ESC_DECLARE:
242 if( UserProc::IsLocalAreaCompiling() ){
243 // ローカル領域をコンパイルしているとき
244 SetError(65,"Declare",cp );
245 }
246 break;
247
248 case ESC_NAMESPACE:
249 compiler.GetNamespaceSupporter().GetLivingNamespaceScopes().push_back( Command + 2 );
250 break;
251 case ESC_ENDNAMESPACE:
252 if( compiler.GetNamespaceSupporter().GetLivingNamespaceScopes().size() <= 0 ){
253 SetError(12,"End Namespace",cp);
254 }
255 compiler.GetNamespaceSupporter().GetLivingNamespaceScopes().pop_back();
256 break;
257 case ESC_IMPORTS:
258 compiler.GetNamespaceSupporter().ImportsNamespace( Command + 2 );
259 break;
260 case ESC_CLEARNAMESPACEIMPORTED:
261 compiler.GetNamespaceSupporter().GetImportedNamespaces().clear();
262 break;
263
264 //Tryによる例外処理
265 case ESC_TRY:
266 Exception::TryCommand();
267 break;
268 case ESC_CATCH:
269 Exception::CatchCommand();
270 break;
271 case ESC_FINALLY:
272 Exception::FinallyCommand();
273 break;
274 case ESC_ENDTRY:
275 Exception::EndTryCommand();
276 break;
277 case ESC_THROW:
278 Exception::ThrowCommand( Command + 2 );
279 break;
280
281 default:
282 char temporary[64];
283 GetDefaultNameFromES(Command[1],temporary);
284 SetError(30,temporary,cp);
285 break;
286 }
287 return;
288 }
289 switch(MAKEWORD(Command[1],Command[0])){
290 case COM_DIM:
291 OpcodeDim(Command+2,0);
292 break;
293 case COM_DELETE:
294 OpcodeDelete(Command+2, false);
295 break;
296 case COM_SWEEPINGDELETE:
297 OpcodeDelete(Command+2, true);
298 break;
299
300 case COM_GOTO:
301 OpcodeGoto(Command+2);
302 break;
303 case COM_WHILE:
304 OpcodeWhile(Command+2);
305 break;
306 case COM_FOR:
307 OpcodeFor(Command+2);
308 break;
309 case COM_DO:
310 OpcodeDo(Command+2);
311 break;
312
313 case COM_GOSUB:
314 OpcodeGosub(Command+2);
315 break;
316 case COM_RETURN:
317 OpcodeReturn(Command+2);
318 break;
319
320 case COM_SETDOUBLE:
321 OpcodeSetPtrData(Command+2,DEF_DOUBLE);
322 break;
323 case COM_SETSINGLE:
324 OpcodeSetPtrData(Command+2,DEF_SINGLE);
325 break;
326 case COM_SETQWORD:
327 OpcodeSetPtrData(Command+2,DEF_QWORD);
328 break;
329 case COM_SETDWORD:
330 OpcodeSetPtrData(Command+2,DEF_DWORD);
331 break;
332 case COM_SETWORD:
333 OpcodeSetPtrData(Command+2,DEF_WORD);
334 break;
335 case COM_SETBYTE:
336 OpcodeSetPtrData(Command+2,DEF_BYTE);
337 break;
338
339 case COM_DEBUG:
340 extern BOOL bDebugCompile;
341 //int 3
342 if(bDebugCompile) OpBuffer[obp++]=(char)0xCC;
343#if defined(_DEBUG)
344 else OpBuffer[obp++]=(char)0xCC;
345#endif
346 break;
347
348 case COM_LET:
349 OpcodeCalc(Command+2);
350 break;
351 default:
352 OpcodeOthers(Command);
353 break;
354 }
355}
356
357void GetGlobalDataForDll(void){
358 extern char *basbuf;
359 extern HANDLE hHeap;
360 int i2,BufferSize;
361 char *Command;
362 DWORD dwRetCode;
363
364 dwRetCode=0;
365 BufferSize=128;
366 Command=(char *)HeapAlloc(hHeap,0,BufferSize);
367 for(cp++,i2=0;;cp++,i2++){
368 if(i2>=BufferSize){
369 //バッファ領域が足りなくなった場合はバッファを増量する
370 BufferSize+=128;
371 Command=(char *)HeapReAlloc(hHeap,0,Command,BufferSize);
372 }
373 if(basbuf[cp]=='\"'){
374 Command[i2]=basbuf[cp];
375 for(cp++,i2++;;cp++,i2++){
376 if(i2>=BufferSize){
377 //バッファ領域が足りなくなった場合はバッファを増量する
378 BufferSize+=128;
379 Command=(char *)HeapReAlloc(hHeap,0,Command,BufferSize);
380 }
381 Command[i2]=basbuf[cp];
382 if(basbuf[cp]=='\"') break;
383 }
384 continue;
385 }
386 if(IsCommandDelimitation(basbuf[cp])){
387 Command[i2]=0;
388
389 if(Command[0]==1&&Command[1]==ESC_SUB){
390 i2=cp;
391 while(!(basbuf[cp]==1&&basbuf[cp+1]==ESC_ENDSUB)){
392 if(basbuf[cp]=='\0'){
393 SetError(22,"Sub",i2);
394 break;
395 }
396 cp++;
397 }
398 if(basbuf[cp+2]=='\0'||basbuf[cp]=='\0') break;
399 cp+=2;
400 i2=-1;
401 continue;
402 }
403 if(Command[0]==1&&Command[1]==ESC_FUNCTION){
404 i2=cp;
405 while(!(basbuf[cp]==1&&basbuf[cp+1]==ESC_ENDFUNCTION)){
406 if(basbuf[cp]=='\0'){
407 SetError(22,"Function",i2);
408 break;
409 }
410 cp++;
411 }
412 if(basbuf[cp+2]=='\0'||basbuf[cp]=='\0') break;
413 cp+=2;
414 i2=-1;
415 continue;
416 }
417 if(Command[0]==1&&Command[1]==ESC_MACRO){
418 i2=cp;
419 while(!(basbuf[cp]==1&&basbuf[cp+1]==ESC_ENDMACRO)){
420 if(basbuf[cp]=='\0'){
421 SetError(22,"Macro",i2);
422 break;
423 }
424 cp++;
425 }
426 if(basbuf[cp+2]=='\0'||basbuf[cp]=='\0') break;
427 cp+=2;
428 i2=-1;
429 continue;
430 }
431 if(Command[0]==1&&Command[1]==ESC_TYPE){
432 i2=cp;
433 while(!(basbuf[cp]==1&&basbuf[cp+1]==ESC_ENDTYPE)){
434 if(basbuf[cp]=='\0'){
435 SetError(22,"Type",i2);
436 break;
437 }
438 cp++;
439 }
440 if(basbuf[cp+2]=='\0'||basbuf[cp]=='\0') break;
441 cp+=2;
442 i2=-1;
443 continue;
444 }
445 if(Command[0]==1&&Command[1]==ESC_CLASS){
446 i2=cp;
447 while(!(basbuf[cp]==1&&basbuf[cp+1]==ESC_ENDCLASS)){
448 if(basbuf[cp]=='\0'){
449 SetError(22,"Class",i2);
450 break;
451 }
452 cp++;
453 }
454 if(basbuf[cp+2]=='\0'||basbuf[cp]=='\0') break;
455 cp+=2;
456 i2=-1;
457 continue;
458 }
459 if(Command[0]==1&&Command[1]==ESC_INTERFACE){
460 i2=cp;
461 while(!(basbuf[cp]==1&&basbuf[cp+1]==ESC_ENDINTERFACE)){
462 if(basbuf[cp]=='\0'){
463 SetError(22,"Interface",i2);
464 break;
465 }
466 cp++;
467 }
468 if(basbuf[cp+2]=='\0'||basbuf[cp]=='\0') break;
469 cp+=2;
470 i2=-1;
471 continue;
472 }
473
474 //DLLのグローバルデータに必要なコマンドだけ
475 if(MAKEWORD(Command[1],Command[0])==COM_DIM)
476 OpcodeDim(Command+2,0);
477
478 // ネイティブコードバッファの再確保
479 ReallocNativeCodeBuffer();
480
481 if(basbuf[cp]=='\0') break;
482 i2=-1;
483 continue;
484 }
485 Command[i2]=basbuf[cp];
486 }
487 HeapDefaultFree(Command);
488}
489DWORD CompileBuffer(char Return_Sequence,WORD Return_Command){
490 extern char *basbuf;
491 extern HANDLE hHeap;
492 int i,i2,i3,i4,BufferSize,ScopeStart;
493 char *Command,temporary[VN_SIZE],*temp2,temp3[32];
494 DWORD dwRetCode;
495
496 ScopeStart=cp;
497
498 dwRetCode=0;
499 BufferSize=128;
500 Command=(char *)HeapAlloc(hHeap,0,BufferSize);
501
502 for(cp++,i2=0;;cp++,i2++){
503 if(i2>=BufferSize){
504 //バッファ領域が足りなくなった場合はバッファを増量する
505 BufferSize+=128;
506 Command=(char *)HeapReAlloc(hHeap,0,Command,BufferSize);
507 }
508 if(basbuf[cp]=='\"'){
509 Command[i2]=basbuf[cp];
510 for(cp++,i2++;;cp++,i2++){
511 if(i2>=BufferSize){
512 //バッファ領域が足りなくなった場合はバッファを増量する
513 BufferSize+=128;
514 Command=(char *)HeapReAlloc(hHeap,0,Command,BufferSize);
515 }
516 Command[i2]=basbuf[cp];
517 if(basbuf[cp]=='\"') break;
518 }
519 continue;
520 }
521 if(IsCommandDelimitation(basbuf[cp])){
522 Command[i2]=0;
523
524 if(Command[0]==1&&Command[1]==ESC_LINENUM){
525 for(i=2,i2=0;;i++,i2++){
526 if(Command[i]==','){
527 temporary[i2]=0;
528 break;
529 }
530 temporary[i2]=Command[i];
531 }
532 i3=atoi(temporary);
533 i4=i+1;
534
535 //Goto先ラベル
536 pLabelNames=(LABEL *)HeapReAlloc(hHeap,0,pLabelNames,(MaxLabelNum+1)*sizeof(LABEL));
537 pLabelNames[MaxLabelNum].pName=0;
538 pLabelNames[MaxLabelNum].line=i3;
539 pLabelNames[MaxLabelNum].address=obp;
540 MaxLabelNum++;
541
542 //書き込みスケジュール
543 std::vector<GotoLabelSchedule>::iterator it = compiler.codeGenerator.gotoLabelSchedules.begin();
544 while( it != compiler.codeGenerator.gotoLabelSchedules.end() )
545 {
546 if( it->GetName().size() == 0 && it->GetLineNum() == i3 )
547 {
548 *((long *)( OpBuffer + it->GetNativeCodePos() ))=obp-(it->GetNativeCodePos()+sizeof(long));
549
550 //詰める
551 it = compiler.codeGenerator.gotoLabelSchedules.erase( it );
552 }
553 else
554 {
555 it++;
556 }
557 }
558
559 temp2=(char *)HeapAlloc(hHeap,0,lstrlen(Command+i4)+1);
560 lstrcpy(temp2,Command+i4);
561 lstrcpy(Command,temp2);
562 HeapDefaultFree(temp2);
563 }
564
565 if(Command[0]==1&&
566 (((Command[1]==ESC_VIRTUAL||Command[1]==ESC_OVERRIDE)&&Command[2]==1&&(Command[3]==ESC_SUB||Command[3]==ESC_FUNCTION))||
567 Command[1]==ESC_SUB||
568 Command[1]==ESC_FUNCTION||
569 Command[1]==ESC_MACRO||
570 Command[1]==ESC_TYPE||
571 Command[1]==ESC_CLASS||
572 Command[1]==ESC_INTERFACE||
573 Command[1]==ESC_ENUM||
574 (Command[1]==ESC_CONST&&Command[2]==1&&Command[3]==ESC_ENUM)
575 )
576 ){
577 if(Command[1]==ESC_VIRTUAL||Command[1]==ESC_OVERRIDE||Command[1]==ESC_CONST){
578 GetDefaultNameFromES(Command[3],temporary);
579 }
580 else{
581 GetDefaultNameFromES(Command[1],temporary);
582 }
583 if(Return_Sequence){
584 SetError(12,temporary,cp);
585 break;
586 }
587
588 if(Command[1]==ESC_CONST) i3=GetEndXXXCommand(Command[3]);
589 else i3=GetEndXXXCommand(Command[1]);
590 for(i2=cp;;cp++){
591 if(basbuf[cp]==1){
592 if(basbuf[cp+1]==i3) break;
593 if(Command[1]==ESC_CLASS||Command[1]==ESC_INTERFACE){
594 //クラス、インターフェイスではSub、Functionの定義を可能にしておく
595 if(basbuf[cp+1]==ESC_MACRO||
596 basbuf[cp+1]==ESC_TYPE||
597 basbuf[cp+1]==ESC_CLASS||
598 basbuf[cp+1]==ESC_INTERFACE||
599 basbuf[cp+1]==ESC_ENUM){
600 GetDefaultNameFromES(basbuf[cp+1],temp3);
601 SetError(12,temp3,cp);
602 }
603 }
604 else{
605 if(basbuf[cp-1]!='*'&&(
606 basbuf[cp+1]==ESC_VIRTUAL||
607 basbuf[cp+1]==ESC_OVERRIDE||
608 basbuf[cp+1]==ESC_SUB||
609 basbuf[cp+1]==ESC_FUNCTION||
610 basbuf[cp+1]==ESC_MACRO||
611 basbuf[cp+1]==ESC_TYPE||
612 basbuf[cp+1]==ESC_CLASS||
613 basbuf[cp+1]==ESC_INTERFACE||
614 basbuf[cp+1]==ESC_ENUM)){
615 GetDefaultNameFromES(basbuf[cp+1],temp3);
616 SetError(12,temp3,cp);
617 }
618 }
619 }
620 if(basbuf[cp]=='\0'){
621 //error
622 //既にエラー発行済みのため、何もせずに抜ける
623 break;
624 }
625 }
626 if(basbuf[cp+2]=='\0'||basbuf[cp]=='\0') break;
627 cp+=2;
628 i2=-1;
629 continue;
630 }
631
632 if(Command[0]==0x10||Command[0]==0x11){
633 //Wend、Next、Loopなど
634 if(Return_Command==MAKEWORD(Command[1],Command[0])){
635 if(Return_Command==COM_NEXT){
636 //Nextの場合は、パラメータ(省略化)の整合性を判断する必要がある(OpcodeFor関数を参照)
637 extern char szNextVariable[VN_SIZE];
638 if(Command[2]) lstrcpy(szNextVariable,Command+2);
639 else szNextVariable[0]=0;
640 }
641 break;
642 }
643 }
644
645 NextLine();
646
647 if(Command[0]==1){
648 if(Return_Sequence==ESC_ENDIF&&Command[1]==ESC_ELSE){
649 dwRetCode=ESC_ELSE;
650 break;
651 }
652
653 if(Command[1]==Return_Sequence){
654 dwRetCode=Command[1];
655 break;
656 }
657 }
658
659 try
660 {
661 ChangeOpcode(Command);
662 }
663 catch( const SmoothieException &smoothieException )
664 {
665 SetError(
666 smoothieException.GetErrorCode(),
667 smoothieException.GetKeyword(),
668 smoothieException.GetNowLine()
669 );
670 }
671
672
673 epi_check();
674
675
676 //コンパイルを中断するとき
677 extern BOOL bStopCompile;
678 if(bStopCompile) return 0;
679
680 ReallocNativeCodeBuffer();
681
682 if(basbuf[cp]=='\0'){
683 switch(Return_Command){
684 case COM_WEND:
685 SetError(4,"\"While\" - \"Wend\" ",ScopeStart);
686 break;
687 case COM_NEXT:
688 SetError(4,"\"For\" - \"Next\" ",ScopeStart);
689 break;
690 case COM_LOOP:
691 SetError(4,"\"Do\" - \"Loop\" ",ScopeStart);
692 break;
693 }
694 switch(Return_Sequence){
695 case ESC_ENDSUB:
696 SetError(4,"\"Sub\" - \"End Sub\" ",ScopeStart);
697 break;
698 case ESC_ENDFUNCTION:
699 SetError(4,"\"Function\" - \"End Function\" ",ScopeStart);
700 break;
701 case ESC_ENDMACRO:
702 SetError(4,"\"Macro\" - \"End Macro\" ",ScopeStart);
703 break;
704 case ESC_ENDIF:
705 SetError(22,"If",ScopeStart);
706 break;
707 }
708 break;
709 }
710 i2=-1;
711 continue;
712 }
713 Command[i2]=basbuf[cp];
714 }
715 HeapDefaultFree(Command);
716
717 return dwRetCode;
718}
Note: See TracBrowser for help on using the repository browser.