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

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

Labelクラスをリファクタリング

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