1 /*	Code to handle Abbreviation Expansions
2 	for MicroEMACS 4.00
3 	(C)Copyright 1995 by Daniel M. Lawrence
4 */
5 
6 #include	<stdio.h>
7 #include	"estruct.h"
8 #include	"eproto.h"
9 #include	"edef.h"
10 #include	"elang.h"
11 
ab_save(c)12 VOID PASCAL NEAR ab_save(c)
13 
14 char c;		/* character to add to current word buffer */
15 
16 {
17 	char *s;	/* ptr to cycle chars */
18 
19 	/* only in ABBREV mode */
20 	if ((curbp->b_mode & MDABBR) == 0)
21 		return;
22 
23 	/* is the buffer full? */
24 	if (ab_pos == ab_end) {
25 		/* shift all the letters down one */
26 		s = ab_word;
27 		while (s < ab_end) {
28 			*s = *(s+1);
29 			++s;
30 		}
31 		ab_pos--;
32 	}
33 
34 	/* add the character */
35 	*ab_pos++ = c;
36 	*ab_pos = 0;
37 }
38 
ab_expand()39 VOID PASCAL NEAR ab_expand()
40 
41 {
42 	char *exp;	/* expansion of current symbol */
43 	char c;		/* current character to insert */
44 
45 	/* only in ABBREV mode, never in VIEW mode */
46 	if ((curbp->b_mode & MDABBR) == 0 ||
47 	    (curbp->b_mode & MDVIEW) == MDVIEW)
48 		return;
49 
50 	/* is the current buffer a symbol in the abbreviation table? */
51 	if ((exp = ab_lookup(ab_word)) != NULL) {
52 
53 		/* backwards delete the symbol */
54 		ldelete(-((long)strlen(ab_word)), FALSE);
55 
56 		/* and insert its expansion */
57 		while (*exp) {
58 
59 			c = *exp++;
60 
61 			/*
62 			 * If a space was typed, fill column is defined, the
63 			 * argument is non-negative, wrap mode is enabled, and
64 			 * we are now past fill column, perform word wrap.
65 			 */
66 			if (c == ' ' && (curwp->w_bufp->b_mode & MDWRAP) &&
67 			    fillcol > 0 &&
68 			    getccol(FALSE) > fillcol)
69 				execkey(&wraphook, FALSE, 1);
70 
71 			linsert(1, c);
72 		}
73 
74 		/* ring the bell */
75 		if (ab_bell)
76 			TTbeep();
77 	}
78 
79 	/* reset the word buffer */
80 	ab_pos = ab_word;
81 	*ab_pos = 0;
82 }
83 
84 /* add a new abbreviation */
85 
add_abbrev(f,n)86 int PASCAL NEAR add_abbrev(f, n)
87 
88 int f, n;	/* numeric flag and argument */
89 
90 {
91 	register int status;	/* status return */
92 	char sym_name[MAXSYM+1];/* name of symbol to fetch */
93 	char value[NSTRING];	/* value to set symbol to */
94 
95 	/* first get the symbol name */
96 	status = mlreply(TEXT231, sym_name, MAXSYM + 1);
97 /*			 "Abbreviation to set: " */
98 	if (status != TRUE)
99 		return(status);
100 
101 	/* get the value for that expansion */
102 	if (f == TRUE)
103 		strcpy(value, int_asc(n));
104 	else {
105 		status = mlreply(TEXT53, &value[0], NSTRING);
106 /*				 "Value: " */
107 		if (status == ABORT)
108 			return(status);
109 	}
110 
111 	/* and add the abbreviation to the list */
112 	return(ab_insert(sym_name, value));
113 }
114 
115 /* Delete a single abbreviation */
116 
del_abbrev(f,n)117 int PASCAL NEAR del_abbrev(f, n)
118 
119 int f, n;	/* numeric flag and argument */
120 
121 {
122 	register int status;	/* status return */
123 	char sym_name[MAXSYM+1];/* name of symbol to fetch */
124 
125 	/* first get the symbol name */
126 	status = mlreply(TEXT232, sym_name, MAXSYM + 1);
127 /*			 "Abbreviation to delete: " */
128 	if (status != TRUE)
129 		return(status);
130 
131 	/* and yank the abbreviation to the list */
132 	return(ab_delete(sym_name));
133 }
134 
135 /* Kill all abbreviations */
136 
kill_abbrevs(f,n)137 int PASCAL NEAR kill_abbrevs(f, n)
138 
139 int f, n;	/* numeric flag and argument */
140 
141 {
142 	/* kill them! */
143 	return(ab_clean());
144 }
145 
desc_abbrevs(f,n)146 int PASCAL NEAR desc_abbrevs(f, n)
147 
148 int f, n;	/* numeric flag and argument */
149 
150 {
151 	register BUFFER *abbbuf;/* buffer to put abbreviation list into */
152 	register ABBREV *cur_node;/* ptr to current abbreviation */
153 	char outseq[NSTRING];	/* output buffer for keystroke sequence */
154 
155 	/* and get a buffer for it */
156 	abbbuf = bfind(TEXT234, TRUE, BFINVS);
157 /*		   "Abbreviation list" */
158 	if (abbbuf == NULL || bclear(abbbuf) == FALSE) {
159 		mlwrite(TEXT235);
160 /*			"Can not display abbreviation list" */
161 		return(FALSE);
162 	}
163 
164 	/* let us know this is in progress */
165 	mlwrite(TEXT233);
166 /*		"[Building Abbreviation list]" */
167 
168 	/* build the abbreviation list */
169 	cur_node = ab_head;
170 	while (cur_node != (ABBREV *)NULL) {
171 
172 		/* add in the abbreviation symbol name */
173 		strcpy(outseq, cur_node->ab_sym);
174 		pad(outseq, 20);
175 
176 		/* add it's expansion */
177 		strncat(outseq, cur_node->ab_exp, NSTRING - 20);
178 		outseq[NSTRING - 1] = 0;
179 
180 		/* and add it as a line into the buffer */
181 		if (addline(abbbuf, outseq) != TRUE)
182 			return(FALSE);
183 
184 		cur_node = cur_node->ab_next;
185 	}
186 
187 	/* display the list */
188 	wpopup(abbbuf);
189 	mlerase();	/* clear the mode line */
190 	return(TRUE);
191 }
192 
193 /* insert a list of all the current abbreviations into the current buffer */
194 
ins_abbrevs(f,n)195 int PASCAL NEAR ins_abbrevs(f, n)
196 
197 int f, n;	/* numeric flag and argument */
198 
199 {
200 	register ABBREV *cur_node;/* ptr to current abbreviation */
201 
202 	/* insert the abbreviation list in the current buffer */
203 	cur_node = ab_head;
204 	while (cur_node != (ABBREV *)NULL) {
205 
206 		/* insert the abbreviation symbol as a line */
207 		if (addline(curbp, cur_node->ab_sym) != TRUE)
208 			return(FALSE);
209 
210 		/* now a line with the expansion */
211 		if (addline(curbp, cur_node->ab_exp) != TRUE)
212 			return(FALSE);
213 
214 		cur_node = cur_node->ab_next;
215 	}
216 
217 	return(TRUE);
218 }
219 
def_abbrevs(f,n)220 int PASCAL NEAR def_abbrevs(f, n)
221 
222 int f,n;	/* prefix flag and argument */
223 
224 {
225 	register BUFFER *bp;	/* ptr to buffer to dump */
226 	register LINE *lp;	/* ptr to current line in our buffer */
227 	register llength;	/* length of the current line being examined */
228 	char cur_sym[MAXSYM+1];	/* current symbol being defined */
229 	char cur_exp[NSTRING];	/* current expansion */
230 
231 	/* get the buffer to load abbreviations from */
232 	bp = getdefb();
233 	bp = getcbuf(TEXT236, bp ? bp->b_bname : mainbuf, TRUE);
234 /*		     "Define Abbreviations in buffer" */
235 	if (bp == NULL)
236 		return(ABORT);
237 
238 	/* step throught the buffer */
239 	lp = lforw(bp->b_linep);
240 	while (lp != bp->b_linep) {
241 
242 		/* get a symbol name */
243 		llength = lused(lp);
244 		if (llength > MAXSYM)
245 			llength = MAXSYM;
246 		strncpy(cur_sym, ltext(lp), llength);
247 		cur_sym[llength] = 0;
248 
249 		/* advance to the next line in the buffer */
250 		lp = lforw(lp);
251 		if (lp == bp->b_linep)
252 			break;
253 
254 		/* and an expansion for that symbol */
255 		llength = lused(lp);
256 		if (llength > MAXSYM)
257 			llength = MAXSYM;
258 		strncpy(cur_exp, ltext(lp), llength);
259 		cur_exp[llength] = 0;
260 
261 		/* add it to the current abbreviation list */
262 		ab_insert(cur_sym, cur_exp);
263 
264 		/* on to the next pair */
265 		lp = lforw(lp);
266 	}
267 }
268 
ab_init()269 VOID PASCAL NEAR ab_init()
270 
271 {
272 	ab_head = (ABBREV *)NULL; /* abbreviation list empty */
273  	ab_bell = FALSE;	/* no ringing please! */
274 	ab_cap = FALSE;		/* don't match capatilization on expansion */
275 	ab_quick = FALSE;	/* no aggressive expansion */
276 	ab_pos = ab_word;	/* no word accumulated yet */
277 	ab_end = &ab_word[NSTRING - 1];	/* ptr to detect end of this buffer */
278 }
279 
280 /* ab_insert:	Insert a <sym> in the abbreviation list defined as
281 		<expansion>
282 */
283 
ab_insert(sym,expansion)284 int PASCAL NEAR ab_insert(sym, expansion)
285 
286 char *sym;		/* symbol to expand */
287 char *expansion;	/* string to expand to */
288 
289 {
290 	ABBREV *new_node;	/* pointer to the newly allocated node */
291 	ABBREV *cur_node;	/* pointer to travel down list */
292 
293 	/* nothing longer than MAXSYM please */
294 	if (strlen(sym) > MAXSYM)
295 		sym[MAXSYM + 1] = 0;
296 
297 	/* is this already defined? */
298 	if (ab_lookup(sym) != NULL)
299 		ab_delete(sym);
300 
301 	/* allocate a new node to hold abbreviation */
302 	new_node = (ABBREV *)room(sizeof(ABBREV)+strlen(expansion)+1);
303 	if (new_node == NULL)
304 		return(FALSE);
305 
306 	/* copy data to that node */
307 	strcpy(new_node->ab_sym, sym);
308 	strcpy(new_node->ab_exp, expansion);
309 
310 	/* do we have an empty list */
311 	if (ab_head == NULL) {
312 
313 		ab_head = new_node;
314 		new_node->ab_next = NULL;
315 
316 	} else {
317 
318 		/* does our new node go before the first */
319 		if (strcmp(sym, ab_head->ab_sym) < 0) {
320 
321 			/* insert the node before the first node */
322 			new_node->ab_next = ab_head;
323 			ab_head = new_node;
324 
325 		} else {
326 
327 			/* search for the right place to insert */
328 			cur_node = ab_head;
329 			while (cur_node->ab_next != NULL) {
330 
331 				if (strcmp(sym, cur_node->ab_next->ab_sym) > 0) {
332 
333 					/* insert after cur_node */
334 					new_node->ab_next = cur_node->ab_next;
335 					cur_node->ab_next = new_node;
336 					return(TRUE);
337 				}
338 
339 				/* step to the next node */
340 				cur_node = cur_node->ab_next;
341 			}
342 
343 			/* insert after the last node */
344 			cur_node->ab_next = new_node;
345 			new_node->ab_next = NULL;
346 		}
347 	}
348 
349 	return(TRUE);
350 }
351 
352 /* ab_lookup:	look up and return the expansion of <sym>.
353 		Return a NULL if it is not in the list
354 */
355 
ab_lookup(sym)356 char *PASCAL NEAR ab_lookup(sym)
357 
358 char *sym;	/* name of the symbol to look up */
359 
360 {
361 
362 	ABBREV *cur_node;	/* ptr to look through list */
363 
364 	/* starting at the head, step through the list */
365 	cur_node = ab_head;
366 	while (cur_node != NULL) {
367 
368 		/* if there is a match, return the expansion */
369 		if (strcmp(sym,cur_node->ab_sym) == 0) {
370 			return(cur_node->ab_exp);
371 		}
372 		cur_node=cur_node->ab_next;
373 	}
374 
375 	/* at the end, return NULL */
376 	return(NULL);
377 }
378 
379 /* ab_delete:	Delete <sym> from the abbreviation list */
380 
ab_delete(sym)381 int PASCAL NEAR ab_delete(sym)
382 
383 char *sym;
384 
385 {
386 
387 	ABBREV *cur_node,*previous;	/* ptr to look through list */
388 
389 	/* start at beginning */
390 	previous=NULL;
391 	cur_node=ab_head;
392 
393 	/* step through the list */
394 	while(cur_node!=NULL) {
395 
396 		/* if there is a match, delete the node */
397 		if (previous == NULL && strcmp(sym,cur_node->ab_sym) == 0) {
398 
399 			/*important: resets our head pointer*/
400 			ab_head=cur_node->ab_next;
401 			free(cur_node);
402 			return(TRUE);
403 
404 		} else if (strcmp(sym,cur_node->ab_sym) == 0
405 			    && cur_node != NULL) {
406 			previous->ab_next=NULL;
407 			free(cur_node);
408 			return(TRUE);
409 		}
410 
411 		/*makes sure our previous pointer steps with cur_node*/
412 		previous = cur_node;
413 		cur_node = cur_node->ab_next;
414 	}
415 
416 	/* at the end, no match to delete */
417 	return(FALSE);
418 }
419 
ab_clean()420 int PASCAL NEAR ab_clean()
421 
422 {
423 
424 	ABBREV *cur_node;	/* ptr to look through list */
425 	ABBREV *next;		/* ptr to next abbreviation */
426 
427 	/* start at the beginning, */
428 	cur_node = ab_head;
429 
430 	/* cycle through the list */
431 	while (cur_node != (ABBREV *)NULL) {
432 		next = cur_node->ab_next;
433 		free(cur_node);
434 		cur_node = next;
435 	}
436 
437 	/* and re-init the list */
438 	ab_head = (ABBREV *)NULL;
439 	return(TRUE);
440 }
441