1 /*- 2 * Copyright (c) 1980, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.proprietary.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)ex_vops3.c 8.1 (Berkeley) 06/09/93"; 10 #endif /* not lint */ 11 12 #include "ex.h" 13 #include "ex_tty.h" 14 #include "ex_vis.h" 15 16 /* 17 * Routines to handle structure. 18 * Operations supported are: 19 * ( ) { } [ ] 20 * 21 * These cover: LISP TEXT 22 * ( ) s-exprs sentences 23 * { } list at same paragraphs 24 * [ ] defuns sections 25 * 26 * { and } for C used to attempt to do something with matching {}'s, but 27 * I couldn't find definitions which worked intuitively very well, so I 28 * scrapped this. 29 * 30 * The code here is very hard to understand. 31 */ 32 line *llimit; 33 int (*lf)(); 34 35 #ifdef LISPCODE 36 int lindent(); 37 #endif 38 39 bool wasend; 40 41 /* 42 * Find over structure, repeated count times. 43 * Don't go past line limit. F is the operation to 44 * be performed eventually. If pastatom then the user said {} 45 * rather than (), implying past atoms in a list (or a paragraph 46 * rather than a sentence. 47 */ 48 lfind(pastatom, cnt, f, limit) 49 bool pastatom; 50 int cnt, (*f)(); 51 line *limit; 52 { 53 register int c; 54 register int rc = 0; 55 char save[LBSIZE]; 56 57 /* 58 * Initialize, saving the current line buffer state 59 * and computing the limit; a 0 argument means 60 * directional end of file. 61 */ 62 wasend = 0; 63 lf = f; 64 strcpy(save, linebuf); 65 if (limit == 0) 66 limit = dir < 0 ? one : dol; 67 llimit = limit; 68 wdot = dot; 69 wcursor = cursor; 70 71 if (pastatom >= 2) { 72 while (cnt > 0 && word(f, cnt)) 73 cnt--; 74 if (pastatom == 3) 75 eend(f); 76 if (dot == wdot) { 77 wdot = 0; 78 if (cursor == wcursor) 79 rc = -1; 80 } 81 } 82 #ifdef LISPCODE 83 else if (!value(LISP)) { 84 #else 85 else { 86 #endif 87 char *icurs; 88 line *idot; 89 90 if (linebuf[0] == 0) { 91 do 92 if (!lnext()) 93 goto ret; 94 while (linebuf[0] == 0); 95 if (dir > 0) { 96 wdot--; 97 linebuf[0] = 0; 98 wcursor = linebuf; 99 /* 100 * If looking for sentence, next line 101 * starts one. 102 */ 103 if (!pastatom) { 104 icurs = wcursor; 105 idot = wdot; 106 goto begin; 107 } 108 } 109 } 110 icurs = wcursor; 111 idot = wdot; 112 113 /* 114 * Advance so as to not find same thing again. 115 */ 116 if (dir > 0) { 117 if (!lnext()) { 118 rc = -1; 119 goto ret; 120 } 121 } else 122 ignore(lskipa1("")); 123 124 /* 125 * Count times find end of sentence/paragraph. 126 */ 127 begin: 128 for (;;) { 129 while (!endsent(pastatom)) 130 if (!lnext()) 131 goto ret; 132 if (!pastatom || wcursor == linebuf && endPS()) 133 if (--cnt <= 0) 134 break; 135 if (linebuf[0] == 0) { 136 do 137 if (!lnext()) 138 goto ret; 139 while (linebuf[0] == 0); 140 } else 141 if (!lnext()) 142 goto ret; 143 } 144 145 /* 146 * If going backwards, and didn't hit the end of the buffer, 147 * then reverse direction. 148 */ 149 if (dir < 0 && (wdot != llimit || wcursor != linebuf)) { 150 dir = 1; 151 llimit = dot; 152 /* 153 * Empty line needs special treatement. 154 * If moved to it from other than begining of next line, 155 * then a sentence starts on next line. 156 */ 157 if (linebuf[0] == 0 && !pastatom && 158 (wdot != dot - 1 || cursor != linebuf)) { 159 ignore(lnext()); 160 goto ret; 161 } 162 } 163 164 /* 165 * If we are not at a section/paragraph division, 166 * advance to next. 167 */ 168 if (wcursor == icurs && wdot == idot || wcursor != linebuf || !endPS()) 169 ignore(lskipa1("")); 170 } 171 #ifdef LISPCODE 172 else { 173 c = *wcursor; 174 /* 175 * Startup by skipping if at a ( going left or a ) going 176 * right to keep from getting stuck immediately. 177 */ 178 if (dir < 0 && c == '(' || dir > 0 && c == ')') { 179 if (!lnext()) { 180 rc = -1; 181 goto ret; 182 } 183 } 184 /* 185 * Now chew up repitition count. Each time around 186 * if at the beginning of an s-exp (going forwards) 187 * or the end of an s-exp (going backwards) 188 * skip the s-exp. If not at beg/end resp, then stop 189 * if we hit a higher level paren, else skip an atom, 190 * counting it unless pastatom. 191 */ 192 while (cnt > 0) { 193 c = *wcursor; 194 if (dir < 0 && c == ')' || dir > 0 && c == '(') { 195 if (!lskipbal("()")) 196 goto ret; 197 /* 198 * Unless this is the last time going 199 * backwards, skip past the matching paren 200 * so we don't think it is a higher level paren. 201 */ 202 if (dir < 0 && cnt == 1) 203 goto ret; 204 if (!lnext() || !ltosolid()) 205 goto ret; 206 --cnt; 207 } else if (dir < 0 && c == '(' || dir > 0 && c == ')') 208 /* Found a higher level paren */ 209 goto ret; 210 else { 211 if (!lskipatom()) 212 goto ret; 213 if (!pastatom) 214 --cnt; 215 } 216 } 217 } 218 #endif 219 ret: 220 strcLIN(save); 221 return (rc); 222 } 223 224 /* 225 * Is this the end of a sentence? 226 */ 227 /* ARGSUSED */ 228 endsent(pastatom) 229 bool pastatom; 230 { 231 register char *cp = wcursor; 232 register int d; 233 234 /* 235 * If this is the beginning of a line, then 236 * check for the end of a paragraph or section. 237 */ 238 if (cp == linebuf) 239 return (endPS()); 240 241 /* 242 * Sentences end with . ! ? not at the beginning 243 * of the line, and must be either at the end of the line, 244 * or followed by 2 spaces. Any number of intervening ) ] ' " 245 * characters are allowed. 246 */ 247 if (!any(*cp, ".!?")) 248 goto tryps; 249 do 250 if ((d = *++cp) == 0) 251 return (1); 252 while (any(d, ")]'")); 253 if (*cp == 0 || *cp++ == ' ' && *cp == ' ') 254 return (1); 255 tryps: 256 if (cp[1] == 0) 257 return (endPS()); 258 return (0); 259 } 260 261 /* 262 * End of paragraphs/sections are respective 263 * macros as well as blank lines and form feeds. 264 */ 265 endPS() 266 { 267 268 return (linebuf[0] == 0 || 269 isa(svalue(PARAGRAPHS)) || isa(svalue(SECTIONS))); 270 271 } 272 273 #ifdef LISPCODE 274 lindent(addr) 275 line *addr; 276 { 277 register int i; 278 char *swcurs = wcursor; 279 line *swdot = wdot; 280 281 again: 282 if (addr > one) { 283 register char *cp; 284 register int cnt = 0; 285 286 addr--; 287 getline(*addr); 288 for (cp = linebuf; *cp; cp++) 289 if (*cp == '(') 290 cnt++; 291 else if (*cp == ')') 292 cnt--; 293 cp = vpastwh(linebuf); 294 if (*cp == 0) 295 goto again; 296 if (cnt == 0) 297 return (whitecnt(linebuf)); 298 addr++; 299 } 300 wcursor = linebuf; 301 linebuf[0] = 0; 302 wdot = addr; 303 dir = -1; 304 llimit = one; 305 lf = lindent; 306 if (!lskipbal("()")) 307 i = 0; 308 else if (wcursor == linebuf) 309 i = 2; 310 else { 311 register char *wp = wcursor; 312 313 dir = 1; 314 llimit = wdot; 315 if (!lnext() || !ltosolid() || !lskipatom()) { 316 wcursor = wp; 317 i = 1; 318 } else 319 i = 0; 320 i += column(wcursor) - 1; 321 if (!inopen) 322 i--; 323 } 324 wdot = swdot; 325 wcursor = swcurs; 326 return (i); 327 } 328 #endif 329 330 lmatchp(addr) 331 line *addr; 332 { 333 register int i; 334 register char *parens, *cp; 335 336 for (cp = cursor; !any(*cp, "({[)}]");) 337 if (*cp++ == 0) 338 return (0); 339 lf = 0; 340 parens = any(*cp, "()") ? "()" : any(*cp, "[]") ? "[]" : "{}"; 341 if (*cp == parens[1]) { 342 dir = -1; 343 llimit = one; 344 } else { 345 dir = 1; 346 llimit = dol; 347 } 348 if (addr) 349 llimit = addr; 350 if (splitw) 351 llimit = dot; 352 wcursor = cp; 353 wdot = dot; 354 i = lskipbal(parens); 355 return (i); 356 } 357 358 lsmatch(cp) 359 char *cp; 360 { 361 char save[LBSIZE]; 362 register char *sp = save; 363 register char *scurs = cursor; 364 365 wcursor = cp; 366 strcpy(sp, linebuf); 367 *wcursor = 0; 368 strcpy(cursor, genbuf); 369 cursor = strend(linebuf) - 1; 370 if (lmatchp(dot - vcline)) { 371 register int i = insmode; 372 register int c = outcol; 373 register int l = outline; 374 375 if (!MI) 376 endim(); 377 vgoto(splitw ? WECHO : LINE(wdot - llimit), column(wcursor) - 1); 378 flush(); 379 sleep(1); 380 vgoto(l, c); 381 if (i) 382 goim(); 383 } 384 else { 385 strcLIN(sp); 386 strcpy(scurs, genbuf); 387 if (!lmatchp((line *) 0)) 388 beep(); 389 } 390 strcLIN(sp); 391 wdot = 0; 392 wcursor = 0; 393 cursor = scurs; 394 } 395 396 ltosolid() 397 { 398 399 return (ltosol1("()")); 400 } 401 402 ltosol1(parens) 403 register char *parens; 404 { 405 register char *cp; 406 407 if (*parens && !*wcursor && !lnext()) 408 return (0); 409 while (isspace(*wcursor) || (*wcursor == 0 && *parens)) 410 if (!lnext()) 411 return (0); 412 if (any(*wcursor, parens) || dir > 0) 413 return (1); 414 for (cp = wcursor; cp > linebuf; cp--) 415 if (isspace(cp[-1]) || any(cp[-1], parens)) 416 break; 417 wcursor = cp; 418 return (1); 419 } 420 421 lskipbal(parens) 422 register char *parens; 423 { 424 register int level = dir; 425 register int c; 426 427 do { 428 if (!lnext()) { 429 wdot = NOLINE; 430 return (0); 431 } 432 c = *wcursor; 433 if (c == parens[1]) 434 level--; 435 else if (c == parens[0]) 436 level++; 437 } while (level); 438 return (1); 439 } 440 441 lskipatom() 442 { 443 444 return (lskipa1("()")); 445 } 446 447 lskipa1(parens) 448 register char *parens; 449 { 450 register int c; 451 452 for (;;) { 453 if (dir < 0 && wcursor == linebuf) { 454 if (!lnext()) 455 return (0); 456 break; 457 } 458 c = *wcursor; 459 if (c && (isspace(c) || any(c, parens))) 460 break; 461 if (!lnext()) 462 return (0); 463 if (dir > 0 && wcursor == linebuf) 464 break; 465 } 466 return (ltosol1(parens)); 467 } 468 469 lnext() 470 { 471 472 if (dir > 0) { 473 if (*wcursor) 474 wcursor++; 475 if (*wcursor) 476 return (1); 477 if (wdot >= llimit) { 478 if (lf == vmove && wcursor > linebuf) 479 wcursor--; 480 return (0); 481 } 482 wdot++; 483 getline(*wdot); 484 wcursor = linebuf; 485 return (1); 486 } else { 487 --wcursor; 488 if (wcursor >= linebuf) 489 return (1); 490 #ifdef LISPCODE 491 if (lf == lindent && linebuf[0] == '(') 492 llimit = wdot; 493 #endif 494 if (wdot <= llimit) { 495 wcursor = linebuf; 496 return (0); 497 } 498 wdot--; 499 getline(*wdot); 500 wcursor = linebuf[0] == 0 ? linebuf : strend(linebuf) - 1; 501 return (1); 502 } 503 } 504 505 lbrack(c, f) 506 register int c; 507 int (*f)(); 508 { 509 register line *addr; 510 511 addr = dot; 512 for (;;) { 513 addr += dir; 514 if (addr < one || addr > dol) { 515 addr -= dir; 516 break; 517 } 518 getline(*addr); 519 if (linebuf[0] == '{' || 520 #ifdef LISPCODE 521 value(LISP) && linebuf[0] == '(' || 522 #endif 523 isa(svalue(SECTIONS))) { 524 if (c == ']' && f != vmove) { 525 addr--; 526 getline(*addr); 527 } 528 break; 529 } 530 if (c == ']' && f != vmove && linebuf[0] == '}') 531 break; 532 } 533 if (addr == dot) 534 return (0); 535 if (f != vmove) 536 wcursor = c == ']' ? strend(linebuf) : linebuf; 537 else 538 wcursor = 0; 539 wdot = addr; 540 vmoving = 0; 541 return (1); 542 } 543 544 isa(cp) 545 register char *cp; 546 { 547 548 if (linebuf[0] != '.') 549 return (0); 550 for (; cp[0] && cp[1]; cp += 2) 551 if (linebuf[1] == cp[0]) { 552 if (linebuf[2] == cp[1]) 553 return (1); 554 if (linebuf[2] == 0 && cp[1] == ' ') 555 return (1); 556 } 557 return (0); 558 } 559