home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume38 / lout / part12 < prev    next >
Encoding:
Text File  |  1993-08-11  |  72.4 KB  |  1,766 lines

  1. Newsgroups: comp.sources.misc
  2. From: jeff@joyce.cs.su.oz.au (Jeff Kingston)
  3. Subject: v38i080:  lout - Lout document formatting system, v2.05, Part12/35
  4. Message-ID: <1993Aug8.180932.11865@sparky.sterling.com>
  5. X-Md4-Signature: 36024c84a55d1c1f6544ff8148e883fe
  6. Sender: kent@sparky.sterling.com (Kent Landfield)
  7. Organization: Sterling Software
  8. Date: Sun, 8 Aug 1993 18:09:32 GMT
  9. Approved: kent@sparky.sterling.com
  10.  
  11. Submitted-by: jeff@joyce.cs.su.oz.au (Jeff Kingston)
  12. Posting-number: Volume 38, Issue 80
  13. Archive-name: lout/part12
  14. Environment: UNIX
  15. Supersedes: lout: Volume 37, Issue 99-128
  16.  
  17. #! /bin/sh
  18. # This is a shell archive.  Remove anything before this line, then feed it
  19. # into a shell via "sh file" or similar.  To overwrite existing files,
  20. # type "sh file -c".
  21. # Contents:  doc/tr.lout/ch4.00 z01.c z10.c z33.c
  22. # Wrapped by kent@sparky on Sun Aug  8 12:29:24 1993
  23. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
  24. echo If this archive is complete, you will see the following message:
  25. echo '          "shar: End of archive 12 (of 35)."'
  26. if test -f 'doc/tr.lout/ch4.00' -a "${1}" != "-c" ; then 
  27.   echo shar: Will not clobber existing file \"'doc/tr.lout/ch4.00'\"
  28. else
  29.   echo shar: Extracting \"'doc/tr.lout/ch4.00'\" \(397 characters\)
  30.   sed "s/^X//" >'doc/tr.lout/ch4.00' <<'END_OF_FILE'
  31. X@Chapter
  32. X   @Title { Examples }
  33. X   @Tag { examples }
  34. X@Begin
  35. X@LP
  36. XThis chapter presents some examples taken from the various
  37. Xpackages available with Basser Lout.  The reader who masters these
  38. Xexamples will be well prepared to read the packages themselves.  The
  39. Xexamples have not been simplified in any way, since an important part of
  40. Xtheir purpose is to show Lout in actual practice.
  41. X@BeginSections
  42. END_OF_FILE
  43.   if test 397 -ne `wc -c <'doc/tr.lout/ch4.00'`; then
  44.     echo shar: \"'doc/tr.lout/ch4.00'\" unpacked with wrong size!
  45.   fi
  46.   # end of 'doc/tr.lout/ch4.00'
  47. fi
  48. if test -f 'z01.c' -a "${1}" != "-c" ; then 
  49.   echo shar: Will not clobber existing file \"'z01.c'\"
  50. else
  51.   echo shar: Extracting \"'z01.c'\" \(16834 characters\)
  52.   sed "s/^X//" >'z01.c' <<'END_OF_FILE'
  53. X/*@z01.c:Supervise:StartSym, AllowCrossDb, Encapsulated, etc.@****************/
  54. X/*                                                                           */
  55. X/*  LOUT: A HIGH-LEVEL LANGUAGE FOR DOCUMENT FORMATTING (VERSION 2.05)       */
  56. X/*  COPYRIGHT (C) 1993 Jeffrey H. Kingston                                   */
  57. X/*                                                                           */
  58. X/*  Jeffrey H. Kingston (jeff@cs.su.oz.au)                                   */
  59. X/*  Basser Department of Computer Science                                    */
  60. X/*  The University of Sydney 2006                                            */
  61. X/*  AUSTRALIA                                                                */
  62. X/*                                                                           */
  63. X/*  This program is free software; you can redistribute it and/or modify     */
  64. X/*  it under the terms of the GNU General Public License as published by     */
  65. X/*  the Free Software Foundation; either version 1, or (at your option)      */
  66. X/*  any later version.                                                       */
  67. X/*                                                                           */
  68. X/*  This program is distributed in the hope that it will be useful,          */
  69. X/*  but WITHOUT ANY WARRANTY; without even the implied warranty of           */
  70. X/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            */
  71. X/*  GNU General Public License for more details.                             */
  72. X/*                                                                           */
  73. X/*  You should have received a copy of the GNU General Public License        */
  74. X/*  along with this program; if not, write to the Free Software              */
  75. X/*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                */
  76. X/*                                                                           */
  77. X/*  FILE:         z01.c                                                      */
  78. X/*  MODULE:       Supervise                                                  */
  79. X/*  EXTERNS:      main(), StartSym, GalleySym, InputSym, PrintSym,           */
  80. X/*                AllowCrossDb, Encapsulated                                 */
  81. X/*                                                                           */
  82. X/*****************************************************************************/
  83. X#include "externs"
  84. X
  85. X
  86. X/*****************************************************************************/
  87. X/*                                                                           */
  88. X/*  StartSym      the symbol table entry for \Start (overall scope)          */
  89. X/*  GalleySym     the symbol table entry for @Galley                         */
  90. X/*  InputSym      the symbol table entry for @LInput                         */
  91. X/*  PrintSym      the symbol table entry for \Print (root target)            */
  92. X/*                                                                           */
  93. X/*****************************************************************************/
  94. X
  95. XOBJECT StartSym, GalleySym, InputSym, PrintSym;
  96. X
  97. X/*****************************************************************************/
  98. X/*                                                                           */
  99. X/*  AllowCrossDb        Allow references to OldCrossDb and NewCrossDb        */
  100. X/*  Encapsulated        Produce a one-page encapsulated PostScript file      */
  101. X/*                                                                           */
  102. X/*****************************************************************************/
  103. X
  104. XBOOLEAN AllowCrossDb;
  105. XBOOLEAN Encapsulated;
  106. X
  107. X
  108. X/*****************************************************************************/
  109. X/*                                                                           */
  110. X/*  static OBJECT load(xstr, xpredefined, xleft, xright, xindef, xprec)      */
  111. X/*                                                                           */
  112. X/*  Load a predefined operator with these attributes into the symbol table.  */
  113. X/*  If the operator has parameters, load symbols for those also.             */
  114. X/*                                                                           */
  115. X/*****************************************************************************/
  116. X
  117. Xstatic OBJECT load(xstr, xpre, xleft, xright, xindef, xprec)
  118. XFULL_CHAR *xstr;  unsigned  xpre;  BOOLEAN xleft, xright, xindef;
  119. Xunsigned char xprec;
  120. X{ OBJECT s;
  121. X  s = InsertSym(xstr, LOCAL, no_fpos, xprec, xindef, FALSE, xpre, StartSym,nil);
  122. X  if( xleft )  InsertSym( AsciiToFull("pa"), LPAR, no_fpos, DEFAULT_PREC,
  123. X    FALSE, FALSE, 0, s, nil);
  124. X  if( xright )  InsertSym( AsciiToFull("pb"), RPAR, no_fpos, DEFAULT_PREC,
  125. X    FALSE, FALSE, 0, s, nil);
  126. X  if( xleft && xright )  right_assoc(s) = TRUE;
  127. X  return s;
  128. X} /* end load */
  129. X
  130. X
  131. X/*@::GetArg(), main()@********************************************************/
  132. X/*                                                                           */
  133. X/*  GetArg(arg, message)                                                     */
  134. X/*                                                                           */
  135. X/*  Get the next argument from the command line and store it in arg.         */
  136. X/*  Print message as a fatal error if it isn't there.                        */
  137. X/*                                                                           */
  138. X/*****************************************************************************/
  139. X
  140. X#define GetArg(arg, message)                        \
  141. X{ if( !StringEqual(AsciiToFull(argv[i]+2), STR_EMPTY) )            \
  142. X    arg = AsciiToFull(argv[i]+2);                    \
  143. X  else if( i < argc-1 && *argv[i+1] != CH_HYPHEN )            \
  144. X    arg = AsciiToFull(argv[i++ +1]);                    \
  145. X  else                                    \
  146. X    Error(FATAL, no_fpos, message);                    \
  147. X} /* end GetArg */
  148. X
  149. X
  150. X/*****************************************************************************/
  151. X/*                                                                           */
  152. X/*  main(argc, argv)                                                         */
  153. X/*                                                                           */
  154. X/*  Read command line, initialise everything, read definitions, read         */
  155. X/*  galleys, clean up and exit.                                              */
  156. X/*                                                                           */
  157. X/*****************************************************************************/
  158. X
  159. Xmain(argc, argv)
  160. Xint argc; char *argv[];
  161. X{ int i, len;  FULL_CHAR *arg;
  162. X  OBJECT t, res, s;            /* current token, parser output      */
  163. X  BOOLEAN stdin_seen;            /* TRUE when stdin file seen         */
  164. X  FULL_CHAR *cross_db;            /* name of cross reference database  */
  165. X  FULL_CHAR *outfile;            /* name of output file               */
  166. X  FILE *out_fp;
  167. X
  168. X  /* initialise various modules, add current directory to search paths */
  169. X  AllowCrossDb = TRUE;
  170. X  Encapsulated = FALSE;
  171. X  InitSym();
  172. X  LexInit();
  173. X  MemInit();
  174. X  InitFiles();
  175. X  AddToPath(SOURCE_PATH,   STR_EMPTY);
  176. X  AddToPath(DATABASE_PATH, STR_EMPTY);
  177. X  AddToPath(INCLUDE_PATH,  STR_EMPTY);
  178. X
  179. X  /* read command line */
  180. X  stdin_seen = FALSE;
  181. X  cross_db = CROSS_DB;
  182. X  outfile = STR_STDOUT;
  183. X  for( i = 1;  i < argc;  i++ )
  184. X  { if( *argv[i] == CH_HYPHEN ) switch( *(argv[i]+1) )
  185. X    {
  186. X      case CH_FLAG_OUTFILE:
  187. X     
  188. X    /* read name of output file */
  189. X    GetArg(outfile, "usage: -o<filename>");
  190. X    break;
  191. X
  192. X
  193. X      case CH_FLAG_SUPPRESS:
  194. X     
  195. X    /* suppress references to OldCrossDb and NewCrossDb */
  196. X    AllowCrossDb = FALSE;
  197. X    break;
  198. X
  199. X
  200. X      case CH_FLAG_CROSS:
  201. X     
  202. X    /* read name of cross reference database */
  203. X    GetArg(cross_db, "usage: -c<filename>");
  204. X    break;
  205. X
  206. X
  207. X      case CH_FLAG_ERRFILE:
  208. X     
  209. X    /* read log file name */
  210. X    GetArg(arg, "usage: -e<filename>");
  211. X    ErrorInit(arg);
  212. X    break;
  213. X
  214. X
  215. X      case CH_FLAG_EPSFIRST:
  216. X     
  217. X    /* -EPS produces encapsulated PostScript output */
  218. X    if( !StringEqual(AsciiToFull(argv[i]+1), STR_EPS) )
  219. X      Error(FATAL, no_fpos, "usage: -EPS");
  220. X    Encapsulated = TRUE;
  221. X    break;
  222. X
  223. X
  224. X      case CH_FLAG_DIRPATH:
  225. X     
  226. X    /* add directory to database and sysdatabase paths */
  227. X    GetArg(arg, "usage: -D<dirname>");
  228. X    AddToPath(DATABASE_PATH, arg);
  229. X    AddToPath(SYSDATABASE_PATH, arg);
  230. X    break;
  231. X
  232. X
  233. X      case CH_FLAG_ENCPATH:
  234. X     
  235. X    /* add directory to encoding path */
  236. X    GetArg(arg, "usage: -C<dirname>");
  237. X    AddToPath(ENCODING_PATH, arg);
  238. X    break;
  239. X
  240. X
  241. X      case CH_FLAG_FNTPATH:
  242. X     
  243. X    /* add directory to font path */
  244. X    GetArg(arg, "usage: -F<dirname>");
  245. X    AddToPath(FONT_PATH, arg);
  246. X    break;
  247. X
  248. X
  249. X      case CH_FLAG_INCPATH:
  250. X     
  251. X    /* add directory to include and sysinclude paths */
  252. X    GetArg(arg, "usage: -I<dirname>");
  253. X    AddToPath(INCLUDE_PATH, arg);
  254. X    AddToPath(SYSINCLUDE_PATH, arg);
  255. X    break;
  256. X
  257. X
  258. X      case CH_FLAG_INCLUDE:
  259. X     
  260. X    /* read sysinclude file and strip any .lt suffix */
  261. X    GetArg(arg, "usage: -i<filename>");
  262. X    len = StringLength(arg) - StringLength(SOURCE_SUFFIX);
  263. X    if( len >= 0 && StringEqual(&arg[len], SOURCE_SUFFIX) )
  264. X      StringCopy(&arg[len], STR_EMPTY);
  265. X    DefineFile(arg, STR_EMPTY, no_fpos,
  266. X      SOURCE_FILE, SYSINCLUDE_PATH);
  267. X    break;
  268. X
  269. X
  270. X      case CH_FLAG_HYPHEN:
  271. X     
  272. X    /* declare hyphenation file */
  273. X    if( FirstFile(HYPH_FILE) != NO_FILE )
  274. X      Error(FATAL, no_fpos, "two -h options illegal");
  275. X    GetArg(arg, "usage: -h<filename>");
  276. X    DefineFile(arg, STR_EMPTY, no_fpos,
  277. X      HYPH_FILE, INCLUDE_PATH);
  278. X    DefineFile(arg, HYPH_SUFFIX, no_fpos,
  279. X      HYPH_PACKED_FILE, INCLUDE_PATH);
  280. X    break;
  281. X
  282. X
  283. X      case CH_FLAG_VERSION:
  284. X     
  285. X    fprintf(stderr, "%s\n", LOUT_VERSION);
  286. X    break;
  287. X
  288. X
  289. X      case CH_FLAG_USAGE:
  290. X     
  291. X    fprintf(stderr, "usage: lout [ -i<filename> ] files\n");
  292. X    exit(0);
  293. X    break;
  294. X
  295. X
  296. X      case CH_FLAG_DEBUG:
  297. X     
  298. X    debug_init(argv[i]);
  299. X    break;
  300. X
  301. X
  302. X      case '\0':
  303. X     
  304. X    /* read stdin as file name */
  305. X    if( stdin_seen )  Error(FATAL, no_fpos, "stdin read twice!");
  306. X    stdin_seen = TRUE;
  307. X    DefineFile(STR_STDIN, STR_EMPTY, no_fpos, SOURCE_FILE, SOURCE_PATH);
  308. X    break;
  309. X
  310. X
  311. X      default:
  312. X     
  313. X    Error(FATAL, no_fpos, "unknown command line flag %s", argv[i]);
  314. X    break;
  315. X
  316. X    }
  317. X    else
  318. X    {   /* argument is source file, strip any .lout suffix and define it */
  319. X    arg = argv[i];
  320. X    len = StringLength(arg) - StringLength(SOURCE_SUFFIX);
  321. X    if( len >= 0 && StringEqual(&arg[len], SOURCE_SUFFIX) )
  322. X      StringCopy(&arg[len], STR_EMPTY);
  323. X    DefineFile(AsciiToFull(argv[i]), STR_EMPTY, no_fpos,
  324. X        SOURCE_FILE, SOURCE_PATH);
  325. X    }
  326. X  } /* for */
  327. X
  328. X  /* define hyphenation file if not done already by -h flag */
  329. X  if( FirstFile(HYPH_FILE) == NO_FILE )
  330. X  { DefineFile(HYPH_FILENAME, STR_EMPTY, no_fpos, HYPH_FILE, SYSINCLUDE_PATH);
  331. X    DefineFile(HYPH_FILENAME, HYPH_SUFFIX, no_fpos,
  332. X      HYPH_PACKED_FILE, SYSINCLUDE_PATH);
  333. X  }
  334. X
  335. X  /* start timing if required */
  336. X  ifdebug(DPP, D, ProfileOn("main"));
  337. X
  338. X  /* open output file, or stdout if none specified, and initialize printer */
  339. X  if( StringEqual(outfile, STR_STDOUT) )  out_fp = stdout;
  340. X  else if( (out_fp = StringFOpen(outfile, "w")) == null )
  341. X    Error(FATAL, no_fpos, "cannot open output file %s", outfile);
  342. X  FontInit();
  343. X  PrintInit(out_fp);
  344. X
  345. X  /* append default directories to file search paths */
  346. X  AddToPath(FONT_PATH,         AsciiToFull(FONT_DIR));
  347. X  AddToPath(ENCODING_PATH,     AsciiToFull(EVEC_DIR));
  348. X  AddToPath(SYSDATABASE_PATH,  AsciiToFull(DATA_DIR));
  349. X  AddToPath(DATABASE_PATH,     AsciiToFull(DATA_DIR));
  350. X  AddToPath(SYSINCLUDE_PATH,   AsciiToFull(INCL_DIR));
  351. X  AddToPath(INCLUDE_PATH,      AsciiToFull(INCL_DIR));
  352. X
  353. X  /* use stdin if no source files were mentioned */
  354. X  if( FirstFile(SOURCE_FILE) == NO_FILE )
  355. X    DefineFile(STR_STDIN, STR_EMPTY, no_fpos, SOURCE_FILE, SOURCE_PATH);
  356. X
  357. X  /* load predefined symbols into symbol table */
  358. X  StartSym = nil;  /* Not a mistake */
  359. X  StartSym  = load(KW_START,    0,     FALSE,  FALSE,  TRUE,  NO_PREC     );
  360. X  GalleySym = load(KW_GALLEY,   0,     FALSE,  FALSE,  TRUE,  NO_PREC     );
  361. X  InputSym  = load(KW_INPUT,    0,     FALSE,  FALSE,  TRUE,  NO_PREC     );
  362. X  PrintSym  = load(KW_PRINT,    0,     FALSE,  FALSE,  TRUE,  NO_PREC     );
  363. X
  364. X  load(KW_BEGIN,       BEGIN,          FALSE,  FALSE,  FALSE, BEGIN_PREC  );
  365. X  load(KW_END,         END,            FALSE,  FALSE,  FALSE, END_PREC    );
  366. X  load(KW_ENV,         ENV,            FALSE,  FALSE,  FALSE, NO_PREC     );
  367. X  load(KW_CLOS,        CLOS,           FALSE,  FALSE,  FALSE, NO_PREC     );
  368. X  load(KW_LVIS,        LVIS,           FALSE,  FALSE,  FALSE, NO_PREC     );
  369. X  load(KW_LBR,         LBR,            FALSE,  FALSE,  FALSE, LBR_PREC    );
  370. X  load(KW_RBR,         RBR,            FALSE,  FALSE,  FALSE, RBR_PREC    );
  371. X  load(KW_INCLUDE,     INCLUDE,        FALSE,  FALSE,  FALSE, NO_PREC     );
  372. X  load(KW_SYSINCLUDE,  SYS_INCLUDE,    FALSE,  FALSE,  FALSE, NO_PREC     );
  373. X  load(KW_PREPEND,     PREPEND,        FALSE,  FALSE,  FALSE, NO_PREC     );
  374. X  load(KW_SYSPREPEND,  SYS_PREPEND,    FALSE,  FALSE,  FALSE, NO_PREC     );
  375. X  load(KW_DATABASE,    DATABASE,       FALSE,  FALSE,  FALSE, NO_PREC     );
  376. X  load(KW_SYSDATABASE, SYS_DATABASE,   FALSE,  FALSE,  FALSE, NO_PREC     );
  377. X  load(KW_USE,         USE,            FALSE,  FALSE,  FALSE, NO_PREC     );
  378. X  load(KW_CASE,        CASE,           TRUE,   TRUE,   FALSE, DEFAULT_PREC);
  379. X  load(KW_YIELD,       YIELD,          TRUE,   TRUE,   FALSE, DEFAULT_PREC);
  380. X  load(KW_XCHAR,       XCHAR,          FALSE,  TRUE,   FALSE, DEFAULT_PREC);
  381. X  load(KW_FONT,        FONT,           TRUE,   TRUE,   FALSE, DEFAULT_PREC);
  382. X  load(KW_SPACE,       SPACE,          TRUE,   TRUE,   FALSE, DEFAULT_PREC);
  383. X  load(KW_BREAK,       BREAK,          TRUE,   TRUE,   FALSE, DEFAULT_PREC);
  384. X  load(KW_NEXT,        NEXT,           FALSE,  TRUE,   FALSE, DEFAULT_PREC);
  385. X  load(KW_OPEN,        OPEN,           TRUE,   TRUE,   FALSE, DEFAULT_PREC);
  386. X  load(KW_TAGGED,      TAGGED,         TRUE,   TRUE,   FALSE, DEFAULT_PREC);
  387. X  load(KW_HIGH,        HIGH,           TRUE,   TRUE,   FALSE, DEFAULT_PREC);
  388. X  load(KW_WIDE,        WIDE,           TRUE,   TRUE,   FALSE, DEFAULT_PREC);
  389. X  load(KW_ONE_COL,     ONE_COL,        FALSE,  TRUE,   FALSE, DEFAULT_PREC);
  390. X  load(KW_ONE_ROW,     ONE_ROW,        FALSE,  TRUE,   FALSE, DEFAULT_PREC);
  391. X  load(KW_HSCALE,      HSCALE,         FALSE,  TRUE,   FALSE, DEFAULT_PREC);
  392. X  load(KW_VSCALE,      VSCALE,         FALSE,  TRUE,   FALSE, DEFAULT_PREC);
  393. X  load(KW_SCALE,       SCALE,          TRUE,   TRUE,   FALSE, DEFAULT_PREC);
  394. X  load(KW_HCONTRACT,   HCONTRACT,      FALSE,  TRUE,   FALSE, DEFAULT_PREC);
  395. X  load(KW_VCONTRACT,   VCONTRACT,      FALSE,  TRUE,   FALSE, DEFAULT_PREC);
  396. X  load(KW_HEXPAND,     HEXPAND,        FALSE,  TRUE,   FALSE, DEFAULT_PREC);
  397. X  load(KW_VEXPAND,     VEXPAND,        FALSE,  TRUE,   FALSE, DEFAULT_PREC);
  398. X  load(KW_PADJUST,     PADJUST,        FALSE,  TRUE,   FALSE, DEFAULT_PREC);
  399. X  load(KW_HADJUST,     HADJUST,        FALSE,  TRUE,   FALSE, DEFAULT_PREC);
  400. X  load(KW_VADJUST,     VADJUST,        FALSE,  TRUE,   FALSE, DEFAULT_PREC);
  401. X  load(KW_ROTATE,      ROTATE,         TRUE,   TRUE,   FALSE, DEFAULT_PREC);
  402. X  load(KW_INCGRAPHIC,  INCGRAPHIC,     FALSE,  TRUE,   FALSE, DEFAULT_PREC);
  403. X  load(KW_SINCGRAPHIC, SINCGRAPHIC,    FALSE,  TRUE,   FALSE, DEFAULT_PREC);
  404. X  load(KW_GRAPHIC,     GRAPHIC,        TRUE,   TRUE,   FALSE, DEFAULT_PREC);
  405. X  load(KW_CROSS,       CROSS,          TRUE,   TRUE,   FALSE, CROSSOP_PREC);
  406. X  load(KW_NULL,        NULL_CLOS,      FALSE,  FALSE,  TRUE,  NO_PREC     );
  407. X
  408. X#define setcat(s, mk, jn)  has_mark(s)=mk, has_join(s)=jn
  409. X
  410. X  s=load(KW_VCAT_NN, VCAT, TRUE, TRUE, FALSE, VCAT_PREC); setcat(s,FALSE,FALSE);
  411. X  s=load(KW_VCAT_MN, VCAT, TRUE, TRUE, FALSE, VCAT_PREC); setcat(s,TRUE, FALSE);
  412. X  s=load(KW_VCAT_NJ, VCAT, TRUE, TRUE, FALSE, VCAT_PREC); setcat(s,FALSE,TRUE);
  413. X  s=load(KW_VCAT_MJ, VCAT, TRUE, TRUE, FALSE, VCAT_PREC); setcat(s,TRUE, TRUE);
  414. X  s=load(KW_HCAT_NN, HCAT, TRUE, TRUE, FALSE, HCAT_PREC); setcat(s,FALSE,FALSE);
  415. X  s=load(KW_HCAT_MN, HCAT, TRUE, TRUE, FALSE, HCAT_PREC); setcat(s,TRUE, FALSE);
  416. X  s=load(KW_HCAT_NJ, HCAT, TRUE, TRUE, FALSE, HCAT_PREC); setcat(s,FALSE,TRUE);
  417. X  s=load(KW_HCAT_MJ, HCAT, TRUE, TRUE, FALSE, HCAT_PREC); setcat(s,TRUE, TRUE);
  418. X  s=load(KW_ACAT_NJ, ACAT, TRUE, TRUE, FALSE, ACAT_PREC); setcat(s,FALSE,TRUE);
  419. X  s=load(KW_ACAT_MJ, ACAT, TRUE, TRUE, FALSE, ACAT_PREC); setcat(s,TRUE, TRUE);
  420. X
  421. X  /* intialize current time and load @Moment symbol */
  422. X  InitTime();
  423. X
  424. X  /* initialise scope chain to <StartSym> */
  425. X  PushScope(StartSym, FALSE, FALSE);
  426. X
  427. X  /* initialise lexical analyser */
  428. X  LexPush(FirstFile(SOURCE_FILE), 0, SOURCE_FILE);
  429. X
  430. X  /* process input files */
  431. X  InitParser(cross_db);
  432. X  t = NewToken(BEGIN, no_fpos, 0, 0, BEGIN_PREC, StartSym);
  433. X  res = Parse(&t, StartSym, TRUE, TRUE);
  434. X  TransferEnd(res);
  435. X  TransferClose();
  436. X
  437. X  /* close various  modules */
  438. X  PrintClose();
  439. X  CrossClose();
  440. X  CloseFiles();
  441. X
  442. X  /* wrapup */
  443. X  ifdebug(DST, D, CheckSymSpread() );
  444. X  debug0(ANY, D, "commencing deletes");
  445. X  ifdebug(ANY, D, DeleteEverySym() );
  446. X  ifdebug(DMA, D, DebugMemory() );
  447. X  ifdebug(DPP, D, ProfileOff("main"));
  448. X  ifdebug(DPP, D, ProfilePrint());
  449. X  exit(0);
  450. X  return 0;
  451. X} /* end main */
  452. END_OF_FILE
  453.   if test 16834 -ne `wc -c <'z01.c'`; then
  454.     echo shar: \"'z01.c'\" unpacked with wrong size!
  455.   fi
  456.   # end of 'z01.c'
  457. fi
  458. if test -f 'z10.c' -a "${1}" != "-c" ; then 
  459.   echo shar: Will not clobber existing file \"'z10.c'\"
  460. else
  461.   echo shar: Extracting \"'z10.c'\" \(26605 characters\)
  462.   sed "s/^X//" >'z10.c' <<'END_OF_FILE'
  463. X/*@z10.c:Cross References:CrossInit(), CrossMake()@***************************/
  464. X/*                                                                           */
  465. X/*  LOUT: A HIGH-LEVEL LANGUAGE FOR DOCUMENT FORMATTING (VERSION 2.05)       */
  466. X/*  COPYRIGHT (C) 1993 Jeffrey H. Kingston                                   */
  467. X/*                                                                           */
  468. X/*  Jeffrey H. Kingston (jeff@cs.su.oz.au)                                   */
  469. X/*  Basser Department of Computer Science                                    */
  470. X/*  The University of Sydney 2006                                            */
  471. X/*  AUSTRALIA                                                                */
  472. X/*                                                                           */
  473. X/*  This program is free software; you can redistribute it and/or modify     */
  474. X/*  it under the terms of the GNU General Public License as published by     */
  475. X/*  the Free Software Foundation; either version 1, or (at your option)      */
  476. X/*  any later version.                                                       */
  477. X/*                                                                           */
  478. X/*  This program is distributed in the hope that it will be useful,          */
  479. X/*  but WITHOUT ANY WARRANTY; without even the implied warranty of           */
  480. X/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            */
  481. X/*  GNU General Public License for more details.                             */
  482. X/*                                                                           */
  483. X/*  You should have received a copy of the GNU General Public License        */
  484. X/*  along with this program; if not, write to the Free Software              */
  485. X/*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                */
  486. X/*                                                                           */
  487. X/*  FILE:         z10.c                                                      */
  488. X/*  MODULE:       Cross References                                           */
  489. X/*  EXTERNS:      CrossInit(), CrossMake(), GallTargEval(), CrossAddTag(),   */
  490. X/*                CrossExpand(), CrossSequence(), CrossClose()               */
  491. X/*                                                                           */
  492. X/*****************************************************************************/
  493. X#include "externs"
  494. X#define    CROSS_LIT    CROSS_TARG
  495. X#define    NO_TARGET    0
  496. X#define    SEEN_TARGET    1
  497. X#define    WRITTEN_TARGET    2
  498. Xstatic OBJECT RootCross = nil;            /* header for all crs        */
  499. X
  500. X
  501. X/*****************************************************************************/
  502. X/*                                                                           */
  503. X/*  CrossInit(sym)     Initialize cross_sym(sym).                            */
  504. X/*                                                                           */
  505. X/*****************************************************************************/
  506. X
  507. XCrossInit(sym)
  508. XOBJECT sym;
  509. X{ int i; OBJECT cs = New(CROSS_SYM);
  510. X  target_state(cs) = NO_TARGET;  target_seq(cs) = 0;
  511. X  cr_file(cs) = NO_FILE;
  512. X  gall_seq(cs) = 0;  gall_tag(cs) = nil;
  513. X  gall_tfile(cs) = NO_FILE;  gentag_file(cs) = NO_FILE;
  514. X  symb(cs) = sym;  cross_sym(sym) = cs;
  515. X  gentag_fseq(cs) = NewWord(WORD, MAX_FILES, no_fpos);
  516. X  for( i = 0;  i < MAX_FILES;  i++ ) string(gentag_fseq(cs))[i] = 0;
  517. X  if( RootCross == nil )  RootCross = New(CR_ROOT);  Link(RootCross, cs);
  518. X}
  519. X
  520. X
  521. X/*****************************************************************************/
  522. X/*                                                                           */
  523. X/*  OBJECT CrossMake(sym, val, ctype)                                        */
  524. X/*                                                                           */
  525. X/*  Make a cross-reference with the given sym and tag value (NB no fpos).    */
  526. X/*                                                                           */
  527. X/*****************************************************************************/
  528. X
  529. XOBJECT CrossMake(sym, val, ctype)
  530. XOBJECT sym, val;  int ctype;
  531. X{ OBJECT v1, res;
  532. X  debug3(DCR, DD, "CrossMake(%s, %s, %s)", SymName(sym),
  533. X    EchoObject(val), Image(ctype));
  534. X  res = New(CROSS);  cross_type(res) = ctype;  threaded(res) = FALSE;
  535. X  v1 = New(CLOSURE);  actual(v1) = sym;
  536. X  Link(res, v1);  Link(res, val);
  537. X  debug1(DCR, DD, "CrossMake returning %s", EchoObject(res));
  538. X  return res;
  539. X}
  540. X
  541. X/*@::GallTargEval(), CrossGenTag()@*******************************************/
  542. X/*                                                                           */
  543. X/*  OBJECT GallTargEval(sym, dfpos)                                          */
  544. X/*                                                                           */
  545. X/*  Produce a suitable cross-reference for a galley target.                  */
  546. X/*                                                                           */
  547. X/*****************************************************************************/
  548. X
  549. XOBJECT GallTargEval(sym, dfpos)
  550. XOBJECT sym; FILE_POS *dfpos;
  551. X{ OBJECT cs, res;
  552. X  FULL_CHAR buff[MAX_LINE], *str;
  553. X  debug2(DCR, DD, "GallTargEval( %s,%s )", SymName(sym), EchoFilePos(dfpos));
  554. X  if( cross_sym(sym) == nil )  CrossInit(sym);
  555. X  cs = cross_sym(sym);
  556. X  if( file_num(*dfpos) != gall_tfile(cs) )
  557. X  { gall_tfile(cs) = file_num(*dfpos);
  558. X    gall_seq(cs)   = 0;
  559. X  }
  560. X  str = FileName(gall_tfile(cs));
  561. X  if( StringLength(str) + 6 >= MAX_LINE )
  562. X    Error(FATAL, dfpos, "automatically generated tag %s&%d is too long",
  563. X    str, ++gall_seq(cs));
  564. X  ++gall_seq(cs);
  565. X  StringCopy(buff, str);
  566. X  StringCat(buff, AsciiToFull("&"));
  567. X  StringCat(buff, StringInt(gall_seq(cs)));
  568. X  res = CrossMake(sym, MakeWord(WORD, buff, dfpos), GALL_TARG);
  569. X  debug1(DCR, DD, "GallTargEval returning %s", EchoObject(res));
  570. X  return res;
  571. X} /* end GallTargEval */
  572. X
  573. X
  574. X/*****************************************************************************/
  575. X/*                                                                           */
  576. X/*  static OBJECT CrossGenTag(x)                                             */
  577. X/*                                                                           */
  578. X/*  Generate a tag suitable for labelling closure x, in such a way that      */
  579. X/*  the same tag is likely to be generated on subsequent runs.               */
  580. X/*                                                                           */
  581. X/*****************************************************************************/
  582. X
  583. Xstatic OBJECT CrossGenTag(x)
  584. XOBJECT x;
  585. X{ FULL_CHAR buff[MAX_LINE], *str1, *str2;
  586. X  OBJECT sym, cs, gt, res;  FILE_NUM fnum;
  587. X  FULL_CHAR *sgt;
  588. X  int seq;
  589. X  debug1(DCR, D, "CrossGenTag( %s )", SymName(actual(x)));
  590. X  sym = actual(x);
  591. X  if( cross_sym(sym) == nil )  CrossInit(sym);
  592. X  cs = cross_sym(sym);
  593. X  fnum = file_num(fpos(x));
  594. X  /* ***
  595. X  if( fnum != gentag_file(cs) )
  596. X  { gentag_file(cs) = fnum;
  597. X    gentag_seq(cs)  = 0;
  598. X  }
  599. X  *** */
  600. X  str1 = FullSymName(sym, AsciiToFull("."));
  601. X  str2 = FileName(fnum);
  602. X  gt = gentag_fseq(cs);
  603. X  sgt = string(gt);
  604. X  seq = ++(sgt[fnum]);
  605. X  if( StringLength(str1) + StringLength(str2) + 10 >= MAX_LINE )
  606. X    Error(FATAL,no_fpos, "automatically generated tag \"%s.%s.%d\" is too long",
  607. X    str1, str2, seq);
  608. X  StringCopy(buff, str1);
  609. X  StringCat(buff, AsciiToFull("."));
  610. X  StringCat(buff, str2);
  611. X  StringCat(buff, AsciiToFull("."));
  612. X  StringCat(buff, StringInt(seq));
  613. X  res = MakeWord(QWORD, buff, &fpos(x));
  614. X  debug1(DCR, DD, "CrossGenTag returning %s", string(res));
  615. X  return res;
  616. X} /* end CrossGenTag */
  617. X
  618. X
  619. X/*@::CrossAddTag()@***********************************************************/
  620. X/*                                                                           */
  621. X/*  CrossAddTag(x)                                                           */
  622. X/*                                                                           */
  623. X/*  Add an automatically generated @Tag parameter to closure x if required.  */
  624. X/*                                                                           */
  625. X/*****************************************************************************/
  626. X
  627. XCrossAddTag(x)
  628. XOBJECT x;
  629. X{ OBJECT link, par, ppar, y;
  630. X  if( has_tag(actual(x)) )
  631. X  { 
  632. X    /* search the parameter list of x for a @Tag parameter */
  633. X    for( link = Down(x);  link != x;  link = NextDown(link) )
  634. X    { Child(par, link);
  635. X      if( type(par) == PAR && is_tag(actual(par)) )  break;
  636. X    }
  637. X    if( link == x )
  638. X    { 
  639. X      /* search the definition of x for name of its @Tag parameter */
  640. X      ppar = nil;
  641. X      for( link=Down(actual(x));  link != actual(x);  link = NextDown(link) )
  642. X      {    Child(y, link);
  643. X    if( is_par(type(y)) && is_tag(y) )
  644. X    { ppar = y;
  645. X      break;
  646. X    }
  647. X      }
  648. X      if( ppar != nil ) /* should always hold */
  649. X      {
  650. X    /* prepare new PAR containing generated tag */
  651. X    par = New(PAR);
  652. X    actual(par) = ppar;
  653. X    y = CrossGenTag(x);
  654. X    Link(par, y);
  655. X
  656. X    /* find the right spot, then link it to x */
  657. X    switch( type(ppar) )
  658. X    {
  659. X      case LPAR:    link = Down(x);
  660. X            break;
  661. X
  662. X      case NPAR:    link = Down(x);
  663. X            if( Down(x) != x )
  664. X            { Child(y, Down(x));
  665. X              if( type(y) == PAR && type(actual(par)) == LPAR )
  666. X                link = NextDown(link);
  667. X            }
  668. X            break;
  669. X
  670. X      case RPAR:    for( link = Down(x); link != x; link = NextDown(link) )
  671. X            { Child(y, link);
  672. X              if( type(y) != PAR )  break;
  673. X            }
  674. X            break;
  675. X    }
  676. X    Link(link, par);
  677. X      }
  678. X    }
  679. X  }
  680. X} /* end CrossAddTag */
  681. X
  682. X
  683. X/*@::CrossExpand()@***********************************************************/
  684. X/*                                                                           */
  685. X/*  OBJECT CrossExpand(x, env, style, crs_wanted, crs, res_env)              */
  686. X/*                                                                           */
  687. X/*  Return the value of cross-reference x, with environment *res_env.  If x  */
  688. X/*  has a non-literal tag, it must be tracked, so an object is added to *crs */
  689. X/*  for this purpose if crs_wanted.  Result replaces x, which is disposed.   */
  690. X/*                                                                           */
  691. X/*****************************************************************************/
  692. Xstatic OBJECT nbt[2] = { nil, nil };
  693. Xstatic OBJECT nft[2] = { nil, nil };
  694. Xstatic OBJECT ntarget = nil;
  695. X
  696. XOBJECT CrossExpand(x, env, style, crs_wanted, crs, res_env)
  697. XOBJECT x, env;  STYLE *style;  BOOLEAN crs_wanted; OBJECT *crs, *res_env;
  698. X{ OBJECT sym, res, tag, y, cs, link, db, tmp, index;
  699. X  int ctype;  FULL_CHAR buff[MAX_LINE], seq[MAX_LINE], *str;
  700. X  FILE_NUM fnum, dfnum;
  701. X  long cont, dfpos;
  702. X  assert( type(x) == CROSS, "CrossExpand: x!" );
  703. X  debug2(DCR, DD, "CrossExpand( %s, %s )", EchoObject(x), EchoObject(*crs));
  704. X  assert( NextDown(Down(x)) == LastDown(x), "CrossExpand: #args!" );
  705. X
  706. X  /* manifest and tidy the right parameter */
  707. X  Child(tag, LastDown(x));
  708. X  tag = Manifest(tag, env, style, nbt, nft, &ntarget, crs, FALSE, FALSE);
  709. X  tag = ReplaceWithTidy(tag);
  710. X
  711. X  /* extract sym (the symbol name) and tag (the tag value) from x */
  712. X  Child(y, Down(x));
  713. X  if( type(y) == CLOSURE )  sym = actual(y);
  714. X  ctype = type(y) != CLOSURE ? 1 :
  715. X      !is_word(type(tag)) ? 2 :
  716. X      StringEqual(string(tag), STR_EMPTY) ? 3 :
  717. X      StringEqual(string(tag), KW_PRECEDING) ? CROSS_PREC :
  718. X      StringEqual(string(tag), KW_FOLLOWING) ? CROSS_FOLL : CROSS_LIT;
  719. X
  720. X  res = nil;
  721. X  switch( ctype )
  722. X  {
  723. X
  724. X    case 1:
  725. X
  726. X      Error(WARN, &fpos(y), "left parameter of %s is not a symbol", KW_CROSS);
  727. X      break;
  728. X
  729. X
  730. X    case 2:
  731. X
  732. X      Error(WARN, &fpos(tag),
  733. X    "value of right parameter of %s is not a simple word", KW_CROSS);
  734. X      break;
  735. X
  736. X
  737. X    case 3:
  738. X    
  739. X      Error(WARN, &fpos(tag),
  740. X    "value of right parameter of %s is an empty word", KW_CROSS);
  741. X      break;
  742. X
  743. X
  744. X    case CROSS_LIT:
  745. X    
  746. X      if( cross_sym(sym) == nil )  CrossInit(sym);
  747. X      cs = cross_sym(sym);
  748. X      if( sym == MomentSym && StringEqual(string(tag), KW_NOW) )
  749. X      {    /* this is a request for the current time */
  750. X    res = StartMoment();
  751. X      }
  752. X      else for( link = NextUp(Up(cs));  link != cs;  link = NextUp(link) )
  753. X      {    Parent(db, link);
  754. X    assert( is_word(type(db)), "CrossExpand: db!" );
  755. X    if( DbRetrieve(db, FALSE, sym, string(tag), seq, &dfnum,&dfpos,&cont) )
  756. X    { res = ReadFromFile(dfnum, dfpos, sym);
  757. X      if( db != OldCrossDb )  AttachEnv(env, res);
  758. X      break;
  759. X    }
  760. X      }
  761. X      break;
  762. X
  763. X
  764. X    case CROSS_PREC:
  765. X    case CROSS_FOLL:
  766. X    
  767. X      if( cross_sym(sym) == nil )  CrossInit(sym);
  768. X      cs = cross_sym(sym);
  769. X      assert( cs != nil, "CrossExpand/CROSS_FOLL: cs == nil!" );
  770. X      assert( type(cs) == CROSS_SYM, "CrossExpand/CROSS_FOLL: type(cs)!" );
  771. X      fnum = file_num(fpos(tag));
  772. X      if( fnum != cr_file(cs) )
  773. X      {    cr_file(cs) = fnum;
  774. X    cr_seq(cs) = 0;
  775. X      }
  776. X      str = FileName(fnum);
  777. X      ++cr_seq(cs);
  778. X      if( StringLength(str) + 5 >= MAX_LINE )
  779. X    Error(FATAL, &fpos(x), "automatically generated tag %s_%d is too long",
  780. X      str, cr_seq(cs));
  781. X      StringCopy(buff, str);
  782. X      StringCat(buff, AsciiToFull("_"));
  783. X      StringCat(buff, StringInt(cr_seq(cs)));
  784. X      tmp = CrossMake(sym, MakeWord(WORD, buff, &fpos(tag)), ctype);
  785. X      index = New(ctype);
  786. X      actual(index) = tmp;
  787. X      Link(index, tmp);
  788. X      if( crs_wanted )
  789. X      {    if( *crs == nil )  *crs = New(CR_LIST);
  790. X    link = Link(*crs, index);
  791. X      }
  792. X      else Error(FATAL, &fpos(x), "%s or %s tag not allowed here",
  793. X    KW_PRECEDING, KW_FOLLOWING);
  794. X      if( AllowCrossDb &&
  795. X      DbRetrieve(OldCrossDb, FALSE, sym, buff, seq, &dfnum, &dfpos,&cont) )
  796. X    res = ReadFromFile(dfnum, dfpos, nil);
  797. X      break;
  798. X
  799. X
  800. X    default:
  801. X    
  802. X      Error(INTERN, no_fpos, "CrossExpand switch!");
  803. X      break;
  804. X
  805. X
  806. X  } /* end switch */
  807. X  if( res == nil )
  808. X  { OBJECT envt;
  809. X    if( ctype > 1 )  Error(WARN, &fpos(x), "%s%s%s unknown",
  810. X        SymName(sym), KW_CROSS, string(tag));
  811. X
  812. X    /* build dummy result with environment attached */
  813. X    /* nb at present we are not adding dummy import closures to this! */
  814. X    res = New(CLOSURE);  actual(res) = sym;
  815. X    y = res;
  816. X    debug1(DCR, DD, "First y = %s", SymName(actual(y)));
  817. X    while( enclosing(actual(y)) != StartSym )
  818. X    { tmp = New(CLOSURE);
  819. X      actual(tmp) = enclosing(actual(y));
  820. X      debug0(DCR, DD, "  calling SetEnv from CrossExpand (a)");
  821. X      envt = SetEnv(tmp, nil);
  822. X      AttachEnv(envt, y);
  823. X      y = tmp;
  824. X      debug1(DCR, DD, "Later y = %s", SymName(actual(y)));
  825. X    }
  826. X    envt = New(ENV);  Link(y, envt);
  827. X  }
  828. X
  829. X  /* set environment, replace x by res, debug and exit */
  830. X  *res_env = DetachEnv(res);
  831. X  ReplaceNode(res, x);
  832. X  DisposeObject(x);
  833. X  assert( type(res) == CLOSURE, "CrossExpand: type(res) != CLOSURE!" );
  834. X  assert( actual(res) == sym, "CrossExpand: actual(res) != sym!" );
  835. X  debug1(DCR, DD, "CrossExpand returning %s", EchoObject(res));
  836. X  debug1(DCR, DD, "  *crs = %s", EchoObject(*crs));
  837. X  debug1(DCR, DD, "  *res_env = %s", EchoObject(*res_env));
  838. X  return res;
  839. X} /* end CrossExpand */
  840. X
  841. X
  842. X/*@::CrossSequence()@*********************************************************/
  843. X/*                                                                           */
  844. X/*  CrossSequence(x)                                                         */
  845. X/*                                                                           */
  846. X/*  Object x is an insinuated cross-reference that has just been popped off  */
  847. X/*  the top of the root galley.  Resolve it with the sequence of others.     */
  848. X/*                                                                           */
  849. X/*****************************************************************************/
  850. X
  851. XCrossSequence(x)
  852. XOBJECT x;
  853. X{ OBJECT sym, tag, val, tmp, cs, par, key, link, y;
  854. X  unsigned ctype;  FULL_CHAR buff[MAX_LINE], *str, *seq;
  855. X  FILE_NUM dfnum;  int dfpos;
  856. X
  857. X  /* if suppressing cross-referencing, dispose x and quit */
  858. X  if( !AllowCrossDb )
  859. X  { if( Up(x) == x )  DisposeObject(x);
  860. X    debug0(DCR, D, "CrossSequence returning (!AllowCrossDb).");
  861. X    return;
  862. X  }
  863. X
  864. X  /* get interesting fragments from x */
  865. X  assert( type(x) == CROSS, "CrossSequence: type(x)!" );
  866. X  ctype = cross_type(x);
  867. X  Child(tmp, Down(x));
  868. X  assert( type(tmp) == CLOSURE, "CrossSequence: type(tmp)!" );
  869. X  sym = actual(tmp);
  870. X  if( cross_sym(sym) == nil )  CrossInit(sym);
  871. X  cs = cross_sym(sym);
  872. X  assert( type(cs) == CROSS_SYM, "CrossSequence: cs!" );
  873. X
  874. X  /* debug output */
  875. X  debug2(DCR, D, "CrossSequence %s %s", Image(ctype), SymName(sym));
  876. X  debug1(DCR, DD, "  x = %s", EchoObject(x));
  877. X  ifdebug(DCR, DD, DebugObject(cs));
  878. X
  879. X  /* delete as much of x as possible */
  880. X  Child(tag, NextDown(Down(x)));
  881. X  DeleteLink(NextDown(Down(x)));
  882. X  if( Up(x) == x )  DisposeObject(x);
  883. X
  884. X  switch( ctype )
  885. X  {
  886. X    case GALL_FOLL:
  887. X    case GALL_PREC:
  888. X
  889. X      /* find key of the galley, if any */
  890. X      val = tag;  key = nil;
  891. X      for( link = Down(val);  link != val;  link = NextDown(link) )
  892. X      {    Child(par, link);
  893. X    if( type(par) == PAR && (is_key(actual(par)) || is_tag(actual(par))) )
  894. X    { assert( Down(par) != par, "CrossSequence: PAR child!" );
  895. X      Child(key, Down(par));
  896. X      key = ReplaceWithTidy(key);
  897. X    }
  898. X      }
  899. X
  900. X      /* write out the galley */
  901. X      str = FileName(file_num(fpos(val)));
  902. X      dfnum = FileNum(str, DATA_SUFFIX);
  903. X      if( dfnum == NO_FILE )
  904. X    dfnum = DefineFile(str, DATA_SUFFIX, &fpos(val),
  905. X      DATABASE_FILE, SOURCE_PATH);
  906. X      AppendToFile(val, dfnum, &dfpos);
  907. X
  908. X      /* determine the sequence number or string of this galley */
  909. X      if( key == nil )
  910. X      {    ++gall_seq(cs);
  911. X    StringCopy(buff, StringFiveInt(gall_seq(cs)));
  912. X    seq = buff;
  913. X      }
  914. X      else if( !is_word(type(key)) )
  915. X      {    Error(WARN, &fpos(key), "%s parameter is not a word", KW_KEY);
  916. X    seq = STR_BADKEY;
  917. X      }
  918. X      else if( StringEqual(string(key), STR_EMPTY) )
  919. X      {    Error(WARN, &fpos(key), "%s parameter is empty word", KW_KEY);
  920. X    seq = STR_BADKEY;
  921. X      }
  922. X      else seq = string(key);
  923. X
  924. X      /* either write out the index immediately or store it for later */
  925. X      if( ctype == GALL_PREC )
  926. X      {    if( gall_tag(cs) == nil )
  927. X    { Error(WARN, &fpos(val), "no %s precedes this %s%s%s",
  928. X        SymName(sym), SymName(sym), KW_CROSS, KW_PRECEDING);
  929. X      debug0(DCR, DD, "  ... so substituting \"none\"");
  930. X      gall_tag(cs) = MakeWord(WORD, STR_NONE, &fpos(val));
  931. X    }
  932. X    assert( is_word(type(gall_tag(cs))) &&
  933. X        !StringEqual(string(gall_tag(cs)), STR_EMPTY),
  934. X            "CrossSequence: gall_tag!" );
  935. X    debug3(DCR, D, "  inserting galley (prec) %s&%s %s", SymName(sym),
  936. X      string(gall_tag(cs)), seq);
  937. X    DbInsert(NewCrossDb, TRUE, sym, string(gall_tag(cs)), seq,
  938. X            dfnum, (long) dfpos);
  939. X      }
  940. X      else
  941. X      {    tmp = MakeWord(WORD, seq, &fpos(val));
  942. X    gall_rec(tmp) = TRUE;
  943. X    file_num(fpos(tmp)) = dfnum;
  944. X    gall_pos(tmp) = dfpos;
  945. X    Link(cs, tmp);
  946. X    debug2(DCR, D, "  saving galley (foll) %s&? %s", SymName(sym), seq);
  947. X      }
  948. X      DisposeObject(val);
  949. X      break;
  950. X
  951. X
  952. X    case GALL_TARG:
  953. X
  954. X      if( gall_tag(cs) != nil )  DisposeObject(gall_tag(cs));
  955. X      if( !is_word(type(tag)) || StringEqual(string(tag), STR_EMPTY) )
  956. X      {
  957. X    debug2(DCR, DD, "  GALL_TARG %s put none for %s",
  958. X      SymName(sym), EchoObject(tag));
  959. X    DisposeObject(tag);
  960. X    gall_tag(cs) = MakeWord(WORD, STR_NONE, no_fpos);
  961. X      }
  962. X      else gall_tag(cs) = tag;
  963. X      debug2(DCR, D, "  have new %s gall_targ %s", SymName(sym),
  964. X      EchoObject(gall_tag(cs)));
  965. X      for( link = Down(cs);  link != cs;  link = NextDown(link) )
  966. X      {    Child(y, link);
  967. X    assert( is_word(type(y)) && !StringEqual(string(y), STR_EMPTY),
  968. X                "CrossSequence: GALL_TARG y!" );
  969. X    if( gall_rec(y) )
  970. X    {
  971. X      debug3(DCR, D, "  inserting galley (foll) %s&%s %s", SymName(sym),
  972. X        string(gall_tag(cs)), string(y));
  973. X      DbInsert(NewCrossDb, TRUE, sym, string(gall_tag(cs)), string(y),
  974. X            file_num(fpos(y)), (long) gall_pos(y));
  975. X      link = PrevDown(link);
  976. X      DisposeChild(NextDown(link));
  977. X    }
  978. X      }
  979. X      break;
  980. X
  981. X
  982. X    case CROSS_PREC:
  983. X
  984. X      if( target_state(cs) == NO_TARGET )
  985. X      {    Error(WARN, &fpos(tag), "no invokation of %s precedes this %s%s%s",
  986. X        SymName(sym), SymName(sym), KW_CROSS, KW_PRECEDING);
  987. X    break;
  988. X      }
  989. X      if( target_state(cs) == SEEN_TARGET )
  990. X      {
  991. X    debug2(DCR, D, "  inserting %s cross_targ %s",
  992. X      SymName(sym), target_val(cs));
  993. X    AppendToFile(target_val(cs), target_file(cs), &target_pos(cs));
  994. X    DisposeObject(target_val(cs));
  995. X    target_val(cs) = nil;
  996. X    target_state(cs) = WRITTEN_TARGET;
  997. X      }
  998. X      if( !is_word(type(tag)) || StringEqual(string(tag), STR_EMPTY) )
  999. X      {
  1000. X    debug2(DCR, DD, "  GALL_TARG %s put none for %s", SymName(sym),
  1001. X        EchoObject(tag));
  1002. X    DisposeObject(tag);
  1003. X    tag = MakeWord(WORD, STR_NONE, no_fpos);
  1004. X      }
  1005. X      debug3(DCR, D, "  inserting cross (prec) %s&%s %s", SymName(sym),
  1006. X        string(tag), "0");
  1007. X      DbInsert(NewCrossDb, FALSE, sym, string(tag), STR_ZERO,
  1008. X    target_file(cs), (long) target_pos(cs));
  1009. X      DisposeObject(tag);
  1010. X      break;
  1011. X
  1012. X
  1013. X    case CROSS_FOLL:
  1014. X
  1015. X      if( !is_word(type(tag)) )
  1016. X      {    Error(WARN, &fpos(tag), "tag of %s is not a simple word",
  1017. X        SymName(symb(cs)));
  1018. X    debug1(DCR, DD, "  tag = %s", EchoObject(tag));
  1019. X      }
  1020. X      else if( StringEqual(string(tag), STR_EMPTY) )
  1021. X      {
  1022. X        debug1(DCR, D, "  ignoring cross (foll) %s (empty tag)", SymName(sym));
  1023. X      }
  1024. X      else
  1025. X      { Link(cs, tag);
  1026. X    gall_rec(tag) = FALSE;
  1027. X        debug3(DCR, D, "  storing cross (foll) %s&%s %s", SymName(sym),
  1028. X        string(tag), "?");
  1029. X      }
  1030. X      break;
  1031. X
  1032. X
  1033. X    case CROSS_TARG:
  1034. X
  1035. X      /* get rid of old target, if any, and add new one */
  1036. X      if( target_state(cs) == SEEN_TARGET )
  1037. X      {
  1038. X    debug2(DCR, D, "  disposing unused %s cross_targ %s", SymName(sym),
  1039. X      target_val(cs));
  1040. X    DisposeObject(target_val(cs));
  1041. X      }
  1042. X      debug2(DCR, D, "  remembering new %s cross_targ %s", SymName(sym),
  1043. X    EchoObject(tag));
  1044. X      target_val(cs) = tag;
  1045. X      assert( Up(tag) == tag, "CrossSeq: Up(tag)!" );
  1046. X      str = FileName(file_num(fpos(tag)));
  1047. X      target_file(cs) = FileNum(str, DATA_SUFFIX);
  1048. X      if( target_file(cs) == NO_FILE )
  1049. X    target_file(cs) = DefineFile(str, DATA_SUFFIX, &fpos(tag),
  1050. X                    DATABASE_FILE, SOURCE_PATH);
  1051. X      target_state(cs) = SEEN_TARGET;
  1052. X
  1053. X      /* store tag of the galley, if any */
  1054. X      tag = nil;
  1055. X      assert( type(target_val(cs)) == CLOSURE, "CrossSequence: target_val!" );
  1056. X      link = Down(target_val(cs));
  1057. X      for( ;  link != target_val(cs);  link = NextDown(link) )
  1058. X      {    Child(par, link);
  1059. X    if( type(par) == PAR && is_tag(actual(par)) )
  1060. X    { assert( Down(par) != par, "CrossSequence: Down(PAR)!" );
  1061. X      Child(tag, Down(par));
  1062. X      tag = ReplaceWithTidy(tag);
  1063. X      if( !is_word(type(tag)) )
  1064. X      { Error(WARN, &fpos(tag), "%s tag is not a simple word",
  1065. X            SymName(actual(target_val(cs))));
  1066. X        debug1(DCR, DD, "  tag = %s", EchoObject(tag));
  1067. X      }
  1068. X      else if( StringEqual(string(tag), STR_EMPTY) )
  1069. X      {
  1070. X            debug1(DCR, D, "  ignoring cross (own tag) %s (empty tag)",
  1071. X        SymName(sym));
  1072. X      }
  1073. X      else
  1074. X      { Link(cs, tag);
  1075. X        gall_rec(tag) = FALSE;
  1076. X            debug3(DCR, D, "  storing cross (own tag) %s&%s %s", SymName(sym),
  1077. X        string(tag), "?");
  1078. X      }
  1079. X      break;
  1080. X    }
  1081. X      }
  1082. X
  1083. X      /* if new target is already writable, write it */
  1084. X      if( Down(cs) != cs )
  1085. X      {
  1086. X    debug2(DCR, D, "  writing %s cross_targ %s", SymName(sym),
  1087. X        EchoObject(target_val(cs)));
  1088. X    AppendToFile(target_val(cs), target_file(cs), &target_pos(cs));
  1089. X    DisposeObject(target_val(cs));
  1090. X    for( link = Down(cs);  link != cs;  link = NextDown(link) )
  1091. X    { Child(tag, link);
  1092. X      assert( is_word(type(tag)) && !StringEqual(string(tag), STR_EMPTY),
  1093. X            "CrossSeq: non-WORD or empty tag!" );
  1094. X      if( !gall_rec(tag) )
  1095. X      {
  1096. X        debug3(DCR, D, "  inserting cross (foll) %s&%s %s", SymName(sym),
  1097. X          string(tag), "0");
  1098. X        DbInsert(NewCrossDb, FALSE, sym, string(tag),
  1099. X          STR_ZERO, target_file(cs), (long) target_pos(cs));
  1100. X        link = PrevDown(link);
  1101. X        DisposeChild(NextDown(link));
  1102. X      }
  1103. X    }
  1104. X    target_state(cs) = WRITTEN_TARGET;
  1105. X      }
  1106. X      break;
  1107. X
  1108. X
  1109. X    default:
  1110. X
  1111. X      Error(INTERN, &fpos(tag), "CrossSequence: ctype = %s", Image(ctype));
  1112. X      break;
  1113. X
  1114. X  } /* end switch */
  1115. X  debug0(DCR, D, "CrossSequence returning.");
  1116. X  debug0(DCR, DD, "   cs =");
  1117. X  ifdebug(DCR, DD, DebugObject(cs));
  1118. X} /* end CrossSequence */
  1119. X
  1120. X
  1121. X/*@::CrossClose()@************************************************************/
  1122. X/*                                                                           */
  1123. X/*  CrossClose()                                                             */
  1124. X/*                                                                           */
  1125. X/*  Check for dangling forward references, and convert old cross reference   */
  1126. X/*  database to new one.                                                     */
  1127. X/*                                                                           */
  1128. X/*****************************************************************************/
  1129. X
  1130. XCrossClose()
  1131. X{ OBJECT link, cs, ylink, y, sym;  BOOLEAN g;  int len, count;
  1132. X  FILE_NUM dfnum;  long dfpos, cont;
  1133. X  FULL_CHAR buff[MAX_LINE], seq[MAX_LINE], tag[MAX_LINE];
  1134. X  debug0(DCR, D, "CrossClose()");
  1135. X  ifdebug(DCR, DD, if( RootCross != nil ) DebugObject(RootCross));
  1136. X
  1137. X  /* if suppressing cross referencing, return */
  1138. X  if( !AllowCrossDb )
  1139. X  { debug0(DCR, D, "CrossClose returning (!AllowCrossDb).");
  1140. X    return;
  1141. X  }
  1142. X
  1143. X  /* check for dangling forward references and dispose cross ref structures */
  1144. X  if( RootCross != nil )
  1145. X  { for( link = Down(RootCross);  link != RootCross;  link = NextDown(link) )
  1146. X    { Child(cs, link);
  1147. X      assert( type(cs) == CROSS_SYM, "CrossClose: type(cs)!" );
  1148. X      count = 0;  ylink = Down(cs);
  1149. X      while( ylink != cs && count <= 5 )
  1150. X      {    Child(y, ylink);
  1151. X    Error(WARN, &fpos(y), "no invokation of %s follows this %s%s%s",
  1152. X      SymName(symb(cs)), SymName(symb(cs)), KW_CROSS, KW_FOLLOWING);
  1153. X    debug2(DCR, D, "gall_rec(y) = %s, y = %s",
  1154. X      bool(gall_rec(y)), EchoObject(y));
  1155. X    if( gall_rec(y) )
  1156. X      DbInsert(NewCrossDb, TRUE, symb(cs), STR_NONE,
  1157. X        string(y), file_num(fpos(y)), (long) gall_pos(y));
  1158. X    count++;  ylink = NextDown(ylink);
  1159. X      }
  1160. X      if( ylink != cs )  Error(WARN, no_fpos, "and more undefined %s%s%s",
  1161. X                SymName(symb(cs)), KW_CROSS, KW_FOLLOWING);
  1162. X      ifdebug(ANY, D,
  1163. X    if( target_state(cs) == SEEN_TARGET )  DisposeObject(target_val(cs));
  1164. X    if( gall_tag(cs) != nil )  DisposeObject(gall_tag(cs));
  1165. X      );
  1166. X    }
  1167. X    ifdebug(ANY, D, DisposeObject(RootCross); );
  1168. X  }
  1169. X
  1170. X  /* add to NewCrossDb those entries of OldCrossDb from other source files */
  1171. X  cont = 0L;  len = StringLength(DATA_SUFFIX);
  1172. X  while( DbRetrieveNext(OldCrossDb, &g, &sym, tag, seq, &dfnum, &dfpos, &cont) )
  1173. X  { if( g ) continue;
  1174. X    StringCopy(buff, FileName(dfnum));
  1175. X    StringCopy(&buff[StringLength(buff) - len], STR_EMPTY);
  1176. X    if( FileNum(buff, STR_EMPTY) == NO_FILE )
  1177. X      DbInsert(NewCrossDb, FALSE, sym, tag, seq, dfnum, dfpos);
  1178. X  }
  1179. X
  1180. X  /* close OldCrossDb's .li file so that NewCrossDb can use its name */
  1181. X  DbClose(OldCrossDb);
  1182. X
  1183. X  /* make NewCrossDb readable, for next run */
  1184. X  DbConvert(NewCrossDb, TRUE);
  1185. X
  1186. X  debug0(DCR, D, "CrossClose returning.");
  1187. X} /* end CrossClose */
  1188. END_OF_FILE
  1189.   if test 26605 -ne `wc -c <'z10.c'`; then
  1190.     echo shar: \"'z10.c'\" unpacked with wrong size!
  1191.   fi
  1192.   # end of 'z10.c'
  1193. fi
  1194. if test -f 'z33.c' -a "${1}" != "-c" ; then 
  1195.   echo shar: Will not clobber existing file \"'z33.c'\"
  1196. else
  1197.   echo shar: Extracting \"'z33.c'\" \(25577 characters\)
  1198.   sed "s/^X//" >'z33.c' <<'END_OF_FILE'
  1199. X/*@z33.c:Database Service:OldCrossDb(), NewCrossDb(), SymToNum()@*************/
  1200. X/*                                                                           */
  1201. X/*  LOUT: A HIGH-LEVEL LANGUAGE FOR DOCUMENT FORMATTING (VERSION 2.05)       */
  1202. X/*  COPYRIGHT (C) 1993 Jeffrey H. Kingston                                   */
  1203. X/*                                                                           */
  1204. X/*  Jeffrey H. Kingston (jeff@cs.su.oz.au)                                   */
  1205. X/*  Basser Department of Computer Science                                    */
  1206. X/*  The University of Sydney 2006                                            */
  1207. X/*  AUSTRALIA                                                                */
  1208. X/*                                                                           */
  1209. X/*  This program is free software; you can redistribute it and/or modify     */
  1210. X/*  it under the terms of the GNU General Public License as published by     */
  1211. X/*  the Free Software Foundation; either version 1, or (at your option)      */
  1212. X/*  any later version.                                                       */
  1213. X/*                                                                           */
  1214. X/*  This program is distributed in the hope that it will be useful,          */
  1215. X/*  but WITHOUT ANY WARRANTY; without even the implied warranty of           */
  1216. X/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            */
  1217. X/*  GNU General Public License for more details.                             */
  1218. X/*                                                                           */
  1219. X/*  You should have received a copy of the GNU General Public License        */
  1220. X/*  along with this program; if not, write to the Free Software              */
  1221. X/*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                */
  1222. X/*                                                                           */
  1223. X/*  FILE:         z33.c                                                      */
  1224. X/*  MODULE:       Database Service                                           */
  1225. X/*  EXTERNS:      OldCrossDb, NewCrossDb, DbCreate(), DbInsert(),            */
  1226. X/*                DbConvert(), DbClose(), DbLoad(), DbRetrieve(),            */
  1227. X/*                DbRetrieveNext()                                           */
  1228. X/*                                                                           */
  1229. X/*****************************************************************************/
  1230. X#include "externs"
  1231. X
  1232. X
  1233. X/*****************************************************************************/
  1234. X/*                                                                           */
  1235. X/*  OldCrossDb     Database containing cross references from previous run.   */
  1236. X/*  NewCrossDb     Writable database of cross references from this run.      */
  1237. X/*                                                                           */
  1238. X/*****************************************************************************/
  1239. X
  1240. XOBJECT OldCrossDb, NewCrossDb;
  1241. X
  1242. X
  1243. X/*****************************************************************************/
  1244. X/*                                                                           */
  1245. X/*  #define SymToNum(db, sym, num, gall)                                     */
  1246. X/*                                                                           */
  1247. X/*  Set num to the number used to refer to sym in database db.  If sym is    */
  1248. X/*  not currently referred to in db, create a new number and record sym.     */
  1249. X/*  If gall is true, sym is the target of galleys stored in this database.   */
  1250. X/*  Store in boolean fields db_targ(link) and is_extern_target(sym).         */
  1251. X/*                                                                           */
  1252. X/*****************************************************************************/
  1253. X
  1254. X#define SymToNum(db, sym, num, gall)                    \
  1255. X{ OBJECT link, yy;  int count;                        \
  1256. X  count = 0;                                \
  1257. X  for( link = Down(db);  link != db;  link = NextDown(link) )        \
  1258. X  { Child(yy, link);                            \
  1259. X    assert(type(yy)==CROSS_SYM || type(yy)==ACAT, "SymToNum: yy!");    \
  1260. X    if( type(yy) != CROSS_SYM )  continue;                \
  1261. X    if( symb(yy) == sym )  break;                    \
  1262. X    if( number(link) > count )  count = number(link);            \
  1263. X  }                                    \
  1264. X  if( link == db )                            \
  1265. X  { if( cross_sym(sym) == nil )  CrossInit(sym);            \
  1266. X    link = Link(db, cross_sym(sym));                    \
  1267. X    number(link) = count + 1;                        \
  1268. X    db_targ(link) = FALSE;                        \
  1269. X  }                                    \
  1270. X  num = number(link);                            \
  1271. X  if( gall )  db_targ(link) = is_extern_target(sym) =            \
  1272. X                uses_extern_target(sym) = TRUE;        \
  1273. X} /* end SymToNum */
  1274. X
  1275. X
  1276. X/*@::NumToSym(), DbCreate()@**************************************************/
  1277. X/*                                                                           */
  1278. X/*  #define NumToSym(db, num, sym)                                           */
  1279. X/*                                                                           */
  1280. X/*  Set sym to the symbol which is referred to in database db by num.        */
  1281. X/*                                                                           */
  1282. X/*****************************************************************************/
  1283. X
  1284. X#define NumToSym(db, num, sym)                        \
  1285. X{ OBJECT link, y;                            \
  1286. X  for( link = Down(db);  link != db;  link = NextDown(link) )        \
  1287. X  { Child(y, link);                            \
  1288. X    if( type(y) == CROSS_SYM && number(link) == num )  break;        \
  1289. X  }                                    \
  1290. X  if( link == db )  Error(INTERN, &fpos(db), "NumToSym: no sym!");    \
  1291. X  assert( type(y) == CROSS_SYM, "NumToSym: y!" );            \
  1292. X  sym = symb(y);                            \
  1293. X} /* end NumToSym */
  1294. X
  1295. X
  1296. X/*****************************************************************************/
  1297. X/*                                                                           */
  1298. X/*  OBJECT DbCreate(x)                                                       */
  1299. X/*                                                                           */
  1300. X/*  Create a new writable database with name (i.e. file stem) x and file     */
  1301. X/*  position fpos for error messages.                                        */
  1302. X/*                                                                           */
  1303. X/*****************************************************************************/
  1304. X
  1305. XOBJECT DbCreate(x)
  1306. XOBJECT x;
  1307. X{ OBJECT db = x;
  1308. X  debug1(DBS, D, "DbCreate(%s)", string(db));
  1309. X  assert( is_word(type(x)), "DbCreate: !is_word(type(x))" );
  1310. X  reading(db) = FALSE;  filep(db) = null;
  1311. X  debug1(DBS, D, "DbCreate returning %s", EchoObject(db));
  1312. X  return db;
  1313. X} /* end DbCreate */
  1314. X
  1315. X
  1316. X/*@::DbInsert()@**************************************************************/
  1317. X/*                                                                           */
  1318. X/*  DbInsert(db, gall, sym, tag, seq, dfnum, dfpos)                          */
  1319. X/*                                                                           */
  1320. X/*  Insert a new entry into writable database db.  The primary key of the    */
  1321. X/*  entry has these three parts:                                             */
  1322. X/*                                                                           */
  1323. X/*      gall        TRUE if inserting a galley                               */
  1324. X/*      sym         The symbol which is the target of this entry             */
  1325. X/*      tag         The tag of this target (must be a non-null string)       */
  1326. X/*                                                                           */
  1327. X/*  There is also an auxiliary key, seq, which enforces an ordering on       */
  1328. X/*  entries with equal primary keys but is not itself ever retrieved.  This  */
  1329. X/*  ordering is used for sorted galleys.  The value of the entry has the     */
  1330. X/*  following parts:                                                         */
  1331. X/*                                                                           */
  1332. X/*      dfnum       The file containing the object                           */
  1333. X/*      dfpos       The position of the object in that file                  */
  1334. X/*                                                                           */
  1335. X/*****************************************************************************/
  1336. X
  1337. XDbInsert(db, gall, sym, tag, seq, dfnum, dfpos)
  1338. XOBJECT db;  BOOLEAN gall;  OBJECT sym;  FULL_CHAR *tag, *seq;
  1339. XFILE_NUM dfnum;  long dfpos;
  1340. X{ int symnum;
  1341. X  FULL_CHAR buff[MAX_LINE];
  1342. X  assert( is_word(type(db)), "DbInsert: db!" );
  1343. X  assert( tag[0] != '\0', "DbInsert: null tag!" );
  1344. X  assert( seq[0] != '\0', "DbInsert: null seq!" );
  1345. X  ifdebug(DPP, D, ProfileOn("DbInsert"));
  1346. X  debug6(DBS, D, "DbInsert(%s, %s, %s, %s, %s, %s, dfpos)",
  1347. X    string(db), bool(gall), SymName(sym), tag, seq,
  1348. X    dfnum == NO_FILE ? AsciiToFull(".") : FileName(dfnum));
  1349. X  if( reading(db) )  Error(INTERN, &fpos(db), "insert into reading database!");
  1350. X  if( filep(db) == null )
  1351. X  { if( StringLength(string(db)) + StringLength(NEW_INDEX_SUFFIX) >= MAX_LINE )
  1352. X      Error(FATAL, no_fpos, "database file name %s%s is too long",
  1353. X    string(db), NEW_INDEX_SUFFIX);
  1354. X    StringCopy(buff, string(db));
  1355. X    StringCat(buff, NEW_INDEX_SUFFIX);
  1356. X    filep(db) = StringFOpen(buff, "w");
  1357. X    if( filep(db) == null )
  1358. X      Error(FATAL, &fpos(db), "cannot write to database file %s", buff);
  1359. X  }
  1360. X  if( dfnum != NO_FILE )
  1361. X  { StringCopy(buff, FileName(dfnum));
  1362. X    StringCopy(&buff[StringLength(buff)-StringLength(DATA_SUFFIX)], STR_EMPTY);
  1363. X  }
  1364. X  else StringCopy(buff, AsciiToFull("."));
  1365. X  SymToNum(db, sym, symnum, gall);
  1366. X  ifdebug(DBS, D,
  1367. X  fprintf(stderr, "  -> %s%d&%s\t%s\t%ld\t%s\n", gall ? "&" : "", symnum,
  1368. X    tag, seq, dfpos, buff);
  1369. X  );
  1370. X  fprintf(filep(db), "%s%d&%s\t%s\t%ld\t%s\n", gall ? "&" : "", symnum,
  1371. X    tag, seq, dfpos, buff);
  1372. X  debug0(DBS, D, "DbInsert returning.");
  1373. X  ifdebug(DPP, D, ProfileOff("DbInsert"));
  1374. X} /* end DbInsert */
  1375. X
  1376. X
  1377. X/*@::DbConvert(), DbClose()@**************************************************/
  1378. X/*                                                                           */
  1379. X/*  DbConvert(db, full_name)                                                 */
  1380. X/*                                                                           */
  1381. X/*  Convert database db from writable to readable, then dispose it.          */
  1382. X/*  full_name is TRUE if symbols are to be known by their full path name.    */
  1383. X/*                                                                           */
  1384. X/*****************************************************************************/
  1385. X
  1386. XDbConvert(db, full_name)
  1387. XOBJECT db;  BOOLEAN full_name;
  1388. X{ FULL_CHAR oldname[MAX_LINE+10], newname[MAX_LINE];
  1389. X  char buff[2*MAX_LINE + 20];
  1390. X  OBJECT link, y;
  1391. X  ifdebug(DPP, D, ProfileOn("DbConvert"));
  1392. X  debug2(DBS, D, "DbConvert( %d %s )", (int) db,string(db));
  1393. X  if( reading(db) )  Error(INTERN, &fpos(db), "DbConvert: reading database!");
  1394. X  StringCopy(newname, string(db));
  1395. X  StringCat(newname, INDEX_SUFFIX);
  1396. X  StringCopy(oldname, string(db));
  1397. X  StringCat(oldname, NEW_INDEX_SUFFIX);
  1398. X  if( filep(db) != null )
  1399. X  { for( link = Down(db);  link != db;  link = NextDown(link) )
  1400. X    { Child(y, link);
  1401. X      assert( type(y) == CROSS_SYM || type(y) == ACAT, "DbConvert: y!" );
  1402. X      if( type(y) != CROSS_SYM )  continue;
  1403. X      fprintf(filep(db), "%s %d %s\n",
  1404. X    db_targ(link) ? "#target" : "#symbol",
  1405. X    number(link),
  1406. X    full_name ? FullSymName(symb(y), AsciiToFull(" ")) : SymName(symb(y)));
  1407. X    }
  1408. X    fclose(filep(db));
  1409. X    sprintf(buff, "sort -o %s %s", newname, oldname);
  1410. X    system(buff);
  1411. X  }
  1412. X  else StringUnlink(newname);
  1413. X  StringUnlink(oldname);
  1414. X  DeleteNode(db);
  1415. X  debug0(DBS, D, "DbConvert returning.");
  1416. X  ifdebug(DPP, D, ProfileOff("DbConvert"));
  1417. X} /* end DbConvert */
  1418. X
  1419. X
  1420. X/*****************************************************************************/
  1421. X/*                                                                           */
  1422. X/*  DbClose(db)                                                              */
  1423. X/*                                                                           */
  1424. X/*  Close readable database db.                                              */
  1425. X/*                                                                           */
  1426. X/*****************************************************************************/
  1427. X
  1428. XDbClose(db)
  1429. XOBJECT db;
  1430. X{ if( db != nil && filep(db) != NULL )
  1431. X  {  fclose(filep(db));
  1432. X     filep(db) = NULL;
  1433. X  }
  1434. X} /* end DbClose */
  1435. X
  1436. X
  1437. X/*@::DbLoad()@****************************************************************/
  1438. X/*                                                                           */
  1439. X/*  OBJECT DbLoad(stem, fpath, create, symbs)                                */
  1440. X/*                                                                           */
  1441. X/*  Open for reading the database whose index file name is string(stem).li.  */
  1442. X/*  This file has not yet been defined; its search path is fpath.  If it     */
  1443. X/*  will not open and create is true, try creating it from string(stem).ld.  */
  1444. X/*                                                                           */
  1445. X/*  symbs is an ACAT of CLOSUREs showing the symbols that the database may   */
  1446. X/*  contain; or nil if the database may contain any symbol.                  */
  1447. X/*                                                                           */
  1448. X/*****************************************************************************/
  1449. X
  1450. XOBJECT DbLoad(stem, fpath, create, symbs)
  1451. XOBJECT stem;  int fpath;  BOOLEAN create;  OBJECT symbs;
  1452. X{ FILE *fp;  OBJECT db, t, res, tag, par, sym, link, y;
  1453. X  int i, lnum, num, count;  FILE_NUM index_fnum, dfnum;  long dfpos;
  1454. X  BOOLEAN gall;  FULL_CHAR line[MAX_LINE], sym_name[MAX_LINE];
  1455. X  ifdebug(DPP, D, ProfileOn("DbLoad"));
  1456. X  debug3(DBS, D, "DbLoad(%s, %d, %s, -)", string(stem), fpath, bool(create));
  1457. X
  1458. X  /* open or else create index file fp */
  1459. X  index_fnum = DefineFile(string(stem), INDEX_SUFFIX, &fpos(stem), INDEX_FILE,
  1460. X         fpath);
  1461. X  fp = OpenFile(index_fnum, create, FALSE);
  1462. X  if( fp == null && create )
  1463. X  { db = nil;
  1464. X    dfnum = DefineFile(string(stem), DATA_SUFFIX, &fpos(stem),
  1465. X      DATABASE_FILE, DATABASE_PATH);
  1466. X    dfpos = 0L;  LexPush(dfnum, 0, DATABASE_FILE);  t = LexGetToken();
  1467. X    while( type(t) == LBR )
  1468. X    { res = Parse(&t, StartSym, FALSE, FALSE);
  1469. X      if( t != nil || type(res) != CLOSURE )  Error(FATAL, &fpos(res),
  1470. X    "syntax error in database file %s", FileName(dfnum));
  1471. X      assert( symbs != nil, "DbLoad: create && symbs == nil!" );
  1472. X      if( symbs != nil )
  1473. X      {    for( link = Down(symbs);  link != symbs;  link = NextDown(link) )
  1474. X    { Child(y, link);
  1475. X      if( type(y) == CLOSURE && actual(y) == actual(res) )  break;
  1476. X    }
  1477. X    if( link == symbs )  Error(FATAL, &fpos(res),
  1478. X      "%s found in database but not declared in %s line",
  1479. X      SymName(actual(res)), KW_DATABASE);
  1480. X      }
  1481. X      for( tag = nil, link = Down(res);  link != res;  link = NextDown(link) )
  1482. X      {    Child(par, link);
  1483. X    if( type(par) == PAR && is_tag(actual(par)) && Down(par) != par )
  1484. X    { Child(tag, Down(par));
  1485. X      break;
  1486. X    }
  1487. X      }
  1488. X      if( tag == nil )
  1489. X    Error(FATAL, &fpos(res), "database symbol %s has no tag", SymName(res));
  1490. X      tag = ReplaceWithTidy(tag);
  1491. X      if( !is_word(type(tag)) )
  1492. X    Error(FATAL, &fpos(res), "database symbol tag is not a simple word");
  1493. X      if( StringEqual(string(tag), STR_EMPTY) )
  1494. X    Error(FATAL, &fpos(res), "database symbol tag is an empty word");
  1495. X      if( db == nil )
  1496. X      {    StringCopy(line, FileName(dfnum));
  1497. X    i = StringLength(line) - StringLength(INDEX_SUFFIX);
  1498. X    assert( i > 0, "DbLoad: FileName(dfnum) (1)!" );
  1499. X    StringCopy(&line[i], STR_EMPTY);
  1500. X    db = DbCreate(MakeWord(WORD, line, &fpos(stem)));
  1501. X      }
  1502. X      DbInsert(db, FALSE, actual(res), string(tag), STR_ZERO, NO_FILE, dfpos);
  1503. X      DisposeObject(res);  dfpos = LexNextTokenPos();  t = LexGetToken();
  1504. X    }
  1505. X    if( type(t) != END )
  1506. X      Error(FATAL, &fpos(t), "%s or end of file expected here", KW_LBR);
  1507. X    LexPop();
  1508. X    if( db == nil )
  1509. X    { StringCopy(line, FileName(dfnum));
  1510. X      i = StringLength(line) - StringLength(INDEX_SUFFIX);
  1511. X      assert( i > 0, "DbLoad: FileName(dfnum) (2)!" );
  1512. X      StringCopy(&line[i], STR_EMPTY);
  1513. X      db = DbCreate(MakeWord(WORD, line, &fpos(stem)));
  1514. X    }
  1515. X    DbConvert(db, FALSE);
  1516. X    if( (fp = OpenFile(index_fnum, FALSE, FALSE)) == null )
  1517. X      Error(FATAL, &fpos(db), "cannot open database file %s",
  1518. X      FileName(index_fnum));
  1519. X  }
  1520. X
  1521. X  /* set up database record */
  1522. X  StringCopy(line, FileName(index_fnum));
  1523. X  i = StringLength(line) - StringLength(INDEX_SUFFIX);
  1524. X  assert( i > 0, "DbLoad: FileName(index_fnum)!" );
  1525. X  StringCopy(&line[i], STR_EMPTY);
  1526. X  db = MakeWord(WORD, line, &fpos(stem));
  1527. X  reading(db) = TRUE;  filep(db) = fp;
  1528. X  if( symbs != nil )
  1529. X  { assert( type(symbs) = ACAT, "DbLoad: type(symbs)!" );
  1530. X    Link(db, symbs);
  1531. X  }
  1532. X  if( fp == null )
  1533. X  { debug1(DBS, D, "DbLoad returning (empty) %s", string(db));
  1534. X    ifdebug(DPP, D, ProfileOff("DbLoad"));
  1535. X    return db;
  1536. X  }
  1537. X
  1538. X  /* read header lines of index file, find its symbols */
  1539. X  left_pos(db) = 0;  lnum = 0;
  1540. X  while( StringFGets(line, MAX_LINE, fp) != NULL && line[0] == '#' )
  1541. X  { lnum++;
  1542. X    left_pos(db) = (int) ftell(fp);
  1543. X    gall = StringBeginsWith(line, AsciiToFull("#target "));
  1544. X    sscanf( (char *) line, gall ? "#target %d" : "#symbol %d", &num);
  1545. X    for( i = 8;  line[i] != CH_SPACE && line[i] != '\0';  i++ );
  1546. X    if( symbs == nil )
  1547. X    {
  1548. X      /* any symbols are possible, full path names in index file required */
  1549. X      count = 0;  sym = StartSym;
  1550. X      while( line[i] != CH_NEWLINE && line[i] != '\0' )
  1551. X      {    PushScope(sym, FALSE, FALSE);  count++;
  1552. X    sscanf( (char *) &line[i+1], "%s", sym_name);
  1553. X    sym = SearchSym(sym_name, StringLength(sym_name));
  1554. X    i += StringLength(sym_name) + 1;
  1555. X      }
  1556. X      for( i = 1;  i <= count;  i++ )  PopScope();
  1557. X    }
  1558. X    else
  1559. X    {
  1560. X      /* only symbs symbols possible, full path names not required */
  1561. X      sym = nil;
  1562. X      sscanf( (char *) &line[i+1], "%s", sym_name);
  1563. X      for( link = Down(symbs);  link != symbs;  link = NextDown(link) )
  1564. X      {    Child(y, link);
  1565. X    assert( type(y) == CLOSURE, "DbLoad: type(y) != CLOSURE!" );
  1566. X    if( StringEqual(sym_name, SymName(actual(y))) )
  1567. X    { sym = actual(y);
  1568. X      break;
  1569. X    }
  1570. X      }
  1571. X    }
  1572. X    if( sym != nil && sym != StartSym )
  1573. X    { if( cross_sym(sym) == nil )  CrossInit(sym);
  1574. X      link = Link(db, cross_sym(sym));
  1575. X      number(link) = num;  db_targ(link) = gall;
  1576. X      if( gall )  is_extern_target(sym) = uses_extern_target(sym) = TRUE;
  1577. X    }
  1578. X    else
  1579. X    { Error(WARN, &fpos(db), "undefined symbol in database file %s (line %d)",
  1580. X            FileName(index_fnum), lnum);
  1581. X      debug1(DBS, D, "DbLoad returning %s (error)", string(db));
  1582. X      fclose(filep(db));  filep(db) = null;  /* effectively an empty database */
  1583. X      ifdebug(DPP, D, ProfileOff("DbLoad"));
  1584. X      return db;
  1585. X    }
  1586. X  }
  1587. X  debug1(DBS, D, "DbLoad returning %s", string(db));
  1588. X  ifdebug(DPP, D, ProfileOff("DbLoad"));
  1589. X  return db;
  1590. X} /* end DbLoad */
  1591. X
  1592. X
  1593. X/*@::SearchFile()@************************************************************/
  1594. X/*                                                                           */
  1595. X/*  static BOOLEAN SearchFile(fp, left, right, str, line)                    */
  1596. X/*                                                                           */
  1597. X/*  File fp is a text file.  left is the beginning of a line, right is the   */
  1598. X/*  end of a line.   Search the file by binary search for a line beginning   */
  1599. X/*  with str.  If found, return it in line, else return FALSE.               */
  1600. X/*                                                                           */
  1601. X/*****************************************************************************/
  1602. X
  1603. Xstatic BOOLEAN SearchFile(fp, left, right, str, line)
  1604. XFILE *fp;  int left, right;  FULL_CHAR *str, *line;
  1605. X{ int l, r, mid, mid_end;  FULL_CHAR buff[MAX_LINE];  BOOLEAN res;
  1606. X  ifdebug(DPP, D, ProfileOn("SearchFile"));
  1607. X  debug3(DBS, DD, "SearchFile(fp, %d, %d, %s, line)", left, right, str);
  1608. X
  1609. X  l = left;  r = right;
  1610. X  while( l <= r )
  1611. X  {
  1612. X    /* loop invt: (l==0 or fp[l-1]==CH_NEWLINE) and (fp[r] == CH_NEWLINE)    */
  1613. X    /* and first key >= str lies in the range fp[l..r+1]                     */
  1614. X
  1615. X    /* find line near middle of the range; mid..mid_end brackets it */
  1616. X    debug2(DBS, DD, "  start loop: l = %d, r = %d", l, r);
  1617. X    mid = (l + r)/2;
  1618. X    fseek(fp, (long) mid, 0);
  1619. X    do { mid++; } while( getc(fp) != CH_NEWLINE );
  1620. X    if( mid == r + 1 )
  1621. X    { mid = l;
  1622. X      fseek(fp, (long) mid, 0);
  1623. X    }
  1624. X    StringFGets(line, MAX_LINE, fp);
  1625. X    mid_end = (int) ftell(fp) - 1;
  1626. X    debug3(DBS, DD, "  mid: %d, mid_end: %d, line: %s", mid, mid_end, line);
  1627. X    assert( l <= mid,      "SearchFile: l > mid!"        );
  1628. X    assert( mid < mid_end, "SearchFile: mid >= mid_end!" );
  1629. X    assert( mid_end <= r,  "SearchFile: mid_end > r!"    );
  1630. X
  1631. X    /* compare str with this line and prepare next step */
  1632. X    debug2(DBS, DD, "  comparing key %s with line %s", str, line);
  1633. X    if( StringLessEqual(str, line) )  r = mid - 1;
  1634. X    else l = mid_end + 1;
  1635. X  } /* end while */
  1636. X
  1637. X  /* now first key >= str lies in fp[l]; compare it with str */
  1638. X  if( l < right )
  1639. X  { fseek(fp, (long) l, 0);
  1640. X    StringFGets(line, MAX_LINE, fp);
  1641. X    sscanf( (char *) line, "%s", buff);
  1642. X    res = StringEqual(str, buff);
  1643. X  }
  1644. X  else res = FALSE;
  1645. X  debug1(DBS, DD, "SearchFile returning %s", bool(res));
  1646. X  ifdebug(DPP, D, ProfileOff("SearchFile"));
  1647. X  return res;
  1648. X} /* end SearchFile */
  1649. X
  1650. X
  1651. X/*@::DbRetrieve()@************************************************************/
  1652. X/*                                                                           */
  1653. X/*  BOOLEAN DbRetrieve(db, gall, sym, tag, seq, dfnum, dfpos, cont)          */
  1654. X/*                                                                           */
  1655. X/*  Retrieve the first entry of database db with the given gall, sym and     */
  1656. X/*  tag.  Set *seq, *dfnum, *dfpos to the associated value.                  */
  1657. X/*  Set *cont to a private value for passing to DbRetrieveNext.              */
  1658. X/*                                                                           */
  1659. X/*****************************************************************************/
  1660. X
  1661. XBOOLEAN DbRetrieve(db, gall, sym, tag, seq, dfnum, dfpos, cont)
  1662. XOBJECT db;  BOOLEAN gall;  OBJECT sym;  FULL_CHAR *tag, *seq;
  1663. XFILE_NUM *dfnum;  long *dfpos;  long *cont;
  1664. X{ int symnum;  FULL_CHAR line[MAX_LINE], buff[MAX_LINE];  OBJECT y;
  1665. X  ifdebug(DPP, D, ProfileOn("DbRetrieve"));
  1666. X  debug4(DBS, D, "DbRetrieve(%s, %s%s&%s)", string(db), gall ? "&" : "",
  1667. X    SymName(sym), tag);
  1668. X  if( !reading(db) || filep(db) == null )
  1669. X  { debug0(DBS, D, "DbRetrieve returning FALSE (empty or not reading)");
  1670. X    ifdebug(DPP, D, ProfileOff("DbRetrieve"));
  1671. X    return FALSE;
  1672. X  }
  1673. X  SymToNum(db, sym, symnum, FALSE);
  1674. X  sprintf( (char *) buff, "%s%d&%s", gall ? "&" : "", symnum, tag);
  1675. X  fseek(filep(db), 0L, 2);
  1676. X  if( !SearchFile(filep(db), (int) left_pos(db), (int) ftell(filep(db)) - 1,
  1677. X    buff, line) )
  1678. X  { debug0(DBS, D, "DbRetrieve returning FALSE (key not present)");
  1679. X    ifdebug(DPP, D, ProfileOff("DbRetrieve"));
  1680. X    return FALSE;
  1681. X  }
  1682. X  sscanf( (char *) line, "%*s\t%s\t%ld\t%[^\n]", seq, dfpos, buff);
  1683. X  if( StringEqual(buff, AsciiToFull(".")) )
  1684. X  { StringCopy(buff, string(db));
  1685. X  }
  1686. X  *dfnum = FileNum(buff, DATA_SUFFIX);
  1687. X  if( *dfnum == NO_FILE )  /* can only occur in cross reference database */
  1688. X    *dfnum = DefineFile(buff, DATA_SUFFIX, &fpos(db),
  1689. X      DATABASE_FILE, SOURCE_PATH);
  1690. X  *cont = ftell(filep(db));
  1691. X  Child(y, Down(db));
  1692. X  debug2(DBS, D, "DbRetrieve returning TRUE (in %s at %ld)",
  1693. X    FileName(*dfnum), *dfpos);
  1694. X  ifdebug(DPP, D, ProfileOff("DbRetrieve"));
  1695. X  return TRUE;
  1696. X} /* end DbRetrieve */
  1697. X
  1698. X
  1699. X/*@::DbRetrieveNext()@********************************************************/
  1700. X/*                                                                           */
  1701. X/*  BOOLEAN DbRetrieveNext(db, gall, sym, tag, seq, dfnum, dfpos, cont)      */
  1702. X/*                                                                           */
  1703. X/*  Retrieve the entry of database db pointed to by *cont.                   */
  1704. X/*  Set *gall, *sym, *tag, *seq, *dfnum, *dfpos to the value of the entry.   */
  1705. X/*  Reset *cont to the next entry for passing to the next DbRetrieveNext.    */
  1706. X/*                                                                           */
  1707. X/*****************************************************************************/
  1708. X
  1709. XBOOLEAN DbRetrieveNext(db, gall, sym, tag, seq, dfnum, dfpos, cont)
  1710. XOBJECT db;  BOOLEAN *gall;  OBJECT *sym;  FULL_CHAR *tag, *seq;
  1711. XFILE_NUM *dfnum;  long *dfpos;  long *cont;
  1712. X{ FULL_CHAR line[MAX_LINE], fname[MAX_LINE]; int symnum;
  1713. X  ifdebug(DPP, D, ProfileOn("DbRetrieveNext"));
  1714. X  debug2(DBS, D, "DbRetrieveNext( %s, %ld )", string(db), *cont);
  1715. X  if( !reading(db) )  Error(INTERN, &fpos(db), "DbRetrieveNext: writing!");
  1716. X  if( filep(db) == null )
  1717. X  { debug0(DBS, D, "DbRetrieveNext returning FALSE (empty database)");
  1718. X    ifdebug(DPP, D, ProfileOff("DbRetrieveNext"));
  1719. X    return FALSE;
  1720. X  }
  1721. X  fseek(filep(db), *cont == 0L ? (long) left_pos(db) : *cont, 0);
  1722. X  if( StringFGets(line, MAX_LINE, filep(db)) == NULL )
  1723. X  { debug0(DBS, D, "DbRetrieveNext returning FALSE (no successor)");
  1724. X    ifdebug(DPP, D, ProfileOff("DbRetrieveNext"));
  1725. X    return FALSE;
  1726. X  }
  1727. X  *gall = (line[0] == '&' ? 1 : 0);
  1728. X  sscanf( (char *) &line[*gall], "%d&%s\t%s\t%ld\t%[^\n]",
  1729. X    &symnum, tag, seq,dfpos,fname);
  1730. X  if( StringEqual(fname, AsciiToFull(".")) )
  1731. X  { StringCopy(fname, string(db));
  1732. X  }
  1733. X  *dfnum = FileNum(fname, DATA_SUFFIX);
  1734. X  if( *dfnum == NO_FILE )  /* can only occur in cross reference database */
  1735. X    *dfnum = DefineFile(fname, DATA_SUFFIX, &fpos(db),
  1736. X      DATABASE_FILE, SOURCE_PATH);
  1737. X  NumToSym(db, symnum, *sym);  *cont = ftell(filep(db));
  1738. X  debug2(DBS, D, "DbRetrieveNext returning TRUE (in %s at %ld)",
  1739. X    FileName(*dfnum), *dfpos);
  1740. X  ifdebug(DPP, D, ProfileOff("DbRetrieveNext"));
  1741. X  return TRUE;
  1742. X} /* end DbRetrieveNext */
  1743. END_OF_FILE
  1744.   if test 25577 -ne `wc -c <'z33.c'`; then
  1745.     echo shar: \"'z33.c'\" unpacked with wrong size!
  1746.   fi
  1747.   # end of 'z33.c'
  1748. fi
  1749. echo shar: End of archive 12 \(of 35\).
  1750. cp /dev/null ark12isdone
  1751. MISSING=""
  1752. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 ; do
  1753.     if test ! -f ark${I}isdone ; then
  1754.     MISSING="${MISSING} ${I}"
  1755.     fi
  1756. done
  1757. if test "${MISSING}" = "" ; then
  1758.     echo You have unpacked all 35 archives.
  1759.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1760. else
  1761.     echo You still must unpack the following archives:
  1762.     echo "        " ${MISSING}
  1763. fi
  1764. exit 0
  1765. exit 0 # Just in case...
  1766.