Gracefuly handle spaces around the equal sign in the Authors file.
[parsecvs.git] / rcs2git.c
blobc13c1f4060402579251df6d0c82c0e48d572ac4b
1 /*
2 * Copyright © 2006 Sean Estabrooks <seanlkml@sympatico.ca>
3 * Copyright © 2006 Keith Packard <keithp@keithp.com>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or (at
8 * your option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
19 * Large portions of code contained in this file were obtained from
20 * the original RCS application under GPLv2 or later license, it retains
21 * the copyright of the original authors listed below:
23 * Copyright 1982, 1988, 1989 Walter Tichy
24 * Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
25 * Distributed under license by the Free Software Foundation, Inc.
27 #include <limits.h>
28 #include <stdarg.h>
29 #include "cvs.h"
31 typedef unsigned char uchar;
32 struct alloclist {
33 void* alloc;
34 struct alloclist *nextalloc;
37 struct out_buffer_type {
38 char *text, *ptr, *end_of_text;
39 size_t size;
42 struct in_buffer_type {
43 uchar *buffer;
44 uchar *ptr;
45 int read_count;
48 struct diffcmd {
49 long line1, nlines, adprev, dafter;
52 const int initial_out_buffer_size = 1024;
53 char const ciklog[] = "checked in with -k by ";
55 #define KEYLENGTH 8 /* max length of any of the above keywords */
56 #define KDELIM '$' /* keyword delimiter */
57 #define VDELIM ':' /* separates keywords from values */
58 #define SDELIM '@' /* string delimiter */
59 #define min(a,b) ((a) < (b) ? (a) : (b))
60 #define max(a,b) ((a) > (b) ? (a) : (b))
62 char const *const Keyword[] = {
63 0, "Author", "Date", "Header", "Id", "Locker", "Log",
64 "Name", "RCSfile", "Revision", "Source", "State"
66 enum markers { Nomatch, Author, Date, Header, Id, Locker, Log,
67 Name, RCSfile, Revision, Source, State };
68 enum stringwork {ENTER, EDIT};
70 enum expand_mode {EXPANDKKV, EXPANDKKVL, EXPANDKK, EXPANDKV, EXPANDKO, EXPANDKB};
71 enum expand_mode Gexpand;
72 char * Glog;
73 int Gkvlen = 0;
74 char* Gkeyval = NULL;
75 char const *Gfilename;
76 char *Gabspath;
77 cvs_version *Gversion;
78 char Gversion_number[CVS_MAX_REV_LEN];
79 struct out_buffer_type *Goutbuf;
80 struct in_buffer_type in_buffer_store;
81 struct in_buffer_type *Ginbuf = &in_buffer_store;
84 * Gline contains pointers to the lines in the currently edit buffer
85 * It is a 0-origin array that represents Glinemax-Ggapsize lines.
86 * Gline[0 .. Ggap-1] and Gline[Ggap+Ggapsize .. Glinemax-1] hold
87 * pointers to lines. Gline[Ggap .. Ggap+Ggapsize-1] contains garbage.
88 * Any @s in lines are duplicated.
89 * Lines are terminated by \n, or (for a last partial line only) by single @.
91 static int depth;
92 static struct {
93 Node *next_branch;
94 Node *node;
95 uchar **line;
96 size_t gap, gapsize, linemax;
97 } stack[CVS_MAX_DEPTH/2];
98 #define Gline stack[depth].line
99 #define Ggap stack[depth].gap
100 #define Ggapsize stack[depth].gapsize
101 #define Glinemax stack[depth].linemax
103 static void fatal_system_error(char const *s)
105 perror(s);
106 exit(1);
109 static void fatal_error(char const *format,...)
111 va_list args;
113 fprintf(stderr, "rcsco2git fatal: ");
114 va_start(args, format);
115 vfprintf(stderr, format, args);
116 va_end(args);
117 fprintf(stderr, "\n");
118 exit(1);
121 static inline void* xmalloc(size_t size)
123 void *ret = malloc(size);
124 if (!ret && !size)
125 ret = malloc(1);
126 if (!ret)
127 fatal_system_error("Out of memory, malloc failed");
128 return ret;
130 static inline void* xrealloc(void *ptr, size_t size)
132 void *ret = realloc(ptr, size);
133 if (!ret && !size)
134 ret = realloc(ptr, 1);
135 if (!ret)
136 fatal_system_error("Out of memory, realloc failed");
137 return ret;
140 /* backup one position in the input buffer, unless at start of buffer
141 * return character at new position, or EOF if we could not back up
143 static int in_buffer_ungetc(void)
145 int c;
146 if (Ginbuf->read_count == 0)
147 return EOF;
148 --Ginbuf->read_count;
149 --Ginbuf->ptr;
150 c = *Ginbuf->ptr;
151 if (c == SDELIM) {
152 --Ginbuf->ptr;
153 c = *Ginbuf->ptr;
155 return c;
158 static int in_buffer_getc(void)
160 int c;
161 c = *(Ginbuf->ptr++);
162 ++Ginbuf->read_count;
163 if (c == SDELIM) {
164 c = *(Ginbuf->ptr++);
165 if (c != SDELIM) {
166 Ginbuf->ptr -= 2;
167 --Ginbuf->read_count;
168 return EOF;
171 return c ;
174 static uchar * in_get_line(void)
176 int c;
177 uchar *ptr = Ginbuf->ptr;
178 c=in_buffer_getc();
179 if (c == EOF)
180 return NULL;
181 while (c != EOF && c != '\n')
182 c = in_buffer_getc();
183 return ptr;
186 static uchar * in_buffer_loc(void)
188 return(Ginbuf->ptr);
191 static void in_buffer_init(uchar *text, int bypass_initial)
193 Ginbuf->ptr = Ginbuf->buffer = text;
194 Ginbuf->read_count=0;
195 if (bypass_initial && *Ginbuf->ptr++ != SDELIM)
196 fatal_error("Illegal buffer, missing @ %s", text);
199 static void out_buffer_init(void)
201 char *t;
202 Goutbuf = xmalloc(sizeof(struct out_buffer_type));
203 memset(Goutbuf, 0, sizeof(struct out_buffer_type));
204 Goutbuf->size = initial_out_buffer_size;
205 t = xmalloc(Goutbuf->size);
206 Goutbuf->text = t;
207 Goutbuf->ptr = t;
208 Goutbuf->end_of_text = t + Goutbuf->size;
211 static void out_buffer_enlarge(void)
213 int ptroffset = Goutbuf->ptr - Goutbuf->text;
214 Goutbuf->size *= 2;
215 Goutbuf->text = xrealloc(Goutbuf->text, Goutbuf->size);
216 Goutbuf->end_of_text = Goutbuf->text + Goutbuf->size;
217 Goutbuf->ptr = Goutbuf->text + ptroffset;
220 static unsigned long out_buffer_count(void)
222 return (unsigned long) (Goutbuf->ptr - Goutbuf->text);
225 static char *out_buffer_text(void)
227 return Goutbuf->text;
230 static void out_buffer_cleanup(void)
232 free(Goutbuf->text);
233 free(Goutbuf);
236 inline static void out_putc(int c)
238 *Goutbuf->ptr++ = c;
239 if (Goutbuf->ptr >= Goutbuf->end_of_text)
240 out_buffer_enlarge();
243 static void out_printf(const char *fmt, ...)
245 int ret, room;
246 va_list ap;
247 while (1) {
248 room = Goutbuf->end_of_text - Goutbuf->ptr;
249 va_start(ap, fmt);
250 ret = vsnprintf(Goutbuf->ptr, room, fmt, ap);
251 va_end(ap);
252 if (ret > -1 && ret < room) {
253 Goutbuf->ptr += ret;
254 return;
256 out_buffer_enlarge();
260 static int out_fputs(const char *s)
262 while (*s)
263 out_putc(*s++);
264 return 0;
267 static void out_awrite(char const *s, size_t len)
269 while (len--)
270 out_putc(*s++);
273 static int latin1_alpha(int c)
275 if (c >= 192 && c != 215 && c != 247 ) return 1;
276 if ((c >= 97 && c < 123) || (c >= 65 && c < 91)) return 1;
277 return 0;
280 static int latin1_whitespace(uchar c)
282 if (c == 32 || (c >= 8 && c <= 13 && c != 10)) return 1;
283 return 0;
286 static enum expand_mode expand_override(char const *s)
288 char * const expand_names[] = {"kv", "kvl", "k", "v", "o", "b"};
289 int i;
290 for (i=0; i < 6; ++i)
291 if (strcmp(s,expand_names[i]) == 0)
292 return (enum expand_mode) i;
293 return EXPANDKK;
296 static char const * basefilename(char const *p)
298 char const *b = p, *q = p;
299 for (;;)
300 switch (*q++) {
301 case '/': b = q; break;
302 case 0: return b;
306 /* Convert relative RCS filename to absolute path */
307 static char const * getfullRCSname(void)
309 char *wdbuf = NULL;
310 int wdbuflen = 0;
312 size_t dlen;
314 char const *r;
315 char* d;
317 if (Gfilename[0] == '/')
318 return Gfilename;
320 /* If we've already calculated the absolute path, return it */
321 if (Gabspath)
322 return Gabspath;
324 /* Get working directory and strip any trailing slashes */
325 wdbuflen = _POSIX_PATH_MAX + 1;
326 wdbuf = xmalloc(wdbuflen);
327 while (!getcwd(wdbuf, wdbuflen)) {
328 if (errno == ERANGE)
329 xrealloc(wdbuf, wdbuflen<<1);
330 else fatal_system_error("getcwd");
333 /* Trim off trailing slashes */
334 dlen = strlen(wdbuf);
335 while (dlen && wdbuf[dlen-1] == '/')
336 --dlen;
337 wdbuf[dlen] = 0;
339 /* Ignore leading `./'s in Gfilename. */
340 for (r = Gfilename; r[0]=='.' && r[1] == '/'; r += 2)
341 while (r[2] == '/')
342 r++;
344 /* Build full pathname. */
345 Gabspath = d = xmalloc(dlen + strlen(r) + 2);
346 memcpy(d, wdbuf, dlen);
347 d += dlen;
348 *d++ = '/';
349 strcpy(d, r);
350 free(wdbuf);
352 return Gabspath;
355 /* Check if string starts with a keyword followed by a KDELIM or VDELIM */
356 static enum markers trymatch(char const *string)
358 int j;
359 char const *p, *s;
360 for (j = sizeof(Keyword)/sizeof(*Keyword); (--j); ) {
361 p = Keyword[j];
362 s = string;
363 while (*p++ == *s++) {
364 if (!*p) {
365 switch (*s) {
366 case KDELIM:
367 case VDELIM:
368 return (enum markers)j;
369 default:
370 return Nomatch;
375 return(Nomatch);
378 /* Before line N, insert line L. N is 0-origin. */
379 static void insertline(unsigned long n, uchar * l)
381 if (n > Glinemax - Ggapsize)
382 fatal_error("edit script tried to insert beyond eof");
383 if (!Ggapsize) {
384 if (Glinemax) {
385 Ggap = Ggapsize = Glinemax; Glinemax <<= 1;
386 Gline = xrealloc(Gline, sizeof(uchar *) * Glinemax);
387 } else {
388 Glinemax = Ggapsize = 1024;
389 Gline = xmalloc(sizeof(uchar *) * Glinemax);
392 if (n < Ggap)
393 memmove(Gline+n+Ggapsize, Gline+n, (Ggap-n) * sizeof(uchar *));
394 else if (Ggap < n)
395 memmove(Gline+Ggap, Gline+Ggap+Ggapsize, (n-Ggap) * sizeof(uchar *));
396 Gline[n] = l;
397 Ggap = n + 1;
398 Ggapsize--;
401 /* Delete lines N through N+NLINES-1. N is 0-origin. */
402 static void deletelines(unsigned long n, unsigned long nlines)
404 unsigned long l = n + nlines;
405 if (Glinemax-Ggapsize < l || l < n)
406 fatal_error("edit script tried to delete beyond eof");
407 if (l < Ggap)
408 memmove(Gline+l+Ggapsize, Gline+l, (Ggap-l) * sizeof(uchar *));
409 else if (Ggap < n)
410 memmove(Gline+Ggap, Gline+Ggap+Ggapsize, (n-Ggap) * sizeof(uchar *));
411 Ggap = n;
412 Ggapsize += nlines;
415 static long parsenum(void)
417 int c;
418 long ret = 0;
419 for(c=in_buffer_getc(); isdigit(c); c=in_buffer_getc())
420 ret = (ret * 10) + (c - '0');
421 in_buffer_ungetc();
422 return ret;
425 static int parse_next_delta_command(struct diffcmd *dc)
427 int cmd;
428 long line1, nlines;
430 cmd = in_buffer_getc();
431 if (cmd==EOF)
432 return -1;
434 line1 = parsenum();
436 while (in_buffer_getc() == ' ')
438 in_buffer_ungetc();
440 nlines = parsenum();
442 while (in_buffer_getc() != '\n')
445 if (!nlines || (cmd != 'a' && cmd != 'd') || line1+nlines < line1)
446 fatal_error("Corrupt delta");
448 if (cmd == 'a') {
449 if (line1 < dc->adprev)
450 fatal_error("backward insertion in delta");
451 dc->adprev = line1 + 1;
452 } else if (cmd == 'd') {
453 if (line1 < dc->adprev || line1 < dc->dafter)
454 fatal_error("backward deletion in delta");
455 dc->adprev = line1;
456 dc->dafter = line1 + nlines;
459 dc->line1 = line1;
460 dc->nlines = nlines;
461 return cmd == 'a';
464 static void escape_string(register char const *s)
466 register char c;
467 for (;;) {
468 switch ((c = *s++)) {
469 case 0: return;
470 case '\t': out_fputs("\\t"); break;
471 case '\n': out_fputs("\\n"); break;
472 case ' ': out_fputs("\\040"); break;
473 case KDELIM: out_fputs("\\044"); break;
474 case '\\': out_fputs("\\\\"); break;
475 default: out_putc(c); break;
480 /* output the appropriate keyword value(s) */
481 static void keyreplace(enum markers marker)
483 const char *target_lockedby = NULL; // Not wired in yet
485 int c;
486 char const *xxp;
487 size_t cs, cw, ls;
488 char *leader = NULL;
489 char date_string[25];
490 uchar *kdelim_ptr = NULL;
491 enum expand_mode exp = Gexpand;
492 char const *sp = Keyword[(int)marker];
494 strftime(date_string, 25,
495 "%Y/%m/%d %H:%M:%S", localtime(&Gversion->date));
497 if (exp != EXPANDKV)
498 out_printf("%c%s", KDELIM, sp);
500 if (exp != EXPANDKK) {
501 if (exp != EXPANDKV)
502 out_printf("%c%c", VDELIM, ' ');
504 switch (marker) {
505 case Author:
506 out_fputs(Gversion->author);
507 break;
508 case Date:
509 out_fputs(date_string);
510 break;
511 case Id:
512 case Header:
513 if (marker == Id )
514 escape_string(basefilename(Gfilename));
515 else escape_string(getfullRCSname());
516 out_printf(" %s %s %s %s",
517 Gversion_number, date_string,
518 Gversion->author, Gversion->state);
519 if (target_lockedby && exp == EXPANDKKVL)
520 out_printf(" %s", target_lockedby);
521 break;
522 case Locker:
523 if (target_lockedby && exp == EXPANDKKVL)
524 out_fputs(target_lockedby);
525 break;
526 case Log:
527 case RCSfile:
528 escape_string(basefilename(Gfilename));
529 break;
530 case Revision:
531 out_fputs(Gversion_number);
532 break;
533 case Source:
534 escape_string(getfullRCSname());
535 break;
536 case State:
537 out_fputs(Gversion->state);
538 break;
539 default:
540 break;
543 if (exp != EXPANDKV)
544 out_putc(' ');
547 #if 0
548 /* Closing delimiter is processed again in expandline */
549 if (exp != EXPANDKV)
550 out_putc(KDELIM);
551 #endif
553 if (marker == Log) {
555 * "Closing delimiter is processed again in explandline"
556 * does not apply here, since we consume the input.
558 if (exp != EXPANDKV)
559 out_putc(KDELIM);
561 sp = Glog;
562 ls = strlen(Glog);
563 if (sizeof(ciklog)-1<=ls && !memcmp(sp,ciklog,sizeof(ciklog)-1))
564 return;
566 /* Back up to the start of the current input line */
567 int num_kdelims = 0;
568 for (;;) {
569 c = in_buffer_ungetc();
570 if (c == EOF)
571 break;
572 if (c == '\n') {
573 in_buffer_getc();
574 break;
576 if (c == KDELIM) {
577 num_kdelims++;
578 /* It is possible to have multiple keywords
579 on one line. Make sure we don't backtrack
580 into some other keyword! */
581 if (num_kdelims > 2) {
582 in_buffer_getc();
583 break;
585 kdelim_ptr = in_buffer_loc();
589 /* Copy characters before `$Log' into LEADER. */
590 xxp = leader = xmalloc(kdelim_ptr - in_buffer_loc());
591 for (cs = 0; ; cs++) {
592 c = in_buffer_getc();
593 if (c == KDELIM)
594 break;
595 leader[cs] = c;
598 /* Convert traditional C or Pascal leader to ` *'. */
599 for (cw = 0; cw < cs; cw++)
600 if (!latin1_whitespace(xxp[cw]))
601 break;
602 if (cw+1 < cs && xxp[cw+1] == '*' &&
603 (xxp[cw] == '/' || xxp[cw] == '(')) {
604 size_t i = cw+1;
605 for (;;) {
606 if (++i == cs) {
607 leader[cw] = ' ';
608 break;
609 } else if (!latin1_whitespace(xxp[i]))
610 break;
614 /* Skip `$Log ... $' string. */
615 do {
616 c = in_buffer_getc();
617 } while (c != KDELIM);
619 out_putc('\n');
620 out_awrite(xxp, cs);
621 out_printf("Revision %s %s %s",
622 Gversion_number,
623 date_string,
624 Gversion->author);
626 /* Do not include state: it may change and is not updated. */
627 cw = cs;
628 for (; cw && (xxp[cw-1]==' ' || xxp[cw-1]=='\t'); --cw)
630 for (;;) {
631 out_putc('\n');
632 out_awrite(xxp, cw);
633 if (!ls)
634 break;
635 --ls;
636 c = *sp++;
637 if (c != '\n') {
638 out_awrite(xxp+cw, cs-cw);
639 do {
640 out_putc(c);
641 if (!ls)
642 break;
643 --ls;
644 c = *sp++;
645 } while (c != '\n');
648 free(leader);
652 static int expandline(void)
654 register int c = 0;
655 char * tp;
656 register int e, r;
657 char const *tlim;
658 enum markers matchresult;
659 int orig_size;
661 if (Gkvlen < KEYLENGTH+3) {
662 Gkvlen = KEYLENGTH + 3;
663 Gkeyval = xrealloc(Gkeyval, Gkvlen);
665 e = 0;
666 r = -1;
668 for (;;) {
669 c = in_buffer_getc();
670 for (;;) {
671 switch (c) {
672 case EOF:
673 goto uncache_exit;
674 default:
675 out_putc(c);
676 r = 0;
677 break;
678 case '\n':
679 out_putc(c);
680 r = 2;
681 goto uncache_exit;
682 case KDELIM:
683 r = 0;
684 /* check for keyword */
685 /* first, copy a long enough string into keystring */
686 tp = Gkeyval;
687 *tp++ = KDELIM;
688 for (;;) {
689 c = in_buffer_getc();
690 if (tp <= &Gkeyval[KEYLENGTH] && latin1_alpha(c))
691 *tp++ = c;
692 else break;
694 *tp++ = c; *tp = '\0';
695 matchresult = trymatch(Gkeyval+1);
696 if (matchresult==Nomatch) {
697 tp[-1] = 0;
698 out_fputs(Gkeyval);
699 continue; /* last c handled properly */
702 /* Now we have a keyword terminated with a K/VDELIM */
703 if (c==VDELIM) {
704 /* try to find closing KDELIM, and replace value */
705 tlim = Gkeyval + Gkvlen;
706 for (;;) {
707 c = in_buffer_getc();
708 if (c=='\n' || c==KDELIM)
709 break;
710 *tp++ =c;
711 if (tlim <= tp) {
712 orig_size = Gkvlen;
713 Gkvlen *= 2;
714 Gkeyval = xrealloc(Gkeyval, Gkvlen);
715 tlim = Gkeyval + Gkvlen;
716 tp = Gkeyval + orig_size;
719 if (c==EOF)
720 goto keystring_eof;
722 if (c!=KDELIM) {
723 /* couldn't find closing KDELIM -- give up */
724 *tp = 0;
725 out_fputs(Gkeyval);
726 continue; /* last c handled properly */
730 * CVS will expand keywords that have
731 * overlapping delimiters, eg "$Name$Id$". To
732 * support that (mis)feature, push the closing
733 * delimiter back on the input so that the
734 * loop will resume processing starting with
735 * it.
737 if (c == KDELIM)
738 in_buffer_ungetc();
740 /* now put out the new keyword value */
741 keyreplace(matchresult);
742 e = 1;
743 break;
745 break;
749 keystring_eof:
750 *tp = 0;
751 out_fputs(Gkeyval);
752 uncache_exit:
753 return r + e;
756 static void process_delta(Node *node, enum stringwork func)
758 long editline = 0, linecnt = 0, adjust = 0;
759 int editor_command;
760 struct diffcmd dc;
761 uchar *ptr;
763 Glog = node->p->log;
764 in_buffer_init((uchar *)node->p->text, 1);
765 Gversion = node->v;
766 cvs_number_string(&Gversion->number, Gversion_number);
768 switch (func) {
769 case ENTER:
770 while( (ptr=in_get_line()) )
771 insertline(editline++, ptr);
772 case EDIT:
773 dc.dafter = dc.adprev = 0;
774 while ((editor_command = parse_next_delta_command(&dc)) >= 0) {
775 if (editor_command) {
776 editline = dc.line1 + adjust;
777 linecnt = dc.nlines;
778 while(linecnt--)
779 insertline(editline++, in_get_line());
780 adjust += dc.nlines;
781 } else {
782 deletelines(dc.line1 - 1 + adjust, dc.nlines);
783 adjust -= dc.nlines;
786 break;
790 static void finishedit(void)
792 uchar **p, **lim, **l = Gline;
793 for (p=l, lim=l+Ggap; p<lim; ) {
794 in_buffer_init(*p++, 0);
795 expandline();
797 for (p+=Ggapsize, lim=l+Glinemax; p<lim; ) {
798 in_buffer_init(*p++, 0);
799 expandline();
803 static void snapshotline(register uchar * l)
805 register int c;
806 do {
807 if ((c = *l++) == SDELIM && *l++ != SDELIM)
808 return;
809 out_putc(c);
810 } while (c != '\n');
814 static void snapshotedit(void)
816 uchar **p, **lim, **l=Gline;
817 for (p=l, lim=l+Ggap; p<lim; )
818 snapshotline(*p++);
819 for (p+=Ggapsize, lim=l+Glinemax; p<lim; )
820 snapshotline(*p++);
823 extern int write_sha1_file( void *buf, unsigned long len,
824 const char *type, uchar *return_sha1);
825 extern char *sha1_to_hex(const uchar *sha1);
827 static void enter_branch(Node *node)
829 uchar **p = xmalloc(sizeof(uchar *) * stack[depth].linemax);
830 memcpy(p, stack[depth].line, sizeof(uchar *) * stack[depth].linemax);
831 stack[depth + 1] = stack[depth];
832 stack[depth + 1].next_branch = node->sib;
833 stack[depth + 1].line = p;
834 depth++;
837 void generate_files(cvs_file *cvs)
839 int expand_override_enabled = 1;
840 int expandflag = Gexpand < EXPANDKO;
841 Node *node = head_node;
842 depth = 0;
843 Gfilename = cvs->name;
844 if (cvs->expand && expand_override_enabled)
845 Gexpand = expand_override(cvs->expand);
846 else Gexpand = EXPANDKK;
847 Gabspath = NULL;
848 Gline = NULL; Ggap = Ggapsize = Glinemax = 0;
849 stack[0].node = node;
850 process_delta(node, ENTER);
851 while (1) {
852 if (node->file) {
853 char sha1_ascii[41];
854 uchar sha1[20];
855 out_buffer_init();
856 if (expandflag)
857 finishedit();
858 else
859 snapshotedit();
860 write_sha1_file(out_buffer_text(),
861 out_buffer_count(),
862 "blob", sha1);
863 out_buffer_cleanup();
864 strncpy(sha1_ascii, sha1_to_hex(sha1), 41);
865 node->file->sha1 = atom(sha1_ascii);
867 node = node->down;
868 if (node) {
869 enter_branch(node);
870 goto Next;
872 while ((node = stack[depth].node->to) == NULL) {
873 free(stack[depth].line);
874 if (!depth)
875 goto Done;
876 node = stack[depth--].next_branch;
877 if (node) {
878 enter_branch(node);
879 break;
882 Next:
883 stack[depth].node = node;
884 process_delta(node, EDIT);
886 Done:
887 free(Gkeyval);
888 Gkeyval = NULL;
889 Gkvlen = 0;
890 free(Gabspath);