TokenUtils 36 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/* Copyright 1997 Acorn Computers Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
15 16 17 18 19 20 21 22 23 24
/***************************************************/
/* File   : TokenUtils.c                           */
/*                                                 */
/* Purpose: Utility functions for finding out      */
/*          information about tokens.              */
/*                                                 */
/* Author : A.D.Hodgkinson                         */
/*                                                 */
/* History: 09-Apr-97: Created.                    */
/***************************************************/
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "HTMLLib.h" /* HTML library API, Which will include html2_ext.h, tags.h and struct.h */

#include "wimp.h"
#include "wimplib.h"
#include "event.h"

#include "swis.h"
#include "kernel.h"

#include "toolbox.h"
#include "event.h"

#include "svcprint.h"
#include "Global.h"
#include "MiscDefs.h"
#include "Utils.h"

#include "Redraw.h"

#include "TokenUtils.h"

/* Locals */

static tokenutils_npaths = 0;

/* Static function prototypes */

static int tokenutils_line_range_r(int toplevel, browser_data * b, reformat_cell * d, HStream * token, int * fline, int * fchunk, int * lline, int * lchunk, token_path ** path);

/*************************************************/
/* tokenutils_anchor_range()                     */
/*                                               */
/* Will return the first (inclusive) and last    */
/* (inclusive) tokens that consecutively point   */
/* to the same thing as anchors. This is useful  */
/* as some links may be made of several tokens,  */
/* as style changes to mark the result of a web  */
/* search (for example) or whatever may be used  */
/* in what is meant to be the same link. If this */
/* link is to be highlighted or selected, need   */
/* to know which tokens are involved.            */
/*                                               */
/* Parameters: Pointer to a browser_data struct  */
/*             relevant to the tokens;           */
74
/*                                               */
75 76
/*             Pointer to one of the tokens in   */
/*             the collection for this anchor;   */
77
/*                                               */
78 79 80 81
/*             Pointer to an HStream pointer,    */
/*             into which the address of the     */
/*             first token involved in the link  */
/*             is placed;                        */
82
/*                                               */
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
/*             Pointer to an HStream pointer,    */
/*             into which the address of the     */
/*             last token involved in the link   */
/*             is placed.                        */
/*                                               */
/* Assumes:    Either of the last two pointers   */
/*             may be NULL. The token pointer    */
/*             given at the start should point   */
/*             to a link. If not, the returned   */
/*             addresses will be undefined...    */
/*************************************************/

void tokenutils_anchor_range(browser_data * b, HStream * token, HStream ** first, HStream ** last)
{
  HStream * top   = NULL;
  HStream * end   = NULL;
  HStream * store = NULL;

101 102 103
  if (first) *first = NULL;
  if (last)  *last  = NULL;

104 105
  if (!b || !token) return;

106 107 108 109
  /* Can only proceed if the given token represents a link */

  if (token && (token->style & A) && token->anchor)
  {
110
    store = top = token;
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133

    /* Move up the token list for as long as the token given matches */
    /* the details of the token being looked at.                     */

    while (
            top                                  &&
            (top->style & A)                     &&
            top->anchor                          &&
            !strcmp(top->anchor, token->anchor)
          )
          store = top, top = top->prev;

    /* Make sure we haven't overshot the first item */

    if (!top) top = store;

    if (
         top && !(
                   (top->style & A)                    &&
                   top->anchor                         &&
                   !strcmp(top->anchor, token->anchor)
                 )
       )
134
       top = top->next;
135

136
    store = end = token;
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161

    /* Similary, move down the token list to find the first token after */
    /* all those involved in the link.                                  */

    while (
            end                                  &&
            (end->flags & HFlags_DealtWithToken) &&
            (end->style & A)                     &&
            end->anchor                          &&
            !strcmp(end->anchor, token->anchor)
          )
          store = end, end = end->next;

    /* Ensure we haven't overshot */

    if (!end) end = store;

    if (
         end && !(
                   (end->flags & HFlags_DealtWithToken) &&
                   (end->style & A)                     &&
                   end->anchor                          &&
                   !strcmp(end->anchor, token->anchor)
                 )
       )
162
       end = end->prev;
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
  }
  else top = end = token;

  /* Return the found values */

  if (first) *first = top;
  if (last)  *last  = end;

  return;
}

