1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS kernel 4 * PURPOSE: Line functions 5 * FILE: win32ss/gdi/eng/lineto.c 6 * PROGRAMER: ReactOS Team 7 */ 8 9 #include <win32k.h> 10 11 #define NDEBUG 12 #include <debug.h> 13 14 static void FASTCALL 15 TranslateRects(RECT_ENUM *RectEnum, POINTL* Translate) 16 { 17 RECTL* CurrentRect; 18 19 if (0 != Translate->x || 0 != Translate->y) 20 { 21 for (CurrentRect = RectEnum->arcl; CurrentRect < RectEnum->arcl + RectEnum->c; CurrentRect++) 22 { 23 CurrentRect->left += Translate->x; 24 CurrentRect->right += Translate->x; 25 CurrentRect->top += Translate->y; 26 CurrentRect->bottom += Translate->y; 27 } 28 } 29 } 30 31 LONG 32 HandleStyles( 33 BRUSHOBJ *pbo, 34 POINTL* Translate, 35 LONG x, 36 LONG y, 37 LONG deltax, 38 LONG deltay, 39 LONG dx, 40 LONG dy, 41 PULONG piStyle) 42 { 43 PEBRUSHOBJ pebo = (PEBRUSHOBJ)pbo; 44 PULONG pulStyles = pebo->pbrush->pStyle; 45 ULONG iStyle, cStyles = pebo->pbrush->dwStyleCount; 46 LONG diStyle, offStyle, lStyleMax; 47 48 if (cStyles > 0) 49 { 50 if (deltax > deltay) 51 { 52 offStyle = (- Translate->x) % pebo->pbrush->ulStyleSize; 53 diStyle = dx; 54 lStyleMax = x; 55 } 56 else 57 { 58 offStyle = (- Translate->y) % pebo->pbrush->ulStyleSize; 59 diStyle = dy; 60 lStyleMax = y; 61 } 62 63 /* Now loop until we have found the style index */ 64 for (iStyle = 0; offStyle >= pulStyles[iStyle]; iStyle++) 65 { 66 offStyle -= pulStyles[iStyle]; 67 } 68 69 if (diStyle > 0) 70 { 71 lStyleMax += pulStyles[iStyle] - offStyle; 72 } 73 else 74 { 75 lStyleMax -= offStyle + 1; 76 } 77 } 78 else 79 { 80 iStyle = 0; 81 lStyleMax = MAX_COORD; 82 } 83 84 *piStyle = iStyle; 85 return lStyleMax; 86 } 87 88 /* 89 * Draw a line from top-left to bottom-right 90 */ 91 void FASTCALL 92 NWtoSE(SURFOBJ* OutputObj, CLIPOBJ* Clip, 93 BRUSHOBJ* pbo, LONG x, LONG y, LONG deltax, LONG deltay, 94 POINTL* Translate) 95 { 96 int i; 97 int error; 98 BOOLEAN EnumMore; 99 RECTL* ClipRect; 100 RECT_ENUM RectEnum; 101 ULONG Pixel = pbo->iSolidColor; 102 LONG delta; 103 PEBRUSHOBJ pebo = (PEBRUSHOBJ)pbo; 104 PULONG pulStyles = pebo->pbrush->pStyle; 105 ULONG iStyle, cStyles = pebo->pbrush->dwStyleCount; 106 LONG lStyleMax; 107 108 lStyleMax = HandleStyles(pbo, Translate, x, y, deltax, deltay, 1, 1, &iStyle); 109 110 CLIPOBJ_cEnumStart(Clip, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, 0); 111 EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum); 112 TranslateRects(&RectEnum, Translate); 113 ClipRect = RectEnum.arcl; 114 delta = max(deltax, deltay); 115 i = 0; 116 error = delta >> 1; 117 while (i < delta && (ClipRect < RectEnum.arcl + RectEnum.c || EnumMore)) 118 { 119 while ((ClipRect < RectEnum.arcl + RectEnum.c /* there's still a current clip rect */ 120 && (ClipRect->bottom <= y /* but it's above us */ 121 || (ClipRect->top <= y && ClipRect->right <= x))) /* or to the left of us */ 122 || EnumMore) /* no current clip rect, but rects left */ 123 { 124 /* Skip to the next clip rect */ 125 if (RectEnum.arcl + RectEnum.c <= ClipRect) 126 { 127 EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum); 128 TranslateRects(&RectEnum, Translate); 129 ClipRect = RectEnum.arcl; 130 } 131 else 132 { 133 ClipRect++; 134 } 135 } 136 if (ClipRect < RectEnum.arcl + RectEnum.c) /* If there's no current clip rect we're done */ 137 { 138 if ((ClipRect->left <= x && ClipRect->top <= y) && ((iStyle & 1) == 0)) 139 { 140 DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_PutPixel( 141 OutputObj, x, y, Pixel); 142 } 143 if (deltax < deltay) 144 { 145 y++; 146 if (y == lStyleMax) 147 { 148 iStyle = (iStyle + 1) % cStyles; 149 lStyleMax = y + pulStyles[iStyle]; 150 } 151 error = error + deltax; 152 if (deltay <= error) 153 { 154 x++; 155 error = error - deltay; 156 } 157 } 158 else 159 { 160 x++; 161 if (x == lStyleMax) 162 { 163 iStyle = (iStyle + 1) % cStyles; 164 lStyleMax = x + pulStyles[iStyle]; 165 } 166 error = error + deltay; 167 if (deltax <= error) 168 { 169 y++; 170 error = error - deltax; 171 } 172 } 173 i++; 174 } 175 } 176 } 177 178 void FASTCALL 179 SWtoNE(SURFOBJ* OutputObj, CLIPOBJ* Clip, 180 BRUSHOBJ* pbo, LONG x, LONG y, LONG deltax, LONG deltay, 181 POINTL* Translate) 182 { 183 int i; 184 int error; 185 BOOLEAN EnumMore; 186 RECTL* ClipRect; 187 RECT_ENUM RectEnum; 188 ULONG Pixel = pbo->iSolidColor; 189 LONG delta; 190 PEBRUSHOBJ pebo = (PEBRUSHOBJ)pbo; 191 PULONG pulStyles = pebo->pbrush->pStyle; 192 ULONG iStyle, cStyles = pebo->pbrush->dwStyleCount; 193 LONG lStyleMax; 194 195 lStyleMax = HandleStyles(pbo, Translate, x, y, deltax, deltay, 1, -1, &iStyle); 196 197 CLIPOBJ_cEnumStart(Clip, FALSE, CT_RECTANGLES, CD_RIGHTUP, 0); 198 EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum); 199 TranslateRects(&RectEnum, Translate); 200 ClipRect = RectEnum.arcl; 201 delta = max(deltax, deltay); 202 i = 0; 203 error = delta >> 1; 204 while (i < delta && (ClipRect < RectEnum.arcl + RectEnum.c || EnumMore)) 205 { 206 while ((ClipRect < RectEnum.arcl + RectEnum.c 207 && (y < ClipRect->top 208 || (y < ClipRect->bottom && ClipRect->right <= x))) 209 || EnumMore) 210 { 211 if (RectEnum.arcl + RectEnum.c <= ClipRect) 212 { 213 EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum); 214 TranslateRects(&RectEnum, Translate); 215 ClipRect = RectEnum.arcl; 216 } 217 else 218 { 219 ClipRect++; 220 } 221 } 222 if (ClipRect < RectEnum.arcl + RectEnum.c) 223 { 224 if ((ClipRect->left <= x && y < ClipRect->bottom) && ((iStyle & 1) == 0)) 225 { 226 DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_PutPixel( 227 OutputObj, x, y, Pixel); 228 } 229 if (deltax < deltay) 230 { 231 y--; 232 if (y == lStyleMax) 233 { 234 iStyle = (iStyle - 1) % cStyles; 235 lStyleMax = y - pulStyles[iStyle]; 236 } 237 error = error + deltax; 238 if (deltay <= error) 239 { 240 x++; 241 error = error - deltay; 242 } 243 } 244 else 245 { 246 x++; 247 if (x == lStyleMax) 248 { 249 iStyle = (iStyle + 1) % cStyles; 250 lStyleMax = x + pulStyles[iStyle]; 251 } 252 error = error + deltay; 253 if (deltax <= error) 254 { 255 y--; 256 error = error - deltax; 257 } 258 } 259 i++; 260 } 261 } 262 } 263 264 void FASTCALL 265 NEtoSW(SURFOBJ* OutputObj, CLIPOBJ* Clip, 266 BRUSHOBJ* pbo, LONG x, LONG y, LONG deltax, LONG deltay, 267 POINTL* Translate) 268 { 269 int i; 270 int error; 271 BOOLEAN EnumMore; 272 RECTL* ClipRect; 273 RECT_ENUM RectEnum; 274 ULONG Pixel = pbo->iSolidColor; 275 LONG delta; 276 PEBRUSHOBJ pebo = (PEBRUSHOBJ)pbo; 277 PULONG pulStyles = pebo->pbrush->pStyle; 278 ULONG iStyle, cStyles = pebo->pbrush->dwStyleCount; 279 LONG lStyleMax; 280 281 lStyleMax = HandleStyles(pbo, Translate, x, y, deltax, deltay, -1, 1, &iStyle); 282 283 CLIPOBJ_cEnumStart(Clip, FALSE, CT_RECTANGLES, CD_LEFTDOWN, 0); 284 EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum); 285 TranslateRects(&RectEnum, Translate); 286 ClipRect = RectEnum.arcl; 287 delta = max(deltax, deltay); 288 i = 0; 289 error = delta >> 1; 290 while (i < delta && (ClipRect < RectEnum.arcl + RectEnum.c || EnumMore)) 291 { 292 while ((ClipRect < RectEnum.arcl + RectEnum.c 293 && (ClipRect->bottom <= y 294 || (ClipRect->top <= y && x < ClipRect->left))) 295 || EnumMore) 296 { 297 if (RectEnum.arcl + RectEnum.c <= ClipRect) 298 { 299 EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum); 300 TranslateRects(&RectEnum, Translate); 301 ClipRect = RectEnum.arcl; 302 } 303 else 304 { 305 ClipRect++; 306 } 307 } 308 if (ClipRect < RectEnum.arcl + RectEnum.c) 309 { 310 if ((x < ClipRect->right && ClipRect->top <= y) && ((iStyle & 1) == 0)) 311 { 312 DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_PutPixel( 313 OutputObj, x, y, Pixel); 314 } 315 if (deltax < deltay) 316 { 317 y++; 318 if (y == lStyleMax) 319 { 320 iStyle = (iStyle + 1) % cStyles; 321 lStyleMax = y + pulStyles[iStyle]; 322 } 323 error = error + deltax; 324 if (deltay <= error) 325 { 326 x--; 327 error = error - deltay; 328 } 329 } 330 else 331 { 332 x--; 333 if (x == lStyleMax) 334 { 335 iStyle = (iStyle - 1) % cStyles; 336 lStyleMax = x - pulStyles[iStyle]; 337 } 338 error = error + deltay; 339 if (deltax <= error) 340 { 341 y++; 342 error = error - deltax; 343 } 344 } 345 i++; 346 } 347 } 348 } 349 350 void FASTCALL 351 SEtoNW(SURFOBJ* OutputObj, CLIPOBJ* Clip, 352 BRUSHOBJ* pbo, LONG x, LONG y, LONG deltax, LONG deltay, 353 POINTL* Translate) 354 { 355 int i; 356 int error; 357 BOOLEAN EnumMore; 358 RECTL* ClipRect; 359 RECT_ENUM RectEnum; 360 ULONG Pixel = pbo->iSolidColor; 361 LONG delta; 362 PEBRUSHOBJ pebo = (PEBRUSHOBJ)pbo; 363 PULONG pulStyles = pebo->pbrush->pStyle; 364 ULONG iStyle, cStyles = pebo->pbrush->dwStyleCount; 365 LONG lStyleMax; 366 367 lStyleMax = HandleStyles(pbo, Translate, x, y, deltax, deltay, -1, -1, &iStyle); 368 369 CLIPOBJ_cEnumStart(Clip, FALSE, CT_RECTANGLES, CD_LEFTUP, 0); 370 EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum); 371 TranslateRects(&RectEnum, Translate); 372 ClipRect = RectEnum.arcl; 373 delta = max(deltax, deltay); 374 i = 0; 375 error = delta >> 1; 376 while (i < delta && (ClipRect < RectEnum.arcl + RectEnum.c || EnumMore)) 377 { 378 while ((ClipRect < RectEnum.arcl + RectEnum.c 379 && (y < ClipRect->top 380 || (y < ClipRect->bottom && x < ClipRect->left))) 381 || EnumMore) 382 { 383 if (RectEnum.arcl + RectEnum.c <= ClipRect) 384 { 385 EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum); 386 TranslateRects(&RectEnum, Translate); 387 ClipRect = RectEnum.arcl; 388 } 389 else 390 { 391 ClipRect++; 392 } 393 } 394 if (ClipRect < RectEnum.arcl + RectEnum.c) 395 { 396 if ((x < ClipRect->right && y < ClipRect->bottom) && ((iStyle & 1) == 0)) 397 { 398 DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_PutPixel( 399 OutputObj, x, y, Pixel); 400 } 401 if (deltax < deltay) 402 { 403 y--; 404 if (y == lStyleMax) 405 { 406 iStyle = (iStyle - 1) % cStyles; 407 lStyleMax = y - pulStyles[iStyle]; 408 } 409 error = error + deltax; 410 if (deltay <= error) 411 { 412 x--; 413 error = error - deltay; 414 } 415 } 416 else 417 { 418 x--; 419 if (x == lStyleMax) 420 { 421 iStyle = (iStyle - 1) % cStyles; 422 lStyleMax = x - pulStyles[iStyle]; 423 } 424 error = error + deltay; 425 if (deltax <= error) 426 { 427 y--; 428 error = error - deltax; 429 } 430 } 431 i++; 432 } 433 } 434 } 435 436 /* 437 * @implemented 438 */ 439 BOOL APIENTRY 440 EngLineTo( 441 _Inout_ SURFOBJ *DestObj, 442 _In_ CLIPOBJ *Clip, 443 _In_ BRUSHOBJ *pbo, 444 _In_ LONG x1, 445 _In_ LONG y1, 446 _In_ LONG x2, 447 _In_ LONG y2, 448 _In_opt_ RECTL *RectBounds, 449 _In_ MIX mix) 450 { 451 LONG x, y, deltax, deltay, xchange, ychange, hx, vy; 452 ULONG i; 453 ULONG Pixel = pbo->iSolidColor; 454 SURFOBJ *OutputObj; 455 RECTL DestRect; 456 POINTL Translate; 457 INTENG_ENTER_LEAVE EnterLeave; 458 RECT_ENUM RectEnum; 459 BOOL EnumMore; 460 CLIPOBJ *pcoPriv = NULL; 461 PEBRUSHOBJ pebo = (PEBRUSHOBJ)pbo; 462 ULONG cStyles = pebo->pbrush->dwStyleCount; 463 464 if (x1 < x2) 465 { 466 DestRect.left = x1; 467 DestRect.right = x2; 468 } 469 else 470 { 471 DestRect.left = x2; 472 DestRect.right = x1 + 1; 473 } 474 if (y1 < y2) 475 { 476 DestRect.top = y1; 477 DestRect.bottom = y2; 478 } 479 else 480 { 481 DestRect.top = y2; 482 DestRect.bottom = y1 + 1; 483 } 484 485 if (! IntEngEnter(&EnterLeave, DestObj, &DestRect, FALSE, &Translate, &OutputObj)) 486 { 487 return FALSE; 488 } 489 490 if (!Clip) 491 { 492 Clip = pcoPriv = EngCreateClip(); 493 if (!Clip) 494 { 495 return FALSE; 496 } 497 IntEngUpdateClipRegion((XCLIPOBJ*)Clip, 0, 0, RectBounds); 498 } 499 500 x1 += Translate.x; 501 x2 += Translate.x; 502 y1 += Translate.y; 503 y2 += Translate.y; 504 505 x = x1; 506 y = y1; 507 deltax = x2 - x1; 508 deltay = y2 - y1; 509 510 if (0 == deltax && 0 == deltay) 511 { 512 return TRUE; 513 } 514 515 if (deltax < 0) 516 { 517 xchange = -1; 518 deltax = - deltax; 519 hx = x2 + 1; 520 } 521 else 522 { 523 xchange = 1; 524 hx = x1; 525 } 526 527 if (deltay < 0) 528 { 529 ychange = -1; 530 deltay = - deltay; 531 vy = y2 + 1; 532 } 533 else 534 { 535 ychange = 1; 536 vy = y1; 537 } 538 539 if ((y1 == y2) && (cStyles == 0)) 540 { 541 CLIPOBJ_cEnumStart(Clip, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, 0); 542 do 543 { 544 EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum); 545 for (i = 0; i < RectEnum.c && RectEnum.arcl[i].top + Translate.y <= y1; i++) 546 { 547 if (y1 < RectEnum.arcl[i].bottom + Translate.y && 548 RectEnum.arcl[i].left + Translate.x <= hx + deltax && 549 hx < RectEnum.arcl[i].right + Translate.x && 550 max(hx, RectEnum.arcl[i].left + Translate.x) < 551 min(hx + deltax, RectEnum.arcl[i].right + Translate.x)) 552 { 553 DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_HLine( 554 OutputObj, 555 max(hx, RectEnum.arcl[i].left + Translate.x), 556 min(hx + deltax, RectEnum.arcl[i].right + Translate.x), 557 y1, Pixel); 558 } 559 } 560 } 561 while (EnumMore); 562 } 563 else if ((x1 == x2) && (cStyles == 0)) 564 { 565 CLIPOBJ_cEnumStart(Clip, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, 0); 566 do 567 { 568 EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum); 569 for (i = 0; i < RectEnum.c; i++) 570 { 571 if (RectEnum.arcl[i].left + Translate.x <= x1 && 572 x1 < RectEnum.arcl[i].right + Translate.x && 573 RectEnum.arcl[i].top + Translate.y <= vy + deltay && 574 vy < RectEnum.arcl[i].bottom + Translate.y) 575 { 576 DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_VLine( 577 OutputObj, x1, 578 max(vy, RectEnum.arcl[i].top + Translate.y), 579 min(vy + deltay, RectEnum.arcl[i].bottom + Translate.y), 580 Pixel); 581 } 582 } 583 } 584 while (EnumMore); 585 } 586 else 587 { 588 if (0 < xchange) 589 { 590 if (0 < ychange) 591 { 592 NWtoSE(OutputObj, Clip, pbo, x, y, deltax, deltay, &Translate); 593 } 594 else 595 { 596 SWtoNE(OutputObj, Clip, pbo, x, y, deltax, deltay, &Translate); 597 } 598 } 599 else 600 { 601 if (0 < ychange) 602 { 603 NEtoSW(OutputObj, Clip, pbo, x, y, deltax, deltay, &Translate); 604 } 605 else 606 { 607 SEtoNW(OutputObj, Clip, pbo, x, y, deltax, deltay, &Translate); 608 } 609 } 610 } 611 612 if (pcoPriv) 613 { 614 EngDeleteClip(pcoPriv); 615 } 616 617 return IntEngLeave(&EnterLeave); 618 } 619 620 BOOL APIENTRY 621 IntEngLineTo(SURFOBJ *psoDest, 622 CLIPOBJ *ClipObj, 623 BRUSHOBJ *pbo, 624 LONG x1, 625 LONG y1, 626 LONG x2, 627 LONG y2, 628 RECTL *RectBounds, 629 MIX Mix) 630 { 631 BOOLEAN ret; 632 SURFACE *psurfDest; 633 PEBRUSHOBJ GdiBrush; 634 RECTL b; 635 636 ASSERT(psoDest); 637 psurfDest = CONTAINING_RECORD(psoDest, SURFACE, SurfObj); 638 ASSERT(psurfDest); 639 640 GdiBrush = CONTAINING_RECORD( 641 pbo, 642 EBRUSHOBJ, 643 BrushObject); 644 ASSERT(GdiBrush); 645 ASSERT(GdiBrush->pbrush); 646 647 if (GdiBrush->pbrush->flAttrs & BR_IS_NULL) 648 return TRUE; 649 650 /* No success yet */ 651 ret = FALSE; 652 653 /* Clip lines totally outside the clip region. This is not done as an 654 * optimization (there are very few lines drawn outside the region) but 655 * as a workaround for what seems to be a problem in the CL54XX driver */ 656 if (NULL == ClipObj || DC_TRIVIAL == ClipObj->iDComplexity) 657 { 658 b.left = 0; 659 b.right = psoDest->sizlBitmap.cx; 660 b.top = 0; 661 b.bottom = psoDest->sizlBitmap.cy; 662 } 663 else 664 { 665 b = ClipObj->rclBounds; 666 } 667 if ((x1 < b.left && x2 < b.left) || (b.right <= x1 && b.right <= x2) || 668 (y1 < b.top && y2 < b.top) || (b.bottom <= y1 && b.bottom <= y2)) 669 { 670 return TRUE; 671 } 672 673 b.left = min(x1, x2); 674 b.right = max(x1, x2); 675 b.top = min(y1, y2); 676 b.bottom = max(y1, y2); 677 if (b.left == b.right) b.right++; 678 if (b.top == b.bottom) b.bottom++; 679 680 if (psurfDest->flags & HOOK_LINETO) 681 { 682 /* Call the driver's DrvLineTo */ 683 ret = GDIDEVFUNCS(psoDest).LineTo( 684 psoDest, ClipObj, pbo, x1, y1, x2, y2, &b, Mix); 685 } 686 687 #if 0 688 if (! ret && (psurfDest->flags & HOOK_STROKEPATH)) 689 { 690 /* FIXME: Emulate LineTo using drivers DrvStrokePath and set ret on success */ 691 } 692 #endif 693 694 if (! ret) 695 { 696 ret = EngLineTo(psoDest, ClipObj, pbo, x1, y1, x2, y2, RectBounds, Mix); 697 } 698 699 return ret; 700 } 701 702 BOOL APIENTRY 703 IntEngPolyline(SURFOBJ *psoDest, 704 CLIPOBJ *Clip, 705 BRUSHOBJ *pbo, 706 CONST LPPOINT pt, 707 LONG dCount, 708 MIX Mix) 709 { 710 LONG i; 711 RECTL rect; 712 BOOL ret = FALSE; 713 714 // Draw the Polyline with a call to IntEngLineTo for each segment. 715 for (i = 1; i < dCount; i++) 716 { 717 rect.left = min(pt[i-1].x, pt[i].x); 718 rect.top = min(pt[i-1].y, pt[i].y); 719 rect.right = max(pt[i-1].x, pt[i].x); 720 rect.bottom = max(pt[i-1].y, pt[i].y); 721 ret = IntEngLineTo(psoDest, 722 Clip, 723 pbo, 724 pt[i-1].x, 725 pt[i-1].y, 726 pt[i].x, 727 pt[i].y, 728 &rect, 729 Mix); 730 if (!ret) 731 { 732 break; 733 } 734 } 735 736 return ret; 737 } 738 739 /* EOF */ 740