home *** CD-ROM | disk | FTP | other *** search
/ Gold Fish 3 / goldfish_volume_3.bin / files / dev / c / cweb / wmerge.ch < prev    next >
Encoding:
Text File  |  1994-12-14  |  24.2 KB  |  730 lines

  1.                                 -*-Web-*-
  2. This file, WMERGE.CH, is part of CWEB (Version 3.3 [patch level 11]).
  3. It is a changefile for WMERGE.W, Version 3.3.
  4.  
  5. Authors and Contributors:
  6. (H2B) Hans-Hermann Bode, Universität Osnabrück,
  7.   (hhbode@@dosuni1.rz.uni-osnabrueck.de or HHBODE@@DOSUNI1.BITNET).
  8.  
  9. (KG) Klaus Guntermann, TH Darmstadt,
  10.   (guntermann@@iti.informatik.th-darmstadt.de).
  11.  
  12. (AS) Andreas Scherer, RWTH Aachen,
  13.   (scherer@@genesis.informatik.rwth-aachen.de).
  14.  
  15. (BS) Barry Schwartz
  16.   (trashman@@crud.mn.org)
  17.  
  18. Caveat utilitor:  Some of the source code introduced by this change file is
  19. made conditional to the use of specific compilers on specific systems.
  20. This applies to places marked with `#ifdef __MSDOS__' and `#ifdef __TURBOC__',
  21. `#ifdef _AMIGA' and `#ifdef __SASC'.
  22.  
  23. This program is distributed WITHOUT ANY WARRANTY, express or implied.
  24.  
  25. The following copyright notice extends to this changefile only, not to
  26. the masterfile WMERGE.W.
  27.  
  28. Copyright (C) 1991-1993 Hans-Hermann Bode
  29. Copyright (C) 1993,1994 Andreas Scherer
  30. Copyright (C) 1994 Barry Schwartz
  31.  
  32. Permission is granted to make and distribute verbatim copies of this
  33. document provided that the copyright notice and this permission notice
  34. are preserved on all copies.
  35.  
  36. Permission is granted to copy and distribute modified versions of this
  37. document under the conditions for verbatim copying, provided that the
  38. entire resulting derived work is distributed under the terms of a
  39. permission notice identical to this one.
  40.  
  41. Version history:
  42.  
  43. Version    Date        Author    Comment
  44. p2    13 Feb 1992    H2B    First hack.
  45. p3    16 Apr 1992    H2B    Change of |@@i| allowed, /dev/null in case
  46.                 replaced by nul.
  47. p4    21 Jun 1992    H2B    Nothing changed.
  48. p5    21 Jul 1992    H2B    Nothing changed.
  49. p5a    30 Jul 1992    KG    remove one #include <stdio.h>,
  50.                 use strchr instead of index and
  51.                 include <string.h> for |strchr| declaration
  52. p5b    06 Aug 1992    KG    fixed a typo
  53. p6    06 Sep 1992    H2B    Nothing changed.
  54. p6a     15 Mar 1993     AS      SAS/C 6.0 support
  55. p6b     28 Jul 1993     AS      make some functions return `void'
  56. p6c    04 Sep 1993    AS    path searching with CWEBINCLUDE
  57. p7    09 Oct 1993    AS    Updated to CWEB 2.8
  58. p8a    11 Mar 1993    H2B    Converted to master change file.
  59.                 [Not released.]
  60. p8b    15 Apr 1993    H2B    Updated for wmerge.w 3.0beta (?).
  61.                 [Not released.]
  62. p8c    22 Jun 1993    H2B    Updated for final wmerge.w 3.0 (?).
  63. p8d    26 Oct 1993    AS    Incorporated with Amiga version 2.8 [p7].
  64. p8e    04 Nov 1993    AS    New patch level in accordance with CWEB.
  65. p9    18 Nov 1993    AS    Update for wmerge.w 3.1.
  66.     26 Nov 1993    AS    Minor casting problems fixed.
  67. p9c    18 Jan 1994    AS    Version information included.
  68. p9d    09 Aug 1994    AS    Extend buf_size.
  69. p10    12 Aug 1994    AS    Updated for wmerge.w 3.2.
  70. p10a    24 Aug 1994    AS    New patch level.
  71. p10b    11 Oct 1994    AS    Write to check_file and compare results.
  72.     13 Oct 1994    AS    WMerge residentable.
  73.     18 Oct 1994    AS    Some refinements for C++ compilation.
  74.     21 Oct 1994    AS    Use _DEV_NULL instead of the multi-way
  75.                 selection for the NULL path/device.
  76.     12 Nov 1994    AS    Use SEPARATORS instead of the multi-way
  77.                 selection for '/', ':', '\', etc.
  78. p11    03 Dec 1994    AS    Updated for CWEB 3.3.
  79.     13 Dec 1994    AS    Slight correction in `wrap_up()'.
  80. ------------------------------------------------------------------------------
  81. @x l.14
  82. #include <stdio.h>
  83. @y
  84. #include <stdio.h>
  85. #include <string.h>
  86. #include <signal.h>
  87. @#
  88. #ifdef SEPARATORS
  89. char separators[]=SEPARATORS;
  90. #else
  91. char separators[]="://";
  92. #endif
  93. @#
  94. #define PATH_SEPARATOR   separators[0]
  95. #define DIR_SEPARATOR    separators[1]
  96. #define DEVICE_SEPARATOR separators[2]
  97. @z
  98. ------------------------------------------------------------------------------
  99. ANSI
  100. @x l.20
  101. main (ac,av)
  102. int ac; char **av;
  103. @y
  104. int main (int ac, char **av)
  105. @z
  106. ------------------------------------------------------------------------------
  107. @x l.24
  108.   @<Set the default options@>;
  109. @y
  110.   @<Set up the exit trap@>@;
  111.   @<Initialize the memory blocks@>;
  112.   @<Set the default options@>;
  113. @z
  114. ------------------------------------------------------------------------------
  115. @x l.32
  116.   return wrap_up();
  117. @y
  118.   if(out_file!=stdout) {
  119.     fclose(out_file); out_file=NULL;
  120.     @<Update the result when it has changed@>@;
  121.     }
  122.   return wrap_up();
  123. @z
  124. ------------------------------------------------------------------------------
  125. @x l.45
  126. @<Predecl...@>=
  127. extern int strlen(); /* length of string */
  128. extern char* strcpy(); /* copy one string to another */
  129. extern int strncmp(); /* compare up to $n$ string characters */
  130. extern char* strncpy(); /* copy up to $n$ string characters */
  131. @y
  132. @z
  133. ------------------------------------------------------------------------------
  134. @x l.69
  135. ASCII buffer[buf_size]; /* where each line of input goes */
  136. ASCII *buffer_end=buffer+buf_size-2; /* end of |buffer| */
  137. @y
  138. ASCII *buffer; /* where each line of input goes */
  139. ASCII *buffer_end; /* end of |buffer| */
  140. @z
  141. ------------------------------------------------------------------------------
  142. @x l.94
  143. input_ln(fp) /* copies a line into |buffer| or returns 0 */
  144. FILE *fp; /* what file to read from */
  145. @y
  146. int input_ln(@t\1\1@> /* copies a line into |buffer| or returns 0 */
  147.   FILE *fp@t\2\2@>) /* what file to read from */
  148. @z
  149. ------------------------------------------------------------------------------
  150. AmigaDOS allows path names with up to 255 characters.
  151. @x l.127
  152. @d max_file_name_length 60
  153. @y
  154. @d max_file_name_length 256
  155. @z
  156. ------------------------------------------------------------------------------
  157. @x l.136
  158. FILE *file[max_include_depth]; /* stack of non-change files */
  159. FILE *change_file; /* change file */
  160. char file_name[max_include_depth][max_file_name_length];
  161.   /* stack of non-change file names */
  162. char change_file_name[max_file_name_length]; /* name of change file */
  163. char alt_web_file_name[max_file_name_length]; /* alternate name to try */
  164. int line[max_include_depth]; /* number of current line in the stacked files */
  165. @y
  166. FILE **file; /* stack of non-change files */
  167. FILE *change_file; /* change file */
  168. char **file_name; /* stack of non-change file names */
  169. char *change_file_name; /* name of change file */
  170. char *alt_web_file_name; /* alternate name to try */
  171. int *line; /* number of current line in the stacked files */
  172. @z
  173. ------------------------------------------------------------------------------
  174. The third argument of `strncpy' should be of type `size_t' not `long'.
  175. @x l.157
  176. @d lines_dont_match (change_limit-change_buffer != limit-buffer ||
  177.   strncmp(buffer, change_buffer, limit-buffer))
  178. @y
  179. @d lines_dont_match (change_limit-change_buffer != limit-buffer ||
  180.   strncmp(buffer, change_buffer, (size_t)(limit-buffer)))
  181. @z
  182. ------------------------------------------------------------------------------
  183. @x l.161
  184. char change_buffer[buf_size]; /* next line of |change_file| */
  185. @y
  186. char *change_buffer; /* next line of |change_file| */
  187. @z
  188. ------------------------------------------------------------------------------
  189. To avoid some nasty warnings by strict ANSI C compilers we redeclare all
  190. functions to `void' that return no concrete values.
  191. @x l.172
  192. void
  193. prime_the_change_buffer()
  194. @y
  195. void prime_the_change_buffer(void)
  196. @z
  197. ------------------------------------------------------------------------------
  198. The third argument of `strncpy' should be of type `size_t' not `long'.
  199. @x l.215
  200.   strncpy(change_buffer,buffer,limit-buffer+1);
  201. @y
  202.   strncpy(change_buffer,buffer,(size_t)(limit-buffer+1));
  203. @z
  204. ------------------------------------------------------------------------------
  205. Another `void' function, i.e., a procedure.
  206. @x l.231
  207. void
  208. check_change() /* switches to |change_file| if the buffers match */
  209. @y
  210. void check_change(void) /* switches to |change_file| if the buffers match */
  211. @z
  212. ------------------------------------------------------------------------------
  213. Another `void function, i.e., a procedure.
  214. @x l.283
  215. void
  216. reset_input()
  217. @y
  218. void reset_input(void)
  219. @z
  220. ------------------------------------------------------------------------------
  221. SAS/C defines `putchar' as a macro and reports a warning about multiple
  222. macro expansion.  The resulting `wmerge' is definitely wrong; it leaves
  223. every second letter out.  This has been tracked to be a bug in SAS's
  224. <stdio.h>, but unfortunately SAS Institute has quit further development.
  225. @x l.345
  226. void put_line()
  227. {
  228.   char *ptr=buffer;
  229.   while (ptr<limit) putc(*ptr++,out_file);
  230.   putc('\n',out_file);
  231. }
  232. @y
  233. void put_line(void)
  234. {
  235.   char *ptr=buffer;
  236.   while (ptr<limit)
  237.   {
  238.     putc(*ptr,out_file);
  239.     ptr++;
  240.   }
  241.   putc('\n',out_file);
  242. }
  243. @z
  244. ------------------------------------------------------------------------------
  245. @x l.352
  246. @ When an \.{@@i} line is found in the |cur_file|, we must temporarily
  247. stop reading it and start reading from the named include file.  The
  248. \.{@@i} line should give a complete file name with or without
  249. double quotes.
  250. If the environment variable \.{CWEBINPUTS} is set, or if the compiler flag 
  251. of the same name was defined at compile time,
  252. \.{CWEB} will look for include files in the directory thus named, if
  253. it cannot find them in the current directory.
  254. (Colon-separated paths are not supported.)
  255. The remainder of the \.{@@i} line after the file name is ignored.
  256. @y
  257. @ When an \.{@@i} line is found in the |cur_file|, we must temporarily
  258. stop reading it and start reading from the named include file.  The
  259. \.{@@i} line should give a complete file name with or without
  260. double quotes.  The remainder of the \.{@@i} line after the file name
  261. is ignored.  \.{CWEB} will look for include files in standard directories
  262. specified in the environment variable \.{CWEBINPUTS}. Multiple search paths
  263. can be specified by delimiting them with \.{PATH\_SEPARATOR}s.  The given
  264. file is searched for in the current directory first.  You also may include
  265. device names; these must have a \.{DEVICE\_SEPARATOR} as their rightmost
  266. character.
  267. @z
  268. ------------------------------------------------------------------------------
  269. @x l.367
  270.   char temp_file_name[max_file_name_length]; 
  271. @y
  272.   static char *temp_file_name; 
  273. @z
  274. ------------------------------------------------------------------------------
  275. @x l.372
  276.   while (*loc!=' '&&*loc!='\t'&&*loc!='"'&&k<=cur_file_name_end) *k++=*loc++;
  277. @y
  278.   alloc_object(temp_file_name,max_file_name_length,char);
  279.   while (*loc!=' '&&*loc!='\t'&&*loc!='"'&&k<=cur_file_name_end) *k++=*loc++;
  280. @z
  281. ------------------------------------------------------------------------------
  282. CWEB will perform a path search for `@i'nclude files along the environment
  283. variable CWEBINPUTS in case the given file can not be opened in the current
  284. directory or in the absolute path.  The single paths are delimited by
  285. PATH_SEPARATORs.
  286. @x l.380
  287.   kk=getenv("CWEBINPUTS");
  288.   if (kk!=NULL) {
  289.     if ((l=strlen(kk))>max_file_name_length-2) too_long();
  290.     strcpy(temp_file_name,kk);
  291.   }
  292.   else {
  293. #ifdef CWEBINPUTS
  294.     if ((l=strlen(CWEBINPUTS))>max_file_name_length-2) too_long();
  295.     strcpy(temp_file_name,CWEBINPUTS);
  296. #else
  297.     l=0; 
  298. #endif /* |CWEBINPUTS| */
  299.   }
  300.   if (l>0) {
  301.     if (k+l+2>=cur_file_name_end)  too_long();
  302. @.Include file name ...@>
  303.     for (; k>= cur_file_name; k--) *(k+l+1)=*k;
  304.     strcpy(cur_file_name,temp_file_name);
  305.     cur_file_name[l]='/'; /* \UNIX/ pathname separator */
  306.     if ((cur_file=fopen(cur_file_name,"r"))!=NULL) {
  307.       cur_line=0; 
  308.       goto restart; /* success */
  309.     }
  310.   }
  311. @y
  312.   if(0==set_path(include_path,getenv("CWEBINPUTS"))) {
  313.     include_depth--; goto restart; /* internal error */
  314.   }
  315.   path_prefix = include_path;
  316.   while(path_prefix) {
  317.     for(kk=temp_file_name, p=path_prefix, l=0;
  318.       p && *p && *p!=PATH_SEPARATOR;
  319.       *kk++ = *p++, l++);
  320.     if(path_prefix && *path_prefix && *path_prefix!=PATH_SEPARATOR &&
  321.       *--p!=DEVICE_SEPARATOR && *p!=DIR_SEPARATOR) {
  322.       *kk++ = DIR_SEPARATOR; l++;
  323.     }
  324.     if(k+l+2>=cur_file_name_end) too_long(); /* emergency break */
  325.     strcpy(kk,cur_file_name);
  326.     if(cur_file = fopen(temp_file_name,"r")) {
  327.       cur_line=0; goto restart; /* success */
  328.     }
  329.     if(next_path_prefix = strchr(path_prefix,PATH_SEPARATOR))
  330.       path_prefix = next_path_prefix+1;
  331.     else break; /* no more paths to search; no file found */
  332.   }
  333. @z
  334. ------------------------------------------------------------------------------
  335. Another `void' function, i.e., a procedure.
  336. @x l.450
  337. void
  338. check_complete(){
  339. @y
  340. void check_complete(void) {
  341. @z
  342. ------------------------------------------------------------------------------
  343. The third argument of `strncpy' should be of type `size_t' not `long'.
  344. @x l.453
  345.     strncpy(buffer,change_buffer,change_limit-change_buffer+1);
  346. @y
  347.     strncpy(buffer,change_buffer,(size_t)(change_limit-change_buffer+1));
  348. @z
  349. ------------------------------------------------------------------------------
  350. Another `void' function, i.e., a procedure.
  351. @x l.490
  352. @<Predecl...@>=
  353. void  err_print();
  354.  
  355. @
  356. @<Functions...@>=
  357. void
  358. err_print(s) /* prints `\..' and location of error message */
  359. char *s;
  360. @y
  361. @<Predecl...@>=
  362. void  err_print(char *);
  363.  
  364. @
  365. @<Functions...@>=
  366. void err_print(char *s) /* prints `\..' and location of error message */
  367. @z
  368. ------------------------------------------------------------------------------
  369. On the AMIGA it is very convenient to know a little bit more about the
  370. reasons why a program failed.  There are four levels of return for this
  371. purpose.  Let CWeb be so kind to use them, so scripts can be made better.
  372. @x l.540
  373. @ Some implementations may wish to pass the |history| value to the
  374. operating system so that it can be used to govern whether or not other
  375. programs are started. Here, for instance, we pass the operating system
  376. a status of 0 if and only if only harmless messages were printed.
  377. @^system dependencies@>
  378.  
  379. @<Func...@>=
  380. wrap_up() {
  381.   @<Print the job |history|@>;
  382.   if (history > harmless_message) return(1);
  383.   else return(0);
  384. }
  385. @y
  386. @ On multi-tasking systems like the Amiga it is very convenient to know
  387. a little bit more about the reasons why a program failed.  The four levels
  388. of return indicated by the |history| value are very suitable for this
  389. purpose.  Here, for instance, we pass the operating system a status of~0
  390. if and only if the run was a complete success.  Any warning or error
  391. message will result in a higher return value, so ARexx scripts can be
  392. made sensitive to these conditions.
  393.  
  394. |__TURBOC__| has another shitty ``feature'' that has to be fixed.
  395. |return|ing from several |case|s crashes the system.  Really funny.
  396. @^system dependencies@>
  397.  
  398. @d RETURN_OK     0 /* No problems, success */
  399. @d RETURN_WARN   5 /* A warning only */
  400. @d RETURN_ERROR 10 /* Something wrong */
  401. @d RETURN_FAIL  20 /* Complete or severe failure */
  402.  
  403. @<Func...@>=
  404. #ifdef __TURBOC__
  405. int wrap_up(void) {
  406.   int return_val;
  407.  
  408.   putchar('\n');
  409.   @<Remove the temporary file if not already done@>@;
  410.   @<Print the job |history|@>;
  411.   switch(history) {
  412.   case harmless_message: return_val=RETURN_WARN; break;
  413.   case error_message: return_val=RETURN_ERROR; break;
  414.   case fatal_message: return_val=RETURN_FAIL; break;
  415.   default: return_val=RETURN_OK;
  416.     }
  417.   return(return_val);
  418. }
  419. #else
  420. int wrap_up(void) {
  421.   putchar('\n');
  422.   @<Remove the temporary file if not already done@>@;
  423.   @<Print the job |history|@>;
  424.   switch(history) {
  425.   case harmless_message: return(RETURN_WARN); break;
  426.   case error_message: return(RETURN_ERROR); break;
  427.   case fatal_message: return(RETURN_FAIL); break;
  428.   default: return(RETURN_OK);
  429.     }
  430. }
  431. #endif
  432. @z
  433. ------------------------------------------------------------------------------
  434. @x l.569
  435. the names of those files. Most of the 128 flags are undefined but available
  436. @y
  437. the names of those files. Most of the 256 flags are undefined but available
  438. @z
  439. ------------------------------------------------------------------------------
  440. @x l.578
  441. char out_file_name[max_file_name_length]; /* name of |out_file| */
  442. boolean flags[128]; /* an option for each 7-bit code */
  443. @y
  444. char *out_file_name; /* name of |out_file| */
  445. char *check_file_name; /* name of |check_file| */
  446. boolean *flags; /* an option for each 8-bit code */
  447. @z
  448. ------------------------------------------------------------------------------
  449. @x l.593
  450. An omitted change file argument means that |'/dev/null'| should be used,
  451. when no changes are desired.
  452. @y
  453. An omitted change file argument means that |'/dev/null'| or---on non-\UNIX/
  454. systems the contents of the compile-time variable |_DEV_NULL|---should
  455. be used, when no changes are desired.
  456. @z
  457. ------------------------------------------------------------------------------
  458. Another `void' function, i.e., a procedure.
  459. @x l.599
  460. @<Pred...@>=
  461. void scan_args();
  462.  
  463. @
  464. @<Function...@>=
  465. void
  466. scan_args()
  467. @y
  468. @<Pred...@>=
  469. void scan_args(void);
  470.  
  471. @
  472. @<Function...@>=
  473. void scan_args(void)
  474. @z
  475. ------------------------------------------------------------------------------
  476. @x l.608
  477.   char *name_pos; /* file name beginning, sans directory */
  478. @y
  479. @z
  480. ------------------------------------------------------------------------------
  481. @x l.617
  482.       s=name_pos=*argv;@+dot_pos=NULL;
  483.       while (*s) {
  484.         if (*s=='.') dot_pos=s++;
  485.         else if (*s=='/') dot_pos=NULL,name_pos=++s;
  486.         else s++;
  487.       }
  488. @y
  489.       s=*argv;@+dot_pos=NULL;
  490.       while (*s) {
  491.         if (*s=='.') dot_pos=s++;
  492.         else if (*s==DIR_SEPARATOR || *s==DEVICE_SEPARATOR || *s=='/')
  493.           dot_pos=NULL,++s;
  494.         else s++;
  495.       }
  496. @z
  497. ------------------------------------------------------------------------------
  498. @x l.630
  499.   if (!found_change) strcpy(change_file_name,"/dev/null");
  500. @y
  501. #ifdef _DEV_NULL
  502.   if (!found_change) strcpy(change_file_name,_DEV_NULL);
  503. #else
  504.   if (!found_change) strcpy(change_file_name,"/dev/null");
  505. #endif
  506. @z
  507. ------------------------------------------------------------------------------
  508. @x l.693
  509. FILE *out_file; /* where output goes */
  510. @y
  511. FILE *out_file; /* where output goes */
  512. FILE *check_file; /* where the temporary output goes */
  513. @z
  514. ------------------------------------------------------------------------------
  515. @x l.696
  516. scan_args();
  517. if (out_file_name[0]=='\0') out_file=stdout;
  518. else if ((out_file=fopen(out_file_name,"w"))==NULL)
  519.     fatal("! Cannot open output file ", out_file_name);
  520. @.Cannot open output file@>
  521. @y
  522. scan_args();
  523. tmpnam(check_file_name);
  524. if(strrchr(check_file_name,DEVICE_SEPARATOR))
  525.   check_file_name=strrchr(check_file_name,DEVICE_SEPARATOR)+1;
  526. if (out_file_name[0]=='\0') out_file=stdout;
  527. else if (!(out_file=fopen(check_file_name,"w")))
  528.     fatal("! Cannot open output file ", check_file_name);
  529. @.Cannot open output file@>
  530. @z
  531. ------------------------------------------------------------------------------
  532. @x l.709
  533. @* Index.
  534. @y
  535. @* Path searching.  By default, \.{CTANGLE} and \.{CWEAVE} are looking
  536. for include files along the path |CWEBINPUTS|.  By setting the environment
  537. variable of the same name to a different search path you can suit your
  538. personal needs.  The |default_path| defined in the Makefile always is
  539. appended to any setting of the environment variable, so you don't have
  540. to repeat the default entries.  The following procedure copies the value
  541. of the |environment| variable (if any) to the variable |include_path| used
  542. for path searching and appends the |default_path| string.
  543.  
  544. @c
  545. static boolean set_path(char *default_path,char *environment)
  546. {
  547.   static char *string;
  548.  
  549.   alloc_object(string,max_path_length+2,char);
  550.   if(environment) {
  551.     if(strlen(environment)+strlen(default_path) >= max_path_length) {
  552.       err_print("! Include path too long"); return(0);
  553. @.Include path too long@>
  554.     }
  555.     else {
  556.       sprintf(string,"%s%c%s",environment,PATH_SEPARATOR,default_path);
  557.       strcpy(default_path,string);
  558.     }
  559.   }
  560.   return(1);
  561. }
  562.  
  563. @ The path search algorithm defined in section |@<Try to open...@>|
  564. needs a few extra variables.  The search path given in the environment
  565. variable |CWEBINPUTS| must not be longer than |max_path_length|.  If no
  566. string is given in this variable, the internal default |CWEBINPUTS| is
  567. used instead, which holds some sensible paths.
  568.  
  569. @d max_path_length 4094
  570.  
  571. @<Definitions...@>=
  572. char *include_path;
  573. char *p, *path_prefix, *next_path_prefix;
  574.  
  575. @ To satisfy all the {\mc ANSI} compilers out there, here are the
  576. prototypes of all internal functions.
  577.  
  578. @<Predecl...@>=
  579. int get_line(void);@/
  580. int input_ln(FILE *);@/
  581. int main(int,char **);
  582. int wrap_up(void);@/
  583. void check_change(void);@/
  584. void check_complete(void);@/
  585. void err_print(char *);@/
  586. void prime_the_change_buffer(void);@/
  587. void put_line(void);@/
  588. void reset_input(void);@/
  589. void scan_args(void);@/
  590. static boolean set_path(char *,char *);@/
  591.  
  592. @ Version information.  The {\mc AMIGA} operating system provides the
  593. `version' command and good programs answer with some informations about
  594. their creation date and their current version.
  595.  
  596. @<Defi...@>=
  597. #ifdef __SASC
  598. const char Version[] = "$VER: WMerge 3.3 [p11] ("__DATE__", "__TIME__")\n";
  599. #endif
  600.  
  601. @* Output file update.  Most \CEE/ projects are controlled by a
  602. \.{makefile} which automatically takes care of the temporal dependencies
  603. between the different source modules.  It is suitable that \.{CWEB} doesn't
  604. create new output for all existing files, when there are only changes to
  605. some of them.  Thus the \.{make} process will only recompile those modules
  606. where necessary.  The idea and basic implementation of this mechanism can
  607. be found in the program \.{NUWEB} by Preston Briggs, to whom credit is due.
  608.  
  609. @f type int /* \.{type} becomes the pseudotype \&{type} */
  610. @#
  611. @d alloc_object(object,size,@!type)
  612.    if(!(object = (type *)malloc((size)*sizeof(type))))
  613.       fatal("","! Memory allocation failure");
  614. @d free_object(object)
  615.    if(object) {
  616.       free(object);
  617.       object=NULL;
  618.       }
  619.  
  620. @<Update the result...@>=
  621. if(out_file=fopen(out_file_name,"r")) {
  622.   char *x,*y;
  623.   int x_size,y_size;
  624.  
  625.   if(!(check_file=fopen(check_file_name,"r")))
  626.     fatal("! Cannot open output file",check_file_name);
  627.  
  628.   alloc_object(x,BUFSIZ,char);
  629.   alloc_object(y,BUFSIZ,char);
  630.  
  631.   @<Compare the temporary output to the previous output@>@;
  632.  
  633.   fclose(out_file); out_file=NULL;
  634.   fclose(check_file); check_file=NULL;
  635.  
  636.   @<Take appropriate action depending on the comparison@>@;
  637.  
  638.   free_object(y);
  639.   free_object(x);
  640.   }
  641. else
  642.   rename(check_file_name,out_file_name); /* This was the first run */
  643.  
  644. check_file_name=NULL; /* We want to get rid of the temporary file */
  645.  
  646. @ We hope that this runs fast on most systems.
  647.  
  648. @<Compare the temp...@>=
  649. do {
  650.   x_size = fread(x,1,BUFSIZ,out_file);
  651.   y_size = fread(y,1,BUFSIZ,check_file);
  652.   } while((x_size == y_size) && !memcmp(x,y,x_size) &&
  653.           !feof(out_file) && !feof(check_file));
  654.  
  655. @ Note the superfluous call to |remove| before |rename|.  We're using it to
  656. get around a bug in some implementations of |rename|.
  657.  
  658. @<Take appropriate action...@>=
  659. if((x_size != y_size) || memcmp(x,y,x_size)) {
  660.   remove(out_file_name);
  661.   rename(check_file_name,out_file_name);
  662.   }
  663. else
  664.   remove(check_file_name); /* The output remains untouched */
  665.  
  666. @* Dynamic memory allocation.  Just as \.{CTANGLE} and \.{CWEAVE} before,
  667. \.{WMERGE} allocates all its internal arrays dynamically, so the resulting
  668. program can be compiled in the \.{NEAR} data segment and made resident on
  669. the Amiga.  We do all the global allocations here.
  670.  
  671. @<Init...@>=
  672. alloc_object(buffer,buf_size,ASCII);
  673. buffer_end=buffer+buf_size-2;
  674. alloc_object(file,max_include_depth,FILE*);
  675. alloc_object(file_name,max_include_depth,char *);
  676. for(i=0; i<max_include_depth; i++)
  677.   alloc_object(file_name[i],max_file_name_length,char);
  678. alloc_object(change_file_name,max_file_name_length,char);
  679. alloc_object(alt_web_file_name,max_file_name_length,char);
  680. alloc_object(line,max_include_depth,int);
  681. alloc_object(change_buffer,buf_size,char);
  682. alloc_object(out_file_name,max_file_name_length,char);
  683. alloc_object(check_file_name,max_file_name_length,char);
  684. alloc_object(flags,256,boolean);
  685. alloc_object(include_path,max_path_length+2,char);
  686. #ifdef CWEBINPUTS
  687. strcpy(include_path,CWEBINPUTS);
  688. #endif
  689.  
  690. @ @<Definitions@>=
  691. int i; /* index variable for initializing matrices */
  692.  
  693. @ In case of an user break we must take care of the dynamically allocated
  694. and opened resources like memory segments.  There is no warranty that in
  695. such cases the exit code automatically frees these resources.  |exit| is
  696. not necessarily called after a break.  {\mc ANSI-C} provides ``interrupt
  697. handlers'' for this purpose.  |catch_break| simply calls |wrap_up| before
  698. |exit|ing the aborted program.
  699. @^system dependencies@>
  700.  
  701. @<Set up the exit trap@>=
  702.   if(signal(SIGINT,&catch_break) == SIG_ERR)
  703.     exit(1); /* Interrupt handler could not be set up. */
  704.  
  705. @ The only purpose of the interrupt handler |catch_break| in case of an
  706. user abort is to call the cleanup routine that takes care of any opened
  707. system resources.
  708.  
  709. @c
  710. void catch_break(int dummy)
  711.    {
  712.    history=fatal_message;
  713.    exit(wrap_up());
  714.    }
  715.  
  716. @ @<Predec...@>=
  717. void catch_break(int);
  718.  
  719. @ @<Remove the temporary file...@>=
  720.   if(out_file)
  721.     fclose(out_file);
  722.   if(check_file)
  723.     fclose(check_file);
  724.   if(check_file_name)
  725.     remove(check_file_name);
  726.  
  727. @* Index.
  728. @z
  729. ------------------------------------------------------------------------------
  730.