/*************************************************/
/* tokenutils_line_range()                       */
/*                                               */
/* Returns the first chunk and line number to    */
/* use a given token, and the last line and      */
/* chunk number to use that token.               */
/*                                               */
/* Parameters: Pointer to a browser_data struct  */
/*             relevant to the token;            */
/*                                               */
/*             Pointer to the token;             */
/*                                               */
/*             Pointer to an int, into which the */
/*             first line number is placed;      */
/*                                               */
/*             Pointer to an int, into which the */
/*             first chunk number is placed;     */
/*                                               */
/*             Pointer to an int, into which the */
/*             last line number is placed;       */
/*                                               */
/*             Pointer to an int, into which the */
/*             last chunk number is placed;      */
/*                                               */
/*             Pointer to a token_path pointer,  */
/*             which will be filled in with the  */
/*             address of a malloced array of    */
201 202 203
/*             reformat_cell structures for      */
/*             tokens within tables, or NULL if  */
/*             this shouldn't be built.          */
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309
/*                                               */
/* Returns:    See parameters list, and note     */
/*             that '-1' will be returned in all */
/*             four fields should be token not   */
/*             be found in a line to start with; */
/*                                               */
/*             The number of entries in the      */
/*             associated token_path structure   */
/*             for table-based tokens.           */
/*                                               */
/* Assumes:    Any of the pointers may be NULL.  */
/*************************************************/

int tokenutils_line_range(browser_data * b, HStream * token,
                          int * fline, int * fchunk, int * lline, int * lchunk, token_path ** path)
{
  tokenutils_npaths = 0;
  if (path) *path = NULL;

  return tokenutils_line_range_r(1, b, b->cell, token, fline, fchunk, lline, lchunk, path);
}

/*************************************************/
/* tokenutils_line_range_r()                     */
/*                                               */
/* Recursive back-end to tokenutils_line_range.  */
/*                                               */
/* Parameters: 1 for a top level call, else 0 if */
/*             being called recursively;         */
/*                                               */
/*             Pointer to a browser_data struct  */
/*             relevant to the token;            */
/*                                               */
/*             Pointer to a reformat_cell struct */
/*             containing the token or a table   */
/*             which holds the token;            */
/*                                               */
/*             Pointer to the token;             */
/*                                               */
/*             Pointer to an int, into which the */
/*             first line number is placed;      */
/*                                               */
/*             Pointer to an int, into which the */
/*             first chunk number is placed;     */
/*                                               */
/*             Pointer to an int, into which the */
/*             last line number is placed;       */
/*                                               */
/*             Pointer to an int, into which the */
/*             last chunk number is placed;      */
/*                                               */
/*             Pointer to a token_path pointer,  */
/*             which will be filled in with the  */
/*             address of a malloced array of    */
/*             token_path structures for tokens  */
/*             within tables, or NULL if this    */
/*             shouldn't be built.               */
/*                                               */
/* Returns:    As for tokenutils_line_range.     */
/*                                               */
/* Assumes:    As for tokenutils_line_range.     */
/*************************************************/

