xref: /illumos-gate/usr/src/cmd/refer/addbib.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
1 /*
2  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
7 /*	  All Rights Reserved  	*/
8 
9 /*
10  * Copyright (c) 1980 Regents of the University of California.
11  * All rights reserved. The Berkeley software License Agreement
12  * specifies the terms and conditions for redistribution.
13  */
14 
15 #pragma ident	"%Z%%M%	%I%	%E% SMI"
16 
17 
18 #include <locale.h>
19 #include <stdio.h>
20 #include <ctype.h>
21 #include <signal.h>
22 #define	MAXENT 50
23 
24 struct skeleton {
25 	char prompt[20];	/* prompt user for entry */
26 	char keylet[5]; 	/* key letter for database */
27 } bibskel[MAXENT] = {
28 	"   Author:",	"%A",
29 	"    Title:",	"%T",
30 	"  Journal:",	"%J",
31 	"   Volume:", 	"%V",
32 	"    Pages:",	"%P",
33 	"Publisher:",	"%I",
34 	"     City:", 	"%C",
35 	"     Date:", 	"%D",
36 	"    Other:",	"%O",
37 	" Keywords:",	"%K",	};
38 
39 int entries = 10;	/* total number of entries in bibskel */
40 int abstract = 1;	/* asking for abstracts is the default */
41 
42 static void addbib(FILE *, char *);
43 void bibedit(FILE *, char *, char *);
44 static void instruct(void);
45 static void rd_skel(char *);
46 static void trim(char []);
47 
48 static void
49 usage(void)			/* print proper usage and exit */
50 {
51 	puts(gettext("Usage:  addbib [-p promptfile] [-a] database\n\
52 \t-p: the promptfile defines alternate fields\n\
53 \t-a: don't include prompting for the abstract\n"));
54 	exit(1);
55 }
56 
57 int
58 main(int argc, char *argv[])	/* addbib: bibliography entry program */
59 {
60 	FILE *fp, *fopen();
61 	int i;
62 
63 	(void) setlocale(LC_ALL, "");
64 
65 #if !defined(TEXT_DOMAIN)
66 #define	TEXT_DOMAIN "SYS_TEST"
67 #endif
68 	(void) textdomain(TEXT_DOMAIN);
69 
70 	if (argc == 1) {
71 		puts(gettext(
72 		    "You must specify a bibliography file (database)."));
73 		usage();
74 	}
75 	for (i = 1; argv[i][0] == '-'; i++) {
76 		if (argv[i][1] == 'p') {
77 			if (i >= argc - 2) {
78 				puts(gettext("Not enough arguments for "
79 				    "-p option."));
80 				usage();
81 			}
82 			rd_skel(argv[++i]);
83 		} else if (argv[i][1] == 'a') {
84 			if (i >= argc - 1) {
85 				puts(gettext(
86 				    "No bibliofile specified after -a."));
87 				usage();
88 			}
89 			abstract = 0;
90 		} else {	/* neither -p nor -a */
91 			printf(gettext(
92 			    "Invalid command line flag: %s\n"), argv[i]);
93 			usage();
94 		}
95 	}
96 	if (i < argc - 1) {
97 		puts(gettext("Too many arguments with no options."));
98 		usage();
99 	}
100 	if ((fp = fopen(argv[i], "a")) == NULL) {
101 		perror(argv[i]);
102 		exit(1);
103 	}
104 	addbib(fp, argv[i]);	/* loop for input */
105 	return (0);
106 }
107 
108 static void
109 addbib(FILE *fp, char *argv)	/* add entries to a bibliographic database */
110 {
111 	char line[BUFSIZ];
112 	int i = 0, firstln, repeat = 0, escape = 0;
113 
114 	printf(gettext("Instructions? "));
115 	fgets(line, BUFSIZ, stdin);
116 	if (line[0] == 'y' || line[0] == 'Y')
117 		instruct();
118 	while (1) {
119 		putchar('\n');
120 		putc('\n', fp);
121 		for (i = 0; i < entries; i++) {
122 			printf("%s\t", gettext(bibskel[i].prompt));
123 			if (fgets(line, BUFSIZ, stdin) == NULL) {
124 				clearerr(stdin);
125 				break;
126 			}
127 			if (line[0] == '-' && line[1] == '\n') {
128 				i -= 2;
129 				if (i < -1) {
130 					printf(gettext("Too far back.\n"));
131 					i++;
132 				}
133 				continue;
134 			} else if (line[strlen(line)-2] == '\\') {
135 				if (line[0] != '\\') {
136 					line[strlen(line)-2] = '\n';
137 					line[strlen(line)-1] = NULL;
138 					trim(line);
139 					fprintf(fp, "%s %s",
140 					    bibskel[i].keylet, line);
141 				}
142 				printf("> ");
143 				again:
144 				fgets(line, BUFSIZ, stdin);
145 				if (line[strlen(line)-2] == '\\') {
146 					line[strlen(line)-2] = '\n';
147 					line[strlen(line)-1] = NULL;
148 					trim(line);
149 					fputs(line, fp);
150 					printf("> ");
151 					goto again;
152 				}
153 				trim(line);
154 				fputs(line, fp);
155 			} else if (line[0] != '\n') {
156 				trim(line);
157 				fprintf(fp, "%s %s", bibskel[i].keylet, line);
158 			}
159 		}
160 		if (abstract) {
161 			puts(gettext(" Abstract: (ctrl-d to end)"));
162 			firstln = 1;
163 			while (fgets(line, BUFSIZ, stdin)) {
164 				if (firstln && line[0] != '%') {
165 					fprintf(fp, "%%X ");
166 					firstln = 0;
167 				}
168 				fputs(line, fp);
169 			}
170 			clearerr(stdin);
171 		}
172 		fflush(fp);	/* write to file at end of each cycle */
173 		if (ferror(fp)) {
174 			perror(argv);
175 			exit(1);
176 		}
177 		editloop:
178 		printf(gettext("\nContinue? "));
179 			fgets(line, BUFSIZ, stdin);
180 		if (line[0] == 'e' || line[0] == 'v') {
181 			bibedit(fp, line, argv);
182 			goto editloop;
183 		}
184 		if (line[0] == 'q' || line[0] == 'n')
185 			return;
186 	}
187 }
188 
189 static void
190 trim(char line[])		/* trim line of trailing white space */
191 {
192 	int n;
193 
194 	n = strlen(line);
195 	while (--n >= 0) {
196 		if (!isspace(line[n]))
197 			break;
198 	}
199 	line[++n] = '\n';
200 	line[++n] = NULL;
201 }
202 
203 void
204 bibedit(FILE *fp, char *cmd, char *arg)	/* edit database with edit, ex, or vi */
205 {
206 	int i = 0, status;
207 
208 	fclose(fp);
209 	while (!isspace(cmd[i]))
210 		i++;
211 	cmd[i] = NULL;
212 	if (fork() == 0) {
213 		if (cmd[0] == 'v' && cmd[1] == 'i')
214 			execlp(cmd, cmd, "+$", arg, NULL);
215 		else /* either ed, ex, or edit */
216 			execlp(cmd, cmd, arg, NULL);
217 	}
218 	signal(SIGINT, SIG_IGN);
219 	signal(SIGQUIT, SIG_IGN);
220 	wait(&status);
221 	signal(SIGINT, SIG_DFL);
222 	signal(SIGQUIT, SIG_DFL);
223 	if ((fp = fopen(arg, "a")) == NULL) {
224 		perror(arg);
225 		exit(1);
226 	}
227 }
228 
229 static void
230 instruct(void)		/* give user elementary directions */
231 {
232 	putchar('\n');
233 	puts(gettext(
234 	    "Addbib will prompt you for various bibliographic fields.\n"
235 "If you don't need a particular field, just hit RETURN,\n"
236 "\tand that field will not appear in the output file.\n"
237 "If you want to return to previous fields in the skeleton,\n"
238 "\ta single minus sign will go back a field at a time.\n"
239 "\t(This is the best way to input multiple authors.)\n"
240 "If you have to continue a field or add an unusual field,\n"
241 "\ta trailing backslash will allow a temporary escape.\n"
242 "Finally, (without -a) you will be prompted for an abstract\n"
243 "Type in as many lines as you need, and end with a ctrl-d.\n"
244 "To quit, type `q' or `n' when asked if you want to continue.\n"
245 "To edit the database, type `edit', `vi', or `ex' instead."));
246 
247 }
248 
249 static void
250 rd_skel(char *arg)		/* redo bibskel from user-supplied file */
251 {
252 	FILE *pfp, *fopen();
253 	char str[BUFSIZ];
254 	int entry, i, j;
255 
256 	if ((pfp = fopen(arg, "r")) == NULL) {
257 		fprintf(stderr, gettext("Promptfile "));
258 		perror(arg);
259 		exit(1);
260 	}
261 	for (entry = 0; fgets(str, BUFSIZ, pfp); entry++) {
262 		for (i = 0; str[i] != '\t' && str[i] != '\n'; i++)
263 			bibskel[entry].prompt[i] = str[i];
264 		bibskel[entry].prompt[i] = NULL;
265 		if (str[i] == '\n') {
266 			fprintf(stderr, gettext(
267 			    "No tabs between promptfile fields.\n"));
268 			fprintf(stderr, gettext(
269 			    "Format: prompt-string <TAB> %%key\n"));
270 			exit(1);
271 		}
272 		for (i++, j = 0; str[i] != '\n'; i++, j++)
273 			bibskel[entry].keylet[j] = str[i];
274 		bibskel[entry].keylet[j] = NULL;
275 
276 		if (entry >= MAXENT) {
277 			fprintf(stderr, gettext(
278 			    "Too many entries in promptfile.\n"));
279 			exit(1);
280 		}
281 	}
282 	entries = entry;
283 	fclose(pfp);
284 }
285