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