Imported Upstream version 2.8.9
[platform/upstream/cmake.git] / Source / cmStringCommand.cxx
1 /*============================================================================
2   CMake - Cross Platform Makefile Generator
3   Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
4
5   Distributed under the OSI-approved BSD License (the "License");
6   see accompanying file Copyright.txt for details.
7
8   This software is distributed WITHOUT ANY WARRANTY; without even the
9   implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10   See the License for more information.
11 ============================================================================*/
12 #include "cmStringCommand.h"
13 #include "cmCryptoHash.h"
14
15 #include <cmsys/RegularExpression.hxx>
16 #include <cmsys/SystemTools.hxx>
17
18 #include <stdlib.h> // required for atoi
19 #include <ctype.h>
20 #include <time.h>
21
22 //----------------------------------------------------------------------------
23 bool cmStringCommand
24 ::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
25 {
26   if(args.size() < 1)
27     {
28     this->SetError("must be called with at least one argument.");
29     return false;
30     }
31   
32   const std::string &subCommand = args[0];
33   if(subCommand == "REGEX")
34     {
35     return this->HandleRegexCommand(args);
36     }
37   else if(subCommand == "REPLACE")
38     {
39     return this->HandleReplaceCommand(args);
40     }
41   else if ( subCommand == "MD5" ||
42             subCommand == "SHA1" ||
43             subCommand == "SHA224" ||
44             subCommand == "SHA256" ||
45             subCommand == "SHA384" ||
46             subCommand == "SHA512" )
47     {
48     return this->HandleHashCommand(args);
49     }
50   else if(subCommand == "TOLOWER")
51     {
52     return this->HandleToUpperLowerCommand(args, false);
53     }
54   else if(subCommand == "TOUPPER")
55     {
56     return this->HandleToUpperLowerCommand(args, true);
57     }
58   else if(subCommand == "COMPARE")
59     {
60     return this->HandleCompareCommand(args);
61     }
62   else if(subCommand == "ASCII")
63     {
64     return this->HandleAsciiCommand(args);
65     }
66   else if(subCommand == "CONFIGURE")
67     {
68     return this->HandleConfigureCommand(args);
69     }
70   else if(subCommand == "LENGTH")
71     {
72     return this->HandleLengthCommand(args);
73     }
74   else if(subCommand == "SUBSTRING")
75     {
76     return this->HandleSubstringCommand(args);
77     }
78   else if(subCommand == "STRIP")
79     {
80     return this->HandleStripCommand(args);
81     }
82   else if(subCommand == "RANDOM")
83     {
84     return this->HandleRandomCommand(args);
85     }
86   else if(subCommand == "FIND")
87     {
88     return this->HandleFindCommand(args);
89     }
90
91   std::string e = "does not recognize sub-command "+subCommand;
92   this->SetError(e.c_str());
93   return false;
94 }
95
96 //----------------------------------------------------------------------------
97 bool cmStringCommand::HandleHashCommand(std::vector<std::string> const& args)
98 {
99 #if defined(CMAKE_BUILD_WITH_CMAKE)
100   if(args.size() != 3)
101     {
102     cmOStringStream e;
103     e << args[0] << " requires an output variable and an input string";
104     this->SetError(e.str().c_str());
105     return false;
106     }
107
108   cmsys::auto_ptr<cmCryptoHash> hash(cmCryptoHash::New(args[0].c_str()));
109   if(hash.get())
110     {
111     std::string out = hash->HashString(args[2].c_str());
112     this->Makefile->AddDefinition(args[1].c_str(), out.c_str());
113     return true;
114     }
115   return false;
116 #else
117   cmOStringStream e;
118   e << args[0] << " not available during bootstrap";
119   this->SetError(e.str().c_str());
120   return false;
121 #endif
122 }
123
124 //----------------------------------------------------------------------------
125 bool cmStringCommand::HandleToUpperLowerCommand(
126   std::vector<std::string> const& args, bool toUpper)
127 {
128   if ( args.size() < 3 )
129     {
130     this->SetError("no output variable specified");
131     return false;
132     }
133
134   std::string outvar = args[2];
135   std::string output;
136
137   if (toUpper) 
138     {
139     output = cmSystemTools::UpperCase(args[1]);
140     } 
141   else 
142     {
143     output = cmSystemTools::LowerCase(args[1]);
144     }
145
146   // Store the output in the provided variable.
147   this->Makefile->AddDefinition(outvar.c_str(), output.c_str());
148   return true;
149 }
150
151 //----------------------------------------------------------------------------
152 bool cmStringCommand::HandleAsciiCommand(std::vector<std::string> const& args)
153 {
154   if ( args.size() < 3 )
155     {
156     this->SetError("No output variable specified");
157     return false;
158     }
159   std::string::size_type cc;
160   std::string outvar = args[args.size()-1];
161   std::string output = "";
162   for ( cc = 1; cc < args.size()-1; cc ++ )
163     {
164     int ch = atoi(args[cc].c_str());
165     if ( ch > 0 && ch < 256 )
166       {
167       output += static_cast<char>(ch);
168       }
169     else
170       {
171       std::string error = "Character with code ";
172       error += args[cc];
173       error += " does not exist.";
174       this->SetError(error.c_str());
175       return false;
176       }
177     }
178   // Store the output in the provided variable.
179   this->Makefile->AddDefinition(outvar.c_str(), output.c_str());
180   return true;
181 }
182
183 //----------------------------------------------------------------------------
184 bool cmStringCommand::HandleConfigureCommand(
185   std::vector<std::string> const& args)
186 {
187   if ( args.size() < 2 )
188     {
189     this->SetError("No input string specified.");
190     return false;
191     }
192   else if ( args.size() < 3 )
193     {
194     this->SetError("No output variable specified.");
195     return false;
196     }
197
198   // Parse options.
199   bool escapeQuotes = false;
200   bool atOnly = false;
201   for(unsigned int i = 3; i < args.size(); ++i)
202     {
203     if(args[i] == "@ONLY")
204       {
205       atOnly = true;
206       }
207     else if(args[i] == "ESCAPE_QUOTES")
208       {
209       escapeQuotes = true;
210       }
211     else
212       {
213       cmOStringStream err;
214       err << "Unrecognized argument \"" << args[i] << "\"";
215       this->SetError(err.str().c_str());
216       return false;
217       }
218     }
219
220   // Configure the string.
221   std::string output;
222   this->Makefile->ConfigureString(args[1], output, atOnly, escapeQuotes);
223
224   // Store the output in the provided variable.
225   this->Makefile->AddDefinition(args[2].c_str(), output.c_str());
226
227   return true;
228 }
229
230 //----------------------------------------------------------------------------
231 bool cmStringCommand::HandleRegexCommand(std::vector<std::string> const& args)
232 {
233   if(args.size() < 2)
234     {
235     this->SetError("sub-command REGEX requires a mode to be specified.");
236     return false;
237     }
238   std::string mode = args[1];
239   if(mode == "MATCH")
240     {
241     if(args.size() < 5)
242       {
243       this->SetError("sub-command REGEX, mode MATCH needs "
244                      "at least 5 arguments total to command.");
245       return false;
246       }
247     return this->RegexMatch(args);
248     }
249   else if(mode == "MATCHALL")
250     {
251     if(args.size() < 5)
252       {
253       this->SetError("sub-command REGEX, mode MATCHALL needs "
254                      "at least 5 arguments total to command.");
255       return false;
256       }
257     return this->RegexMatchAll(args);
258     }
259   else if(mode == "REPLACE")
260     {
261     if(args.size() < 6)
262       {
263       this->SetError("sub-command REGEX, mode REPLACE needs "
264                      "at least 6 arguments total to command.");
265       return false;
266       }
267     return this->RegexReplace(args);
268     }
269   
270   std::string e = "sub-command REGEX does not recognize mode "+mode;
271   this->SetError(e.c_str());
272   return false;
273 }
274
275 //----------------------------------------------------------------------------
276 bool cmStringCommand::RegexMatch(std::vector<std::string> const& args)
277 {
278   //"STRING(REGEX MATCH <regular_expression> <output variable>
279   // <input> [<input>...])\n";
280   std::string regex = args[2];
281   std::string outvar = args[3];
282   
283   // Concatenate all the last arguments together.
284   std::string input = args[4];
285   for(unsigned int i=5; i < args.size(); ++i)
286     {
287     input += args[i];
288     }
289   
290   this->ClearMatches(this->Makefile);
291   // Compile the regular expression.
292   cmsys::RegularExpression re;
293   if(!re.compile(regex.c_str()))
294     {
295     std::string e = 
296       "sub-command REGEX, mode MATCH failed to compile regex \""+regex+"\".";
297     this->SetError(e.c_str());
298     return false;
299     }
300   
301   // Scan through the input for all matches.
302   std::string output;
303   if(re.find(input.c_str()))
304     {
305     this->StoreMatches(this->Makefile, re);
306     std::string::size_type l = re.start();
307     std::string::size_type r = re.end();
308     if(r-l == 0)
309       {
310       std::string e = 
311         "sub-command REGEX, mode MATCH regex \""+regex+
312         "\" matched an empty string.";
313       this->SetError(e.c_str());
314       return false;
315       }
316     output = input.substr(l, r-l);
317     }
318   
319   // Store the output in the provided variable.
320   this->Makefile->AddDefinition(outvar.c_str(), output.c_str());
321   return true;
322 }
323
324 //----------------------------------------------------------------------------
325 bool cmStringCommand::RegexMatchAll(std::vector<std::string> const& args)
326 {
327   //"STRING(REGEX MATCHALL <regular_expression> <output variable> <input> 
328   // [<input>...])\n";
329   std::string regex = args[2];
330   std::string outvar = args[3];
331   
332   // Concatenate all the last arguments together.
333   std::string input = args[4];
334   for(unsigned int i=5; i < args.size(); ++i)
335     {
336     input += args[i];
337     }
338   
339   this->ClearMatches(this->Makefile);
340   // Compile the regular expression.
341   cmsys::RegularExpression re;
342   if(!re.compile(regex.c_str()))
343     {
344     std::string e =
345       "sub-command REGEX, mode MATCHALL failed to compile regex \""+
346       regex+"\".";
347     this->SetError(e.c_str());
348     return false;
349     }
350   
351   // Scan through the input for all matches.
352   std::string output;
353   const char* p = input.c_str();
354   while(re.find(p))
355     {
356     this->StoreMatches(this->Makefile, re);
357     std::string::size_type l = re.start();
358     std::string::size_type r = re.end();
359     if(r-l == 0)
360       {
361       std::string e = "sub-command REGEX, mode MATCHALL regex \""+
362         regex+"\" matched an empty string.";
363       this->SetError(e.c_str());
364       return false;
365       }
366     if(output.length() > 0)
367       {
368       output += ";";
369       }
370     output += std::string(p+l, r-l);
371     p += r;
372     }
373   
374   // Store the output in the provided variable.
375   this->Makefile->AddDefinition(outvar.c_str(), output.c_str());
376   return true;
377 }
378
379 //----------------------------------------------------------------------------
380 bool cmStringCommand::RegexReplace(std::vector<std::string> const& args)
381 {
382   //"STRING(REGEX REPLACE <regular_expression> <replace_expression> 
383   // <output variable> <input> [<input>...])\n"
384   std::string regex = args[2];
385   std::string replace = args[3];  
386   std::string outvar = args[4];
387   
388   // Pull apart the replace expression to find the escaped [0-9] values.
389   std::vector<RegexReplacement> replacement;
390   std::string::size_type l = 0;
391   while(l < replace.length())
392     {
393     std::string::size_type r = replace.find("\\", l);
394     if(r == std::string::npos)
395       {
396       r = replace.length();
397       replacement.push_back(replace.substr(l, r-l));
398       }
399     else
400       {
401       if(r-l > 0)
402         {
403         replacement.push_back(replace.substr(l, r-l));
404         }
405       if(r == (replace.length()-1))
406         {
407         this->SetError("sub-command REGEX, mode REPLACE: "
408                        "replace-expression ends in a backslash.");
409         return false;
410         }
411       if((replace[r+1] >= '0') && (replace[r+1] <= '9'))
412         {
413         replacement.push_back(replace[r+1]-'0');
414         }
415       else if(replace[r+1] == 'n')
416         {
417         replacement.push_back("\n");
418         }
419       else if(replace[r+1] == '\\')
420         {
421         replacement.push_back("\\");
422         }
423       else
424         {
425         std::string e = "sub-command REGEX, mode REPLACE: Unknown escape \"";
426         e += replace.substr(r, 2);
427         e += "\" in replace-expression.";
428         this->SetError(e.c_str());
429         return false;
430         }
431       r += 2;
432       }
433     l = r;
434     }
435   
436   // Concatenate all the last arguments together.
437   std::string input = args[5];
438   for(unsigned int i=6; i < args.size(); ++i)
439     {
440     input += args[i];
441     }
442   
443   this->ClearMatches(this->Makefile);
444   // Compile the regular expression.
445   cmsys::RegularExpression re;
446   if(!re.compile(regex.c_str()))
447     {
448     std::string e = 
449       "sub-command REGEX, mode REPLACE failed to compile regex \""+
450       regex+"\".";
451     this->SetError(e.c_str());
452     return false;
453     }
454   
455   // Scan through the input for all matches.
456   std::string output;
457   std::string::size_type base = 0;
458   while(re.find(input.c_str()+base))
459     {
460     this->StoreMatches(this->Makefile, re);
461     std::string::size_type l2 = re.start();
462     std::string::size_type r = re.end();
463     
464     // Concatenate the part of the input that was not matched.
465     output += input.substr(base, l2);
466     
467     // Make sure the match had some text.
468     if(r-l2 == 0)
469       {
470       std::string e = "sub-command REGEX, mode REPLACE regex \""+
471         regex+"\" matched an empty string.";
472       this->SetError(e.c_str());
473       return false;
474       }
475     
476     // Concatenate the replacement for the match.
477     for(unsigned int i=0; i < replacement.size(); ++i)
478       {
479       if(replacement[i].number < 0)
480         {
481         // This is just a plain-text part of the replacement.
482         output += replacement[i].value;
483         }
484       else
485         {
486         // Replace with part of the match.
487         int n = replacement[i].number;
488         std::string::size_type start = re.start(n);
489         std::string::size_type end = re.end(n);
490         std::string::size_type len = input.length()-base;
491         if((start != std::string::npos) && (end != std::string::npos) &&
492            (start <= len) && (end <= len))
493           {
494           output += input.substr(base+start, end-start);
495           }
496         else
497           {
498           std::string e =
499             "sub-command REGEX, mode REPLACE: replace expression \""+
500             replace+"\" contains an out-of-range escape for regex \""+
501             regex+"\".";
502           this->SetError(e.c_str());
503           return false;
504           }
505         }
506       }
507     
508     // Move past the match.
509     base += r;
510     }
511   
512   // Concatenate the text after the last match.
513   output += input.substr(base, input.length()-base);
514   
515   // Store the output in the provided variable.
516   this->Makefile->AddDefinition(outvar.c_str(), output.c_str());
517   return true;
518 }
519
520 //----------------------------------------------------------------------------
521 void cmStringCommand::ClearMatches(cmMakefile* mf)
522 {
523   for (unsigned int i=0; i<10; i++)
524     {
525     char name[128];
526     sprintf(name, "CMAKE_MATCH_%d", i);
527     mf->AddDefinition(name, "");
528     mf->MarkVariableAsUsed(name);
529     }
530 }
531
532 //----------------------------------------------------------------------------
533 void cmStringCommand::StoreMatches(cmMakefile* mf,cmsys::RegularExpression& re)
534 {
535   for (unsigned int i=0; i<10; i++)
536     {
537     char name[128];
538     sprintf(name, "CMAKE_MATCH_%d", i);
539     mf->AddDefinition(name, re.match(i).c_str());
540     mf->MarkVariableAsUsed(name);
541     }
542 }
543
544 //----------------------------------------------------------------------------
545 bool cmStringCommand::HandleFindCommand(std::vector<std::string> const&
546                                            args)
547 {
548   // check if all required parameters were passed
549   if(args.size() < 4 || args.size() > 5)
550     {
551     this->SetError("sub-command FIND requires 3 or 4 parameters.");
552     return false;
553     }
554
555   // check if the reverse flag was set or not
556   bool reverseMode = false;
557   if(args.size() == 5 && args[4] == "REVERSE")
558     {
559     reverseMode = true;
560     }
561
562   // if we have 5 arguments the last one must be REVERSE
563   if(args.size() == 5 && args[4] != "REVERSE")
564     {
565     this->SetError("sub-command FIND: unknown last parameter");
566     return false;
567     }
568
569   // local parameter names.
570   const std::string& sstring = args[1];
571   const std::string& schar = args[2];
572   const std::string& outvar = args[3];
573
574   // ensure that the user cannot accidentally specify REVERSE as a variable
575   if(outvar == "REVERSE")
576     {
577     this->SetError("sub-command FIND does not allow to select REVERSE as "
578                    "the output variable.  "
579                    "Maybe you missed the actual output variable?");
580     return false;
581     }
582
583   // try to find the character and return its position
584   size_t pos;
585   if(!reverseMode)
586     {
587     pos = sstring.find(schar);
588     }
589   else
590     {
591     pos = sstring.rfind(schar);
592     }
593   if(std::string::npos != pos)
594     {
595     cmOStringStream s;
596     s << pos;
597     this->Makefile->AddDefinition(outvar.c_str(), s.str().c_str());
598     return true;
599     }
600
601   // the character was not found, but this is not really an error
602   this->Makefile->AddDefinition(outvar.c_str(), "-1");
603   return true;
604 }
605
606 //----------------------------------------------------------------------------
607 bool cmStringCommand::HandleCompareCommand(std::vector<std::string> const&
608                                            args)
609 {
610   if(args.size() < 2)
611     {
612     this->SetError("sub-command COMPARE requires a mode to be specified.");
613     return false;
614     }
615   std::string mode = args[1];
616   if((mode == "EQUAL") || (mode == "NOTEQUAL") ||
617      (mode == "LESS") || (mode == "GREATER"))
618     {
619     if(args.size() < 5)
620       {
621       std::string e = "sub-command COMPARE, mode ";
622       e += mode;
623       e += " needs at least 5 arguments total to command.";
624       this->SetError(e.c_str());
625       return false;
626       }
627     
628     const std::string& left = args[2];
629     const std::string& right = args[3];  
630     const std::string& outvar = args[4];
631     bool result;
632     if(mode == "LESS")
633       {
634       result = (left < right);
635       }
636     else if(mode == "GREATER")
637       {
638       result = (left > right);
639       }
640     else if(mode == "EQUAL")
641       {
642       result = (left == right);
643       }
644     else // if(mode == "NOTEQUAL")
645       {
646       result = !(left == right);
647       }
648     if(result)
649       {
650       this->Makefile->AddDefinition(outvar.c_str(), "1");
651       }
652     else
653       {
654       this->Makefile->AddDefinition(outvar.c_str(), "0");
655       }
656     return true;
657     }  
658   std::string e = "sub-command COMPARE does not recognize mode "+mode;
659   this->SetError(e.c_str());
660   return false;
661 }
662
663 //----------------------------------------------------------------------------
664 bool cmStringCommand::HandleReplaceCommand(std::vector<std::string> const&
665                                            args)
666 {
667   if(args.size() < 5)
668     {
669     this->SetError("sub-command REPLACE requires at least four arguments.");
670     return false;
671     }
672
673   const std::string& matchExpression = args[1];
674   const std::string& replaceExpression = args[2];
675   const std::string& variableName = args[3];
676
677   std::string input = args[4];
678   for(unsigned int i=5; i < args.size(); ++i)
679     {
680     input += args[i];
681     }
682
683   cmsys::SystemTools::ReplaceString(input, matchExpression.c_str(), 
684                                     replaceExpression.c_str());
685
686   this->Makefile->AddDefinition(variableName.c_str(), input.c_str());
687   return true;
688 }
689
690 //----------------------------------------------------------------------------
691 bool cmStringCommand::HandleSubstringCommand(std::vector<std::string> const& 
692                                              args)
693 {
694   if(args.size() != 5)
695     {
696     this->SetError("sub-command SUBSTRING requires four arguments.");
697     return false;
698     }
699
700   const std::string& stringValue = args[1];
701   int begin = atoi(args[2].c_str());
702   int end = atoi(args[3].c_str());
703   const std::string& variableName = args[4];
704
705   size_t stringLength = stringValue.size();
706   int intStringLength = static_cast<int>(stringLength);
707   if ( begin < 0 || begin > intStringLength )
708     {
709     cmOStringStream ostr;
710     ostr << "begin index: " << begin << " is out of range 0 - "
711          << stringLength;
712     this->SetError(ostr.str().c_str());
713     return false;
714     }
715   int leftOverLength = intStringLength - begin;
716   if ( end < -1 || end > leftOverLength )
717     {
718     cmOStringStream ostr;
719     ostr << "end index: " << end << " is out of range -1 - "
720          << leftOverLength;
721     this->SetError(ostr.str().c_str());
722     return false;
723     }
724
725   this->Makefile->AddDefinition(variableName.c_str(), 
726                                 stringValue.substr(begin, end).c_str());
727   return true;
728 }
729
730 //----------------------------------------------------------------------------
731 bool cmStringCommand
732 ::HandleLengthCommand(std::vector<std::string> const& args)
733 {
734   if(args.size() != 3)
735     {
736     this->SetError("sub-command LENGTH requires two arguments.");
737     return false;
738     }
739
740   const std::string& stringValue = args[1];
741   const std::string& variableName = args[2];
742
743   size_t length = stringValue.size();
744   char buffer[1024];
745   sprintf(buffer, "%d", static_cast<int>(length));
746
747   this->Makefile->AddDefinition(variableName.c_str(), buffer);
748   return true;
749 }
750
751 //----------------------------------------------------------------------------
752 bool cmStringCommand::HandleStripCommand(
753   std::vector<std::string> const& args)
754 {
755  if(args.size() != 3)
756     {
757     this->SetError("sub-command STRIP requires two arguments.");
758     return false;
759     }
760
761   const std::string& stringValue = args[1];
762   const std::string& variableName = args[2];
763   size_t inStringLength = stringValue.size();
764   size_t startPos = inStringLength + 1;
765   size_t endPos = 0;
766   const char* ptr = stringValue.c_str();
767   size_t cc;
768   for ( cc = 0; cc < inStringLength; ++ cc )
769     {
770     if ( !isspace(*ptr) )
771       {
772       if ( startPos > inStringLength )
773         {
774         startPos = cc;
775         }
776       endPos = cc;
777       }
778     ++ ptr;
779     }
780
781   size_t outLength = 0;
782
783   // if the input string didn't contain any non-space characters, return 
784   // an empty string
785   if (startPos > inStringLength)
786     {
787     outLength = 0;
788     startPos = 0;
789     }
790   else
791     {
792     outLength=endPos - startPos + 1;
793     }
794
795   this->Makefile->AddDefinition(variableName.c_str(),
796     stringValue.substr(startPos, outLength).c_str());
797   return true;
798 }
799
800 //----------------------------------------------------------------------------
801 bool cmStringCommand
802 ::HandleRandomCommand(std::vector<std::string> const& args)
803 {
804   if(args.size() < 2 || args.size() == 3 || args.size() == 5)
805     {
806     this->SetError("sub-command RANDOM requires at least one argument.");
807     return false;
808     }
809
810   static bool seeded = false;
811   bool force_seed = false;
812   unsigned int seed = 0;
813   int length = 5;
814   const char cmStringCommandDefaultAlphabet[] = "qwertyuiopasdfghjklzxcvbnm"
815     "QWERTYUIOPASDFGHJKLZXCVBNM"
816     "0123456789";
817   std::string alphabet;
818
819   if ( args.size() > 3 )
820     {
821     size_t i = 1;
822     size_t stopAt = args.size() - 2;
823
824     for ( ; i < stopAt; ++i )
825       {
826       if ( args[i] == "LENGTH" )
827         {
828         ++i;
829         length = atoi(args[i].c_str());
830         }
831       else if ( args[i] == "ALPHABET" )
832         {
833         ++i;
834         alphabet = args[i];
835         }
836       else if ( args[i] == "RANDOM_SEED" )
837         {
838         ++i;
839         seed = static_cast<unsigned int>(atoi(args[i].c_str()));
840         force_seed = true;
841         }
842       }
843     }
844   if ( !alphabet.size() )
845     {
846     alphabet = cmStringCommandDefaultAlphabet;
847     }
848
849   double sizeofAlphabet = static_cast<double>(alphabet.size());
850   if ( sizeofAlphabet < 1 )
851     {
852     this->SetError("sub-command RANDOM invoked with bad alphabet.");
853     return false;
854     }
855   if ( length < 1 )
856     {
857     this->SetError("sub-command RANDOM invoked with bad length.");
858     return false;
859     }
860   const std::string& variableName = args[args.size()-1];
861
862   std::vector<char> result;
863
864   if (!seeded || force_seed)
865     {
866     seeded = true;
867     srand(force_seed? seed : cmSystemTools::RandomSeed());
868     }
869
870   const char* alphaPtr = alphabet.c_str();
871   int cc;
872   for ( cc = 0; cc < length; cc ++ )
873     {
874     int idx=(int) (sizeofAlphabet* rand()/(RAND_MAX+1.0));
875     result.push_back(*(alphaPtr + idx));
876     }
877   result.push_back(0);
878
879   this->Makefile->AddDefinition(variableName.c_str(), &*result.begin());
880   return true;
881 }