install-info.pl 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. #!/usr/bin/perl --
  2. # fixme: --dirfile option
  3. # fixme: sort entries
  4. # fixme: send to FSF ?
  5. $version= '0.93.42.2'; # This line modified by Makefile
  6. sub version {
  7. print STDERR <<END;
  8. Debian GNU/Linux install-info $version. Copyright (C) 1994,1995
  9. Ian Jackson. This is free software; see the GNU General Public Licence
  10. version 2 or later for copying conditions. There is NO warranty.
  11. END
  12. }
  13. sub usage {
  14. print STDERR <<END;
  15. usage: install-info [--version] [--help] [--debug] [--maxwidth=nnn]
  16. [--section regexp title] [--infodir=xxx] [--align=nnn]
  17. [--calign=nnn] [--quiet] [--menuentry=xxx] [--info-dir=xxx]
  18. [--keep-old] [--description=xxx] [--test] [--remove] [--]
  19. filename
  20. END
  21. }
  22. $infodir='/usr/info';
  23. $maxwidth=79;
  24. $align=27;
  25. $calign=29;
  26. undef $menuentry;
  27. undef $quiet;
  28. undef $nowrite;
  29. undef $keepold;
  30. undef $description;
  31. undef $sectionre;
  32. undef $sectiontitle;
  33. $0 =~ m|[^/]+$|; $name= $&;
  34. while ($ARGV[0] =~ m/^--/) {
  35. $_= shift(@ARGV);
  36. last if $_ eq '--';
  37. if ($_ eq '--version') {
  38. &version; exit 0;
  39. } elsif ($_ eq '--quiet') {
  40. $quiet=1;
  41. } elsif ($_ eq '--test') {
  42. $nowrite=1;
  43. } elsif ($_ eq '--keep-old') {
  44. $keepold=1;
  45. } elsif ($_ eq '--remove') {
  46. $remove=1;
  47. } elsif ($_ eq '--help') {
  48. &usage; exit 0;
  49. } elsif ($_ eq '--debug') {
  50. open(DEBUG,">&STDERR") || exit 1;
  51. } elsif ($_ eq '--section') {
  52. if (@ARGV < 2) {
  53. print STDERR "$name: --section needs two more args\n";
  54. &usage; exit 1;
  55. }
  56. $sectionre= shift(@ARGV);
  57. $sectiontitle= shift(@ARGV);
  58. } elsif (m/^--maxwidth=([0-9]+)$/) {
  59. $maxwidth= $1;
  60. } elsif (m/^--align=([0-9]+)$/) {
  61. $align= $1;
  62. } elsif (m/^--calign=([0-9]+)$/) {
  63. $calign= $1;
  64. } elsif (m/^--infodir=/) {
  65. $infodir=$';
  66. } elsif (m/^--menuentry=/) {
  67. $menuentry=$';
  68. } elsif (m/^--info-dir=/) {
  69. $infodir=$';
  70. } elsif (m/^--description=/) {
  71. $description=$';
  72. } else {
  73. print STDERR "$name: unknown option \`$_'\n"; &usage; exit 1;
  74. }
  75. }
  76. if (!@ARGV) { &version; print STDERR "\n"; &usage; exit 1; }
  77. $filename= shift(@ARGV);
  78. if (@ARGV) { print STDERR "$name: too many arguments\n"; &usage; exit 1; }
  79. if ($remove) {
  80. print STDERR "$name: --section ignored with --remove\n" if length($sectiontitle);
  81. print STDERR "$name: --description ignored with --remove\n" if length($description);
  82. }
  83. print STDERR "$name: test mode - dir file will not be updated\n"
  84. if $nowrite && !$quiet;
  85. umask(umask(0777) & ~0444);
  86. $filename =~ m|[^/]+$|; $basename= $&; $basename =~ s/(\.info)?(\.gz)?$//;
  87. print DEBUG <<END;
  88. infodir=\`$infodir' filename=\`$filename' maxwidth=\`$maxwidth'
  89. menuentry=\`$menuentry' basename=\`$basename'
  90. description=\`$description' remove=$remove
  91. END
  92. if (!$remove) {
  93. if (!-f $filename && -f "$filename.gz" || $filename =~ s/\.gz$//) {
  94. $filename= "gzip -d <$filename.gz |"; $pipeit= 1;
  95. } else {
  96. $filename= "< $filename";
  97. }
  98. if (!length($description)) {
  99. open(IF,"$filename") || die "$name: read $filename: $!\n";
  100. $asread='';
  101. while(<IF>) {
  102. m/^START-INFO-DIR-ENTRY$/ && last;
  103. m/^INFO-DIR-SECTION (.+)$/ && do {
  104. $sectiontitle = $1 unless defined($sectiontitle);
  105. $sectionre = '^'.quotemeta($1) unless defined($sectionre);
  106. }
  107. }
  108. while(<IF>) { last if m/^END-INFO-DIR-ENTRY$/; $asread.= $_; }
  109. close(IF); &checkpipe;
  110. if ($asread =~ m/(\* *[^:]+: *\([^\)]+\).*\. *.*\n){2,}/) {
  111. $infoentry= $asread; $multiline= 1;
  112. print DEBUG <<END;
  113. multiline \`$asread'
  114. END
  115. } elsif ($asread =~ m/^\* *([^:]+):( *\([^\)]+\)\.|:)\s*/) {
  116. $menuentry= $1; $description= $';
  117. print DEBUG <<END;
  118. infile menuentry \`$menuentry' description \`$description'
  119. END
  120. } elsif (length($asread)) {
  121. print STDERR <<END;
  122. $name: warning, ignoring confusing INFO-DIR-ENTRY in file.
  123. END
  124. }
  125. }
  126. if (length($infoentry)) {
  127. $infoentry =~ m/\n/;
  128. print "$`\n" unless $quiet;
  129. $infoentry =~ m/^\* *([^:]+): *\(([^\)]+)\)/ || die; # internal error
  130. $sortby= $1; $fileinentry= $2;
  131. } else {
  132. if (!length($description)) {
  133. open(IF,"$filename") || die "$name: read $filename: $!\n";
  134. $asread='';
  135. while(<IF>) {
  136. if (m/^\s*[Tt]his file documents/) {
  137. $asread=$';
  138. last;
  139. }
  140. }
  141. if (length($asread)) {
  142. while(<IF>) { last if m/^\s*$/; $asread.= $_; }
  143. $description= $asread;
  144. }
  145. close(IF); &checkpipe;
  146. }
  147. if (!length($description)) {
  148. print STDERR <<END;
  149. No \`START-INFO-DIR-ENTRY' and no \`This file documents'.
  150. $name: unable to determine description for \`dir' entry - giving up
  151. END
  152. exit 1;
  153. }
  154. $description =~ s/^\s*(.)//; $_=$1; y/a-z/A-Z/;
  155. $description= $_ . $description;
  156. if (!length($menuentry)) {
  157. $menuentry= $basename; $menuentry =~ s/\Winfo$//;
  158. $menuentry =~ s/^.//; $_=$&; y/a-z/A-Z/;
  159. $menuentry= $_ . $menuentry;
  160. }
  161. print DEBUG <<END;
  162. menuentry=\`$menuentry' description=\`$description'
  163. END
  164. $cprefix= sprintf("* %s: (%s).", $menuentry, $basename);
  165. $align--; $calign--;
  166. $lprefix= length($cprefix);
  167. if ($lprefix < $align) {
  168. $cprefix .= ' ' x ($align - $lprefix);
  169. $lprefix= $align;
  170. }
  171. $prefix= "\n". (' 'x $calign);
  172. $cwidth= $maxwidth+1;
  173. for $_ (split(/\s+/,$description)) {
  174. $l= length($_);
  175. $cwidth++; $cwidth += $l;
  176. if ($cwidth > $maxwidth) {
  177. $infoentry .= $cprefix;
  178. $cwidth= $lprefix+1+$l;
  179. $cprefix= $prefix; $lprefix= $calign;
  180. }
  181. $infoentry.= ' '; $infoentry .= $_;
  182. }
  183. $infoentry.= "\n";
  184. print $infoentry unless $quiet;
  185. $sortby= $menuentry; $sortby =~ y/A-Z/a-z/;
  186. }
  187. }
  188. if (!$nowrite && !link("$infodir/dir","$infodir/dir.lock")) {
  189. die "$name: failed to lock dir for editing! $!\n".
  190. ($! =~ m/exists/i ? "try deleting $infodir/dir.lock ?\n" : '');
  191. }
  192. open(OLD,"$infodir/dir") || &ulquit("$name: open $infodir/dir: $!\n");
  193. @work= <OLD>;
  194. eof(OLD) || &ulquit("$name: read $infodir/dir: $!\n");
  195. close(OLD) || &ulquit("$name: close $infodir/dir after read: $!\n");
  196. while ($work[$#work] !~ m/\S/) { $#work--; }
  197. do {
  198. last if !@work;
  199. $_= shift(@work);
  200. push(@head,$_);
  201. } until (m/^\*\s*Menu:/i);
  202. if (!$remove) {
  203. for ($i=0; $i<=$#work; $i++) {
  204. next unless $work[$i] =~ m/^\* *[^:]+: *\(([^\)]+)\).*\.\s/;
  205. last if $1 eq $basename || $1 eq "$basename.info";
  206. }
  207. for ($j=$i; $j<=$#work+1; $j++) {
  208. next if $work[$j] =~ m/^\s+\S/;
  209. last unless $work[$j] =~ m/^\* *[^:]+: *\(([^\)]+)\).*\.\s/;
  210. last unless $1 eq $basename || $1 eq "$basename.info";
  211. }
  212. if ($i < $j) {
  213. if ($keepold) {
  214. print "$name: existing entry for \`$basename' not replaced\n" unless $quiet;
  215. $nowrite=1;
  216. } else {
  217. print "$name: replacing existing dir entry for \`$basename'\n" unless $quiet;
  218. }
  219. $mss= $i;
  220. @work= (@work[0..$i-1], @work[$j..$#work]);
  221. } elsif (length($sectionre)) {
  222. $mss= -1;
  223. for ($i=0; $i<=$#work; $i++) {
  224. $_= $work[$i];
  225. next if m/^\*/;
  226. next unless m/$sectionre/io;
  227. $mss= $i+1; last;
  228. }
  229. if ($mss < 0) {
  230. print "$name: creating new section \`$sectiontitle'\n" unless $quiet;
  231. for ($i= $#work; $i>=0 && $work[$i] =~ m/\S/; $i--) { }
  232. if ($i <= 0) { # We ran off the top, make this section and Misc.
  233. print "$name: no sections yet, creating Miscellaneous section too.\n"
  234. unless $quiet;
  235. @work= ("\n", "$sectiontitle\n", "\n", "Miscellaneous:\n", @work);
  236. $mss= 1;
  237. } else {
  238. @work= (@work[0..$i], "$sectiontitle\n", "\n", @work[$i+1..$#work]);
  239. $mss= $i+1;
  240. }
  241. }
  242. while ($mss <= $#work) {
  243. $work[$mss] =~ m/\S/ || last;
  244. $work[$mss] =~ m/^\* *([^:]+):/ || ($mss++, next);
  245. last if $multiline;
  246. $_=$1; y/A-Z/a-z/;
  247. last if $_ gt $sortby;
  248. $mss++;
  249. }
  250. } else {
  251. print "$name: no section specified for new entry, placing at end\n"
  252. unless $quiet;
  253. $mss= $#work+1;
  254. }
  255. @work= (@work[0..$mss-1], $infoentry, @work[$mss..$#work]);
  256. } else {
  257. for ($i=0; $i<=$#work; $i++) {
  258. next unless $work[$i] =~ m/^\* *([^:]+): *\((\w[^\)]*)\)/;
  259. $tme= $1; $tfile= $2; $match= $&;
  260. next unless $tfile eq $basename;
  261. last if !length($menuentry);
  262. $tme =~ y/A-Z/a-z/;
  263. last if $tme eq $menuentry;
  264. }
  265. for ($j=$i; $j<=$#work+1; $j++) {
  266. next if $work[$j] =~ m/^\s+\S/;
  267. last unless $work[$j] =~ m/^\* *([^:]+): *\((\w[^\)]*)\)/;
  268. $tme= $1; $tfile= $2;
  269. last unless $tfile eq $basename;
  270. next if !length($menuentry);
  271. $tme =~ y/A-Z/a-z/;
  272. last unless $tme eq $menuentry;
  273. }
  274. print DEBUG <<END;
  275. i=$i \$work[\$i]=\`$work[$i]' j=$j \$work[\$j]=\`$work[$j]'
  276. END
  277. if ($i < $j) {
  278. print "$name: deleting entry \`$match ...'\n" unless $quiet;
  279. $_= $work[$i-1];
  280. unless (m/^\s/ || m/^\*/ || m/^$/ ||
  281. $j > $#work || $work[$j] !~ m/^\s*$/) {
  282. s/:?\s+$//;
  283. if ($keepold) {
  284. print "$name: empty section \`$_' not removed\n" unless $quiet;
  285. } else {
  286. $i--; $j++;
  287. print "$name: deleting empty section \`$_'\n" unless $quiet;
  288. }
  289. }
  290. @work= (@work[0..$i-1], @work[$j..$#work]);
  291. } else {
  292. print "$name: no entry for file \`$basename'".
  293. (length($menuentry) ? " and menu entry \`$menuentry'": '').
  294. ".\n"
  295. unless $quiet;
  296. }
  297. }
  298. if (!$nowrite) {
  299. open(NEW,"> $infodir/dir.new") || &ulquit("$name: create $infodir/dir.new: $!\n");
  300. print(NEW @head,@work) || &ulquit("$name: write $infodir/dir.new: $!\n");
  301. close(NEW) || &ulquit("$name: close $infodir/dir.new: $!\n");
  302. unlink("$infodir/dir.old");
  303. link("$infodir/dir","$infodir/dir.old") ||
  304. &ulquit("$name: cannot backup old $infodir/dir, giving up: $!\n");
  305. rename("$infodir/dir.new","$infodir/dir") ||
  306. &ulquit("$name: install new $infodir/dir: $!\n");
  307. unlink("$infodir/dir.lock") || die "$name: unlock $infodir/dir: $!\n";
  308. }
  309. sub ulquit {
  310. unlink("$infodir/dir.lock") ||
  311. warn "$name: warning - unable to unlock $infodir/dir: $!\n";
  312. die $_[0];
  313. }
  314. sub checkpipe {
  315. return if !$pipeit || !$? || $?==0x8D00 || $?==0x0D;
  316. die "$name: read $filename: $?\n";
  317. }
  318. exit 0;