cmDocumentation.cxx 30.5 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*=========================================================================

  Program:   CMake - Cross-Platform Makefile Generator
  Module:    $RCSfile$
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 2002 Kitware, Inc., Insight Consortium.  All rights reserved.
  See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#include "cmDocumentation.h"

#include "cmSystemTools.h"
20
#include "cmVersion.h"
21
22
23
24

//----------------------------------------------------------------------------
static const cmDocumentationEntry cmDocumentationStandardOptions[] =
{
25
26
  {"--copyright [file]", "Print the CMake copyright and exit.",
   "If a file is specified, the copyright is written into it."},
27
28
  {"--help", "Print usage information and exit.",
   "Usage describes the basic command line interface and its options."},
29
  {"--help-full [file]", "Print full help and exit.",
30
31
   "Full help displays most of the documentation provided by the UNIX "
   "man page.  It is provided for use on non-UNIX platforms, but is "
32
33
34
35
36
37
38
39
40
41
   "also convenient if the man page is not installed.  If a file is "
   "specified, the help is written into it."},
  {"--help-html [file]", "Print full help in HTML format.",
   "This option is used by CMake authors to help produce web pages.  "
   "If a file is specified, the help is written into it."},
  {"--help-man [file]", "Print a UNIX man page and exit.",
   "This option is used by the cmake build to generate the UNIX man page.  "
   "If a file is specified, the help is written into it."},
  {"--version [file]", "Show program name/version banner and exit.",
   "If a file is specified, the version is written into it."},
42
43
44
  {0,0,0}
};

45
46
47
48
49
50
51
52
//----------------------------------------------------------------------------
static const cmDocumentationEntry cmDocumentationCommandsHeader[] =
{
  {0,
   "The following commands are available in CMakeLists.txt code:", 0},
  {0,0,0}
};

53
54
55
56
57
58
59
60
//----------------------------------------------------------------------------
static const cmDocumentationEntry cmDocumentationGeneratorsHeader[] =
{
  {0,
   "The following generators are available on this platform:", 0},
  {0,0,0}
};

Andy Cedilnik's avatar
Andy Cedilnik committed
61
62
63
64
65
//----------------------------------------------------------------------------
const cmDocumentationEntry cmDocumentationMailingList[] =
{
  {0,
   "For help and discussion about using cmake, a mailing list is provided "
66
   "at cmake@www.cmake.org.  Please first read the full documentation at "
Andy Cedilnik's avatar
Andy Cedilnik committed
67
68
69
70
   "http://www.cmake.org before posting questions to the list.", 0},
  {0,0,0}
};

71
72
73
74
//----------------------------------------------------------------------------
const cmDocumentationEntry cmDocumentationAuthor[] =
{
  {0,
75
   "This manual page was generated by the \"--help-man\" option.", 0},
76
77
78
  {0,0,0}
};

79
80
81
82
//----------------------------------------------------------------------------
const cmDocumentationEntry cmDocumentationCopyright[] =
{
  {0,
83
84
   "Copyright (c) 2002 Kitware, Inc., Insight Consortium.  "
   "All rights reserved.", 0},
85
86
87
  {0,
   "Redistribution and use in source and binary forms, with or without "
   "modification, are permitted provided that the following conditions are "
88
89
   "met:", 0},
  {"",
90
   "Redistributions of source code must retain the above copyright notice, "
91
92
   "this list of conditions and the following disclaimer.", 0},
  {"",
93
94
   "Redistributions in binary form must reproduce the above copyright "
   "notice, this list of conditions and the following disclaimer in the "
95
   "documentation and/or other materials provided with the distribution.",
96
   0},
97
  {"",
98
99
100
   "The names of Kitware, Inc., the Insight Consortium, or the names of "
   "any consortium members, or of any contributors, may not be used to "
   "endorse or promote products derived from this software without "
101
102
   "specific prior written permission.", 0},
  {"",
103
   "Modified source versions must be plainly marked as such, and must "
104
   "not be misrepresented as being the original software.", 0},
105
106
107
108
109
110
111
112
113
114
115
  {0,
   "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "
   "``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT "
   "LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR "
   "A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR "
   "CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, "
   "EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, "
   "PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR "
   "PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF "
   "LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING "
   "NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS "
116
   "SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.", 0},
117
118
119
120
121
122
  {0, 0, 0}
};

