install-info.c 90 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846
  1. /* install-info -- merge Info directory entries from an Info file.
  2. $Id$
  3. Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
  4. 2005, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016
  5. Free Software Foundation, Inc.
  6. This program is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program. If not, see <http://www.gnu.org/licenses/>. */
  16. #include "system.h"
  17. #include <getopt.h>
  18. #include <regex.h>
  19. #include <argz.h>
  20. #define TAB_WIDTH 8
  21. static char *progname = "install-info";
  22. static char *default_section = NULL;
  23. struct spec_entry;
  24. struct spec_section;
  25. struct line_data *findlines (char *data, int size, int *nlinesp);
  26. void insert_entry_here (struct spec_entry *entry, int line_number,
  27. struct line_data *dir_lines, int n_entries);
  28. int compare_section_names (const void *s1, const void *s2);
  29. int compare_entries_text (const void *e1, const void *e2);
  30. /* Data structures. */
  31. /* Record info about a single line from a file as read into core. */
  32. struct line_data
  33. {
  34. /* The start of the line. */
  35. char *start;
  36. /* The number of characters in the line,
  37. excluding the terminating newline. */
  38. int size;
  39. /* Vector containing pointers to the entries to add before this line.
  40. The vector is null-terminated. */
  41. struct spec_entry **add_entries_before;
  42. /* Vector containing pointers to the sections to add before this line.
  43. The vector is not null-terminated. */
  44. struct spec_section **add_sections_before;
  45. /* The vector ADD_SECTIONS_BEFORE_HERE contains exactly this many
  46. pointers to sections. */
  47. int num_sections_to_add;
  48. /* 1 means don't output this line. */
  49. int delete;
  50. };
  51. /* This is used for a list of the specified menu section names
  52. in which entries should be added. */
  53. struct spec_section
  54. {
  55. struct spec_section *next;
  56. char *name;
  57. /* 1 means we have not yet found an existing section with this name
  58. in the dir file--so we will need to add a new section. */
  59. int missing;
  60. };
  61. /* This is used for a list of the entries specified to be added. */
  62. struct spec_entry
  63. {
  64. struct spec_entry *next;
  65. char *text;
  66. size_t text_len;
  67. /* A pointer to the list of sections to which this entry should be
  68. added. */
  69. struct spec_section *entry_sections;
  70. /* A pointer to a section that is beyond the end of the chain whose
  71. head is pointed to by entry_sections. */
  72. struct spec_section *entry_sections_tail;
  73. /* Non-zero means that the entry doesn't have a name specified. This
  74. can only happen if a --description preceeds a --name option. */
  75. int missing_name;
  76. /* Non-zero means that the entry doesn't have a description. This
  77. happens when a --name option is given prior to a --description
  78. option. */
  79. int missing_description;
  80. /* Non-zero means that the entry doesn't have an Info file specified.
  81. This means that the entry was taken from the command-line but it
  82. only contains the name, and not the info file's basename, which
  83. we get later on. This only happens on entries that originate
  84. from --name options. */
  85. int missing_basename;
  86. };
  87. /* This is used for a list of nodes found by parsing the dir file. */
  88. struct node
  89. {
  90. struct node *next;
  91. /* The node name. */
  92. char *name;
  93. /* The line number of the line where the node starts.
  94. This is the line that contains control-underscore. */
  95. int start_line;
  96. /* The line number of the line where the node ends,
  97. which is the end of the file or where the next line starts. */
  98. int end_line;
  99. /* Start of first line in this node's menu
  100. (the line after the * Menu: line). */
  101. char *menu_start;
  102. /* The start of the chain of sections in this node's menu. */
  103. struct menu_section *sections;
  104. /* The last menu section in the chain. */
  105. struct menu_section *last_section;
  106. };
  107. /* This is used for a list of sections found in a node's menu.
  108. Each struct node has such a list in the sections field. */
  109. struct menu_section
  110. {
  111. struct menu_section *next;
  112. char *name;
  113. /* Line number of start of section. */
  114. int start_line;
  115. /* Line number of end of section. */
  116. int end_line;
  117. };
  118. /* This table defines all the long-named options, says whether they
  119. use an argument, and maps them into equivalent single-letter options. */
  120. struct option longopts[] =
  121. {
  122. { "add-once", no_argument, NULL, '1'},
  123. { "align", required_argument, NULL, 'A'},
  124. { "append-new-sections", no_argument, NULL, 'a'},
  125. { "calign", required_argument, NULL, 'C'},
  126. { "debug", no_argument, NULL, 'g' },
  127. { "delete", no_argument, NULL, 'r' },
  128. { "defentry", required_argument, NULL, 'E' },
  129. { "defsection", required_argument, NULL, 'S' },
  130. { "dir-file", required_argument, NULL, 'd' },
  131. { "entry", required_argument, NULL, 'e' },
  132. { "name", required_argument, NULL, 't' },
  133. { "menuentry", required_argument, NULL, 't' },
  134. { "description", required_argument, NULL, 'c' },
  135. { "help", no_argument, NULL, 'h' },
  136. { "no-indent", no_argument, NULL, 'I' },
  137. { "infodir", required_argument, NULL, 'D' },
  138. { "info-dir", required_argument, NULL, 'D' },
  139. { "info-file", required_argument, NULL, 'i' },
  140. { "item", required_argument, NULL, 'e' },
  141. { "keep-old", no_argument, NULL, 'k' },
  142. { "maxwidth", required_argument, NULL, 'W'},
  143. { "max-width", required_argument, NULL, 'W'},
  144. { "quiet", no_argument, NULL, 'q' },
  145. { "remove", no_argument, NULL, 'r' },
  146. { "remove-exactly", no_argument, NULL, 'x' },
  147. { "section", required_argument, NULL, 's' },
  148. { "regex", required_argument, NULL, 'R' },
  149. { "silent", no_argument, NULL, 'q' },
  150. { "test", no_argument, NULL, 'n' },
  151. { "dry-run", no_argument, NULL, 'n' },
  152. { "version", no_argument, NULL, 'V' },
  153. { 0 }
  154. };
  155. regex_t *psecreg = NULL;
  156. /* Nonzero means that the name specified for the Info file will be used
  157. (without removing .gz, .info extension or leading path) to match the
  158. entries that must be removed. */
  159. int remove_exactly = 0;
  160. /* Nonzero means that sections that don't have entries in them will be
  161. deleted. */
  162. int remove_empty_sections = 1;
  163. /* Nonzero means that new Info entries into the DIR file go into all
  164. sections that match with --section-regex or --section. Zero means
  165. that new entries go into only the first section that matches. */
  166. int add_entries_into_all_matching_sections = 1;
  167. /* Nonzero means we do not replace same-named info entries. */
  168. int keep_old_flag = 0;
  169. /* Nonzero means --test was specified, to inhibit updating the dir file. */
  170. int chicken_flag = 0;
  171. /* Zero means that entries will not be formatted when they are either
  172. added or replaced. */
  173. int indent_flag = 1;
  174. /* Zero means that new sections will be added at the end of the DIR file. */
  175. int order_new_sections_alphabetically_flag = 1;
  176. /* Error message functions. */
  177. void
  178. vdiag (const char *fmt, const char *diagtype, va_list ap)
  179. {
  180. fprintf (stderr, "%s: ", progname);
  181. if (diagtype)
  182. fprintf (stderr, "%s: ", diagtype);
  183. vfprintf (stderr, fmt, ap);
  184. putc ('\n', stderr);
  185. }
  186. void
  187. error (const char *fmt, ...)
  188. {
  189. va_list ap;
  190. va_start (ap, fmt);
  191. vdiag (fmt, NULL, ap);
  192. va_end (ap);
  193. }
  194. /* VARARGS1 */
  195. void
  196. warning (const char *fmt, ...)
  197. {
  198. va_list ap;
  199. va_start (ap, fmt);
  200. vdiag (fmt, "warning", ap);
  201. va_end (ap);
  202. }
  203. /* Print error message and exit. */
  204. void
  205. fatal (const char *fmt, ...)
  206. {
  207. va_list ap;
  208. va_start (ap, fmt);
  209. vdiag (fmt, NULL, ap);
  210. va_end (ap);
  211. exit (EXIT_FAILURE);
  212. }
  213. /* Return a newly-allocated string
  214. whose contents concatenate those of S1, S2, S3. */
  215. char *
  216. concat (const char *s1, const char *s2, const char *s3)
  217. {
  218. int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
  219. char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
  220. strcpy (result, s1);
  221. strcpy (result + len1, s2);
  222. strcpy (result + len1 + len2, s3);
  223. *(result + len1 + len2 + len3) = 0;
  224. return result;
  225. }
  226. /* Return a string containing SIZE characters
  227. copied from starting at STRING. */
  228. char *
  229. copy_string (const char *string, int size)
  230. {
  231. int i;
  232. char *copy = (char *) xmalloc (size + 1);
  233. for (i = 0; i < size; i++)
  234. copy[i] = string[i];
  235. copy[size] = 0;
  236. return copy;
  237. }
  238. /* Print fatal error message based on errno, with file name NAME. */
  239. void
  240. pfatal_with_name (const char *name)
  241. {
  242. /* Empty files don't set errno, so we get something like
  243. "install-info: No error for foo", which is confusing. */
  244. if (errno == 0)
  245. fatal (_("%s: empty file"), name);
  246. fatal (_("%s for %s"), strerror (errno), name);
  247. }
  248. /* Compare the menu item names in LINE1 (line length LEN1)
  249. and LINE2 (line length LEN2). Return 1 if the item name
  250. in LINE1 is less, 0 otherwise. */
  251. static int
  252. menu_line_lessp (char *line1, int len1, char *line2, int len2)
  253. {
  254. int minlen = (len1 < len2 ? len1 : len2);
  255. int i;
  256. for (i = 0; i < minlen; i++)
  257. {
  258. /* If one item name is a prefix of the other,
  259. the former one is less. */
  260. if (line1[i] == ':' && line2[i] != ':')
  261. return 1;
  262. if (line2[i] == ':' && line1[i] != ':')
  263. return 0;
  264. /* If they both continue and differ, one is less. */
  265. if (line1[i] < line2[i])
  266. return 1;
  267. if (line1[i] > line2[i])
  268. return 0;
  269. }
  270. /* With a properly formatted dir file,
  271. we can only get here if the item names are equal. */
  272. return 0;
  273. }
  274. /* Compare the menu item names in LINE1 (line length LEN1)
  275. and LINE2 (line length LEN2). Return 1 if the item names are equal,
  276. 0 otherwise. */
  277. static int
  278. menu_line_equal (char *line1, int len1, char *line2, int len2)
  279. {
  280. int minlen = (len1 < len2 ? len1 : len2);
  281. int i;
  282. for (i = 0; i < minlen; i++)
  283. {
  284. /* If both item names end here, they are equal. */
  285. if (line1[i] == ':' && line2[i] == ':')
  286. return 1;
  287. /* If they both continue and differ, one is less. */
  288. if (line1[i] != line2[i])
  289. return 0;
  290. }
  291. /* With a properly formatted dir file,
  292. we can only get here if the item names are equal. */
  293. return 1;
  294. }
  295. /* Given the full text of a menu entry, null terminated,
  296. return just the menu item name (copied). */
  297. char *
  298. extract_menu_item_name (char *item_text)
  299. {
  300. char *p;
  301. if (*item_text == '*')
  302. item_text++;
  303. while (*item_text == ' ')
  304. item_text++;
  305. p = item_text;
  306. while (*p && *p != ':') p++;
  307. return copy_string (item_text, p - item_text);
  308. }
  309. /* Given the full text of a menu entry, terminated by null or newline,
  310. return just the menu item file (copied). */
  311. char *
  312. extract_menu_file_name (char *item_text)
  313. {
  314. char *p = item_text;
  315. /* If we have text that looks like * ITEM: (FILE)NODE...,
  316. extract just FILE. Otherwise return "(none)". */
  317. if (*p == '*')
  318. p++;
  319. while (*p == ' ')
  320. p++;
  321. /* Skip to and past the colon. */
  322. while (*p && *p != '\n' && *p != ':') p++;
  323. if (*p == ':') p++;
  324. /* Skip past the open-paren. */
  325. while (1)
  326. {
  327. if (*p == '(')
  328. break;
  329. else if (*p == ' ' || *p == '\t')
  330. p++;
  331. else
  332. return "(none)";
  333. }
  334. p++;
  335. item_text = p;
  336. /* File name ends just before the close-paren. */
  337. while (*p && *p != '\n' && *p != ')') p++;
  338. if (*p != ')')
  339. return "(none)";
  340. return copy_string (item_text, p - item_text);
  341. }
  342. /* Return FNAME with any [.info][.gz] suffix removed. */
  343. static char *
  344. strip_info_suffix (char *fname)
  345. {
  346. char *ret = xstrdup (fname);
  347. unsigned len = strlen (ret);
  348. if (len > 3 && FILENAME_CMP (ret + len - 3, ".gz") == 0)
  349. {
  350. len -= 3;
  351. ret[len] = 0;
  352. }
  353. else if (len > 3 && FILENAME_CMP (ret + len - 3, ".xz") == 0)
  354. {
  355. len -= 3;
  356. ret[len] = 0;
  357. }
  358. else if (len > 4 && FILENAME_CMP (ret + len - 4, ".bz2") == 0)
  359. {
  360. len -= 4;
  361. ret[len] = 0;
  362. }
  363. else if (len > 3 && FILENAME_CMP (ret + len - 3, ".lz") == 0)
  364. {
  365. len -= 3;
  366. ret[len] = 0;
  367. }
  368. else if (len > 5 && FILENAME_CMP (ret + len - 5, ".lzma") == 0)
  369. {
  370. len -= 5;
  371. ret[len] =0;
  372. }
  373. if (len > 5 && FILENAME_CMP (ret + len - 5, ".info") == 0)
  374. {
  375. len -= 5;
  376. ret[len] = 0;
  377. }
  378. else if (len > 4 && FILENAME_CMP (ret + len - 4, ".inf") == 0)
  379. {
  380. len -= 4;
  381. ret[len] = 0;
  382. }
  383. #ifdef __MSDOS__
  384. else if (len > 4 && (FILENAME_CMP (ret + len - 4, ".inz") == 0
  385. || FILENAME_CMP (ret + len - 4, ".igz") == 0))
  386. {
  387. len -= 4;
  388. ret[len] = 0;
  389. }
  390. #endif /* __MSDOS__ */
  391. return ret;
  392. }
  393. /* Return true if ITEM matches NAME and is followed by TERM_CHAR. ITEM
  394. can also be followed by `.gz', `.info.gz', or `.info' (and then
  395. TERM_CHAR) and still match. */
  396. static int
  397. menu_item_equal (const char *item, char term_char, const char *name)
  398. {
  399. int ret;
  400. const char *item_basename = item;
  401. unsigned name_len = strlen (name);
  402. /* We must compare the basename in ITEM, since we are passed the
  403. basename of the original info file. Otherwise, a new entry like
  404. "lilypond/lilypond" won't match "lilypond".
  405. Actually, it seems to me that we should really compare the whole
  406. name, and not just the basename. Couldn't there be dir1/foo.info
  407. and dir2/foo.info? Also, it seems like we should be using the
  408. filename from the new dir entries, not the filename on the command
  409. line. Not worrying about those things right now, though. --karl,
  410. 26mar04. */
  411. if (!remove_exactly) {
  412. while (*item_basename && !IS_SLASH (*item_basename)
  413. && *item_basename != term_char)
  414. item_basename++;
  415. if (! *item_basename || *item_basename == term_char)
  416. item_basename = item; /* no /, use original */
  417. else
  418. item_basename++; /* have /, move past it */
  419. }
  420. /* First, ITEM must actually match NAME (usually it won't). */
  421. ret = mbsncasecmp (item_basename, name, name_len) == 0;
  422. if (ret)
  423. {
  424. /* Then, `foobar' doesn't match `foo', so be sure we've got all of
  425. ITEM. The various suffixes should never actually appear in the
  426. dir file, but sometimes people put them in. */
  427. static char *suffixes[]
  428. = { "", ".info.gz", ".info", ".inf", ".gz",
  429. #ifdef __MSDOS__
  430. ".inz", ".igz",
  431. #endif
  432. NULL };
  433. unsigned i;
  434. ret = 0;
  435. for (i = 0; !ret && suffixes[i]; i++)
  436. {
  437. char *suffix = suffixes[i];
  438. unsigned suffix_len = strlen (suffix);
  439. ret = mbsncasecmp (item_basename + name_len, suffix, suffix_len) == 0
  440. && item_basename[name_len + suffix_len] == term_char;
  441. }
  442. }
  443. return ret;
  444. }
  445. void
  446. suggest_asking_for_help (void)
  447. {
  448. fprintf (stderr, _("\tTry `%s --help' for a complete list of options.\n"),
  449. progname);
  450. exit (EXIT_FAILURE);
  451. }
  452. void
  453. print_help (void)
  454. {
  455. printf (_("Usage: %s [OPTION]... [INFO-FILE [DIR-FILE]]\n"), progname);
  456. puts ("");
  457. puts (_("Add or remove entries in INFO-FILE from the Info directory DIR-FILE."));
  458. puts (_("INFO-FILE and DIR-FILE are required unless the --info-file\n\
  459. or --dir-file (or --info-dir) options are given, respectively."));
  460. puts ("");
  461. puts (_("\
  462. Options:\n\
  463. --add-once add only to first matching section, not all.\n\
  464. --align=COL start description of new entries at column COL.\n\
  465. --calign=COL format second and subsequent description lines to\n\
  466. start at column COL."));
  467. puts (_("\
  468. --debug report what is being done.\n\
  469. --delete delete existing entries for INFO-FILE from DIR-FILE;\n\
  470. don't insert any new entries.\n\
  471. --defsection=TEXT like --section, but only use TEXT if no sections\n\
  472. are present in INFO-FILE (replacing \"Miscellaneous\").\n\
  473. --description=TEXT the description of the entry is TEXT; used with\n\
  474. the --name option to become synonymous with the\n\
  475. --entry option.\n\
  476. --dir-file=NAME specify file name of Info directory file;\n\
  477. equivalent to using the DIR-FILE argument.\n\
  478. --dry-run same as --test."));
  479. puts (_("\
  480. --entry=TEXT insert TEXT as an Info directory entry,\n\
  481. overriding any corresponding entry from DIR-FILE.\n\
  482. TEXT is written as an Info menu item line followed\n\
  483. by zero or more extra lines starting with whitespace.\n\
  484. If you specify more than one entry, all are added.\n\
  485. If you don't specify any entries, they are determined\n\
  486. from information in the Info file itself."));
  487. puts (_("\
  488. --help display this help and exit.\n\
  489. --info-dir=DIR same as --dir-file=DIR/dir.\n\
  490. --info-file=FILE specify Info file to install in the directory;\n\
  491. equivalent to using the INFO-FILE argument.\n\
  492. --item=TEXT same as --entry=TEXT.\n\
  493. --keep-old do not replace entries, or remove empty sections."));
  494. puts (_("\
  495. --maxwidth, --max-width=COL wrap description at column COL.\n\
  496. --menuentry=TEXT same as --name=TEXT.\n\
  497. --name=TEXT the name of the entry is TEXT; used with --description\n\
  498. to become synonymous with the --entry option.\n\
  499. --no-indent do not format new entries in the DIR file.\n\
  500. --quiet suppress warnings."));
  501. puts (_("\
  502. --regex=R put this file's entries in all sections that match the\n\
  503. regular expression R (ignoring case).\n\
  504. --remove same as --delete.\n\
  505. --remove-exactly only remove if the info file name matches exactly;\n\
  506. suffixes such as .info and .gz are not ignored.\n\
  507. --section=SEC put entries in section SEC of the directory.\n\
  508. If you specify more than one section, all the entries\n\
  509. are added in each of the sections.\n\
  510. If you don't specify any sections, they are determined\n\
  511. from information in the Info file itself;\n\
  512. if nothing is available there, the --defsection\n\
  513. value is used; if that is not specified, the\n\
  514. final default is \"Miscellaneous\".\n\
  515. --section R SEC equivalent to --regex=R --section=SEC --add-once."));
  516. puts (_("\
  517. --silent suppress warnings.\n\
  518. --test suppress updating of DIR-FILE.\n\
  519. --version display version information and exit."));
  520. puts ("");
  521. puts (_("\
  522. Email bug reports to bug-texinfo@gnu.org,\n\
  523. general questions and discussion to help-texinfo@gnu.org.\n\
  524. Texinfo home page: http://www.gnu.org/software/texinfo/"));
  525. }
  526. /* If DIRFILE does not exist, and we are not in test mode, create a
  527. minimal one (or abort). If it already exists, do nothing. */
  528. static void
  529. ensure_dirfile_exists (char *dirfile)
  530. {
  531. int desc;
  532. if (chicken_flag)
  533. return;
  534. desc = open (dirfile, O_RDONLY);
  535. if (desc < 0 && errno == ENOENT)
  536. {
  537. FILE *f;
  538. char *readerr = strerror (errno);
  539. f = fopen (dirfile, "w");
  540. if (f)
  541. {
  542. fprintf (f, _("This is the file .../info/dir, which contains the\n\
  543. topmost node of the Info hierarchy, called (dir)Top.\n\
  544. The first time you invoke Info you start off looking at this node.\n\
  545. %c\n\
  546. %s\tThis is the top of the INFO tree\n\
  547. \n\
  548. This (the Directory node) gives a menu of major topics.\n\
  549. Typing \"q\" exits, \"H\" lists all Info commands, \"d\" returns here,\n\
  550. \"h\" gives a primer for first-timers,\n\
  551. \"mEmacs<Return>\" visits the Emacs manual, etc.\n\
  552. \n\
  553. In Emacs, you can click mouse button 2 on a menu item or cross reference\n\
  554. to select it.\n\
  555. \n\
  556. %s\n\
  557. "), /* These keywords must not be translated: */
  558. '\x1f', "File: dir,\tNode: Top", "* Menu:"
  559. );
  560. if (fclose (f) < 0)
  561. pfatal_with_name (dirfile);
  562. }
  563. else
  564. {
  565. /* Didn't exist, but couldn't open for writing. */
  566. fatal (_("%s: could not read (%s) and could not create (%s)"),
  567. dirfile, readerr, strerror (errno));
  568. }
  569. }
  570. else
  571. close (desc); /* It already existed, so fine. */
  572. }
  573. /* Open FILENAME and return the resulting stream pointer. If it doesn't
  574. exist, try FILENAME.gz. If that doesn't exist either, call
  575. CREATE_CALLBACK (with FILENAME as arg) to create it, if that is
  576. non-NULL. If still no luck, return a null pointer.
  577. Return the actual name of the file we tried to open in
  578. OPENED_FILENAME and the compress program to (de)compress it in
  579. COMPRESSION_PROGRAM. The compression program is determined by the
  580. magic number, not the filename.
  581. Return either stdin reading the file, or a non-stdin pipe reading
  582. the output of the compression program. */
  583. FILE *
  584. open_possibly_compressed_file (char *filename,
  585. void (*create_callback) (char *),
  586. char **opened_filename, char **compression_program)
  587. {
  588. char *local_opened_filename, *local_compression_program;
  589. int nread;
  590. char data[13];
  591. FILE *f;
  592. /* We let them pass NULL if they don't want this info, but it's easier
  593. to always determine it. */
  594. if (!opened_filename)
  595. opened_filename = &local_opened_filename;
  596. *opened_filename = filename;
  597. f = fopen (*opened_filename, FOPEN_RBIN);
  598. if (!f)
  599. {
  600. *opened_filename = concat (filename, ".gz", "");
  601. f = fopen (*opened_filename, FOPEN_RBIN);
  602. }
  603. if (!f)
  604. {
  605. free (*opened_filename);
  606. *opened_filename = concat (filename, ".xz", "");
  607. f = fopen (*opened_filename, FOPEN_RBIN);
  608. }
  609. if (!f)
  610. {
  611. free (*opened_filename);
  612. *opened_filename = concat (filename, ".bz2", "");
  613. f = fopen (*opened_filename, FOPEN_RBIN);
  614. }
  615. if (!f)
  616. {
  617. free (*opened_filename);
  618. *opened_filename = concat (filename, ".lz", "");
  619. f = fopen (*opened_filename, FOPEN_RBIN);
  620. }
  621. if (!f)
  622. {
  623. free (*opened_filename);
  624. *opened_filename = concat (filename, ".lzma", "");
  625. f = fopen (*opened_filename, FOPEN_RBIN);
  626. }
  627. #ifdef __MSDOS__
  628. if (!f)
  629. {
  630. free (*opened_filename);
  631. *opened_filename = concat (filename, ".igz", "");
  632. f = fopen (*opened_filename, FOPEN_RBIN);
  633. }
  634. if (!f)
  635. {
  636. free (*opened_filename);
  637. *opened_filename = concat (filename, ".inz", "");
  638. f = fopen (*opened_filename, FOPEN_RBIN);
  639. }
  640. #endif /* __MSDOS__ */
  641. if (!f)
  642. {
  643. /* The file was not found with any extention added. Try the
  644. original file again. */
  645. free (*opened_filename);
  646. *opened_filename = filename;
  647. if (create_callback)
  648. {
  649. /* Create the file if we can. */
  650. (*create_callback) (filename);
  651. /* And try opening it again. */
  652. f = fopen (*opened_filename, FOPEN_RBIN);
  653. if (!f)
  654. return 0;
  655. }
  656. else
  657. return 0;
  658. }
  659. /* Read first few bytes of file rather than relying on the filename.
  660. If the file is shorter than this it can't be usable anyway. */
  661. nread = fread (data, sizeof (data), 1, f);
  662. if (nread != 1)
  663. {
  664. if (nread == 0)
  665. {
  666. /* Try to create the file if its empty. */
  667. if (feof (f) && create_callback)
  668. {
  669. if (fclose (f) != 0)
  670. return 0; /* unknown error closing file */
  671. if (remove (filename) != 0)
  672. return 0; /* unknown error deleting file */
  673. (*create_callback) (filename);
  674. f = fopen (*opened_filename, FOPEN_RBIN);
  675. if (!f)
  676. return 0;
  677. nread = fread (data, sizeof (data), 1, f);
  678. if (nread == 0)
  679. return 0;
  680. goto determine_file_type; /* success */
  681. }
  682. }
  683. errno = 0;
  684. return 0; /* unknown error */
  685. }
  686. determine_file_type:
  687. if (!compression_program)
  688. compression_program = &local_compression_program;
  689. if (data[0] == '\x1f' && data[1] == '\x8b')
  690. #if STRIP_DOT_EXE
  691. /* An explicit .exe yields a better diagnostics from popen below
  692. if they don't have gzip installed. */
  693. *compression_program = "gzip.exe";
  694. #else
  695. *compression_program = "gzip";
  696. #endif
  697. else if (data[0] == '\xFD' && data[1] == '7' && data[2] == 'z'
  698. && data[3] == 'X' && data[4] == 'Z' && data[5] == 0)
  699. #ifndef STRIP_DOT_EXE
  700. *compression_program = "xz.exe";
  701. #else
  702. *compression_program = "xz";
  703. #endif
  704. else if (data[0] == 'B' && data[1] == 'Z' && data[2] == 'h')
  705. #ifndef STRIP_DOT_EXE
  706. *compression_program = "bzip2.exe";
  707. #else
  708. *compression_program = "bzip2";
  709. #endif
  710. else if (data[0] == 'B' && data[1] == 'Z' && data[2] == '0')
  711. #ifndef STRIP_DOT_EXE
  712. *compression_program = "bzip.exe";
  713. #else
  714. *compression_program = "bzip";
  715. #endif
  716. else if (data[0] == 0x4C && data[1] == 0x5A && data[2] == 0x49
  717. && data[3] == 0x50 && data[4] == 1) /* "LZIP" */
  718. #ifndef STRIP_DOT_EXE
  719. *compression_program = "lzip.exe";
  720. #else
  721. *compression_program = "lzip";
  722. #endif
  723. /* We (try to) match against old lzma format (which lacks proper
  724. header, two first matches), as well as the new format (last match). */
  725. else if ((data[9] == 0x00 && data[10] == 0x00 && data[11] == 0x00
  726. && data[12] == 0x00)
  727. || (data[5] == '\xFF' && data[6] == '\xFF' && data[7] == '\xFF'
  728. && data[8] == '\xFF' && data[9] == '\xFF' && data[10] == '\xFF'
  729. && data[11] == '\xFF' && data[12] == '\xFF')
  730. || (data[0] == '\xFF' && data[1] == 'L' && data[2] == 'Z'
  731. && data[3] == 'M' && data[4] == 'A' && data[5] == 0x00))
  732. #ifndef STRIP_DOT_EXE
  733. *compression_program = "lzma.exe";
  734. #else
  735. *compression_program = "lzma";
  736. #endif
  737. else
  738. *compression_program = NULL;
  739. /* Seek back over the magic bytes. */
  740. if (fseek (f, 0, 0) < 0)
  741. return 0;
  742. if (*compression_program)
  743. { /* It's compressed, so open a pipe. */
  744. char *command = concat (*compression_program, " -d", "");
  745. if (fclose (f) < 0)
  746. return 0;
  747. f = freopen (*opened_filename, FOPEN_RBIN, stdin);
  748. if (!f)
  749. return 0;
  750. f = popen (command, "r");
  751. if (!f)
  752. {
  753. /* Used for error message in calling code. */
  754. *opened_filename = command;
  755. return 0;
  756. }
  757. }
  758. else
  759. {
  760. #if O_BINARY
  761. /* Since this is a text file, and we opened it in binary mode,
  762. switch back to text mode. */
  763. f = freopen (*opened_filename, "r", f);
  764. if (! f)
  765. return 0;
  766. #endif
  767. }
  768. return f;
  769. }
  770. /* Read all of file FILENAME into memory and return the address of the
  771. data. Store the size of the data into SIZEP. If need be, uncompress
  772. (i.e., try FILENAME.gz et al. if FILENAME does not exist) and store
  773. the actual file name that was opened into OPENED_FILENAME (if it is
  774. non-NULL), and the companion compression program (if any, else NULL)
  775. into COMPRESSION_PROGRAM (if that is non-NULL). If trouble, return
  776. a null pointer. */
  777. char *
  778. readfile (char *filename, int *sizep,
  779. void (*create_callback) (char *), char **opened_filename,
  780. char **compression_program)
  781. {
  782. FILE *f;
  783. int filled = 0;
  784. int data_size = 8192;
  785. char *data = xmalloc (data_size);
  786. /* If they passed the space for the file name to return, use it. */
  787. f = open_possibly_compressed_file (filename, create_callback,
  788. opened_filename,
  789. compression_program);
  790. if (!f)
  791. return 0;
  792. for (;;)
  793. {
  794. int nread = fread (data + filled, 1, data_size - filled, f);
  795. if (nread < 0)
  796. return 0;
  797. if (nread == 0)
  798. break;
  799. filled += nread;
  800. if (filled == data_size)
  801. {
  802. data_size += 65536;
  803. data = xrealloc (data, data_size);
  804. }
  805. }
  806. /* We'll end up wasting space if we're not passing the filename back
  807. and it is not just FILENAME, but so what. */
  808. /* We need to close the stream, since on some systems the pipe created
  809. by popen is simulated by a temporary file which only gets removed
  810. inside pclose. */
  811. if (f != stdin)
  812. pclose (f);
  813. *sizep = filled;
  814. return data;
  815. }
  816. /* Output the old dir file, interpolating the new sections
  817. and/or new entries where appropriate. If COMPRESSION_PROGRAM is not
  818. null, pipe to it to create DIRFILE. Thus if we read dir.gz on input,
  819. we'll write dir.gz on output. */
  820. static void
  821. output_dirfile (char *dirfile, int dir_nlines, struct line_data *dir_lines,
  822. int n_entries_to_add, struct spec_entry *entries_to_add,
  823. struct spec_section *input_sections, char *compression_program)
  824. {
  825. int n_entries_added = 0;
  826. int i;
  827. FILE *output;
  828. if (compression_program)
  829. {
  830. char *command = concat (compression_program, ">", dirfile);
  831. output = popen (command, "w");
  832. }
  833. else
  834. output = fopen (dirfile, "w");
  835. if (!output)
  836. {
  837. perror (dirfile);
  838. exit (EXIT_FAILURE);
  839. }
  840. for (i = 0; i <= dir_nlines; i++)
  841. {
  842. int j;
  843. /* If we decided to output some new entries before this line,
  844. output them now. */
  845. if (dir_lines[i].add_entries_before)
  846. for (j = 0; j < n_entries_to_add; j++)
  847. {
  848. struct spec_entry *this = dir_lines[i].add_entries_before[j];
  849. if (this == 0)
  850. break;
  851. if (n_entries_added >= 1 &&
  852. !add_entries_into_all_matching_sections)
  853. break;
  854. fputs (this->text, output);
  855. n_entries_added++;
  856. }
  857. /* If we decided to add some sections here
  858. because there are no such sections in the file,
  859. output them now.
  860. FIXME: we add all sections here, but they should
  861. be interspersed throughout the DIR file in
  862. alphabetic order. */
  863. if (dir_lines[i].add_sections_before)
  864. {
  865. struct spec_section *spec;
  866. struct spec_entry *entry;
  867. struct spec_entry **entries;
  868. int n_entries = 0;
  869. /* If we specified --add-once, and we've added an entry, then
  870. it's time to bail. */
  871. if (n_entries_added >= 1 &&
  872. !add_entries_into_all_matching_sections)
  873. break;
  874. qsort (dir_lines[i].add_sections_before,
  875. dir_lines[i].num_sections_to_add,
  876. sizeof (struct spec_section *), compare_section_names);
  877. /* Count the entries and allocate a vector for all of them. */
  878. for (entry = entries_to_add; entry; entry = entry->next)
  879. n_entries++;
  880. entries = ((struct spec_entry **)
  881. xmalloc (n_entries * sizeof (struct spec_entry *)));
  882. /* Fill the vector ENTRIES with pointers to all the sections,
  883. and sort them. */
  884. j = 0;
  885. for (entry = entries_to_add; entry; entry = entry->next)
  886. entries[j++] = entry;
  887. qsort (entries, n_entries, sizeof (struct spec_entry *),
  888. compare_entries_text);
  889. /* Generate the new sections in alphabetical order. In each
  890. new section, output all of the entries that belong to that
  891. section, in alphabetical order. */
  892. for (j = 0; j < dir_lines[i].num_sections_to_add; j++)
  893. {
  894. spec = dir_lines[i].add_sections_before[j];
  895. if (spec->missing)
  896. {
  897. int k;
  898. putc ('\n', output);
  899. fputs (spec->name, output);
  900. putc ('\n', output);
  901. spec->missing = 0;
  902. for (k = 0; k < n_entries; k++)
  903. {
  904. struct spec_section *spec1;
  905. /* Did they at all want this entry to be put into
  906. this section? */
  907. entry = entries[k];
  908. for (spec1 = entry->entry_sections;
  909. spec1 && spec1 != entry->entry_sections_tail;
  910. spec1 = spec1->next)
  911. {
  912. if (!strcmp (spec1->name, spec->name))
  913. break;
  914. }
  915. if (spec1 && spec1 != entry->entry_sections_tail)
  916. fputs (entry->text, output);
  917. }
  918. }
  919. }
  920. n_entries_added++;
  921. free (entries);
  922. }
  923. /* Output the original dir lines unless marked for deletion. */
  924. if (i < dir_nlines && !dir_lines[i].delete)
  925. {
  926. fwrite (dir_lines[i].start, 1, dir_lines[i].size, output);
  927. putc ('\n', output);
  928. }
  929. }
  930. /* Some systems, such as MS-DOS, simulate pipes with temporary files.
  931. On those systems, the compressor actually gets run inside pclose,
  932. so we must call pclose. */
  933. if (compression_program)
  934. pclose (output);
  935. else
  936. fclose (output);
  937. }
  938. /* Read through the input LINES, to find the section names and the
  939. entry names it specifies. Each INFO-DIR-SECTION entry is added
  940. to the SECTIONS linked list. Each START-INFO-DIR-ENTRY block is added to
  941. the ENTRIES linked list, and the last group of INFO-DIR-SECTION entries
  942. is recorded in next->entry_sections and next->entry_sections_tail, where
  943. next is the new entry. Return the number of entries to add from this
  944. file. */
  945. int
  946. parse_input (const struct line_data *lines, int nlines,
  947. struct spec_section **sections, struct spec_entry **entries,
  948. int delete_flag)
  949. {
  950. int n_entries = 0;
  951. int prefix_length = strlen ("INFO-DIR-SECTION ");
  952. struct spec_section *head = *sections, *tail = NULL;
  953. int reset_tail = 0;
  954. char *start_of_this_entry = 0;
  955. int ignore_sections = *sections != 0;
  956. int ignore_entries = delete_flag ? 0: *entries != 0;
  957. int i;
  958. if (ignore_sections && ignore_entries)
  959. return 0;
  960. for (i = 0; i < nlines; i++)
  961. {
  962. if (!ignore_sections
  963. && !strncmp ("INFO-DIR-SECTION ", lines[i].start, prefix_length))
  964. {
  965. struct spec_section *next
  966. = (struct spec_section *) xmalloc (sizeof (struct spec_section));
  967. next->name = copy_string (lines[i].start + prefix_length,
  968. lines[i].size - prefix_length);
  969. next->next = *sections;
  970. next->missing = 1;
  971. if (reset_tail)
  972. {
  973. tail = *sections;
  974. reset_tail = 0;
  975. }
  976. *sections = next;
  977. head = *sections;
  978. }
  979. /* If entries were specified explicitly with command options,
  980. ignore the entries in the input file. */
  981. else if (!ignore_entries)
  982. {
  983. if (!strncmp ("START-INFO-DIR-ENTRY", lines[i].start, lines[i].size)
  984. && sizeof ("START-INFO-DIR-ENTRY") - 1 == lines[i].size)
  985. {
  986. if (!*sections)
  987. {
  988. /* We found an entry, but didn't yet see any sections
  989. specified. Default to section "Miscellaneous". */
  990. *sections = (struct spec_section *)
  991. xmalloc (sizeof (struct spec_section));
  992. (*sections)->name = "Miscellaneous";
  993. (*sections)->next = 0;
  994. (*sections)->missing = 1;
  995. head = *sections;
  996. }
  997. /* Next time we see INFO-DIR-SECTION, we will reset the
  998. tail pointer. */
  999. reset_tail = 1;
  1000. /* Save start of the entry. If this is non-zero, we're
  1001. already inside an entry, so fail. */
  1002. if (start_of_this_entry != 0)
  1003. fatal (_("START-INFO-DIR-ENTRY without matching END-INFO-DIR-ENTRY"));
  1004. start_of_this_entry = lines[i + 1].start;
  1005. }
  1006. else if (start_of_this_entry)
  1007. {
  1008. if ((!strncmp ("* ", lines[i].start, 2)
  1009. && lines[i].start > start_of_this_entry)
  1010. || (!strncmp ("END-INFO-DIR-ENTRY",
  1011. lines[i].start, lines[i].size)
  1012. && sizeof ("END-INFO-DIR-ENTRY") - 1 == lines[i].size))
  1013. {
  1014. /* We found the end of this entry. Save its contents
  1015. in a new entry in the linked list. */
  1016. struct spec_entry *next
  1017. = (struct spec_entry *) xmalloc (sizeof (struct spec_entry));
  1018. next->text
  1019. = copy_string (start_of_this_entry,
  1020. lines[i].start - start_of_this_entry);
  1021. next->text_len = lines[i].start - start_of_this_entry;
  1022. next->entry_sections = head;
  1023. next->entry_sections_tail = tail;
  1024. next->missing_basename = 0;
  1025. next->next = *entries;
  1026. *entries = next;
  1027. n_entries++;
  1028. if (!strncmp ("END-INFO-DIR-ENTRY",
  1029. lines[i].start, lines[i].size)
  1030. && sizeof ("END-INFO-DIR-ENTRY") - 1 == lines[i].size)
  1031. start_of_this_entry = 0;
  1032. else
  1033. start_of_this_entry = lines[i].start;
  1034. }
  1035. else if (!strncmp ("END-INFO-DIR-ENTRY",
  1036. lines[i].start, lines[i].size)
  1037. && sizeof ("END-INFO-DIR-ENTRY") - 1 == lines[i].size)
  1038. fatal (_("END-INFO-DIR-ENTRY without matching START-INFO-DIR-ENTRY"));
  1039. }
  1040. }
  1041. }
  1042. if (start_of_this_entry != 0)
  1043. fatal (_("START-INFO-DIR-ENTRY without matching END-INFO-DIR-ENTRY"));
  1044. /* If we ignored the INFO-DIR-ENTRY directives, we need now go back
  1045. and plug the names of all the sections we found into every
  1046. element of the ENTRIES list. */
  1047. if (ignore_entries && *entries)
  1048. {
  1049. struct spec_entry *entry;
  1050. for (entry = *entries; entry; entry = entry->next)
  1051. {
  1052. entry->entry_sections = head;
  1053. entry->entry_sections_tail = tail;
  1054. }
  1055. }
  1056. return n_entries;
  1057. }
  1058. /* Parse the dir file whose basename is BASE_NAME. Find all the
  1059. nodes, and their menus, and the sections of their menus. */
  1060. static void
  1061. parse_dir_file (struct line_data *lines, int nlines, struct node **nodes)
  1062. {
  1063. int node_header_flag = 0;
  1064. int i;
  1065. *nodes = 0;
  1066. for (i = 0; i < nlines; i++)
  1067. {
  1068. /* Parse node header lines. */
  1069. if (node_header_flag)
  1070. {
  1071. int j, end;
  1072. for (j = 0; j < lines[i].size; j++)
  1073. /* Find the node name and store it in the `struct node'. */
  1074. if (!strncmp ("Node:", lines[i].start + j, 5))
  1075. {
  1076. char *line = lines[i].start;
  1077. /* Find the start of the node name. */
  1078. j += 5;
  1079. while (line[j] == ' ' || line[j] == '\t')
  1080. j++;
  1081. /* Find the end of the node name. */
  1082. end = j;
  1083. while (line[end] != 0 && line[end] != ',' && line[end] != '\n'
  1084. && line[end] != '\t')
  1085. end++;
  1086. (*nodes)->name = copy_string (line + j, end - j);
  1087. }
  1088. node_header_flag = 0;
  1089. }
  1090. /* Notice the start of a node. */
  1091. if (*lines[i].start == 037)
  1092. {
  1093. struct node *next = (struct node *) xmalloc (sizeof (struct node));
  1094. next->next = *nodes;
  1095. next->name = NULL;
  1096. next->start_line = i;
  1097. next->end_line = 0;
  1098. next->menu_start = NULL;
  1099. next->sections = NULL;
  1100. next->last_section = NULL;
  1101. if (*nodes != 0)
  1102. (*nodes)->end_line = i;
  1103. /* Fill in the end of the last menu section
  1104. of the previous node. */
  1105. if (*nodes != 0 && (*nodes)->last_section != 0)
  1106. (*nodes)->last_section->end_line = i;
  1107. *nodes = next;
  1108. /* The following line is the header of this node;
  1109. parse it. */
  1110. node_header_flag = 1;
  1111. }
  1112. /* Notice the lines that start menus. */
  1113. if (*nodes != 0 && !strncmp ("* Menu:", lines[i].start, 7))
  1114. (*nodes)->menu_start = lines[i + 1].start;
  1115. /* Notice sections in menus. */
  1116. if (*nodes != 0
  1117. && (*nodes)->menu_start != 0
  1118. && *lines[i].start != '\n'
  1119. && *lines[i].start != '*'
  1120. && *lines[i].start != ' '
  1121. && *lines[i].start != '\t')
  1122. {
  1123. /* Add this menu section to the node's list.
  1124. This list grows in forward order. */
  1125. struct menu_section *next
  1126. = (struct menu_section *) xmalloc (sizeof (struct menu_section));
  1127. next->start_line = i + 1;
  1128. next->next = 0;
  1129. next->end_line = 0;
  1130. next->name = copy_string (lines[i].start, lines[i].size);
  1131. if ((*nodes)->sections)
  1132. {
  1133. (*nodes)->last_section->next = next;
  1134. (*nodes)->last_section->end_line = i;
  1135. }
  1136. else
  1137. (*nodes)->sections = next;
  1138. (*nodes)->last_section = next;
  1139. }
  1140. }
  1141. /* Finish the info about the end of the last node. */
  1142. if (*nodes != 0)
  1143. {
  1144. (*nodes)->end_line = nlines;
  1145. if ((*nodes)->last_section != 0)
  1146. (*nodes)->last_section->end_line = nlines;
  1147. }
  1148. }
  1149. /* Iterate through NLINES LINES looking for an entry that has a name
  1150. that matches NAME. If such an entry is found, flag the entry for
  1151. deletion later on. */
  1152. int
  1153. mark_entry_for_deletion (struct line_data *lines, int nlines, char *name)
  1154. {
  1155. int something_deleted = 0;
  1156. int i;
  1157. for (i = 0; i < nlines; i++)
  1158. {
  1159. /* Check for an existing entry that should be deleted.
  1160. Delete all entries which specify this file name. */
  1161. if (*lines[i].start == '*')
  1162. {
  1163. char *q;
  1164. char *p = lines[i].start;
  1165. p++; /* skip * */
  1166. while (*p == ' ') p++; /* ignore following spaces */
  1167. q = p; /* remember this, it's the beginning of the menu item. */
  1168. /* Read menu item. */
  1169. while (*p != 0 && *p != ':')
  1170. p++;
  1171. p++; /* skip : */
  1172. if (*p == ':')
  1173. { /* XEmacs-style entry, as in * Mew::Messaging. */
  1174. if (menu_item_equal (q, ':', name))
  1175. {
  1176. lines[i].delete = 1;
  1177. something_deleted = 1;
  1178. }
  1179. }
  1180. else
  1181. { /* Emacs-style entry, as in * Emacs: (emacs). */
  1182. while (*p == ' ') p++; /* skip spaces after : */
  1183. if (*p == '(') /* if at parenthesized (FILENAME) */
  1184. {
  1185. p++;
  1186. if (menu_item_equal (p, ')', name))
  1187. {
  1188. lines[i].delete = 1;
  1189. something_deleted = 1;
  1190. }
  1191. }
  1192. }
  1193. }
  1194. /* Treat lines that start with whitespace
  1195. as continuations; if we are deleting an entry,
  1196. delete all its continuations as well. */
  1197. else if (i > 0 && (*lines[i].start == ' ' || *lines[i].start == '\t'))
  1198. {
  1199. lines[i].delete = lines[i - 1].delete;
  1200. }
  1201. }
  1202. return something_deleted;
  1203. }
  1204. /* Assuming the current column is COLUMN, return the column that
  1205. printing C will move the cursor to.
  1206. The first column is 0.
  1207. This function is used to assist in indenting of entries. */
  1208. static size_t
  1209. adjust_column (size_t column, char c)
  1210. {
  1211. if (c == '\b')
  1212. {
  1213. if (column > 0)
  1214. column--;
  1215. }
  1216. else if (c == '\r')
  1217. column = 0;
  1218. else if (c == '\t')
  1219. column += TAB_WIDTH - column % TAB_WIDTH;
  1220. else /* if (isprint (c)) */
  1221. column++;
  1222. return column;
  1223. }
  1224. /* Format the Info entry's NAME and DESCRIPTION.
  1225. NAME is of the form "* TEXT (TEXT)[:TEXT].".
  1226. The description on the first line is indented at the CALIGN-th column, and
  1227. all subsequent lines are indented at the ALIGN-th column.
  1228. Lines are wrapped at the WIDTH column.
  1229. The resulting Info entry is put into OUTSTR.
  1230. */
  1231. static int
  1232. format_entry (char *name, size_t name_len, char *desc, size_t desc_len,
  1233. int calign, int align, size_t width,
  1234. char **outstr_out, size_t *outstr_len)
  1235. {
  1236. int i, j;
  1237. char c;
  1238. size_t column = 0; /* Screen column where next char will go */
  1239. /* Used to collect a line at a time, before transferring to outstr. */
  1240. static char *line_out = NULL;
  1241. size_t offset_out = 0; /* Index in `line_out' for next char. */
  1242. static size_t allocated_out = 0; /* Space allocated in `line_out'. */
  1243. char *outstr;
  1244. if (!desc || !name)
  1245. return 1;
  1246. outstr = xmalloc (width
  1247. + (desc_len + width) / (width - align) * width * 2 * sizeof (char));
  1248. outstr[0] = '\0';
  1249. strncat (outstr, name, name_len);
  1250. column = name_len;
  1251. if (name_len > calign - 2)
  1252. {
  1253. /* Name is too long to have description on the same line. */
  1254. if (desc_len > 1)
  1255. {
  1256. strncat (outstr, "\n", 1);
  1257. column = 0;
  1258. for (j = 0; j < calign - 1; j++)
  1259. {
  1260. column = adjust_column (column, ' ');
  1261. strncat (outstr, " ", 1);
  1262. }
  1263. }
  1264. }
  1265. else
  1266. for (j = 0; j < calign - name_len - 1; j++)
  1267. {
  1268. if (desc_len <= 2)
  1269. break;
  1270. column = adjust_column (column, ' ');
  1271. strncat (outstr, " ", 1);
  1272. }
  1273. for (i = 0; i < desc_len; i++)
  1274. {
  1275. if (desc_len <= 2)
  1276. break;
  1277. c = desc[i];
  1278. if (offset_out + 1 >= allocated_out)
  1279. {
  1280. allocated_out = offset_out + 1;
  1281. line_out = (char *) xrealloc ((void *)line_out, allocated_out + 1);
  1282. /* The + 1 here shouldn't be necessary, but a crash was reported
  1283. for a following strncat call. */
  1284. }
  1285. if (c == '\n')
  1286. {
  1287. line_out[offset_out++] = c;
  1288. strncat (outstr, line_out, offset_out);
  1289. column = offset_out = 0;
  1290. continue;
  1291. }
  1292. /* Come here from inside "column > width" block below. */
  1293. rescan:
  1294. column = adjust_column (column, c);
  1295. if (column > width)
  1296. {
  1297. /* This character would make the line too long.
  1298. Print the line plus a newline, and make this character
  1299. start the next line. */
  1300. int found_blank = 0;
  1301. size_t logical_end = offset_out;
  1302. /* Look for the last blank. */
  1303. while (logical_end)
  1304. {
  1305. --logical_end;
  1306. if (line_out[logical_end] == ' '
  1307. || line_out[logical_end] == '\t')
  1308. {
  1309. found_blank = 1;
  1310. break;
  1311. }
  1312. }
  1313. if (found_blank)
  1314. {
  1315. size_t i;
  1316. /* Found a blank. Don't output the part after it. */
  1317. logical_end++;
  1318. strncat (outstr, line_out, logical_end);
  1319. strncat (outstr, "\n", 1);
  1320. for (j = 0; j < align - 1; j++)
  1321. {
  1322. column = adjust_column (column, ' ');
  1323. strncat (outstr, " ", 1);
  1324. }
  1325. /* Move the remainder to the beginning of the next
  1326. line.
  1327. The areas being copied here might overlap. */
  1328. memmove (line_out, line_out + logical_end,
  1329. offset_out - logical_end);
  1330. offset_out -= logical_end;
  1331. for (column = i = 0; i < offset_out; i++)
  1332. column = adjust_column (column, line_out[i]);
  1333. goto rescan;
  1334. }
  1335. if (offset_out == 0)
  1336. {
  1337. line_out[offset_out++] = c;
  1338. continue;
  1339. }
  1340. line_out[offset_out++] = '\n';
  1341. strncat (outstr, line_out, offset_out);
  1342. column = offset_out = 0;
  1343. goto rescan;
  1344. }
  1345. line_out[offset_out++] = c;
  1346. }
  1347. if (desc_len <= 2)
  1348. strncat (outstr, "\n", 1);
  1349. if (offset_out)
  1350. strncat (outstr, line_out, offset_out);
  1351. *outstr_out = outstr;
  1352. *outstr_len = strlen (outstr);
  1353. return 1;
  1354. }
  1355. /* Extract the NAME and DESCRIPTION from ENTRY. NAME and DESCRIPTION must be
  1356. free'd.
  1357. */
  1358. static void
  1359. split_entry (const char *entry, char **name, size_t *name_len,
  1360. char **description, size_t *description_len)
  1361. {
  1362. char *endptr;
  1363. /* on the first line, the description starts after the first ". ";
  1364. that's a period and space -- our heuristic to handle item names like
  1365. "config.status", and node names like "config.status Invocation".
  1366. Also accept period-tab and period-newline. */
  1367. char *ptr = strchr (entry, '.');
  1368. while (ptr && ptr[1] != ' ' && ptr[1] != '\t' && ptr[1] != '\n') {
  1369. ptr = strchr (ptr + 1, '.');
  1370. }
  1371. /* Maybe there's no period, and no description */
  1372. if (!ptr)
  1373. {
  1374. size_t length = strlen (entry);
  1375. if (length == 0)
  1376. return;
  1377. *name = strdup (entry);
  1378. *name_len = length + 1;
  1379. return;
  1380. }
  1381. /* The name is everything up to and including the period. */
  1382. *name_len = (size_t) (ptr - entry + 1);
  1383. *name = xmalloc (*name_len + 1);
  1384. (*name)[0] = '\0';
  1385. strncat (*name, entry, *name_len);
  1386. ptr++;
  1387. *description = xmalloc (strlen (entry));
  1388. (*description)[0] = '\0';
  1389. while (ptr[0] != '\0')
  1390. {
  1391. /* Eat up the whitespace after the name, and at the start of a line. */
  1392. while (isspace(ptr[0]))
  1393. ptr++;
  1394. /* Okay, we're at the start of the description. */
  1395. if (ptr[0] == '\0')
  1396. continue;
  1397. /* See how far the description goes... */
  1398. endptr = strchr (ptr, '\n');
  1399. /* Either the description continues up to the next newline. */
  1400. if (endptr)
  1401. {
  1402. size_t length = (size_t) (endptr - ptr) / sizeof (char);
  1403. strncat (*description, ptr, length);
  1404. ptr = endptr;
  1405. /* First of all, we eat the newline here. But then what?
  1406. Sometimes the newline separates 2 sentences, so we
  1407. end up with the next word starting directly after the period,
  1408. instead of after the customary 2 spaces in english.
  1409. If the previous character was a `.', then we should add 2
  1410. spaces if there is anything on the next line.
  1411. if it's a comma, then we should put one space.
  1412. If it's neither, we just put a space.
  1413. If it's some other whitespace, we shouldn't do anything. */
  1414. ptr++;
  1415. if (length > 1 && strlen (ptr) > 0)
  1416. {
  1417. endptr--;
  1418. /* *ENDPTR is the 2nd last character */
  1419. if (*endptr == '.')
  1420. strncat (*description, " ", 2);
  1421. else if (!isspace (*endptr))
  1422. strncat (*description, " ", 1);
  1423. }
  1424. }
  1425. /* Or the description continues to the end of the string. */
  1426. else
  1427. {
  1428. /* Just show the rest when there's no newline. */
  1429. size_t length = strlen (ptr);
  1430. strncat (*description, ptr, length);
  1431. ptr += length;
  1432. }
  1433. }
  1434. /* Descriptions end in a new line. */
  1435. strncat (*description, "\n", 1);
  1436. *description_len = strlen (*description);
  1437. }
  1438. /* Indent all ENTRIES according to some formatting options.
  1439. CALIGN_CLI is the starting column for the first line of the description.
  1440. ALIGN_CLI is the starting column for all subsequent lines of the
  1441. description. MAXWIDTH_CLI is the number of columns in the line.
  1442. When CALIGN_CLI, ALIGN_CLI, or MAXWIDTH_CLI is -1, choose a sane default. */
  1443. static void
  1444. reformat_new_entries (struct spec_entry *entries, int calign_cli, int align_cli,
  1445. int maxwidth_cli)
  1446. {
  1447. struct spec_entry *entry;
  1448. for (entry = entries; entry; entry = entry->next)
  1449. {
  1450. int calign = -1, align = -1, maxwidth = -1;
  1451. char *name = NULL, *desc = NULL;
  1452. size_t name_len = 0, desc_len = 0;
  1453. split_entry (entry->text, &name, &name_len, &desc, &desc_len);
  1454. free (entry->text);
  1455. /* Specify sane defaults if we need to */
  1456. if (calign_cli == -1 || align_cli == -1)
  1457. {
  1458. struct spec_section *section;
  1459. calign = calign_cli;
  1460. align = align_cli;
  1461. for (section = entry->entry_sections;
  1462. section && section != entry->entry_sections_tail;
  1463. section = section->next)
  1464. {
  1465. if (!strcmp (section->name, "Individual utilities"))
  1466. {
  1467. if (calign == -1)
  1468. calign = 48 + 1;
  1469. if (align == -1)
  1470. align = 50 + 1;
  1471. break;
  1472. }
  1473. }
  1474. if (calign == -1)
  1475. calign = 32 + 1;
  1476. if (align == -1)
  1477. align = 34 + 1;
  1478. }
  1479. else
  1480. {
  1481. calign = calign_cli;
  1482. align = align_cli;
  1483. }
  1484. maxwidth = maxwidth_cli == -1 ? 79 : maxwidth_cli;
  1485. format_entry (name, name_len, desc, desc_len, calign, align,
  1486. maxwidth, &entry->text, &entry->text_len);
  1487. }
  1488. }
  1489. /* Insert NAME into every entry in ENTRIES that requires it.
  1490. NAME is the basename of the Info file being installed.
  1491. The idea here is that there was a --name on the command-line
  1492. and we need to put the basename in the empty parentheses. */
  1493. void
  1494. add_missing_basenames (struct spec_entry *entries, char *name)
  1495. {
  1496. struct spec_entry *entry;
  1497. for (entry = entries; entry; entry = entry->next)
  1498. {
  1499. if (entry->missing_basename)
  1500. {
  1501. /* Insert NAME into the right place in ENTRY->TEXT. */
  1502. char *info, *rest, *text;
  1503. size_t name_len = strlen (name);
  1504. char *ptr = strstr (entry->text, ": (). ");
  1505. if (!ptr)
  1506. return;
  1507. ptr[0] = '\0';
  1508. rest = ptr += strlen (": (). ");
  1509. info = xmalloc (name_len + 7);
  1510. snprintf (info, name_len + 7, ": (%s). ", name);
  1511. text = concat (entry->text, info, rest);
  1512. free (info);
  1513. if (entry->text)
  1514. free (entry->text);
  1515. entry->text = text;
  1516. entry->text_len = strlen (entry->text);
  1517. entry->missing_name = 0;
  1518. entry->missing_basename = 0;
  1519. }
  1520. }
  1521. }
  1522. /* Add NAME to the start of any entry in ENTRIES that is missing a name
  1523. component. If NAME doesn't start with `*', it is formatted to look
  1524. like an Info entry. */
  1525. void
  1526. add_missing_names (struct spec_entry *entries, char *name)
  1527. {
  1528. struct spec_entry *entry;
  1529. for (entry = entries; entry; entry = entry->next)
  1530. {
  1531. if (entry->missing_name)
  1532. {
  1533. char *text;
  1534. /* Prepend NAME onto ENTRY->TEXT. */
  1535. int add_nl = 1;
  1536. if (entry->text)
  1537. if (entry->text[entry->text_len - 1] == '\n')
  1538. add_nl = 0;
  1539. if (name[0] == '*')
  1540. text = concat (name, entry->text == NULL ? "" : entry->text,
  1541. add_nl ? "\n" : "");
  1542. else
  1543. {
  1544. size_t full_name_len = strlen (name) * 2 + 9;
  1545. char *full_name = xmalloc (full_name_len);
  1546. snprintf (full_name, full_name_len, "* %s: (%s).", name, name);
  1547. text = concat (full_name,
  1548. entry->text == NULL ? "" : entry->text,
  1549. add_nl ? "\n" : "");
  1550. free (full_name);
  1551. }
  1552. if (entry->text)
  1553. free (entry->text);
  1554. entry->text = text;
  1555. entry->text_len = strlen (entry->text);
  1556. entry->missing_name = 0;
  1557. entry->missing_basename = 0;
  1558. }
  1559. }
  1560. }
  1561. /* Append DESC to every entry in ENTRIES that needs it. */
  1562. void
  1563. add_missing_descriptions (struct spec_entry *entries, char *desc)
  1564. {
  1565. struct spec_entry *entry;
  1566. for (entry = entries; entry; entry = entry->next)
  1567. {
  1568. if (entry->missing_description)
  1569. {
  1570. char *text;
  1571. int add_nl = 1;
  1572. if (strlen (desc) > 1)
  1573. if (desc[strlen (desc) - 1] == '\n')
  1574. add_nl = 0;
  1575. /* Append DESC onto ENTRY->TEXT. */
  1576. text = concat (entry->text == NULL ? "" : entry->text, desc,
  1577. add_nl ? "\n" : "");
  1578. if (entry->text)
  1579. free (entry->text);
  1580. entry->text = text;
  1581. entry->text_len = strlen (entry->text);
  1582. }
  1583. }
  1584. }
  1585. /* Detect old-style Debian `--section REGEX TITLE' semantics in ARGV.
  1586. When detected the options are munged to look like:
  1587. `--regex REGEX --section TITLE --add-once'
  1588. Return 1 if munging took place, return 0 if not.
  1589. Otherwise return a negative number if something went wrong.
  1590. NEW_ARGC, and NEW_ARGV are filled with the newly munged options
  1591. when munging took place.
  1592. */
  1593. static int
  1594. munge_old_style_debian_options (int argc, char **argv,
  1595. int *new_argc, char ***new_argv)
  1596. {
  1597. char *opt = NULL;
  1598. int i, err;
  1599. char *argz = NULL;
  1600. size_t argz_len = 0;
  1601. const char *regex, *title;
  1602. int munge = 0;
  1603. /* Flip through the options to detect the old `--section REGEX TITLE'
  1604. syntax */
  1605. for (i = 0; i < argc; i++)
  1606. {
  1607. if (strcmp (argv[i], "--section") == 0)
  1608. {
  1609. FILE *fileptr;
  1610. /* Go forward one arg and obtain the REGEX. */
  1611. if (i + 1 < argc)
  1612. i++;
  1613. else
  1614. return -1;
  1615. regex = argv[i];
  1616. /* Go forward another arg and obtain the TITLE. */
  1617. if (i + 1 < argc)
  1618. i++;
  1619. else
  1620. return -1;
  1621. title = argv[i];
  1622. /* When the title starts with a `-' it's probably an option,
  1623. and not a title. */
  1624. if (title[0] == '-')
  1625. break;
  1626. /* When the title is a filename it's probably an Info file, or
  1627. a dir file, and not a title. */
  1628. fileptr = fopen (title, "r");
  1629. if (fileptr)
  1630. {
  1631. fclose (fileptr);
  1632. break;
  1633. }
  1634. /* Okay, it looks like we're using the old debian syntax
  1635. for --section. */
  1636. munge = 1;
  1637. /* Okay, we munge the options to look like this:
  1638. --regex=REGEX --section=TITLE --add-once */
  1639. opt = xmalloc (strlen (regex) + sizeof ("--regex="));
  1640. if (sprintf (opt, "--regex=%s", regex) == -1)
  1641. err = 1;
  1642. if (!err)
  1643. err = argz_add (&argz, &argz_len, opt);
  1644. free (opt); opt = NULL;
  1645. opt = xmalloc (strlen (title) + sizeof ("--section="));
  1646. if (sprintf (opt, "--section=%s", title) == -1)
  1647. err = 1;
  1648. if (!err)
  1649. err = argz_add (&argz, &argz_len, opt);
  1650. free (opt); opt = NULL;
  1651. if (!err)
  1652. err = argz_add (&argz, &argz_len, "--add-once");
  1653. }
  1654. else
  1655. err = argz_add (&argz, &argz_len, argv[i]);
  1656. if (err)
  1657. return -1;
  1658. }
  1659. if (munge)
  1660. {
  1661. *new_argc = argz_count (argz, argz_len);
  1662. *new_argv = xmalloc ((*new_argc + 1) * sizeof (char *));
  1663. opt = NULL; i = 0;
  1664. while ((opt = argz_next (argz, argz_len, opt)))
  1665. {
  1666. (*new_argv)[i] = xstrdup (opt);
  1667. i++;
  1668. }
  1669. (*new_argv)[*new_argc] = NULL;
  1670. }
  1671. free (argz);
  1672. return munge;
  1673. }
  1674. int
  1675. main (int argc, char *argv[])
  1676. {
  1677. char *opened_dirfilename;
  1678. char *compression_program;
  1679. char *infile_sans_info;
  1680. char *infile = 0, *dirfile = 0;
  1681. int calign = -1;
  1682. int align = -1;
  1683. int maxwidth = -1;
  1684. /* Record the text of the Info file, as a sequence of characters
  1685. and as a sequence of lines. */
  1686. char *input_data = NULL;
  1687. int input_size = 0;
  1688. struct line_data *input_lines = NULL;
  1689. int input_nlines = 0;
  1690. /* Record here the specified section names and directory entries. */
  1691. struct spec_section *input_sections = NULL;
  1692. struct spec_entry *entries_to_add = NULL;
  1693. struct spec_entry *entries_to_add_from_file = NULL;
  1694. int n_entries_to_add = 0;
  1695. struct spec_entry *default_entries_to_add = NULL;
  1696. int n_default_entries_to_add = 0;
  1697. /* Record the old text of the dir file, as plain characters,
  1698. as lines, and as nodes. */
  1699. char *dir_data;
  1700. int dir_size;
  1701. int dir_nlines;
  1702. struct line_data *dir_lines;
  1703. struct node *dir_nodes;
  1704. /* Nonzero means --delete was specified (just delete existing entries). */
  1705. int delete_flag = 0;
  1706. int something_deleted = 0;
  1707. /* Nonzero means -quiet/--silent was specified. */
  1708. int quiet_flag = 0;
  1709. /* Nonzero means --debug was specified. */
  1710. int debug_flag = 0;
  1711. int i;
  1712. #ifdef HAVE_SETLOCALE
  1713. /* Set locale via LC_ALL. */
  1714. setlocale (LC_ALL, "");
  1715. #endif
  1716. /* Set the text message domain. */
  1717. bindtextdomain (PACKAGE, LOCALEDIR);
  1718. textdomain (PACKAGE);
  1719. /* Make sure standard input can be freopened at will. Otherwise,
  1720. when stdin starts off closed, bad things could happen if a plain fopen
  1721. returns stdin before open_possibly_compressed_file freopens it. */
  1722. if (! freopen (NULL_DEVICE, "r", stdin))
  1723. pfatal_with_name (NULL_DEVICE);
  1724. munge_old_style_debian_options (argc, argv, &argc, &argv);
  1725. while (1)
  1726. {
  1727. int opt = getopt_long (argc, argv,
  1728. "i:d:e:s:t:E:c:C:W:A:hHrk1Ia", longopts, 0);
  1729. if (opt == EOF)
  1730. break;
  1731. switch (opt)
  1732. {
  1733. case 0:
  1734. /* If getopt returns 0, then it has already processed a
  1735. long-named option. We should do nothing. */
  1736. break;
  1737. case 1:
  1738. abort ();
  1739. case '1':
  1740. add_entries_into_all_matching_sections = 0;
  1741. break;
  1742. case 'a':
  1743. order_new_sections_alphabetically_flag = 0;
  1744. break;
  1745. case 'A':
  1746. {
  1747. char *end = NULL;
  1748. unsigned long int val;
  1749. val = strtoul (optarg, &end, 0);
  1750. if (end == NULL || end == optarg || *end != '\0')
  1751. suggest_asking_for_help ();
  1752. align = val;
  1753. if (align <= 0)
  1754. suggest_asking_for_help ();
  1755. }
  1756. break;
  1757. case 'c':
  1758. {
  1759. struct spec_entry *next;
  1760. size_t length = strlen (optarg);
  1761. if (!entries_to_add)
  1762. {
  1763. next =
  1764. (struct spec_entry *) xmalloc (sizeof (struct spec_entry));
  1765. next->text = NULL;
  1766. next->text_len = 0;
  1767. next->entry_sections = NULL;
  1768. next->entry_sections_tail = NULL;
  1769. next->missing_name = 1;
  1770. next->missing_basename = 1;
  1771. next->next = entries_to_add;
  1772. entries_to_add = next;
  1773. n_entries_to_add++;
  1774. }
  1775. else
  1776. next = entries_to_add;
  1777. next->missing_description = 0;
  1778. if (next->text)
  1779. {
  1780. char *nl = strrchr (next->text, '\n');
  1781. if (nl)
  1782. nl[0] = '\0';
  1783. }
  1784. /* Concat the description onto the current entry, adding a
  1785. newline if we need one. Prepend a space if we have no
  1786. previous text, since eventually we will be adding the
  1787. "* foo ()." and we want to end up with a ". " for parsing. */
  1788. next->text = concat (next->text ? next->text : " ",
  1789. optarg,
  1790. optarg[length - 1] == '\n' ? "" : "\n");
  1791. next->text_len = strlen (next->text);
  1792. }
  1793. break;
  1794. case 'C':
  1795. {
  1796. char *end = NULL;
  1797. unsigned long int val;
  1798. val = strtoul (optarg, &end, 0);
  1799. if (end == NULL || end == optarg || *end != '\0')
  1800. suggest_asking_for_help ();
  1801. calign = val;
  1802. if (calign <= 0)
  1803. suggest_asking_for_help ();
  1804. }
  1805. break;
  1806. case 'd':
  1807. if (dirfile)
  1808. {
  1809. fprintf (stderr, _("%s: already have dir file: %s\n"),
  1810. progname, dirfile);
  1811. suggest_asking_for_help ();
  1812. }
  1813. dirfile = optarg;
  1814. break;
  1815. case 'D':
  1816. if (dirfile)
  1817. {
  1818. fprintf (stderr, _("%s: already have dir file: %s\n"),
  1819. progname, dirfile);
  1820. suggest_asking_for_help ();
  1821. }
  1822. dirfile = concat (optarg, "", "/dir");
  1823. break;
  1824. case 't':
  1825. {
  1826. struct spec_entry *next
  1827. = (struct spec_entry *) xmalloc (sizeof (struct spec_entry));
  1828. size_t length;
  1829. if (optarg[0] != '*')
  1830. {
  1831. /* Make enough space for "* foo: (). ". */
  1832. length = strlen (optarg) + 9;
  1833. next->text = xmalloc (length);
  1834. snprintf (next->text, length, "* %s: (). ", optarg);
  1835. next->missing_basename = 1;
  1836. /* The basename will be inserted in between the parentheses
  1837. at a later time. See add_missing_basenames. */
  1838. }
  1839. else
  1840. {
  1841. /* Make enough space for "foo ". */
  1842. length = strlen (optarg) + 2;
  1843. next->text = xmalloc (length);
  1844. snprintf (next->text, length, "%s ", optarg);
  1845. next->missing_basename = 0;
  1846. /* FIXME: check for info entry correctness in TEXT.
  1847. e.g. `* Aaa: (bbb).' */
  1848. }
  1849. next->text_len = length - 1;
  1850. next->entry_sections = NULL;
  1851. next->entry_sections_tail = NULL;
  1852. next->next = entries_to_add;
  1853. next->missing_name = 0;
  1854. next->missing_description = 1;
  1855. entries_to_add = next;
  1856. n_entries_to_add++;
  1857. }
  1858. break;
  1859. case 'E':
  1860. case 'e':
  1861. {
  1862. struct spec_entry *next
  1863. = (struct spec_entry *) xmalloc (sizeof (struct spec_entry));
  1864. int olen = strlen (optarg);
  1865. if (! (*optarg != 0 && optarg[olen - 1] == '\n'))
  1866. {
  1867. optarg = concat (optarg, "\n", "");
  1868. olen++;
  1869. }
  1870. next->text = optarg;
  1871. next->text_len = olen;
  1872. next->entry_sections = NULL;
  1873. next->entry_sections_tail = NULL;
  1874. next->missing_name = 0;
  1875. next->missing_basename = 0;
  1876. next->missing_description = 0;
  1877. if (opt == 'e')
  1878. {
  1879. next->next = entries_to_add;
  1880. entries_to_add = next;
  1881. n_entries_to_add++;
  1882. }
  1883. else
  1884. {
  1885. /* Although this list is maintained, nothing is ever
  1886. done with it. So it seems no one cares about the
  1887. feature. The intended --help string was:
  1888. --defentry=TEXT like --entry, but only use TEXT if an entry\n\
  1889. is not present in INFO-FILE.\n\
  1890. in case anyone ever wants to finish it. */
  1891. next->next = default_entries_to_add;
  1892. default_entries_to_add = next;
  1893. n_default_entries_to_add++;
  1894. }
  1895. }
  1896. break;
  1897. case 'g':
  1898. debug_flag = 1;
  1899. break;
  1900. case 'h':
  1901. case 'H':
  1902. print_help ();
  1903. exit (EXIT_SUCCESS);
  1904. case 'i':
  1905. if (infile)
  1906. {
  1907. fprintf (stderr, _("%s: Specify the Info file only once.\n"),
  1908. progname);
  1909. suggest_asking_for_help ();
  1910. }
  1911. infile = optarg;
  1912. break;
  1913. case 'I':
  1914. indent_flag = 0;
  1915. break;
  1916. case 'k':
  1917. keep_old_flag = 1;
  1918. break;
  1919. case 'n':
  1920. chicken_flag = 1;
  1921. break;
  1922. case 'q':
  1923. quiet_flag = 1;
  1924. break;
  1925. case 'r':
  1926. delete_flag = 1;
  1927. break;
  1928. case 'R':
  1929. {
  1930. int error;
  1931. if (psecreg)
  1932. {
  1933. warning
  1934. (_("Extra regular expression specified, ignoring `%s'"),
  1935. optarg);
  1936. break;
  1937. }
  1938. psecreg = (regex_t *) xmalloc (sizeof (regex_t));
  1939. error = regcomp (psecreg, optarg, REG_ICASE|REG_NOSUB);
  1940. if (error != 0)
  1941. {
  1942. int errbuf_size = regerror (error, psecreg, NULL, 0);
  1943. char *errbuf = (char *) xmalloc (errbuf_size);
  1944. regerror (error, psecreg, errbuf, errbuf_size);
  1945. fatal (_("Error in regular expression `%s': %s"),
  1946. optarg, errbuf);
  1947. };
  1948. }
  1949. break;
  1950. case 'S':
  1951. default_section = optarg;
  1952. break;
  1953. case 's':
  1954. {
  1955. struct spec_section *next
  1956. = (struct spec_section *) xmalloc (sizeof (struct spec_section));
  1957. next->name = optarg;
  1958. next->next = input_sections;
  1959. next->missing = 1;
  1960. input_sections = next;
  1961. }
  1962. break;
  1963. case 'V':
  1964. printf ("install-info (GNU %s) %s\n", PACKAGE, VERSION);
  1965. puts ("");
  1966. printf (_("Copyright (C) %s Free Software Foundation, Inc.\n\
  1967. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n\
  1968. This is free software: you are free to change and redistribute it.\n\
  1969. There is NO WARRANTY, to the extent permitted by law.\n"),
  1970. "2016");
  1971. exit (EXIT_SUCCESS);
  1972. case 'W':
  1973. {
  1974. char *end = NULL;
  1975. unsigned long int val;
  1976. val = strtoul (optarg, &end, 0);
  1977. if (end == NULL || end == optarg || *end != '\0')
  1978. suggest_asking_for_help ();
  1979. maxwidth = val;
  1980. if (maxwidth <= 0)
  1981. suggest_asking_for_help ();
  1982. }
  1983. break;
  1984. case 'x':
  1985. delete_flag = 1;
  1986. remove_exactly = 1;
  1987. break;
  1988. default:
  1989. suggest_asking_for_help ();
  1990. }
  1991. }
  1992. /* Interpret the non-option arguments as file names. */
  1993. for (; optind < argc; ++optind)
  1994. {
  1995. if (infile == 0)
  1996. infile = argv[optind];
  1997. else if (dirfile == 0)
  1998. dirfile = argv[optind];
  1999. else
  2000. error (_("excess command line argument `%s'"), argv[optind]);
  2001. }
  2002. if (!infile)
  2003. fatal (_("No input file specified; try --help for more information."));
  2004. if (!dirfile)
  2005. fatal (_("No dir file specified; try --help for more information."));
  2006. /* Now read in the Info dir file. */
  2007. if (debug_flag)
  2008. printf ("debug: reading dir file %s\n", dirfile);
  2009. if (!delete_flag)
  2010. {
  2011. dir_data = readfile (dirfile, &dir_size, ensure_dirfile_exists,
  2012. &opened_dirfilename, &compression_program);
  2013. if (!dir_data)
  2014. pfatal_with_name (opened_dirfilename);
  2015. }
  2016. else
  2017. {
  2018. /* For "--remove" operation, it is not an error for the dir file
  2019. not to exist. */
  2020. dir_data = readfile (dirfile, &dir_size, NULL,
  2021. &opened_dirfilename, &compression_program);
  2022. if (!dir_data)
  2023. {
  2024. warning (_("Could not read %s."), opened_dirfilename);
  2025. exit (EXIT_SUCCESS);
  2026. }
  2027. }
  2028. dir_lines = findlines (dir_data, dir_size, &dir_nlines);
  2029. parse_dir_file (dir_lines, dir_nlines, &dir_nodes);
  2030. if (!delete_flag)
  2031. {
  2032. /* Find which sections match our regular expression. */
  2033. if (psecreg)
  2034. {
  2035. struct node *node;
  2036. struct menu_section *section;
  2037. for (node = dir_nodes; node ; node = node->next)
  2038. for (section = node->sections; section ; section = section->next)
  2039. if (regexec (psecreg, section->name, 0, NULL, 0) == 0)
  2040. {
  2041. /* we have a match! */
  2042. struct spec_section *next =
  2043. (struct spec_section *) xmalloc
  2044. (sizeof (struct spec_section));
  2045. next->name = section->name;
  2046. next->next = input_sections;
  2047. next->missing = 0;
  2048. input_sections = next;
  2049. }
  2050. }
  2051. }
  2052. /* We will be comparing the entries in the dir file against the
  2053. current filename, so need to strip off any directory prefix and/or
  2054. [.info][.gz] suffix. */
  2055. if (!remove_exactly) {
  2056. char *infile_basename = infile + strlen (infile);
  2057. if (HAVE_DRIVE (infile))
  2058. infile += 2; /* get past the drive spec X: */
  2059. while (infile_basename > infile && !IS_SLASH (infile_basename[-1]))
  2060. infile_basename--;
  2061. infile_sans_info = strip_info_suffix (infile_basename);
  2062. } else
  2063. infile_sans_info = xstrdup(infile);
  2064. /* Now Read the Info file and parse it into lines, unless we're
  2065. removing exactly. */
  2066. if (!remove_exactly)
  2067. {
  2068. char *opened_infilename;
  2069. if (debug_flag)
  2070. printf ("debug: reading input file %s\n", infile);
  2071. input_data = readfile (infile, &input_size, NULL,
  2072. &opened_infilename, NULL);
  2073. if (!input_data)
  2074. pfatal_with_name (opened_infilename);
  2075. input_lines = findlines (input_data, input_size, &input_nlines);
  2076. }
  2077. i = parse_input (input_lines, input_nlines,
  2078. &input_sections, &entries_to_add_from_file, delete_flag);
  2079. if (!delete_flag)
  2080. {
  2081. /* If there are no entries on the command-line at all, use the entries
  2082. found in the Info file itself (if any). */
  2083. if (entries_to_add == NULL)
  2084. {
  2085. entries_to_add = entries_to_add_from_file;
  2086. n_entries_to_add = i;
  2087. }
  2088. /* There are entries on the command-line, and they override the entries
  2089. found in the Info file. */
  2090. else if (entries_to_add)
  2091. {
  2092. if (entries_to_add_from_file == NULL)
  2093. {
  2094. /* No entries found in the file anyway. Fill in any
  2095. missing names with the info file's basename. We're out
  2096. of luck for any missing descriptions. */
  2097. add_missing_names (entries_to_add, infile_sans_info);
  2098. /* add_missing_descriptions (entries_to_add, "\n"); */
  2099. }
  2100. else
  2101. {
  2102. /* Fill in any missing names or descriptions with what was
  2103. found in the Info file. */
  2104. char *desc = NULL;
  2105. size_t desc_len = 0;
  2106. char *name = NULL;
  2107. size_t name_len = 0;
  2108. split_entry (entries_to_add_from_file->text, &name, &name_len,
  2109. &desc, &desc_len);
  2110. if (name)
  2111. {
  2112. /* If the name doesn't look right, bail and use the
  2113. name based on the Info file. */
  2114. if (name[0] != '*')
  2115. add_missing_names (entries_to_add, infile_sans_info);
  2116. else
  2117. add_missing_names (entries_to_add, name);
  2118. free (name);
  2119. }
  2120. if (desc)
  2121. {
  2122. add_missing_descriptions (entries_to_add, desc);
  2123. free (desc);
  2124. }
  2125. }
  2126. }
  2127. /* Lastly, fill in any missing basenames that might still be hanging
  2128. around from --name options on the command-line. */
  2129. add_missing_basenames (entries_to_add, infile_sans_info);
  2130. /* Reformat the new entries if we're doing that. */
  2131. if (indent_flag)
  2132. {
  2133. char *no_indent = getenv ("INSTALL_INFO_NO_INDENT");
  2134. if (!no_indent)
  2135. reformat_new_entries (entries_to_add, calign, align, maxwidth);
  2136. }
  2137. /* If we got no sections, use the --defsection value if it was
  2138. given, else "Miscellaneous". */
  2139. if (input_sections == NULL)
  2140. {
  2141. input_sections = (struct spec_section *)
  2142. xmalloc (sizeof (struct spec_section));
  2143. input_sections->name = default_section ? default_section
  2144. : "Miscellaneous";
  2145. input_sections->next = NULL;
  2146. input_sections->missing = 1;
  2147. }
  2148. if (entries_to_add == 0)
  2149. { /* No need to abort here, the original info file may not
  2150. have the requisite Texinfo commands. This is not
  2151. something an installer should have to correct (it's a
  2152. problem for the maintainer), and there's no need to cause
  2153. subsequent parts of `make install' to fail. */
  2154. if (!quiet_flag)
  2155. warning (_("no info dir entry in `%s'"), infile);
  2156. exit (EXIT_SUCCESS);
  2157. }
  2158. /* If the entries came from the command-line arguments, their
  2159. entry_sections pointers are not yet set. Walk the chain of
  2160. the entries and for each entry update entry_sections to point
  2161. to the head of the list of sections where this entry should
  2162. be put. Note that all the entries specified on the command
  2163. line get put into ALL the sections we've got, either from the
  2164. Info file, or (under --section) from the command line,
  2165. because in the loop below every entry inherits the entire
  2166. chain of sections. */
  2167. if (n_entries_to_add > 0 && entries_to_add->entry_sections == NULL)
  2168. {
  2169. struct spec_entry *ep;
  2170. for (ep = entries_to_add; ep; ep = ep->next)
  2171. ep->entry_sections = input_sections;
  2172. }
  2173. }
  2174. if (delete_flag)
  2175. {
  2176. something_deleted = mark_entry_for_deletion (dir_lines, dir_nlines,
  2177. infile_sans_info);
  2178. if (!something_deleted && !remove_exactly)
  2179. {
  2180. struct spec_entry *entry;
  2181. for (entry = entries_to_add; entry; entry = entry->next)
  2182. {
  2183. /* If the entry came from the info file... */
  2184. if (entry->entry_sections != NULL)
  2185. {
  2186. char *name = extract_menu_item_name (entry->text);
  2187. something_deleted =
  2188. mark_entry_for_deletion (dir_lines, dir_nlines, name);
  2189. free (name);
  2190. }
  2191. }
  2192. if (!something_deleted)
  2193. {
  2194. struct spec_entry *entry;
  2195. for (entry = entries_to_add; entry; entry = entry->next)
  2196. {
  2197. /* If the entry came from the command-line... */
  2198. if (entry->entry_sections == NULL)
  2199. something_deleted =
  2200. mark_entry_for_deletion (dir_lines, dir_nlines,
  2201. entry->text);
  2202. }
  2203. }
  2204. }
  2205. }
  2206. /* Check for sections with zero entries and mark them for deletion. */
  2207. if (delete_flag && something_deleted && !keep_old_flag)
  2208. {
  2209. struct node *node;
  2210. struct menu_section *section;
  2211. int section_empty;
  2212. for (node = dir_nodes; node ; node = node->next)
  2213. for (section = node->sections; section ; section = section->next)
  2214. {
  2215. section_empty = 1;
  2216. for (i = section->end_line; i > section->start_line; i--)
  2217. {
  2218. if (dir_lines[i - 1].delete == 0 &&
  2219. dir_lines[i - 1].size != 0)
  2220. {
  2221. section_empty = 0;
  2222. break;
  2223. }
  2224. }
  2225. if (section_empty)
  2226. {
  2227. /* This gets rid of any trailing empty lines at the end
  2228. of the section, and the title too. */
  2229. for (i = section->end_line; i >= section->start_line; i--)
  2230. dir_lines[i - 1].delete = 1;
  2231. }
  2232. }
  2233. }
  2234. /* Decide where to add the new entries (unless --delete was used).
  2235. Find the menu sections to add them in.
  2236. In each section, find the proper alphabetical place to add
  2237. each of the entries. */
  2238. if (!delete_flag)
  2239. {
  2240. struct node *node;
  2241. struct menu_section *section;
  2242. struct spec_section *spec;
  2243. for (node = dir_nodes; node; node = node->next)
  2244. for (section = node->sections; section; section = section->next)
  2245. {
  2246. for (i = section->end_line; i > section->start_line; i--)
  2247. if (dir_lines[i - 1].size != 0)
  2248. break;
  2249. section->end_line = i;
  2250. for (spec = input_sections; spec; spec = spec->next)
  2251. if (!strcmp (spec->name, section->name))
  2252. break;
  2253. if (spec)
  2254. {
  2255. int add_at_line = section->end_line;
  2256. struct spec_entry *entry;
  2257. /* Say we have found at least one section with this name,
  2258. so we need not add such a section. */
  2259. spec->missing = 0;
  2260. /* For each entry, find the right place in this section
  2261. to add it. */
  2262. for (entry = entries_to_add; entry; entry = entry->next)
  2263. {
  2264. /* Did they at all want this entry to be put into
  2265. this section? */
  2266. for (spec = entry->entry_sections;
  2267. spec && spec != entry->entry_sections_tail;
  2268. spec = spec->next)
  2269. {
  2270. if (!strcmp (spec->name, section->name))
  2271. break;
  2272. }
  2273. if (!spec || spec == entry->entry_sections_tail)
  2274. continue;
  2275. /* Subtract one because dir_lines is zero-based,
  2276. but the `end_line' and `start_line' members are
  2277. one-based. */
  2278. for (i = section->end_line - 1;
  2279. i >= section->start_line - 1; i--)
  2280. {
  2281. /* If an entry exists with the same name,
  2282. and was not marked for deletion
  2283. (which means it is for some other file),
  2284. we are in trouble. */
  2285. if (dir_lines[i].start[0] == '*'
  2286. && menu_line_equal (entry->text, entry->text_len,
  2287. dir_lines[i].start,
  2288. dir_lines[i].size)
  2289. && !dir_lines[i].delete)
  2290. {
  2291. if (keep_old_flag)
  2292. {
  2293. add_at_line = -1;
  2294. break;
  2295. }
  2296. else
  2297. {
  2298. int j;
  2299. dir_lines[i].delete = 1;
  2300. for (j = i + 1; j < section->end_line; j++)
  2301. {
  2302. if (dir_lines[j].start[0] == '*')
  2303. break;
  2304. dir_lines[j].delete = 1;
  2305. }
  2306. }
  2307. }
  2308. if (dir_lines[i].start[0] == '*'
  2309. && menu_line_lessp (entry->text, entry->text_len,
  2310. dir_lines[i].start,
  2311. dir_lines[i].size))
  2312. add_at_line = i;
  2313. }
  2314. if (add_at_line < 0)
  2315. continue;
  2316. insert_entry_here (entry, add_at_line,
  2317. dir_lines, n_entries_to_add);
  2318. }
  2319. }
  2320. }
  2321. }
  2322. /* Decide where to add the new sections (unless --delete was used).
  2323. Alphabetically find the menu sections to add them before. */
  2324. if (!delete_flag)
  2325. {
  2326. struct node *node;
  2327. struct node *top = NULL;
  2328. /* Find the `Top' node. */
  2329. for (node = dir_nodes; node; node = node->next)
  2330. if (node->name && strcmp (node->name, "Top") == 0)
  2331. top = node;
  2332. if (top)
  2333. {
  2334. struct spec_section *spec;
  2335. int found = 0;
  2336. struct line_data *target_line = NULL;
  2337. for (spec = input_sections; spec; spec = spec->next)
  2338. {
  2339. found = 0;
  2340. target_line = NULL;
  2341. if (!spec->missing)
  2342. continue;
  2343. if (order_new_sections_alphabetically_flag)
  2344. {
  2345. struct menu_section *section;
  2346. struct menu_section *prev_section = NULL;
  2347. /* Look for the first section name that
  2348. exceeds SPEC->NAME. */
  2349. for (section = top->sections; section ;
  2350. section = section->next)
  2351. {
  2352. found = (mbscasecmp (spec->name, section->name) < 0);
  2353. if (found)
  2354. {
  2355. /* Mark the section for addition at this point. */
  2356. if (prev_section)
  2357. target_line = &dir_lines[prev_section->end_line];
  2358. else
  2359. target_line =
  2360. &dir_lines[top->sections->start_line - 2];
  2361. break;
  2362. }
  2363. prev_section = section;
  2364. }
  2365. }
  2366. /* When we can't put a section anywhere, we put it at the
  2367. bottom of the file. */
  2368. if (!found)
  2369. target_line = &dir_lines[top->end_line];
  2370. /* Add the section to our list of sections being added
  2371. at this point of the DIR file. */
  2372. target_line->num_sections_to_add++;
  2373. target_line->add_sections_before =
  2374. (struct spec_section **) xrealloc
  2375. (target_line->add_sections_before,
  2376. (target_line->num_sections_to_add *
  2377. sizeof (struct spec_section *)));
  2378. i = target_line->num_sections_to_add - 1;
  2379. target_line->add_sections_before[i] = spec;
  2380. }
  2381. }
  2382. }
  2383. if (delete_flag && !something_deleted && !quiet_flag)
  2384. warning (_("no entries found for `%s'; nothing deleted"), infile);
  2385. if (debug_flag)
  2386. printf ("debug: writing dir file %s\n", opened_dirfilename);
  2387. if (chicken_flag)
  2388. printf ("test mode, not updating dir file %s\n", opened_dirfilename);
  2389. else
  2390. output_dirfile (opened_dirfilename, dir_nlines, dir_lines,
  2391. n_entries_to_add, entries_to_add,
  2392. input_sections, compression_program);
  2393. exit (EXIT_SUCCESS);
  2394. }
  2395. /* Divide the text at DATA (of SIZE bytes) into lines.
  2396. Return a vector of struct line_data describing the lines.
  2397. Store the length of that vector into *NLINESP. */
  2398. struct line_data *
  2399. findlines (char *data, int size, int *nlinesp)
  2400. {
  2401. int i;
  2402. int lineflag = 1;
  2403. int lines_allocated = 511;
  2404. int filled = 0;
  2405. struct line_data *lines
  2406. = xmalloc ((lines_allocated + 1) * sizeof (struct line_data));
  2407. for (i = 0; i < size; i++)
  2408. {
  2409. if (lineflag)
  2410. {
  2411. if (filled == lines_allocated)
  2412. {
  2413. /* try to keep things somewhat page-aligned */
  2414. lines_allocated = ((lines_allocated + 1) * 2) - 1;
  2415. lines = xrealloc (lines, (lines_allocated + 1)
  2416. * sizeof (struct line_data));
  2417. }
  2418. lines[filled].start = &data[i];
  2419. lines[filled].add_entries_before = 0;
  2420. lines[filled].add_sections_before = NULL;
  2421. lines[filled].num_sections_to_add = 0;
  2422. lines[filled].delete = 0;
  2423. if (filled > 0)
  2424. lines[filled - 1].size
  2425. = lines[filled].start - lines[filled - 1].start - 1;
  2426. filled++;
  2427. }
  2428. lineflag = (data[i] == '\n');
  2429. }
  2430. if (filled > 0)
  2431. lines[filled - 1].size = &data[i] - lines[filled - 1].start - lineflag;
  2432. /* Do not leave garbage in the last element. */
  2433. lines[filled].start = NULL;
  2434. lines[filled].add_entries_before = NULL;
  2435. lines[filled].add_sections_before = NULL;
  2436. lines[filled].num_sections_to_add = 0;
  2437. lines[filled].delete = 0;
  2438. lines[filled].size = 0;
  2439. *nlinesp = filled;
  2440. return lines;
  2441. }
  2442. /* This is the comparison function for qsort for a vector of pointers to
  2443. struct spec_section. (Have to use const void * as the parameter type
  2444. to avoid incompatible-with-qsort warnings.)
  2445. Compare the section names. */
  2446. int
  2447. compare_section_names (const void *p1, const void *p2)
  2448. {
  2449. struct spec_section **sec1 = (struct spec_section **) p1;
  2450. struct spec_section **sec2 = (struct spec_section **) p2;
  2451. char *name1 = (*sec1)->name;
  2452. char *name2 = (*sec2)->name;
  2453. return strcmp (name1, name2);
  2454. }
  2455. /* This is the comparison function for qsort
  2456. for a vector of pointers to struct spec_entry.
  2457. Compare the entries' text. */
  2458. int
  2459. compare_entries_text (const void *p1, const void *p2)
  2460. {
  2461. struct spec_entry **entry1 = (struct spec_entry **) p1;
  2462. struct spec_entry **entry2 = (struct spec_entry **) p2;
  2463. char *text1 = (*entry1)->text;
  2464. char *text2 = (*entry2)->text;
  2465. char *colon1 = strchr (text1, ':');
  2466. char *colon2 = strchr (text2, ':');
  2467. int len1, len2;
  2468. if (!colon1)
  2469. len1 = strlen (text1);
  2470. else
  2471. len1 = colon1 - text1;
  2472. if (!colon2)
  2473. len2 = strlen (text2);
  2474. else
  2475. len2 = colon2 - text2;
  2476. return mbsncasecmp (text1, text2, len1 <= len2 ? len1 : len2);
  2477. }
  2478. /* Insert ENTRY into the ADD_ENTRIES_BEFORE vector for line number LINE_NUMBER
  2479. of the dir file. DIR_LINES and N_ENTRIES carry information from like-named
  2480. variables in main. */
  2481. void
  2482. insert_entry_here (struct spec_entry *entry, int line_number,
  2483. struct line_data *dir_lines, int n_entries)
  2484. {
  2485. int i, j;
  2486. if (dir_lines[line_number].add_entries_before == 0)
  2487. {
  2488. dir_lines[line_number].add_entries_before
  2489. = (struct spec_entry **) xmalloc (n_entries * sizeof (struct spec_entry *));
  2490. for (i = 0; i < n_entries; i++)
  2491. dir_lines[line_number].add_entries_before[i] = 0;
  2492. }
  2493. /* Find the place where this entry belongs. If there are already
  2494. several entries to add before LINE_NUMBER, make sure they are in
  2495. alphabetical order. */
  2496. for (i = 0; i < n_entries; i++)
  2497. if (dir_lines[line_number].add_entries_before[i] == 0
  2498. || menu_line_lessp (entry->text, strlen (entry->text),
  2499. dir_lines[line_number].add_entries_before[i]->text,
  2500. strlen (dir_lines[line_number].add_entries_before[i]->text)))
  2501. break;
  2502. if (i == n_entries)
  2503. abort ();
  2504. /* If we need to plug ENTRY into the middle of the
  2505. ADD_ENTRIES_BEFORE array, move the entries which should be output
  2506. after this one down one notch, before adding a new one. */
  2507. if (dir_lines[line_number].add_entries_before[i] != 0)
  2508. for (j = n_entries - 1; j > i; j--)
  2509. dir_lines[line_number].add_entries_before[j]
  2510. = dir_lines[line_number].add_entries_before[j - 1];
  2511. dir_lines[line_number].add_entries_before[i] = entry;
  2512. }