install-info.pl 13 KB

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