//----------------------------------------------------------------------------
cmDocumentation::cmDocumentation()
{
123
124
125
  this->CurrentForm = TextForm;
  this->TextIndent = "";
  this->TextWidth = 77;
126
127
128
}

//----------------------------------------------------------------------------
129
bool cmDocumentation::PrintCopyright(std::ostream& os)
130
{
131
132
  for(const cmDocumentationEntry* op = cmDocumentationCopyright;
      op->brief; ++op)
133
134
135
    {
    if(op->name)
      {
136
137
138
      os << " * ";
      this->TextIndent = "    ";
      this->PrintColumn(os, op->brief);
139
140
141
      }
    else
      {
142
143
      this->TextIndent = "";
      this->PrintColumn(os, op->brief);
144
      }
145
146
    os << "\n";
    }
147
  return true;
148
149
150
}

//----------------------------------------------------------------------------
151
bool cmDocumentation::PrintVersion(std::ostream& os)
152
{
153
  os << this->GetNameString() << " version " << cmVersion::GetCMakeVersion() << "\n";
154
  return true;
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
}

//----------------------------------------------------------------------------
void cmDocumentation::AddSection(const char* name,
                                 const cmDocumentationEntry* d)
{
  this->Names.push_back(name);
  this->Sections.push_back(d);
}

//----------------------------------------------------------------------------
void cmDocumentation::ClearSections()
{
  this->Names.erase(this->Names.begin(), this->Names.end());
  this->Sections.erase(this->Sections.begin(), this->Sections.end());
}

//----------------------------------------------------------------------------
173
bool cmDocumentation::PrintDocumentation(Type ht, std::ostream& os)
174
{
175
176
177
178
179
  if ( ht != cmDocumentation::HTML &&
    ht != cmDocumentation::Man )
    {
    this->PrintVersion(os);
    }
180
  switch (ht)
181
    {
182
183
184
185
186
187
188
    case cmDocumentation::Usage:     return this->PrintDocumentationUsage(os);
    case cmDocumentation::Single:    return this->PrintDocumentationSingle(os);
    case cmDocumentation::List:      return this->PrintDocumentationList(os);
    case cmDocumentation::Full:      return this->PrintDocumentationFull(os);
    case cmDocumentation::HTML:      return this->PrintDocumentationHTML(os);
    case cmDocumentation::Man:       return this->PrintDocumentationMan(os);
    case cmDocumentation::Copyright: return this->PrintCopyright(os);
189
    case cmDocumentation::Version:   return true;
190
    default: return false;
191
    }
192
193
194
}

//----------------------------------------------------------------------------
195
196
197
198
199
200
201
202
bool cmDocumentation::PrintRequestedDocumentation(std::ostream& os)
{
  bool result = true;
  
  // Loop over requested documentation types.
  for(RequestedMapType::const_iterator i = this->RequestedMap.begin();
      i != this->RequestedMap.end(); ++i)
    {
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
    // Special case for printing help for a single command.
    if(i->first == cmDocumentation::Usage && i->second.length() > 0 &&
       !this->CommandsSection.empty())
      {
      // Check if the argument to the usage request was a command.
      for(cmDocumentationEntry* entry = &this->CommandsSection[0];
          entry->brief; ++entry)
        {
        if(entry->name && (strcmp(entry->name, i->second.c_str()) == 0))
          {
          this->PrintDocumentationCommand(os, entry);
          return true;
          }
        }
      
      // Argument was not a command.  Complain.
      os << "Help argument \"" << i->second.c_str()
         << "\" is not a CMake command.  "
221
         << "Use --help-command-list to see all commands.\n";
222
223
224
      return false;
      }
    
225
226
227
228
229
230
    // If a file name was given, use it.  Otherwise, default to the
    // given stream.
    std::ofstream* fout = 0;
    std::ostream* s = &os;
    if(i->second.length() > 0)
      {
Brad King's avatar
Brad King committed
231
      fout = new std::ofstream(i->second.c_str(), std::ios::out);
232
233
234
235
236
237
238
239
240
241
242
      if(fout)
        {
        s = fout;
        }
      else
        {
        result = false;
        }
      }
    
    // Print this documentation type to the stream.
243
    if(!this->PrintDocumentation(i->first, *s) || !*s)
244
245
246
247
248
249
250
251
252
253
254
255
256
257
      {
      result = false;
      }
    
    // Close the file if we wrote one.
    if(fout)
      {
      delete fout;
      }
    }
  return result;
}

