this repo has no description
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at fixPythonPipStalling 1277 lines 28 kB view raw
1/* 2This file is part of Darling. 3 4Copyright (C) 2017 Lubos Dolezel 5 6Darling is free software: you can redistribute it and/or modify 7it under the terms of the GNU General Public License as published by 8the Free Software Foundation, either version 3 of the License, or 9(at your option) any later version. 10 11Darling is distributed in the hope that it will be useful, 12but WITHOUT ANY WARRANTY; without even the implied warranty of 13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14GNU General Public License for more details. 15 16You should have received a copy of the GNU General Public License 17along with Darling. If not, see <http://www.gnu.org/licenses/>. 18*/ 19 20#include <stdlib.h> 21#include <stdio.h> 22#include <CoreFoundation/CoreFoundation.h> 23#include <stdbool.h> 24 25bool processArgs(int argc, const char** argv, const char** command); 26void resolvePlistEntry(const char* whatStr, CFPropertyListRef* parent, CFPropertyListRef* entry, char** last, bool autoCreate); 27void setEntry(const char* entryName, const char* entryValue); 28void printUsage(void); 29void printHelp(void); 30bool revertToFile(void); 31bool saveToFile(void); 32void runCommand(const char* cmd); 33void doPrint(const char* what); 34 35enum PropertyType { 36 typeUnknown = 0, typeString, typeArray, typeDict, typeBool, typeReal, typeInteger, typeDate, typeData 37}; 38void addEntry(const char* entry, enum PropertyType type, const char* value); 39CFPropertyListRef parseValue(enum PropertyType type, const char* string); 40void deleteEntry(const char* entry); 41void copyEntry(const char* src, const char* dst); 42void mergeFile(const char* path, const char* entry); 43void importFile(const char* entry, const char* path); 44 45// Forces XML output when printing to screen 46bool forceXML = false; 47CFPropertyListRef plist = NULL; 48const char* outputFile = NULL; 49 50int main(int argc, const char **argv) 51{ 52 const char* command = NULL; 53 54 if (!processArgs(argc, argv, &command)) 55 { 56 printUsage(); 57 return 1; 58 } 59 if (!outputFile) 60 return 0; 61 62 if (!revertToFile()) 63 return 1; 64 65 if (command != NULL) 66 { 67 runCommand(command); 68 if (!saveToFile()) 69 return 1; 70 } 71 else 72 { 73 while (true) 74 { 75 char buffer[200]; 76 77 printf("Command: "); 78 79 if (!fgets(buffer, sizeof(buffer), stdin)) 80 break; 81 82 size_t len = strlen(buffer); 83 if (buffer[len-1] == '\n') 84 buffer[len-1] = '\0'; 85 runCommand(buffer); 86 } 87 } 88 89 return EXIT_SUCCESS; 90} 91 92void printUsage() 93{ 94 puts("Usage: PlistBuddy [-cxh] <file.plist>\n" 95 " -c \"<command>\" execute command, otherwise run in interactive mode\n" 96 " -x output will be in the form of an xml plist where appropriate\n" 97 " -h print the complete help info, with command guide\n"); 98} 99 100void printHelp() 101{ 102 puts("Command Format:\n\n" 103 " Help - Prints this information\n" 104 " Exit - Exits the program, changes are not saved to the file\n" 105 " Save - Saves the current changes to the file\n" 106 " Revert - Reloads the last saved version of the file\n" 107 " Clear [<Type>] - Clears out all existing entries, and creates root of Type\n" 108 " Print [<Entry>] - Prints value of Entry. Otherwise, prints file\n" 109 " Set <Entry> <Value> - Sets the value at Entry to Value\n" 110 " Add <Entry> <Type> [<Value>] - Adds Entry to the plist, with value Value\n" 111 " Copy <EntrySrc> <EntryDst> - Copies the EntrySrc property to EntryDst\n" 112 " Delete <Entry> - Deletes Entry from the plist\n" 113 " Merge <file.plist> [<Entry>] - Adds the contents of file.plist to Entry\n" 114 " Import <Entry> <file> - Creates or sets Entry the contents of file\n" 115 "\n" 116 "Entry Format:\n" 117 " Entries consist of property key names delimited by colons. Array items\n" 118 " are specified by a zero-based integer index. Examples:\n" 119 " :CFBundleShortVersionString\n" 120 " :CFBundleDocumentTypes:2:CFBundleTypeExtensions\n" 121 "\n" 122 "Types:\n" 123 " string\n" 124 " array\n" 125 " dict\n" 126 " bool\n" 127 " real\n" 128 " integer\n" 129 " date\n" 130 " data\n" 131 "\n" 132 "Examples:\n" 133 " Set :CFBundleIdentifier com.apple.plistbuddy\n" 134 " Sets the CFBundleIdentifier property to com.apple.plistbuddy\n" 135 " Add :CFBundleGetInfoString string \"App version 1.0.1\"\n" 136 " Adds the CFBundleGetInfoString property to the plist\n" 137 " Add :CFBundleDocumentTypes: dict\n" 138 " Adds a new item of type dict to the CFBundleDocumentTypes array\n" 139 " Add :CFBundleDocumentTypes:0 dict\n" 140 " Adds the new item to the beginning of the array\n" 141 " Delete :CFBundleDocumentTypes:0 dict\n" 142 " Deletes the FIRST item in the array\n" 143 " Delete :CFBundleDocumentTypes\n" 144 " Deletes the ENTIRE CFBundleDocumentTypes array\n"); 145} 146 147bool processArgs(int argc, const char** argv, const char** command) 148{ 149 if (argc <= 1) 150 return false; 151 152 for (int i = 1; i < argc; i++) 153 { 154 if (strcmp(argv[i], "-c") == 0) 155 { 156 if (i+1 >= argc) 157 return false; 158 *command = argv[++i]; 159 } 160 else if (strcmp(argv[i], "-x") == 0) 161 { 162 forceXML = true; 163 } 164 else if (strcmp(argv[i], "-h") == 0) 165 { 166 printHelp(); 167 return true; 168 } 169 else if (i+1 >= argc) 170 { 171 outputFile = argv[i]; 172 } 173 else 174 { 175 puts("Invalid Arguments"); 176 exit(1); 177 } 178 } 179 180 return outputFile != NULL; 181} 182 183CFPropertyListRef loadPlist(const char* filePath) 184{ 185 SInt32 errorCode = 0; 186 CFStringRef errorString = NULL; 187 CFDataRef data = NULL; 188 CFPropertyListRef plist; 189 CFStringRef path = CFStringCreateWithCString(kCFAllocatorDefault, filePath, kCFStringEncodingUTF8); 190 CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path, kCFURLPOSIXPathStyle, false); 191 192 CFRelease(path); 193 194 CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, url, &data, NULL, NULL, &errorCode); 195 CFRelease(url); 196 197 if (errorCode != 0) 198 { 199 printf("Error Reading File: %s\n", filePath); 200 return false; 201 } 202 203 plist = CFPropertyListCreateFromXMLData(kCFAllocatorDefault, data, kCFPropertyListMutableContainers, &errorString); 204 205 if (errorString != NULL) 206 { 207 CFShow(errorString); 208 CFRelease(errorString); 209 210 printf("Error Reading File: %s\n", filePath); 211 } 212 213 return plist; 214} 215 216bool revertToFile(void) 217{ 218 if (plist != NULL) 219 CFRelease(plist); 220 221 if (access(outputFile, F_OK) != 0) 222 { 223 printf("File Doesn't Exist, Will Create: %s\n", outputFile); 224 plist = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 225 return true; 226 } 227 else 228 { 229 bool rv; 230 231 plist = loadPlist(outputFile); 232 rv = plist != NULL; 233 234 if (plist == NULL) 235 plist = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 236 237 return rv; 238 } 239} 240 241bool saveToFile(void) 242{ 243 bool rv = true; 244 CFDataRef data; 245 CFStringRef path = CFStringCreateWithCString(kCFAllocatorDefault, outputFile, kCFStringEncodingUTF8); 246 CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path, kCFURLPOSIXPathStyle, false); 247 248 CFRelease(path); 249 250 data = CFPropertyListCreateXMLData(kCFAllocatorDefault, plist); 251 if (data != NULL) 252 { 253 SInt32 errorCode = 0; 254 255 CFURLWriteDataAndPropertiesToResource(url, data, NULL, &errorCode); 256 CFRelease(data); 257 258 if (errorCode != 0) 259 { 260 puts("Cannot Write File"); 261 rv = false; 262 } 263 } 264 else 265 { 266 puts("Cannot Format Plist"); 267 rv = false; 268 } 269 270 CFRelease(url); 271 return rv; 272} 273 274static const char* nextWord(const char* input) 275{ 276 int i; 277 278 for (i = 0; isspace(input[i]) && input[i] != '\0'; i++) 279 ; 280 281 if (input[i]) 282 return &input[i]; 283 else 284 return NULL; 285} 286 287bool isCommand(const char* input, const char* cmd, const char** next) 288{ 289 size_t len = strlen(cmd); 290 291 if (strncasecmp(input, cmd, len) == 0 && (input[len] == ' ' || input[len] == '\0')) 292 { 293 if (next != NULL) 294 *next = nextWord(input + len); 295 return true; 296 } 297 else 298 return false; 299} 300 301static enum PropertyType parseType(const char* type) 302{ 303 if (strcasecmp(type, "string") == 0) 304 return typeString; 305 else if (strcasecmp(type, "array") == 0) 306 return typeArray; 307 else if (strcasecmp(type, "dict") == 0) 308 return typeDict; 309 else if (strcasecmp(type, "bool") == 0) 310 return typeBool; 311 else if (strcasecmp(type, "real") == 0) 312 return typeReal; 313 else if (strcasecmp(type, "integer") == 0) 314 return typeInteger; 315 else if (strcasecmp(type, "date") == 0) 316 return typeDate; 317 else if (strcasecmp(type, "data") == 0) 318 return typeData; 319 else 320 { 321 printf("Unrecognized Type: %s\n", type); 322 return typeUnknown; 323 } 324} 325 326static enum PropertyType inferType(CFPropertyListRef obj) 327{ 328 CFTypeID typeId = CFGetTypeID(obj); 329 330 if (typeId == CFStringGetTypeID()) 331 return typeString; 332 else if (typeId == CFArrayGetTypeID()) 333 return typeArray; 334 else if (typeId == CFDictionaryGetTypeID()) 335 return typeDict; 336 else if (typeId == CFBooleanGetTypeID()) 337 return typeBool; 338 else if (typeId == CFNumberGetTypeID()) 339 { 340 if (CFNumberIsFloatType((CFNumberRef) obj)) 341 return typeReal; 342 else 343 return typeInteger; 344 } 345 else if (typeId == CFDateGetTypeID()) 346 return typeDate; 347 else if (typeId == CFDataGetTypeID()) 348 return typeData; 349 else 350 return typeUnknown; 351} 352 353char* getWord(const char* cmd, const char** next) 354{ 355 if (cmd[0] == '"') 356 { 357 int i = 1, j = 0; 358 char* out = strdup(cmd); 359 360 for (; cmd[i] != '\0'; i++) 361 { 362 if (cmd[i] == '\\' && cmd[i+1] != '\0') 363 { 364 i++; 365 switch (cmd[i]) 366 { 367 case '"': 368 out[j++] = '"'; 369 break; 370 case 'n': 371 out[j++] = '\n'; 372 break; 373 case 't': 374 out[j++] = '\t'; 375 break; 376 default: 377 out[j++] = '\\'; 378 out[j++] = cmd[i]; 379 } 380 } 381 else if (cmd[i] == '"') 382 { 383 out[j++] = '\0'; 384 break; 385 } 386 else 387 { 388 out[j++] = cmd[i]; 389 } 390 } 391 392 if (j > 0 && out[j-1] != '\0') 393 { 394 free(out); 395 puts("Unterminated Quotes"); 396 return NULL; 397 } 398 if (next) 399 *next = nextWord(cmd + i + 1); 400 401 return out; 402 } 403 else 404 { 405 char* p = strchr(cmd, ' '); 406 if (p == NULL) 407 { 408 if (next) 409 *next = NULL; 410 return strdup(cmd); 411 } 412 else 413 { 414 char* rv = strndup(cmd, p-cmd); 415 if (next) 416 *next = nextWord(p); 417 return rv; 418 } 419 } 420} 421 422void runCommand(const char* cmd) 423{ 424 const char* next = NULL; 425 426 if (isCommand(cmd, "Exit", NULL) || isCommand(cmd, "Quit", NULL) || isCommand(cmd, "Bye", NULL)) 427 { 428 exit(0); 429 } 430 else if (isCommand(cmd, "Help", NULL)) 431 { 432 printHelp(); 433 } 434 else if (isCommand(cmd, "Save", &next)) 435 { 436 puts("Saving..."); 437 saveToFile(); 438 } 439 else if (isCommand(cmd, "Revert", NULL)) 440 { 441 puts("Reverting to last saved state..."); 442 revertToFile(); 443 } 444 else if (isCommand(cmd, "Print", &next) || isCommand(cmd, "ls", &next)) 445 { 446 doPrint(next); 447 } 448 else if (isCommand(cmd, "Clear", &next)) 449 { 450 enum PropertyType type = typeUnknown; 451 if (next != NULL) 452 type = parseType(next); 453 if (type == typeUnknown) 454 type = typeDict; 455 } 456 else if (isCommand(cmd, "Set", &next) || isCommand(cmd, "=", &next)) 457 { 458 // entry value 459 if (!next) 460 { 461 puts("Missing arguments"); 462 return; 463 } 464 465 char* entry = getWord(next, &next); 466 467 if (!next) 468 next = ""; 469 470 setEntry(entry, next); 471 472 free(entry); 473 } 474 else if (isCommand(cmd, "Add", &next) || isCommand(cmd, "+", &next)) 475 { 476 // entry type [value] 477 if (!next) 478 { 479 puts("Missing arguments"); 480 return; 481 } 482 483 char* entry = getWord(next, &next); 484 485 if (!next) 486 { 487 free(entry); 488 puts("Missing arguments"); 489 return; 490 } 491 492 char* type = getWord(next, &next); 493 enum PropertyType typeV = parseType(type); 494 495 if (typeV == typeUnknown) 496 { 497 free(entry); 498 free(type); 499 return; 500 } 501 502 if (!next) 503 next = ""; 504 505 addEntry(entry, typeV, next); 506 507 free(entry); 508 free(type); 509 } 510 else if (isCommand(cmd, "Copy", &next) || isCommand(cmd, "cp", &next)) 511 { 512 // entrySrc entryDst 513 if (!next) 514 { 515 puts("Missing arguments"); 516 return; 517 } 518 519 char* src = getWord(next, &next); 520 if (!next) 521 { 522 puts("Missing arguments"); 523 return; 524 } 525 526 char* dst = getWord(next, NULL); 527 528 copyEntry(src, dst); 529 530 free(src); 531 free(dst); 532 } 533 else if (isCommand(cmd, "Delete", &next) || isCommand(cmd, "rm", &next) || isCommand(cmd, "-", &next)) 534 { 535 // entry 536 if (!next) 537 { 538 puts("Missing arguments"); 539 return; 540 } 541 542 deleteEntry(next); 543 } 544 else if (isCommand(cmd, "Merge", &next)) 545 { 546 // file.plist [entryDst] 547 if (!next) 548 { 549 puts("Missing arguments"); 550 return; 551 } 552 553 char* path = getWord(next, &next); 554 555 mergeFile(path, next); 556 free(path); 557 } 558 else if (isCommand(cmd, "Import", &next)) 559 { 560 // entry file.plist 561 if (!next) 562 { 563 puts("Missing arguments"); 564 return; 565 } 566 char* entry = getWord(next, &next); 567 568 if (!next) 569 { 570 puts("Missing arguments"); 571 free(entry); 572 return; 573 } 574 char* path = getWord(next, &next); 575 576 importFile(entry, path); 577 578 free(path); 579 free(entry); 580 } 581 else 582 { 583 puts("Unrecognized Command"); 584 } 585} 586 587void addEntry(const char* entry, enum PropertyType type, const char* value) 588{ 589 CFPropertyListRef parent, existing; 590 CFPropertyListRef newValue; 591 char* leafName = NULL; 592 CFTypeID parentType; 593 594 // printf("add entry (type %d) with value: %s\n", type, value); 595 596 if (type == typeArray) 597 { 598 newValue = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); 599 } 600 else if (type == typeDict) 601 { 602 newValue = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 603 } 604 else 605 { 606 newValue = parseValue(type, value); 607 if (newValue == NULL) 608 return; 609 } 610 611 resolvePlistEntry(entry, &parent, &existing, &leafName, true); 612 613 if (parent == NULL) 614 { 615 printf("Add: Entry, \"%s\", Does Not Exist\n", entry); 616 free(leafName); 617 return; 618 } 619 620 parentType = CFGetTypeID(parent); 621 622 // in case of arrays, we just insert at given position 623 if (existing != NULL && parentType != CFArrayGetTypeID()) 624 { 625 printf("Add: \"%s\" Entry Already Exists\n", entry); 626 goto out; 627 } 628 629 if (parentType == CFArrayGetTypeID()) 630 { 631 CFMutableArrayRef array = (CFMutableArrayRef) parent; 632 CFIndex index = atoi(leafName); 633 634 if (index < 0) 635 index = 0; 636 else if (index > CFArrayGetCount(array)) 637 index = CFArrayGetCount(array); 638 639 CFArrayInsertValueAtIndex(array, index, newValue); 640 } 641 else if (parentType == CFDictionaryGetTypeID()) 642 { 643 // printf("Add new entry named %s into dict %p, root is %p\n", leafName, parent, plist); 644 CFStringRef key = CFStringCreateWithCString(kCFAllocatorDefault, leafName, kCFStringEncodingUTF8); 645 CFDictionaryAddValue((CFMutableDictionaryRef) parent, key, newValue); 646 CFRelease(key); 647 } 648 else 649 { 650 printf("Add: Can't Add Entry, \"%s\", to Parent\n", entry); 651 } 652 653out: 654 free(leafName); 655 CFRelease(newValue); 656} 657 658CFPropertyListRef parseValue(enum PropertyType type, const char* string) 659{ 660 switch (type) 661 { 662 case typeString: 663 case typeData: 664 { 665 char* stringOut; 666 bool hasQuotes = string[0] == '"'; 667 668 size_t len = strlen(string); 669 size_t i = 0, j = 0; 670 671 if (hasQuotes) 672 { 673 if (string[len-1] != '"') 674 { 675 puts("Parse Error: Unclosed Quotes"); 676 return NULL; 677 } 678 i++; 679 len--; 680 } 681 682 stringOut = (char*) malloc(len+1); 683 684 for (; i < len; i++) 685 { 686 if (string[i] != '\\') 687 { 688 stringOut[j] = string[i]; 689 j++; 690 } 691 else 692 { 693 if (i+1 == len) 694 { 695 free(stringOut); 696 puts("Parse Error: Unclosed Quotes"); 697 return NULL; 698 } 699 700 switch (string[++i]) 701 { 702 case '"': 703 stringOut[j++] = '"'; 704 break; 705 case 'n': 706 stringOut[j++] = '\n'; 707 break; 708 case 't': 709 stringOut[j++] = '\t'; 710 break; 711 default: 712 stringOut[j++] = string[i]; 713 } 714 } 715 } 716 stringOut[j] = '\0'; 717 718 CFPropertyListRef rv; 719 if (type == typeString) 720 rv = CFStringCreateWithCString(kCFAllocatorDefault, stringOut, kCFStringEncodingUTF8); 721 else 722 rv = CFDataCreate(kCFAllocatorDefault, (const UInt8*) string, strlen(string)); 723 724 free(stringOut); 725 return rv; 726 } 727 case typeBool: 728 if (strcasecmp(string, "true") == 0 || strcasecmp(string, "yes") == 0 || strcmp(string, "1") == 0) 729 return kCFBooleanTrue; 730 return kCFBooleanFalse; 731 732 case typeInteger: 733 { 734 char* endptr; 735 long long v; 736 737 v = strtoll(string, &endptr, 0); 738 if (endptr == string) 739 { 740 puts("Unrecognized Integer Format"); 741 return NULL; 742 } 743 744 return CFNumberCreate(kCFAllocatorDefault, kCFNumberLongLongType, &v); 745 } 746 747 case typeReal: 748 { 749 char* endptr; 750 double v; 751 752 v = strtod(string, &endptr); 753 if (endptr == string) 754 { 755 puts("Unrecognized Real Format"); 756 return NULL; 757 } 758 759 return CFNumberCreate(kCFAllocatorDefault, kCFNumberFloat64Type, &v); 760 } 761 case typeDate: 762 { 763 struct tm tm; 764 765 if (!strptime(string, "%a %b %d %H:%M:%S %Z %Y", &tm) 766 && !strptime(string, "%c", &tm) 767 && !strptime(string, "%D", &tm)) 768 { 769 puts("Unrecognized Date Format"); 770 return NULL; 771 } 772 773 CFTimeZoneRef tz = CFTimeZoneCopyDefault(); 774 CFAbsoluteTime at; 775 CFGregorianDate date; 776 777 date.day = tm.tm_mday; 778 date.hour = tm.tm_hour; 779 date.minute = tm.tm_min; 780 date.month = tm.tm_mon + 1; 781 date.second = tm.tm_sec; 782 date.year = tm.tm_year + 1900; 783 784 at = CFGregorianDateGetAbsoluteTime(date, tz); 785 786 CFDateRef rv = CFDateCreate(kCFAllocatorDefault, at); 787 788 CFRelease(tz); 789 return rv; 790 } 791 default: 792 { 793 puts("Cannot parse this entry type"); 794 return NULL; 795 } 796 } 797} 798 799void setEntry(const char* entry, const char* entryValue) 800{ 801 CFPropertyListRef parent, existing; 802 CFPropertyListRef newValue; 803 char* leafName = NULL; 804 enum PropertyType type; 805 806 resolvePlistEntry(entry, &parent, &existing, &leafName, false); 807 if (existing == NULL) 808 { 809 free(leafName); 810 printf("Set: Entry, \"%s\", Does Not Exist\n", entry); 811 return; 812 } 813 814 type = inferType(existing); 815 if (type == typeArray || type == typeDict) 816 { 817 free(leafName); 818 puts("Set: Cannot Perform Set On Containers"); 819 return; 820 } 821 822 newValue = parseValue(type, entryValue); 823 if (newValue == NULL) 824 { 825 free(leafName); 826 return; 827 } 828 829 if (CFGetTypeID(parent) == CFDictionaryGetTypeID()) 830 { 831 CFStringRef leafNameStr = CFStringCreateWithCString(kCFAllocatorDefault, leafName, kCFStringEncodingUTF8); 832 CFDictionaryReplaceValue((CFMutableDictionaryRef) parent, leafNameStr, newValue); 833 CFRelease(leafNameStr); 834 } 835 else 836 { 837 int index = atoi(leafName); 838 839 CFArraySetValueAtIndex((CFMutableArrayRef) parent, index, newValue); 840 } 841 842 free(leafName); 843 CFRelease(newValue); 844} 845 846static const char* strtok_empty(char** pstr, char delim) 847{ 848 char* p; 849 char* str = *pstr; 850 851 if (str == NULL) 852 return NULL; 853 854 while (str[0] == delim) 855 str++; 856 857 if ((p = strchr (str, delim)) != NULL) 858 { 859 *p = '\0'; 860 *pstr = p + 1; 861 } else { 862 *pstr = NULL; 863 } 864 865 return str; 866} 867 868void resolvePlistEntry(const char* whatStr, CFPropertyListRef* parent, CFPropertyListRef* entry, char** last, bool autoCreate) 869{ 870 CFPropertyListRef pos = plist; 871 CFPropertyListRef lastPos = NULL; 872 873 const char *tok, *lastTok = ""; 874 875 // trim head 876 while (whatStr[0] == ':') 877 whatStr++; 878 879 // trim tail 880 size_t len = strlen(whatStr); 881 while(len > 0 && whatStr[len - 1] == ':') { 882 len--; 883 } 884 885 char* whatStr2 = strndup(whatStr, len); 886 char* p = whatStr2; 887 888 while ((tok = strtok_empty(&p, ':')) && pos != NULL) 889 { 890 lastPos = pos; 891 if (*tok) 892 { 893 CFTypeID typeId = CFGetTypeID(pos); 894 895 if (typeId == CFDictionaryGetTypeID()) 896 { 897 CFStringRef key = CFStringCreateWithCString(kCFAllocatorDefault, tok, kCFStringEncodingUTF8); 898 pos = (CFPropertyListRef) CFDictionaryGetValue((CFDictionaryRef) pos, key); 899 if (pos == NULL && autoCreate && p != NULL) 900 { 901 pos = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 902 CFDictionaryAddValue((CFMutableDictionaryRef) lastPos, key, pos); 903 } 904 CFRelease(key); 905 } 906 else if (typeId == CFArrayGetTypeID()) 907 { 908 int index = atoi(tok); 909 if (index < 0 || index >= CFArrayGetCount((CFArrayRef) pos)) 910 { 911 pos = NULL; 912 } 913 else 914 { 915 pos = (CFPropertyListRef) CFArrayGetValueAtIndex((CFArrayRef) pos, index); 916 } 917 } 918 else 919 { 920 pos = NULL; 921 } 922 } 923 924 lastTok = tok; 925 } 926 927 if (last != NULL) 928 *last = strdup(lastTok); 929 930 if (entry != NULL) 931 *entry = pos; 932 933 if (parent != NULL) 934 *parent = (!tok) ? lastPos : NULL; 935 936 free(whatStr2); 937} 938 939void prettyPrintPlist(CFPropertyListRef what, int indentNum) 940{ 941 CFTypeID typeId = CFGetTypeID(what); 942 char* indent = __builtin_alloca(indentNum + 1); 943 944 memset(indent, ' ', indentNum); 945 indent[indentNum] = '\0'; 946 947 if (typeId == CFStringGetTypeID()) 948 { 949 const char* str = CFStringGetCStringPtr((CFStringRef) what, kCFStringEncodingUTF8); 950 printf("%s", str); 951 } 952 else if (typeId == CFArrayGetTypeID()) 953 { 954 CFArrayRef array = (CFArrayRef) what; 955 CFIndex count = CFArrayGetCount(array); 956 957 printf("Array {\n"); 958 for (CFIndex i = 0; i < count; i++) 959 { 960 CFPropertyListRef elem = (CFPropertyListRef) CFArrayGetValueAtIndex(array, i); 961 printf("%s ", indent); 962 963 prettyPrintPlist(elem, indentNum + 4); 964 printf("\n"); 965 } 966 967 printf("%s}", indent); 968 } 969 else if (typeId == CFDictionaryGetTypeID()) 970 { 971 CFDictionaryRef dict = (CFDictionaryRef) what; 972 CFStringRef* keys; 973 CFPropertyListRef* values; 974 975 CFIndex count = CFDictionaryGetCount(dict); 976 977 keys = malloc(sizeof(CFStringRef*) * count); 978 values = malloc(sizeof(CFStringRef*) * count); 979 980 CFDictionaryGetKeysAndValues(dict, (const void**) keys, (const void**) values); 981 982 printf("Dict {\n"); 983 for (CFIndex i = 0; i < count; i++) 984 { 985 printf("%s ", indent); 986 prettyPrintPlist(keys[i], 0); 987 printf(" = "); 988 prettyPrintPlist(values[i], indentNum + 4); 989 printf("\n"); 990 } 991 992 printf("%s}", indent); 993 994 free(keys); 995 free(values); 996 } 997 else if (typeId == CFBooleanGetTypeID()) 998 { 999 if (what == kCFBooleanTrue) 1000 printf("true"); 1001 else 1002 printf("false"); 1003 } 1004 else if (typeId == CFNumberGetTypeID()) 1005 { 1006 CFNumberRef num = (CFNumberRef) what; 1007 1008 if (CFNumberIsFloatType(num)) 1009 { 1010 Float64 d; 1011 CFNumberGetValue(num, kCFNumberFloat64Type, &d); 1012 printf("%f", d); 1013 } 1014 else 1015 { 1016 long long l; 1017 CFNumberGetValue(num, kCFNumberLongLongType, &l); 1018 printf("%lld", l); 1019 } 1020 } 1021 else if (typeId == CFDateGetTypeID()) 1022 { 1023 CFAbsoluteTime t = CFDateGetAbsoluteTime((CFDateRef) what); 1024 CFTimeZoneRef tz = CFTimeZoneCopyDefault(); 1025 CFGregorianDate d = CFAbsoluteTimeGetGregorianDate(t, tz); 1026 struct tm tm; 1027 char buf[150]; 1028 1029 tm.tm_mday = d.day; 1030 tm.tm_mon = d.month - 1; 1031 tm.tm_year = d.year - 1900; 1032 tm.tm_hour = d.hour; 1033 tm.tm_min = d.minute; 1034 tm.tm_sec = d.second; 1035 tm.tm_wday = CFAbsoluteTimeGetDayOfWeek(t, tz); 1036 1037 if (tm.tm_wday == 7) 1038 tm.tm_wday = 0; 1039 1040 tm.tm_zone = 0; 1041 tm.tm_isdst = 0; 1042 1043 strftime(buf, sizeof(buf), "%a %b %d %H:%M:%S %Z %Y", &tm); 1044 printf("%s", buf); 1045 1046 CFRelease(tz); 1047 } 1048 else if (typeId == CFDataGetTypeID()) 1049 { 1050 CFDataRef data = (CFDataRef) what; 1051 const UInt8* bytes = CFDataGetBytePtr(data); 1052 CFIndex len = CFDataGetLength(data); 1053 1054 fwrite(bytes, 1, len, stdout); 1055 } 1056} 1057 1058void doPrint(const char* whatStr) 1059{ 1060 CFPropertyListRef what = plist; 1061 CFPropertyListRef entry = plist; 1062 1063 if (whatStr != NULL) 1064 { 1065 resolvePlistEntry(whatStr, &what, &entry, NULL, false); 1066 if (entry == NULL) 1067 { 1068 printf("Print: Entry, \"%s\", Does Not Exist\n", whatStr); 1069 return; 1070 } 1071 } 1072 1073 if (!forceXML) { 1074 prettyPrintPlist(entry, 0); 1075 printf("\n"); 1076 } 1077 else 1078 { 1079 CFDataRef data = CFPropertyListCreateXMLData(kCFAllocatorDefault, entry); 1080 1081 if (data != NULL) 1082 { 1083 prettyPrintPlist(data, 0); 1084 printf("\n"); 1085 1086 CFRelease(data); 1087 } 1088 } 1089} 1090 1091void deleteEntry(const char* entry) 1092{ 1093 CFPropertyListRef parent, existing; 1094 CFPropertyListRef newValue; 1095 char* leafName = NULL; 1096 1097 resolvePlistEntry(entry, &parent, &existing, &leafName, false); 1098 if (existing == NULL) 1099 { 1100 printf("Delete: Entry, \"%s\", Does Not Exist\n", entry); 1101 goto out; 1102 } 1103 1104 CFTypeID typeID = CFGetTypeID(parent); 1105 if (typeID == CFDictionaryGetTypeID()) 1106 { 1107 CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, leafName, kCFStringEncodingUTF8); 1108 CFDictionaryRemoveValue((CFMutableDictionaryRef) parent, str); 1109 CFRelease(str); 1110 } 1111 else 1112 { 1113 CFIndex idx = atoi(leafName); 1114 CFArrayRemoveValueAtIndex((CFMutableArrayRef) parent, idx); 1115 } 1116 1117out: 1118 free(leafName); 1119} 1120 1121void copyEntry(const char* src, const char* dst) 1122{ 1123 CFPropertyListRef existing, entry, newParent, entryCopy; 1124 char* leafName = NULL; 1125 1126 resolvePlistEntry(src, NULL, &entry, NULL, false); 1127 resolvePlistEntry(dst, &newParent, &existing, &leafName, true); 1128 1129 if (entry == NULL) 1130 { 1131 printf("Copy: Entry, \"%s\", Does Not Exist\n", src); 1132 goto out; 1133 } 1134 if (existing != NULL) 1135 { 1136 printf("Copy: \"%s\" Entry Already Exists\n", dst); 1137 goto out; 1138 } 1139 1140 entryCopy = CFPropertyListCreateDeepCopy(kCFAllocatorDefault, entry, kCFPropertyListMutableContainers); 1141 1142 CFTypeID typeID = CFGetTypeID(newParent); 1143 if (typeID == CFDictionaryGetTypeID()) 1144 { 1145 CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, leafName, kCFStringEncodingUTF8); 1146 CFDictionaryAddValue((CFMutableDictionaryRef) newParent, str, entryCopy); 1147 CFRelease(str); 1148 } 1149 else 1150 { 1151 CFIndex idx = atoi(leafName); 1152 CFArrayInsertValueAtIndex((CFMutableArrayRef) newParent, idx, entryCopy); 1153 } 1154 1155 CFRelease(entryCopy); 1156out: 1157 free(leafName); 1158} 1159 1160void mergeFile(const char* path, const char* entry) 1161{ 1162 CFPropertyListRef dest, fileContents; 1163 1164 fileContents = loadPlist(path); 1165 if (fileContents == NULL) 1166 return; 1167 1168 if (entry != NULL && *entry) 1169 { 1170 resolvePlistEntry(entry, NULL, &dest, NULL, true); 1171 if (dest == NULL) 1172 { 1173 printf("Merge: Entry, \"%s\", Does Not Exist\n", entry); 1174 CFRelease(fileContents); 1175 return; 1176 } 1177 } 1178 else 1179 dest = plist; 1180 1181 CFTypeID typeID = CFGetTypeID(dest); 1182 CFTypeID sourceTypeID = CFGetTypeID(fileContents); 1183 1184 if (typeID == CFArrayGetTypeID()) 1185 { 1186 if (sourceTypeID == CFArrayGetTypeID()) 1187 { 1188 CFArrayAppendArray((CFMutableArrayRef) dest, fileContents, CFRangeMake(0, CFArrayGetCount(fileContents))); 1189 } 1190 else if (sourceTypeID == CFDictionaryGetTypeID()) 1191 { 1192 CFIndex count = CFDictionaryGetCount((CFDictionaryRef) fileContents); 1193 void** values = malloc(sizeof(void*) * count); 1194 CFDictionaryGetKeysAndValues((CFDictionaryRef) fileContents, NULL, (const void**) values); 1195 1196 CFArrayReplaceValues((CFMutableArrayRef) dest, CFRangeMake(CFArrayGetCount((CFArrayRef) dest) - 1, 0), (const void**) values, count); 1197 free(values); 1198 } 1199 else 1200 { 1201 CFArrayAppendValue((CFMutableArrayRef) dest, fileContents); 1202 } 1203 } 1204 else if (typeID == CFDictionaryGetTypeID()) 1205 { 1206 if (sourceTypeID == CFDictionaryGetTypeID()) 1207 { 1208 CFIndex count = CFDictionaryGetCount((CFDictionaryRef) fileContents); 1209 void** values = malloc(sizeof(void*) * count); 1210 void** keys = malloc(sizeof(void*) * count); 1211 1212 CFDictionaryGetKeysAndValues((CFDictionaryRef) fileContents, (const void**) keys, (const void**) values); 1213 1214 for (CFIndex i = 0; i < count; i++) 1215 CFDictionarySetValue((CFMutableDictionaryRef) dest, keys[i], values[i]); 1216 1217 free(keys); 1218 free(values); 1219 } 1220 else if (sourceTypeID == CFArrayGetTypeID()) 1221 { 1222 puts("Merge: Can't Add array Entries to dict"); 1223 } 1224 else 1225 { 1226 CFDictionarySetValue((CFMutableDictionaryRef) dest, CFSTR(""), fileContents); 1227 } 1228 } 1229 else 1230 { 1231 puts("Merge: Specified Entry Must Be a Container"); 1232 } 1233 1234 CFRelease(fileContents); 1235} 1236 1237// NOTE: This function doesn't seem to work at all in the original program 1238void importFile(const char* entry, const char* path) 1239{ 1240 CFPropertyListRef dest, fileContents; 1241 char* leafName; 1242 1243 fileContents = loadPlist(path); 1244 if (fileContents == NULL) 1245 return; 1246 1247 resolvePlistEntry(entry, &dest, NULL, &leafName, true); 1248 if (dest == NULL) 1249 { 1250 printf("Import: Entry, \"%s\", Does Not Exist\n", entry); 1251 CFRelease(fileContents); 1252 return; 1253 } 1254 1255 CFTypeID typeID = CFGetTypeID(dest); 1256 if (typeID == CFDictionaryGetTypeID()) 1257 { 1258 CFStringRef key = CFStringCreateWithCString(kCFAllocatorDefault, leafName, kCFStringEncodingUTF8); 1259 CFDictionarySetValue((CFMutableDictionaryRef) dest, key, fileContents); 1260 CFRelease(key); 1261 } 1262 else if (typeID == CFArrayGetTypeID()) 1263 { 1264 CFIndex index = atoi(leafName); 1265 if (index < 0) 1266 index = 0; 1267 1268 if (index >= CFArrayGetCount((CFArrayRef) dest)) 1269 CFArrayAppendValue((CFMutableArrayRef) dest, fileContents); 1270 else 1271 CFArraySetValueAtIndex((CFMutableArrayRef) dest, index, fileContents); 1272 } 1273 1274 free(leafName); 1275 CFRelease(fileContents); 1276} 1277