1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 //-----------------------------------------------------------------------------
19 //-----------------------------------------------------------------------------
21 #include "nel/misc/path.h"
22 #include "nel/misc/command.h"
23 #include "nel/misc/algo.h"
24 #include "nel/misc/sheet_id.h"
25 #include "game_share/file_description_container.h"
26 #include "game_share/persistent_data.h"
27 #include "game_share/singleton_registry.h"
28 #include "handy_commands.h"
31 //-----------------------------------------------------------------------------
32 // Very handy utility routines for the handy utility commands
33 //-----------------------------------------------------------------------------
35 static void readFileList(const NLMISC::CSString
& fileListName
, CFileDescriptionContainer
& result
)
37 // read the file list from disk (the result will be empty if the file list didn't exist)
38 NLMISC::CSString fileList
;
39 fileList
.readFromFile(fileListName
);
41 // split the file list text block into lines
42 NLMISC::CVectorSString files
;
43 fileList
.splitLines(files
);
45 // iterate over the lies in the input file
46 for(uint32 i
=0;i
<files
.size();++i
)
48 // clean lines up, stripping spaces and quotes
49 NLMISC::CSString theFile
= files
[i
].strip().unquoteIfQuoted();
51 // skip empty lines and comments
52 if (theFile
.empty() || theFile
.left(1)=="#")
55 // add the file name to the result
56 result
.addFile(theFile
);
60 static void addToFdc(const NLMISC::CSString
& filespec
, CFileDescriptionContainer
& result
)
62 if (filespec
.left(1)=="@")
64 readFileList(filespec
.leftCrop(1),result
);
68 result
.addFileSpec(filespec
);
73 //-----------------------------------------------------------------------------
74 // Handy utility commands - pdr
75 //-----------------------------------------------------------------------------
76 // pdrBin2xml <input file name> <output file name>
77 // pdrXml2bin <input file name> <output file name>
78 // pdr2xml <input file spec>
79 // pdr2bin <input file spec>
80 // pdr2txt <input file spec>
83 NLMISC_CATEGORISED_COMMAND(utils
,pdrBin2xml
,"convert a binary pdr file to xml","<input file name> <output file name>")
85 NLMISC::CNLLogOverride
logOverride(&log
);
90 log
.displayNL("Converting to XML : %s => %s",args
[0].c_str(),args
[1].c_str());
92 static CPersistentDataRecord pdr
;
94 pdr
.readFromBinFile(args
[0]);
95 pdr
.writeToTxtFile(args
[1]);
100 NLMISC_CATEGORISED_COMMAND(utils
,pdrXml2bin
,"convert a text pdr file to binary","<input file name> <output file name>")
102 NLMISC::CNLLogOverride
logOverride(&log
);
107 log
.displayNL("Converting to Binary : %s => %s",args
[0].c_str(),args
[1].c_str());
109 static CPersistentDataRecord pdr
;
111 pdr
.readFromTxtFile(args
[0]);
112 pdr
.writeToBinFile(args
[1]);
117 NLMISC_CATEGORISED_COMMAND(utils
,pdr2xml
,"convert one or more sets of pdr files to xml format","<input file spec>|'@'<listfile> [<input file spec>[...]]")
119 NLMISC::CNLLogOverride
logOverride(&log
);
124 for (uint32 i
=0;i
<args
.size();++i
)
126 CFileDescriptionContainer fdc
;
127 addToFdc(args
[i
],fdc
);
129 DROP_IF(fdc
.empty(),"No files found that match file spec: "<<args
[i
],continue);
131 for (uint32 j
=0;j
<fdc
.size();++j
)
133 const CFileDescription
& fd
=fdc
[j
];
134 NLMISC::CSString outputFileName
=
135 (fd
.FileName
.right(4).toLower()==".bin" || fd
.FileName
.right(4).toLower()==".txt")?
136 fd
.FileName
.rightCrop(4)+".xml": fd
.FileName
+".xml";
138 log
.displayNL("Converting to XML : %s => %s",fd
.FileName
.c_str(),outputFileName
.c_str());
139 static CPersistentDataRecord pdr
;
141 pdr
.readFromFile(fd
.FileName
);
142 pdr
.writeToFile(outputFileName
);
149 NLMISC_CATEGORISED_COMMAND(utils
,pdr2bin
,"convert one or more sets of pdr files to binary format","<input file spec>|'@'<listfile> [<input file spec>[...]]")
151 NLMISC::CNLLogOverride
logOverride(&log
);
156 for (uint32 i
=0;i
<args
.size();++i
)
158 CFileDescriptionContainer fdc
;
159 addToFdc(args
[i
],fdc
);
161 DROP_IF(fdc
.empty(),"No files found that match file spec: "<<args
[i
],continue);
163 for (uint32 j
=0;j
<fdc
.size();++j
)
165 const CFileDescription
& fd
=fdc
[j
];
166 NLMISC::CSString outputFileName
=
167 (fd
.FileName
.right(4).toLower()==".xml" || fd
.FileName
.right(4).toLower()==".txt")?
168 fd
.FileName
.rightCrop(4)+".bin": fd
.FileName
+".bin";
170 log
.displayNL("Converting to Binary : %s => %s",fd
.FileName
.c_str(),outputFileName
.c_str());
171 static CPersistentDataRecord pdr
;
173 pdr
.readFromFile(fd
.FileName
);
174 pdr
.writeToFile(outputFileName
);
181 NLMISC_CATEGORISED_COMMAND(utils
,pdr2txt
,"convert one or more sets of pdr files to txt (lines) format","<input file spec>|'@'<listfile> [<input file spec>[...]]")
183 NLMISC::CNLLogOverride
logOverride(&log
);
188 for (uint32 i
=0;i
<args
.size();++i
)
190 CFileDescriptionContainer fdc
;
191 addToFdc(args
[i
],fdc
);
193 DROP_IF(fdc
.empty(),"No files found that match file spec: "<<args
[i
],continue);
195 for (uint32 j
=0;j
<fdc
.size();++j
)
197 const CFileDescription
& fd
=fdc
[j
];
198 NLMISC::CSString outputFileName
=
199 (fd
.FileName
.right(4).toLower()==".bin" || fd
.FileName
.right(4).toLower()==".xml")?
200 fd
.FileName
.rightCrop(4)+".txt": fd
.FileName
+".txt";
202 log
.displayNL("Converting to TXT : %s => %s",fd
.FileName
.c_str(),outputFileName
.c_str());
203 static CPersistentDataRecord pdr
;
205 pdr
.readFromFile(fd
.FileName
);
206 pdr
.writeToFile(outputFileName
);
213 NLMISC_CATEGORISED_COMMAND(utils
,pdrFileCompare
,"Compare 2 pdr files","<first file> <second file>")
215 NLMISC::CNLLogOverride
logOverride(&log
);
220 CPersistentDataRecord pdr0
;
221 pdr0
.readFromFile(args
[0]);
223 CPersistentDataRecord pdr1
;
224 pdr1
.readFromFile(args
[1]);
226 log
.displayNL("%s : %s / %s", (pdr0
==pdr1
)?"Files MATCH":"Files DON'T match", args
[0].c_str(), args
[1].c_str());
231 NLMISC_CATEGORISED_COMMAND(utils
,pdrInfo
,"Extract info from pdr file(s)","<input file spec>|'@'<listfile> [<input file spec>[...]] [<output fil name>.csv]")
233 NLMISC::CNLLogOverride
logOverride(&log
);
235 NLMISC::CSString outputFileName
;
236 NLMISC::CSString csvTxt
;
237 uint32 numFileSpecs
=(uint32
)args
.size();
239 if (numFileSpecs
>0 && NLMISC::CSString(args
.back()).right(4)==".csv")
241 outputFileName
= args
.back();
243 log
.displayNL("Extracting PDR info to write to csv file: %s",outputFileName
.quoteIfNotQuoted().c_str());
244 csvTxt
= "FileName,"+ CPersistentDataRecord::getCSVHeaderLine()+"\n";
248 log
.displayNL("Extracting PDR info (No output file specified so no csv file will be written)",outputFileName
.quoteIfNotQuoted().c_str());
254 for (uint32 i
=0;i
<numFileSpecs
;++i
)
256 CFileDescriptionContainer fdc
;
258 H_AUTO(pdrInfo_BuildFDC
)
259 addToFdc(args
[i
],fdc
);
262 DROP_IF(fdc
.empty(),"No files found that match file spec: "<<args
[i
],continue);
264 for (uint32 j
=0;j
<fdc
.size();++j
)
266 H_AUTO(pdrInfo_treatFile
)
267 static CPersistentDataRecord pdr
;
270 const CFileDescription
& fd
=fdc
[j
];
271 log
.display("- %s: ", fd
.FileName
.quoteIfNotQuoted().c_str());
274 H_AUTO(pdrInfo_readFromFile
)
275 pdr
.readFromFile(fd
.FileName
);
278 log
.displayNL("%s", pdr
.getInfo().c_str());
280 if (!outputFileName
.empty())
282 csvTxt
+=NLMISC::CFile::getFilenameWithoutExtension(fd
.FileName
)+","+pdr
.getInfoAsCSV()+"\n";
287 if (!outputFileName
.empty())
289 log
.displayNL("Writing file: %s",outputFileName
.quoteIfNotQuoted().c_str());
290 csvTxt
.writeToFile(outputFileName
);
292 log
.displayNL("Info extraction from PDRs finished");
298 //-----------------------------------------------------------------------------
299 // Handy utility commands - file compare
300 //-----------------------------------------------------------------------------
301 // quickFileCompare <file0> <file1>
302 // thoroughFileCompare <file0> <file1> [<max mem footprint>]
304 NLMISC_CATEGORISED_COMMAND(utils
,quickFileCompare
,"compare 2 files (by comparing timestamp and size)","<file0> <file1>")
306 NLMISC::CNLLogOverride
logOverride(&log
);
311 nlinfo("comparing files ...");
312 bool result
= NLMISC::CFile::quickFileCompare(args
[0], args
[1]);
313 nlinfo("- %s",result
?"Same":"Different");
318 NLMISC_CATEGORISED_COMMAND(utils
,thoroughFileCompare
,"compare 2 files (by comparing data)","<file0> <file1> [<max mem footprint>]")
320 NLMISC::CNLLogOverride
logOverride(&log
);
322 if (args
.size()!=2 && args
.size()!=3)
326 nlinfo("comparing files ...");
331 NLMISC::fromString(args
[2], size
);
334 nlwarning("The third parameter must be a value >= 2 : The following value is not valid: %s",args
[2].c_str());
337 result
= NLMISC::CFile::thoroughFileCompare(args
[0], args
[1], size
);
341 result
= NLMISC::CFile::thoroughFileCompare(args
[0], args
[1]);
344 nlinfo("- %s",result
?"Same":"Different");
349 //-----------------------------------------------------------------------------
350 // Handy utility commands - file and directory management
351 //-----------------------------------------------------------------------------
354 // copyFile <src> <dest>
357 // deltree <directory>
360 NLMISC_CATEGORISED_COMMAND(utils
,cd
,"change directory or display current working directory","[<path>]")
362 NLMISC::CNLLogOverride
logOverride(&log
);
364 if (args
.size()!=0 && args
.size()!=1)
369 NLMISC::CPath::setCurrentPath(args
[0].c_str());
372 nlinfo("Current directory: %s",NLMISC::CPath::getCurrentPath().c_str());
376 NLMISC_CATEGORISED_COMMAND(utils
,md
,"create a new directory (or directory tree)","<path>")
378 NLMISC::CNLLogOverride
logOverride(&log
);
383 NLMISC::CFile::createDirectoryTree(args
[0]);
388 NLMISC_CATEGORISED_COMMAND(utils
,copyFile
,"copy a file","<src> <dest>")
390 NLMISC::CNLLogOverride
logOverride(&log
);
395 NLMISC::CFile::copyFile(args
[1],args
[0]);
400 NLMISC_CATEGORISED_COMMAND(utils
,del
,"delete a file","<fileName>")
402 NLMISC::CNLLogOverride
logOverride(&log
);
407 NLMISC::CFile::deleteFile(args
[0]);
412 NLMISC_CATEGORISED_COMMAND(utils
,dir
,"list files in the current directory","[<wildcard>]")
414 NLMISC::CNLLogOverride
logOverride(&log
);
416 if (args
.size()!=1 && args
.size()!=0)
419 std::string wildcard
="*";
423 std::vector
<std::string
> directories
;
424 NLMISC::CPath::getPathContent(".",false,true,false,directories
);
425 for (uint32 i
=(uint32
)directories
.size();i
--;)
427 if (!NLMISC::testWildCard(directories
[i
],wildcard
))
429 directories
[i
]=directories
.back();
430 directories
.pop_back();
433 std::sort(directories
.begin(),directories
.end());
434 for (uint32 i
=0;i
<directories
.size();++i
)
436 nlinfo("%s/",directories
[i
].c_str());
439 std::vector
<std::string
> files
;
440 NLMISC::CPath::getPathContent(".",false,false,true,files
);
441 for (uint32 i
=(uint32
)files
.size();i
--;)
443 if (!NLMISC::testWildCard(files
[i
],wildcard
))
445 files
[i
]=files
.back();
449 std::sort(files
.begin(),files
.end());
450 for (uint32 i
=0;i
<files
.size();++i
)
452 nlinfo("%-40s %10d",files
[i
].c_str(),NLMISC::CFile::getFileSize(files
[i
]));
458 NLMISC_CATEGORISED_COMMAND(utils
,deltree
,"delete all files matching given spec, recursively","<fileSpec>")
460 NLMISC::CNLLogOverride
logOverride(&log
);
465 CFileDescriptionContainer tempFiles
;
466 tempFiles
.addFileSpec(args
[0],true);
467 for (uint32 i
=0;i
<tempFiles
.size();++i
)
469 NLMISC::CFile::deleteFile(tempFiles
[i
].FileName
);
476 //-----------------------------------------------------------------------------
477 // Handy utility commands - file viewing
478 //-----------------------------------------------------------------------------
479 // viewTxtFile <file_name> [<first_line=1>[ <num_lines=100>]]
480 // viewBinFile <file_name> [<first_offset=0>[ <length=65536>]]
482 NLMISC_CATEGORISED_COMMAND(utils
,viewTxtFile
,"view a text file segment","<file_name> [<first_line=1>[ <num_lines=100>]]")
484 NLMISC::CNLLogOverride
logOverride(&log
);
486 // deal with command line arguments
492 NLMISC::fromString(args
[2], count
);
493 if (count
<1||args
[2]!=NLMISC::toString("%u",count
))
497 NLMISC::fromString(args
[1], firstLine
);
498 if (firstLine
<1||args
[1]!=NLMISC::toString("%u",firstLine
))
508 NLMISC::CSString fileBody
;
509 fileBody
.readFromFile(args
[0]);
510 if (fileBody
.empty())
512 nlwarning("File not found or file empty: %s",args
[0].c_str());
516 // if we have a utf16 file then convert to utf8
517 if (fileBody
.size()>=2 && ((fileBody
[0]==char(0xff) && fileBody
[1]==char(0xfe)) || (fileBody
[0]==char(0xfe) && fileBody
[1]==char(0xff))) )
519 nlinfo("Displaying unicode UTF16 text:");
521 ucs
.resize((fileBody
.size()-2)/2);
522 memcpy((char*)&ucs
[0],(char*)&fileBody
[0],fileBody
.size()-2);
523 fileBody
=ucs
.toUtf8();
526 // split the new file into lines
527 NLMISC::CVectorSString lines
;
528 fileBody
.splitLines(lines
);
531 nlinfo("Listing lines %u to %u of %u for file: %s",firstLine
,std::min(uint32(firstLine
+count
-1),(uint32
)lines
.size()),lines
.size(),args
[0].c_str());
532 for (uint32 i
=0;i
<count
&& i
+firstLine
<=lines
.size();++i
)
533 nlinfo("%6i %s",i
+firstLine
,lines
[i
+firstLine
-1].c_str());
538 NLMISC_CATEGORISED_COMMAND(utils
,viewBinFile
,"view a binary file segment","<file_name> [<first_offset=0>[ <length=65536>]]")
540 NLMISC::CNLLogOverride
logOverride(&log
);
542 // deal with command line arguments
548 NLMISC::fromString(args
[2], count
);
549 if (count
<1||args
[2]!=NLMISC::toString("%u",count
))
553 NLMISC::fromString(args
[1], start
);
554 if (args
[1]!=NLMISC::toString("%u",start
))
563 // read the new file and convert to lines
564 NLMISC::CSString fileBody
;
565 fileBody
.readFromFile(args
[0]);
566 if (fileBody
.empty())
568 nlwarning("File not found or file empty: %s",args
[0].c_str());
572 // ensure start is valid
573 if (start
>=fileBody
.size())
575 nlwarning("first_offset (%u) beyond end of file (%u): %s",start
,fileBody
.size(),args
[0].c_str());
579 // clamp the value of 'count'
580 if (start
+count
>fileBody
.size())
582 count
= (uint32
)fileBody
.size()-start
;
586 uint32 entriesPerLine
=20;
587 nlinfo("Dumping offset %u to %u of %u for file: %s",start
,start
+count
,fileBody
.size(),args
[0].c_str());
588 for (uint32 i
=0;i
<(count
+15)/entriesPerLine
;++i
)
592 // generate the address
593 s
= NLMISC::toString("%10u ",start
+entriesPerLine
*i
);
595 // generate the hex text
597 for (;j
<entriesPerLine
&& entriesPerLine
*i
+j
<count
;++j
)
598 s
+=NLMISC::toString("%02X ",(uint8
)fileBody
[start
+entriesPerLine
*i
+j
]);
600 // pad out to the start of the ASCII text
601 for (;j
<entriesPerLine
;++j
)
605 // generate the ASCII text
606 for (j
=0;j
<entriesPerLine
&& entriesPerLine
*i
+j
<count
;++j
)
607 s
+=NLMISC::CSString::isPrintable(fileBody
[start
+entriesPerLine
*i
+j
])?fileBody
[start
+entriesPerLine
*i
+j
]:'.';
610 log
.displayNL("%s",s
.c_str());
616 //-----------------------------------------------------------------------------
617 // Handy utility commands - text editing
618 //-----------------------------------------------------------------------------
619 // txtEditAppend <text>
620 // txtEditCopy <start_line> <end_line> <insert_location>
621 // txtEditDeleteLines <first_line>[ <last_line>]
623 // txtEditInsert <line_number> <text>
624 // txtEditList [<first_line=1>[ <num_lines=100>]]
625 // txtEditMergeFile <insert_location> <file_name> [<first_line> <last_line>]
626 // txtEditNew <fileName>
627 // txtEditRead <fileName>
628 // txtEditSet <line_number> <text>
629 // txtEditToFile <file name>
633 static NLMISC::CSString TxtEditFileName
;
634 static NLMISC::CVectorSString TxtEditLines
;
636 NLMISC_CATEGORISED_COMMAND(utils
,txtEditUnload
,"unload the text file in ram","")
638 NLMISC::CNLLogOverride
logOverride(&log
);
643 TxtEditFileName
.clear();
644 TxtEditLines
.clear();
649 NLMISC_CATEGORISED_COMMAND(utils
,txtEditRead
,"load a text file into ram","<fileName>")
651 NLMISC::CNLLogOverride
logOverride(&log
);
656 // make sure there is no file currently loaded
657 if (!TxtEditFileName
.empty())
659 nlwarning("unable to open file '%s' because file '%s' is already open",args
[0].c_str(),TxtEditFileName
.c_str());
663 // check that the file exists
664 if (!NLMISC::CFile::fileExists(args
[0]))
666 nlwarning("File Not Found: %s",args
[0].c_str());
670 // read the file and split into lines
671 NLMISC::CSString fileBody
;
672 fileBody
.readFromFile(args
[0]);
673 fileBody
.splitLines(TxtEditLines
);
676 TxtEditFileName
=args
[0];
677 nlinfo("Loaded %u lines from file :%s",TxtEditLines
.size(),TxtEditFileName
.c_str());
681 NLMISC_CATEGORISED_COMMAND(utils
,txtEditMergeFile
,"load a text file into ram","<insert_location> <file_name> [<first_line> <last_line>]")
683 NLMISC::CNLLogOverride
logOverride(&log
);
685 // make sure there is a file currently loaded
686 if (TxtEditFileName
.empty())
688 nlwarning("no text file currently loaded - nothing to save");
692 // make sure there's a valid arg count
702 // get the insert location and make sure it's valid
703 uint32 insertPosition
;
704 NLMISC::fromString(args
[0], insertPosition
);
705 if (insertPosition
<1|| args
[0]!=NLMISC::toString("%u",insertPosition
)) return false;
706 if (insertPosition
>TxtEditLines
.size()+1) { nlwarning("Invalid insert position"); return false; }
708 // read the new file and convert to lines
709 NLMISC::CVectorSString newLines
;
710 NLMISC::CSString fileBody
;
711 fileBody
.readFromFile(args
[1]);
712 fileBody
.splitLines(newLines
);
713 if (fileBody
.empty()) { nlwarning("File not found or file empty: %s",args
[1].c_str()); return false; }
717 // we have to merge in the whole file...
718 TxtEditLines
.insert(TxtEditLines
.begin()+(insertPosition
-1),newLines
.begin(),newLines
.end());
719 nlinfo("Merged in %u lines from file :%s",newLines
.size(),args
[1].c_str());
723 // we only want part of the new file
725 // determine the first and last lines to extract from the new file
726 uint32 firstLine
, lastLine
;
727 NLMISC::fromString(args
[2], firstLine
);
728 if (firstLine
<1|| args
[2]!=NLMISC::toString("%u",firstLine
)) return false;
729 NLMISC::fromString(args
[3], lastLine
);
730 if (lastLine
<1|| args
[3]!=NLMISC::toString("%u",lastLine
)) return false;
732 // make sure the line numbers are valid
733 if (firstLine
==0||firstLine
>lastLine
||lastLine
>newLines
.size())
735 nlwarning("invalid line number argument or first line is beyond last line");
740 NLMISC::CVectorSString
linesToMerge(newLines
.begin()+(firstLine
-1),newLines
.begin()+lastLine
);
741 TxtEditLines
.insert(TxtEditLines
.begin()+(insertPosition
-1),linesToMerge
.begin(),linesToMerge
.end());
742 nlinfo("Merged in %u lines from file :%s",linesToMerge
.size(),args
[1].c_str());
748 NLMISC_CATEGORISED_COMMAND(utils
,txtEditNew
,"prepare to edit a new textfile","<fileName>")
750 NLMISC::CNLLogOverride
logOverride(&log
);
755 // make sure there is no file currently loaded
756 if (!TxtEditFileName
.empty())
758 nlwarning("unable to craete new file '%s' because file '%s' is already open",args
[0].c_str(),TxtEditFileName
.c_str());
762 // check that the file doesn't exist
763 if (NLMISC::CFile::fileExists(args
[0]))
765 nlwarning("File Already Exists: %s",args
[0].c_str());
770 TxtEditLines
.clear();
771 TxtEditFileName
=args
[0];
772 nlinfo("Created new empty buffer for file :%s",TxtEditFileName
.c_str());
776 NLMISC_CATEGORISED_COMMAND(utils
,txtEditWrite
,"save a modified text file","")
778 NLMISC::CNLLogOverride
logOverride(&log
);
783 // make sure there is a file currently loaded
784 if (TxtEditFileName
.empty())
786 nlwarning("no text file currently loaded - nothing to save");
790 // join the lines and write to file
791 nlinfo("Writing %u lines to file :%s",TxtEditLines
.size(),TxtEditFileName
.c_str());
792 NLMISC::CSString fileBody
;
793 fileBody
.join(TxtEditLines
,'\n');
794 fileBody
.writeToFile(TxtEditFileName
);
800 NLMISC_CATEGORISED_COMMAND(utils
,txtEditToFile
,"save a loaded text file","<file name>")
802 NLMISC::CNLLogOverride
logOverride(&log
);
807 // make sure there is a file currently loaded
808 if (TxtEditFileName
.empty())
810 nlwarning("no text file currently loaded - nothing to save");
814 // check that the file doesn't exist
815 if (NLMISC::CFile::fileExists(args
[0]))
817 nlwarning("File Already Exists: %s",args
[0].c_str());
821 // set the new file name
822 TxtEditFileName
=args
[0];
824 // join the lines and write to file
825 nlinfo("Writing %u lines to file :%s",TxtEditLines
.size(),TxtEditFileName
.c_str());
826 NLMISC::CSString fileBody
;
827 fileBody
.join(TxtEditLines
,'\n');
828 fileBody
.writeToFile(TxtEditFileName
);
834 NLMISC_CATEGORISED_COMMAND(utils
,txtEditList
,"list the lines in a loaded textfile","[<first_line=1>[ <num_lines=100>]]")
836 NLMISC::CNLLogOverride
logOverride(&log
);
838 // make sure there is a file currently loaded
839 if (TxtEditFileName
.empty())
841 nlwarning("no text file currently loaded");
845 // deal with command line arguments
851 NLMISC::fromString(args
[1], count
);
852 if (count
<1||args
[1]!=NLMISC::toString("%u",count
))
856 NLMISC::fromString(args
[0], firstLine
);
857 if (firstLine
<1||args
[0]!=NLMISC::toString("%u",firstLine
))
867 nlinfo("Listing lines %u to %u of %u for file: %s",firstLine
,std::min(uint32(firstLine
+count
-1),(uint32
)TxtEditLines
.size()),TxtEditLines
.size(),TxtEditFileName
.c_str());
868 for (uint32 i
=0;i
<count
&& i
+firstLine
<=TxtEditLines
.size();++i
)
869 nlinfo("%6i %s",i
+firstLine
,TxtEditLines
[i
+firstLine
-1].c_str());
874 NLMISC_CATEGORISED_COMMAND(utils
,txtEditDeleteLines
,"delete one or more lines in a loaded textfile","<first_line>[ <last_line>]")
876 NLMISC::CNLLogOverride
logOverride(&log
);
878 // make sure there is a file currently loaded
879 if (TxtEditFileName
.empty())
881 nlwarning("no text file currently loaded");
885 // deal with command line arguments
891 NLMISC::fromString(args
[1], lastLine
);
892 if (lastLine
<1||args
[1]!=NLMISC::toString("%u",lastLine
))
896 NLMISC::fromString(args
[0], firstLine
);
897 if (firstLine
<1||args
[0]!=NLMISC::toString("%u",firstLine
))
908 if (lastLine
<firstLine
)
910 nlwarning("last_line (%u) must be >= first_line (%u)",lastLine
,firstLine
);
914 // ensure that the lines to be deleted fall within the file
915 if (lastLine
>TxtEditLines
.size())
917 nlwarning("last_line (%u) must be <= num lines (%u) in file: %s",lastLine
,TxtEditLines
.size(),args
[0].c_str());
922 nlinfo("Deleting lines %u to %u of %u for file: %s",firstLine
,lastLine
,TxtEditLines
.size(),args
[0].c_str());
923 TxtEditLines
.erase(TxtEditLines
.begin()+firstLine
-1,TxtEditLines
.begin()+lastLine
);
928 NLMISC_CATEGORISED_COMMAND(utils
,txtEditErase
,"erase all of the current contents of the currently loaded file","")
930 NLMISC::CNLLogOverride
logOverride(&log
);
935 // make sure there is a file currently loaded
936 if (TxtEditFileName
.empty())
938 nlwarning("no text file currently loaded");
943 TxtEditLines
.clear();
948 NLMISC_CATEGORISED_COMMAND(utils
,txtEditAppend
,"append a line of text to a loaded textfile","<text>")
950 NLMISC::CNLLogOverride
logOverride(&log
);
955 // make sure there is a file currently loaded
956 if (TxtEditFileName
.empty())
958 nlwarning("no text file currently loaded");
962 TxtEditLines
.push_back(args
[0]);
967 NLMISC_CATEGORISED_COMMAND(utils
,txtEditCopy
,"duplicate a segment of the text file and insert it at the given location","<start_line> <end_line> <insert_location>")
969 NLMISC::CNLLogOverride
logOverride(&log
);
974 // make sure there is a file currently loaded
975 if (TxtEditFileName
.empty())
977 nlwarning("no text file currently loaded");
981 // extract numeric values for args and verify theri validity
982 uint32 firstLine
, lastLine
, insertPosition
;
983 NLMISC::fromString(args
[0], firstLine
);
984 if (firstLine
<1|| args
[0]!=NLMISC::toString("%u",firstLine
)) return false;
985 NLMISC::fromString(args
[1], lastLine
);
986 if (lastLine
<1|| args
[1]!=NLMISC::toString("%u",lastLine
)) return false;
987 NLMISC::fromString(args
[2], insertPosition
);
988 if (insertPosition
<1|| args
[2]!=NLMISC::toString("%u",insertPosition
)) return false;
990 // make sure the line numbers are valid
991 if (firstLine
>lastLine
||lastLine
>TxtEditLines
.size()||insertPosition
>TxtEditLines
.size()+1)
993 nlwarning("invalid line number argument or first line is beyond last line");
997 // duplicate the lines in question and insert them
998 NLMISC::CVectorSString
newLines(TxtEditLines
.begin()+firstLine
-1,TxtEditLines
.begin()+lastLine
);
999 TxtEditLines
.insert(TxtEditLines
.begin()+(insertPosition
-1),newLines
.begin(),newLines
.end());
1004 NLMISC_CATEGORISED_COMMAND(utils
,txtEditInsert
,"insert a line into a loaded text file","<line_number> <text>")
1006 NLMISC::CNLLogOverride
logOverride(&log
);
1011 // make sure there is a file currently loaded
1012 if (TxtEditFileName
.empty())
1014 nlwarning("no text file currently loaded");
1018 // extract the line number
1020 NLMISC::fromString(args
[0], lineNumber
);
1021 if (lineNumber
<1||args
[0]!=NLMISC::toString("%u",lineNumber
))
1024 // deal with special case of insert at end of buffer
1025 if (lineNumber
==TxtEditLines
.size()+1)
1027 TxtEditLines
.push_back(args
[1]);
1031 // make sure the line number falls within the file
1032 if (lineNumber
>TxtEditLines
.size())
1034 nlwarning("line number (%u) must be less than or equal to num lines in file (%u)",lineNumber
,TxtEditLines
.size());
1038 TxtEditLines
.insert(TxtEditLines
.begin()+(lineNumber
-1),args
[1]);
1042 NLMISC_CATEGORISED_COMMAND(utils
,txtEditSet
,"change a line in a loaded text file","<line_number> <text>")
1044 NLMISC::CNLLogOverride
logOverride(&log
);
1049 // make sure there is a file currently loaded
1050 if (TxtEditFileName
.empty())
1052 nlwarning("no text file currently loaded");
1056 // extract the line number
1058 NLMISC::fromString(args
[0], lineNumber
);
1059 if (lineNumber
<1||args
[0]!=NLMISC::toString("%u",lineNumber
))
1062 // make sure the line number falls within the file
1063 if (lineNumber
>TxtEditLines
.size())
1065 nlwarning("line number (%u) must be less than or equal to num lines in file (%u)",lineNumber
,TxtEditLines
.size());
1069 TxtEditLines
[lineNumber
-1]= args
[1];
1074 //-----------------------------------------------------------------------------
1075 // init the sheetid.bin file for use by PDR
1076 //-----------------------------------------------------------------------------
1078 class CForSheetId
: public IServiceSingleton
1083 // NLMISC::CSheetId::init(false);
1087 static CForSheetId ForSheetId
;
1090 //-------------------------------------------------------------------------------------------------
1091 // Fake variable to force a link to the handy_commands module
1092 //-------------------------------------------------------------------------------------------------
1094 CHandyCommandIncluderClass::CHandyCommandIncluderClass()
1096 static bool firstTime
= true;
1101 // nldebug("Activating Handy Commands");
1106 //-----------------------------------------------------------------------------