static int tokenutils_line_range_r(int toplevel, browser_data * b, reformat_cell * d, HStream * token,
                                   int * fline, int * fchunk, int * lline, int * lchunk, token_path ** path)
{
  int fl = -1, fc = -1, ll = -1, lc = -1; /* First Line, First Chunk, Last Line, Last Chunk */

  /* Start with all values at -1; saves having to fill them */
  /* in at any given failure point.                         */

  if (fline)  *fline  = fl;
  if (fchunk) *fchunk = fc;
  if (lline)  *lline  = ll;
  if (lchunk) *lchunk = lc;

  /* Can only try to find the token if the browser_data */
  /* and token pointers were not NULL.                  */

  if (b && d && token && d->nlines)
  {
    int cl, cc  = -1, mc; /* Current Line, Current Chunk, Maximum Chunk */
    int found   = 0;

    /* Must find the first line / chunk even if not asked for it */

    cl = 0;

    /* Loop through all lines */

    while (cl < d->nlines && !found)
    {
      cc = d->ldata[cl].chunks;
      mc = cc + d->ldata[cl].n;

      /* Go through this line's chunks looking for the token */

      while (cc < mc && !found)
      {
        if (toplevel) tokenutils_npaths = 0;

        if (d->cdata[cc].t == token) found = 1;
        else
        {
          /* Must recursively scan token lists for tables */

310
          if (d->cdata[cc].t->tagno == TAG_TABLE)
311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433
          {
            table_stream   * table     = (table_stream *) d->cdata[cc].t;
            table_row      * row       = NULL;
            table_headdata * head      = NULL;
            reformat_cell  * cellarray = table->cells;
            reformat_cell  * cell;
            int              found     = 0;
            int              cellindex;
            int              cellcount = 0;
            int              cellmax   = table->ColSpan * table->RowSpan;

            /* Naming convention: [Pointer] Table First/Last Line/Chunk */

            int              tfl = -1, tfc = -1, tll = -1, tlc = -1;
            int            * ptfl, * ptfc, * ptll, * ptlc;

            if (cellarray)
            {
              /* For recursive scanning of line lists, keep efficiency */
              /* as high as possible by only asking for the same       */
              /* values as originally passed to the function (e.g.     */
              /* don't want to look at last lines or chunks during     */
              /* the recursive scan unless they are needed at the top  */
              /* level too).                                           */

              if (fline)  ptfl = &tfl;
              else        ptfl = NULL;

              if (fchunk) ptfc = &tfc;
              else        ptfc = NULL;

              if (lline)  ptll = &tll;
              else        ptll = NULL;

              if (lchunk) ptlc = &tlc;
              else        ptlc = NULL;

              /* Scan the table */

              row = table->List;

              while (row && !found && cellcount < cellmax)
              {
                head = row->List;

                while (head && !found && cellcount < cellmax)
                {
                  switch (head->Tag)
                  {
                    case TagTableData:
                    case TagTableHead:
                    {
                      cellindex = table->ColSpan * head->RowOffs + head->ColOffs;

                      if (cellindex < cellmax)
                      {
                        cell = &cellarray[cellindex];

                        /* If a cell corresponding to this headdata item can be */
                        /* found and it has lines to scan, call this function   */
                        /* recursively on its contents.                         */

                        if (cell && cell->nlines)
                        {
                          /* Move flex anchors into the temporary browser_data struct */

                          tokenutils_line_range_r(0,
                                                  b,
                                                  cell,
                                                  token,
                                                  ptfl,
                                                  ptfc,
                                                  ptll,
                                                  ptlc,
                                                  path);

                          /* Check if the token was found */

                          if (tfl != -1 || tfc != -1 || tll != -1 || tlc != -1) found = 1;
                        }
                      }
                    }
                    break;
                  }

                  if (!found)
                  {
                    cellcount++;

                    head = head->Next;
                  }
                }

                if (!found) row = row->Next;
              }

              if (found)
              {
                if (path)
                {
                  token_path * temp;

                  /* Increment the tokenutils_npaths counter and allocate memory for a */
                  /* new token_path structure.                                         */

                  tokenutils_npaths++;

                  /* Note 'tokenutils_npaths + 1' - an extra structure for marking the */
                  /* end of the array.                                                 */

                  if (*path) temp = realloc(*path, (tokenutils_npaths + 1) * sizeof(token_path));
                  else       temp =         malloc((tokenutils_npaths + 1) * sizeof(token_path));

                  /* Complain and bail out if the allocation failed */

                  if (!temp)
                  {
                    if (*path)
                    {
                      free(*path);
                      *path = NULL;
                    }

434 435
                    show_error_ret(make_no_memory_error(1));

436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466
                    return 0;
                  }
                  else *path = temp;

                  /* Fill in the new token_path structure */

                  (*path)[tokenutils_npaths - 1].line  = cl;
                  (*path)[tokenutils_npaths - 1].chunk = cc;
                  (*path)[tokenutils_npaths - 1].head  = head;

                  /* Fill in the terminating structure */

                  (*path)[tokenutils_npaths].line  = -1;
                  (*path)[tokenutils_npaths].chunk = -1;
                  (*path)[tokenutils_npaths].head  = NULL;
                }

                /* Since we've found the token within a table inside this line, */
                /* and the token_path is filled in, want to exit now.           */

                if (fline)  *fline  = tfl;
                if (fchunk) *fchunk = tfc;
                if (lline)  *lline  = tll;
                if (lchunk) *lchunk = tlc;

                return tokenutils_npaths;
              }

            /* Closure of 'if (cellarray)' */
            }

467
          /* Closure of 'if (d->cdata[cc].t->tagno == TAG_TABLE)' */
468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540
          }

          cc++;

        /* Closure of 'else' section to 'if (d->cdata[cc].t == token)' */
        }

      /* Closure of 'while' loop going through all the chunks */
      }

      /* If we haven't found a chunk yet, go to the next line */

      if (!found) cl ++;
    }

    if (found)
    {
      if (cl >= d->nlines) cl = d->nlines - 1;
      fl = cl, fc = cc;

      /* If a line and chunk have been found, record them in fl and fc */

      if (cl >= 0 && cc >= 0)
      {
        /* Only try to find the last line / chunk if asked for them */

        if (lline || lchunk)
        {
          /* Start at the next line and if this starts with the given */
          /* token, keep moving on until a line which doesn't start   */
          /* with the token is found.                                 */

          cl++;
          while (cl < d->nlines && d->cdata[d->ldata[cl].chunks].t == token) cl++;

          /* Coming out of the above loop either we'll be at cl = d->nlines, */
          /* or cl will be the first line that doesn't start with the given  */
          /* token. In either case, must decrement cl by one to get back to  */
          /* a line which does include the token.                            */

          cl--;

          if (lchunk)
          {
            /* Now search the chunks for the token, starting at the last chunk */

            cc = d->ldata[cl].chunks + d->ldata[cl].n - 1;

            while (cc >= d->ldata[cl].chunks && d->cdata[cc].t != token) cc--;

            /* If cc is still in range, a token was found on this line (it */
            /* should always be, but something might go wrong above and    */
            /* this check is worth doing for robustness). So copy the last */
            /* line and chunk details to ll and lc.                        */

            if (cc >= d->ldata[cl].chunks) ll = cl, lc = cc;
          }
          else ll = cl;
        }
      }
    }
  }

  /* Fill in any requested values */

  if (fline)  *fline  = fl;
  if (fchunk) *fchunk = fc;
  if (lline)  *lline  = ll;
  if (lchunk) *lchunk = lc;

  return tokenutils_npaths;
}