//----------------------------------------------------------------------------
258
bool cmDocumentation::CheckOptions(int argc, const char* const* argv)
259
{
260
261
262
  // Providing zero arguments gives usage information.
  if(argc == 1)
    {
263
264
    this->RequestedMap[cmDocumentation::Usage] = "";
    return true;
265
266
267
    }
  
  // Search for supported help options.
268
  bool result = false;
269
  for(int i=1; i < argc; ++i)
270
    {
271
272
    // Check if this is a supported help option.
    Type type = cmDocumentation::None;
273
274
275
276
277
278
    if((strcmp(argv[i], "-help") == 0) ||
       (strcmp(argv[i], "--help") == 0) ||
       (strcmp(argv[i], "/?") == 0) ||
       (strcmp(argv[i], "-usage") == 0) ||
       (strcmp(argv[i], "-h") == 0) ||
       (strcmp(argv[i], "-H") == 0))
279
      {
280
281
282
283
284
      type = cmDocumentation::Usage;
      }
    else if(strcmp(argv[i], "--help-full") == 0)
      {
      type = cmDocumentation::Full;
285
      }
286
    else if(strcmp(argv[i], "--help-html") == 0)
287
      {
288
      type = cmDocumentation::HTML;
289
      }
290
    else if(strcmp(argv[i], "--help-man") == 0)
291
      {
292
      type = cmDocumentation::Man;
293
      }
294
295
296
297
298
299
300
301
302
303
    else if(strcmp(argv[i], "--help-command") == 0)
      {
      type = cmDocumentation::Single;
      if((i+1 < argc) && !this->IsOption(argv[i+1]))
        {
        this->SingleCommand = argv[i+1];
        i = i+1;
        }
      }
    else if(strcmp(argv[i], "--help-command-list") == 0)
304
305
306
      {
      type = cmDocumentation::List;
      }
307
    else if(strcmp(argv[i], "--copyright") == 0)
308
      {
309
      type = cmDocumentation::Copyright;
310
      }
311
312
313
    else if((strcmp(argv[i], "--version") == 0) || 
            (strcmp(argv[i], "-version") == 0) || 
            (strcmp(argv[i], "/V") == 0))
314
      {
315
      type = cmDocumentation::Version;
316
      }
317
    if(type)
318
      {
319
320
      // This is a help option.  See if there is a file name given.
      result = true;
321
      if((i+1 < argc) && !this->IsOption(argv[i+1]))
322
323
324
325
326
327
328
329
        {
        this->RequestedMap[type] = argv[i+1];
        i = i+1;
        }
      else
        {
        this->RequestedMap[type] = "";
        }
330
331
      }
    }
332
  return result;
333
334
}

335
//----------------------------------------------------------------------------
336
void cmDocumentation::Print(Form f, std::ostream& os)
337
{
338
  this->CurrentForm = f;
339
  for(unsigned int i=0; i < this->Sections.size(); ++i)
340
341
342
343
344
    {
    this->PrintSection(os, this->Sections[i], this->Names[i]);
    }
}

345
346
347
348
349
350
//----------------------------------------------------------------------------
void cmDocumentation::SetName(const char* name)
{
  this->NameString = name?name:"";
}

351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
//----------------------------------------------------------------------------
void cmDocumentation::SetNameSection(const cmDocumentationEntry* section)
{
  this->SetSection(0, section, 0, this->NameSection);
}

//----------------------------------------------------------------------------
void cmDocumentation::SetUsageSection(const cmDocumentationEntry* section)
{
  this->SetSection(0, section, 0, this->UsageSection);
}

//----------------------------------------------------------------------------
void cmDocumentation::SetDescriptionSection(const cmDocumentationEntry* section)
{
  this->SetSection(0, section, 0, this->DescriptionSection);
}

