Annotation of src/usr.bin/mg/region.c, Revision 1.43
1.43 ! op 1: /* $OpenBSD: region.c,v 1.42 2023/03/27 17:54:20 op Exp $ */
1.17 kjell 2:
3: /* This file is in the public domain. */
1.4 niklas 4:
1.1 deraadt 5: /*
6: * Region based commands.
1.6 mickey 7: * The routines in this file deal with the region, that magic space between
1.3 millert 8: * "." and mark. Some functions are commands. Some functions are just for
1.1 deraadt 9: * internal use.
10: */
1.3 millert 11:
1.35 bcallah 12: #include <sys/queue.h>
13: #include <sys/socket.h>
1.30 lum 14: #include <sys/types.h>
1.36 lum 15: #include <sys/wait.h>
1.35 bcallah 16: #include <errno.h>
1.30 lum 17: #include <fcntl.h>
1.43 ! op 18: #include <paths.h>
1.30 lum 19: #include <poll.h>
1.35 bcallah 20: #include <signal.h>
21: #include <stdio.h>
22: #include <stdlib.h>
1.30 lum 23: #include <string.h>
24: #include <unistd.h>
25:
1.3 millert 26: #include "def.h"
27:
1.30 lum 28: #define TIMEOUT 10000
29:
30: static char leftover[BUFSIZ];
31:
1.19 deraadt 32: static int getregion(struct region *);
1.32 florian 33: static int iomux(int, char * const, int, struct buffer *);
1.30 lum 34: static int preadin(int, struct buffer *);
35: static void pwriteout(int, char **, int *);
1.19 deraadt 36: static int setsize(struct region *, RSIZE);
1.33 lum 37: static int shellcmdoutput(char * const[], char * const, int);
1.1 deraadt 38:
39: /*
1.3 millert 40: * Kill the region. Ask "getregion" to figure out the bounds of the region.
1.26 kjell 41: * Move "." to the start, and kill the characters. Mark is cleared afterwards.
1.1 deraadt 42: */
1.3 millert 43: int
1.12 cloder 44: killregion(int f, int n)
1.1 deraadt 45: {
1.3 millert 46: int s;
1.19 deraadt 47: struct region region;
1.1 deraadt 48:
1.2 millert 49: if ((s = getregion(®ion)) != TRUE)
1.1 deraadt 50: return (s);
1.3 millert 51: /* This is a kill-type command, so do magic kill buffer stuff. */
52: if ((lastflag & CFKILL) == 0)
53: kdelete();
54: thisflag |= CFKILL;
1.1 deraadt 55: curwp->w_dotp = region.r_linep;
56: curwp->w_doto = region.r_offset;
1.28 kjell 57: curwp->w_dotline = region.r_lineno;
1.29 kjell 58: s = ldelete(region.r_size, KFORW | KREG);
1.26 kjell 59: clearmark(FFARG, 0);
60:
1.23 kjell 61: return (s);
1.1 deraadt 62: }
63:
64: /*
1.26 kjell 65: * Copy all of the characters in the region to the kill buffer,
66: * clearing the mark afterwards.
67: * This is a bit like a kill region followed by a yank.
1.1 deraadt 68: */
1.3 millert 69: int
1.12 cloder 70: copyregion(int f, int n)
1.1 deraadt 71: {
1.19 deraadt 72: struct line *linep;
73: struct region region;
1.3 millert 74: int loffs;
75: int s;
1.1 deraadt 76:
1.2 millert 77: if ((s = getregion(®ion)) != TRUE)
1.15 db 78: return (s);
1.3 millert 79:
80: /* kill type command */
81: if ((lastflag & CFKILL) == 0)
1.1 deraadt 82: kdelete();
83: thisflag |= CFKILL;
1.3 millert 84:
85: /* current line */
86: linep = region.r_linep;
87:
88: /* current offset */
89: loffs = region.r_offset;
90:
1.1 deraadt 91: while (region.r_size--) {
1.2 millert 92: if (loffs == llength(linep)) { /* End of line. */
1.39 lum 93: if ((s = kinsert(*curbp->b_nlchr, KFORW)) != TRUE)
1.1 deraadt 94: return (s);
95: linep = lforw(linep);
96: loffs = 0;
1.3 millert 97: } else { /* Middle of line. */
1.2 millert 98: if ((s = kinsert(lgetc(linep, loffs), KFORW)) != TRUE)
1.15 db 99: return (s);
1.1 deraadt 100: ++loffs;
101: }
102: }
1.26 kjell 103: clearmark(FFARG, 0);
104:
1.15 db 105: return (TRUE);
1.1 deraadt 106: }
107:
108: /*
1.6 mickey 109: * Lower case region. Zap all of the upper case characters in the region to
110: * lower case. Use the region code to set the limits. Scan the buffer, doing
111: * the changes. Call "lchange" to ensure that redisplay is done in all
1.3 millert 112: * buffers.
1.1 deraadt 113: */
1.3 millert 114: int
1.12 cloder 115: lowerregion(int f, int n)
1.1 deraadt 116: {
1.19 deraadt 117: struct line *linep;
118: struct region region;
1.3 millert 119: int loffs, c, s;
1.1 deraadt 120:
1.27 kjell 121: if ((s = checkdirty(curbp)) != TRUE)
122: return (s);
1.10 vincent 123: if (curbp->b_flag & BFREADONLY) {
1.34 lum 124: dobeep();
1.10 vincent 125: ewprintf("Buffer is read-only");
126: return (FALSE);
127: }
128:
1.2 millert 129: if ((s = getregion(®ion)) != TRUE)
1.15 db 130: return (s);
1.9 vincent 131:
132: undo_add_change(region.r_linep, region.r_offset, region.r_size);
1.11 deraadt 133:
1.22 kjell 134: lchange(WFFULL);
1.1 deraadt 135: linep = region.r_linep;
136: loffs = region.r_offset;
137: while (region.r_size--) {
138: if (loffs == llength(linep)) {
139: linep = lforw(linep);
140: loffs = 0;
141: } else {
142: c = lgetc(linep, loffs);
143: if (ISUPPER(c) != FALSE)
144: lputc(linep, loffs, TOLOWER(c));
145: ++loffs;
146: }
147: }
1.15 db 148: return (TRUE);
1.1 deraadt 149: }
150:
151: /*
1.6 mickey 152: * Upper case region. Zap all of the lower case characters in the region to
1.3 millert 153: * upper case. Use the region code to set the limits. Scan the buffer,
1.6 mickey 154: * doing the changes. Call "lchange" to ensure that redisplay is done in all
1.3 millert 155: * buffers.
1.1 deraadt 156: */
1.3 millert 157: int
1.12 cloder 158: upperregion(int f, int n)
1.1 deraadt 159: {
1.19 deraadt 160: struct line *linep;
161: struct region region;
1.3 millert 162: int loffs, c, s;
1.1 deraadt 163:
1.27 kjell 164: if ((s = checkdirty(curbp)) != TRUE)
165: return (s);
1.10 vincent 166: if (curbp->b_flag & BFREADONLY) {
1.34 lum 167: dobeep();
1.10 vincent 168: ewprintf("Buffer is read-only");
169: return (FALSE);
170: }
1.2 millert 171: if ((s = getregion(®ion)) != TRUE)
1.15 db 172: return (s);
1.11 deraadt 173:
1.9 vincent 174: undo_add_change(region.r_linep, region.r_offset, region.r_size);
1.11 deraadt 175:
1.22 kjell 176: lchange(WFFULL);
1.1 deraadt 177: linep = region.r_linep;
178: loffs = region.r_offset;
179: while (region.r_size--) {
180: if (loffs == llength(linep)) {
181: linep = lforw(linep);
182: loffs = 0;
183: } else {
184: c = lgetc(linep, loffs);
185: if (ISLOWER(c) != FALSE)
186: lputc(linep, loffs, TOUPPER(c));
187: ++loffs;
188: }
189: }
1.15 db 190: return (TRUE);
1.1 deraadt 191: }
192:
193: /*
1.6 mickey 194: * This routine figures out the bound of the region in the current window,
195: * and stores the results into the fields of the REGION structure. Dot and
196: * mark are usually close together, but I don't know the order, so I scan
197: * outward from dot, in both directions, looking for mark. The size is kept
198: * in a long. At the end, after the size is figured out, it is assigned to
199: * the size field of the region structure. If this assignment loses any bits,
200: * then we print an error. This is "type independent" overflow checking. All
201: * of the callers of this routine should be ready to get an ABORT status,
1.15 db 202: * because I might add a "if regions is big, ask before clobbering" flag.
1.1 deraadt 203: */
1.3 millert 204: static int
1.19 deraadt 205: getregion(struct region *rp)
1.2 millert 206: {
1.19 deraadt 207: struct line *flp, *blp;
1.3 millert 208: long fsize, bsize;
1.1 deraadt 209:
210: if (curwp->w_markp == NULL) {
1.34 lum 211: dobeep();
1.1 deraadt 212: ewprintf("No mark set in this window");
213: return (FALSE);
214: }
1.3 millert 215:
216: /* "r_size" always ok */
217: if (curwp->w_dotp == curwp->w_markp) {
1.1 deraadt 218: rp->r_linep = curwp->w_dotp;
1.28 kjell 219: rp->r_lineno = curwp->w_dotline;
1.1 deraadt 220: if (curwp->w_doto < curwp->w_marko) {
221: rp->r_offset = curwp->w_doto;
1.3 millert 222: rp->r_size = (RSIZE)(curwp->w_marko - curwp->w_doto);
1.1 deraadt 223: } else {
224: rp->r_offset = curwp->w_marko;
1.3 millert 225: rp->r_size = (RSIZE)(curwp->w_doto - curwp->w_marko);
1.1 deraadt 226: }
1.15 db 227: return (TRUE);
1.1 deraadt 228: }
1.3 millert 229: /* get region size */
230: flp = blp = curwp->w_dotp;
1.1 deraadt 231: bsize = curwp->w_doto;
1.2 millert 232: fsize = llength(flp) - curwp->w_doto + 1;
1.24 kjell 233: while (lforw(flp) != curbp->b_headp || lback(blp) != curbp->b_headp) {
234: if (lforw(flp) != curbp->b_headp) {
1.1 deraadt 235: flp = lforw(flp);
236: if (flp == curwp->w_markp) {
237: rp->r_linep = curwp->w_dotp;
238: rp->r_offset = curwp->w_doto;
1.28 kjell 239: rp->r_lineno = curwp->w_dotline;
1.1 deraadt 240: return (setsize(rp,
1.3 millert 241: (RSIZE)(fsize + curwp->w_marko)));
1.1 deraadt 242: }
1.2 millert 243: fsize += llength(flp) + 1;
1.1 deraadt 244: }
1.24 kjell 245: if (lback(blp) != curbp->b_headp) {
1.1 deraadt 246: blp = lback(blp);
1.2 millert 247: bsize += llength(blp) + 1;
1.1 deraadt 248: if (blp == curwp->w_markp) {
249: rp->r_linep = blp;
250: rp->r_offset = curwp->w_marko;
1.28 kjell 251: rp->r_lineno = curwp->w_markline;
1.1 deraadt 252: return (setsize(rp,
1.3 millert 253: (RSIZE)(bsize - curwp->w_marko)));
1.1 deraadt 254: }
255: }
256: }
1.34 lum 257: dobeep();
1.3 millert 258: ewprintf("Bug: lost mark");
1.15 db 259: return (FALSE);
1.1 deraadt 260: }
261:
262: /*
263: * Set size, and check for overflow.
264: */
1.3 millert 265: static int
1.19 deraadt 266: setsize(struct region *rp, RSIZE size)
1.2 millert 267: {
1.1 deraadt 268: rp->r_size = size;
269: if (rp->r_size != size) {
1.34 lum 270: dobeep();
1.1 deraadt 271: ewprintf("Region is too large");
1.15 db 272: return (FALSE);
1.1 deraadt 273: }
1.15 db 274: return (TRUE);
1.1 deraadt 275: }
276:
277: #define PREFIXLENGTH 40
1.3 millert 278: static char prefix_string[PREFIXLENGTH] = {'>', '\0'};
1.1 deraadt 279:
280: /*
1.6 mickey 281: * Prefix the region with whatever is in prefix_string. Leaves dot at the
282: * beginning of the line after the end of the region. If an argument is
1.3 millert 283: * given, prompts for the line prefix string.
1.1 deraadt 284: */
1.3 millert 285: int
1.12 cloder 286: prefixregion(int f, int n)
1.1 deraadt 287: {
1.19 deraadt 288: struct line *first, *last;
289: struct region region;
1.3 millert 290: char *prefix = prefix_string;
291: int nline;
292: int s;
1.1 deraadt 293:
1.27 kjell 294: if ((s = checkdirty(curbp)) != TRUE)
295: return (s);
1.10 vincent 296: if (curbp->b_flag & BFREADONLY) {
1.34 lum 297: dobeep();
1.10 vincent 298: ewprintf("Buffer is read-only");
299: return (FALSE);
300: }
1.1 deraadt 301: if ((f == TRUE) && ((s = setprefix(FFRAND, 1)) != TRUE))
1.15 db 302: return (s);
1.1 deraadt 303:
304: /* get # of lines to affect */
305: if ((s = getregion(®ion)) != TRUE)
306: return (s);
307: first = region.r_linep;
308: last = (first == curwp->w_dotp) ? curwp->w_markp : curwp->w_dotp;
309: for (nline = 1; first != last; nline++)
310: first = lforw(first);
311:
1.2 millert 312: /* move to beginning of region */
1.1 deraadt 313: curwp->w_dotp = region.r_linep;
314: curwp->w_doto = region.r_offset;
1.28 kjell 315: curwp->w_dotline = region.r_lineno;
1.1 deraadt 316:
317: /* for each line, go to beginning and insert the prefix string */
318: while (nline--) {
1.5 art 319: (void)gotobol(FFRAND, 1);
1.1 deraadt 320: for (prefix = prefix_string; *prefix; prefix++)
1.5 art 321: (void)linsert(1, *prefix);
322: (void)forwline(FFRAND, 1);
1.1 deraadt 323: }
1.5 art 324: (void)gotobol(FFRAND, 1);
1.15 db 325: return (TRUE);
1.1 deraadt 326: }
327:
328: /*
1.25 kjell 329: * Set line prefix string. Used by prefixregion.
1.1 deraadt 330: */
1.3 millert 331: int
1.12 cloder 332: setprefix(int f, int n)
1.1 deraadt 333: {
1.14 vincent 334: char buf[PREFIXLENGTH], *rep;
1.15 db 335: int retval;
1.1 deraadt 336:
337: if (prefix_string[0] == '\0')
1.18 kjell 338: rep = eread("Prefix string: ", buf, sizeof(buf),
339: EFNEW | EFCR);
1.1 deraadt 340: else
1.18 kjell 341: rep = eread("Prefix string (default %s): ", buf, sizeof(buf),
342: EFNUL | EFNEW | EFCR, prefix_string);
343: if (rep == NULL)
344: return (ABORT);
345: if (rep[0] != '\0') {
1.15 db 346: (void)strlcpy(prefix_string, rep, sizeof(prefix_string));
1.14 vincent 347: retval = TRUE;
1.18 kjell 348: } else if (rep[0] == '\0' && prefix_string[0] != '\0') {
1.14 vincent 349: /* CR -- use old one */
350: retval = TRUE;
351: } else
352: retval = FALSE;
1.15 db 353: return (retval);
1.1 deraadt 354: }
1.9 vincent 355:
356: int
1.19 deraadt 357: region_get_data(struct region *reg, char *buf, int len)
1.9 vincent 358: {
1.15 db 359: int i, off;
1.19 deraadt 360: struct line *lp;
1.11 deraadt 361:
1.9 vincent 362: off = reg->r_offset;
363: lp = reg->r_linep;
1.13 vincent 364: for (i = 0; i < len; i++) {
1.9 vincent 365: if (off == llength(lp)) {
366: lp = lforw(lp);
1.24 kjell 367: if (lp == curbp->b_headp)
1.9 vincent 368: break;
369: off = 0;
1.39 lum 370: buf[i] = *curbp->b_nlchr;
1.9 vincent 371: } else {
372: buf[i] = lgetc(lp, off);
373: off++;
374: }
375: }
1.13 vincent 376: buf[i] = '\0';
1.15 db 377: return (i);
1.9 vincent 378: }
379:
1.20 kjell 380: void
1.9 vincent 381: region_put_data(const char *buf, int len)
382: {
383: int i;
384:
1.21 kjell 385: for (i = 0; buf[i] != '\0' && i < len; i++) {
1.39 lum 386: if (buf[i] == *curbp->b_nlchr)
1.9 vincent 387: lnewline();
388: else
389: linsert(1, buf[i]);
390: }
1.30 lum 391: }
392:
393: /*
394: * Mark whole buffer by first traversing to end-of-buffer
395: * and then to beginning-of-buffer. Mark, dot are implicitly
396: * set to eob, bob respectively during traversal.
397: */
398: int
399: markbuffer(int f, int n)
400: {
401: if (gotoeob(f,n) == FALSE)
402: return (FALSE);
1.38 lum 403: (void) clearmark(f, n);
1.30 lum 404: if (gotobob(f,n) == FALSE)
405: return (FALSE);
406: return (TRUE);
407: }
408:
409: /*
410: * Pipe text from current region to external command.
411: */
412: int
413: piperegion(int f, int n)
414: {
1.32 florian 415: struct region region;
1.33 lum 416: int len;
417: char *cmd, cmdbuf[NFILEN], *text;
1.32 florian 418: char *argv[] = {"sh", "-c", (char *) NULL, (char *) NULL};
1.30 lum 419:
420: /* C-u M-| is not supported yet */
421: if (n > 1)
422: return (ABORT);
423:
424: if (curwp->w_markp == NULL) {
1.34 lum 425: dobeep();
1.30 lum 426: ewprintf("The mark is not set now, so there is no region");
427: return (FALSE);
428: }
1.32 florian 429:
1.30 lum 430: if ((cmd = eread("Shell command on region: ", cmdbuf, sizeof(cmdbuf),
431: EFNEW | EFCR)) == NULL || (cmd[0] == '\0'))
432: return (ABORT);
433:
1.32 florian 434: argv[2] = cmd;
435:
436: if (getregion(®ion) != TRUE)
437: return (FALSE);
438:
439: len = region.r_size;
440:
441: if ((text = malloc(len + 1)) == NULL) {
1.34 lum 442: dobeep();
1.32 florian 443: ewprintf("Cannot allocate memory.");
444: return (FALSE);
445: }
446:
1.33 lum 447: region_get_data(®ion, text, len);
448:
449: return shellcmdoutput(argv, text, len);
450: }
451:
452: /*
453: * Get command from mini-buffer and execute externally.
454: */
455: int
456: shellcommand(int f, int n)
457: {
458: char *cmd, cmdbuf[NFILEN];
459: char *argv[] = {"sh", "-c", (char *) NULL, (char *) NULL};
460:
461: if (n > 1)
462: return (ABORT);
463:
464: if ((cmd = eread("Shell command: ", cmdbuf, sizeof(cmdbuf),
465: EFNEW | EFCR)) == NULL || (cmd[0] == '\0'))
466: return (ABORT);
467:
468: argv[2] = cmd;
469:
470: return shellcmdoutput(argv, NULL, 0);
471: }
472:
473: int
474: shellcmdoutput(char* const argv[], char* const text, int len)
475: {
476: struct buffer *bp;
477: char *shellp;
478: int ret;
479:
1.32 florian 480: bp = bfind("*Shell Command Output*", TRUE);
481: bp->b_flag |= BFREADONLY;
482: if (bclear(bp) != TRUE) {
483: free(text);
484: return (FALSE);
485: }
486:
1.43 ! op 487: if ((shellp = getenv("SHELL")) == NULL)
! 488: shellp = _PATH_BSHELL;
1.32 florian 489:
490: ret = pipeio(shellp, argv, text, len, bp);
491:
492: if (ret == TRUE) {
493: eerase();
494: if (lforw(bp->b_headp) == bp->b_headp)
495: addline(bp, "(Shell command succeeded with no output)");
496: }
497:
498: free(text);
499: return (ret);
1.30 lum 500: }
501:
502: /*
1.32 florian 503: * Create a socketpair, fork and execv path with argv.
504: * STDIN, STDOUT and STDERR of child process are redirected to socket.
505: * Parent writes len chars from text to socket.
1.30 lum 506: */
507: int
1.32 florian 508: pipeio(const char* const path, char* const argv[], char* const text, int len,
509: struct buffer *outbp)
1.30 lum 510: {
1.36 lum 511: int s[2], ret;
1.32 florian 512: char *err;
1.36 lum 513: pid_t pid;
1.30 lum 514:
515: if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, s) == -1) {
1.34 lum 516: dobeep();
1.30 lum 517: ewprintf("socketpair error");
518: return (FALSE);
519: }
1.32 florian 520:
1.36 lum 521: switch((pid = fork())) {
1.30 lum 522: case -1:
1.34 lum 523: dobeep();
1.30 lum 524: ewprintf("Can't fork");
525: return (FALSE);
526: case 0:
527: /* Child process */
528: close(s[0]);
529: if (dup2(s[1], STDIN_FILENO) == -1)
530: _exit(1);
531: if (dup2(s[1], STDOUT_FILENO) == -1)
532: _exit(1);
533: if (dup2(s[1], STDERR_FILENO) == -1)
534: _exit(1);
1.32 florian 535:
536: execv(path, argv);
537: err = strerror(errno);
538: write(s[1], err, strlen(err));
1.30 lum 539: _exit(1);
540: default:
541: /* Parent process */
542: close(s[1]);
1.36 lum 543: ret = iomux(s[0], text, len, outbp);
544: waitpid(pid, NULL, 0); /* Collect child to prevent zombies */
545:
546: return (ret);
1.30 lum 547: }
548: return (FALSE);
549: }
550:
551: /*
1.32 florian 552: * Multiplex read, write on socket fd passed. Put output in outbp
1.30 lum 553: * Poll on the fd for both read and write readiness.
554: */
555: int
1.32 florian 556: iomux(int fd, char* const text, int len, struct buffer *outbp)
1.30 lum 557: {
558: struct pollfd pfd[1];
559: int nfds;
1.32 florian 560: char *textcopy;
1.31 florian 561:
1.30 lum 562: textcopy = text;
563: fcntl(fd, F_SETFL, O_NONBLOCK);
1.32 florian 564: pfd[0].fd = fd;
565:
566: /* There is nothing to write if len is zero
1.41 op 567: * but the cmd's output should be read so shutdown
1.32 florian 568: * the socket for writing only and don't wait for POLLOUT
1.30 lum 569: */
1.32 florian 570: if (len == 0) {
1.30 lum 571: shutdown(fd, SHUT_WR);
1.32 florian 572: pfd[0].events = POLLIN;
573: } else
574: pfd[0].events = POLLIN | POLLOUT;
1.30 lum 575:
576: while ((nfds = poll(pfd, 1, TIMEOUT)) != -1 ||
577: (pfd[0].revents & (POLLERR | POLLHUP | POLLNVAL))) {
1.32 florian 578: if (pfd[0].revents & POLLOUT && len > 0)
579: pwriteout(fd, &textcopy, &len);
1.30 lum 580: else if (pfd[0].revents & POLLIN)
1.32 florian 581: if (preadin(fd, outbp) == FALSE)
1.30 lum 582: break;
1.32 florian 583: if (len == 0 && pfd[0].events & POLLOUT)
584: pfd[0].events = POLLIN;
1.30 lum 585: }
586: close(fd);
1.32 florian 587:
1.41 op 588: /* In case if last line doesn't have a '\n' add the leftover
1.30 lum 589: * characters to buffer.
590: */
591: if (leftover[0] != '\0') {
1.32 florian 592: addline(outbp, leftover);
1.30 lum 593: leftover[0] = '\0';
594: }
595: if (nfds == 0) {
1.34 lum 596: dobeep();
1.30 lum 597: ewprintf("poll timed out");
598: return (FALSE);
599: } else if (nfds == -1) {
1.34 lum 600: dobeep();
1.30 lum 601: ewprintf("poll error");
602: return (FALSE);
603: }
1.32 florian 604: return (popbuftop(outbp, WNONE));
1.30 lum 605: }
606:
607: /*
1.41 op 608: * Write some text from region to fd. Once done shutdown the
1.30 lum 609: * write end.
610: */
611: void
612: pwriteout(int fd, char **text, int *len)
613: {
614: int w;
615:
616: if (((w = send(fd, *text, *len, MSG_NOSIGNAL)) == -1)) {
617: switch(errno) {
618: case EPIPE:
619: *len = -1;
620: break;
621: case EAGAIN:
622: return;
623: }
624: } else
625: *len -= w;
626:
627: *text += w;
628: if (*len <= 0)
1.41 op 629: shutdown(fd, SHUT_WR);
1.30 lum 630: }
631:
632: /*
633: * Read some data from socket fd, break on '\n' and add
634: * to buffer. If couldn't break on newline hold leftover
635: * characters and append in next iteration.
636: */
637: int
638: preadin(int fd, struct buffer *bp)
639: {
640: int len;
641: char buf[BUFSIZ], *p, *q;
642:
1.37 lum 643: if ((len = read(fd, buf, BUFSIZ - 1)) <= 0)
1.30 lum 644: return (FALSE);
1.32 florian 645:
1.30 lum 646: buf[len] = '\0';
647: p = q = buf;
1.39 lum 648: if (leftover[0] != '\0' && ((q = strchr(p, *bp->b_nlchr)) != NULL)) {
1.30 lum 649: *q++ = '\0';
650: if (strlcat(leftover, p, sizeof(leftover)) >=
651: sizeof(leftover)) {
1.34 lum 652: dobeep();
1.30 lum 653: ewprintf("line too long");
654: return (FALSE);
655: }
656: addline(bp, leftover);
657: leftover[0] = '\0';
658: p = q;
659: }
1.39 lum 660: while ((q = strchr(p, *bp->b_nlchr)) != NULL) {
1.30 lum 661: *q++ = '\0';
662: addline(bp, p);
663: p = q;
664: }
665: if (strlcpy(leftover, p, sizeof(leftover)) >= sizeof(leftover)) {
1.34 lum 666: dobeep();
1.30 lum 667: ewprintf("line too long");
668: return (FALSE);
669: }
670: return (TRUE);
1.9 vincent 671: }