541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586
/*************************************************/
/* tokenutils_find_ancestor_line()               */
/*                                               */
/* Returns the line in a given browser's main    */
/* line list in which a given token lies, or -1  */
/* if the token can't be found.                  */
/*                                               */
/* Parameters: Pointer to a browser_data struct  */
/*             relevant to the token and lines;  */
/*                                               */
/*             Pointer to the HStream struct to  */
/*             find.                             */
/*                                               */
/* Returns:    Line number that the token lies   */
/*             in, in the main line list - so    */
/*             the token could well lie inside   */
/*             a table within that line. -1 is   */
/*             returned if the token is not      */
/*             found in the line list at all.    */
/*************************************************/

int tokenutils_find_ancestor_line(browser_data * b, HStream * t)
{
  int          l;
  int          chunk, depth, noline = 0;
  token_path * path = NULL;

  depth = tokenutils_line_range(b, t, &l, &chunk, NULL, NULL, &path);

  if (l < 0) noline = 1;
  else
  {
    /* If a line was found and depth is non-zero, the line was inside */
    /* a table - want to find the parent line of the table            */

    if (depth) l = path[depth - 1].line;
    if (l < 0) noline = 1;
  }

  if (path) free(path);

  if (noline) return -1;

  return l;
}

587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747
/*************************************************/
/* tokenutils_find_token                         */
/*                                               */
/* For a given token in a given reformat_cell,   */
/* returns the line and chunk number that the    */
/* token spans.                                  */
/*                                               */
/* Parameters: Pointer to a browser_data struct  */
/*             relevant to the token;            */
/*                                               */
/*             Pointer to a reformat_cell struct */
/*             containing the token or a table   */
/*             which holds the token;            */
/*                                               */
/*             Pointer to the token;             */
/*                                               */
/*             Pointer to an int, into which the */
/*             first line number is placed;      */
/*                                               */
/*             Pointer to an int, into which the */
/*             first chunk number is placed;     */
/*                                               */
/*             Pointer to an int, into which the */
/*             last line number is placed;       */
/*                                               */
/*             Pointer to an int, into which the */
/*             last chunk number is placed;      */
/*                                               */
/* Returns:    See parameters list, and note     */
/*             that '-1' will be returned in all */
/*             four fields should be token not   */
/*             be found in a line to start with; */
/*                                               */
/* Assumes:    Any of the pointers may be NULL.  */
/*************************************************/