//----------------------------------------------------------------------------
void cmDocumentation::SetOptionsSection(const cmDocumentationEntry* section)
{
  this->SetSection(0, section, cmDocumentationStandardOptions,
                   this->OptionsSection);
}

//----------------------------------------------------------------------------
void cmDocumentation::SetCommandsSection(const cmDocumentationEntry* section)
{
  this->SetSection(cmDocumentationCommandsHeader, section, 0,
                   this->CommandsSection);
}

383
384
385
386
387
388
389
//----------------------------------------------------------------------------
void cmDocumentation::SetGeneratorsSection(const cmDocumentationEntry* section)
{
  this->SetSection(cmDocumentationGeneratorsHeader, section, 0,
                   this->GeneratorsSection);
}

390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
//----------------------------------------------------------------------------
void cmDocumentation::SetSeeAlsoList(const cmDocumentationEntry* also)
{
  this->SeeAlsoString = ".B ";
  for(const cmDocumentationEntry* i = also; i->brief; ++i)
    {
    this->SeeAlsoString += i->brief;
    this->SeeAlsoString += (i+1)->brief? "(1), ":"(1)";    
    }
  cmDocumentationEntry e = {0, 0, 0};
  e.brief = this->SeeAlsoString.c_str();
  this->SeeAlsoSection.push_back(e);
  e.brief = 0;
  this->SeeAlsoSection.push_back(e);  
}

406
407
408
409
410
411
412
413
414
415
416
417
//----------------------------------------------------------------------------
void cmDocumentation::PrintSection(std::ostream& os,
                                   const cmDocumentationEntry* section,
                                   const char* name)
{
  switch (this->CurrentForm)
    {
    case TextForm: this->PrintSectionText(os, section, name); break;
    case HTMLForm: this->PrintSectionHTML(os, section, name); break;
    case ManForm: this->PrintSectionMan(os, section, name); break;
    case UsageForm: this->PrintSectionUsage(os, section, name); break;
    }
418
419
}

420
//----------------------------------------------------------------------------
421
422
423
void cmDocumentation::PrintSectionText(std::ostream& os,
                                       const cmDocumentationEntry* section,
                                       const char* name)
424
{
425
426
  if(name)
    {
427
428
429
    os <<
      "---------------------------------------"
      "---------------------------------------\n";
430
431
    os << name << "\n\n";
    }
432
  if(!section) { return; }
433
  for(const cmDocumentationEntry* op = section; op->brief; ++op)
434
    {
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
    if(op->name)
      {
      if(op->name[0])
        {
        os << "  " << op->name << "\n";
        }
      this->TextIndent = "       ";
      this->PrintFormatted(os, op->brief);
      if(op->full)
        {
        os << "\n";
        this->PrintFormatted(os, op->full);
        }
      }
    else
      {
      this->TextIndent = "";
      this->PrintFormatted(os, op->brief);
      }
    os << "\n";
    }  
}

//----------------------------------------------------------------------------
void cmDocumentation::PrintSectionHTML(std::ostream& os,
                                       const cmDocumentationEntry* section,
                                       const char* name)
{
  if(name)
    {
    os << "<h2>" << name << "</h2>\n";
466
    }
467
  if(!section) { return; }
468
469
470
471
472
473
474
475
  for(const cmDocumentationEntry* op = section; op->brief;)
    {
    if(op->name)
      {
      os << "<ul>\n";
      for(;op->name;++op)
        {
        os << "  <li>\n";
476
477
478
479
480
481
        if(op->name[0])
          {
          os << "    <b><code>";
          this->PrintHTMLEscapes(os, op->name);
          os << "</code></b>: ";
          }
482
483
484
        this->PrintHTMLEscapes(os, op->brief);
        if(op->full)
          {
485
486
          os << "<br>\n    ";
          this->PrintFormatted(os, op->full);
487
488
489
490
491
492
493
494
          }
        os << "\n";
        os << "  </li>\n";
        }
      os << "</ul>\n";
      }
    else
      {
495
      this->PrintFormatted(os, op->brief);
496
497
498
499
500
501
502
      os << "\n";
      ++op;
      }
    }
}

//----------------------------------------------------------------------------
503
504
505
void cmDocumentation::PrintSectionMan(std::ostream& os,
                                      const cmDocumentationEntry* section,
                                      const char* name)
