|
|
1.1 root 1: /* @(microEMACS)random.c
2: *
3: * This file contains the command processing functions for a number of
4: * random commands. There is no functional grouping here, for sure.
5: */
6: #include <stdio.h>
7: #include "ed.h"
8:
9: /*
10: * Return current column. Stop at first non-blank given TRUE argument.
11: */
12: getccol(bflg)
13: int bflg;
14: {
15: register int i;
16: register int col = 0;
17: register WINDOW *lcurwp;
18: unsigned c;
19:
20: lcurwp = curwp;
21: for (i=0; i<lcurwp->w_doto; ++i) {
22: c = lgetc(lcurwp->w_dotp, i);
23: if (c != ' ' && c != '\t' && bflg)
24: break;
25: switch (dblchr(c)) {
26: case 2:
27: taber(col);
28: break;
29: case 1:
30: ++col;
31: }
32: ++col;
33: }
34: return (col);
35: }
36:
37: /*
38: * Set fill column to n, if given, otherwise use the current cursor
39: * column. Either way, tell user where the fill column really is.
40: */
41: setfillcol(f, n)
42: register int n;
43: {
44: if (!n)
45: bind.fillcol = 0;
46: else if (n == 1)
47: bind.fillcol = getccol(FALSE);
48: else
49: bind.fillcol = n - 1;
50:
51: if (bind.fillcol)
52: mlwrite("[Wrap at column %d]", bind.fillcol+1);
53: else
54: mlwrite("Word wrap turned off");
55: return (TRUE);
56: }
57:
58: /*
59: * Display the current position of the cursor,
60: * in origin 1 X-Y coordinates, the character that is
61: * under the cursor (in hex), and the fraction of the
62: * text that is before the cursor. The displayed column
63: * is not the current column, but the column that would
64: * be used on an infinite width display. Normally this
65: * is bound to "C-X =".
66: */
67: showcpos(f, n)
68: {
69: register LINE *clp;
70: register long nch = 0L;
71: register long nbc;
72: register int cbo = 0;
73: register int linecnt = 1;
74: register int cac;
75: register int curline = 0;
76: int ratio;
77: int col;
78:
79: clp = lforw(curbp->b_linep); /* Grovel the data. */
80:
81: for (;;) {
82: if (clp==curwp->w_dotp && cbo==curwp->w_doto) {
83: curline = linecnt;
84: nbc = nch;
85: if (cbo == llength(clp))
86: cac = '\n';
87: else
88: cac = lgetc(clp, cbo);
89: }
90: if (cbo == llength(clp)) {
91: if (clp == curbp->b_linep)
92: break;
93: clp = lforw(clp);
94: ++linecnt;
95: cbo = 0;
96: } else
97: ++cbo;
98: ++nch;
99: }
100: col = getccol(FALSE)+1; /* Get real column. */
101: ratio = 0; /* Ratio before dot. */
102: if (nch != 0)
103: ratio = (100L*nbc) / nch;
104: mlwrite("X=%d Y=%d CH=0x%x .=%ld (%d%% of %ld) line %d of %d",
105: col, currow+1, cac, nbc, ratio, nch, curline, linecnt);
106: return (TRUE);
107: }
108:
109: /*
110: * Twiddle the two characters on either side of
111: * dot. If dot is at the end of the line twiddle the
112: * two characters before it. Return with an error if dot
113: * is at the beginning of line; it seems to be a bit
114: * pointless to make this work. This fixes up a very
115: * common typo with a single stroke. Normally bound
116: * to "C-T". This always works within a line, so
117: * "WFEDIT" is good enough.
118: */
119: twiddle(f, n)
120: {
121: register WINDOW *lcurwp;
122: register LINE *dotp;
123: register int doto;
124: register int cl;
125: register int cr;
126:
127: lcurwp = curwp;
128: dotp = lcurwp->w_dotp;
129: doto = lcurwp->w_doto;
130: if (doto==llength(dotp) && --doto<0)
131: return (FALSE);
132: cr = lgetc(dotp, doto);
133: if (--doto < 0)
134: return (FALSE);
135: cl = lgetc(dotp, doto);
136: lputc(dotp, doto+0, cr);
137: lputc(dotp, doto+1, cl);
138: lchange(WFEDIT);
139: return (TRUE);
140: }
141:
142: /*
143: * Quote the next character, and insert it into the buffer. All the characters
144: * are taken literally, with the exception of the newline, which always has
145: * its line splitting meaning. The character is always read, even if it is
146: * inserted 0 times, for regularity. If executing a macro, get the character
147: * from memory, otherwise, get it from the keyboard.
148: * Bound to "C-Q"
149: */
150: quote(f, n)
151: register int n;
152: {
153: register int s;
154: register int c;
155:
156: if (kbdmop != NULL) /* if in a macro, get from memory */
157: c = *kbdmop++; /* fixes a bug in an old version */
158: else /* where the quoted character was */
159: c = tgetc(); /* not remembered. */
160: if (kbdmip != NULL)
161: *kbdmip++ = c; /* if defining a macro, remember */
162: if (n < 0)
163: return (FALSE);
164: if (n == 0)
165: return (TRUE);
166: if (c == '\n') {
167: do {
168: s = lnewline();
169: } while (s==TRUE && --n);
170: return (s);
171: }
172: return (linsert(n, c));
173: }
174:
175: /*
176: * Get character by value, and insert it into the buffer. All the characters
177: * are taken literally, with the exception of the newline, which always has
178: * its line splitting meaning. The character is always read, even if it is
179: * inserted 0 times, for regularity.
180: * Bound to "M-Q"
181: */
182: quoteval(f, n)
183: register int n;
184: {
185: register int s;
186: register int c;
187: char buf[10]; /* big enough */
188:
189: if (TRUE != (s = mlreply("value of char to insert ", buf, sizeof(buf))))
190: return (s);
191:
192: if (n < 0)
193: return (FALSE);
194: if (n == 0)
195: return (TRUE);
196:
197: c = atoi(buf);
198: if (c == '\n') {
199: do {
200: s = lnewline();
201: } while (s==TRUE && --n);
202: return (s);
203: }
204: return (linsert(n, c));
205: }
206:
207: /*
208: * Toggle autoindent flag.
209: */
210: autoind(f, n)
211: {
212: bind.autoindent ^= 1;
213: }
214:
215: /*
216: * Set tab size if given non-default argument (n <> 1). Otherwise, insert a
217: * tab into file. If given argument, n, of zero, change to true tabs.
218: * If n > 1, simulate tab stop every n-characters using spaces.
219: * This has to be done in this slightly funny way because the
220: * tab (in ASCII) has been turned into "C-I" (in 10
221: * bit code) already. Bound to "C-I".
222: */
223: tab(f, n)
224: register int n;
225: {
226: if (n == 1) /* normal tabbing */
227: return (bind.tabsize ?
228: linsert(bind.tabsize - (getccol(FALSE)%bind.tabsize),' ') :
229: linsert(1, '\t'));
230:
231: if (n < 0) { /* change the meaning of tab character */
232: bind.tabsiz = -n;
233: curwp->w_flag |= WFMODE|WFFORCE|WFHARD;
234: return (TRUE);
235: }
236:
237: /* change the meaning of tab key */
238: if (!(bind.tabsize = n)) {
239: bind.tabsiz = 8; /* back to the default for 0 */
240: curwp->w_flag |= WFMODE|WFFORCE|WFHARD;
241: }
242: return (TRUE);
243: }
244:
245: /*
246: * Open up some blank space. The basic plan
247: * is to insert a bunch of newlines, and then back
248: * up over them. Everything is done by the subcommand
249: * procerssors. They even handle the looping. Normally
250: * this is bound to "C-O".
251: */
252: openline(f, n)
253: register int n;
254: {
255: register int i;
256: register int s;
257:
258: if (n < 0)
259: return (FALSE);
260: if (n == 0)
261: return (TRUE);
262: i = n; /* Insert newlines. */
263: do {
264: s = lnewline();
265: } while (s==TRUE && --i);
266: if (s == TRUE) /* Then back up overtop */
267: s = backchar(f, n); /* of them all. */
268: return (s);
269: }
270:
271: /*
272: * Insert a newline. Bound to "C-M".
273: * If you are at the end of the line and the
274: * next line is a blank line, just move into the
275: * blank line. This makes "C-O" and "C-X C-O" work
276: * nicely, and reduces the ammount of screen
277: * update that has to be done. This would not be
278: * as critical if screen update were a lot
279: * more efficient.
280: */
281: newline(f, n)
282: register int n;
283: {
284: register LINE *lp;
285: register int s;
286:
287: if (n < 0)
288: return (FALSE);
289: while (n--) {
290: lp = curwp->w_dotp;
291: if (llength(lp) == curwp->w_doto
292: && lp != curbp->b_linep
293: && llength(lforw(lp)) == 0) {
294: if ((s=forwchar(FALSE, 1)) != TRUE)
295: return (s);
296: } else if ((s=lnewline()) != TRUE)
297: return (s);
298: }
299: return (TRUE);
300: }
301:
302: /*
303: * Delete blank lines around dot.
304: * What this command does depends if dot is
305: * sitting on a blank line. If dot is sitting on a
306: * blank line, this command deletes all the blank lines
307: * above and below the current line. If it is sitting
308: * on a non blank line then it deletes all of the
309: * blank lines after the line. Normally this command
310: * is bound to "C-X C-O". Any argument is ignored.
311: */
312: deblank(f, n)
313: {
314: register LINE *lp1;
315: register LINE *lp2;
316: register int nld;
317: register WINDOW *lcurwp;
318:
319: lcurwp = curwp;
320: lp1 = lcurwp->w_dotp;
321: while (llength(lp1)==0 && (lp2=lback(lp1))!=curbp->b_linep)
322: lp1 = lp2;
323: lp2 = lp1;
324: nld = 0;
325: while ((lp2=lforw(lp2))!=curbp->b_linep && llength(lp2)==0)
326: ++nld;
327: if (nld == 0)
328: return (TRUE);
329: lcurwp->w_dotp = lforw(lp1);
330: lcurwp->w_doto = 0;
331: return (ldelete(nld, FALSE));
332: }
333:
334: /*
335: * Insert a newline, then enough
336: * tabs and spaces to duplicate the indentation
337: * of the previous line. Assumes tabs are every eight
338: * characters. Quite simple. Figure out the indentation
339: * of the current line. Insert a newline by calling
340: * the standard routine. Insert the indentation by
341: * inserting the right number of tabs and spaces.
342: * Return TRUE if all ok. Return FALSE if one
343: * of the subcomands failed. Normally bound
344: * to "C-J".
345: */
346: indent(f, n)
347: {
348: register int nicol;
349: register int c;
350: register int i;
351:
352: if (n < 0)
353: return (FALSE);
354: while (n--) {
355: nicol = 0;
356: for (i=0; i<llength(curwp->w_dotp); ++i) {
357: c = lgetc(curwp->w_dotp, i);
358: if (c!=' ' && c!='\t')
359: break;
360: if (c == '\t')
361: taber(nicol);
362: ++nicol;
363: }
364: if (lnewline() == FALSE
365: || ((i=nicol/bind.tabsiz)!=0 && linsert(i, '\t')==FALSE)
366: || ((i=nicol%bind.tabsiz)!=0 && linsert(i, ' ')==FALSE))
367: return (FALSE);
368: }
369: return (TRUE);
370: }
371:
372: /*
373: * Delete forward. This is real
374: * easy, because the basic delete routine does
375: * all of the work. Watches for negative arguments,
376: * and does the right thing. If any argument is
377: * present, it kills rather than deletes, to prevent
378: * loss of text if typed with a big argument.
379: * Normally bound to "C-D".
380: */
381: forwdel(f, n)
382: {
383: if (n < 0)
384: return (backdel(f, -n));
385: if (f != FALSE) { /* Really a kill. */
386: if ((lastflag&CFKILL) == 0)
387: kdelete();
388: thisflag |= CFKILL;
389: }
390: return (ldelete(n, f));
391: }
392:
393: /*
394: * Delete backwards. This is quite easy too,
395: * because it's all done with other functions. Just
396: * move the cursor back, and delete forwards.
397: * Like delete forward, this actually does a kill
398: * if presented with an argument. Bound to both
399: * "RUBOUT" and "C-H".
400: */
401: backdel(f, n)
402: {
403: register int s;
404:
405: if (n < 0)
406: return (forwdel(f, -n));
407: if (f != FALSE) { /* Really a kill. */
408: if ((lastflag&CFKILL) == 0)
409: kdelete();
410: thisflag |= CFKILL;
411: }
412: if ((s=backchar(f, n)) == TRUE)
413: s = ldelete(n, f);
414: return (s);
415: }
416:
417: /*
418: * Kill text. If called without an argument,
419: * it kills from dot to the end of the line, unless it
420: * is at the end of the line, when it kills the newline.
421: * If called with an argument of 0, it kills from the
422: * start of the line to dot. If called with a positive
423: * argument, it kills from dot forward over that number
424: * of newlines. If called with a negative argument it
425: * kills backwards that number of newlines. Normally
426: * bound to "C-K".
427: */
428: kill(f, n)
429: {
430: register int chunk;
431: register LINE *nextp;
432:
433: if ((lastflag&CFKILL) == 0) /* Clear kill buffer if */
434: kdelete(); /* last wasn't a kill. */
435: thisflag |= CFKILL;
436: if (f == FALSE) {
437: chunk = llength(curwp->w_dotp)-curwp->w_doto;
438: if (chunk == 0)
439: chunk = 1;
440: } else if (n == 0) {
441: chunk = curwp->w_doto;
442: curwp->w_doto = 0;
443: } else if (n > 0) {
444: chunk = llength(curwp->w_dotp)-curwp->w_doto+1;
445: nextp = lforw(curwp->w_dotp);
446: while (--n) {
447: if (nextp == curbp->b_linep)
448: return (FALSE);
449: chunk += llength(nextp)+1;
450: nextp = lforw(nextp);
451: }
452: } else {
453: mlwrite("neg kill");
454: return (FALSE);
455: }
456: return (ldelete(chunk, TRUE));
457: }
458:
459: /*
460: * Yank text back from the kill buffer. This
461: * is really easy. All of the work is done by the
462: * standard insert routines. All you do is run the loop,
463: * and check for errors. Bound to "C-Y". The blank
464: * lines are inserted with a call to "newline"
465: * instead of a call to "lnewline" so that the magic
466: * stuff that happens when you type a carriage
467: * return also happens when a carriage return is
468: * yanked back from the kill buffer.
469: */
470: yank(f, n)
471: {
472: register int c;
473: register int i;
474: extern int kused;
475:
476: if (n < 0)
477: return (FALSE);
478: while (n--) {
479: i = 0;
480: while ((c=kremove(i)) >= 0) {
481: if (c == '\n') {
482: if (newline(FALSE, 1) == FALSE)
483: return (FALSE);
484: } else {
485: if (linsert(1, c) == FALSE)
486: return (FALSE);
487: }
488: ++i;
489: }
490: }
491: return (TRUE);
492: }
493:
494: #if GEM
495: /*
496: * singlecase the characters in the given buffer. this is used for
497: * buffer and file names on the ST, since everything becomes uppercase
498: * (whether you like it or not) from the desktop and in file names.
499: * this routine assumes ASCII.
500: */
501: fixname(bp)
502: register uchar *bp;
503: {
504: register unsigned c;
505:
506: while (c = *bp)
507: #if UPPERNM
508: if (c >= 'a' && c <= 'z')
509: *bp++ = c & ~0x20; /* Lower to upper case */
510: #else
511: if (c >= 'A' && c <= 'Z')
512: *bp++ = c | 0x20; /* Upper to lower case */
513: #endif
514: else
515: ++bp;
516: }
517: #endif
518:
519: setfold(f,n)
520: {
521: if (f)
522: bind.ffold = n;
523: else
524: bind.ffold = !bind.ffold;
525: if (bind.ffold)
526: mlwrite("[Case fold on search]");
527: else
528: mlwrite("[Match case on search]");
529: return TRUE;
530: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.