void tokenutils_find_token(browser_data * b, reformat_cell * d, HStream * token, int * fline, int * fchunk, int * lline, int * lchunk)
{
  int fl = -1, fc = -1, ll = -1, lc = -1; /* First Line, First Chunk, Last Line, Last Chunk */

  /* Start with all values at -1; saves having to fill them */
  /* in at any given failure point.                         */

  if (fline)  *fline  = fl;
  if (fchunk) *fchunk = fc;
  if (lline)  *lline  = ll;
  if (lchunk) *lchunk = lc;

  /* Can only try to find the token if the browser_data */
  /* and token pointers were not NULL.                  */

  if (b && d && token && d->nlines)
  {
    int cl, cc  = -1, mc; /* Current Line, Current Chunk, Maximum Chunk */
    int found   = 0;

    /* Must find the first line / chunk even if not asked for it */

    cl = 0;

    /* Loop through all lines */

    while (cl < d->nlines && !found)
    {
      cc = d->ldata[cl].chunks;
      mc = cc + d->ldata[cl].n;

      /* Go through this line's chunks looking for the token */

      while (cc < mc && !found)
      {
        if (d->cdata[cc].t == token) found = 1;

        /* If not found, go to the next chunk */

        else cc++;
      }

      /* If we haven't found a chunk yet, go to the next line */

      if (!found) cl ++;
    }

    if (found)
    {
      if (cl >= d->nlines) cl = d->nlines - 1;
      fl = cl, fc = cc;

      /* If a line and chunk have been found, record them in fl and fc */

      if (cl >= 0 && cc >= 0)
      {
        /* Only try to find the last line / chunk if asked for them */

        if (lline || lchunk)
        {
          /* Start at the next line and if this starts with the given */
          /* token, keep moving on until a line which doesn't start   */
          /* with the token is found.                                 */

          cl++;
          while (cl < d->nlines && d->cdata[d->ldata[cl].chunks].t == token) cl++;

          /* Coming out of the above loop either we'll be at cl = d->nlines, */
          /* or cl will be the first line that doesn't start with the given  */
          /* token. In either case, must decrement cl by one to get back to  */
          /* a line which does include the token.                            */

          cl--;

          if (lchunk)
          {
            /* Now search the chunks for the token, starting at the last chunk */

            cc = d->ldata[cl].chunks + d->ldata[cl].n - 1;

            while (cc >= d->ldata[cl].chunks && d->cdata[cc].t != token) cc--;

            /* If cc is still in range, a token was found on this line (it */
            /* should always be, but something might go wrong above and    */
            /* this check is worth doing for robustness). So copy the last */
            /* line and chunk details to ll and lc.                        */

            if (cc >= d->ldata[cl].chunks) ll = cl, lc = cc;
          }
          else ll = cl;
        }
      }
    }
  }

  /* Fill in any requested values */

  if (fline)  *fline  = fl;
  if (fchunk) *fchunk = fc;
  if (lline)  *lline  = ll;
  if (lchunk) *lchunk = lc;

  /* Finished */

  return;
}

/*************************************************/
/* tokenutils_token_cell_offset()                */
/*                                               */
/* When a token has been found to lie in a table */
/* (tokenutils_line_range has filled in an       */
/* array of token_path structures) this call     */
/* can be used to quickly find the x and y       */
/* offset from the top left of the main page     */
/* that the line list the token was in is        */
/* positioned at (i.e. for tables, the offset of */
/* the table cell the token lies in). This can   */
/* be used as an origin shift for any subsequent */
/* redraws (say).                                */
/*                                               */
/* External callers trying to then find the      */
/* token x and y position should remember to     */
/* work this out for the correct line array,     */
/* which will be indicated by the first entry    */
748
/* in the token_path array.                      */
749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928
/*                                               */
/* Parameters: Pointer to a browser_data struct  */
/*             relevant to the token_path array; */
/*                                               */
/*             Pointer to the token_path array;  */
/*                                               */
/*             Pointer to an int, in which the   */
/*             x offset will be written;         */
/*                                               */
/*             Pointer to an int, in which the   */
/*             y offset will be written.         */
/*                                               */
/* Assumes:    Any pointer may be NULL. If the   */
/*             token_path array is NULL, then    */
/*             an offset of 0,0 is given.        */
/*************************************************/

