1 29 30 package com.caucho.quercus.lib; 31 32 import com.caucho.quercus.QuercusModuleException; 33 import com.caucho.quercus.annotation.Optional; 34 import com.caucho.quercus.annotation.ReadOnly; 35 import com.caucho.quercus.annotation.Reference; 36 import com.caucho.quercus.annotation.UsesSymbolTable; 37 import com.caucho.quercus.env.*; 38 import com.caucho.quercus.env.ArrayValue.AbstractGet; 39 import com.caucho.quercus.env.ArrayValue.GetKey; 40 import com.caucho.quercus.env.ArrayValue.KeyComparator; 41 import com.caucho.quercus.env.ArrayValue.ValueComparator; 42 import com.caucho.quercus.module.AbstractQuercusModule; 43 import com.caucho.quercus.program.AbstractFunction; 44 import com.caucho.util.L10N; 45 import com.caucho.util.RandomUtil; 46 47 import java.text.Collator ; 48 import java.util.Comparator ; 49 import java.util.Iterator ; 50 import java.util.Locale ; 51 import java.util.Map ; 52 import java.util.logging.Level ; 53 import java.util.logging.Logger ; 54 55 58 public class ArrayModule 59 extends AbstractQuercusModule 60 { 61 private static final L10N L = new L10N(ArrayModule.class); 62 63 private static final Logger log = 64 Logger.getLogger(ArrayModule.class.getName()); 65 66 public static final int CASE_UPPER = 2; 67 public static final int CASE_LOWER = 1; 68 69 public static final int SORT_REGULAR = 0; 70 public static final int SORT_NUMERIC = 1; 71 public static final int SORT_STRING = 2; 72 public static final int SORT_LOCALE_STRING = 5; 73 public static final int SORT_NORMAL = 1; 74 public static final int SORT_REVERSE = -1; 75 76 public static final int SORT_DESC = 3; 77 public static final int SORT_ASC = 4; 78 79 public static final int EXTR_OVERWRITE = 0; 80 public static final int EXTR_SKIP = 1; 81 public static final int EXTR_PREFIX_SAME = 2; 82 public static final int EXTR_PREFIX_ALL = 3; 83 public static final int EXTR_PREFIX_INVALID = 4; 84 public static final int EXTR_IF_EXISTS = 6; 85 public static final int EXTR_PREFIX_IF_EXISTS = 5; 86 public static final int EXTR_REFS = 256; 87 88 public static final boolean CASE_SENSITIVE = true; 89 public static final boolean CASE_INSENSITIVE = false; 90 public static final boolean KEY_RESET = true; 91 public static final boolean NO_KEY_RESET = false; 92 public static final boolean STRICT = true; 93 public static final boolean NOT_STRICT = false; 94 95 private static final CompareString CS_VALUE_NORMAL 96 = new CompareString(ArrayValue.GET_VALUE, SORT_NORMAL); 97 private static final CompareString CS_VALUE_REVERSE 98 = new CompareString(ArrayValue.GET_VALUE, SORT_REVERSE); 99 private static final CompareString CS_KEY_NORMAL 100 = new CompareString(ArrayValue.GET_KEY, SORT_NORMAL); 101 private static final CompareString CS_KEY_REVERSE 102 = new CompareString(ArrayValue.GET_KEY, SORT_REVERSE); 103 104 private static final CompareNumeric CN_VALUE_NORMAL 105 = new CompareNumeric(ArrayValue.GET_VALUE, SORT_NORMAL); 106 private static final CompareNumeric CN_VALUE_REVERSE 107 = new CompareNumeric(ArrayValue.GET_VALUE, SORT_REVERSE); 108 private static final CompareNumeric CN_KEY_NORMAL 109 = new CompareNumeric(ArrayValue.GET_KEY, SORT_NORMAL); 110 private static final CompareNumeric CN_KEY_REVERSE 111 = new CompareNumeric(ArrayValue.GET_KEY, SORT_REVERSE); 112 113 private static final CompareNormal CNO_VALUE_NORMAL 114 = new CompareNormal(ArrayValue.GET_VALUE, SORT_NORMAL); 115 private static final CompareNormal CNO_VALUE_REVERSE 116 = new CompareNormal(ArrayValue.GET_VALUE, SORT_REVERSE); 117 private static final CompareNormal CNO_KEY_NORMAL 118 = new CompareNormal(ArrayValue.GET_KEY, SORT_NORMAL); 119 private static final CompareNormal CNO_KEY_REVERSE 120 = new CompareNormal(ArrayValue.GET_KEY, SORT_REVERSE); 121 122 private static final CompareNatural CNA_VALUE_NORMAL_SENSITIVE 123 = new CompareNatural(ArrayValue.GET_VALUE, SORT_NORMAL, CASE_SENSITIVE); 124 private static final CompareNatural CNA_VALUE_NORMAL_INSENSITIVE 125 = new CompareNatural(ArrayValue.GET_VALUE, SORT_NORMAL, CASE_INSENSITIVE); 126 127 130 public String []getLoadedExtensions() 131 { 132 return new String [] { "standard" }; 133 } 134 135 138 public Value array_change_key_case(ArrayValue array, 139 @Optional("CASE_LOWER") int toCase) 140 { 141 if (array == null) 142 return BooleanValue.FALSE; 143 144 ArrayValue newArray = new ArrayValueImpl(); 145 146 for (Map.Entry <Value, Value> entry : array.entrySet()) { 147 Value keyValue = entry.getKey(); 148 149 if (keyValue instanceof StringValue) { 150 String key = keyValue.toString(); 151 152 if (toCase == CASE_UPPER) 153 key = key.toUpperCase(); 154 else 155 key = key.toLowerCase(); 156 157 newArray.put(new StringValueImpl(key), entry.getValue()); 158 } 159 else 160 newArray.put(keyValue, entry.getValue()); 161 } 162 163 return newArray; 164 } 165 166 169 public Value array_chunk(Env env, 170 ArrayValue array, 171 int size, 172 @Optional boolean preserveKeys) 173 { 174 if (array == null) 175 return NullValue.NULL; 176 177 ArrayValue newArray = new ArrayValueImpl(); 178 ArrayValue currentArray = null; 179 180 if (size < 1) { 181 env.warning("Size parameter expected to be greater than 0"); 182 183 return NullValue.NULL; 184 } 185 186 int i = 0; 187 for (Map.Entry <Value, Value> entry : array.entrySet()) { 188 Value key = entry.getKey(); 189 Value value = entry.getKey(); 190 191 if (i % size == 0) { 192 currentArray = new ArrayValueImpl(); 193 newArray.put(currentArray); 194 } 195 196 if (preserveKeys) 197 currentArray.put(key, value); 198 else 199 currentArray.put(new LongValue(i % size), value); 200 201 i++; 202 } 203 204 return newArray; 205 } 206 207 210 public Value array_combine(Env env, ArrayValue keys, 211 ArrayValue values) 212 { 213 if (keys == null || values == null) 214 return BooleanValue.FALSE; 215 216 if (keys.getSize() < 1 || values.getSize() < 1) { 217 env.warning("Both parameters should have at least 1 element"); 218 219 return BooleanValue.FALSE; 220 } 221 222 if (keys.getSize() != values.getSize()) { 223 env.warning("Both parameters should have equal number of elements"); 224 225 return BooleanValue.FALSE; 226 } 227 228 Iterator <Value> keyIter = keys.values().iterator(); 229 Iterator <Value> valueIter = values.values().iterator(); 230 231 ArrayValue array = new ArrayValueImpl(); 232 233 while (keyIter.hasNext() && valueIter.hasNext()) { 234 array.put(keyIter.next(), valueIter.next()); 235 } 236 237 return array; 238 } 239 240 243 public Value array_count_values(Env env, ArrayValue array) 244 { 245 if (array == null) 246 return NullValue.NULL; 247 248 ArrayValue result = new ArrayValueImpl(); 249 250 for (Value value : array.values()) { 251 if (! (value instanceof LongValue) && ! (value instanceof StringValue)) 252 env.warning("Can only count STRING and INTEGER values!"); 253 else { 254 Value count = result.get(value); 255 256 if (count == null) 257 count = new LongValue(1); 258 else 259 count = count.add(1); 260 261 result.put(value, count); 262 } 263 } 264 265 return result; 266 } 267 268 271 public Value array_pop(Value value) 272 { 273 if (value instanceof ArrayValue) { 274 ArrayValue array = (ArrayValue) value; 275 276 return array.pop(); 277 } 278 else 279 return BooleanValue.FALSE; 280 } 281 282 285 public static Value count(@ReadOnly Value value) 286 { 287 return new LongValue(value.getSize()); 288 } 289 290 293 public static Value current(@ReadOnly Value value) 294 { 295 if (value instanceof ArrayValue) { 296 ArrayValue array = (ArrayValue) value; 297 298 return array.current(); 299 } 300 else 301 return BooleanValue.FALSE; 302 } 303 304 307 public static Value key(@ReadOnly Value value) 308 { 309 if (value instanceof ArrayValue) { 310 ArrayValue array = (ArrayValue) value; 311 312 return array.key(); 313 } 314 else 315 return BooleanValue.FALSE; 316 } 317 318 321 public static Value pos(@ReadOnly Value value) 322 { 323 return current(value); 324 } 325 326 329 public static Value next(Value value) 330 { 331 if (value instanceof ArrayValue) { 332 ArrayValue array = (ArrayValue) value; 333 334 return array.next(); 335 } 336 else 337 return BooleanValue.FALSE; 338 } 339 340 343 public static Value each(Value value) 344 { 345 if (value instanceof ArrayValue) { 346 ArrayValue array = (ArrayValue) value; 347 348 return array.each(); 349 } 350 else 351 return BooleanValue.FALSE; 352 } 353 354 357 public static Value prev(Value value) 358 { 359 if (value instanceof ArrayValue) { 360 ArrayValue array = (ArrayValue) value; 361 362 return array.prev(); 363 } 364 else 365 return BooleanValue.FALSE; 366 } 367 368 371 public static Value reset(Value value) 372 { 373 if (value instanceof ArrayValue) { 374 ArrayValue array = (ArrayValue) value; 375 376 return array.reset(); 377 } 378 else 379 return BooleanValue.FALSE; 380 } 381 382 385 public static Value shuffle(ArrayValue array) 386 { 387 if (array == null) 388 return BooleanValue.FALSE; 389 390 array.shuffle(); 391 392 return BooleanValue.TRUE; 393 } 394 395 398 public static Value end(Value value) 399 { 400 if (value instanceof ArrayValue) { 401 ArrayValue array = (ArrayValue) value; 402 403 return array.end(); 404 } 405 else 406 return BooleanValue.FALSE; 407 } 408 409 416 public static boolean array_key_exists(Env env, 417 @ReadOnly Value key, 418 @ReadOnly Value searchArray) 419 { 420 if (! searchArray.isset() || ! key.isset()) 421 return false; 422 423 if (!((searchArray instanceof ArrayValue) || (searchArray instanceof ObjectValue))) { 424 env.warning(L.l("'" + searchArray.toString() + "' is an unexpected argument, expected ArrayValue or ObjectValue")); 425 return false; 426 } 427 428 if (!((key instanceof StringValue) || (key instanceof LongValue))) { 429 env.warning(L.l( 430 "The first argument (a '{0}') should be either a string or an integer", 431 key.getType())); 432 return false; 433 } 434 435 if (searchArray instanceof ArrayValue) 436 return ((ArrayValue) searchArray).containsKey(key) != null; 437 else 438 return ! searchArray.getField(env, key.toString()).isNull(); 439 } 440 441 444 public static boolean key_exists(Env env, 445 @ReadOnly Value key, 446 @ReadOnly Value searchArray) 447 { 448 return array_key_exists(env, key, searchArray); 449 } 450 451 458 public Value array_keys(Env env, 459 @ReadOnly ArrayValue array, 460 @Optional @ReadOnly Value searchValue, 461 @Optional boolean isStrict) 462 { 463 if (array == null) 464 return NullValue.NULL; 465 466 ArrayValue newArray = new ArrayValueImpl(array.getSize()); 467 468 for (Map.Entry <Value, Value> entry : array.entrySet()) { 469 Value entryValue = entry.getValue(); 470 Value entryKey = entry.getKey(); 471 472 473 if (searchValue == null || searchValue instanceof DefaultValue) 474 newArray.put(entryKey); 475 else if (entryValue.eq(searchValue)) 476 newArray.put(entryKey); 477 } 478 479 return newArray; 480 } 481 482 492 public Value array_fill(Env env, long start, long num, Value value) 493 { 494 495 if (num < 0) { 496 env.warning("Number of elements must be positive"); 497 498 return BooleanValue.FALSE; 499 } 500 501 ArrayValue array = new ArrayValueImpl(); 502 503 for (long k = start; k < num + start; k++) 504 array.put(LongValue.create(k), value); 505 506 return array; 507 } 508 509 517 public Value array_flip(Env env, 518 ArrayValue array) 519 { 520 if (array == null) 521 return BooleanValue.FALSE; 522 523 ArrayValue newArray = new ArrayValueImpl(); 524 525 for (Map.Entry <Value, Value> entry : array.entrySet()) { 526 Value entryValue = entry.getValue(); 527 528 if ((entryValue instanceof LongValue) || 529 (entryValue instanceof StringValue)) 530 newArray.put(entryValue, entry.getKey()); 531 else 532 env.warning("Can only flip STRING and INTEGER values!"); 533 } 534 535 return newArray; 536 } 537 538 551 public Value array_pad(Env env, ArrayValue input, long padSize, 552 Value padValue) 553 { 554 if (input == null) 555 return NullValue.NULL; 556 557 long inputSize = input.getSize(); 558 559 long size = Math.abs(padSize); 560 561 if (input.getSize() >= size) 562 return input; 563 564 if (size - inputSize > 1048576) { 565 env.warning("You may only pad up to 1048576 elements at a time"); 566 567 return BooleanValue.FALSE; 568 } 569 570 ArrayValue paddedArray = new ArrayValueImpl(); 571 572 boolean padFront = padSize < 0; 573 574 Iterator <Value> keyIterator = input.keySet().iterator(); 575 576 for (long ctr = 0; ctr < size; ctr++) { 577 Value newValue; 578 579 if (padFront && ctr < size - inputSize) 580 newValue = padValue; 581 else if ((! padFront) && ctr >= inputSize) 582 newValue = padValue; 583 else 584 newValue = input.get(keyIterator.next()); 585 586 paddedArray.put(LongValue.create(ctr), newValue); 587 } 588 589 return paddedArray; 590 } 591 592 600 public Value array_filter(Env env, 601 ArrayValue array, 602 @Optional Callback callback) 603 { 604 if (array == null) 605 return NullValue.NULL; 606 607 ArrayValue filteredArray = new ArrayValueImpl(); 608 609 if (callback != null) { 610 611 if (!callback.isValid()) { 612 env.warning("The second argument, '" + ((CallbackFunction) callback).getFunctionName() + "', should be a valid callback"); 613 return NullValue.NULL; 614 } 615 616 for (Map.Entry <Value, Value> entry : array.entrySet()) { 617 try { 618 boolean isMatch = callback.call(env, entry.getValue()).toBoolean(); 619 620 if (isMatch) 621 filteredArray.put(entry.getKey(), entry.getValue()); 622 } 623 catch (Throwable t) { 624 log.log(Level.WARNING, t.toString(), t); 625 env.warning("An error occurred while invoking the filter callback"); 626 627 return NullValue.NULL; 628 } 629 } 630 } 631 else { 632 633 for (Map.Entry <Value, Value> entry : array.entrySet()) { 634 if (entry.getValue().toBoolean()) 635 filteredArray.put(entry.getKey(), entry.getValue()); 636 } 637 } 638 639 return filteredArray; 640 } 641 642 648 public Value array_product(Env env, 649 ArrayValue array) 650 { 651 if (array == null) 652 return NullValue.NULL; 653 654 if (array.getSize() == 0) 655 return DoubleValue.create(0); 656 657 double product = 1; 658 659 for (Map.Entry <Value, Value> entry : array.entrySet()) 660 product *= entry.getValue().toDouble(); 661 662 return DoubleValue.create(product); 663 } 664 665 670 public int array_push(Env env, ArrayValue array, Value []values) 671 { 672 for (Value value : values) { 673 array.put(value); 674 } 675 676 return array.getSize(); 677 } 678 679 686 public Value array_rand(Env env, 687 ArrayValue array, 688 @Optional("1") long num) 689 { 690 if (array == null) 691 return NullValue.NULL; 692 693 if (array.getSize() == 0) 694 return NullValue.NULL; 695 696 if (num < 1 || array.getSize() < num) { 697 env.warning("Second argument has to be between 1 and the number of " + 698 "elements in the array"); 699 700 return NullValue.NULL; 701 } 702 703 long arraySize = array.getSize(); 704 705 Value[] keys = new Value[(int) arraySize]; 706 707 array.keySet().toArray(keys); 708 709 if (num == 1) { 710 int index = (int) (RandomUtil.getRandomLong() % arraySize); 711 712 if (index < 0) 713 index *= -1; 714 715 return keys[index]; 716 } 717 718 int length = keys.length; 719 for (int i = 0; i < length; i++) { 720 int rand = RandomUtil.nextInt(length); 721 722 Value temp = keys[rand]; 723 keys[rand] = keys[i]; 724 keys[i] = temp; 725 } 726 727 ArrayValue randArray = new ArrayValueImpl(); 728 729 for (int i = 0; i < num; i++) { 730 randArray.put(keys[i]); 731 } 732 733 return randArray; 734 } 735 736 747 public Value array_reduce(Env env, 748 ArrayValue array, 749 String callback, 750 @Optional("NULL") Value initialValue) 751 { 752 if (array == null) 753 return NullValue.NULL; 754 755 AbstractFunction func = env.findFunction(callback.intern()); 756 757 if (func == null) { 758 env.warning("The second argument, '" + callback + 759 "', should be a valid callback"); 760 761 return NullValue.NULL; 762 } 763 764 Value result = initialValue; 765 766 for (Map.Entry <Value, Value> entry : array.entrySet()) { 767 try { 768 result = func.call(env, result, entry.getValue()); 769 } 770 catch (Throwable t) { 771 log.log(Level.WARNING, t.toString(), t); 773 env.warning("An error occurred while invoking the reduction callback"); 774 775 return NullValue.NULL; 776 } 777 } 778 779 return result; 780 } 781 782 789 public Value array_reverse(Env env, 790 ArrayValue inputArray, 791 @Optional("false") boolean keyed) 792 { 793 if (inputArray == null) 794 return NullValue.NULL; 795 796 Map.Entry <Value, Value>[] entryArray = 797 new Map.Entry [inputArray.getSize()]; 798 799 inputArray.entrySet().toArray(entryArray); 800 801 ArrayValue newArray = new ArrayValueImpl(); 802 803 int newIndex = 0; 804 805 for (int index = entryArray.length - 1; index > -1; index--) { 806 Value currentKey = entryArray[index].getKey(); 807 808 Value currentValue = entryArray[index].getValue(); 809 810 if (keyed || (currentKey instanceof StringValue)) 811 newArray.put(currentKey, currentValue); 812 else { 813 newArray.put(LongValue.create(newIndex), currentValue); 814 815 newIndex++; 816 } 817 } 818 819 return newArray; 820 } 821 822 831 public Value array_search(Env env, 832 @ReadOnly Value needle, 833 @ReadOnly ArrayValue array, 834 @Optional("false") boolean strict) 835 { 836 if (array == null) 837 return BooleanValue.FALSE; 838 839 for (Map.Entry <Value, Value> entry : array.entrySet()) { 840 Value entryValue = entry.getValue(); 841 842 Value entryKey = entry.getKey(); 843 844 if (needle.eq(entryValue)) { 845 if (strict) { 846 if ((entryValue.getType()).equals(needle.getType())) 847 return entryKey; 848 } 849 else 850 return entryKey; 851 } 852 } 853 854 return BooleanValue.FALSE; 855 } 856 857 863 public Value array_shift(Env env, 864 ArrayValue array) 865 { 866 if (array == null) 867 return NullValue.NULL; 868 869 if (array.getSize() < 1) 870 return NullValue.NULL; 871 872 Iterator <Value> iterator = array.keySet().iterator(); 873 874 Value firstValue = array.remove(iterator.next()); 875 876 array.keyReset(0, NOT_STRICT); 877 878 return firstValue; 879 } 880 881 895 public Value array_slice(Env env, 896 ArrayValue array, 897 long offset, 898 @Optional("NULL") Value elements, 899 @Optional("false") boolean presKeys) 900 { 901 if (array == null) 902 return NullValue.NULL; 903 904 long size = array.getSize(); 905 906 long startIndex = offset; 907 908 if (offset < 0) 909 startIndex = size + offset; 910 911 long endIndex = size; 912 913 if (elements != NullValue.NULL) { 914 endIndex = elements.toLong(); 915 916 if (endIndex < 0) 917 endIndex += size; 918 else 919 endIndex += startIndex; 920 } 921 922 Iterator <Map.Entry <Value, Value>> iterator = array.entrySet().iterator(); 923 924 ArrayValue slicedArray = new ArrayValueImpl(); 925 926 for (int k = 0; k < endIndex && iterator.hasNext(); k++) { 927 Map.Entry <Value, Value> entry = iterator.next(); 928 929 if (k >= startIndex) { 930 Value entryKey = entry.getKey(); 931 932 Value entryValue = entry.getValue(); 933 934 if ((entryKey instanceof StringValue) || presKeys) 935 slicedArray.put(entryKey, entryValue); 936 else 937 slicedArray.put(entryValue); 938 } 939 } 940 941 return slicedArray; 942 } 943 944 958 public Value array_splice(Env env, 959 @Reference Value arrayVar, int offset, 961 @Optional("NULL") Value length, 962 @Optional Value replace) 963 { 964 if (! arrayVar.isset()) 965 return NullValue.NULL; 966 967 ArrayValue array = arrayVar.toArrayValue(env); 968 969 if (array == null) 970 return NullValue.NULL; 971 972 int size = array.getSize(); 973 974 int startIndex = offset; 975 976 if (startIndex < 0) 977 startIndex += size; 978 979 int endIndex = size; 980 981 if (length != NullValue.NULL) { 982 endIndex = length.toInt(); 983 984 if (endIndex < 0) 985 endIndex += size; 986 else 987 endIndex += startIndex; 988 } 989 990 return spliceImpl(arrayVar, array, startIndex, endIndex, 991 (ArrayValue) replace.toArray()); 992 } 993 994 public Value spliceImpl(Value var, 995 ArrayValue array, 996 int start, 997 int end, 998 ArrayValue replace) 999 { 1000 int index = 0; 1001 1002 ArrayValue newArray = new ArrayValueImpl(); 1003 ArrayValue result = new ArrayValueImpl(); 1004 1005 var.set(newArray); 1006 1007 ArrayValue.Entry ptr = array.getHead(); 1008 for (; ptr != null; ptr = ptr.getNext()) { 1009 Value key = ptr.getKey(); 1010 1011 if (start == index && replace != null) { 1012 for (ArrayValue.Entry replaceEntry = replace.getHead(); 1013 replaceEntry != null; 1014 replaceEntry = replaceEntry.getNext()) { 1015 newArray.put(replaceEntry.getValue()); 1016 } 1017 } 1018 1019 if (start <= index && index < end) { 1020 if (ptr.getKey() instanceof StringValue) 1021 result.put(ptr.getKey(), ptr.getValue()); 1022 else 1023 result.put(ptr.getValue()); 1024 } 1025 else { 1026 if (ptr.getKey() instanceof StringValue) 1027 newArray.put(ptr.getKey(), ptr.getValue()); 1028 else 1029 newArray.put(ptr.getValue()); 1030 } 1031 1032 index++; 1033 } 1034 1035 if (index <= start && replace != null) { 1036 for (ArrayValue.Entry replaceEntry = replace.getHead(); 1037 replaceEntry != null; 1038 replaceEntry = replaceEntry.getNext()) { 1039 newArray.put(replaceEntry.getValue()); 1040 } 1041 } 1042 1043 return result; 1044 } 1045 1046 1052 public Value array_sum(Env env, 1053 @ReadOnly ArrayValue array) 1054 { 1055 if (array == null) 1056 return NullValue.NULL; 1057 1058 double sum = 0; 1059 1060 for (Map.Entry <Value, Value> entry : array.entrySet()) 1061 sum += entry.getValue().toDouble(); 1062 1063 return DoubleValue.create(sum); 1064 } 1065 1066 1070 1074 1080 public Value array_unique(Env env, 1081 ArrayValue array) 1082 { 1083 if (array == null) 1084 return BooleanValue.FALSE; 1085 1086 array.sort(CNO_VALUE_NORMAL, NO_KEY_RESET, NOT_STRICT); 1087 1088 Map.Entry <Value, Value> lastEntry = null; 1089 1090 ArrayValue uniqueArray = new ArrayValueImpl(); 1091 1092 for (Map.Entry <Value, Value> entry : array.entrySet()) { 1093 Value entryValue = entry.getValue(); 1094 1095 if (lastEntry == null) { 1096 uniqueArray.put(entry.getKey(), entryValue); 1097 1098 lastEntry = entry; 1099 1100 continue; 1101 } 1102 1103 Value lastEntryValue = lastEntry.getValue(); 1104 1105 if (! entryValue.toString().equals(lastEntryValue.toString())) 1106 uniqueArray.put(entry.getKey(), entryValue); 1107 1108 lastEntry = entry; 1109 } 1110 1111 uniqueArray.sort(CNO_KEY_NORMAL, NO_KEY_RESET, NOT_STRICT); 1112 1113 return uniqueArray; 1114 } 1115 1116 1123 public Value array_unshift(Env env, 1124 ArrayValue array, 1125 Value []values) 1126 { 1127 if (array == null) 1128 return NullValue.NULL; 1129 1130 for (int i = values.length - 1; i >= 0; i--) { 1131 array.unshift(values[i]); 1132 } 1133 1134 array.keyReset(0, NOT_STRICT); 1135 1136 return array; 1137 } 1138 1139 1145 public Value array_values(Env env, 1146 ArrayValue array) 1147 { 1148 if (array == null) 1149 return NullValue.NULL; 1150 1151 ArrayValue arrayValues = new ArrayValueImpl(); 1152 1153 for (Map.Entry <Value, Value> entry : array.entrySet()) 1154 arrayValues.put(entry.getValue()); 1155 1156 return arrayValues; 1157 } 1158 1159 1169 public boolean array_walk_recursive(Env env, 1170 ArrayValue array, 1171 Value call, 1172 @Optional("NULL") Value extra) 1173 { 1174 if (array == null) 1175 return false; 1176 1177 if (! (call instanceof StringValue)) { 1178 env.warning("Wrong syntax for function name"); 1179 1180 return false; 1181 } 1182 1183 AbstractFunction callback = env.findFunction(call.toString().intern()); 1184 1185 if (callback == null) 1186 return true; 1187 1188 for (Map.Entry <Value, Value> entry : array.entrySet()) { 1189 Value entryValue = entry.getValue(); 1190 1191 if (entryValue instanceof ArrayValue) 1192 array_walk_recursive(env, (ArrayValue) entryValue, call, extra); 1193 else { 1194 try { 1195 arrayWalkImpl(env, entry, extra, callback); 1196 } 1197 catch (Throwable t) { 1198 log.log(Level.WARNING, t.toString(), t); 1199 env.warning("An error occured while invoking the callback"); 1200 1201 return false; 1202 } 1203 } 1204 } 1205 1206 return true; 1207 } 1208 1209 1215 private void arrayWalkImpl(Env env, Map.Entry <Value, Value> entry, 1216 Value extra, AbstractFunction callback) 1217 { 1218 callback.call(env, entry.getValue(), entry.getKey(), extra); 1219 } 1220 1221 1229 public boolean array_walk(Env env, 1230 ArrayValue array, 1231 Value call, 1232 @Optional("NULL") Value extra) 1233 { 1234 if (array == null) 1235 return false; 1236 1237 if (! (call instanceof StringValue)) { 1238 env.warning("Wrong syntax for function name"); 1239 1240 return false; 1241 } 1242 1243 AbstractFunction callback = env.findFunction(call.toString().intern()); 1244 1245 if (callback == null) 1246 return true; 1247 1248 for (Map.Entry <Value, Value> entry : array.entrySet()) { 1249 try { 1250 arrayWalkImpl(env, entry, extra, callback); 1251 } 1252 catch (Throwable t) { 1253 log.log(Level.WARNING, t.toString(), t); 1255 env.warning("An error occured while invoking the callback"); 1256 1257 return false; 1258 } 1259 } 1260 1261 return true; 1262 } 1263 1264 1272 public boolean arsort(Env env, ArrayValue array, 1273 @Optional long sortFlag) 1274 { 1275 if (array == null) 1276 return false; 1277 1278 switch ((int) sortFlag) { 1279 case SORT_STRING: 1280 array.sort(CS_VALUE_REVERSE, NO_KEY_RESET, NOT_STRICT); 1281 break; 1282 case SORT_NUMERIC: 1283 array.sort(CN_VALUE_REVERSE, NO_KEY_RESET, NOT_STRICT); 1284 break; 1285 case SORT_LOCALE_STRING: 1286 Locale locale = env.getLocaleInfo().getCollate(); 1287 array.sort(new CompareLocale(ArrayValue.GET_VALUE, SORT_REVERSE, 1288 Collator.getInstance(locale)), 1289 NO_KEY_RESET, NOT_STRICT); 1290 break; 1291 default: 1292 array.sort(CNO_VALUE_REVERSE, NO_KEY_RESET, NOT_STRICT); 1293 break; 1294 } 1295 1296 return true; 1297 } 1298 1299 1307 public boolean asort(Env env, ArrayValue array, 1308 @Optional long sortFlag) 1309 { 1310 if (array == null) 1311 return false; 1312 1313 switch ((int) sortFlag) { 1314 case SORT_STRING: 1315 array.sort(CS_VALUE_NORMAL, NO_KEY_RESET, NOT_STRICT); 1316 break; 1317 case SORT_NUMERIC: 1318 array.sort(CN_VALUE_NORMAL, NO_KEY_RESET, NOT_STRICT); 1319 break; 1320 case SORT_LOCALE_STRING: 1321 Locale locale = env.getLocaleInfo().getCollate(); 1322 array.sort(new CompareLocale(ArrayValue.GET_VALUE, SORT_NORMAL, 1323 Collator.getInstance(locale)), 1324 NO_KEY_RESET, NOT_STRICT); 1325 break; 1326 default: 1327 array.sort(CNO_VALUE_NORMAL, NO_KEY_RESET, NOT_STRICT); 1328 break; 1329 } 1330 1331 return true; 1332 } 1333 1334 1342 public boolean ksort(Env env, ArrayValue array, 1343 @Optional long sortFlag) 1344 { 1345 if (array == null) 1346 return false; 1347 1348 switch ((int) sortFlag) { 1349 case SORT_STRING: 1350 array.sort(CS_KEY_NORMAL, NO_KEY_RESET, NOT_STRICT); 1351 break; 1352 case SORT_NUMERIC: 1353 array.sort(CN_KEY_NORMAL, NO_KEY_RESET, NOT_STRICT); 1354 break; 1355 case SORT_LOCALE_STRING: 1356 Locale locale = env.getLocaleInfo().getCollate(); 1357 array.sort(new CompareLocale(ArrayValue.GET_KEY, SORT_NORMAL, 1358 Collator.getInstance(locale)), 1359 NO_KEY_RESET, NOT_STRICT); 1360 break; 1361 default: 1362 array.sort(CNO_KEY_NORMAL, NO_KEY_RESET, NOT_STRICT); 1363 break; 1364 } 1365 1366 return true; 1367 } 1368 1369 1377 public boolean krsort(Env env, ArrayValue array, 1378 @Optional long sortFlag) 1379 { 1380 if (array == null) 1381 return false; 1382 1383 switch ((int) sortFlag) { 1384 case SORT_STRING: 1385 array.sort(CS_KEY_REVERSE, NO_KEY_RESET, NOT_STRICT); 1386 break; 1387 case SORT_NUMERIC: 1388 array.sort(CN_KEY_REVERSE, NO_KEY_RESET, NOT_STRICT); 1389 break; 1390 case SORT_LOCALE_STRING: 1391 Locale locale = env.getLocaleInfo().getCollate(); 1392 array.sort(new CompareLocale(ArrayValue.GET_KEY, SORT_REVERSE, 1393 Collator.getInstance(locale)), 1394 NO_KEY_RESET, NOT_STRICT); 1395 break; 1396 default: 1397 array.sort(CNO_KEY_REVERSE, NO_KEY_RESET, NOT_STRICT); 1398 break; 1399 } 1400 1401 return true; 1402 } 1403 1404 1412 public Value natsort(ArrayValue array) 1413 { 1414 if (array == null) 1415 return NullValue.NULL; 1416 1417 trimArrayStrings(array); 1418 1419 array.sort(CNA_VALUE_NORMAL_SENSITIVE, NO_KEY_RESET, NOT_STRICT); 1420 1421 return BooleanValue.TRUE; 1422 } 1423 1424 1432 public Value natcasesort(ArrayValue array) 1433 { 1434 if (array == null) 1435 return NullValue.NULL; 1436 1437 trimArrayStrings(array); 1438 1439 array.sort(CNA_VALUE_NORMAL_INSENSITIVE, NO_KEY_RESET, NOT_STRICT); 1440 1441 return BooleanValue.TRUE; 1442 } 1443 1444 1450 private void trimArrayStrings(ArrayValue array) 1451 { 1452 if (array != null) { 1453 1454 for (Map.Entry <Value, Value> entry : array.entrySet()) { 1455 Value entryValue = entry.getValue(); 1456 1457 if (entryValue instanceof StringValue) 1458 array.put(entry.getKey(), 1459 StringValue.create(entryValue.toString().trim())); 1460 } 1461 } 1462 } 1463 1464 1466 1473 public boolean in_array(@ReadOnly Value needle, 1474 @ReadOnly ArrayValue stack, 1475 @Optional("false") boolean strict) 1476 { 1477 if (stack == null) 1478 return false; 1479 1480 if (strict) 1481 return stack.containsStrict(needle) != NullValue.NULL; 1482 else 1483 return stack.contains(needle) != NullValue.NULL; 1484 } 1485 1486 1494 public boolean sort(Env env, ArrayValue array, @Optional long sortFlag) 1495 { 1496 if (array == null) 1497 return false; 1498 1499 switch ((int) sortFlag) { 1500 case SORT_STRING: 1501 array.sort(CS_VALUE_NORMAL, KEY_RESET, STRICT); 1502 break; 1503 case SORT_NUMERIC: 1504 array.sort(CN_VALUE_NORMAL, KEY_RESET, STRICT); 1505 break; 1506 case SORT_LOCALE_STRING: 1507 Locale locale = env.getLocaleInfo().getCollate(); 1508 array.sort(new CompareLocale(ArrayValue.GET_VALUE, SORT_NORMAL, 1509 Collator.getInstance(locale)), 1510 KEY_RESET, STRICT); 1511 break; 1512 default: 1513 array.sort(CNO_VALUE_NORMAL, KEY_RESET, STRICT); 1514 break; 1515 } 1516 1517 return true; 1518 } 1519 1520 1528 public boolean rsort(Env env, ArrayValue array, @Optional long sortFlag) 1529 { 1530 if (array == null) 1531 return false; 1532 1533 switch ((int) sortFlag) { 1534 case SORT_STRING: 1535 array.sort(CS_VALUE_REVERSE, KEY_RESET, STRICT); 1536 break; 1537 case SORT_NUMERIC: 1538 array.sort(CN_VALUE_REVERSE, KEY_RESET, STRICT); 1539 break; 1540 case SORT_LOCALE_STRING: 1541 Locale locale = env.getLocaleInfo().getCollate(); 1542 array.sort(new CompareLocale(ArrayValue.GET_VALUE, SORT_REVERSE, 1543 Collator.getInstance(locale)), 1544 KEY_RESET, STRICT); 1545 break; 1546 default: 1547 array.sort(CNO_VALUE_REVERSE, KEY_RESET, STRICT); 1548 break; 1549 } 1550 1551 return true; 1552 } 1553 1554 1564 public boolean usort(Env env, 1565 ArrayValue array, 1566 Callback func, 1567 @Optional long sortFlag) 1568 { 1569 if (array == null) 1570 return false; 1571 1572 if (!func.isValid()) { 1573 env.warning(L.l("Invalid comparison function")); 1574 return false; 1575 } 1576 1577 CompareCallBack cmp; 1578 1579 cmp = new CompareCallBack(ArrayValue.GET_VALUE, SORT_NORMAL, func, env); 1580 1581 array.sort(cmp, KEY_RESET, STRICT); 1582 1583 return true; 1584 } 1585 1586 1596 public boolean uasort(Env env, 1597 ArrayValue array, 1598 Callback func, 1599 @Optional long sortFlag) 1600 { 1601 if (array == null) 1602 return false; 1603 1604 if (!func.isValid()) { 1605 env.warning(L.l("Invalid comparison function")); 1606 return false; 1607 } 1608 1609 array.sort(new CompareCallBack(ArrayValue.GET_VALUE, SORT_NORMAL, func, 1610 env), NO_KEY_RESET, NOT_STRICT); 1611 1612 return true; 1613 } 1614 1615 1625 public boolean uksort(Env env, 1626 ArrayValue array, 1627 Callback func, 1628 @Optional long sortFlag) 1629 { 1630 if (array == null) 1631 return false; 1632 1633 if (!func.isValid()) { 1634 env.warning(L.l("Invalid comparison function")); 1635 return false; 1636 } 1637 1638 CompareCallBack cmp; 1639 1640 cmp = new CompareCallBack(ArrayValue.GET_KEY, SORT_NORMAL, func, env); 1641 1642 array.sort(cmp, NO_KEY_RESET, NOT_STRICT); 1643 1644 return true; 1645 } 1646 1647 1656 public Value range(Env env, 1657 @ReadOnly Value start, 1658 @ReadOnly Value end, 1659 @Optional("1") long step) 1660 { 1661 if (step < 1) 1662 step = 1; 1663 1664 if (!start.getType().equals(end.getType())) { 1665 start = LongValue.create(start.toLong()); 1666 end = LongValue.create(end.toLong()); 1667 } 1668 else if (Character.isDigit(start.toChar())) { 1669 start = LongValue.create(start.toLong()); 1670 end = LongValue.create(end.toLong()); 1671 } 1672 else { 1673 start = rangeIncrement(start, 0); 1674 end = rangeIncrement(end, 0); 1675 } 1676 1677 if (start.eq(end)) { 1678 } 1679 else if (start instanceof StringValue && 1680 (Math.abs(end.toChar() - start.toChar()) < step)) { 1681 env.warning("steps exceeds the specified range"); 1682 1683 return BooleanValue.FALSE; 1684 } 1685 else if (start instanceof LongValue && 1686 (Math.abs(end.toLong() - start.toLong()) < step)) { 1687 env.warning("steps exceeds the specified range"); 1688 1689 return BooleanValue.FALSE; 1690 } 1691 1692 boolean increment = true; 1693 1694 if (! end.geq(start)) { 1695 step *= -1; 1696 increment = false; 1697 } 1698 1699 ArrayValue array = new ArrayValueImpl(); 1700 1701 do { 1702 array.put(start); 1703 1704 start = rangeIncrement(start, step); 1705 } while ((increment && start.leq(end)) || 1706 (!increment && start.geq(end))); 1707 1708 return array; 1709 } 1710 1711 private Value rangeIncrement(Value value, long step) 1712 { 1713 if (value instanceof StringValue) 1714 return StringValue.create((char) (value.toChar() + step)); 1715 1716 return LongValue.create(value.toLong() + step); 1717 } 1718 1719 1728 1737 @UsesSymbolTable 1738 public static Value extract(Env env, 1739 ArrayValue array, 1740 @Optional("EXTR_OVERWRITE") long rawType, 1741 @Optional("NULL") Value valuePrefix) 1742 { 1743 if (array == null) 1744 return NullValue.NULL; 1745 1746 long extractType = rawType & ~EXTR_REFS; 1747 1748 boolean extrRefs = (rawType & EXTR_REFS) != 0; 1749 1750 if (extractType < EXTR_OVERWRITE || extractType > EXTR_IF_EXISTS && 1751 extractType != EXTR_REFS) { 1752 env.warning("Unknown extract type"); 1753 1754 return NullValue.NULL; 1755 } 1756 1757 if (extractType >= EXTR_PREFIX_SAME && 1758 extractType <= EXTR_PREFIX_IF_EXISTS && 1759 (valuePrefix == null || (! (valuePrefix instanceof StringValue)))) { 1760 env.warning("Prefix expected to be specified"); 1761 1762 return NullValue.NULL; 1763 } 1764 1765 String prefix = ""; 1766 1767 if (valuePrefix instanceof StringValue) 1768 prefix = valuePrefix.toString() + "_"; 1769 1770 int completedSymbols = 0; 1771 1772 for (Value entryKey : array.keySet()) { 1773 Value entryValue; 1774 1775 if (extrRefs) 1776 entryValue = array.getRef(entryKey); 1777 else 1778 entryValue = array.get(entryKey); 1779 1780 String symbolName = entryKey.toString(); 1781 1782 Value tableValue = env.getValue(symbolName); 1783 1784 switch ((int) extractType) { 1785 case EXTR_SKIP: 1786 if (tableValue != NullValue.NULL) 1787 symbolName = ""; 1788 1789 break; 1790 case EXTR_PREFIX_SAME: 1791 if (tableValue != NullValue.NULL) 1792 symbolName = prefix + symbolName; 1793 1794 break; 1795 case EXTR_PREFIX_ALL: 1796 symbolName = prefix + symbolName; 1797 1798 break; 1799 case EXTR_PREFIX_INVALID: 1800 if (! validVariableName(symbolName)) 1801 symbolName = prefix + symbolName; 1802 1803 break; 1804 case EXTR_IF_EXISTS: 1805 if (tableValue == NullValue.NULL) 1806 symbolName = ""; 1808 break; 1809 case EXTR_PREFIX_IF_EXISTS: 1810 if (tableValue != NullValue.NULL) 1811 symbolName = prefix + symbolName; 1812 else 1813 symbolName = ""; 1814 1815 break; 1816 default: 1817 1818 break; 1819 } 1820 1821 if (validVariableName(symbolName)) { 1822 env.setValue(symbolName, entryValue); 1823 1824 completedSymbols++; 1825 } 1826 } 1827 1828 return LongValue.create(completedSymbols); 1829 } 1830 1831 1837 private static boolean validVariableName(String variableName) 1838 { 1839 if (variableName.length() < 1) 1840 return false; 1841 1842 char checkChar = variableName.charAt(0); 1843 1844 if (! Character.isLetter(checkChar) && checkChar != '_') 1845 return false; 1846 1847 for (int k = 1; k < variableName.length(); k++) { 1848 checkChar = variableName.charAt(k); 1849 1850 if (!Character.isLetterOrDigit(checkChar) && checkChar != '_') 1851 return false; 1852 } 1853 1854 return true; 1855 } 1856 1857 1867 public Value array_diff(Env env, ArrayValue array, Value []arrays) 1868 { 1869 if (array == null) 1870 return NullValue.NULL; 1871 1872 if (arrays.length < 1) { 1873 env.warning("Wrong parameter count for array_diff()"); 1874 1875 return NullValue.NULL; 1876 } 1877 1878 ArrayValue diffArray = new ArrayValueImpl(); 1879 1880 boolean valueFound; 1881 1882 for (Map.Entry <Value, Value> entry : array.entrySet()) { 1883 valueFound = false; 1884 1885 Value entryValue = entry.getValue(); 1886 1887 for (int k = 0; k < arrays.length && ! valueFound; k++) { 1888 if (! (arrays[k] instanceof ArrayValue)) { 1889 env.warning("Argument #" + (k + 2) + " is not an array"); 1890 1891 return NullValue.NULL; 1892 } 1893 1894 valueFound = 1895 ((ArrayValue) arrays[k]).contains(entryValue) != NullValue.NULL; 1896 } 1897 1898 if (! valueFound) 1899 diffArray.put(entry.getKey(), entryValue); 1900 } 1901 1902 return diffArray; 1903 } 1904 1905 1906 1916 public Value array_diff_assoc(Env env, ArrayValue array, Value []arrays) 1917 { 1918 if (array == null) 1919 return NullValue.NULL; 1920 1921 if (arrays.length < 1) { 1922 env.warning("Wrong parameter count for array_diff()"); 1923 1924 return NullValue.NULL; 1925 } 1926 1927 ArrayValue diffArray = new ArrayValueImpl(); 1928 1929 for (Map.Entry <Value, Value> entry : array.entrySet()) { 1930 boolean valueFound = false; 1931 1932 Value entryValue = entry.getValue(); 1933 1934 Value entryKey = entry.getKey(); 1935 1936 for (int k = 0; k < arrays.length && ! valueFound; k++) { 1937 if (! (arrays[k] instanceof ArrayValue)) { 1938 env.warning("Argument #" + (k + 2) + " is not an array"); 1939 1940 return NullValue.NULL; 1941 } 1942 1943 valueFound = 1944 ((ArrayValue) arrays[k]).contains(entryValue).eq(entryKey); 1945 } 1946 1947 if (! valueFound) 1948 diffArray.put(entryKey, entryValue); 1949 } 1950 1951 return diffArray; 1952 } 1953 1954 1964 public Value array_diff_key(Env env, ArrayValue array, Value []arrays) 1965 { 1966 if (array == null) 1967 return NullValue.NULL; 1968 1969 if (arrays.length < 1) { 1970 env.warning("Wrong parameter count for array_diff()"); 1971 1972 return NullValue.NULL; 1973 } 1974 1975 ArrayValue diffArray = new ArrayValueImpl(); 1976 1977 for (Map.Entry <Value, Value> entry : array.entrySet()) { 1978 boolean keyFound = false; 1979 1980 Value entryKey = entry.getKey(); 1981 1982 for (int k = 0; k < arrays.length && ! keyFound; k++) { 1983 if (! (arrays[k] instanceof ArrayValue)) { 1984 env.warning("Argument #" + (k + 2) + " is not an array"); 1985 1986 return NullValue.NULL; 1987 } 1988 1989 keyFound = ((ArrayValue) arrays[k]).containsKey(entryKey) != null; 1990 } 1991 1992 if (! keyFound) 1993 diffArray.put(entryKey, entry.getValue()); 1994 } 1995 1996 return diffArray; 1997 } 1998 1999 2009 public Value array_diff_uassoc(Env env, ArrayValue array, Value []arrays) 2010 { 2011 if (array == null) 2012 return NullValue.NULL; 2013 2014 if (arrays.length < 2) { 2015 env.warning("Wrong parameter count for array_diff()"); 2016 2017 return NullValue.NULL; 2018 } 2019 2020 AbstractFunction func = 2021 env.findFunction(arrays[arrays.length - 1].toString().intern()); 2022 2023 if (func == null) { 2024 env.warning("Invalid comparison function"); 2025 2026 return NullValue.NULL; 2027 } 2028 2029 ArrayValue diffArray = new ArrayValueImpl(); 2030 2031 for (Map.Entry <Value, Value> entry : array.entrySet()) { 2032 boolean ValueFound = false; 2033 2034 Value entryValue = entry.getValue(); 2035 2036 Value entryKey = entry.getKey(); 2037 2038 for (int k = 0; k < arrays.length - 1 && ! ValueFound; k++) { 2039 if (! (arrays[k] instanceof ArrayValue)) { 2040 env.warning("Argument #" + (k + 2) + " is not an array"); 2041 2042 return NullValue.NULL; 2043 } 2044 2045 Value searchKey = ((ArrayValue) arrays[k]).contains(entryValue); 2046 2047 if (searchKey != NullValue.NULL) 2048 ValueFound = ((int) func.call(env, searchKey, entryKey).toLong()) == 2049 0; 2050 } 2051 2052 if (! ValueFound) 2053 diffArray.put(entryKey, entryValue); 2054 } 2055 2056 return diffArray; 2057 } 2058 2059 2069 public Value array_diff_ukey(Env env, ArrayValue array, Value []arrays) 2070 { 2071 if (array == null) 2072 return NullValue.NULL; 2073 2074 if (arrays.length < 2) { 2075 env.warning("Wrong parameter count for array_diff()"); 2076 2077 return NullValue.NULL; 2078 } 2079 2080 AbstractFunction func = 2081 env.findFunction(arrays[arrays.length - 1].toString().intern()); 2082 2083 if (func == null) { 2084 env.warning("Invalid comparison function"); 2085 2086 return NullValue.NULL; 2087 } 2088 2089 ArrayValue diffArray = new ArrayValueImpl(); 2090 2091 for (Map.Entry <Value, Value> entry : array.entrySet()) { 2092 boolean keyFound = false; 2093 2094 Value entryKey = entry.getKey(); 2095 2096 for (int k = 0; k < arrays.length - 1 && ! keyFound; k++) { 2097 if (! (arrays[k] instanceof ArrayValue)) { 2098 env.warning("Argument #" + (k + 2) + " is not an array"); 2099 2100 return NullValue.NULL; 2101 } 2102 2103 Iterator <Value> keyItr = ((ArrayValue) arrays[k]).keySet().iterator(); 2104 2105 keyFound = false; 2106 2107 while (keyItr.hasNext() && ! keyFound) { 2108 Value currentKey = keyItr.next(); 2109 2110 keyFound = ((int) func.call(env, entryKey, currentKey).toLong()) == 0; 2111 } 2112 } 2113 2114 if (! keyFound) 2115 diffArray.put(entryKey, entry.getValue()); 2116 } 2117 2118 return diffArray; 2119 } 2120 2121 2131 public Value array_intersect(Env env, ArrayValue array, Value []arrays) 2132 { 2133 if (array == null) 2134 return NullValue.NULL; 2135 2136 if (arrays.length < 1) { 2137 env.warning("Wrong parameter count for array_diff()"); 2138 2139 return NullValue.NULL; 2140 } 2141 2142 ArrayValue interArray = new ArrayValueImpl(); 2143 2144 for (Map.Entry <Value, Value> entry : array.entrySet()) { 2145 boolean valueFound = false; 2146 2147 Value entryValue = entry.getValue(); 2148 2149 for (int k = 0; k < arrays.length; k++) { 2150 if (! (arrays[k] instanceof ArrayValue)) { 2151 env.warning("Argument #" + (k + 2) + " is not an array"); 2152 2153 return NullValue.NULL; 2154 } 2155 2156 if (k > 0 && ! valueFound) 2157 break; 2158 2159 valueFound = 2160 ((ArrayValue) arrays[k]).contains(entryValue) != NullValue.NULL; 2161 } 2162 2163 if (valueFound) 2164 interArray.put(entry.getKey(), entryValue); 2165 } 2166 2167 return interArray; 2168 } 2169 2170 2180 public Value array_intersect_assoc(Env env, ArrayValue array, Value []arrays) 2181 { 2182 if (array == null) 2183 return NullValue.NULL; 2184 2185 if (arrays.length < 1) { 2186 env.warning("Wrong parameter count for array_diff()"); 2187 2188 return NullValue.NULL; 2189 } 2190 2191 ArrayValue interArray = new ArrayValueImpl(); 2192 2193 for (Map.Entry <Value, Value> entry : array.entrySet()) { 2194 boolean valueFound = false; 2195 2196 Value entryKey = entry.getKey(); 2197 2198 Value entryValue = entry.getValue(); 2199 2200 for (int k = 0; k < arrays.length; k++) { 2201 if (! (arrays[k] instanceof ArrayValue)) { 2202 env.warning("Argument #" + (k + 2) + " is not an array"); 2203 2204 return NullValue.NULL; 2205 } 2206 2207 if (k > 0 && ! valueFound) 2208 break; 2209 2210 Value searchValue = ((ArrayValue) arrays[k]).containsKey(entryKey); 2211 2212 if (searchValue != null) 2213 valueFound = searchValue.eq(entryValue); 2214 else 2215 valueFound = false; 2216 } 2217 2218 if (valueFound) 2219 interArray.put(entryKey, entryValue); 2220 } 2221 2222 return interArray; 2223 } 2224 2225 2235 public Value array_intersect_key(Env env, ArrayValue array, Value []arrays) 2236 { 2237 if (array == null) 2238 return NullValue.NULL; 2239 2240 if (arrays.length < 1) { 2241 env.warning("Wrong parameter count for array_diff()"); 2242 2243 return NullValue.NULL; 2244 } 2245 2246 ArrayValue interArray = new ArrayValueImpl(); 2247 2248 for (Map.Entry <Value, Value> entry : array.entrySet()) { 2249 boolean keyFound = false; 2250 2251 Value entryKey = entry.getKey(); 2252 2253 for (int k = 0; k < arrays.length; k++) { 2254 if (! (arrays[k] instanceof ArrayValue)) { 2255 env.warning("Argument #" + (k + 2) + " is not an array"); 2256 2257 return NullValue.NULL; 2258 } 2259 2260 if (k > 0 && ! keyFound) 2261 break; 2262 2263 keyFound = ((ArrayValue) arrays[k]).containsKey(entryKey) != null; 2264 } 2265 2266 if (keyFound) 2267 interArray.put(entryKey, entry.getValue()); 2268 } 2269 2270 return interArray; 2271 } 2272 2273 2284 public Value array_intersect_uassoc(Env env, ArrayValue array, Value []arrays) 2285 { 2286 if (array == null) 2287 return NullValue.NULL; 2288 2289 if (arrays.length < 2) { 2290 env.warning("Wrong parameter count for array_diff()"); 2291 2292 return NullValue.NULL; 2293 } 2294 2295 AbstractFunction func = 2296 env.findFunction(arrays[arrays.length - 1].toString().intern()); 2297 2298 if (func == null) { 2299 env.warning("Invalid comparison function"); 2300 2301 return NullValue.NULL; 2302 } 2303 2304 ArrayValue interArray = new ArrayValueImpl(); 2305 2306 for (Map.Entry <Value, Value> entry : array.entrySet()) { 2307 boolean valueFound = false; 2308 2309 Value entryKey = entry.getKey(); 2310 2311 Value entryValue = entry.getValue(); 2312 2313 for (int k = 0; k < arrays.length - 1; k++) { 2314 if (! (arrays[k] instanceof ArrayValue)) { 2315 env.warning("Argument #" + (k + 2) + " is not an array"); 2316 2317 return NullValue.NULL; 2318 } 2319 2320 if (k > 0 && ! valueFound) 2321 break; 2322 2323 Value searchValue = ((ArrayValue) arrays[k]).containsKey(entryKey); 2324 2325 if (searchValue != null) 2326 valueFound = func.call(env, searchValue, entryValue).toLong() == 0; 2327 else 2328 valueFound = false; 2329 } 2330 2331 if (valueFound) 2332 interArray.put(entryKey, entryValue); 2333 } 2334 2335 return interArray; 2336 } 2337 2338 2349 public Value array_intersect_ukey(Env env, ArrayValue array, Value []arrays) 2350 { 2351 if (array == null) 2352 return NullValue.NULL; 2353 2354 if (arrays.length < 2) { 2355 env.warning("Wrong parameter count for array_diff()"); 2356 2357 return NullValue.NULL; 2358 } 2359 2360 AbstractFunction func = 2361 env.findFunction(arrays[arrays.length - 1].toString().intern()); 2362 2363 if (func == null) { 2364 env.warning("Invalid comparison function"); 2365 2366 return NullValue.NULL; 2367 } 2368 2369 ArrayValue interArray = new ArrayValueImpl(); 2370 2371 for (Map.Entry <Value, Value> entry : array.entrySet()) { 2372 boolean keyFound = false; 2373 2374 Value entryKey = entry.getKey(); 2375 2376 for (int k = 0; k < arrays.length - 1; k++) { 2377 if (! (arrays[k] instanceof ArrayValue)) { 2378 env.warning("Argument #" + (k + 2) + " is not an array"); 2379 2380 return NullValue.NULL; 2381 } 2382 2383 if (k > 0 && ! keyFound) 2384 break; 2385 2386 Iterator <Value> keyItr = ((ArrayValue) arrays[k]).keySet().iterator(); 2387 2388 keyFound = false; 2389 2390 while (keyItr.hasNext() && ! keyFound) { 2391 Value currentKey = keyItr.next(); 2392 2393 keyFound = ((int) func.call(env, entryKey, currentKey).toLong()) == 0; 2394 } 2395 2396 } 2397 2398 if (keyFound) 2399 interArray.put(entryKey, entry.getValue()); 2400 } 2401 2402 return interArray; 2403 } 2404 2405 2412 public Value array_map(Env env, Callback fun, 2413 ArrayValue arg, Value []args) 2414 { 2415 Iterator <Map.Entry <Value, Value>> argIter = arg.entrySet().iterator(); 2417 2418 Iterator []iters = new Iterator [args.length]; 2419 for (int i = 0; i < args.length; i++) { 2420 if (! (args[i] instanceof ArrayValue)) 2421 throw env.errorException(L.l("expected array")); 2422 2423 ArrayValue argArray = (ArrayValue) args[i]; 2424 2425 iters[i] = argArray.values().iterator(); 2426 } 2427 2428 ArrayValue resultArray = new ArrayValueImpl(); 2429 2430 Value []param = new Value[args.length + 1]; 2431 while (argIter.hasNext()) { 2432 Map.Entry <Value, Value> entry = argIter.next(); 2433 2434 param[0] = entry.getValue(); 2435 2436 for (int i = 0; i < iters.length; i++) { 2437 param[i + 1] = (Value) iters[i].next(); 2438 2439 if (param[i + 1] == null) 2440 param[i + 1] = NullValue.NULL; 2441 } 2442 2443 resultArray.put(entry.getKey(), fun.call(env, param)); 2444 } 2445 2446 return resultArray; 2447 } 2448 2449 2455 public Value array_merge(Value []args) 2456 { 2457 2459 ArrayValue result = new ArrayValueImpl(); 2460 2461 for (Value arg : args) { 2462 if (arg.isNull()) 2463 return NullValue.NULL; 2464 2465 if (! (arg.toValue() instanceof ArrayValue)) 2466 continue; 2467 2468 ArrayValue array = (ArrayValue) arg.toValue(); 2469 2470 for (Map.Entry <Value, Value> entry : array.entrySet()) { 2471 Value key = entry.getKey(); 2472 Value value = entry.getValue(); 2473 2474 if (key.isNumberConvertible()) 2475 result.put(value); 2476 else 2477 result.put(key, value); 2478 } 2479 } 2480 2481 return result; 2482 } 2483 2484 2490 public Value array_merge_recursive(Value []args) 2491 { 2492 2494 ArrayValue result = new ArrayValueImpl(); 2495 2496 for (Value arg : args) { 2497 if (! (arg.toValue() instanceof ArrayValue)) 2498 continue; 2499 2500 arrayMergeRecursiveImpl(result, (ArrayValue) arg.toValue()); 2501 } 2502 2503 return result; 2504 } 2505 2506 private static void arrayMergeRecursiveImpl(ArrayValue result, 2507 ArrayValue array) 2508 { 2509 for (Map.Entry <Value, Value> entry : array.entrySet()) { 2510 Value key = entry.getKey(); 2511 Value value = entry.getValue().toValue(); 2512 2513 if (key.isNumberConvertible()) { 2514 result.put(value); 2515 } 2516 else { 2517 Value oldValue = result.get(key).toValue(); 2518 2519 if (oldValue != null && oldValue.isset()) { 2520 if (oldValue.isArray() && value.isArray()) { 2521 arrayMergeRecursiveImpl((ArrayValue) oldValue, (ArrayValue) value); 2522 } 2523 else if (oldValue.isArray()) { 2524 oldValue.put(value); 2525 } 2526 else if (value.isArray()) { 2527 value.put(oldValue); 2529 } 2530 else { 2531 ArrayValue newArray = new ArrayValueImpl(); 2532 2533 newArray.put(oldValue); 2534 newArray.put(value); 2535 2536 result.put(key, newArray); 2537 } 2538 } 2539 else { 2540 result.put(key, value); 2541 } 2542 } 2543 } 2544 } 2545 2546 2552 public boolean array_multisort(Env env, Value[] arrays) 2553 { 2554 int maxsize = 0; 2555 for(int i=0; i<arrays.length; i++) 2556 if (arrays[i] instanceof ArrayValue) 2557 maxsize = Math.max(maxsize, 2558 ((ArrayValue)arrays[i]).getSize()); 2559 2560 LongValue []rows = new LongValue[maxsize]; 2562 for(int i=0; i<rows.length; i++) 2563 rows[i] = LongValue.create(i); 2564 2565 java.util.Arrays.sort(rows, new MultiSortComparator(env, arrays)); 2566 2567 for(int i=0; i<arrays.length; i++) 2569 if (arrays[i] instanceof ArrayValue) 2570 permute(env, (ArrayValue)arrays[i], rows); 2571 2572 return true; 2573 } 2574 2575 2580 private static void permute(Env env, ArrayValue array, 2581 LongValue[] permutation) 2582 { 2583 Value[] values = array.getValueArray(env); 2584 for(int i=0; i<permutation.length; i++) 2585 array.put(LongValue.create(i), 2586 values[(int)permutation[i].toLong()]); 2587 } 2588 2589 2590 2594 2609 2610 2614 2629 2630 2640 public Value array_udiff(Env env, Value[] arrays) 2641 { 2642 if (arrays.length < 3) { 2643 env.warning("Wrong paremeter count for array_udiff()"); 2644 2645 return NullValue.NULL; 2646 } 2647 2648 if (! (arrays[0] instanceof ArrayValue)) { 2649 env.warning("Argument #1 is not an array"); 2650 2651 return NullValue.NULL; 2652 } 2653 2654 ArrayValue array = (ArrayValue) arrays[0]; 2655 2656 Value callbackValue = arrays[arrays.length - 1]; 2657 2658 Callback cmp; 2659 2660 try { 2661 cmp = env.createCallback(callbackValue); 2662 } 2663 catch (Throwable t) { 2664 log.log(Level.WARNING, t.toString(), t); 2665 2666 env.warning("Not a valid callback " + callbackValue.toString()); 2667 2668 return NullValue.NULL; 2669 } 2670 2671 if (cmp == null) { 2672 env.warning("Not a valid callback " + callbackValue.toString()); 2673 2674 return NullValue.NULL; 2675 } 2676 2677 ArrayValue diffArray = new ArrayValueImpl(); 2678 2679 boolean isFound = false; 2680 2681 for (Value entryKey : array.keySet()) { 2682 Value entryValue = array.get(entryKey); 2683 2684 for (int k = 1; k < arrays.length - 1 && ! isFound; k++) { 2685 if (! (arrays[k] instanceof ArrayValue)) { 2686 env.warning("Argument #" + (k + 1) + " is not an array"); 2687 2688 return NullValue.NULL; 2689 } 2690 2691 ArrayValue checkArray = (ArrayValue) arrays[k]; 2692 2693 for (Map.Entry <Value, Value> entry : checkArray.entrySet()) { 2694 try { 2695 isFound = cmp.call(env, entryValue, entry.getValue()).toLong() == 0; 2696 } 2697 catch (Throwable t) { 2698 log.log(Level.WARNING, t.toString(), t); 2699 2700 env.warning("An error occurred while invoking the filter callback"); 2701 2702 return NullValue.NULL; 2703 } 2704 2705 if (isFound) 2706 break; 2707 } 2708 } 2709 2710 if (! isFound) 2711 diffArray.put(entryKey, entryValue); 2712 2713 isFound = false; 2714 } 2715 2716 return diffArray; 2717 } 2718 2719 2730 public Value array_udiff_assoc(Env env, Value[] arrays) 2731 { 2732 if (arrays.length < 3) { 2733 env.warning("Wrong paremeter count for array_udiff_assoc()"); 2734 2735 return NullValue.NULL; 2736 } 2737 2738 if (! (arrays[0] instanceof ArrayValue)) { 2739 env.warning("Argument #1 is not an array"); 2740 2741 return NullValue.NULL; 2742 } 2743 2744 ArrayValue array = (ArrayValue) arrays[0]; 2745 2746 Value callbackValue = arrays[arrays.length - 1]; 2747 2748 Callback cmp; 2749 2750 try { 2751 cmp = env.createCallback(callbackValue); 2752 } 2753 catch (Throwable t) { 2754 log.log(Level.WARNING, t.toString(), t); 2755 2756 env.warning("Not a valid callback " + callbackValue.toString()); 2757 2758 return NullValue.NULL; 2759 } 2760 2761 if (cmp == null) { 2762 env.warning("Not a valid callback " + callbackValue.toString()); 2763 2764 return NullValue.NULL; 2765 } 2766 2767 ArrayValue diffArray = new ArrayValueImpl(); 2768 2769 boolean isFound = false; 2770 2771 for (Value entryKey : array.keySet()) { 2772 Value entryValue = array.get(entryKey); 2773 2774 for (int k = 1; k < arrays.length - 1 && ! isFound; k++) { 2775 if (! (arrays[k] instanceof ArrayValue)) { 2776 env.warning("Argument #" + (k + 1) + " is not an array"); 2777 2778 return NullValue.NULL; 2779 } 2780 2781 ArrayValue checkArray = (ArrayValue) arrays[k]; 2782 2783 for (Map.Entry <Value, Value> entry : checkArray.entrySet()) { 2784 try { 2785 boolean keyFound = entryKey.eql(entry.getKey()); 2786 2787 boolean valueFound = false; 2788 2789 if (keyFound) 2790 valueFound = cmp.call(env, entryValue, entry.getValue()) 2791 .toLong() == 0; 2792 2793 isFound = keyFound && valueFound; 2794 } 2795 catch (Throwable t) { 2796 log.log(Level.WARNING, t.toString(), t); 2797 2798 env.warning("An error occurred while invoking the filter callback"); 2799 2800 return NullValue.NULL; 2801 } 2802 2803 if (isFound) 2804 break; 2805 } 2806 } 2807 2808 if (! isFound) 2809 diffArray.put(entryKey, entryValue); 2810 2811 isFound = false; 2812 } 2813 2814 return diffArray; 2815 } 2816 2817 2828 public Value array_udiff_uassoc(Env env, Value[] arrays) 2829 { 2830 if (arrays.length < 4) { 2831 env.warning("Wrong paremeter count for array_udiff_uassoc()"); 2832 2833 return NullValue.NULL; 2834 } 2835 2836 if (! (arrays[0] instanceof ArrayValue)) { 2837 env.warning("Argument #1 is not an array"); 2838 2839 return NullValue.NULL; 2840 } 2841 2842 ArrayValue array = (ArrayValue) arrays[0]; 2843 2844 Value callbackValue = arrays[arrays.length - 2]; 2845 2846 Callback cmpValue; 2847 2848 try { 2849 cmpValue = env.createCallback(callbackValue); 2850 } 2851 catch (Throwable t) { 2852 log.log(Level.WARNING, t.toString(), t); 2853 2854 env.warning("Not a valid callback " + callbackValue.toString()); 2855 2856 return NullValue.NULL; 2857 } 2858 2859 if (cmpValue == null) { 2860 env.warning("Not a valid callback " + callbackValue.toString()); 2861 2862 return NullValue.NULL; 2863 } 2864 2865 Value callbackKey = arrays[arrays.length - 1]; 2866 2867 Callback cmpKey; 2868 2869 try { 2870 cmpKey = env.createCallback(callbackKey); 2871 } 2872 catch (Throwable t) { 2873 log.log(Level.WARNING, t.toString(), t); 2874 2875 env.warning("Not a valid callback " + callbackKey.toString()); 2876 2877 return NullValue.NULL; 2878 } 2879 2880 if (cmpKey == null) { 2881 env.warning("Not a valid callback " + callbackKey.toString()); 2882 2883 return NullValue.NULL; 2884 } 2885 2886 ArrayValue diffArray = new ArrayValueImpl(); 2887 2888 boolean isFound = false; 2889 2890 for (Value entryKey : array.keySet()) { 2891 Value entryValue = array.get(entryKey); 2892 2893 for (int k = 1; k < arrays.length - 2 && ! isFound; k++) { 2894 if (! (arrays[k] instanceof ArrayValue)) { 2895 env.warning("Argument #" + (k + 1) + " is not an array"); 2896 2897 return NullValue.NULL; 2898 } 2899 2900 ArrayValue checkArray = (ArrayValue) arrays[k]; 2901 2902 for (Map.Entry <Value, Value> entry : checkArray.entrySet()) { 2903 try { 2904 boolean valueFound = 2905 cmpValue.call(env, entryValue, entry.getValue()).toLong() == 0; 2906 2907 boolean keyFound = false; 2908 2909 if (valueFound) 2910 keyFound = cmpKey.call(env, entryKey, entry.getKey()).toLong() == 2911 0; 2912 2913 isFound = valueFound && keyFound; 2914 } 2915 catch (Throwable t) { 2916 log.log(Level.WARNING, t.toString(), t); 2917 2918 env.warning("An error occurred while invoking the filter callback"); 2919 2920 return NullValue.NULL; 2921 } 2922 2923 if (isFound) 2924 break; 2925 } 2926 } 2927 2928 if (! isFound) 2929 diffArray.put(entryKey, entryValue); 2930 2931 isFound = false; 2932 } 2933 2934 return diffArray; 2935 } 2936 2937 2947 public Value array_uintersect(Env env, Value[] arrays) 2948 { 2949 if (arrays.length < 3) { 2950 env.warning("Wrong paremeter count for array_uintersect()"); 2951 2952 return NullValue.NULL; 2953 } 2954 2955 if (! (arrays[0] instanceof ArrayValue)) { 2956 env.warning("Argument #1 is not an array"); 2957 2958 return NullValue.NULL; 2959 } 2960 2961 ArrayValue array = (ArrayValue) arrays[0]; 2962 2963 Value callbackValue = arrays[arrays.length - 1]; 2964 2965 Callback cmp; 2966 2967 try { 2968 cmp = env.createCallback(callbackValue); 2969 } 2970 catch (Throwable t) { 2971 log.log(Level.WARNING, t.toString(), t); 2972 2973 env.warning("Not a valid callback " + callbackValue.toString()); 2974 2975 return NullValue.NULL; 2976 } 2977 2978 if (cmp == null) { 2979 env.warning("Not a valid callback " + callbackValue.toString()); 2980 2981 return NullValue.NULL; 2982 } 2983 2984 ArrayValue interArray = new ArrayValueImpl(); 2985 2986 boolean isFound = true; 2987 2988 for (Value entryKey : array.keySet()) { 2989 Value entryValue = array.get(entryKey); 2990 2991 for (int k = 1; k < arrays.length - 1 && isFound; k++) { 2992 if (! (arrays[k] instanceof ArrayValue)) { 2993 env.warning("Argument #" + (k + 1) + " is not an array"); 2994 2995 return NullValue.NULL; 2996 } 2997 2998 ArrayValue checkArray = (ArrayValue) arrays[k]; 2999 3000 for (Map.Entry <Value, Value> entry : checkArray.entrySet()) { 3001 try { 3002 isFound = cmp.call(env, entryValue, entry.getValue()).toLong() == 0; 3003 } 3004 catch (Throwable t) { 3005 log.log(Level.WARNING, t.toString(), t); 3006 3007 env.warning("An error occurred while invoking the filter callback"); 3008 3009 return NullValue.NULL; 3010 } 3011 3012 if (isFound) 3013 break; 3014 } 3015 } 3016 3017 if (isFound) 3018 interArray.put(entryKey, entryValue); 3019 } 3020 3021 return interArray; 3022 } 3023 3024 3035 public Value array_uintersect_assoc(Env env, Value[] arrays) 3036 { 3037 if (arrays.length < 3) { 3038 env.warning("Wrong paremeter count for array_uintersect_assoc()"); 3039 3040 return NullValue.NULL; 3041 } 3042 3043 if (! (arrays[0] instanceof ArrayValue)) { 3044 env.warning("Argument #1 is not an array"); 3045 3046 return NullValue.NULL; 3047 } 3048 3049 ArrayValue array = (ArrayValue) arrays[0]; 3050 3051 Value callbackValue = arrays[arrays.length - 1]; 3052 3053 Callback cmp; 3054 3055 try { 3056 cmp = env.createCallback(callbackValue); 3057 } 3058 catch (Throwable t) { 3059 log.log(Level.WARNING, t.toString(), t); 3060 3061 env.warning("Not a valid callback " + callbackValue.toString()); 3062 3063 return NullValue.NULL; 3064 } 3065 3066 if (cmp == null) { 3067 env.warning("Not a valid callback " + callbackValue.toString()); 3068 3069 return NullValue.NULL; 3070 } 3071 3072 ArrayValue interArray = new ArrayValueImpl(); 3073 3074 boolean isFound = true; 3075 3076 for (Value entryKey : array.keySet()) { 3077 Value entryValue = array.get(entryKey); 3078 3079 for (int k = 1; k < arrays.length - 1 && isFound; k++) { 3080 if (! (arrays[k] instanceof ArrayValue)) { 3081 env.warning("Argument #" + (k + 1) + " is not an array"); 3082 3083 return NullValue.NULL; 3084 } 3085 3086 ArrayValue checkArray = (ArrayValue) arrays[k]; 3087 3088 for (Map.Entry <Value, Value> entry : checkArray.entrySet()) { 3089 try { 3090 boolean keyFound = entryKey.eql(entry.getKey()); 3091 3092 boolean valueFound = false; 3093 3094 if (keyFound) 3095 valueFound = cmp.call(env, entryValue, entry.getValue()) 3096 .toLong() == 0; 3097 3098 isFound = keyFound && valueFound; 3099 } 3100 catch (Throwable t) { 3101 log.log(Level.WARNING, t.toString(), t); 3102 3103 env.warning("An error occurred while invoking the filter callback"); 3104 3105 return NullValue.NULL; 3106 } 3107 3108 if (isFound) 3109 break; 3110 } 3111 } 3112 3113 if (isFound) 3114 interArray.put(entryKey, entryValue); 3115 } 3116 3117 return interArray; 3118 } 3119 3120 3131 public Value array_uintersect_uassoc(Env env, Value[] arrays) 3132 { 3133 if (arrays.length < 4) { 3134 env.warning("Wrong paremeter count for array_uintersect_uassoc()"); 3135 3136 return NullValue.NULL; 3137 } 3138 3139 if (! (arrays[0] instanceof ArrayValue)) { 3140 env.warning("Argument #1 is not an array"); 3141 3142 return NullValue.NULL; 3143 } 3144 3145 ArrayValue array = (ArrayValue) arrays[0]; 3146 3147 Value callbackValue = arrays[arrays.length - 2]; 3148 3149 Callback cmpValue; 3150 3151 try { 3152 cmpValue = env.createCallback(callbackValue); 3153 } 3154 catch (Throwable t) { 3155 log.log(Level.WARNING, t.toString(), t); 3156 3157 env.warning("Not a valid callback " + callbackValue.toString()); 3158 3159 return NullValue.NULL; 3160 } 3161 3162 if (cmpValue == null) { 3163 env.warning("Not a valid callback " + callbackValue.toString()); 3164 3165 return NullValue.NULL; 3166 } 3167 3168 Value callbackKey = arrays[arrays.length - 1]; 3169 3170 Callback cmpKey; 3171 3172 try { 3173 cmpKey = env.createCallback(callbackKey); 3174 } 3175 catch (Throwable t) { 3176 log.log(Level.WARNING, t.toString(), t); 3177 3178 env.warning("Not a valid callback " + callbackKey.toString()); 3179 3180 return NullValue.NULL; 3181 } 3182 3183 if (cmpKey == null) { 3184 env.warning("Not a valid callback " + callbackKey.toString()); 3185 3186 return NullValue.NULL; 3187 } 3188 3189 ArrayValue interArray = new ArrayValueImpl(); 3190 3191 boolean isFound = true; 3192 3193 for (Value entryKey : array.keySet()) { 3194 Value entryValue = array.get(entryKey); 3195 3196 for (int k = 1; k < arrays.length - 2 && isFound; k++) { 3197 if (! (arrays[k] instanceof ArrayValue)) { 3198 env.warning("Argument #" + (k + 1) + " is not an array"); 3199 3200 return NullValue.NULL; 3201 } 3202 3203 ArrayValue checkArray = (ArrayValue) arrays[k]; 3204 3205 for (Map.Entry <Value, Value> entry : checkArray.entrySet()) { 3206 try { 3207 boolean valueFound = 3208 cmpValue.call(env, entryValue, entry.getValue()).toLong() == 0; 3209 3210 boolean keyFound = false; 3211 3212 if (valueFound) 3213 keyFound = cmpKey.call(env, entryKey, entry.getKey()).toLong() == 3214 0; 3215 3216 isFound = valueFound && keyFound; 3217 } 3218 catch (Throwable t) { 3219 log.log(Level.WARNING, t.toString(), t); 3220 3221 env.warning("An error occurred while invoking the filter callback"); 3222 3223 return NullValue.NULL; 3224 } 3225 3226 if (isFound) 3227 break; 3228 } 3229 } 3230 3231 if (isFound) 3232 interArray.put(entryKey, entryValue); 3233 } 3234 3235 return interArray; 3236 } 3237 3238 3246 @UsesSymbolTable 3247 public ArrayValue compact(Env env, Value[] variables) 3248 { 3249 ArrayValue compactArray = new ArrayValueImpl(); 3250 3251 for (Value variableName : variables) { 3252 if (variableName instanceof StringValue) { 3253 Value tableValue = env.getValue(variableName.toString()); 3254 3255 if (tableValue.isset()) 3256 compactArray.put(variableName, tableValue); 3257 } 3258 else if (variableName instanceof ArrayValue) { 3259 ArrayValue array = (ArrayValue) variableName; 3260 3261 ArrayValue innerArray = compact(env, array.valuesToArray()); 3262 3263 compactArray.putAll(innerArray); 3264 } 3265 } 3266 3267 return compactArray; 3268 } 3269 3270 3273 public static Value sizeof(@ReadOnly Value value) 3274 { 3275 return count(value); 3276 } 3277 3278 private static class CompareString 3279 implements 3280 Comparator<Map.Entry <Value, Value>> 3281 { 3282 private AbstractGet _getter; 3283 3284 private int _order; 3285 3286 CompareString(AbstractGet getter, int order) 3287 { 3288 _getter = getter; 3289 _order = order; 3290 } 3291 3292 public int compare(Map.Entry <Value, Value> aEntry, 3293 Map.Entry <Value, Value> bEntry) 3294 { 3295 String aElement = _getter.get(aEntry).toString(); 3296 String bElement = _getter.get(bEntry).toString(); 3297 3298 return aElement.compareTo(bElement) * _order; 3299 } 3300 } 3301 3302 private static class CompareNumeric 3303 implements 3304 Comparator<Map.Entry <Value, Value>> 3305 { 3306 private AbstractGet _getter; 3307 3308 private int _order; 3309 3310 CompareNumeric(AbstractGet getter, int order) 3311 { 3312 _getter = getter; 3313 _order = order; 3314 } 3315 3316 public int compare(Map.Entry <Value, Value> aEntry, 3317 Map.Entry <Value, Value> bEntry) 3318 { 3319 try { 3320 long aElement = _getter.get(aEntry).toLong(); 3321 long bElement = _getter.get(bEntry).toLong(); 3322 3323 if (aElement == bElement) 3324 return 0; 3325 else if (aElement < bElement) 3326 return -1 * _order; 3327 else 3328 return _order; 3329 } 3330 catch (Throwable e) { 3331 throw new RuntimeException (e); 3332 } 3333 } 3334 } 3335 3336 private static class CompareLocale 3337 implements 3338 Comparator<Map.Entry <Value, Value>> 3339 { 3340 private AbstractGet _getter; 3341 3342 private int _order; 3343 3344 private Collator _collator; 3345 3346 CompareLocale(AbstractGet getter, int order, Collator collator) 3347 { 3348 _getter = getter; 3349 _order = order; 3350 _collator = collator; 3351 } 3352 3353 public int compare(Map.Entry <Value, Value> aEntry, 3354 Map.Entry <Value, Value> bEntry) 3355 { 3356 String aElement = _getter.get(aEntry).toString(); 3357 String bElement = _getter.get(bEntry).toString(); 3358 3359 return _collator.compare(aElement, bElement) * _order; 3360 } 3361 } 3362 3363 private static class CompareNormal 3364 implements Comparator<Map.Entry <Value, Value>> 3365 { 3366 private AbstractGet _getter; 3367 3368 private int _order; 3369 3370 CompareNormal(AbstractGet getter, int order) 3371 { 3372 _getter = getter; 3373 _order = order; 3374 } 3375 3376 public int compare(Map.Entry <Value, Value> aEntry, 3377 Map.Entry <Value, Value> bEntry) 3378 { 3379 if (_getter instanceof GetKey) { 3380 KeyComparator k = KeyComparator.CMP; 3381 3382 return k.compare(aEntry, bEntry) * _order; 3383 } 3384 3385 ValueComparator c = ValueComparator.CMP; 3386 3387 return c.compare(aEntry, bEntry) * _order; 3388 } 3389 } 3390 3391 private static class CompareNatural 3392 implements 3393 Comparator<Map.Entry <Value, Value>> 3394 { 3395 private AbstractGet _getter; 3396 3397 private int _order; 3398 3399 private boolean _isCaseSensitive; 3400 3401 CompareNatural(AbstractGet getter, int order, boolean isCaseSensitive) 3402 { 3403 _getter = getter; 3404 _order = order; 3405 _isCaseSensitive = isCaseSensitive; 3406 } 3407 3408 public int compare(Map.Entry <Value, Value> aEntry, 3409 Map.Entry <Value, Value> bEntry) 3410 { 3411 try { 3412 String aElement = _getter.get(aEntry).toString(); 3413 String bElement = _getter.get(bEntry).toString(); 3414 3415 if (! _isCaseSensitive) { 3416 aElement = aElement.toLowerCase(); 3417 bElement = bElement.toLowerCase(); 3418 } 3419 3420 StringParser aParser = new StringParser(aElement); 3421 StringParser bParser = new StringParser(bElement); 3422 3423 while (aParser.hasNext() && bParser.hasNext()) { 3424 String aPart = aParser.next(); 3425 String bPart = bParser.next(); 3426 3427 int comparison; 3428 3429 try { 3430 Long aLong = Long.valueOf(aPart); 3431 Long bLong = Long.valueOf(bPart); 3432 3433 comparison = aLong.compareTo(bLong); 3434 } 3435 catch (NumberFormatException e) { 3436 comparison = aPart.compareTo(bPart); 3437 } 3438 3439 if (comparison < 0) 3440 return -1; 3441 else if (comparison > 0) 3442 return 1; 3443 } 3444 3445 if (bParser.hasNext()) 3446 return 1; 3447 else if (aParser.hasNext()) 3448 return -1; 3449 else 3450 return 0; 3451 3452 } 3453 catch (Throwable e) { 3454 throw new RuntimeException (e); 3455 } 3456 } 3457 } 3458 3459 private static class CompareCallBack 3460 implements Comparator<Map.Entry <Value, Value>> 3461 { 3462 private AbstractGet _getter; 3463 3464 private int _order; 3465 3466 private Callback _func; 3467 3468 private Env _env; 3469 3470 CompareCallBack(AbstractGet getter, int order, Callback func, 3471 Env env) 3472 { 3473 _getter = getter; 3474 _order = order; 3475 _func = func; 3476 _env = env; 3477 } 3478 3479 public int compare(Map.Entry <Value, Value> aEntry, 3480 Map.Entry <Value, Value> bEntry) 3481 { 3482 try { 3483 Value aElement = _getter.get(aEntry); 3484 Value bElement = _getter.get(bEntry); 3485 3486 return (int) _func.call(_env, aElement, bElement).toLong(); 3487 } 3488 catch (Exception e) { 3489 throw new QuercusModuleException(e); 3490 } 3491 } 3492 } 3493 3494 3498 private static class MultiSortComparator 3499 implements Comparator<LongValue> 3500 { 3501 3502 private final Env _env; 3503 private final Value[] _arrays; 3504 3505 public MultiSortComparator(Env env, Value[] arrays) 3506 { 3507 this._env = env; 3508 this._arrays = arrays; 3509 } 3510 3511 3516 public int compare(LongValue index1, LongValue index2) 3517 { 3518 for(int i=0; i<_arrays.length; i++) { 3519 3520 int direction = SORT_ASC; 3522 int mode = SORT_REGULAR; 3523 ArrayValue av = (ArrayValue)_arrays[i]; 3524 3525 while((i+1)<_arrays.length && _arrays[i+1] instanceof LongValue) { 3527 switch(_arrays[++i].toInt()) { 3528 case SORT_ASC: direction = SORT_ASC; break; 3529 case SORT_DESC: direction = SORT_DESC; break; 3530 case SORT_REGULAR: mode = SORT_REGULAR; break; 3531 case SORT_STRING: mode = SORT_STRING; break; 3532 case SORT_NUMERIC: mode = SORT_NUMERIC; break; 3533 default: _env.warning("Unknown sort flag: " + _arrays[i]); 3534 } 3535 } 3536 3537 Value v1 = av.get(index1); 3538 Value v2 = av.get(index2); 3539 3540 if (mode==SORT_STRING) { 3541 v1 = v1.toStringValue(); 3542 v2 = v2.toStringValue(); 3543 } else if (mode==SORT_NUMERIC) { 3544 v1 = LongValue.create(v1.toLong()); 3545 v2 = LongValue.create(v2.toLong()); 3546 } 3547 3548 if (v1.lt(v2)) return direction==SORT_ASC ? -1 : 1; 3549 if (v1.gt(v2)) return direction==SORT_ASC ? 1 : -1; 3550 3551 } 3552 return 0; 3553 } 3554 } 3555 3556 private static class StringParser { 3557 private int _current; 3558 private int _length; 3559 3560 private String _string; 3561 3562 private static final int SYMBOL = 1; 3563 private static final int LETTER = 2; 3564 private static final int DIGIT = 3; 3565 3566 StringParser(String string) 3567 { 3568 _string = string; 3569 _length = string.length(); 3570 _current = 0; 3571 } 3572 3573 public boolean hasNext() 3574 { 3575 return _current < _length; 3576 } 3577 3578 public String next() 3579 { 3580 int start; 3581 int type; 3582 3583 try { 3584 char character = _string.charAt(_current); 3585 3586 if (character == '0') { 3587 _current++; 3588 return "0"; 3589 } 3590 else if (Character.isLetter(character)) 3591 type = LETTER; 3592 else if (Character.isDigit(character)) 3593 type = DIGIT; 3594 else 3595 type = SYMBOL; 3596 3597 for (start = _current; _current < _length; _current++) { 3598 if (type == LETTER && Character.isLetter(_string.charAt(_current))) 3599 { 3600 } 3601 else if (type == DIGIT && Character.isDigit(_string.charAt(_current))) 3602 { 3603 } 3604 else if (type == SYMBOL && 3605 !Character.isLetterOrDigit(_string.charAt(_current))) { 3606 } 3607 else 3608 break; 3609 } 3610 3611 return _string.substring(start, _current); 3612 } 3613 catch (Exception e) { 3614 log.log(Level.WARNING, e.toString(), e); 3615 return null; 3616 } 3617 } 3618 } 3619} 3620 | Popular Tags |