506
{
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
  if(name)
    {
    os << ".SH " << name << "\n";
    }
  if(!section) { return; }
  for(const cmDocumentationEntry* op = section; op->brief; ++op)
    {
    if(op->name)
      {
      os << ".TP\n"
         << ".B " << (op->name[0]?op->name:"*") << "\n";
      this->PrintFormatted(os, op->brief);
      this->PrintFormatted(os, op->full);
      }
    else
      {
      os << ".PP\n";
      this->PrintFormatted(os, op->brief);
      }
    }  
}

//----------------------------------------------------------------------------
void cmDocumentation::PrintSectionUsage(std::ostream& os,
                                        const cmDocumentationEntry* section,
                                        const char* name)
{
  if(name)
    {
    os << name << "\n";
    }
538
539
540
541
542
  if(!section) { return; }
  for(const cmDocumentationEntry* op = section; op->brief; ++op)
    {
    if(op->name)
      {
543
      os << "  " << op->name;
544
      this->TextIndent = "                                ";
545
546
      int align = static_cast<int>(strlen(this->TextIndent))-4;
      for(int i = static_cast<int>(strlen(op->name)); i < align; ++i)
547
548
549
        {
        os << " ";
        }
Andy Cedilnik's avatar
Andy Cedilnik committed
550
551
552
553
554
      if ( strlen(op->name) > strlen(this->TextIndent)-4 )
        {
        os << "\n";
        os.write(this->TextIndent, strlen(this->TextIndent)-2);
        }
555
556
557
      os << "= ";
      this->PrintColumn(os, op->brief);
      os << "\n";
558
559
560
561
      }
    else
      {
      os << "\n";
562
563
      this->TextIndent = "";
      this->PrintFormatted(os, op->brief);
564
      }
565
    }
566
  os << "\n";
567
568
569
}

//----------------------------------------------------------------------------
570
void cmDocumentation::PrintFormatted(std::ostream& os, const char* text)
571
{
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
  if(!text)
    {
    return;
    }
  const char* ptr = text;
  while(*ptr)
    {
    // Any ptrs starting in a space are treated as preformatted text.
    std::string preformatted;
    while(*ptr == ' ')
      {
      for(char ch = *ptr; ch && ch != '\n'; ++ptr, ch = *ptr)
        {
        preformatted.append(1, ch);
        }
      if(*ptr)
        {
        ++ptr;
        preformatted.append(1, '\n');
        }
      }
    if(preformatted.length())
      {
      this->PrintPreformatted(os, preformatted.c_str());
      }
    
    // Other ptrs are treated as paragraphs.
    std::string paragraph;
    for(char ch = *ptr; ch && ch != '\n'; ++ptr, ch = *ptr)
      {
      paragraph.append(1, ch);
      }
    if(*ptr)
      {
      ++ptr;
      paragraph.append(1, '\n');
      }
    if(paragraph.length())
      {
      this->PrintParagraph(os, paragraph.c_str());
      }
    }
614
615
616
}

//----------------------------------------------------------------------------
617
void cmDocumentation::PrintPreformatted(std::ostream& os, const char* text)
618
{
619
  switch (this->CurrentForm)
620
    {
621
622
623
624
    case TextForm: this->PrintPreformattedText(os, text); break;
    case HTMLForm: this->PrintPreformattedHTML(os, text); break;
    case ManForm: this->PrintPreformattedMan(os, text); break;
    case UsageForm: this->PrintPreformattedText(os, text); break;
625
626
627
628
    }
}

//----------------------------------------------------------------------------
629
void cmDocumentation::PrintParagraph(std::ostream& os, const char* text)
630
{
631
632
633
634
635
636
637
  switch (this->CurrentForm)
    {
    case TextForm: this->PrintParagraphText(os, text); break;
    case HTMLForm: this->PrintParagraphHTML(os, text); break;
    case ManForm: this->PrintParagraphMan(os, text); break;
    case UsageForm: this->PrintParagraphText(os, text); break;
    }
638
639
640
}

