1// mk4too.cpp -- Tcl object command interface to Metakit 2// $Id: mk4too.cpp 4452 2008-12-10 22:57:54Z patthoyts $ 3// This is part of Metakit, see http://www.equi4.com/metakit.html 4// Copyright (C) 2000-2004 by Matt Newman and Jean-Claude Wippler. 5 6#include "mk4tcl.h" 7#include <stdio.h> 8#include <string.h> 9 10#if 10 * TCL_MAJOR_VERSION + TCL_MINOR_VERSION < 86 11#define Tcl_GetErrorLine(interp) (interp)->errorLine 12#endif 13 14/////////////////////////////////////////////////////////////////////////////// 15// Defined in this file: 16 17class MkView; 18 19/////////////////////////////////////////////////////////////////////////////// 20// The MkView class adds Metakit-specific utilities and all the command procs. 21 22int MkView::Dispatcher(ClientData cd, Tcl_Interp *ip, int oc, Tcl_Obj *const * 23 ov) { 24 MkView *self = (MkView*)cd; 25 26 if (self == 0 || self->interp != ip) { 27 Tcl_SetResult(ip, "Initialization error in dispatcher", TCL_STATIC); 28 return TCL_ERROR; 29 } 30 return self->Execute(oc, ov); 31} 32 33void MkView::DeleteProc(ClientData cd) { 34 MkView *self = (MkView*)cd; 35 delete self; 36} 37 38MkView::MkView(Tcl_Interp *ip_, c4_View view_, const char *name): Tcl(ip_), 39 work(*(MkWorkspace*)Tcl_GetAssocData(interp, "mk4tcl", 0)), view(view_) { 40 Register(name); 41} 42 43MkView::MkView(Tcl_Interp *ip_, const char *name): Tcl(ip_), work(* 44 (MkWorkspace*)Tcl_GetAssocData(interp, "mk4tcl", 0)) { 45 Register(name); 46} 47 48MkView::~MkView(){} 49 50void MkView::Register(const char *name) { 51 static int uid = 0; 52 char buf[32]; 53 54 if (name == 0 || *name == 0) { 55 sprintf(buf, "%d", uid++); 56 cmd = "view" + (c4_String)buf; 57 } else { 58 cmd = name; 59 } 60 // save token... so I can delete cmd later (even if renamed) 61 cmdToken = Tcl_CreateObjCommand(interp, (char*)(const char*)cmd, MkView 62 ::Dispatcher, this, MkView::DeleteProc); 63} 64 65c4_View MkView::View(Tcl_Interp *interp, Tcl_Obj *obj) { 66 const char *name = Tcl_GetStringFromObj(obj, 0); 67 Tcl_CmdInfo ci; 68 69 if (!Tcl_GetCommandInfo(interp, (char*)name, &ci) || ci.objProc != MkView 70 ::Dispatcher) { 71 //Fail("no such view"); 72 c4_View temp; 73 return temp; 74 } else { 75 MkView *v = (MkView*)ci.objClientData; 76 return v->view; 77 } 78} 79 80int MkView::asIndex(c4_View &view, Tcl_Obj *obj_, bool mayExceed_) { 81 int size = view.GetSize(); 82 int index; 83 84 if (Tcl_GetIntFromObj(interp, obj_, &index) != TCL_OK) { 85 const char *step = Tcl_GetStringFromObj(obj_, 0); 86 if (step != 0 && strcmp(step, "end") == 0) { 87 index = !mayExceed_ ? size - 1: size; 88 Tcl_ResetResult(interp); // clear error 89 _error = TCL_OK; 90 } else { 91 index = - 1; 92 } 93 } 94 95 if (mayExceed_) { 96 if (index > size) 97 Fail("view index is too large"); 98 else if (index < 0) 99 Fail("view index is negative"); 100 } else if (index < 0 || index >= size) 101 Fail("view index is out of range"); 102 103 return index; 104} 105 106int MkView::SetValues(const c4_RowRef &row_, int objc, Tcl_Obj *const * objv, 107 c4_View &view_) { 108 if (objc % 2) 109 Fail("bad args: must be prop value pairs"); 110 111 while (objc > 0 && !_error) { 112 _error = SetAsObj(interp, row_, AsProperty(objv[0], view_), objv[1]); 113 114 objc -= 2; 115 objv += 2; 116 } 117 118 return _error; 119} 120 121int MkView::Execute(int oc, Tcl_Obj *const * ov) { 122 struct CmdDef { 123 int(MkView:: *proc)(); 124 int min; 125 int max; 126 const char *desc; 127 }; 128 129 static const char *subCmds[] = { 130 "close", "delete", "exists", "find", "get", "properties", "insert", "open", 131 "search", "select", "set", "size", "loop", "view", "info", 132 // will be deprecated (use "properties" instead) 133 0 134 }; 135 static CmdDef defTab[] = { 136 // the "&MkView::" stuff is required for Mac cwpro2 137 { 138 &MkView::CloseCmd, 2, 2, "close" 139 } 140 , { 141 &MkView::DeleteCmd, 3, 4, "delete cursor ?cursor2?" 142 } 143 , { 144 &MkView::ExistsCmd, 3, 0, "exists cursor ?prop ...?" 145 } 146 , { 147 &MkView::FindCmd, 2, 0, "find ?prop value ...?" 148 } 149 , { 150 &MkView::GetCmd, 3, 0, "get cursor ?prop ...?" 151 } 152 , { 153 &MkView::InfoCmd, 2, 2, "properties" 154 } 155 , { 156 &MkView::InsertCmd, 3, 0, "insert cursor ?prop ...?" 157 } 158 , { 159 &MkView::OpenCmd, 4, 4, "open cursor prop" 160 } 161 , { 162 &MkView::SearchCmd, 4, 4, "search prop value" 163 } 164 , { 165 &MkView::SelectCmd, 2, 0, "select ?..?" 166 } 167 , { 168 &MkView::SetCmd, 3, 0, "set cursor prop ?value prop value ...?" 169 } 170 , { 171 &MkView::SizeCmd, 2, 3, "size ?newsize?" 172 } 173 , { 174 &MkView::LoopCmd, 3, 0, "loop cursor ?first? ?limit? ?step? body" 175 } 176 , { 177 &MkView::ViewCmd, 3, 0, "view option ?args?" 178 } 179 , { 180 &MkView::InfoCmd, 2, 2, "info" 181 } 182 , { 183 0, 0, 0, 0 184 } 185 , 186 }; 187 _error = TCL_OK; 188 189 int id = tcl_GetIndexFromObj(ov[1], subCmds); 190 191 if (id == - 1) 192 return TCL_ERROR; 193 194 CmdDef &cd = defTab[id]; 195 196 objc = oc; 197 objv = ov; 198 199 if (oc < cd.min || (cd.max > 0 && oc > cd.max)) { 200 msg = "wrong # args: should be \"$obj "; 201 msg += cd.desc; 202 msg += "\""; 203 204 return Fail(msg); 205 } 206 207 return (this->*cd.proc)(); 208} 209 210// 211// Tcl command methods 212// 213 214int MkView::CloseCmd() { 215 // remove command instance... this will call delete... 216 Tcl_DeleteCommandFromToken(interp, cmdToken); 217 return TCL_OK; 218} 219 220int MkView::DeleteCmd() { 221 int count = 1; 222 int index = asIndex(view, objv[2], true); 223 224 if (_error) 225 return _error; 226 227 if (objc > 3) { 228 int index2 = asIndex(view, objv[3], true); 229 230 if (_error) 231 return _error; 232 233 count = index2 - index + 1; 234 } 235 236 if (count > view.GetSize() - index) 237 count = view.GetSize() - index; 238 239 if (count >= 1) { 240 view.RemoveAt(index, count); 241 } 242 return TCL_OK; 243} 244 245int MkView::ExistsCmd() { 246 asIndex(view, objv[2], false); 247 int r = _error ? 0 : 1; 248 _error = 0; 249 return tcl_SetObjResult(Tcl_NewIntObj(r)); 250} 251 252int MkView::FindCmd() { 253 c4_Row row; 254 int idx = 2; 255 256 while (idx < objc && !_error) { 257 _error = SetAsObj(interp, row, AsProperty(objv[idx], view), objv[idx + 1]); 258 idx += 2; 259 } 260 if (_error) 261 return _error; 262 263 idx = view.Find(row, 0); 264 if (idx == - 1) { 265 Fail("not found"); 266 return TCL_ERROR; 267 } 268 return tcl_SetObjResult(Tcl_NewIntObj(idx)); 269} 270 271int MkView::GetCmd() { 272 int index = asIndex(view, objv[2], false); 273 if (_error) 274 return _error; 275 276 Tcl_Obj *result = tcl_GetObjResult(); 277 c4_RowRef row = view[index]; 278 279 if (objc < 4) { 280 for (int i = 0; i < view.NumProperties() && !_error; ++i) { 281 const c4_Property &prop = view.NthProperty(i); 282 c4_String name = prop.Name(); 283 284 if (prop.Type() == 'V') 285 continue; 286 // omit subviews 287 288 tcl_ListObjAppendElement(result, tcl_NewStringObj(name)); 289 tcl_ListObjAppendElement(result, GetValue(row, prop)); 290 } 291 } else if (objc == 4) { 292 GetValue(row, AsProperty(objv[3], view), result); 293 } else { 294 for (int i = 3; i < objc && !_error; ++i) { 295 const c4_Property &prop = AsProperty(objv[i], view); 296 tcl_ListObjAppendElement(result, GetValue(row, prop)); 297 } 298 } 299 return _error; 300} 301 302int MkView::InfoCmd() { 303 Tcl_Obj *result = tcl_GetObjResult(); 304 305 for (int i = 0; i < view.NumProperties() && !_error; ++i) { 306 const c4_Property &prop = view.NthProperty(i); 307 308 c4_String s = prop.Name(); 309 if (prop.Type() != 'S') { 310 s += ":"; 311 s += prop.Type(); 312 } 313 314 tcl_ListObjAppendElement(result, tcl_NewStringObj(s)); 315 } 316 return tcl_SetObjResult(result); 317} 318 319int MkView::InsertCmd() { 320 int index = asIndex(view, objv[2], true); 321 if (_error) 322 return _error; 323 324 c4_Row temp; 325 SetValues(temp, objc - 3, objv + 3, view); 326 view.InsertAt(index, temp, 1); 327 //SetValues(view[index], objc - 3, objv + 3); 328 329 if (_error) { 330 view.RemoveAt(index, 1); // remove new row on errors 331 return _error; 332 } 333 return tcl_SetObjResult(Tcl_NewIntObj(index)); 334} 335 336int MkView::OpenCmd() { 337 int index = asIndex(view, objv[2], false); 338 339 if (_error) 340 return _error; 341 342 const c4_Property &prop = AsProperty(objv[3], view); 343 if (_error) 344 return _error; 345 346 if (prop.Type() != 'V') { 347 Fail("bad property: must be a view"); 348 return TCL_ERROR; 349 } 350 MkView *ncmd = new MkView(interp, ((const c4_ViewProp &)prop)(view[index])); 351 352 return tcl_SetObjResult(tcl_NewStringObj(ncmd->CmdName())); 353} 354 355int MkView::SearchCmd() { 356 Tcl_Obj *obj_ = objv[3]; 357 const c4_Property &prop = AsProperty(objv[2], view); 358 char type = prop.Type(); 359 double dblVal = 0, dtmp; 360 long longVal = 0; 361#ifdef TCL_WIDE_INT_TYPE 362 Tcl_WideInt wideVal = 0, wtmp; 363#endif 364 c4_String strVal; 365 366 int size = view.GetSize(); 367 int first = 0, last = size; 368 int row, rc, e; 369 370 switch (type) { 371 case 'S': 372 { 373 strVal = Tcl_GetStringFromObj(obj_, 0); 374 } 375 break; 376 377 case 'F': 378 case 'D': 379 { 380 e = Tcl_GetDoubleFromObj(interp, obj_, &dblVal); 381 if (e != TCL_OK) 382 return e; 383 } 384 break; 385 386#ifdef TCL_WIDE_INT_TYPE 387 case 'L': 388 { 389 e = Tcl_GetWideIntFromObj(interp, obj_, &wideVal); 390 if (e != TCL_OK) 391 return e; 392 } 393 break; 394#endif 395 396 case 'I': 397 { 398 e = Tcl_GetLongFromObj(interp, obj_, &longVal); 399 if (e != TCL_OK) 400 return e; 401 } 402 break; 403 404 default: 405 Tcl_SetResult(interp, "unsupported property type", TCL_STATIC); 406 return TCL_ERROR; 407 } 408 409 while (first <= last) { 410 row = (first + last) / 2; 411 412 if (row >= size) 413 break; 414 415 switch (type) { 416 case 'S': 417 rc = strVal.CompareNoCase(((c4_StringProp &)prop)(view[row])); 418 break; 419 case 'F': 420 dtmp = dblVal - ((c4_FloatProp &)prop)(view[row]); 421 rc = (dtmp < 0 ? - 1: (dtmp > 0)); 422 break; 423 case 'D': 424 dtmp = dblVal - ((c4_DoubleProp &)prop)(view[row]); 425 rc = (dtmp < 0 ? - 1: (dtmp > 0)); 426 break; 427#ifdef TCL_WIDE_INT_TYPE 428 case 'L': 429 wtmp = wideVal - ((c4_LongProp &)prop)(view[row]); 430 rc = (wtmp < 0 ? - 1: (wtmp > 0)); 431 break; 432#endif 433 case 'I': 434 rc = longVal - ((c4_IntProp &)prop)(view[row]); 435 break; 436 default: 437 rc = 0; // 27-09-2001, to satisfy MSVC6 warn level 4 438 } 439 440 if (rc == 0) { 441 goto done; 442 } else if (rc > 0) { 443 first = row + 1; 444 } else { 445 last = row - 1; 446 } 447 } 448 // Not found 449 row = - 1; 450 done: return tcl_SetObjResult(Tcl_NewIntObj(row)); 451} 452 453int MkView::SelectCmd() { 454 TclSelector sel(interp, view); 455 456 static const char *opts[] = { 457 "-min", // 0 458 "-max", // 1 459 "-exact", // 2 460 "-glob", // 3 461 "-regexp", // 4 462 "-keyword", // 5 463 "-first", // 6 464 "-count", // 7 465 "-sort", // 8 466 "-rsort", // 9 467 "-globnc", // 10 468 0 469 }; 470 471 while (objc >= 4) { 472 objc -= 2; // gobble next two arguments 473 objv += 2; 474 475 // at this point, *objv is the next option, and objc >= 2 476 477 int id = - 1; 478 479 const char *p = Tcl_GetStringFromObj(*objv, 0); 480 if (p && *p == '-') { 481 id = tcl_GetIndexFromObj(*objv, opts); 482 if (id < 0) 483 return _error; 484 } 485 486 switch (id) { 487 case - 1: { // prop value : case-insensitive match 488 _error = sel.AddCondition( - 1, objv[0], objv[1]); 489 } 490 break; 491 492 case 0: 493 // -min prop value : property must be greater or equal to value 494 case 1: 495 // -max prop value : property must be less or equal to value 496 case 2: 497 // -exact prop value : exact case-sensitive match 498 case 3: 499 // -glob prop pattern : match "glob" expression wildcard 500 case 4: 501 // -regexp prop pattern : match specified regular expression 502 case 5: 503 // -keyword prop prefix : match keyword in given property 504 case 10: 505 { // -globnc prop pattern : match "glob", but ignore case 506 if (objc < 3) 507 return Fail("not enough arguments"); 508 509 _error = sel.AddCondition(id, objv[1], objv[2]); 510 511 --objc; // gobble a third argument 512 ++objv; 513 } 514 break; 515 516 case 6: 517 // -first pos : searching starts at specified row index 518 case 7: 519 { // -count num : return no more than this many results 520 int n = tcl_GetIntFromObj(objv[1]); 521 if (_error) 522 return _error; 523 524 if (id == 6) 525 sel._first = n; 526 else 527 sel._count = n; 528 } 529 break; 530 531 case 8: 532 // -sort prop : sort on one or more properties, ascending 533 case 9: 534 { // -rsort prop : sort on one or more properties, descending 535 c4_View props = sel.GetAsProps(objv[1]); 536 for (int i = 0; i < props.NumProperties(); ++i) { 537 const c4_Property &prop = props.NthProperty(i); 538 539 sel._sortProps.AddProperty(prop); 540 if (id == 9) 541 sel._sortRevProps.AddProperty(prop); 542 } 543 } 544 break; 545 } 546 } 547 548 if (_error) 549 return _error; 550 551 c4_View nview; 552 sel.DoSelect(0, &nview); 553 MkView *ncmd = new MkView(interp, nview); 554 return tcl_SetObjResult(tcl_NewStringObj(ncmd->CmdName())); 555} 556 557int MkView::SetCmd() { 558 if (objc < 4) 559 return GetCmd(); 560 561 int index = asIndex(view, objv[2], false); 562 if (_error) 563 return _error; 564 565 return SetValues(view[index], objc - 3, objv + 3, view); 566} 567 568int MkView::SizeCmd() { 569 if (objc > 2) { 570 int i = tcl_GetIntFromObj(objv[2]); 571 if (_error) 572 return _error; 573 view.SetSize(i); 574 } 575 576 return tcl_SetObjResult(Tcl_NewIntObj(view.GetSize())); 577} 578 579int MkView::LoopCmd() { 580 long first = 0; 581 long limit = view.GetSize(); 582 long incr = 1; 583 584 if (objc >= 5) 585 first = tcl_ExprLongObj(objv[3]); 586 587 if (objc >= 6) 588 limit = tcl_ExprLongObj(objv[4]); 589 590 if (objc >= 7) { 591 incr = tcl_ExprLongObj(objv[5]); 592 if (incr == 0) 593 Fail("increment has to be nonzero"); 594 } 595 596 if (_error) 597 return _error; 598 599 Tcl_Obj *vname = objv[2]; 600 Tcl_Obj *cmd = objv[objc - 1]; 601 602 for (int i = first; i < limit && incr > 0 || i > limit && incr < 0; i += incr) 603 { 604 Tcl_Obj *var = Tcl_ObjSetVar2(interp, vname, 0, Tcl_NewIntObj(i), 605 TCL_LEAVE_ERR_MSG); 606 if (var == 0) 607 return Fail(); 608 609 _error = Mk_EvalObj(interp, cmd); 610 611 if (_error) { 612 if (_error == TCL_CONTINUE) 613 _error = TCL_OK; 614 else { 615 if (_error == TCL_BREAK) 616 _error = TCL_OK; 617 else if (_error == TCL_ERROR) { 618 char msg[100]; 619 sprintf(msg, "\n (\"mk::loop\" body line %d)", Tcl_GetErrorLine(interp)); 620 Tcl_AddObjErrorInfo(interp, msg, - 1); 621 } 622 break; 623 } 624 } 625 } 626 627 if (_error == TCL_OK) 628 Tcl_ResetResult(interp); 629 630 return _error; 631} 632 633int MkView::ViewCmd() { 634 struct CmdDef { 635 int(MkView:: *proc)(); 636 int min; 637 int max; 638 const char *desc; 639 }; 640 641 static const char *subCmds[] = { 642 "blocked", "clone", "concat", "copy", "different", "dup", "flatten", 643 "groupby", "hash", "indexed", "intersect", "join", "map", "minus", 644 "ordered", "pair", "product", "project", "range", "readonly", "rename", 645 "restrict", "union", "unique", 646#if 0 647 "==", "!=", "<", ">", "<=", ">=", 648#endif 649 0 650 }; 651 static CmdDef defTab[] = { 652 // the "&MkView::" stuff is required for Mac cwpro2 653 { 654 &MkView::BlockedCmd, 2, 2, "blocked" 655 } 656 , { 657 &MkView::CloneCmd, 2, 2, "clone" 658 } 659 , { 660 &MkView::ConcatCmd, 3, 3, "concat view" 661 } 662 , { 663 &MkView::CopyCmd, 2, 3, "copy" 664 } 665 , { 666 &MkView::DifferentCmd, 3, 3, "different view" 667 } 668 , { 669 &MkView::DupCmd, 2, 2, "dup" 670 } 671 , { 672 &MkView::FlattenCmd, 3, 3, "flatten prop" 673 } 674 , { 675 &MkView::GroupByCmd, 4, 0, "groupby subview prop ?prop ...?" 676 } 677 , { 678 &MkView::HashCmd, 3, 4, "hash map ?numkeys?" 679 } 680 , { 681 &MkView::IndexedCmd, 5, 0, "indexed map unique prop ?prop ...?" 682 } 683 , { 684 &MkView::IntersectCmd, 3, 3, "intersect view" 685 } 686 , { 687 &MkView::JoinCmd, 4, 0, "join view prop ?prop ...?" 688 } 689 , { 690 &MkView::MapCmd, 3, 3, "map view" 691 } 692 , { 693 &MkView::MinusCmd, 3, 3, "minus view" 694 } 695 , { 696 &MkView::OrderedCmd, 2, 3, "ordered ?numkeys?" 697 } 698 , { 699 &MkView::PairCmd, 3, 3, "pair view" 700 } 701 , { 702 &MkView::ProductCmd, 3, 3, "product view" 703 } 704 , { 705 &MkView::ProjectCmd, 3, 0, "project prop ?prop ...?" 706 } 707 , { 708 &MkView::RangeCmd, 4, 0, "range start finish ?step?" 709 } 710 , { 711 &MkView::ReadOnlyCmd, 2, 2, "readonly" 712 } 713 , { 714 &MkView::RenameCmd, 4, 4, "rename oprop nprop" 715 } 716 , { 717 &MkView::RestrictCmd, 2, 0, "restrict...." 718 } 719 , { 720 &MkView::UnionCmd, 3, 3, "union view" 721 } 722 , { 723 &MkView::UniqueCmd, 2, 2, "unique" 724 } 725 , 726#if 0 727 { 728 &MkView::OperatorCmd, 3, 3, "== view" 729 } 730 , { 731 &MkView::OperatorCmd, 3, 3, "!= view" 732 } 733 , { 734 &MkView::OperatorCmd, 3, 3, "< view" 735 } 736 , { 737 &MkView::OperatorCmd, 3, 3, "> view" 738 } 739 , { 740 &MkView::OperatorCmd, 3, 3, "<= view" 741 } 742 , { 743 &MkView::OperatorCmd, 3, 3, ">= view" 744 } 745 , 746#endif 747 { 748 0, 0, 0, 0 749 } 750 , 751 }; 752 _error = TCL_OK; 753 754 objc--; 755 objv++; 756 757 int id = tcl_GetIndexFromObj(objv[1], subCmds); 758 759 if (id == - 1) 760 return TCL_ERROR; 761 762 CmdDef &cd = defTab[id]; 763 764 if (objc < cd.min || (cd.max > 0 && objc > cd.max)) { 765 msg = "wrong # args: should be \"$obj view "; 766 msg += cd.desc; 767 msg += "\""; 768 769 return Fail(msg); 770 } 771 772 return (this->*cd.proc)(); 773} 774 775// 776// View-based methods (typically return a new view) 777// 778int MkView::BlockedCmd() { 779 MkView *ncmd = new MkView(interp, view.Blocked()); 780 781 return tcl_SetObjResult(tcl_NewStringObj(ncmd->CmdName())); 782} 783 784int MkView::DupCmd() { 785 MkView *cmd = new MkView(interp, view); 786 787 return tcl_SetObjResult(tcl_NewStringObj(cmd->CmdName())); 788} 789 790int MkView::CloneCmd() { 791 MkView *cmd = new MkView(interp, view.Clone()); 792 793 return tcl_SetObjResult(tcl_NewStringObj(cmd->CmdName())); 794} 795 796int MkView::ConcatCmd() { 797 c4_View nview = View(interp, objv[2]); 798 MkView *ncmd = new MkView(interp, view.Concat(nview)); 799 800 return tcl_SetObjResult(tcl_NewStringObj(ncmd->CmdName())); 801} 802 803int MkView::DifferentCmd() { 804 c4_View nview = View(interp, objv[2]); 805 MkView *ncmd = new MkView(interp, view.Different(nview)); 806 807 return tcl_SetObjResult(tcl_NewStringObj(ncmd->CmdName())); 808} 809 810int MkView::CopyCmd() { 811 MkView *cmd = new MkView(interp, view.Duplicate()); 812 813 return tcl_SetObjResult(tcl_NewStringObj(cmd->CmdName())); 814} 815 816int MkView::FlattenCmd() { 817 c4_View nview; 818 819 const c4_Property &prop = AsProperty(objv[2], view); 820 if (_error) 821 return _error; 822 823 if (prop.Type() != 'V') { 824 Fail("bad property: must be a view"); 825 return TCL_ERROR; 826 } 827 MkView *ncmd = new MkView(interp, view.JoinProp((const c4_ViewProp &)prop)); 828 829 return tcl_SetObjResult(tcl_NewStringObj(ncmd->CmdName())); 830} 831 832int MkView::GroupByCmd() { 833 const c4_Property &prop = AsProperty(objv[2], view); 834 if (_error) 835 return _error; 836 837 if (prop.Type() != 'V') { 838 Fail("bad property: must be a view"); 839 return TCL_ERROR; 840 } 841 c4_View nview; 842 843 for (int i = 3; i < objc && !_error; ++i) { 844 const c4_Property &prop = AsProperty(objv[i], view); 845 nview.AddProperty(prop); 846 } 847 if (_error) 848 return _error; 849 850 MkView *ncmd = new MkView(interp, view.GroupBy(nview, (const c4_ViewProp &) 851 prop)); 852 853 return tcl_SetObjResult(tcl_NewStringObj(ncmd->CmdName())); 854} 855 856int MkView::HashCmd() { 857 c4_View nview = View(interp, objv[2]); 858 int nkeys = objc > 3 ? tcl_GetIntFromObj(objv[3]): 1; 859 MkView *ncmd = new MkView(interp, view.Hash(nview, nkeys)); 860 861 return tcl_SetObjResult(tcl_NewStringObj(ncmd->CmdName())); 862} 863 864int MkView::IndexedCmd() { 865 c4_View map = View(interp, objv[2]); 866 bool unique = tcl_GetIntFromObj(objv[3]) != 0; 867 868 c4_View props; 869 for (int i = 4; i < objc && !_error; ++i) { 870 const c4_Property &prop = AsProperty(objv[i], view); 871 props.AddProperty(prop); 872 } 873 if (_error) 874 return _error; 875 876 MkView *ncmd = new MkView(interp, view.Indexed(map, props, unique)); 877 878 return tcl_SetObjResult(tcl_NewStringObj(ncmd->CmdName())); 879} 880 881int MkView::IntersectCmd() { 882 c4_View nview = View(interp, objv[2]); 883 MkView *ncmd = new MkView(interp, view.Intersect(nview)); 884 885 return tcl_SetObjResult(tcl_NewStringObj(ncmd->CmdName())); 886} 887 888int MkView::JoinCmd() { 889 c4_View nview = View(interp, objv[2]); 890 c4_View props; 891 892 for (int i = 3; i < objc && !_error; ++i) { 893 const c4_Property &prop = AsProperty(objv[i], view); 894 props.AddProperty(prop); 895 } 896 if (_error) 897 return _error; 898 899 MkView *ncmd = new MkView(interp, view.Join(props, nview)); 900 901 return tcl_SetObjResult(tcl_NewStringObj(ncmd->CmdName())); 902} 903 904int MkView::MapCmd() { 905 c4_View nview = View(interp, objv[2]); 906 MkView *ncmd = new MkView(interp, view.RemapWith(nview)); 907 908 return tcl_SetObjResult(tcl_NewStringObj(ncmd->CmdName())); 909} 910 911int MkView::MinusCmd() { 912 c4_View nview = View(interp, objv[2]); 913 MkView *ncmd = new MkView(interp, view.Minus(nview)); 914 915 return tcl_SetObjResult(tcl_NewStringObj(ncmd->CmdName())); 916} 917 918#if 0 919int MkView::OperatorCmd() { 920 c4_String op = (const char*)Tcl_GetStringFromObj(objv[1], 0); 921 c4_View nview = View(interp, objv[2]); 922 bool rc; 923 924 if (op == "==") 925 rc = (view == nview); 926 else if (op == "!=") 927 rc = (view != nview); 928 else if (op == "<") 929 rc = (view < nview); 930 else if (op == ">") 931 rc = (view > nview); 932 else if (op == ">=") 933 rc = (view >= nview); 934 else if (op == "<=") 935 rc = (view <= nview); 936 else 937 return Fail("bad operator: must be one of ==, !=, <, >, <=, >="); 938 939 return tcl_SetObjResult(Tcl_NewBooleanObj(rc ? 1 : 0)); 940} 941 942#endif 943 944int MkView::OrderedCmd() { 945 int nkeys = objc > 2 ? tcl_GetIntFromObj(objv[2]): 1; 946 MkView *ncmd = new MkView(interp, view.Ordered(nkeys)); 947 948 return tcl_SetObjResult(tcl_NewStringObj(ncmd->CmdName())); 949} 950 951int MkView::PairCmd() { 952 c4_View nview = View(interp, objv[2]); 953 954 MkView *ncmd = new MkView(interp, view.Pair(nview)); 955 956 return tcl_SetObjResult(tcl_NewStringObj(ncmd->CmdName())); 957} 958 959int MkView::ProductCmd() { 960 c4_View nview = View(interp, objv[2]); 961 MkView *ncmd = new MkView(interp, view.Product(nview)); 962 963 return tcl_SetObjResult(tcl_NewStringObj(ncmd->CmdName())); 964} 965 966int MkView::ProjectCmd() { 967 c4_View nview; 968 969 for (int i = 2; i < objc; i++) { 970 const c4_Property &prop = AsProperty(objv[i], view); 971 972 nview.AddProperty(prop); 973 } 974 MkView *ncmd = new MkView(interp, view.Project(nview)); 975 976 return tcl_SetObjResult(tcl_NewStringObj(ncmd->CmdName())); 977} 978 979int MkView::RangeCmd() { 980 int start = asIndex(view, objv[2], false); 981 if (_error) 982 return _error; 983 984 int finish = objc > 3 ? asIndex(view, objv[3], false) + 1: start + 1; 985 if (_error) 986 return _error; 987 988 int step = objc > 4 ? tcl_GetIntFromObj(objv[4]): 1; 989 if (_error) 990 return _error; 991 992 MkView *ncmd = new MkView(interp, view.Slice(start, finish, step)); 993 994 return tcl_SetObjResult(tcl_NewStringObj(ncmd->CmdName())); 995} 996 997int MkView::ReadOnlyCmd() { 998 MkView *ncmd = new MkView(interp, view.ReadOnly()); 999 1000 return tcl_SetObjResult(tcl_NewStringObj(ncmd->CmdName())); 1001} 1002 1003int MkView::RenameCmd() { 1004 const c4_Property &oprop = AsProperty(objv[2], view); 1005 if (_error) 1006 return _error; 1007 1008 const c4_Property &nprop = AsProperty(objv[3], view); 1009 if (_error) 1010 return _error; 1011 1012 MkView *ncmd = new MkView(interp, view.Rename(oprop, nprop)); 1013 1014 return tcl_SetObjResult(tcl_NewStringObj(ncmd->CmdName())); 1015} 1016 1017int MkView::RestrictCmd() { 1018 int index = asIndex(view, objv[2], false); 1019 int pos = tcl_GetIntFromObj(objv[3]); 1020 int count = tcl_GetIntFromObj(objv[4]); 1021 1022 int result = view.RestrictSearch(view[index], pos, count); 1023 1024 Tcl_Obj *r = tcl_GetObjResult(); 1025 tcl_ListObjAppendElement(r, Tcl_NewIntObj(result)); 1026 tcl_ListObjAppendElement(r, Tcl_NewIntObj(pos)); 1027 tcl_ListObjAppendElement(r, Tcl_NewIntObj(count)); 1028 return _error; 1029} 1030 1031int MkView::UnionCmd() { 1032 c4_View nview = View(interp, objv[2]); 1033 MkView *ncmd = new MkView(interp, view.Union(nview)); 1034 1035 return tcl_SetObjResult(tcl_NewStringObj(ncmd->CmdName())); 1036} 1037 1038int MkView::UniqueCmd() { 1039 MkView *ncmd = new MkView(interp, view.Unique()); 1040 1041 return tcl_SetObjResult(tcl_NewStringObj(ncmd->CmdName())); 1042} 1043