void tokenutils_token_offset(browser_data * b, token_path * path, int * offset_x, int * offset_y)
{
  int             actx = 0, acty = 0;
  reformat_cell * cell = b->cell;

  /* Only start working things out if there's a token_path array */

  if (path && tokenutils_npaths)
  {
    int              index = tokenutils_npaths - 1;
    int              line, chunk;
    table_stream   * table;
    table_headdata * head;
    reformat_cell  * cellarray = NULL;
    reformat_cell  * c         = NULL;

    /* Find the line, chunk, headdata structure, table structure and */
    /* cell array for the last item in the token_path array.         */

    line      = path[index].line;
    chunk     = path[index].chunk;
    head      = path[index].head;
    table     = (table_stream *) cell->cdata[chunk].t;
    cellarray = table->cells;

    /* Increment by the offset of the top left of the table. */
    /* Since the last item in the array corresponds to the   */
    /* browser_data structure's cell array itself, here we   */
    /* use b->cell (stored in 'cell' above) rather than a    */
    /* table-derived cell.                                   */

    actx += redraw_start_x(b, cell, cell->cdata[chunk].t, line);
    acty += cell->ldata[line].y + cell->ldata[line].h;

    /* If there's a cell array, find the cell the current headdata */
    /* item is represented by.                                     */

    if (cellarray) c = &cellarray[table->ColSpan * head->RowOffs + head->ColOffs];

    /* If there's a cell, offset actx and acty by the top left */
    /* hand offset of that cell.                               */

    if (c)
    {
      int incx, incy;

      convert_pair_to_os(c->x, c->y, &incx, &incy);

      actx += incx, acty += incy;
    }

    /* Now do much the same for the remaining items in the token_path array */

    index--;

    while (index >= 0 && c && c->ldata && c->cdata)
    {
      line      = path[index].line;
      chunk     = path[index].chunk;
      head      = path[index].head;
      table     = (table_stream *) c->cdata[chunk].t;
      cellarray = table->cells;

      actx += redraw_start_x(b, c, c->cdata[chunk].t, line);
      acty += c->ldata[line].y + c->ldata[line].h;

      if (cellarray) c = &cellarray[table->ColSpan * head->RowOffs + head->ColOffs];

      if (c)
      {
        int incx, incy;

        convert_pair_to_os(c->x, c->y, &incx, &incy);

        actx += incx, acty += incy;
      }

      index--;
    }
  }

  /* actx and acty will either have been calculated from the token_path */
  /* array or will still be at 0 if no array was given.                 */

  if (offset_x) *offset_x = actx;
  if (offset_y) *offset_y = acty;

  return;
}

/*************************************************/
/* tokenutils_find_cell()                        */
/*                                               */
/* Examines a token_path array and returns the   */
/* address of the reformat_cell structure that   */
/* corresponds to the last entry.                */
/*                                               */
/* Parameters: Pointer to the reformat_cell that */
/*             the token_path array refers to in */
/*             the first entry (e.g. the 'cell'  */
/*             field of the parent browser_data  */
/*             structure);                       */
/*                                               */
/*             Number of entries in the array;   */
/*                                               */
/*             Pointer to the first entry.       */
/*                                               */
/* Returns:    Pointer to the reformat_cell      */
/*             structure corresponding to the    */
/*             last entry, or NULL if none may   */
/*             be found.                         */
/*************************************************/