//----------------------------------------------------------------------------
641
void cmDocumentation::PrintPreformattedText(std::ostream& os, const char* text)
642
{
643
644
  bool newline = true;
  for(const char* ptr = text; *ptr; ++ptr)
645
    {
646
    if(newline)
647
      {
648
649
      os << this->TextIndent;
      newline = false;
650
      }
651
652
    os << *ptr;
    if(*ptr == '\n')
653
      {
654
      newline = true;
655
656
      }
    }
657
  os << "\n";
658
659
660
}

//----------------------------------------------------------------------------
661
void cmDocumentation::PrintParagraphText(std::ostream& os, const char* text)
662
{
663
664
665
666
667
668
669
670
671
672
673
  os << this->TextIndent;
  this->PrintColumn(os, text);
  os << "\n";
}

//----------------------------------------------------------------------------
void cmDocumentation::PrintPreformattedHTML(std::ostream& os, const char* text)
{
  os << "<pre>";
  this->PrintHTMLEscapes(os, text);
  os << "</pre>\n    ";
674
675
676
}

//----------------------------------------------------------------------------
677
void cmDocumentation::PrintParagraphHTML(std::ostream& os, const char* text)
678
{
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
  os << "<p>";
  this->PrintHTMLEscapes(os, text);
}

//----------------------------------------------------------------------------
void cmDocumentation::PrintPreformattedMan(std::ostream& os, const char* text)
{
  os << text << "\n";
}

//----------------------------------------------------------------------------
void cmDocumentation::PrintParagraphMan(std::ostream& os, const char* text)
{
  os << text << "\n\n";
}

//----------------------------------------------------------------------------
void cmDocumentation::PrintColumn(std::ostream& os, const char* text)
{
  // Print text arranged in an indented column of fixed witdh.
699
700
701
  const char* l = text;
  int column = 0;
  bool newSentence = false;
702
  bool firstLine = true;
703
  int width = this->TextWidth - static_cast<int>(strlen(this->TextIndent));
704
705
  
  // Loop until the end of the text.
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
  while(*l)
    {
    // Parse the next word.
    const char* r = l;
    while(*r && (*r != '\n') && (*r != ' ')) { ++r; }
    
    // Does it fit on this line?
    if(r-l < (width-column-(newSentence?1:0)))
      {
      // Word fits on this line.
      if(r > l)
        {
        if(column)
          {
          // Not first word on line.  Separate from the previous word
          // by a space, or two if this is a new sentence.
          if(newSentence)
            {
            os << "  ";
            column += 2;
            }
          else
            {
            os << " ";
            column += 1;
            }
          }
        else
          {
          // First word on line.  Print indentation unless this is the
          // first line.
737
          os << (firstLine?"":this->TextIndent);
738
739
740
741
742
743
744
745
746
747
748
749
750
          }
        
        // Print the word.
        os.write(l, static_cast<long>(r-l));
        newSentence = (*(r-1) == '.');
        }
      
      if(*r == '\n')
        {
        // Text provided a newline.  Start a new line.
        os << "\n";
        ++r;
        column = 0;
751
        firstLine = false;
752
753
754
755
756
757
758
759
760
761
762
        }
      else
        {
        // No provided newline.  Continue this line.
        column += static_cast<long>(r-l);
        }
      }
    else
      {
      // Word does not fit on this line.  Start a new line.
      os << "\n";
763
      firstLine = false;
764
765
      if(r > l)
        {
766
        os << this->TextIndent;
767
768
769
770
771
772
773
774
775
776
777
778
779
        os.write(l, static_cast<long>(r-l));
        column = static_cast<long>(r-l);
        newSentence = (*(r-1) == '.');
        }
      }
    
    // Move to beginning of next word.  Skip over whitespace.
    l = r;
    while(*l && (*l == ' ')) { ++l; }    
    }
}

//----------------------------------------------------------------------------
780
void cmDocumentation::PrintHTMLEscapes(std::ostream& os, const char* text)
781
{
782
783
784
785
786
787
788
789
790
  static cmDocumentationEntry escapes[] =
  {
    {"<", "&lt;", 0},
    {">", "&gt;", 0},
    {"&", "&amp;", 0},
    {"\n", "<br>", 0},
    {0,0,0}
  };
  for(const char* p = text; *p; ++p)
791
    {
792
793
    bool found = false;
    for(const cmDocumentationEntry* op = escapes; !found && op->name; ++op)
794
      {
795
      if(op->name[0] == *p)
796
        {
797
798
        os << op->brief;
        found = true;
799
800
        }
      }
801
    if(!found)
802
      {
803
      os << *p;
804
805
806
807
808
      }
    }
}

