install-info.pl 15 KB

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