1: static char *RCSid =
2: "$Header: sccstorcs.c,v 1.4 84/10/17 21:12:11 root Exp $";
3:
4: /*
5: * SCCSTORCS - build RCS file from SCCS file preserving deltas.
6: * Author: Ken Greer
7: *
8: * Copyright (c) 1983 by Kenneth L. Greer
9: *
10: * All rights reserved. No part of this software may be sold or distributed
11: * in any form or by any means without the prior written permission of the
12: * author.
13: *
14: * $Log: sccstorcs.c,v $
15: * Revision 1.4 84/10/17 21:12:11 root
16: * Added check for having multiple deltas in a row for the same revision.
17: * --ks
18: *
19: * Revision 1.3 84/10/17 20:53:18 root
20: * Put in SCCS string in comment for telling who checked it in..
21: * --ks
22: *
23: * Revision 1.2 84/10/17 12:22:14 root
24: * Fixed the case when a delta was removed.
25: * Also, use -f on checkin so comments are kept even if the file
26: * didn't change between deltas.
27: * --ks
28: *
29: * Revision 1.1 84/10/07 14:59:47 root
30: * Initial revision
31: *
32: * Revision 1.2 83/03/27 11:21:17 root
33: * Returns non-zero exit codes on soft errors also.
34: *
35: * Revision 1.1 83/03/24 14:33:24 root
36: * Initial revision
37: *
38: */
39:
40: #include <stdio.h>
41:
42: #define TRUE 1
43: #define FALSE 0
44: #define SOH 001 /* SCCS lines start with SOH (Control-A) */
45: #define RCS "rcs -q"
46: #define GET "get -s"
47: #define CI "ci -q -f"
48:
49: #define prefix(a, b) (strncmp(a, b, strlen(a)) == 0)
50: #define null(str) ((str) == NULL ? "<null>\n" : (str))
51:
52: int
53: trace = FALSE, /* just show what would be done, don't run commands */
54: verbose = FALSE; /* Print commands before executing */
55:
56: typedef struct delta
57: {
58: char *revision;
59: char *commentary;
60: struct delta *next;
61: } DELTA;
62:
63: typedef struct userlist
64: {
65: char *user;
66: struct userlist *next;
67: } USERLIST;
68:
69: typedef struct
70: {
71: DELTA *deltas;
72: USERLIST *userlist;
73: char *description;
74: } ;
75:
76:
77: quit (fmt, args)
78: char *fmt;
79: {
80: fprintf (stderr, "sccstorcs: ");
81: _doprnt(fmt, &args, stderr);
82: exit (1);
83: }
84:
85: char *
86: xalloc (size)
87: unsigned size;
88: {
89: extern char *malloc ();
90: char *p;
91: if ((p = malloc (size)) == NULL)
92: quit ("Out of Memory.\n");
93: return (p);
94: }
95:
96: /*
97: * Allocate space for string and copy str to it.
98: */
99: char *
100: string (str)
101: char *str;
102: {
103: register char *p = xalloc ((unsigned) (strlen (str) + 1));
104: strcpy (p, str);
105: return (p);
106: }
107:
108: /*
109: * Return pointer to the final file name in a path.
110: * I.e. sname ("/foo/baz/mumble") returns a pointer to "mumble".
111: */
112: char *
113: sname (s)
114: register char *s;
115: {
116: register char *p;
117:
118: for (p = s; *p;)
119: if (*p++ == '/')
120: s = p;
121: return (s);
122: }
123:
124: DELTA *
125: new_delta (line)
126: char *line;
127: {
128: register DELTA *delta;
129: char rev[32];
130:
131: sscanf (line, "%*s %*s %s", rev);
132: delta = (DELTA *) xalloc (sizeof (DELTA));
133: delta -> revision = string (rev);
134: delta -> commentary = NULL;
135: return (delta);
136: }
137:
138: char *
139: concat (old_str, str)
140: char *old_str, *str;
141: {
142: register int len;
143: register char *newstring;
144:
145: if (old_str == NULL)
146: return (string (str));
147:
148: len = strlen (old_str) + strlen (str);
149: newstring = (char *) xalloc ((unsigned) (len + 1));
150: strcpy (newstring, old_str);
151: strcat (newstring, str);
152: free (old_str);
153: return (newstring);
154: }
155:
156: trimtail (line)
157: char *line;
158: {
159: register char *p = line;
160: while (*p) p++;
161: while (p > line && p[-1] <= ' ')
162: p--;
163: *p = '\0';
164: }
165:
166: USERLIST *
167: collect_userlist (fd)
168: FILE *fd;
169: {
170: char line[128];
171: USERLIST *userlist = NULL, *newuser;
172: while (fgets (line, sizeof line, fd))
173: {
174: if (line[0] == SOH && line[1] == 'U') /* End of userlist */
175: break;
176: trimtail (line);
177: newuser = (USERLIST *) xalloc (sizeof (USERLIST));
178: newuser -> user = string (line);
179: newuser -> next = userlist;
180: userlist = newuser;
181: }
182: return (userlist);
183: }
184:
185: *
186: collect_header (fd)
187: FILE *fd;
188: {
189: DELTA *head = NULL, *delta;
190: USERLIST *userlist = NULL;
191: static HEADER header;
192: char line[512], *description = NULL;
193: while (fgets (line, sizeof line, fd))
194: {
195: if (line[0] != SOH)
196: continue;
197: if (line[1] == 'I') /* The first INCLUDE */
198: break;
199: switch (line[1])
200: {
201: case 'd': /* New delta */
202: #ifdef PURDUE_EE
203: if (line[3] == 'R')
204: while (fgets (line, sizeof line, fd))
205: if (line[0] == SOH && line[1] == 'd' && line[3] != 'R')
206: break;
207: #endif
208: delta = new_delta (line);
209: #ifdef PURDUE_EE
210: if (!head || strcmp(delta -> revision, head -> revision)) {
211: #endif
212: delta -> next = head;
213: head = delta;
214: #ifdef PURDUE_EE
215: }
216: #endif
217: #ifndef PURDUE_EE
218: break;
219: #endif
220: case 'c': /* Commentary */
221: delta -> commentary = concat (delta -> commentary, &line[3]);
222: break;
223: case 'u':
224: userlist = collect_userlist (fd);
225: break;
226: case 't':
227: while (fgets (line, sizeof line, fd) && !prefix("\1T", line))
228: description = concat (description, line);
229: }
230: }
231: header.userlist = userlist;
232: header.deltas = head;
233: header.description = description;
234: return (&header);
235: }
236:
237: /*
238: * Convert SCCS file to RCS file
239: */
240: HEADER *
241: read_sccs (sccsfile)
242: char *sccsfile;
243: {
244: HEADER *header;
245: FILE *fd;
246: if (strncmp (sname (sccsfile), "s.", 2) != 0) /* An SCCS file? */
247: {
248: fprintf (stderr, "%s: not an SCCS file.\n", sccsfile);
249: return (NULL);
250: }
251: if ((fd = fopen (sccsfile, "r")) == NULL)
252: {
253: fprintf (stderr, "%s: cannot open.\n", sccsfile);
254: return (NULL);
255: }
256: header = collect_header (fd);
257: fclose (fd);
258: return (header);
259: }
260:
261: install_userlist (userlist, rcsfile)
262: register USERLIST *userlist;
263: char *rcsfile;
264: {
265: char command[512];
266: int count;
267: if (userlist == NULL)
268: return (0);
269: sprintf (command, "%s -a", RCS);
270: for (count = 0; userlist; userlist = userlist -> next, count++)
271: {
272: if (count > 0)
273: strcat (command, ",");
274: strcat (command, userlist -> user);
275: }
276: strcat (command, " ");
277: strcat (command, rcsfile);
278: if (trace || verbose)
279: printf ("%% %s\n", command);
280: if (trace)
281: return (0);
282: return (system (command));
283: }
284:
285: initialize_rcsfile (description, rcsfile)
286: char *description, *rcsfile;
287: {
288: char command[512];
289: extern FILE *popen();
290: FILE *pd;
291:
292: sprintf (command, "%s -i -U %s", RCS, rcsfile);
293: if (trace || verbose)
294: printf ("%% %s\n", command);
295: if (trace)
296: {
297: printf ("Description:\n%s\n", null(description));
298: return (0);
299: }
300: if ((pd = popen (command, "w")) == NULL)
301: return (-1);
302: fprintf (pd, "%s", description ? description : "\n");
303: return (pclose (pd));
304: }
305:
306: install_deltas (delta, sccsfile, rcsfile)
307: register DELTA *delta;
308: char *sccsfile, *rcsfile;
309: {
310: char command[512];
311: for (; delta; delta = delta -> next)
312: {
313: /*
314: * Get the SCCS file.
315: */
316: sprintf (command, "%s -p -r%s %s > %s",
317: GET, delta -> revision, sccsfile, rcsfile);
318: if (trace || verbose)
319: printf("%% %s\n", command);
320: if (!trace)
321: {
322: if (system (command))
323: return (-1);
324: }
325:
326: sprintf (command, "%s -r%s %s", CI, delta -> revision, rcsfile);
327: if (trace || verbose)
328: printf("%% %s\n", command);
329: if (trace)
330: printf("Commentary:\n%s\n", null(delta -> commentary));
331: else
332: {
333: extern FILE *popen ();
334: FILE *pd;
335: int x;
336: if ((pd = popen (command, "w")) == NULL)
337: return (-1);
338: if (delta -> commentary)
339: fprintf (pd, delta -> commentary);
340: if ((x = pclose (pd)) != 0)
341: return (x);
342: }
343: }
344: return (0);
345: }
346:
347: finalize_rcsfile (rcsfile)
348: char *rcsfile;
349: {
350: char command[512];
351: sprintf (command, "%s -L %s", RCS, rcsfile);
352: if (trace || verbose)
353: printf ("%% %s\n", command);
354: if (trace)
355: return (0);
356: return (system (command));
357: }
358:
359: build_new_rcs_file (header, sccsfile)
360: HEADER *header;
361: char *sccsfile;
362: {
363: char *rcsfile = &(sname (sccsfile))[2];
364:
365: if (initialize_rcsfile (header -> description, rcsfile))
366: quit ("Error initializing new rcs file %s\n", rcsfile);
367:
368: if (install_userlist (header -> userlist, rcsfile))
369: quit ("Error installing user access list to rcs file %s\n", rcsfile);
370:
371: if (install_deltas (header -> deltas, sccsfile, rcsfile))
372: quit ("Error installing delta to rcs file %s\n", rcsfile);
373:
374: if (finalize_rcsfile (rcsfile))
375: quit ("Error setting defaults to rcs file %s\n", rcsfile);
376: }
377:
378: (sccsfile, header)
379: char *sccsfile;
380: register HEADER *header;
381: {
382: register DELTA *d;
383: register USERLIST *u;
384:
385: printf ("\n%s:\n", sccsfile);
386: printf ("------------------------------------------------------------\n");
387: if (header -> description)
388: printf ("Descriptive text:\n%s", header -> description);
389:
390: if (header -> userlist)
391: {
392: printf ("\nUser access list:\n");
393: for (u = header -> userlist; u; u = u -> next)
394: printf ("%s\n", u -> user);
395: }
396:
397: for (d = header -> deltas; d; d = d -> next)
398: {
399: printf ("\nRelease: %s\n", d -> revision);
400: printf ("Commentary:\n%s", d -> commentary);
401: }
402: printf ("------------------------------------------------------------\n");
403: }
404:
405: main (argc, argv)
406: char **argv;
407: {
408: int errors = 0;
409:
410: for (; argc > 1 && argv[1][0] == '-'; argc--, argv++)
411: {
412: switch (argv[1][1])
413: {
414: case 'v':
415: verbose = TRUE;
416: break;
417: case 't':
418: trace = TRUE;
419: break;
420: default:
421: fprintf (stderr, "Unknown switch \"%s\".\n", argv[1]);
422: exit (1);
423: }
424: }
425:
426: if (argc <= 1)
427: quit ("Usage: sccstorcs [-t -v] s.file ...\n");
428:
429: for (; argc > 1; argc--, argv++)
430: {
431: HEADER *header;
432: char *sccsfile;
433: sccsfile = argv[1];
434: if ((header = read_sccs (sccsfile)) != NULL)
435: {
436: if (trace)
437: print_header (sccsfile, header);
438: build_new_rcs_file (header, sccsfile);
439: }
440: else
441: errors++;
442: }
443: exit (errors);
444: }