//----------------------------------------------------------------------------
809
bool cmDocumentation::PrintDocumentationSingle(std::ostream& os)
810
{
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
  if(this->CommandsSection.empty())
    {
    os << "Internal error: commands list is empty." << std::endl;
    return false;
    }
  if(this->SingleCommand.length() == 0)
    {
    os << "Argument --help-command needs a command name.\n";
    return false;
    }
  for(cmDocumentationEntry* entry = &this->CommandsSection[0];
      entry->brief; ++entry)
    {
    if(entry->name && this->SingleCommand == entry->name)
      {
      this->PrintDocumentationCommand(os, entry);
      return true;
      }
    }
  // Argument was not a command.  Complain.
  os << "Argument \"" << this->SingleCommand.c_str()
     << "\" to --help-command is not a CMake command.  "
     << "Use --help-command-list to see all commands.\n";
  return false;
835
836
}

837
//----------------------------------------------------------------------------
838
bool cmDocumentation::PrintDocumentationList(std::ostream& os)
839
{
840
841
842
843
844
  if(this->CommandsSection.empty())
    {
    os << "Internal error: commands list is empty." << std::endl;
    return false;
    }
845
846
847
848
849
850
851
852
  for(cmDocumentationEntry* entry = &this->CommandsSection[0];
      entry->brief; ++entry)
    {
    if(entry->name)
      {
      os << entry->name << std::endl;
      }
    }
853
  return true;
854
855
}

856
//----------------------------------------------------------------------------
857
858
859
860
861
862
863
864
865
bool cmDocumentation::PrintDocumentationUsage(std::ostream& os)
{
  this->CreateUsageDocumentation();
  this->Print(UsageForm, os);
  return true;
}

//----------------------------------------------------------------------------
bool cmDocumentation::PrintDocumentationFull(std::ostream& os)
866
867
868
{
  this->CreateFullDocumentation();
  this->Print(TextForm, os);
869
  return true;
870
871
872
}

//----------------------------------------------------------------------------
873
bool cmDocumentation::PrintDocumentationHTML(std::ostream& os)
874
875
876
877
878
{
  this->CreateFullDocumentation();
  os << "<html><body>\n";
  this->Print(HTMLForm, os);
  os << "</body></html>\n";
879
  return true;
880
881
882
}

//----------------------------------------------------------------------------
883
bool cmDocumentation::PrintDocumentationMan(std::ostream& os)
884
885
{
  this->CreateManDocumentation();
886
  os << ".TH " << this->GetNameString() << " 1 \""
887
     << cmSystemTools::GetCurrentDateTime("%B %d, %Y").c_str()
888
889
     << "\" \"" << this->GetNameString() << " " << cmVersion::GetCMakeVersion()
     << "\"\n";
890
  this->Print(ManForm, os);
891
  return true;
892
893
}

894
895
896
897
898
899
900
901
902
903
904
905
906
907
//----------------------------------------------------------------------------
void cmDocumentation::PrintDocumentationCommand(std::ostream& os,
                                                cmDocumentationEntry* entry)
{
  cmDocumentationEntry singleCommandSection[3] =
    {
      {entry->name, entry->brief, entry->full},
      {0,0,0}
    };
  this->ClearSections();
  this->AddSection(0, &singleCommandSection[0]);
  this->Print(TextForm, os);
}

908
909
910
911
912
913
914
915
916
917
918
//----------------------------------------------------------------------------
void cmDocumentation::CreateUsageDocumentation()
{
  this->ClearSections();
  if(!this->UsageSection.empty())
    {
    this->AddSection("Usage", &this->UsageSection[0]);
    }
  if(!this->OptionsSection.empty())
    {
    this->AddSection("Command-Line Options", &this->OptionsSection[0]);
919
    }
920
921
922
923
  if(!this->GeneratorsSection.empty())
    {
    this->AddSection("Generators", &this->GeneratorsSection[0]);
    }
924
925
926
}

