removal due to another working script
[trueprint.git] / src / diffs.c
blob968237c1f6e4ee49b8958fb8c47a9de4db00eb40
1 /*
2 * Source file:
3 * diffs.c
5 * Implements the highlighting of differences between old and new versions
6 * of files.
7 */
9 #include "config.h"
11 #ifndef DIFF_CMD
13 #include "trueprint.h"
14 #include "diffs.h"
16 /* If there is no diff command just provide stubs */
18 void setup_diffs(void) { return; }
19 void init_diffs(char newfile[]) { return; }
20 void end_diffs(void) { return; }
21 boolean getdelline(long current_line, char *input_line, char_status input_status[]) { return 0; }
22 boolean line_inserted(long current_line) { return 0; }
24 #else
26 #include <ctype.h>
27 #include <errno.h>
28 /* Ultrix needs these sys header files this way around */
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
35 #include "trueprint.h"
36 #include "utils.h"
37 #include "main.h"
38 #include "output.h"
39 #include "openpipe.h"
40 #include "options.h"
41 #include "debug.h"
43 #include "diffs.h"
45 static char *diffs_string;
48 * Private part
50 static unsigned short read_values(FILE *,long *value1_ptr, long *value2_ptr);
51 static boolean read_long(FILE *, long *);
52 static void parse_line(void);
53 static stream_status get_diff_char(char *input_char, char_status *status);
55 static FILE *diffs_stream;
56 static boolean diffs_on;
57 static long diff_start_line;
58 static long diff_end_line;
59 static long lines_deleted;
60 static long lines_added;
63 * Function:
64 * setup_diffs
67 void
68 setup_diffs(void)
70 diffs_string = NULL;
71 diffs_stream = NULL;
73 string_option("O", "diff", NULL, &diffs_string, NULL, NULL,
74 OPT_MISC,
75 "if <string> is a file then print diffs between <string> and input file\n"
76 " otherwise use as a prefix and print diffs");
80 * Function:
81 * init_diffs
83 * Initialises the diffs system:
84 * checks to see if any old version was provided and returns if not;
85 * calls end_diffs() if necessary;
86 * starts up the diff process;
88 void
89 init_diffs(char newfile[])
92 char command[COMMAND_LEN];
93 char *diff_cmd;
94 struct stat dummy;
95 /* Check to see if any old versions given */
97 if (diffs_string == NULL)
99 /* turn off diffs and return */
100 diffs_on = FALSE;
101 return;
104 diffs_on = TRUE;
106 if ((diff_cmd = getenv("TP_DIFF_CMD")) == NULL)
108 diff_cmd = DIFF_CMD;
112 * diffs_stream is only set if still reading from
113 * diff process, so need to finish the old diffs.
115 if (diffs_stream != NULL) end_diffs();
118 * Check to see if diffs_string is a valid prefix or
119 * a filename...
121 sprintf(command,"%s%s",diffs_string,newfile);
123 if (stat(command,&dummy) == 0)
125 sprintf(command,"%s %s%s %s", diff_cmd,diffs_string,newfile,newfile);
128 else if (stat(diffs_string,&dummy) == 0)
130 sprintf(command, "%s %s %s", diff_cmd, diffs_string, newfile);
133 dm('d',3,"diffs command: %s\n",command);
135 if ((diffs_stream = fopenpipe(command, "r")) == NULL)
136 abort;
138 parse_line();
142 * Function:
143 * read_values
145 * scan a line reading one integer, and reading a second if the next
146 * character is a ","
148 unsigned short
149 read_values(FILE *stream, long *value1_ptr, long *value2_ptr)
152 int next_char;
153 unsigned short retval;
155 *value1_ptr = 0;
156 *value2_ptr = 0;
158 /* read first value - if none then return*/
159 if (!read_long(stream, value1_ptr)) return 0;
161 /* skip spaces and check for a comma */
162 while ((next_char = getc(stream)) == ' ')
164 if (next_char == ',')
166 /* if next char was a comma read second value */
167 if (!read_long(stream, value2_ptr))
169 fprintf(stderr, gettext(CMD_NAME ": internal error reading diffs\n"));
170 exit(2);
172 /* and skip spaces again */
173 while ((next_char = getc(stream)) == ' ')
175 retval = 2;
177 else
179 retval = 1;
180 *value2_ptr = *value1_ptr;
183 if (next_char != EOF)
185 /* replace last char in buffer for calling function */
186 ungetc((int)next_char,stream);
189 return(retval);
193 * Function:
194 * read_long
196 * Reads a long from a stream
198 boolean
199 read_long(FILE *stream, long *value)
202 boolean retval = FALSE;
203 int next_char;
205 *value = 0;
207 while (TRUE)
209 if ((next_char = getc(stream)) == EOF) break;
210 if (!isdigit(next_char)) break;
212 retval = TRUE;
213 *value = (*value * 10) + (next_char - '0');
216 if (next_char != EOF)
218 ungetc(next_char, stream);
221 return retval;
225 * Function:
226 * parse_line
228 * Reads a line from the diff stream, reading start and end line numbers
229 * for both the old and new files and the change type (d, a or c).
231 void
232 parse_line(void)
235 long delete_start;
236 long delete_end;
237 int diff_type;
240 * Read the first two values - if there aren't any then we've
241 * reached the end of the file. These values refer to the
242 * first file so we're only interested in them for deleting lines.
244 if (read_values(diffs_stream, &delete_start, &delete_end) == 0)
246 end_diffs();
247 diffs_on = FALSE;
248 return;
252 * Calculate the number of lines deleted.
253 * If delete start and delete end are the same then 1 line has been
254 * deleted... i.e. one more than the difference.
256 lines_deleted = delete_end - delete_start + 1;
258 diff_type = getc(diffs_stream); /* a=add, d=del, c=change */
260 switch (diff_type)
262 case 'a':
263 case 'd':
264 case 'c':
265 break;
266 default:
267 fprintf(stderr, gettext(CMD_NAME ": warning, bad diffs stream format char %c!\n"), diff_type);
268 end_diffs();
269 diffs_on = FALSE;
270 return;
273 /* Same as before, only for new version of file */
274 if (read_values(diffs_stream, &diff_start_line, &diff_end_line) == 0)
276 fprintf(stderr, gettext(CMD_NAME ": warning, bad diffs stream format!\n"));
277 end_diffs();
278 diffs_on = FALSE;
279 return;
281 lines_added = diff_end_line - diff_start_line + 1;
283 if (diff_type == 'a') lines_deleted = 0;
284 if (diff_type == 'd')
286 lines_added = 0;
288 * deleted lines are actually *after* the specified line,
289 * so we need to pretend they're one line later...
291 diff_start_line += 1;
292 diff_end_line += 1;
294 /* Skip to the end of the line */
295 while (getc(diffs_stream) != '\n')
300 * Function:
301 * end_diffs
303 * Finish off the diffs system:
304 * - close the diffs stream (i.e. kill off the diff process);
307 void
308 end_diffs(void)
311 if (!diffs_on) return;
313 dm('d',3,"diffs: closing diffs\n");
315 fclosepipe(diffs_stream);
316 diffs_stream = NULL;
320 * Function:
321 * get_diff_char
323 * Simple function to be passed to getnextline() (which expands tabs, etc)
324 * in getdelline(), so we don't need to duplicate the functionality of
325 * getnextline().
327 stream_status
328 get_diff_char(char *input_char, char_status *status)
331 *status = CHAR_NORMAL;
332 *input_char = (char)getc(diffs_stream);
333 return(STREAM_OK);
337 * Function:
338 * getdelline
340 * Returns:
341 * TRUE if a(nother) deleted line occurs after current line, returns
342 * line in parameters.
343 * FALSE if no deleted line between current line and next line.
346 boolean
347 getdelline(long current_line, char *input_line, char_status input_status[])
350 boolean blank_line;
353 * Check whether there is a deleted line waiting...
355 if ((current_line != diff_start_line)
356 || !diffs_on
357 || (lines_deleted == 0))
358 return(FALSE);
361 * First skip the first two characters of the line -
362 * they should be "< "
364 if ((getc(diffs_stream)!='<') || (getc(diffs_stream)!=' '))
366 fprintf(stderr, gettext(CMD_NAME ": diffs stream in unexpected format\n"));
367 exit(2);
369 /* Read in the next line from diff stream */
370 getnextline(get_diff_char,&blank_line,input_line,input_status);
372 lines_deleted -= 1;
373 if (lines_deleted == 0)
376 * If there are lines added then this is a "change" and
377 * the added lines will be dealt with by line_inserted().
378 * Otherwise we need to find the next difference with
379 * parse_line().
381 if (lines_added == 0)
382 parse_line();
383 else
384 /* else skip over line of ---- */
385 while (getc(diffs_stream) != '\n')
388 return(TRUE);
392 * Function:
393 * line_inserted
395 * Returns:
396 * INSERT if line_number has been inserted
397 * NORMAL otherwise
400 boolean
401 line_inserted(long current_line)
404 boolean retval = FALSE;
405 if (!diffs_on) return(FALSE);
406 if ((current_line >= diff_start_line)
407 && (current_line <= diff_end_line))
409 /* skip over line */
410 while (getc(diffs_stream) != '\n')
412 retval = TRUE;
414 /* If reached the end of the insertion... */
415 if (current_line >= diff_end_line) parse_line();
416 return(retval);
419 #endif