1: /******************************************************
2: * plist.c: Process Source Listings for Publication
3: * Written by Leor Zolman, 4/91
4: *
5: * Usage:
6: * plist [-t#[,@]] [-n[#]] [-c#] [-o] <file(s)>
7: *
8: * Options:
9: * -t#[,@]: Set new tab spacing to every # columns
10: * If @ given, specifies OLD tab spacing
11: * (Both # and @ default to TAB_SETTING)
12: * -n[#]: Generate line numbers, using # as field
13: * width (defaults to NUM_WIDTH)
14: * -c#: Right-justify comments to column #
15: * -o Write output into ".lst" file(s)
16: * If omitted, output goes to stdout.
17: * Compile:
18: * Turbo C:
19: * tcc plist.c [wildargs.obj]
20: * Xenix C:
21: * cc plist.c -o plist
22: ******************************************************/
23:
24: #include <stdio.h>
25: #include <stdlib.h>
26: #include <ctype.h>
27: #include <string.h>
28:
29: #define XENIX 0 /* 1 for Xenix, 0 for DOS */
30: #define MAXLINE 200 /* longest allowable line */
31: #define TAB_SETTING 4 /* default soft tab setting */
32: #define NUM_WIDTH 3 /* default line # width */
33: #define TRUE 1
34: #define FALSE 0
35:
36: char *makofname(char *, char *);
37: void do_line(char *);
38: void dofile(char *);
39:
40: #if XENIX
41: char *strstr( char*, char * );
42: #endif
43:
44: void pass1(char *, char *);
45: void pass2(char *);
46:
47: int docmnts = FALSE; /* do comments */
48: int donums = FALSE; /* line numbering flag */
49: int make_lst = FALSE; /* create .LST files */
50: int numwidth = NUM_WIDTH;
51: int tabstop = TAB_SETTING;
52: int old_tab = TAB_SETTING;
53: int cmnt_col; /* col. to right-justify to */
54:
55: char fmt[20]; /* line numbering fmt spec */
56: FILE *fpi, *fpo; /* Input and output ptrs */
57: int lineno; /* current line number */
58:
59: void main(argc, argv)
60: int argc;
61: char **argv;
62: {
63: int i, j;
64: /* Process command line options: */
65: for (i = 1; i <argc; i++)
66: if (argv[i][0] == '-')
67: {
68: switch (tolower(argv[i][1]))
69: {
70: case 'n': donums = TRUE;
71: if (j = atoi(&argv[i][2]))
72: numwidth = j;
73: break;
74:
75: case 't': j = sscanf(&argv[i][2], "%d,%d",
76: &tabstop, &old_tab);
77: break;
78:
79: case 'c': docmnts = TRUE;
80: cmnt_col = atoi(&argv[i][2]);
81: if (cmnt_col < 30)
82: fprintf(stderr,
83: "WARNING: -c value small!\n");
84: break;
85:
86: case 'o': make_lst = TRUE;
87: break;
88:
89: default: fprintf(stderr, "Unknown option: '%s'\n",
90: argv[i]);
91: exit(0);
92: }
93: for (j = i; j <argc - 1; j++) /* compress */
94: argv[j] = argv[j + 1]; /* arg list */
95: argc-;
96: i-;
97: }
98:
99: if (argc < 2)
100: exit(fprintf(stderr,
101: "Usage: plist [-t#] [-n[#]] files...\n"));
102:
103: if (donums) /* create line number format string */
104: sprintf(fmt, "%%%dd: ", numwidth);
105:
106: for (i = 1; i < argc; i++)
107: dofile(argv[i]); /* process list of given files */
108: }
109:
110: /*
111: * Process the named file.
112: * If make_lst is true, create a .LST file for output.
113: * Otherwise, write output to standard output.
114: */
115:
116: void dofile(fname)
117: char *fname;
118: {
119: char linbuf[MAXLINE];
120: char ofname[30];
121:
122: if ((fpi = fopen(fname, "r")) == NULL)
123: {
124: fprintf(stderr,
125: "\aCan't open input file \"%s\"\n", fname);
126: return;
127: }
128:
129: if (make_lst) /* if making .LST files... */
130: {
131: makofname(ofname, fname);/* create output filename */
132: if ((fpo = fopen(ofname, "w")) == NULL)
133: {
134: fprintf(stderr, "\aCan't create \"%s\"\n", ofname)
135: fclose(fpi);
136: return;
137: }
138: fprintf(stderr, "Creating %s...\n", ofname);
139: }
140: else /* write to standard output */
141: fpo = stdout;
142:
143: for (lineno=1;
144: fgets(linbuf, MAXLINE, fpi); lineno++)
145: do_line(linbuf); /* process each line */
146:
147: fclose(fpi); /* close input file */
148: if (make_lst) /* and, if writing .LST, */
149: fclose(fpo); /* then close that too */
150: }
151:
152: /*
153: * do_line(): Process a line of text
154: */
155:
156: void do_line(cp)
157: char *cp;
158: {
159: char result[MAXLINE], *resultp;
160:
161: resultp = result;
162: if (donums) /* if we're generating line nos. */
163: {
164: sprintf(result, fmt, lineno);
165: resultp += numwidth + 2;
166: }
167:
168: pass1(cp, resultp); /* perform tab translation */
169: if (docmnts)
170: pass2(result); /* right justify comments */
171:
172: fputs(result, fpo); /* write finished line */
173: }
174:
175: /*
176: * Perform tab translation for the line pointed to by cp.
177: * Within comments, interpret soft tab as having spacing
178: * of ORIGINAL soft tab setting, not the new tab setting.
179: */
180:
181: void pass1(cp, resultp)
182: char *cp, *resultp;
183: {
184: char c;
185: int col, old_col; /* current column no. */
186: int in_cmnt = FALSE; /* if in a comment */
187:
188: col = old_col = 1;
189:
190: while (c = *cp++)
191: {
192: if (docmnts && !in_cmnt && c == '/' && *cp == '*')
193: in_cmnt = TRUE;
194:
195: switch (c)
196: {
197: case '\t': /* process a tab: */
198: if (!in_cmnt)
199: { /* if not in a comment */
200: do /* then add real spaces */
201: *resultp++ = ' ';
202: while (col++ % tabstop);
203: do /* and log virtual ones */
204: ;
205: while (old_col++ % old_tab);
206: }
207: else /* if IN a comment, */
208: do /* then translate as */
209: *resultp++ = ' '; /* per the OLD tab size */
210: while (old_col++ % old_tab);
211: break;
212:
213: default: /* handle other chars: */
214: *resultp++ = c;
215: col++; /* just pass on through */
216: old_col++;
217: }
218: }
219: *resultp = '\0';
220: }
221:
222: /*
223: * Justify comments to a common right margin.
224: * Complain if there isn't enough room on a line to fit the
225: * comment into the desired column width.
226: */
227:
228: void pass2(line)
229: char *line;
230: {
231: char cmntbuf[MAXLINE];
232: char *cmnt_start, *cmnt_end;
233: int cmnt_len, code_len, col;
234:
235: if (!(cmnt_start = strstr(line, "/*")) ||
236: !(cmnt_end = strstr(line, "*/")))
237: return; /* If no complete comment, return */
238:
239: *(cmnt_end += 2) = '\0'; /* found a comment */
240: strcpy(cmntbuf, cmnt_start); /* save the comment */
241: cmnt_len = strlen(cmntbuf); /* get its length */
242:
243: while (isspace(*-cmnt_start)) /* find last non- */
244: ; /* space before the comment */
245: *++cmnt_start = '\0'; /* and terminte the code */
246:
247: code_len = cmnt_start - line; /* length of code */
248: if (code_len + cmnt_len > cmnt_col) /* comment fit? */
249: { /* no. complain. */
250: fprintf(stderr,
251: "\aWarning: comment on line %d doesn't fit.\n",
252: lineno);
253: strcat(line, cmntbuf); /* and concatenate it */
254: }
255: else
256: { /* comment will fit. Pad with spaces: */
257: for (col = code_len;
258: col < (cmnt_col - cmnt_len); col++)
259: line[col] = ' ';
260: strcpy(&line[col], cmntbuf); /* add comment */
261: }
262: strcat(line, "\n");
263: }
264:
265: /*
266: * Create output file name by replacing extension of
267: * original filename with ".lst":
268: */
269:
270: char *makofname(dest, orig)
271: char *dest, *orig;
272: {
273: int i;
274:
275: strcpy(dest, orig);
276: for (i = 0; dest[i] && dest[i] != '.'; i++)
277: ;
278: strcpy(&dest[i], ".lst");
279: return dest;
280: }
281:
282: #if XENIX
283: /*
284: * Search for first occurence of substring s2 in s1:
285: * Return a pointer to the first occurence, or NULL if
286: * none was found.
287: * (provided for Xenix only; this function is included
288: * with most ANSI-C distribution libraries)
289: */
290:
291: char *strstr(s1, s2)
292: char *s1, *s2;
293: {
294: int i, j, nposs;
295: char *p1;
296:
297: int len1 = strlen(s1);
298: int len2 = strlen(s2);
299:
300: if (len1 < len2) /* can't have substring longer */
301: return NULL; /* than entire string! */
302:
303: nposs = len1 - len2; /* # of possible positions */
304:
305: for (i = 0; i <= nposs; i++)
306: { /* check each possible position */
307: for (j = 0, p1 = &s1[i]; j < len2; j++)
308: if (*pl++ != s2[j])
309: break; /* break on 1st mismatch */
310: if (j == len2) /* if no mismatches, */
311: return &s1[i]; /* then pattern was found */
312: }
313: return NULL; /* didn't find the pattern */
314: }
315: #endif
/* End of File */