//----------------------------------------------------------------------------
927
void cmDocumentation::CreateFullDocumentation()
928
{
929
930
  this->ClearSections();
  if(!this->NameSection.empty())
931
    {
932
    this->AddSection("Name", &this->NameSection[0]);
933
    }
934
935
936
937
938
939
940
941
942
943
944
945
  if(!this->UsageSection.empty())
    {
    this->AddSection("Usage", &this->UsageSection[0]);
    }
  if(!this->DescriptionSection.empty())
    {
    this->AddSection(0, &this->DescriptionSection[0]);
    }
  if(!this->OptionsSection.empty())
    {
    this->AddSection("Command-Line Options", &this->OptionsSection[0]);
    }
946
947
948
949
  if(!this->GeneratorsSection.empty())
    {
    this->AddSection("Generators", &this->GeneratorsSection[0]);
    }
950
951
952
953
954
955
  if(!this->CommandsSection.empty())
    {
    this->AddSection("Listfile Commands", &this->CommandsSection[0]);
    }
  this->AddSection("Copyright", cmDocumentationCopyright);
  this->AddSection("Mailing List", cmDocumentationMailingList);
956
957
958
}

//----------------------------------------------------------------------------
959
void cmDocumentation::CreateManDocumentation()
960
{
961
962
  this->ClearSections();
  if(!this->NameSection.empty())
963
    {
964
    this->AddSection("NAME", &this->NameSection[0]);
965
    }
966
  if(!this->UsageSection.empty())
967
    {
968
    this->AddSection("SYNOPSIS", &this->UsageSection[0]);
969
    }
970
971
972
973
974
975
976
977
  if(!this->DescriptionSection.empty())
    {
    this->AddSection("DESCRIPTION", &this->DescriptionSection[0]);
    }
  if(!this->OptionsSection.empty())
    {
    this->AddSection("OPTIONS", &this->OptionsSection[0]);
    }
978
979
980
981
  if(!this->GeneratorsSection.empty())
    {
    this->AddSection("GENERATORS", &this->GeneratorsSection[0]);
    }
982
983
984
985
986
  if(!this->CommandsSection.empty())
    {
    this->AddSection("COMMANDS", &this->CommandsSection[0]);
    }
  this->AddSection("COPYRIGHT", cmDocumentationCopyright);
987
988
989
990
991
  this->AddSection("MAILING LIST", cmDocumentationMailingList);  
  if(!this->SeeAlsoSection.empty())
    {
    this->AddSection("SEE ALSO", &this->SeeAlsoSection[0]);
    }
992
  this->AddSection("AUTHOR", cmDocumentationAuthor);
993
}
994
995

//----------------------------------------------------------------------------
996
997
998
999
void cmDocumentation::SetSection(const cmDocumentationEntry* header,
                                 const cmDocumentationEntry* section,
                                 const cmDocumentationEntry* footer,
                                 std::vector<cmDocumentationEntry>& vec)
1000
{
1001
1002
  vec.erase(vec.begin(), vec.end());
  if(header)
1003
    {
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
    for(const cmDocumentationEntry* op = header; op->brief; ++op)
      {
      vec.push_back(*op);
      }
    }
  if(section)
    {
    for(const cmDocumentationEntry* op = section; op->brief; ++op)
      {
      vec.push_back(*op);
      }
1015
    }
1016
  if(footer)
1017
    {
1018
    for(const cmDocumentationEntry* op = footer; op->brief; ++op)
1019
      {
1020
      vec.push_back(*op);
1021
1022
1023
      }
    }
  cmDocumentationEntry empty = {0,0,0};
1024
  vec.push_back(empty);  
1025
}
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038

//----------------------------------------------------------------------------
const char* cmDocumentation::GetNameString()
{
  if(this->NameString.length() > 0)
    {
    return this->NameString.c_str();
    }
  else
    {
    return "CMake";
    }
}
1039
1040
1041
1042
1043
1044
1045
1046

//----------------------------------------------------------------------------
bool cmDocumentation::IsOption(const char* arg)
{
  return ((arg[0] == '-') ||
          (strcmp(arg, "/V") == 0) ||
          (strcmp(arg, "/?") == 0));
}