diff options
| author | Jim Blandy | 1994-10-08 22:15:15 +0000 |
|---|---|---|
| committer | Jim Blandy | 1994-10-08 22:15:15 +0000 |
| commit | 9169c321e5e6b1fc3d8e88b53d845d7791d0454b (patch) | |
| tree | b0f980a90c3595393b805408330e4351920f871d /src | |
| parent | 56e1065ec396c40e81518e603444edecae4320f2 (diff) | |
| download | emacs-9169c321e5e6b1fc3d8e88b53d845d7791d0454b.tar.gz emacs-9169c321e5e6b1fc3d8e88b53d845d7791d0454b.zip | |
* search.c: #include "region-cache.h".
(max, min): Make these functions, not macros; we'd like to pass
them arguments that would be bad to evaluate more than once.
(newline_cache_on_off): New function.
(scan_buffer): New argument END. Call newline_cache_on_off. If
this buffer's newline cache is enabled, consult it to see if we
need to scan a region for newlines, and store information in the
cache after doing so.
(find_next_newline): Pass new arg to scan_buffer.
(find_before_next_newline): New function.
Diffstat (limited to 'src')
| -rw-r--r-- | src/search.c | 299 |
1 files changed, 227 insertions, 72 deletions
diff --git a/src/search.c b/src/search.c index c0a778697ad..bb871395b74 100644 --- a/src/search.c +++ b/src/search.c | |||
| @@ -22,15 +22,13 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |||
| 22 | #include "lisp.h" | 22 | #include "lisp.h" |
| 23 | #include "syntax.h" | 23 | #include "syntax.h" |
| 24 | #include "buffer.h" | 24 | #include "buffer.h" |
| 25 | #include "region-cache.h" | ||
| 25 | #include "commands.h" | 26 | #include "commands.h" |
| 26 | #include "blockinput.h" | 27 | #include "blockinput.h" |
| 27 | 28 | ||
| 28 | #include <sys/types.h> | 29 | #include <sys/types.h> |
| 29 | #include "regex.h" | 30 | #include "regex.h" |
| 30 | 31 | ||
| 31 | #define max(a, b) ((a) > (b) ? (a) : (b)) | ||
| 32 | #define min(a, b) ((a) < (b) ? (a) : (b)) | ||
| 33 | |||
| 34 | /* We compile regexps into this buffer and then use it for searching. */ | 32 | /* We compile regexps into this buffer and then use it for searching. */ |
| 35 | 33 | ||
| 36 | struct re_pattern_buffer searchbuf; | 34 | struct re_pattern_buffer searchbuf; |
| @@ -253,34 +251,94 @@ fast_string_match (regexp, string) | |||
| 253 | return val; | 251 | return val; |
| 254 | } | 252 | } |
| 255 | 253 | ||
| 256 | /* Search for COUNT instances of the character TARGET, starting at START. | 254 | /* max and min. */ |
| 257 | If COUNT is negative, search backwards. | 255 | |
| 256 | static int | ||
| 257 | max (a, b) | ||
| 258 | int a, b; | ||
| 259 | { | ||
| 260 | return ((a > b) ? a : b); | ||
| 261 | } | ||
| 262 | |||
| 263 | static int | ||
| 264 | min (a, b) | ||
| 265 | int a, b; | ||
| 266 | { | ||
| 267 | return ((a < b) ? a : b); | ||
| 268 | } | ||
| 269 | |||
| 270 | |||
| 271 | /* The newline cache: remembering which sections of text have no newlines. */ | ||
| 272 | |||
| 273 | /* If the user has requested newline caching, make sure it's on. | ||
| 274 | Otherwise, make sure it's off. | ||
| 275 | This is our cheezy way of associating an action with the change of | ||
| 276 | state of a buffer-local variable. */ | ||
| 277 | static void | ||
| 278 | newline_cache_on_off (buf) | ||
| 279 | struct buffer *buf; | ||
| 280 | { | ||
| 281 | if (NILP (buf->cache_long_line_scans)) | ||
| 282 | { | ||
| 283 | /* It should be off. */ | ||
| 284 | if (buf->newline_cache) | ||
| 285 | { | ||
| 286 | free_region_cache (buf->newline_cache); | ||
| 287 | buf->newline_cache = 0; | ||
| 288 | } | ||
| 289 | } | ||
| 290 | else | ||
| 291 | { | ||
| 292 | /* It should be on. */ | ||
| 293 | if (buf->newline_cache == 0) | ||
| 294 | buf->newline_cache = new_region_cache (); | ||
| 295 | } | ||
| 296 | } | ||
| 297 | |||
| 298 | |||
| 299 | /* Search for COUNT instances of the character TARGET between START and END. | ||
| 300 | |||
| 301 | If COUNT is positive, search forwards; END must be >= START. | ||
| 302 | If COUNT is negative, search backwards for the -COUNTth instance; | ||
| 303 | END must be <= START. | ||
| 304 | If COUNT is zero, do anything you please; run rogue, for all I care. | ||
| 305 | |||
| 306 | If END is zero, use BEGV or ZV instead, as appropriate for the | ||
| 307 | direction indicated by COUNT. | ||
| 258 | 308 | ||
| 259 | If we find COUNT instances, set *SHORTAGE to zero, and return the | 309 | If we find COUNT instances, set *SHORTAGE to zero, and return the |
| 260 | position after the COUNTth match. Note that for reverse motion | 310 | position after the COUNTth match. Note that for reverse motion |
| 261 | this is not the same as the usual convention for Emacs motion commands. | 311 | this is not the same as the usual convention for Emacs motion commands. |
| 262 | 312 | ||
| 263 | If we don't find COUNT instances before reaching the end of the | 313 | If we don't find COUNT instances before reaching END, set *SHORTAGE |
| 264 | buffer (or the beginning, if scanning backwards), set *SHORTAGE to | 314 | to the number of TARGETs left unfound, and return END. |
| 265 | the number of TARGETs left unfound, and return the end of the | ||
| 266 | buffer we bumped up against. | ||
| 267 | 315 | ||
| 268 | If ALLOW_QUIT is non-zero, set immediate_quit. That's good to do | 316 | If ALLOW_QUIT is non-zero, set immediate_quit. That's good to do |
| 269 | except when inside redisplay. */ | 317 | except when inside redisplay. */ |
| 270 | 318 | ||
| 271 | scan_buffer (target, start, count, shortage, allow_quit) | 319 | scan_buffer (target, start, end, count, shortage, allow_quit) |
| 272 | int *shortage, start; | 320 | register int target; |
| 273 | register int count, target; | 321 | int start, end; |
| 322 | int count; | ||
| 323 | int *shortage; | ||
| 274 | int allow_quit; | 324 | int allow_quit; |
| 275 | { | 325 | { |
| 276 | int limit = ((count > 0) ? ZV - 1 : BEGV); | 326 | struct region_cache *newline_cache; |
| 277 | int direction = ((count > 0) ? 1 : -1); | 327 | int direction; |
| 278 | 328 | ||
| 279 | register unsigned char *cursor; | 329 | if (count > 0) |
| 280 | unsigned char *base; | 330 | { |
| 331 | direction = 1; | ||
| 332 | if (! end) end = ZV; | ||
| 333 | } | ||
| 334 | else | ||
| 335 | { | ||
| 336 | direction = -1; | ||
| 337 | if (! end) end = BEGV; | ||
| 338 | } | ||
| 281 | 339 | ||
| 282 | register int ceiling; | 340 | newline_cache_on_off (current_buffer); |
| 283 | register unsigned char *ceiling_addr; | 341 | newline_cache = current_buffer->newline_cache; |
| 284 | 342 | ||
| 285 | if (shortage != 0) | 343 | if (shortage != 0) |
| 286 | *shortage = 0; | 344 | *shortage = 0; |
| @@ -288,78 +346,175 @@ scan_buffer (target, start, count, shortage, allow_quit) | |||
| 288 | immediate_quit = allow_quit; | 346 | immediate_quit = allow_quit; |
| 289 | 347 | ||
| 290 | if (count > 0) | 348 | if (count > 0) |
| 291 | while (start != limit + 1) | 349 | while (start != end) |
| 292 | { | 350 | { |
| 293 | ceiling = BUFFER_CEILING_OF (start); | 351 | /* Our innermost scanning loop is very simple; it doesn't know |
| 294 | ceiling = min (limit, ceiling); | 352 | about gaps, buffer ends, or the newline cache. ceiling is |
| 295 | ceiling_addr = &FETCH_CHAR (ceiling) + 1; | 353 | the position of the last character before the next such |
| 296 | base = (cursor = &FETCH_CHAR (start)); | 354 | obstacle --- the last character the dumb search loop should |
| 297 | while (1) | 355 | examine. */ |
| 298 | { | 356 | register int ceiling = end - 1; |
| 299 | while (*cursor != target && ++cursor != ceiling_addr) | 357 | |
| 300 | ; | 358 | /* If we're looking for a newline, consult the newline cache |
| 301 | if (cursor != ceiling_addr) | 359 | to see where we can avoid some scanning. */ |
| 302 | { | 360 | if (target == '\n' && newline_cache) |
| 303 | if (--count == 0) | 361 | { |
| 304 | { | 362 | int next_change; |
| 305 | immediate_quit = 0; | 363 | immediate_quit = 0; |
| 306 | return (start + cursor - base + 1); | 364 | while (region_cache_forward |
| 307 | } | 365 | (current_buffer, newline_cache, start, &next_change)) |
| 308 | else | 366 | start = next_change; |
| 309 | if (++cursor == ceiling_addr) | 367 | immediate_quit = 1; |
| 310 | break; | 368 | |
| 311 | } | 369 | /* start should never be after end. */ |
| 312 | else | 370 | if (start >= end) |
| 313 | break; | 371 | start = end - 1; |
| 314 | } | 372 | |
| 315 | start += cursor - base; | 373 | /* Now the text after start is an unknown region, and |
| 374 | next_change is the position of the next known region. */ | ||
| 375 | ceiling = min (next_change - 1, ceiling); | ||
| 376 | } | ||
| 377 | |||
| 378 | /* The dumb loop can only scan text stored in contiguous | ||
| 379 | bytes. BUFFER_CEILING_OF returns the last character | ||
| 380 | position that is contiguous, so the ceiling is the | ||
| 381 | position after that. */ | ||
| 382 | ceiling = min (BUFFER_CEILING_OF (start), ceiling); | ||
| 383 | |||
| 384 | { | ||
| 385 | /* The termination address of the dumb loop. */ | ||
| 386 | register unsigned char *ceiling_addr = &FETCH_CHAR (ceiling) + 1; | ||
| 387 | register unsigned char *cursor = &FETCH_CHAR (start); | ||
| 388 | unsigned char *base = cursor; | ||
| 389 | |||
| 390 | while (cursor < ceiling_addr) | ||
| 391 | { | ||
| 392 | unsigned char *scan_start = cursor; | ||
| 393 | |||
| 394 | /* The dumb loop. */ | ||
| 395 | while (*cursor != target && ++cursor < ceiling_addr) | ||
| 396 | ; | ||
| 397 | |||
| 398 | /* If we're looking for newlines, cache the fact that | ||
| 399 | the region from start to cursor is free of them. */ | ||
| 400 | if (target == '\n' && newline_cache) | ||
| 401 | know_region_cache (current_buffer, newline_cache, | ||
| 402 | start + scan_start - base, | ||
| 403 | start + cursor - base); | ||
| 404 | |||
| 405 | /* Did we find the target character? */ | ||
| 406 | if (cursor < ceiling_addr) | ||
| 407 | { | ||
| 408 | if (--count == 0) | ||
| 409 | { | ||
| 410 | immediate_quit = 0; | ||
| 411 | return (start + cursor - base + 1); | ||
| 412 | } | ||
| 413 | cursor++; | ||
| 414 | } | ||
| 415 | } | ||
| 416 | |||
| 417 | start += cursor - base; | ||
| 418 | } | ||
| 316 | } | 419 | } |
| 317 | else | 420 | else |
| 318 | { | 421 | while (start > end) |
| 319 | start--; /* first character we scan */ | 422 | { |
| 320 | while (start > limit - 1) | 423 | /* The last character to check before the next obstacle. */ |
| 321 | { /* we WILL scan under start */ | 424 | register int ceiling = end; |
| 322 | ceiling = BUFFER_FLOOR_OF (start); | 425 | |
| 323 | ceiling = max (limit, ceiling); | 426 | /* Consult the newline cache, if appropriate. */ |
| 324 | ceiling_addr = &FETCH_CHAR (ceiling) - 1; | 427 | if (target == '\n' && newline_cache) |
| 325 | base = (cursor = &FETCH_CHAR (start)); | 428 | { |
| 326 | cursor++; | 429 | int next_change; |
| 327 | while (1) | 430 | immediate_quit = 0; |
| 328 | { | 431 | while (region_cache_backward |
| 329 | while (--cursor != ceiling_addr && *cursor != target) | 432 | (current_buffer, newline_cache, start, &next_change)) |
| 330 | ; | 433 | start = next_change; |
| 331 | if (cursor != ceiling_addr) | 434 | immediate_quit = 1; |
| 332 | { | 435 | |
| 333 | if (++count == 0) | 436 | /* Start should never be at or before end. */ |
| 334 | { | 437 | if (start <= end) |
| 335 | immediate_quit = 0; | 438 | start = end + 1; |
| 336 | return (start + cursor - base + 1); | 439 | |
| 337 | } | 440 | /* Now the text before start is an unknown region, and |
| 338 | } | 441 | next_change is the position of the next known region. */ |
| 339 | else | 442 | ceiling = max (next_change, ceiling); |
| 340 | break; | 443 | } |
| 341 | } | 444 | |
| 342 | start += cursor - base; | 445 | /* Stop scanning before the gap. */ |
| 343 | } | 446 | ceiling = max (BUFFER_FLOOR_OF (start - 1), ceiling); |
| 344 | } | 447 | |
| 448 | { | ||
| 449 | /* The termination address of the dumb loop. */ | ||
| 450 | register unsigned char *ceiling_addr = &FETCH_CHAR (ceiling); | ||
| 451 | register unsigned char *cursor = &FETCH_CHAR (start - 1); | ||
| 452 | unsigned char *base = cursor; | ||
| 453 | |||
| 454 | while (cursor >= ceiling_addr) | ||
| 455 | { | ||
| 456 | unsigned char *scan_start = cursor; | ||
| 457 | |||
| 458 | while (*cursor != target && --cursor >= ceiling_addr) | ||
| 459 | ; | ||
| 460 | |||
| 461 | /* If we're looking for newlines, cache the fact that | ||
| 462 | the region from after the cursor to start is free of them. */ | ||
| 463 | if (target == '\n' && newline_cache) | ||
| 464 | know_region_cache (current_buffer, newline_cache, | ||
| 465 | start + cursor - base, | ||
| 466 | start + scan_start - base); | ||
| 467 | |||
| 468 | /* Did we find the target character? */ | ||
| 469 | if (cursor >= ceiling_addr) | ||
| 470 | { | ||
| 471 | if (++count >= 0) | ||
| 472 | { | ||
| 473 | immediate_quit = 0; | ||
| 474 | return (start + cursor - base); | ||
| 475 | } | ||
| 476 | cursor--; | ||
| 477 | } | ||
| 478 | } | ||
| 479 | |||
| 480 | start += cursor - base; | ||
| 481 | } | ||
| 482 | } | ||
| 483 | |||
| 345 | immediate_quit = 0; | 484 | immediate_quit = 0; |
| 346 | if (shortage != 0) | 485 | if (shortage != 0) |
| 347 | *shortage = count * direction; | 486 | *shortage = count * direction; |
| 348 | return (start + ((direction == 1 ? 0 : 1))); | 487 | return start; |
| 349 | } | 488 | } |
| 350 | 489 | ||
| 351 | int | 490 | int |
| 352 | find_next_newline_no_quit (from, cnt) | 491 | find_next_newline_no_quit (from, cnt) |
| 353 | register int from, cnt; | 492 | register int from, cnt; |
| 354 | { | 493 | { |
| 355 | return scan_buffer ('\n', from, cnt, (int *) 0, 0); | 494 | return scan_buffer ('\n', from, 0, cnt, (int *) 0, 0); |
| 356 | } | 495 | } |
| 357 | 496 | ||
| 358 | int | 497 | int |
| 359 | find_next_newline (from, cnt) | 498 | find_next_newline (from, cnt) |
| 360 | register int from, cnt; | 499 | register int from, cnt; |
| 361 | { | 500 | { |
| 362 | return scan_buffer ('\n', from, cnt, (int *) 0, 1); | 501 | return scan_buffer ('\n', from, 0, cnt, (int *) 0, 1); |
| 502 | } | ||
| 503 | |||
| 504 | |||
| 505 | /* Like find_next_newline, but returns position before the newline, | ||
| 506 | not after, and only search up to TO. This isn't just | ||
| 507 | find_next_newline (...)-1, because you might hit TO. */ | ||
| 508 | int | ||
| 509 | find_before_next_newline (from, to, cnt) | ||
| 510 | { | ||
| 511 | int shortage; | ||
| 512 | int pos = scan_buffer ('\n', from, to, cnt, &shortage, 1); | ||
| 513 | |||
| 514 | if (shortage == 0) | ||
| 515 | pos--; | ||
| 516 | |||
| 517 | return pos; | ||
| 363 | } | 518 | } |
| 364 | 519 | ||
| 365 | Lisp_Object skip_chars (); | 520 | Lisp_Object skip_chars (); |