install-info.pl 12 KB

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