home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #31 / NN_1992_31.iso / spool / comp / unix / bsd / 10574 < prev    next >
Encoding:
Internet Message Format  |  1992-12-22  |  15.2 KB

  1. Xref: sparky comp.unix.bsd:10574 comp.lang.perl:7583 alt.sources:2856
  2. Newsgroups: comp.unix.bsd,comp.lang.perl,alt.sources
  3. Path: sparky!uunet!zaphod.mps.ohio-state.edu!darwin.sura.net!spool.mu.edu!cass.ma02.bull.com!melb.bull.oz.au!zen.void.oz.au!sjg
  4. From: sjg@zen.void.oz.au (Simon J. Gerraty)
  5. Subject: Re: Easy way to create unix man pages?
  6. Message-ID: <1992Dec22.082736.21124@zen.void.oz.au>
  7. Keywords: unix manual hypertext
  8. Organization: zen programming...
  9. References: <1992Dec17.165257.9439@oakhill.sps.mot.com> <1992Dec18.040514.11824@netcom.com> <id.FBYV.EU5@ferranti.com>
  10. Date: Tue, 22 Dec 1992 08:27:36 GMT
  11. Lines: 578
  12.  
  13. Want easy to write man pages?
  14. Want to have them in your source?
  15. Have you got perl installed?  If you don't, this might tempt you :-)
  16.  
  17. [I have posted this before, but it appears upstream news problems
  18. dropped it on the floor.]
  19.  
  20. cmt2doc.pl can generate pretty decent troff source from (almost)
  21. plain text comments in your source.  The comment at the start of
  22. cmt2doc.pl IS the man page for cmt2doc.  Just try:
  23.  
  24.     cmt2doc.pl -pm cmt2doc.pl | groff -Tps -man | lpr -Plaser
  25.  
  26. or whatever works for you.
  27.  
  28. #!/bin/sh
  29. # This is a shell archive.
  30. # remove everything above the "#!/bin/sh" line
  31. # and feed to /bin/sh
  32. # Use -c option to overwrite existing files
  33. #
  34. # Contents: 
  35. #    cmt2doc.pl
  36. #
  37. # packed by: <sjg@zen> on Fri Jun  5 22:40:38 EST 1992
  38. #
  39. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  40. if test -f cmt2doc.pl -a "${1}" != "-c" ; then
  41.   echo shar: Will not over-write existing file \"cmt2doc.pl\"
  42. else
  43.   echo shar: Extracting \"cmt2doc.pl\" \(13166 characters\)
  44.   sed 's/^X//' >cmt2doc.pl << '!EOF'
  45. X#!/usr/bin/perl --
  46. Xeval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
  47. X  if $running_under_some_shell;
  48. X#
  49. X# NAME:
  50. X#    cmt2doc - extract documentation from source
  51. X#
  52. X# SYNOPSIS:
  53. X#    cmt2doc [-pamit][-e "oext"][-S "secn"][-D "secd"][-O "org"]
  54. X#        [-L "lang"][-C "cmt"][-E "ecmt"] "file"
  55. X#
  56. X# DESCRIPTION:
  57. X#    This 'Perl' script extracts documentation from comments    in
  58. X#    source files.  It allows manual pages to be written in ``plain
  59. X#    text'' in source files where they are most likely to be updated
  60. X#    when the source code is.
  61. X#
  62. X#    'cmt2doc' extracts the documentation as either clean text or as
  63. X#    input suitable for 'troff'(1) and friends.   The results in
  64. X#    either case are usually quite adequate.  Try the following
  65. X#    commands:
  66. X#.nf
  67. X#
  68. X#        'perl cmt2doc.pl -p cmt2doc.pl | more'
  69. X#        'perl cmt2doc.pl -pm cmt2doc.pl | nroff -man | more'
  70. X#.fi
  71. X#
  72. X#    'cmt2doc' can usually work out for itself how to extract the
  73. X#    text from a comment.  It looks for the regular expression 
  74. X#    '.* NAME:$' which it treats as the start of a manual page, and
  75. X#    uses what ever is found before 'NAME' as the characters to
  76. X#    remove from the start of each line. 
  77. X#
  78. X#    Typographical conventions:
  79. X#.nf
  80. X#        Words like \'this word\' will be type-set in 'bold'.
  81. X#        Words like \"this word\" will be set in "italics".
  82. X#        Words like ``this quote'' will not be touched.
  83. X#.fi
  84. X#
  85. X#    It is possible to put 'troff' commands at the start of an
  86. X#    otherwise blank line.  Indeed they are sometimes needed such as
  87. X#    when setting out examples.  They will be stripped if not
  88. X#    generating 'troff' output.  
  89. X#
  90. X#    'cmt2doc' understands the format required for most manual page
  91. X#    sections and attempts to set them appropriately.
  92. X#
  93. X# OPTIONS:
  94. X#    -p    print to stdout.  By default documentation for
  95. X#        "file" will be printed to a file in the current
  96. X#        directory of the same name but with an extention
  97. X#        that represents the format (.doc,.man,.tex). 
  98. X#
  99. X#    -a    print all documentation, not just the top level.
  100. X#
  101. X#    -m    Output for 'troff -man'.
  102. X#
  103. X#    -i    Output for texinfo (no yet implemented).
  104. X#
  105. X#    -t    ``Plain text'' strip single quotes.  Leave double quotes
  106. X#        alone though.
  107. X#
  108. X#    -e "oext"
  109. X#        Use "oext" as the extension for the output file.
  110. X#
  111. X#    -S "secn"
  112. X#        Tell [nt]roff which section the man page belongs in.
  113. X#        Default is 'L'.
  114. X#
  115. X#    -L "lang"
  116. X#        Select default values for "cmt" and "ecmt" based on
  117. X#        "lang" ('c','c++','lisp').  Most shell like languages
  118. X#        such as 'perl' and 'sh' are easily handled by the
  119. X#        defaults.
  120. X#
  121. X#    -D "secd"
  122. X#        Use "secd" as the section description.
  123. X#
  124. X#    -C "cmt"
  125. X#        Assume the comment lines start with "cmt".  Otherwise
  126. X#        we attempt to work it out either based on the file
  127. X#        extention (.c,.h,.cc etc) or from the comment itself.
  128. X#
  129. X#    -E "ecmt"
  130. X#        The comment ends when we see "ecmt" otherwise the first
  131. X#        line that does not start with "cmt".
  132. X#
  133. X#    -O "org"
  134. X#        Use "org" as the organization identifier (printed bottom
  135. X#        left of each page).
  136. X#
  137. X#    Some options only apply to certain output modes.
  138. X#
  139. X# FILES:
  140. X#    /usr/bin/perl        The perl interpreter.  This entry
  141. X#                is really just to show how 'cmt2doc'
  142. X#                handles the 'FILES' section.
  143. X#    /local/bin/cmt2doc.pl    This script. "ditto".
  144. X#
  145. X# BUGS:
  146. X#    It probably does not handle nested quotes correctly.
  147. X#    Lines starting with a \'.\' are in trouble.
  148. X#    For good results it is hard to avoid using 'troff' commands,
  149. X#    particularly '.nf' and '.fi'.
  150. X#    
  151. X#    Handling of '.TH' seems to vary with different man macro sets.
  152. X#    You may have to hack 'man_init' to get good results.
  153. X#
  154. X
  155. X#
  156. X# RCSid:
  157. X#    $Id: cmt2doc.pl,v 1.7 1992/06/05 12:39:07 sjg Exp $
  158. X#
  159. X#    @(#)Copyright (c) 1992, Simon J. Gerraty
  160. X#
  161. X#    This file is provided in the hope that it will
  162. X#    be of use.  There is absolutely NO WARRANTY.
  163. X#    Permission to copy, redistribute or otherwise
  164. X#    use this file is hereby granted provided that 
  165. X#    the above copyright notice and this notice are
  166. X#    left intact. 
  167. X#      
  168. X#    Please send copies of changes and bug-fixes to:
  169. X#    sjg@zen.void.oz.au
  170. X#
  171. X
  172. X$Myname=$0;
  173. X$Myname=~ s#^.*/([^/]*)$#$1#;
  174. X
  175. X# some defaults
  176. X$do_init='txt_init';
  177. X$do_fini='noop';
  178. X$do_sec='txt_sec';
  179. X$do_para='noop';
  180. X$do_line='txt_line';
  181. X
  182. X$man_secn='L';            # local commands
  183. X$oext='.doc';
  184. X$Debug = 0;
  185. X$start_para='';
  186. X$indent=0;
  187. X$defPD='.8v';
  188. X
  189. X$date=&get_date;
  190. X$org='FreeWare';        # be sure to set this!
  191. X
  192. Xrequire 'getopts.pl';
  193. Xdo Getopts('dpamite:L:S:C:E:D:O:');
  194. X
  195. X$org=$opt_O if defined($opt_O);
  196. X$cmt=$opt_C if defined($opt_C);
  197. X$ecmt=$opt_E if defined($opt_E);
  198. X# redefine the necessary functions
  199. Xif (defined($opt_m)) {    # [tn]roff -man
  200. X  $oext = '.man';
  201. X  $do_init='man_init';
  202. X  $do_para='man_para';
  203. X  $do_sec='man_sec';
  204. X  $do_line='man_line';
  205. X} elsif (defined($opt_i)) {    # texinfo
  206. X  $oext = '.tex';
  207. X  $do_init='texi_init';
  208. X  $do_fini='texi_fini';
  209. X  $do_sec='texi_sec';
  210. X  $do_line='texi_line';
  211. X}
  212. X$man_secn=$opt_S if defined($opt_S);
  213. Xif (defined($opt_D)) {
  214. X  $man_secd=$opt_D;
  215. X} else {
  216. X  $man_secd=&lookup_mansec($man_secn);
  217. X}
  218. X$oext=$opt_e if defined($opt_e);
  219. X$Debug = 1 if defined($opt_d);
  220. X$Lang=$opt_L if defined($opt_L);
  221. X
  222. X
  223. X$indoc=0;
  224. X$in_para = 0;
  225. X
  226. XFILE: foreach $file (@ARGV) {
  227. X  print STDERR "doing $file\n" if $Debug > 0;
  228. X  $name="./$file";
  229. X  $name=~s#^.*/([^/]*)$#$1#;
  230. X  $ext=$name;
  231. X  $ext=~s/.*(\.[^.]*)$/\1/;
  232. X
  233. X  if (!defined($opt_L)) {
  234. X    $Lang='c' if ($ext =~ m/\.[ch]$/);
  235. X    $Lang='c++' if ($ext =~ m/\.(cc|C|H)$/);
  236. X    $Lang='lisp' if ($ext =~ m/\.el$/);
  237. X  }
  238. X  if (defined($Lang)) {
  239. X    if ($Lang eq 'c') {
  240. X      $cmt = '[/ ]\*';
  241. X      $ecmt = ' *\*/';
  242. X    } elsif ($Lang eq 'c++') {
  243. X      $cmt = '(//|[/ ]\*)';
  244. X      $ecmt = ' *\*/';
  245. X    } elsif ($Lang eq 'lisp') {
  246. X      $cmt = ';+';
  247. X    }
  248. X  }
  249. X  if (!defined($opt_p)) {
  250. X    $ofile = $name;        # we've already stripped dirname
  251. X    $ofile =~ s#\.[^/.]+$##;
  252. X    $ofile .= $oext;
  253. X    print STDERR "Output to $ofile\n" if $Debug > 0;
  254. X    open(STDOUT, "> $ofile") || die "can't redirect STDOUT: $!\n";
  255. X  }
  256. X  if (!open(F, "< $file")) {
  257. X    print STDERR "can't open $file: $!\n";
  258. X    next FILE;
  259. X  }
  260. X  LINE: while (<F>) {
  261. X    chop;
  262. X    if ($indoc == 0 && m/ NAME:$/) {
  263. X      if (!defined($cmt)) {
  264. X    $cmt = $_;
  265. X    $cmt =~ s/^(.*) NAME.*/\1/;
  266. X      }
  267. X      $indoc = 1;
  268. X      $in_para = 0;
  269. X      &$do_init;
  270. X    }
  271. X    next if ($indoc == 0);
  272. X    # we are inside doc section
  273. X    if ($_ !~ m@^$cmt@ || (defined($ecmt) && $_ =~ m@^$ecmt@)) {
  274. X      $indoc = 0;
  275. X      &$do_fini;
  276. X      if (defined($opt_a)) {
  277. X    next LINE;
  278. X      } else {
  279. X    next FILE;
  280. X      }
  281. X    }
  282. X    s@^$cmt ?@@;
  283. X    $needout = 1;
  284. X    if (m/^[A-Z][A-Za-z _-]+:$/) {
  285. X      &$do_sec;
  286. X    } elsif (m/^[ \t]*$/) {
  287. X      $in_para = 0;
  288. X      if (defined($opt_m)) {
  289. X    $needout = 0;
  290. X      }
  291. X    } else {
  292. X      if ($in_para == 0) {
  293. X    $in_para = 1;
  294. X    &$do_para;
  295. X      }
  296. X      &$do_line;
  297. X    }
  298. X    print "$_\n" if ($needout > 0);
  299. X  }
  300. X  close F;
  301. X}
  302. Xexit 0;
  303. X
  304. X# for plain text these are noops
  305. Xsub noop {
  306. X}
  307. X
  308. Xsub txt_init {
  309. X  local($i,$c);
  310. X  $llength = 65;
  311. X  $c = 0;
  312. X  
  313. X  $nm=$name;
  314. X  $nm=~s/\.[^.]*$//;
  315. X  $nm =~ tr/[a-z]/[A-Z]/;
  316. X  $nm = "$nm($man_secn)";
  317. X  print "\n$nm";
  318. X  $c += length($nm);
  319. X  $i = int(($llength - length($man_secd))/ 2);
  320. X  while ($c < $i) {
  321. X    $c++;
  322. X    print " ";
  323. X  }
  324. X  print "$man_secd";
  325. X  $c += length($man_secd);
  326. X  $i = $llength - length($nm);
  327. X  while ($c < $i) {
  328. X    $c++;
  329. X    print " ";
  330. X  }
  331. X  print "$nm\n\n\n";
  332. X}
  333. X
  334. Xsub txt_sec {
  335. X  # just loose the trailing ':'
  336. X  $sec = $_;
  337. X  $sec =~ s/ *([A-Z][A-Za-z _-]*):/\1/;
  338. X  $_ = $sec;
  339. X  $in_para = 0;
  340. X}
  341. X
  342. Xsub txt_line {
  343. X  $needout = 0 if (m/^\.\w+/);    # strip nroff commands
  344. X  if (defined($opt_t)) {
  345. X    # strip 'word' to just word.
  346. X    # a bit of trickery to avoid ``quotes'' and \'word\'.
  347. X    s/^'([^']+)'/\1/g;    # 'bold'
  348. X    s/([^'\\])'([^']+)'/\1\2/g;    # 'bold'
  349. X  }
  350. X  s/\\(['"\\])/\1/g;        # strip \\ \' and \" to ' " and \
  351. X}
  352. X
  353. X
  354. Xsub man_init {
  355. X  print ".\\\" extracted from $file $date by $Myname\n";
  356. X  
  357. X  $nm=$name;
  358. X  $nm=~s/\.[^.]*$//;
  359. X  $nm =~ tr/[a-z]/[A-Z]/;
  360. X  # some tmac.an macros don't support $org HP-UX for example.
  361. X  # But most do.  Just comment out setting of $org above.
  362. X  if (defined($org)) {
  363. X    print ".TH $nm $man_secn \"$date\" \"$org\" \"$man_secd\"\n";
  364. X  } else {
  365. X    print ".TH $nm $man_secn \"$date\" \"$man_secd\"\n";
  366. X  }
  367. X  # just to be sure
  368. X  print ".PD $defPD\n";
  369. X}
  370. X
  371. Xsub man_sec {
  372. X  &man_indent(0);        # make sure indentation is back to 0
  373. X
  374. X  if ($start_para eq '.nf') {
  375. X    print ".fi\n";
  376. X  }
  377. X  if ($sec eq 'FILES') {
  378. X    # previous section was FILES
  379. X    # restore inter-paragraph distance
  380. X    print ".PD $defPD\n";
  381. X  }
  382. X  # get new section name.
  383. X  $sec = $_;
  384. X  $sec =~ s/ *([A-Z][A-Za-z _-]*):/\1/;
  385. X
  386. X  if ($sec ne 'NAME') {
  387. X    print "\n";
  388. X  }
  389. X  if ($sec =~ m/ /) {
  390. X    print ".SH \"$sec\"\n";
  391. X  } else {
  392. X    print ".SH $sec\n";
  393. X  }
  394. X  if ($sec eq 'FILES') {
  395. X    # little or no gap between paragraphs.
  396. X    # so it looks like it should.
  397. X    print ".PD .1v\n";
  398. X  }
  399. X  $needout = 0;
  400. X  $in_para = 0;
  401. X}
  402. X
  403. X# this gets a little messy
  404. Xsub man_para {
  405. X  if (m/^\.\w+/) {
  406. X    # a [tn]roff command, next line is start of para
  407. X    $in_para=0;
  408. X    return;
  409. X  }
  410. X  if ($sec =~ m/DESCRIPTION|OPTIONS/ && m/^[ \t]*-/) {
  411. X    $start_para = '.TP';
  412. X  } elsif ($sec eq 'FILES') {
  413. X    $start_para = '.TP 30';
  414. X  } elsif ($sec =~ m/NAME|SYNOPSIS/) {
  415. X    $start_para = '.nf';
  416. X  } elsif ($start_para =~ m/\.TP/) {
  417. X    $start_para = '.PP';
  418. X  } else {
  419. X    $start_para = '';
  420. X  }
  421. X  print "$start_para\n" if ($needout > 0);
  422. X  # handle indented paras
  423. X  if ($start_para !~ m/\.TP/ && m/^\t/) {
  424. X    &man_indent(-1);
  425. X  }
  426. X}
  427. X
  428. X
  429. X# we have to do more that we would like here, to
  430. X# set 'bold' and "italics" but not to harm \'words\'
  431. X# \"words\" and ``quotes''.
  432. Xsub man_line {
  433. X  # man_para will have been called once already
  434. X  # so first time in after a new para, $in_para==1.
  435. X  # in here we can set it to other values to indicate
  436. X  # a need to force a new para, or adjust indentation.
  437. X  if ($in_para == 3) {
  438. X    &man_indent(-1);
  439. X    $in_para=1;
  440. X  }
  441. X  if (m/^\.\w+/) {
  442. X    # a [tn]roff command
  443. X    $in_para=3;
  444. X    return;
  445. X  }
  446. X  s/^[ \t]*//;
  447. X  if ($sec eq 'FILES') {
  448. X    # we assume file descriptions are formated
  449. X    # filename\tdecription
  450. X    if (m/^[^\t]+\t+[^\t]+/) {
  451. X      if ($in_para == 2) {
  452. X        &man_para;
  453. X      }
  454. X      $in_para = 2;
  455. X      s/^[ \t]*//;
  456. X      s/^([^\t]+)\t+([^\t]+)/\1\n\2/;
  457. X    }
  458. X  } elsif ($sec =~ m/DESCRIPTION|OPTIONS/ && m/^[ \t]*-/) {
  459. X    if ($in_para == 2) {
  460. X      &man_para;
  461. X    }
  462. X    $in_para = 2;
  463. X    s/^[ \t]*//;
  464. X    s/\t/ /g;
  465. X    # format options correctly
  466. X    s/^([^'" ]+)/'\1'/ if (m/^[^'"]/);
  467. X    s/^('[^']+' *"[^"]+") *([^'" ])/\1\n\2/;
  468. X    s/^('[^']+') *([^'" ])/\1\n\2/;
  469. X  }
  470. X  s/\t/ /g;
  471. X  if ($sec eq 'SYNOPSIS') {
  472. X    s/^(\w+)/'\1'/;
  473. X    s/(-\w+)/'\1'/g if (m/\[/);
  474. X  }
  475. X  s/([ '"])-/\1\\-/g;
  476. X  s/^"([^"]+)"/\\fI\1\\fR/g;    # "italic"
  477. X  # avoid \"word\"
  478. X  s/([^\\])"([^"]*[^\\])"/\1\\fI\2\\fR/g;    # "italic"
  479. X  # a bit of trickery to avoid ``quotes'' and \'word\'.
  480. X  s/^'([^']+)'/\\fB\1\\fR/g;    # 'bold'
  481. X  s/([^'\\])'([^']+)'/\1\\fB\2\\fR/g;    # 'bold'
  482. X  # now make \['"] into just ' or "
  483. X  s/\\(['"])/\1/g;
  484. X}
  485. X
  486. X# adjust the indent level
  487. Xsub man_indent {
  488. X  local($i) = @_;
  489. X  local($itabs,@tabs);
  490. X  
  491. X  if ($i < 0) {
  492. X    # calculate required indent level
  493. X    $itabs=$_;
  494. X    $itabs =~ s/^(\t+)[^\t].*/\1/;
  495. X
  496. X    @tabs=split(/\t/,$itabs, 10);
  497. X    $i = $#tabs - 1;
  498. X  }
  499. X  if ($i >= 0) {
  500. X    while ($indent < $i) {
  501. X      $indent++;
  502. X      print ".RS\n";
  503. X    }
  504. X    while ($indent > $i) {
  505. X      $indent--;
  506. X      print ".RE\n";
  507. X    }
  508. X  }
  509. X}
  510. X
  511. X
  512. Xsub lookup_mansec {
  513. X  local($n) = @_;
  514. X  local($d);
  515. X  %s = &init_secd if (!defined(%s));
  516. X
  517. X  $d = $s{$n};
  518. X  if (!defined($d)) {
  519. X    $d = $s{'default'};
  520. X  }
  521. X  $d;
  522. X}
  523. X
  524. Xsub init_secd {
  525. X  local(%s);
  526. X
  527. X  $s{'default'} = 'MISC. REFERENCE MANUAL PAGES';
  528. X  $s{'1'} = 'USER COMMANDS ';
  529. X  $s{'1C'} = 'USER COMMANDS';
  530. X  $s{'1G'} = 'USER COMMANDS';
  531. X  $s{'1S'} = 'USER COMMANDS';
  532. X  $s{'1V'} = 'USER COMMANDS ';
  533. X  $s{'2'} = 'SYSTEM CALLS';
  534. X  $s{'2V'} = 'SYSTEM CALLS';
  535. X  $s{'3'} = 'C LIBRARY FUNCTIONS';
  536. X  $s{'3C'} = 'COMPATIBILITY FUNCTIONS';
  537. X  $s{'3F'} = 'FORTRAN LIBRARY ROUTINES';
  538. X  $s{'3K'} = 'KERNEL VM LIBRARY FUNCTIONS';
  539. X  $s{'3L'} = 'LIGHTWEIGHT PROCESSES LIBRARY';
  540. X  $s{'3M'} = 'MATHEMATICAL LIBRARY';
  541. X  $s{'3N'} = 'NETWORK FUNCTIONS';
  542. X  $s{'3R'} = 'RPC SERVICES LIBRARY';
  543. X  $s{'3S'} = 'STANDARD I/O FUNCTIONS';
  544. X  $s{'3V'} = 'C LIBRARY FUNCTIONS';
  545. X  $s{'3X'} = 'MISCELLANEOUS LIBRARY FUNCTIONS';
  546. X  $s{'4'} = 'DEVICES AND NETWORK INTERFACES';
  547. X  $s{'4F'} = 'PROTOCOL FAMILIES';
  548. X  $s{'4I'} = 'DEVICES AND NETWORK INTERFACES';
  549. X  $s{'4M'} = 'DEVICES AND NETWORK INTERFACES';
  550. X  $s{'4N'} = 'DEVICES AND NETWORK INTERFACES';
  551. X  $s{'4P'} = 'PROTOCOLS';
  552. X  $s{'4S'} = 'DEVICES AND NETWORK INTERFACES';
  553. X  $s{'4V'} = 'DEVICES AND NETWORK INTERFACES';
  554. X  $s{'5'} = 'FILE FORMATS';
  555. X  $s{'5V'} = 'FILE FORMATS';
  556. X  $s{'6'} = 'GAMES AND DEMOS';
  557. X  $s{'7'} = 'ENVIRONMENTS, TABLES, AND TROFF MACROS';
  558. X  $s{'7V'} = 'ENVIRONMENTS, TABLES, AND TROFF MACROS';
  559. X  $s{'8'} = 'MAINTENANCE COMMANDS';
  560. X  $s{'8C'} = 'MAINTENANCE COMMANDS';
  561. X  $s{'8S'} = 'MAINTENANCE COMMANDS';
  562. X  $s{'8V'} = 'MAINTENANCE COMMANDS';
  563. X  $s{'L'} = 'LOCAL COMMANDS';
  564. X  %s;
  565. X}
  566. X
  567. Xsub get_date {
  568. X  @months = ('January','February','March','April','May',
  569. X         'June','July','August','September','October',
  570. X         'November','December');
  571. X  ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$idst) =
  572. X    localtime(time);
  573. X  if ($year < 70) {
  574. X    $cent='20';
  575. X  } else {
  576. X    $cent = '19';
  577. X  }
  578. X  $month = $months[$mon];
  579. X  "$mday $month $cent$year";
  580. X}
  581. !EOF
  582.   if test 13166 -ne `wc -c < cmt2doc.pl`; then
  583.     echo shar: \"cmt2doc.pl\" unpacked with wrong size!
  584.   fi
  585. fi
  586. exit 0
  587. -- 
  588. Simon J. Gerraty        <sjg@zen.void.oz.au>
  589.  
  590. #include <disclaimer>   /* imagine something _very_ witty here */
  591.