reformat_cell * tokenutils_find_cell(reformat_cell * cell, int depth, token_path * path)
{
  if (depth && path && path[0].line >= 0 && path[depth - 1].line >= 0)
  {
    table_stream   * table;
    table_headdata * head;
    reformat_cell  * cellarray    = NULL;
    reformat_cell  * c            = NULL;
    int              index        = depth - 1;
    int              line, chunk;

    /* Start looking at the token_path array. The last */
    /* entry refers to the main line array, so get to  */
    /* the appropriate reformat_cell structure through */
    /* the main line list.                             */

    line  = path[index].line;
    chunk = path[index].chunk;
    head  = path[index].head;

    table     = (table_stream *) cell->cdata[chunk].t;
    cellarray = table->cells;

    if (cellarray) c = &cellarray[table->ColSpan * head->RowOffs + head->ColOffs];

    index--;

    /* Need to look at subsequent cell line arrays for any */
    /* nested tables.                                      */

    while (index >= 0 && c)
    {
      line  = path[index].line;
      chunk = path[index].chunk;
      head  = path[index].head;

      table     = (table_stream *) c->cdata[chunk].t;
      cellarray = table->cells;

      if (cellarray) c = &cellarray[table->ColSpan * head->RowOffs + head->ColOffs];

      index--;
    }

    return c;
  }

  return NULL;
}

929 930 931 932 933 934 935 936 937 938 939 940 941 942 943
/*************************************************/
/* tokenutils_token_cell()                       */
/*                                               */
/* Returns the reformat_cell that a given token  */
/* lies in. This may be NULL.                    */
/*                                               */
/* Parameters: Pointer to a browser_data struct  */
/*             relevant to the token;            */
/*                                               */
/*             Pointer to the token.             */
/*************************************************/

reformat_cell * tokenutils_token_cell(browser_data * b, HStream * token)
{
  table_headdata * head;
944
  table_row      * row;
945 946 947 948 949 950 951 952 953 954 955 956
  table_stream   * table;

  reformat_cell  * cellarray;
  int              cellnumber;

  if (!b || !token) return NULL;

  /* Find the table the token lies in */

  head = token->parent;
  if (!head) return NULL;

957 958 959 960
  row = head->parent;
  if (!row) return NULL;

  table = row->parent;
961 962 963 964 965 966 967 968 969 970 971 972 973
  if (!table) return NULL;

  cellarray = table->cells;
  if (!cellarray) return NULL;

  /* Work out what number this cell is in the cell array */

  cellnumber = head->ColOffs + table->ColSpan * head->RowOffs;

  if (cellnumber > table->ncells) return NULL;
  else                            return &cellarray[cellnumber];
}

974 975 976 977 978 979 980 981
/*************************************************/
/* tokenutils_within_distance()                  */
/*                                               */
/* Returns 1 if a given token is within a given  */
/* distance of another, vertically.              */
/*                                               */
/* Parameters: Pointer to a browser_data struct  */
/*             relevant to the tokens;           */
982
/*                                               */
983
/*             Pointer to the first token;       */
984
/*                                               */
985
/*             Pointer to the second token;      */
986
/*                                               */
987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027
/*             Distance that the tokens must be  */
/*             within.                           */
/*                                               */
/* Returns:    1 if the tokens are within the    */
/*             given distance of each other,     */
/*             else 0.                           */
/*                                               */
/* Assumes:    If either HStream pointer is NULL */
/*             the function return 1.            */
/*************************************************/

int tokenutils_within_distance(browser_data * b, HStream * t1, HStream * t2, int distance)
{
  int             lfir1, llas1, lfir2, llas2;
  int             check;
  reformat_cell * cell = b->cell;

  if (!t1 || !t2) return 1;

  /* Ensure distance is a positive number and find the */
  /* lines that the tokens span.                       */

  if (distance < 0) distance = -distance;

  tokenutils_line_range(b, t1, &lfir1, NULL, &llas1, NULL, NULL);
  tokenutils_line_range(b, t2, &lfir2, NULL, &llas2, NULL, NULL);

  /* Special case, tokens must be at zero distance effectively */

  if (lfir1 == lfir2 || llas1 == llas2) return 1;

  /* Want to ensure that the maximum distance between the tokens */
  /* is taken for the check. E.g. if t1 is above t2 (i.e. lfir1  */
  /* is less than lfir2) then want to check the distance between */
  /* the top line of t1 to the bottom line of t2.                */

  if (lfir1 < lfir2) check = cell->ldata[lfir1].y + cell->ldata[lfir1].h - cell->ldata[lfir2].y;
  else               check = cell->ldata[lfir2].y + cell->ldata[lfir2].h - cell->ldata[lfir1].y;

  return (check <= distance);
}